From 6abb7e1069d9851cab94f321bf33f95410454a6a Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Fri, 11 Mar 2016 06:23:11 -0500 Subject: [PATCH 1/2] namespace: respect hoisting --- src/rules/namespace.js | 54 ++++++++++++++++++++---------------- tests/src/rules/namespace.js | 22 +++++++++++++++ 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/rules/namespace.js b/src/rules/namespace.js index 5dd6f7f200..a41050d415 100644 --- a/src/rules/namespace.js +++ b/src/rules/namespace.js @@ -14,37 +14,43 @@ module.exports = function (context) { return { - 'ImportDeclaration': function (declaration) { - if (declaration.specifiers.length === 0) return + // pick up all imports at body entry time, to properly respect hoisting + 'Program': function ({ body }) { + function processBodyStatement(declaration) { + if (declaration.type !== 'ImportDeclaration') return - const imports = Exports.get(declaration.source.value, context) - if (imports == null) return null + if (declaration.specifiers.length === 0) return - if (imports.errors.length) { - imports.reportErrors(context, declaration) - return - } + const imports = Exports.get(declaration.source.value, context) + if (imports == null) return null + + if (imports.errors.length) { + imports.reportErrors(context, declaration) + return + } - for (let specifier of declaration.specifiers) { - switch (specifier.type) { - case 'ImportNamespaceSpecifier': - if (!imports.hasNamed) { - context.report(specifier, - `No exported names found in module '${declaration.source.value}'.`) + for (let specifier of declaration.specifiers) { + switch (specifier.type) { + case 'ImportNamespaceSpecifier': + if (!imports.hasNamed) { + context.report(specifier, + `No exported names found in module '${declaration.source.value}'.`) + } + namespaces.set(specifier.local.name, imports.named) + break + case 'ImportDefaultSpecifier': + case 'ImportSpecifier': { + const meta = imports.named.get( + // default to 'default' for default http://i.imgur.com/nj6qAWy.jpg + specifier.imported ? specifier.imported.name : 'default') + if (!meta || !meta.namespace) break + namespaces.set(specifier.local.name, meta.namespace) + break } - namespaces.set(specifier.local.name, imports.named) - break - case 'ImportDefaultSpecifier': - case 'ImportSpecifier': { - const meta = imports.named.get( - // default to 'default' for default http://i.imgur.com/nj6qAWy.jpg - specifier.imported ? specifier.imported.name : 'default') - if (!meta || !meta.namespace) break - namespaces.set(specifier.local.name, meta.namespace) - break } } } + body.forEach(processBodyStatement) }, // same as above, but does not add names to local map diff --git a/tests/src/rules/namespace.js b/tests/src/rules/namespace.js index 995ffdda2a..0d364fcfae 100644 --- a/tests/src/rules/namespace.js +++ b/tests/src/rules/namespace.js @@ -68,6 +68,13 @@ const valid = [ parser: 'babel-eslint', }), + // respect hoisting + test({ + code: + 'function x() { console.log((names.b).c); } ' + + 'import * as names from "./named-exports"; ', + }), + ] const invalid = [ @@ -138,6 +145,21 @@ const invalid = [ code: "import b from './deep/default'; console.log(b.e)", errors: [ "'e' not found in imported namespace 'b'." ], }), + + // respect hoisting + test({ + code: + 'console.log(names.c);' + + "import * as names from './named-exports'; ", + errors: [error('c', 'names')], + }), + test({ + code: + 'function x() { console.log(names.c) } ' + + "import * as names from './named-exports'; ", + errors: [error('c', 'names')], + }), + ] /////////////////////// From 10fb144ccbe8612ad629b53fcd4318b6968c730f Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Fri, 11 Mar 2016 06:30:48 -0500 Subject: [PATCH 2/2] no-deprecated: respect hoisting --- src/rules/no-deprecated.js | 3 ++- tests/src/rules/no-deprecated.js | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/rules/no-deprecated.js b/src/rules/no-deprecated.js index 5556fa5911..cc7f553d9f 100644 --- a/src/rules/no-deprecated.js +++ b/src/rules/no-deprecated.js @@ -6,6 +6,7 @@ module.exports = function (context) { , namespaces = new Map() function checkSpecifiers(node) { + if (node.type !== 'ImportDeclaration') return if (node.source == null) return // local export, ignore const imports = Exports.get(node.source.value, context) @@ -64,7 +65,7 @@ module.exports = function (context) { } return { - 'ImportDeclaration': checkSpecifiers, + 'Program': ({ body }) => body.forEach(checkSpecifiers), 'Identifier': function (node) { if (node.parent.type === 'MemberExpression' && node.parent.property === node) { diff --git a/tests/src/rules/no-deprecated.js b/tests/src/rules/no-deprecated.js index 38fb817d9a..92660348b2 100644 --- a/tests/src/rules/no-deprecated.js +++ b/tests/src/rules/no-deprecated.js @@ -134,3 +134,25 @@ ruleTester.run('no-deprecated', rule, { }), ], }) + +ruleTester.run('no-deprecated: hoisting', rule, { + valid: [ + + test({ + code: "function x(deepDep) { console.log(deepDep.MY_TERRIBLE_ACTION) } import { deepDep } from './deep-deprecated'", + }), + + ], + + invalid: [ + + test({ + code: "console.log(MY_TERRIBLE_ACTION); import { MY_TERRIBLE_ACTION } from './deprecated'", + errors: [ + { type: 'Identifier', message: 'Deprecated: please stop sending/handling this action type.' }, + { type: 'ImportSpecifier', message: 'Deprecated: please stop sending/handling this action type.' }, + ], + }), + + ], +})