diff --git a/src/rules/namespace.js b/src/rules/namespace.js index 5dd6f7f20..a41050d41 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/src/rules/no-deprecated.js b/src/rules/no-deprecated.js index 5556fa591..cc7f553d9 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/namespace.js b/tests/src/rules/namespace.js index 995ffdda2..0d364fcfa 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')], + }), + ] /////////////////////// diff --git a/tests/src/rules/no-deprecated.js b/tests/src/rules/no-deprecated.js index 38fb817d9..92660348b 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.' }, + ], + }), + + ], +})