diff --git a/lib/rules/no-use-before-define.js b/lib/rules/no-use-before-define.js index 26f2292..0c5409d 100644 --- a/lib/rules/no-use-before-define.js +++ b/lib/rules/no-use-before-define.js @@ -39,6 +39,14 @@ function parseOptions(options) { return { functions, classes, variables, typedefs }; } +/** + * @param {Scope} scope - a scope to check + * @returns {boolean} `true` if the scope is toplevel + */ +function isTopLevelScope(scope) { + return scope.type === "module" || scope.type === "global"; +} + /** * Checks whether or not a given variable is a function declaration. * @@ -57,10 +65,18 @@ function isFunction(variable) { * @returns {boolean} `true` if the variable is a class declaration. */ function isOuterClass(variable, reference) { - return ( - variable.defs[0].type === "ClassName" && - variable.scope.variableScope !== reference.from.variableScope - ); + if (variable.defs[0].type !== "ClassName") { + return false; + } + + if (variable.scope.variableScope === reference.from.variableScope) { + // allow the same scope only if it's the top level global/module scope + if (!isTopLevelScope(variable.scope.variableScope)) { + return false; + } + } + + return true; } /** @@ -70,10 +86,18 @@ function isOuterClass(variable, reference) { * @returns {boolean} `true` if the variable is a variable declaration. */ function isOuterVariable(variable, reference) { - return ( - variable.defs[0].type === "Variable" && - variable.scope.variableScope !== reference.from.variableScope - ); + if (variable.defs[0].type !== "Variable") { + return false; + } + + if (variable.scope.variableScope === reference.from.variableScope) { + // allow the same scope only if it's the top level global/module scope + if (!isTopLevelScope(variable.scope.variableScope)) { + return false; + } + } + + return true; } /** diff --git a/tests/lib/rules/no-use-before-define.js b/tests/lib/rules/no-use-before-define.js index 98d0fd3..6aff81c 100644 --- a/tests/lib/rules/no-use-before-define.js +++ b/tests/lib/rules/no-use-before-define.js @@ -178,6 +178,26 @@ type Foo = string | number `, options: [{ typedefs: false }], parser: "typescript-eslint-parser" + }, + + // test for https://github.com/bradzacher/eslint-plugin-typescript/issues/142 + { + code: ` +var alias = Test; + +class Test {} + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ classes: false }] + }, + { + code: ` +var alias = Test; + +export class Test {} + `, + parserOptions: { ecmaVersion: 6, sourceType: "module" }, + options: [{ classes: false }] } ], invalid: [ @@ -509,20 +529,6 @@ var a=function() {}; { code: ` new A(); -class A {}; - `, - options: [{ functions: false, classes: false }], - parserOptions: { ecmaVersion: 6 }, - errors: [ - { - message: "'A' was used before it was defined.", - type: "Identifier" - } - ] - }, - { - code: ` -new A(); var A = class {}; `, options: [{ classes: false }], @@ -688,19 +694,6 @@ var bar; type: "Identifier" } ] - }, - { - code: ` -foo; -var foo; - `, - options: [{ variables: false }], - errors: [ - { - message: "'foo' was used before it was defined.", - type: "Identifier" - } - ] } ] });