diff --git a/analyze-scope.js b/analyze-scope.js new file mode 100644 index 0000000..d090290 --- /dev/null +++ b/analyze-scope.js @@ -0,0 +1,598 @@ +"use strict"; + +/* eslint-disable new-cap, no-underscore-dangle */ + +const escope = require("eslint-scope"); +const { Definition, ParameterDefinition } = require("eslint-scope/lib/definition"); +const OriginalPatternVisitor = require("eslint-scope/lib/pattern-visitor"); +const Reference = require("eslint-scope/lib/reference"); +const OriginalReferencer = require("eslint-scope/lib/referencer"); +const Scope = require("eslint-scope/lib/scope").Scope; +const fallback = require("eslint-visitor-keys").getKeys; +const lodash = require("lodash"); +const childVisitorKeys = require("./visitor-keys"); + +/** + * Get `.range[0]` of a given object. + * @param {{range: number[]}} x The object to get. + * @returns {number} The gotten value. + */ +function byRange0(x) { + return x.range[0]; +} + +/** + * Check the TSModuleDeclaration node is `declare global {}` or not. + * @param {TSModuleDeclaration} node The TSModuleDeclaration node to check. + * @param {Token[]} tokens The token list. + * @returns {boolean} `true` if the node is `declare global {}`. + */ +function isGlobalAugmentation(node, tokens) { + const i = lodash.sortedIndexBy(tokens, node, byRange0); + const token1 = tokens[i]; + const token2 = tokens[i + 1]; + + return Boolean( + token1 && + token2 && + (token1.type === "Keyword" || token1.type === "Identifier") && + token1.value === "declare" && + (token2.type === "Keyword" || token2.type === "Identifier") && + token2.value === "global" + ); +} + +/** + * Define the override function of `Scope#__define` for global augmentation. + * @param {Function} define The original Scope#__define method. + * @returns {Function} The override function. + */ +function overrideDefine(define) { + return /* @this {Scope} */ function(node, definition) { + define.call(this, node, definition); + + // Set `variable.eslintUsed` to tell ESLint that the variable is exported. + const variable = this.set.get(node.name); + if (variable) { + variable.eslintUsed = true; + } + }; +} + +/** The scope class for enum. */ +class EnumScope extends Scope { + constructor(scopeManager, upperScope, block) { + super(scopeManager, "enum", upperScope, block, false); + } +} + +class PatternVisitor extends OriginalPatternVisitor { + Identifier(node) { + super.Identifier(node); + if (node.typeAnnotation) { + this.rightHandNodes.push(node.typeAnnotation); + } + } + + ArrayPattern(node) { + node.elements.forEach(this.visit, this); + if (node.typeAnnotation) { + this.rightHandNodes.push(node.typeAnnotation); + } + } + + ObjectPattern(node) { + node.properties.forEach(this.visit, this); + if (node.typeAnnotation) { + this.rightHandNodes.push(node.typeAnnotation); + } + } +} + +class Referencer extends OriginalReferencer { + constructor(...args) { + super(...args); + this.typeMode = false; + } + + /** + * Override to use PatternVisitor we overrode. + * @param {Identifier} node The Identifier node to visit. + * @param {Object} [options] The flag to visit right-hand side nodes. + * @param {Function} callback The callback function for left-hand side nodes. + * @returns {void} + */ + visitPattern(node, options, callback) { + if (!node) { + return; + } + + if (typeof options === "function") { + callback = options; + options = { processRightHandNodes: false }; + } + + const visitor = new PatternVisitor(this.options, node, callback); + visitor.visit(node); + + if (options.processRightHandNodes) { + visitor.rightHandNodes.forEach(this.visit, this); + } + } + + /** + * Override. + * Visit `node.typeParameters` and `node.returnType` additionally to find `typeof` expressions. + * @param {FunctionDeclaration|FunctionExpression|ArrowFunctionExpression} node The function node to visit. + * @returns {void} + */ + visitFunction(node) { + const { type, id, typeParameters, params, returnType, body } = node; + const scopeManager = this.scopeManager; + const upperScope = this.currentScope(); + + // Process the name. + if (type === "FunctionDeclaration" && id) { + upperScope.__define( + id, + new Definition("FunctionName", id, node, null, null, null) + ); + + // Remove overload definition to avoid confusion of no-redeclare rule. + const { defs, identifiers } = upperScope.set.get(id.name); + for (let i = 0; i < defs.length; ++i) { + const def = defs[i]; + if (def.type === "FunctionName" && def.node.type === "TSEmptyBodyFunctionDeclaration") { + defs.splice(i, 1); + identifiers.splice(i, 1); + break; + } + } + } else if (type === "FunctionExpression" && id) { + scopeManager.__nestFunctionExpressionNameScope(node); + } + + // Process the type parameters + this.visit(typeParameters); + + // Open the function scope. + scopeManager.__nestFunctionScope(node, this.isInnerMethodDefinition); + const innerScope = this.currentScope(); + + // Process parameter declarations. + for (let i = 0; i < params.length; ++i) { + this.visitPattern( + params[i], + { processRightHandNodes: true }, + (pattern, info) => { + innerScope.__define( + pattern, + new ParameterDefinition( + pattern, + node, + i, + info.rest + ) + ); + this.referencingDefaultValue( + pattern, + info.assignments, + null, + true + ); + } + ); + } + + // Process the return type. + this.visit(returnType); + + // Process the body. + if (body.type === "BlockStatement") { + this.visitChildren(body); + } else { + this.visit(body); + } + + // Close the function scope. + this.close(node); + } + + /** + * Override. + * Visit decorators. + * @param {ClassDeclaration|ClassExpression} node The class node to visit. + * @returns {void} + */ + visitClass(node) { + this.visitDecorators(node.decorators); + super.visitClass(node); + } + + /** + * Override. + * Don't create the reference object in the type mode. + * @param {Identifier} node The Identifier node to visit. + * @returns {void} + */ + Identifier(node) { + if (!this.typeMode) { + super.Identifier(node); + } + this.visit(node.typeAnnotation); + } + + /** + * Override. + * Visit decorators. + * @param {MethodDefinition} node The MethodDefinition node to visit. + * @returns {void} + */ + MethodDefinition(node) { + this.visitDecorators(node.decorators); + super.MethodDefinition(node); + } + + /** + * Override. + * Don't make variable if `kind === "type"`. + * It doesn't declare variables but declare types. + * @param {VariableDeclaration} node The VariableDeclaration node to visit. + * @returns {void} + */ + VariableDeclaration(node) { + if (node.kind !== "type") { + super.VariableDeclaration(node); + return; + } + + // To detect typeof. + this.typeMode = true; + this.visitChildren(node); + this.typeMode = false; + } + + /** + * Don't create the reference object for the key if not computed. + * @param {TSEmptyBodyFunctionDeclaration} node The TSEmptyBodyFunctionDeclaration node to visit. + * @returns {void} + */ + ClassProperty(node) { + const upperTypeMode = this.typeMode; + const { computed, decorators, key, typeAnnotation, value } = node; + + this.typeMode = false; + this.visitDecorators(decorators); + if (computed) { + this.visit(key); + } + this.typeMode = true; + this.visit(typeAnnotation); + this.typeMode = false; + this.visit(value); + + this.typeMode = upperTypeMode; + } + + /** + * Define the variable of this function declaration only once. + * Because to avoid confusion of `no-redeclare` rule by overloading. + * @param {TSEmptyBodyFunctionDeclaration} node The TSEmptyBodyFunctionDeclaration node to visit. + * @returns {void} + */ + TSEmptyBodyFunctionDeclaration(node) { + const upperTypeMode = this.typeMode; + const scope = this.currentScope(); + const { id, typeParameters, params, returnType } = node; + + // Ignore this if other overloadings have already existed. + const variable = scope.set.get(id.name); + const defs = variable && variable.defs; + const existed = defs && defs.some(d => d.type === "FunctionName"); + if (!existed) { + scope.__define( + id, + new Definition("FunctionName", id, node, null, null, null) + ); + } + + // Find `typeof` expressions. + this.typeMode = true; + this.visit(typeParameters); + params.forEach(this.visit, this); + this.visit(returnType); + this.typeMode = upperTypeMode; + } + TSEmptyBodyDeclareFunction(node) { + this.TSEmptyBodyFunctionDeclaration(node); + } + + /** + * Create reference objects for the references in parameters and return type. + * @param {TSEmptyBodyFunctionExpression} node The TSEmptyBodyFunctionExpression node to visit. + * @returns {void} + */ + TSEmptyBodyFunctionExpression(node) { + const upperTypeMode = this.typeMode; + const { typeParameters, params, returnType } = node; + + this.typeMode = true; + this.visit(typeParameters); + params.forEach(this.visit, this); + this.visit(returnType); + this.typeMode = upperTypeMode; + } + + /** + * Don't make variable because it declares only types. + * Switch to the type mode and visit child nodes to find `typeof x` expression in type declarations. + * @param {TSInterfaceDeclaration} node The TSInterfaceDeclaration node to visit. + * @returns {void} + */ + TSInterfaceDeclaration(node) { + if (this.typeMode) { + this.visitChildren(node); + } else { + this.typeMode = true; + this.visitChildren(node); + this.typeMode = false; + } + } + + /** + * Switch to the type mode and visit child nodes to find `typeof x` expression in type declarations. + * @param {TSTypeAnnotation} node The TSTypeAnnotation node to visit. + * @returns {void} + */ + TSTypeAnnotation(node) { + if (this.typeMode) { + this.visitChildren(node); + } else { + this.typeMode = true; + this.visitChildren(node); + this.typeMode = false; + } + } + + /** + * Switch to the type mode and visit child nodes to find `typeof x` expression in type declarations. + * @param {TSTypeParameterDeclaration} node The TSTypeParameterDeclaration node to visit. + * @returns {void} + */ + TSTypeParameterDeclaration(node) { + if (this.typeMode) { + this.visitChildren(node); + } else { + this.typeMode = true; + this.visitChildren(node); + this.typeMode = false; + } + } + + /** + * Create reference objects for the references in `typeof` expression. + * @param {TSTypeQuery} node The TSTypeQuery node to visit. + * @returns {void} + */ + TSTypeQuery(node) { + if (this.typeMode) { + this.typeMode = false; + this.visitChildren(node); + this.typeMode = true; + } else { + this.visitChildren(node); + } + } + + /** + * Create reference objects for the references in computed keys. + * @param {TSPropertySignature} node The TSPropertySignature node to visit. + * @returns {void} + */ + TSPropertySignature(node) { + const upperTypeMode = this.typeMode; + const { computed, key, typeAnnotation, initializer } = node; + + if (computed) { + this.typeMode = false; + this.visit(key); + this.typeMode = true; + } else { + this.typeMode = true; + this.visit(key); + } + this.visit(typeAnnotation); + this.visit(initializer); + + this.typeMode = upperTypeMode; + } + + /** + * Create reference objects for the references in computed keys. + * @param {TSMethodSignature} node The TSMethodSignature node to visit. + * @returns {void} + */ + TSMethodSignature(node) { + const upperTypeMode = this.typeMode; + const { computed, key, typeParameters, params, typeAnnotation } = node; + + if (computed) { + this.typeMode = false; + this.visit(key); + this.typeMode = true; + } else { + this.typeMode = true; + this.visit(key); + } + this.visit(typeParameters); + params.forEach(this.visit, this); + this.visit(typeAnnotation); // Maybe returnType? + + this.typeMode = upperTypeMode; + } + + /** + * Create variable object for the enum. + * The enum declaration creates a scope for the enum members. + * + * enum E { + * A, + * B, + * C = A + B // A and B are references to the enum member. + * } + * + * const a = 0 + * enum E { + * A = a // a is above constant. + * } + * + * @param {TSEnumDeclaration} node The TSEnumDeclaration node to visit. + * @returns {void} + */ + TSEnumDeclaration(node) { + const { id, members } = node; + const scopeManager = this.scopeManager; + const scope = this.currentScope(); + + if (id) { + scope.__define(id, new Definition("EnumName", id, node)); + } + + scopeManager.__nestScope(new EnumScope(scopeManager, scope, node)); + for (const member of members) { + this.visit(member); + } + this.close(node); + } + + /** + * Create variable object for the enum member and create reference object for the initializer. + * And visit the initializer. + * + * @param {TSEnumMember} node The TSEnumMember node to visit. + * @returns {void} + */ + TSEnumMember(node) { + const { id, initializer } = node; + const scope = this.currentScope(); + + scope.__define(id, new Definition("EnumMemberName", id, node)); + if (initializer) { + scope.__referencing( + id, + Reference.WRITE, + initializer, + null, + false, + true + ); + this.visit(initializer); + } + } + + /** + * Create the variable object for the module name, and visit children. + * @param {TSModuleDeclaration} node The TSModuleDeclaration node to visit. + * @returns {void} + */ + TSModuleDeclaration(node) { + const astRoot = this.scopeManager.globalScope.block; + const scope = this.currentScope(); + const { id, body } = node; + + // https://github.com/JamesHenry/typescript-estree/issues/27 + if (isGlobalAugmentation(node, astRoot.tokens)) { + this.visitGlobalAugmentation(node); + return; + } + + if (id && id.type === "Identifier") { + scope.__define( + id, + new Definition("NamespaceName", id, node, null, null, null) + ); + } + this.visit(body); + } + + /** + * Process the module block. + * @param {TSModuleBlock} node The TSModuleBlock node to visit. + * @returns {void} + */ + TSModuleBlock(node) { + this.scopeManager.__nestBlockScope(node); + this.visitChildren(node); + this.close(node); + } + + TSAbstractClassDeclaration(node) { + this.ClassDeclaration(node); + } + TSAbstractClassProperty(node) { + this.ClassProperty(node); + } + TSAbstractMethodDefinition(node) { + this.MethodDefinition(node); + } + + /** + * Process the global augmentation. + * 1. Set the global scope as the current scope. + * 2. Configure the global scope to set `variable.eslintUsed = true` for all defined variables. This means `no-unused-vars` doesn't warn those. + * @param {TSModuleDeclaration} node The TSModuleDeclaration node to visit. + * @returns {void} + */ + visitGlobalAugmentation(node) { + const scopeManager = this.scopeManager; + const currentScope = this.currentScope(); + const globalScope = scopeManager.globalScope; + const originalDefine = globalScope.__define; + + globalScope.__define = overrideDefine(originalDefine); + scopeManager.__currentScope = globalScope; + + // Skip TSModuleBlock to avoid to create that block scope. + for (const moduleItem of node.body.body) { + this.visit(moduleItem); + } + + scopeManager.__currentScope = currentScope; + globalScope.__define = originalDefine; + } + + /** + * Process decorators. + * @param {Decorator[]|undefined} decorators The decorator nodes to visit. + * @returns {void} + */ + visitDecorators(decorators) { + if (decorators) { + decorators.forEach(this.visit, this); + } + } +} + +module.exports = function(ast, parserOptions, extraOptions) { + const options = { + ignoreEval: true, + optimistic: false, + directive: false, + nodejsScope: + ast.sourceType === "script" && + (parserOptions.ecmaFeatures && + parserOptions.ecmaFeatures.globalReturn) === true, + impliedStrict: false, + sourceType: extraOptions.sourceType, + ecmaVersion: parserOptions.ecmaVersion || 2018, + childVisitorKeys, + fallback + }; + + const scopeManager = new escope.ScopeManager(options); + const referencer = new Referencer(options, scopeManager); + + referencer.visit(ast); + + return scopeManager; +}; diff --git a/package.json b/package.json index f9bf461..17c3509 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "version": "20.1.1", "files": [ "parser.js", + "analyze-scope.js", "visitor-keys.js" ], "engines": { @@ -43,7 +44,9 @@ "typescript": "*" }, "dependencies": { + "eslint-scope": "^4.0.0", "eslint-visitor-keys": "^1.0.0", + "lodash": "^4.17.11", "typescript-estree": "5.0.0" }, "devDependencies": { diff --git a/parser.js b/parser.js index 32b4e7c..8e9049f 100644 --- a/parser.js +++ b/parser.js @@ -11,6 +11,7 @@ const parse = require("typescript-estree").parse; const astNodeTypes = require("typescript-estree").AST_NODE_TYPES; const traverser = require("eslint/lib/util/traverser"); +const analyzeScope = require("./analyze-scope"); const visitorKeys = require("./visitor-keys"); //------------------------------------------------------------------------------ @@ -21,16 +22,45 @@ exports.version = require("./package.json").version; exports.parseForESLint = function parseForESLint(code, options) { const ast = parse(code, options); + const extraOptions = { + sourceType: ast.sourceType + }; + traverser.traverse(ast, { enter: node => { - if (node.type === "DeclareFunction" || node.type === "FunctionExpression" || node.type === "FunctionDeclaration") { - if (!node.body) { - node.type = `TSEmptyBody${node.type}`; - } + switch (node.type) { + // Just for backword compatibility. + case "DeclareFunction": + if (!node.body) { + node.type = `TSEmptyBody${node.type}`; + } + break; + + // Function#body cannot be null in ESTree spec. + case "FunctionExpression": + case "FunctionDeclaration": + if (!node.body) { + node.type = `TSEmptyBody${node.type}`; + } + break; + + // Import/Export declarations cannot appear in script. + // But if those appear only in namespace/module blocks, `ast.sourceType` was `"script"`. + // This doesn't modify `ast.sourceType` directly for backrard compatibility. + case "ImportDeclaration": + case "ExportAllDeclaration": + case "ExportDefaultDeclaration": + case "ExportNamedDeclaration": + extraOptions.sourceType = "module"; + break; + + // no default } } }); - return { ast, visitorKeys }; + + const scopeManager = analyzeScope(ast, options, extraOptions); + return { ast, scopeManager, visitorKeys }; }; exports.parse = function(code, options) { diff --git a/tests/fixtures/scope-analysis/535.ts b/tests/fixtures/scope-analysis/535.ts new file mode 100644 index 0000000..07dfa60 --- /dev/null +++ b/tests/fixtures/scope-analysis/535.ts @@ -0,0 +1,3 @@ +function foo({ bar }: { bar: string }) { + bar; +} diff --git a/tests/fixtures/scope-analysis/abstract-class.ts b/tests/fixtures/scope-analysis/abstract-class.ts new file mode 100644 index 0000000..b71fd3e --- /dev/null +++ b/tests/fixtures/scope-analysis/abstract-class.ts @@ -0,0 +1,4 @@ +abstract class A { + abstract a: string + abstract f(): number +} diff --git a/tests/fixtures/scope-analysis/class-properties.ts b/tests/fixtures/scope-analysis/class-properties.ts new file mode 100644 index 0000000..c446050 --- /dev/null +++ b/tests/fixtures/scope-analysis/class-properties.ts @@ -0,0 +1,5 @@ +const s = Symbol() +class A { + a: typeof s + [s]: number +} diff --git a/tests/fixtures/scope-analysis/computed-properties-in-interface.ts b/tests/fixtures/scope-analysis/computed-properties-in-interface.ts new file mode 100644 index 0000000..b821bc7 --- /dev/null +++ b/tests/fixtures/scope-analysis/computed-properties-in-interface.ts @@ -0,0 +1,5 @@ +const s1 = Symbol(), s2 = Symbol() +interface A { + [s1]: number + [s2](s1: number, s2: number): number; +} diff --git a/tests/fixtures/scope-analysis/computed-properties-in-type.ts b/tests/fixtures/scope-analysis/computed-properties-in-type.ts new file mode 100644 index 0000000..46f7294 --- /dev/null +++ b/tests/fixtures/scope-analysis/computed-properties-in-type.ts @@ -0,0 +1,5 @@ +const s1 = Symbol(), s2 = Symbol() +type A = { + [s1]: number + [s2](s1: number, s2: number): number; +} diff --git a/tests/fixtures/scope-analysis/declare-function.ts b/tests/fixtures/scope-analysis/declare-function.ts new file mode 100644 index 0000000..ea6c15b --- /dev/null +++ b/tests/fixtures/scope-analysis/declare-function.ts @@ -0,0 +1,2 @@ +declare function f(a: number): number +f diff --git a/tests/fixtures/scope-analysis/declare-global.ts b/tests/fixtures/scope-analysis/declare-global.ts new file mode 100644 index 0000000..76c4bef --- /dev/null +++ b/tests/fixtures/scope-analysis/declare-global.ts @@ -0,0 +1,7 @@ +declare global { + let C: number +} + +C = 1 + +export {} diff --git a/tests/fixtures/scope-analysis/declare-module.ts b/tests/fixtures/scope-analysis/declare-module.ts new file mode 100644 index 0000000..9459128 --- /dev/null +++ b/tests/fixtures/scope-analysis/declare-module.ts @@ -0,0 +1,6 @@ +const a = 1 +declare module "foo" { + export const a: number + export const b: typeof a +} +a diff --git a/tests/fixtures/scope-analysis/decorators.ts b/tests/fixtures/scope-analysis/decorators.ts new file mode 100644 index 0000000..34da4b5 --- /dev/null +++ b/tests/fixtures/scope-analysis/decorators.ts @@ -0,0 +1,13 @@ +function dec(target: any) { +} +function gec() { + return (target: any, propertyKey: string) => {} +} + +@dec +class C { + @gec() field: string + @gec() method(): string { + return "" + } +} diff --git a/tests/fixtures/scope-analysis/enum.ts b/tests/fixtures/scope-analysis/enum.ts new file mode 100644 index 0000000..98464d4 --- /dev/null +++ b/tests/fixtures/scope-analysis/enum.ts @@ -0,0 +1,6 @@ +const a: number = 1 +enum E { + A = a, + B = a + 1, + C = A + B +} diff --git a/tests/fixtures/scope-analysis/function-overload-2.ts b/tests/fixtures/scope-analysis/function-overload-2.ts new file mode 100644 index 0000000..548267a --- /dev/null +++ b/tests/fixtures/scope-analysis/function-overload-2.ts @@ -0,0 +1,2 @@ +function f(): void +function f(a: number): void diff --git a/tests/fixtures/scope-analysis/function-overload.ts b/tests/fixtures/scope-analysis/function-overload.ts new file mode 100644 index 0000000..7d23f50 --- /dev/null +++ b/tests/fixtures/scope-analysis/function-overload.ts @@ -0,0 +1,5 @@ +function f(): void +function f(a: number): void +function f(a?: number): void { + // do something. +} diff --git a/tests/fixtures/scope-analysis/ignore-type-only-stuff.ts b/tests/fixtures/scope-analysis/ignore-type-only-stuff.ts new file mode 100644 index 0000000..45cabe3 --- /dev/null +++ b/tests/fixtures/scope-analysis/ignore-type-only-stuff.ts @@ -0,0 +1,9 @@ +type A = number +interface B { + prop1: A +} +interface C extends B { + method(a: { b: A }): { c: A } +} + +var a: C diff --git a/tests/fixtures/scope-analysis/method-overload.ts b/tests/fixtures/scope-analysis/method-overload.ts new file mode 100644 index 0000000..fd8cbbd --- /dev/null +++ b/tests/fixtures/scope-analysis/method-overload.ts @@ -0,0 +1,8 @@ +const s = Symbol() +class A { + f(): void + f(a: typeof s): void + f(a?: any): void { + // do something. + } +} diff --git a/tests/fixtures/scope-analysis/namespace.ts b/tests/fixtures/scope-analysis/namespace.ts new file mode 100644 index 0000000..216c093 --- /dev/null +++ b/tests/fixtures/scope-analysis/namespace.ts @@ -0,0 +1,7 @@ +const a = 1 +namespace N { + export const a = 2 + a +} +a +N.a diff --git a/tests/fixtures/scope-analysis/type-annotations.ts b/tests/fixtures/scope-analysis/type-annotations.ts new file mode 100644 index 0000000..f5d4e63 --- /dev/null +++ b/tests/fixtures/scope-analysis/type-annotations.ts @@ -0,0 +1,7 @@ +type A = number +var a: { b: A } +class C { + f(a: { b: A }): { b: A } { + return {b: 1} + } +} diff --git a/tests/fixtures/scope-analysis/type-assertions.ts b/tests/fixtures/scope-analysis/type-assertions.ts new file mode 100644 index 0000000..0a4caa7 --- /dev/null +++ b/tests/fixtures/scope-analysis/type-assertions.ts @@ -0,0 +1,3 @@ +type A = number; +a = b; +a = b as A; diff --git a/tests/fixtures/scope-analysis/typeof-in-assertions.ts b/tests/fixtures/scope-analysis/typeof-in-assertions.ts new file mode 100644 index 0000000..023291c --- /dev/null +++ b/tests/fixtures/scope-analysis/typeof-in-assertions.ts @@ -0,0 +1,3 @@ +var obj = { value: 1 } +a = b; +a = b as typeof obj; diff --git a/tests/fixtures/scope-analysis/typeof-in-call-signature.ts b/tests/fixtures/scope-analysis/typeof-in-call-signature.ts new file mode 100644 index 0000000..e3e90ce --- /dev/null +++ b/tests/fixtures/scope-analysis/typeof-in-call-signature.ts @@ -0,0 +1,5 @@ +const obj = { value: 1 } +interface A { + (a: typeof obj, b: T): typeof obj + new (a: typeof obj, b: T): typeof obj +} diff --git a/tests/fixtures/scope-analysis/typeof-in-return-type.ts b/tests/fixtures/scope-analysis/typeof-in-return-type.ts new file mode 100644 index 0000000..15f6b7c --- /dev/null +++ b/tests/fixtures/scope-analysis/typeof-in-return-type.ts @@ -0,0 +1,3 @@ +function f(a: number): typeof a { // this `a` is the parameter `a`. + return 1 +} diff --git a/tests/fixtures/scope-analysis/typeof-in-type-parameters.ts b/tests/fixtures/scope-analysis/typeof-in-type-parameters.ts new file mode 100644 index 0000000..2bf99cb --- /dev/null +++ b/tests/fixtures/scope-analysis/typeof-in-type-parameters.ts @@ -0,0 +1,3 @@ +function g(g: T): number { + return 1 +} diff --git a/tests/fixtures/scope-analysis/typeof-in-var.ts b/tests/fixtures/scope-analysis/typeof-in-var.ts new file mode 100644 index 0000000..c970514 --- /dev/null +++ b/tests/fixtures/scope-analysis/typeof-in-var.ts @@ -0,0 +1,4 @@ +var obj = { value: 1 } +var obj2: typeof obj = { value: 2 } +var { value }: typeof obj = { value: 2 } +var [element]: (typeof obj)[] = [{ value: 2 }] diff --git a/tests/fixtures/scope-analysis/typeof.ts b/tests/fixtures/scope-analysis/typeof.ts new file mode 100644 index 0000000..10e4143 --- /dev/null +++ b/tests/fixtures/scope-analysis/typeof.ts @@ -0,0 +1,2 @@ +var obj = { value: 1 } +type B = typeof obj diff --git a/tests/lib/__snapshots__/scope-analysis.js.snap b/tests/lib/__snapshots__/scope-analysis.js.snap new file mode 100644 index 0000000..5fe0286 --- /dev/null +++ b/tests/lib/__snapshots__/scope-analysis.js.snap @@ -0,0 +1,5465 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/535.ts 1`] = ` +Object { + "$id": 5, + "block": Object { + "range": Array [ + 0, + 52, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 4, + "block": Object { + "range": Array [ + 0, + 51, + ], + "type": "FunctionDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 3, + "from": Object { + "$ref": 4, + }, + "identifier": Object { + "name": "bar", + "range": Array [ + 45, + 48, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 5, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 1, + }, + "bar": Object { + "$ref": 2, + }, + }, + "variableScope": Object { + "$ref": 4, + }, + "variables": Array [ + Object { + "$id": 1, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 4, + }, + }, + Object { + "$id": 2, + "defs": Array [ + Object { + "name": Object { + "name": "bar", + "range": Array [ + 15, + 18, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 51, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "bar", + "range": Array [ + 15, + 18, + ], + "type": "Identifier", + }, + ], + "name": "bar", + "references": Array [ + Object { + "$ref": 3, + }, + ], + "scope": Object { + "$ref": 4, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "foo": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 5, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "foo", + "range": Array [ + 9, + 12, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 51, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "foo", + "range": Array [ + 9, + 12, + ], + "type": "Identifier", + }, + ], + "name": "foo", + "references": Array [], + "scope": Object { + "$ref": 5, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/abstract-class.ts 1`] = ` +Object { + "$id": 2, + "block": Object { + "range": Array [ + 0, + 69, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 1, + "block": Object { + "range": Array [ + 0, + 68, + ], + "type": "TSAbstractClassDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "class", + "upperScope": Object { + "$ref": 2, + }, + "variableMap": Object { + "A": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 2, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "A", + "range": Array [ + 15, + 16, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 68, + ], + "type": "TSAbstractClassDeclaration", + }, + "parent": undefined, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "A", + "range": Array [ + 15, + 16, + ], + "type": "Identifier", + }, + ], + "name": "A", + "references": Array [], + "scope": Object { + "$ref": 1, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 2, + }, + "variables": Array [], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/class-properties.ts 1`] = ` +Object { + "$id": 8, + "block": Object { + "range": Array [ + 0, + 63, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 7, + "block": Object { + "range": Array [ + 19, + 62, + ], + "type": "ClassDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 5, + "from": Object { + "$ref": 7, + }, + "identifier": Object { + "name": "s", + "range": Array [ + 43, + 44, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 6, + "from": Object { + "$ref": 7, + }, + "identifier": Object { + "name": "s", + "range": Array [ + 50, + 51, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 5, + }, + Object { + "$ref": 6, + }, + ], + "type": "class", + "upperScope": Object { + "$ref": 8, + }, + "variableMap": Object { + "A": Object { + "$ref": 4, + }, + }, + "variableScope": Object { + "$ref": 8, + }, + "variables": Array [ + Object { + "$id": 4, + "defs": Array [ + Object { + "name": Object { + "name": "A", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 19, + 62, + ], + "type": "ClassDeclaration", + }, + "parent": undefined, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "A", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + ], + "name": "A", + "references": Array [], + "scope": Object { + "$ref": 7, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 2, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "s", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 10, + 18, + ], + "type": "CallExpression", + }, + }, + Object { + "$id": 3, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "Symbol", + "range": Array [ + 10, + 16, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 3, + }, + ], + "type": "global", + "upperScope": null, + "variableMap": Object { + "A": Object { + "$ref": 1, + }, + "s": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 8, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "s", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 6, + 18, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 18, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "s", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + ], + "name": "s", + "references": Array [ + Object { + "$ref": 2, + }, + Object { + "$ref": 5, + }, + Object { + "$ref": 6, + }, + ], + "scope": Object { + "$ref": 8, + }, + }, + Object { + "$id": 1, + "defs": Array [ + Object { + "name": Object { + "name": "A", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 19, + 62, + ], + "type": "ClassDeclaration", + }, + "parent": null, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "A", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + ], + "name": "A", + "references": Array [], + "scope": Object { + "$ref": 8, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/computed-properties-in-interface.ts 1`] = ` +Object { + "$id": 8, + "block": Object { + "range": Array [ + 0, + 110, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 2, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "s1", + "range": Array [ + 6, + 8, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 11, + 19, + ], + "type": "CallExpression", + }, + }, + Object { + "$id": 3, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "Symbol", + "range": Array [ + 11, + 17, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + Object { + "$id": 4, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "s2", + "range": Array [ + 21, + 23, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 1, + }, + "writeExpr": Object { + "range": Array [ + 26, + 34, + ], + "type": "CallExpression", + }, + }, + Object { + "$id": 5, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "Symbol", + "range": Array [ + 26, + 32, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + Object { + "$id": 6, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "s1", + "range": Array [ + 54, + 56, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 7, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "s2", + "range": Array [ + 71, + 73, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 1, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 3, + }, + Object { + "$ref": 5, + }, + ], + "type": "global", + "upperScope": null, + "variableMap": Object { + "s1": Object { + "$ref": 0, + }, + "s2": Object { + "$ref": 1, + }, + }, + "variableScope": Object { + "$ref": 8, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "s1", + "range": Array [ + 6, + 8, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 6, + 19, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 34, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "s1", + "range": Array [ + 6, + 8, + ], + "type": "Identifier", + }, + ], + "name": "s1", + "references": Array [ + Object { + "$ref": 2, + }, + Object { + "$ref": 6, + }, + ], + "scope": Object { + "$ref": 8, + }, + }, + Object { + "$id": 1, + "defs": Array [ + Object { + "name": Object { + "name": "s2", + "range": Array [ + 21, + 23, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 21, + 34, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 34, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "s2", + "range": Array [ + 21, + 23, + ], + "type": "Identifier", + }, + ], + "name": "s2", + "references": Array [ + Object { + "$ref": 4, + }, + Object { + "$ref": 7, + }, + ], + "scope": Object { + "$ref": 8, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/computed-properties-in-type.ts 1`] = ` +Object { + "$id": 8, + "block": Object { + "range": Array [ + 0, + 107, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 2, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "s1", + "range": Array [ + 6, + 8, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 11, + 19, + ], + "type": "CallExpression", + }, + }, + Object { + "$id": 3, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "Symbol", + "range": Array [ + 11, + 17, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + Object { + "$id": 4, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "s2", + "range": Array [ + 21, + 23, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 1, + }, + "writeExpr": Object { + "range": Array [ + 26, + 34, + ], + "type": "CallExpression", + }, + }, + Object { + "$id": 5, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "Symbol", + "range": Array [ + 26, + 32, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + Object { + "$id": 6, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "s1", + "range": Array [ + 51, + 53, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 7, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "s2", + "range": Array [ + 68, + 70, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 1, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 3, + }, + Object { + "$ref": 5, + }, + ], + "type": "global", + "upperScope": null, + "variableMap": Object { + "s1": Object { + "$ref": 0, + }, + "s2": Object { + "$ref": 1, + }, + }, + "variableScope": Object { + "$ref": 8, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "s1", + "range": Array [ + 6, + 8, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 6, + 19, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 34, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "s1", + "range": Array [ + 6, + 8, + ], + "type": "Identifier", + }, + ], + "name": "s1", + "references": Array [ + Object { + "$ref": 2, + }, + Object { + "$ref": 6, + }, + ], + "scope": Object { + "$ref": 8, + }, + }, + Object { + "$id": 1, + "defs": Array [ + Object { + "name": Object { + "name": "s2", + "range": Array [ + 21, + 23, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 21, + 34, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 34, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "s2", + "range": Array [ + 21, + 23, + ], + "type": "Identifier", + }, + ], + "name": "s2", + "references": Array [ + Object { + "$ref": 4, + }, + Object { + "$ref": 7, + }, + ], + "scope": Object { + "$ref": 8, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/declare-function.ts 1`] = ` +Object { + "$id": 2, + "block": Object { + "range": Array [ + 0, + 40, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 1, + "from": Object { + "$ref": 2, + }, + "identifier": Object { + "name": "f", + "range": Array [ + 38, + 39, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "f": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 2, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "f", + "range": Array [ + 17, + 18, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 37, + ], + "type": "TSEmptyBodyDeclareFunction", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "f", + "range": Array [ + 17, + 18, + ], + "type": "Identifier", + }, + ], + "name": "f", + "references": Array [ + Object { + "$ref": 1, + }, + ], + "scope": Object { + "$ref": 2, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/declare-global.ts 1`] = ` +Object { + "$id": 3, + "block": Object { + "range": Array [ + 0, + 55, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 2, + "block": Object { + "range": Array [ + 0, + 55, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 1, + "from": Object { + "$ref": 2, + }, + "identifier": Object { + "name": "C", + "range": Array [ + 38, + 39, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 42, + 43, + ], + "type": "Literal", + }, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 1, + }, + ], + "type": "module", + "upperScope": Object { + "$ref": 3, + }, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 2, + }, + "variables": Array [], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "C": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 3, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "C", + "range": Array [ + 25, + 34, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 25, + 34, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 21, + 34, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": true, + "identifiers": Array [ + Object { + "name": "C", + "range": Array [ + 25, + 34, + ], + "type": "Identifier", + }, + ], + "name": "C", + "references": Array [ + Object { + "$ref": 1, + }, + ], + "scope": Object { + "$ref": 3, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/declare-module.ts 1`] = ` +Object { + "$id": 8, + "block": Object { + "range": Array [ + 0, + 95, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 7, + "block": Object { + "range": Array [ + 0, + 95, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 6, + "block": Object { + "range": Array [ + 33, + 92, + ], + "type": "TSModuleBlock", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 5, + "from": Object { + "$ref": 6, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 89, + 90, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 3, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "block", + "upperScope": Object { + "$ref": 7, + }, + "variableMap": Object { + "a": Object { + "$ref": 3, + }, + "b": Object { + "$ref": 4, + }, + }, + "variableScope": Object { + "$ref": 7, + }, + "variables": Array [ + Object { + "$id": 3, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 52, + 61, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 52, + 61, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 46, + 61, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 52, + 61, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [ + Object { + "$ref": 5, + }, + ], + "scope": Object { + "$ref": 6, + }, + }, + Object { + "$id": 4, + "defs": Array [ + Object { + "name": Object { + "name": "b", + "range": Array [ + 79, + 90, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 79, + 90, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 73, + 90, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "b", + "range": Array [ + 79, + 90, + ], + "type": "Identifier", + }, + ], + "name": "b", + "references": Array [], + "scope": Object { + "$ref": 6, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 1, + "from": Object { + "$ref": 7, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 10, + 11, + ], + "type": "Literal", + }, + }, + Object { + "$id": 2, + "from": Object { + "$ref": 7, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 93, + 94, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "module", + "upperScope": Object { + "$ref": 8, + }, + "variableMap": Object { + "a": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 7, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 6, + 11, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 11, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [ + Object { + "$ref": 1, + }, + Object { + "$ref": 2, + }, + ], + "scope": Object { + "$ref": 7, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 8, + }, + "variables": Array [], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/decorators.ts 1`] = ` +Object { + "$id": 18, + "block": Object { + "range": Array [ + 0, + 198, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 6, + "block": Object { + "range": Array [ + 0, + 29, + ], + "type": "FunctionDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 18, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 4, + }, + "target": Object { + "$ref": 5, + }, + }, + "variableScope": Object { + "$ref": 6, + }, + "variables": Array [ + Object { + "$id": 4, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 6, + }, + }, + Object { + "$id": 5, + "defs": Array [ + Object { + "name": Object { + "name": "target", + "range": Array [ + 13, + 24, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 29, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "target", + "range": Array [ + 13, + 24, + ], + "type": "Identifier", + }, + ], + "name": "target", + "references": Array [], + "scope": Object { + "$ref": 6, + }, + }, + ], + }, + Object { + "$id": 11, + "block": Object { + "range": Array [ + 30, + 100, + ], + "type": "FunctionDeclaration", + }, + "childScopes": Array [ + Object { + "$id": 10, + "block": Object { + "range": Array [ + 58, + 98, + ], + "type": "ArrowFunctionExpression", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 11, + }, + "variableMap": Object { + "propertyKey": Object { + "$ref": 9, + }, + "target": Object { + "$ref": 8, + }, + }, + "variableScope": Object { + "$ref": 10, + }, + "variables": Array [ + Object { + "$id": 8, + "defs": Array [ + Object { + "name": Object { + "name": "target", + "range": Array [ + 59, + 70, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 58, + 98, + ], + "type": "ArrowFunctionExpression", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "target", + "range": Array [ + 59, + 70, + ], + "type": "Identifier", + }, + ], + "name": "target", + "references": Array [], + "scope": Object { + "$ref": 10, + }, + }, + Object { + "$id": 9, + "defs": Array [ + Object { + "name": Object { + "name": "propertyKey", + "range": Array [ + 72, + 91, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 58, + 98, + ], + "type": "ArrowFunctionExpression", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "propertyKey", + "range": Array [ + 72, + 91, + ], + "type": "Identifier", + }, + ], + "name": "propertyKey", + "references": Array [], + "scope": Object { + "$ref": 10, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 18, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 7, + }, + }, + "variableScope": Object { + "$ref": 11, + }, + "variables": Array [ + Object { + "$id": 7, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 11, + }, + }, + ], + }, + Object { + "$id": 17, + "block": Object { + "range": Array [ + 102, + 197, + ], + "type": "ClassDeclaration", + }, + "childScopes": Array [ + Object { + "$id": 16, + "block": Object { + "range": Array [ + 159, + 195, + ], + "type": "FunctionExpression", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 17, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 15, + }, + }, + "variableScope": Object { + "$ref": 16, + }, + "variables": Array [ + Object { + "$id": 15, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 16, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 13, + "from": Object { + "$ref": 17, + }, + "identifier": Object { + "name": "gec", + "range": Array [ + 122, + 125, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 1, + }, + "writeExpr": undefined, + }, + Object { + "$id": 14, + "from": Object { + "$ref": 17, + }, + "identifier": Object { + "name": "gec", + "range": Array [ + 147, + 150, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 1, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 13, + }, + Object { + "$ref": 14, + }, + ], + "type": "class", + "upperScope": Object { + "$ref": 18, + }, + "variableMap": Object { + "C": Object { + "$ref": 12, + }, + }, + "variableScope": Object { + "$ref": 18, + }, + "variables": Array [ + Object { + "$id": 12, + "defs": Array [ + Object { + "name": Object { + "name": "C", + "range": Array [ + 113, + 114, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 102, + 197, + ], + "type": "ClassDeclaration", + }, + "parent": undefined, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "C", + "range": Array [ + 113, + 114, + ], + "type": "Identifier", + }, + ], + "name": "C", + "references": Array [], + "scope": Object { + "$ref": 17, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 3, + "from": Object { + "$ref": 18, + }, + "identifier": Object { + "name": "dec", + "range": Array [ + 103, + 106, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "C": Object { + "$ref": 2, + }, + "dec": Object { + "$ref": 0, + }, + "gec": Object { + "$ref": 1, + }, + }, + "variableScope": Object { + "$ref": 18, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "dec", + "range": Array [ + 9, + 12, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 29, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "dec", + "range": Array [ + 9, + 12, + ], + "type": "Identifier", + }, + ], + "name": "dec", + "references": Array [ + Object { + "$ref": 3, + }, + ], + "scope": Object { + "$ref": 18, + }, + }, + Object { + "$id": 1, + "defs": Array [ + Object { + "name": Object { + "name": "gec", + "range": Array [ + 39, + 42, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 30, + 100, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "gec", + "range": Array [ + 39, + 42, + ], + "type": "Identifier", + }, + ], + "name": "gec", + "references": Array [ + Object { + "$ref": 13, + }, + Object { + "$ref": 14, + }, + ], + "scope": Object { + "$ref": 18, + }, + }, + Object { + "$id": 2, + "defs": Array [ + Object { + "name": Object { + "name": "C", + "range": Array [ + 113, + 114, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 102, + 197, + ], + "type": "ClassDeclaration", + }, + "parent": null, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "C", + "range": Array [ + 113, + 114, + ], + "type": "Identifier", + }, + ], + "name": "C", + "references": Array [], + "scope": Object { + "$ref": 18, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/enum.ts 1`] = ` +Object { + "$id": 14, + "block": Object { + "range": Array [ + 0, + 71, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 13, + "block": Object { + "range": Array [ + 20, + 70, + ], + "type": "TSEnumDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 6, + "from": Object { + "$ref": 13, + }, + "identifier": Object { + "name": "A", + "range": Array [ + 33, + 34, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 3, + }, + "writeExpr": Object { + "name": "a", + "range": Array [ + 37, + 38, + ], + "type": "Identifier", + }, + }, + Object { + "$id": 7, + "from": Object { + "$ref": 13, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 37, + 38, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 8, + "from": Object { + "$ref": 13, + }, + "identifier": Object { + "name": "B", + "range": Array [ + 44, + 45, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 4, + }, + "writeExpr": Object { + "range": Array [ + 48, + 53, + ], + "type": "BinaryExpression", + }, + }, + Object { + "$id": 9, + "from": Object { + "$ref": 13, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 48, + 49, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 10, + "from": Object { + "$ref": 13, + }, + "identifier": Object { + "name": "C", + "range": Array [ + 59, + 60, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 5, + }, + "writeExpr": Object { + "range": Array [ + 63, + 68, + ], + "type": "BinaryExpression", + }, + }, + Object { + "$id": 11, + "from": Object { + "$ref": 13, + }, + "identifier": Object { + "name": "A", + "range": Array [ + 63, + 64, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 3, + }, + "writeExpr": undefined, + }, + Object { + "$id": 12, + "from": Object { + "$ref": 13, + }, + "identifier": Object { + "name": "B", + "range": Array [ + 67, + 68, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 4, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 7, + }, + Object { + "$ref": 9, + }, + ], + "type": "enum", + "upperScope": Object { + "$ref": 14, + }, + "variableMap": Object { + "A": Object { + "$ref": 3, + }, + "B": Object { + "$ref": 4, + }, + "C": Object { + "$ref": 5, + }, + }, + "variableScope": Object { + "$ref": 14, + }, + "variables": Array [ + Object { + "$id": 3, + "defs": Array [ + Object { + "name": Object { + "name": "A", + "range": Array [ + 33, + 34, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 33, + 38, + ], + "type": "TSEnumMember", + }, + "parent": undefined, + "type": "EnumMemberName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "A", + "range": Array [ + 33, + 34, + ], + "type": "Identifier", + }, + ], + "name": "A", + "references": Array [ + Object { + "$ref": 6, + }, + Object { + "$ref": 11, + }, + ], + "scope": Object { + "$ref": 13, + }, + }, + Object { + "$id": 4, + "defs": Array [ + Object { + "name": Object { + "name": "B", + "range": Array [ + 44, + 45, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 44, + 53, + ], + "type": "TSEnumMember", + }, + "parent": undefined, + "type": "EnumMemberName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "B", + "range": Array [ + 44, + 45, + ], + "type": "Identifier", + }, + ], + "name": "B", + "references": Array [ + Object { + "$ref": 8, + }, + Object { + "$ref": 12, + }, + ], + "scope": Object { + "$ref": 13, + }, + }, + Object { + "$id": 5, + "defs": Array [ + Object { + "name": Object { + "name": "C", + "range": Array [ + 59, + 60, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 59, + 68, + ], + "type": "TSEnumMember", + }, + "parent": undefined, + "type": "EnumMemberName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "C", + "range": Array [ + 59, + 60, + ], + "type": "Identifier", + }, + ], + "name": "C", + "references": Array [ + Object { + "$ref": 10, + }, + ], + "scope": Object { + "$ref": 13, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 2, + "from": Object { + "$ref": 14, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 6, + 15, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 18, + 19, + ], + "type": "Literal", + }, + }, + ], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "E": Object { + "$ref": 1, + }, + "a": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 14, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 6, + 15, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 6, + 19, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 19, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 6, + 15, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [ + Object { + "$ref": 2, + }, + Object { + "$ref": 7, + }, + Object { + "$ref": 9, + }, + ], + "scope": Object { + "$ref": 14, + }, + }, + Object { + "$id": 1, + "defs": Array [ + Object { + "name": Object { + "name": "E", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 20, + 70, + ], + "type": "TSEnumDeclaration", + }, + "parent": undefined, + "type": "EnumName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "E", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + ], + "name": "E", + "references": Array [], + "scope": Object { + "$ref": 14, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/function-overload.ts 1`] = ` +Object { + "$id": 4, + "block": Object { + "range": Array [ + 0, + 101, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 3, + "block": Object { + "range": Array [ + 47, + 100, + ], + "type": "FunctionDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 4, + }, + "variableMap": Object { + "a": Object { + "$ref": 2, + }, + "arguments": Object { + "$ref": 1, + }, + }, + "variableScope": Object { + "$ref": 3, + }, + "variables": Array [ + Object { + "$id": 1, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 3, + }, + }, + Object { + "$id": 2, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 58, + 68, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 47, + 100, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 58, + 68, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [], + "scope": Object { + "$ref": 3, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "f": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 4, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "f", + "range": Array [ + 56, + 57, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 47, + 100, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "f", + "range": Array [ + 56, + 57, + ], + "type": "Identifier", + }, + ], + "name": "f", + "references": Array [], + "scope": Object { + "$ref": 4, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/function-overload-2.ts 1`] = ` +Object { + "$id": 1, + "block": Object { + "range": Array [ + 0, + 47, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "f": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 1, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "f", + "range": Array [ + 9, + 10, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 18, + ], + "type": "TSEmptyBodyFunctionDeclaration", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "f", + "range": Array [ + 9, + 10, + ], + "type": "Identifier", + }, + ], + "name": "f", + "references": Array [], + "scope": Object { + "$ref": 1, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/ignore-type-only-stuff.ts 1`] = ` +Object { + "$id": 1, + "block": Object { + "range": Array [ + 0, + 115, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "a": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 1, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 110, + 114, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 110, + 114, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 106, + 114, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 110, + 114, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [], + "scope": Object { + "$ref": 1, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/method-overload.ts 1`] = ` +Object { + "$id": 10, + "block": Object { + "range": Array [ + 0, + 124, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 9, + "block": Object { + "range": Array [ + 19, + 123, + ], + "type": "ClassDeclaration", + }, + "childScopes": Array [ + Object { + "$id": 8, + "block": Object { + "range": Array [ + 73, + 121, + ], + "type": "FunctionExpression", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 9, + }, + "variableMap": Object { + "a": Object { + "$ref": 7, + }, + "arguments": Object { + "$ref": 6, + }, + }, + "variableScope": Object { + "$ref": 8, + }, + "variables": Array [ + Object { + "$id": 6, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 8, + }, + }, + Object { + "$id": 7, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 74, + 81, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 73, + 121, + ], + "type": "FunctionExpression", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 74, + 81, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [], + "scope": Object { + "$ref": 8, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 5, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "s", + "range": Array [ + 59, + 60, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 5, + }, + ], + "type": "class", + "upperScope": Object { + "$ref": 10, + }, + "variableMap": Object { + "A": Object { + "$ref": 4, + }, + }, + "variableScope": Object { + "$ref": 10, + }, + "variables": Array [ + Object { + "$id": 4, + "defs": Array [ + Object { + "name": Object { + "name": "A", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 19, + 123, + ], + "type": "ClassDeclaration", + }, + "parent": undefined, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "A", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + ], + "name": "A", + "references": Array [], + "scope": Object { + "$ref": 9, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 2, + "from": Object { + "$ref": 10, + }, + "identifier": Object { + "name": "s", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 10, + 18, + ], + "type": "CallExpression", + }, + }, + Object { + "$id": 3, + "from": Object { + "$ref": 10, + }, + "identifier": Object { + "name": "Symbol", + "range": Array [ + 10, + 16, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 3, + }, + ], + "type": "global", + "upperScope": null, + "variableMap": Object { + "A": Object { + "$ref": 1, + }, + "s": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 10, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "s", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 6, + 18, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 18, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "s", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + ], + "name": "s", + "references": Array [ + Object { + "$ref": 2, + }, + Object { + "$ref": 5, + }, + ], + "scope": Object { + "$ref": 10, + }, + }, + Object { + "$id": 1, + "defs": Array [ + Object { + "name": Object { + "name": "A", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 19, + 123, + ], + "type": "ClassDeclaration", + }, + "parent": null, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "A", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + ], + "name": "A", + "references": Array [], + "scope": Object { + "$ref": 10, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/namespace.ts 1`] = ` +Object { + "$id": 10, + "block": Object { + "range": Array [ + 0, + 63, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 9, + "block": Object { + "range": Array [ + 0, + 63, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 8, + "block": Object { + "range": Array [ + 24, + 56, + ], + "type": "TSModuleBlock", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 6, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 43, + 44, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 5, + }, + "writeExpr": Object { + "range": Array [ + 47, + 48, + ], + "type": "Literal", + }, + }, + Object { + "$id": 7, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 53, + 54, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 5, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "block", + "upperScope": Object { + "$ref": 9, + }, + "variableMap": Object { + "a": Object { + "$ref": 5, + }, + }, + "variableScope": Object { + "$ref": 9, + }, + "variables": Array [ + Object { + "$id": 5, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 43, + 44, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 43, + 48, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 37, + 48, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 43, + 44, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [ + Object { + "$ref": 6, + }, + Object { + "$ref": 7, + }, + ], + "scope": Object { + "$ref": 8, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 2, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 10, + 11, + ], + "type": "Literal", + }, + }, + Object { + "$id": 3, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 57, + 58, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 4, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "N", + "range": Array [ + 59, + 60, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 1, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "module", + "upperScope": Object { + "$ref": 10, + }, + "variableMap": Object { + "N": Object { + "$ref": 1, + }, + "a": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 9, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 6, + 11, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 11, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [ + Object { + "$ref": 2, + }, + Object { + "$ref": 3, + }, + ], + "scope": Object { + "$ref": 9, + }, + }, + Object { + "$id": 1, + "defs": Array [ + Object { + "name": Object { + "name": "N", + "range": Array [ + 22, + 23, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 12, + 56, + ], + "type": "TSModuleDeclaration", + }, + "parent": null, + "type": "NamespaceName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "N", + "range": Array [ + 22, + 23, + ], + "type": "Identifier", + }, + ], + "name": "N", + "references": Array [ + Object { + "$ref": 4, + }, + ], + "scope": Object { + "$ref": 9, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 10, + }, + "variables": Array [], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/type-annotations.ts 1`] = ` +Object { + "$id": 7, + "block": Object { + "range": Array [ + 0, + 103, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 6, + "block": Object { + "range": Array [ + 32, + 102, + ], + "type": "ClassDeclaration", + }, + "childScopes": Array [ + Object { + "$id": 5, + "block": Object { + "range": Array [ + 47, + 100, + ], + "type": "FunctionExpression", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 6, + }, + "variableMap": Object { + "a": Object { + "$ref": 4, + }, + "arguments": Object { + "$ref": 3, + }, + }, + "variableScope": Object { + "$ref": 5, + }, + "variables": Array [ + Object { + "$id": 3, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 5, + }, + }, + Object { + "$id": 4, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 48, + 59, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 47, + 100, + ], + "type": "FunctionExpression", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 48, + 59, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [], + "scope": Object { + "$ref": 5, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "class", + "upperScope": Object { + "$ref": 7, + }, + "variableMap": Object { + "C": Object { + "$ref": 2, + }, + }, + "variableScope": Object { + "$ref": 7, + }, + "variables": Array [ + Object { + "$id": 2, + "defs": Array [ + Object { + "name": Object { + "name": "C", + "range": Array [ + 38, + 39, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 32, + 102, + ], + "type": "ClassDeclaration", + }, + "parent": undefined, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "C", + "range": Array [ + 38, + 39, + ], + "type": "Identifier", + }, + ], + "name": "C", + "references": Array [], + "scope": Object { + "$ref": 6, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "C": Object { + "$ref": 1, + }, + "a": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 7, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 20, + 31, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 20, + 31, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 16, + 31, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 20, + 31, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [], + "scope": Object { + "$ref": 7, + }, + }, + Object { + "$id": 1, + "defs": Array [ + Object { + "name": Object { + "name": "C", + "range": Array [ + 38, + 39, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 32, + 102, + ], + "type": "ClassDeclaration", + }, + "parent": null, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "C", + "range": Array [ + 38, + 39, + ], + "type": "Identifier", + }, + ], + "name": "C", + "references": Array [], + "scope": Object { + "$ref": 7, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/type-assertions.ts 1`] = ` +Object { + "$id": 4, + "block": Object { + "range": Array [ + 0, + 40, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 0, + "from": Object { + "$ref": 4, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 17, + 18, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": null, + "writeExpr": Object { + "range": Array [ + 21, + 26, + ], + "type": "TSTypeAssertionExpression", + }, + }, + Object { + "$id": 1, + "from": Object { + "$ref": 4, + }, + "identifier": Object { + "name": "b", + "range": Array [ + 25, + 26, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + Object { + "$id": 2, + "from": Object { + "$ref": 4, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 28, + 29, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": null, + "writeExpr": Object { + "range": Array [ + 32, + 38, + ], + "type": "TSAsExpression", + }, + }, + Object { + "$id": 3, + "from": Object { + "$ref": 4, + }, + "identifier": Object { + "name": "b", + "range": Array [ + 32, + 33, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 0, + }, + Object { + "$ref": 1, + }, + Object { + "$ref": 2, + }, + Object { + "$ref": 3, + }, + ], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 4, + }, + "variables": Array [], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/typeof.ts 1`] = ` +Object { + "$id": 3, + "block": Object { + "range": Array [ + 0, + 43, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 1, + "from": Object { + "$ref": 3, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 4, + 7, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 10, + 22, + ], + "type": "ObjectExpression", + }, + }, + Object { + "$id": 2, + "from": Object { + "$ref": 3, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 39, + 42, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "obj": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 3, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "obj", + "range": Array [ + 4, + 7, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 4, + 22, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 22, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "obj", + "range": Array [ + 4, + 7, + ], + "type": "Identifier", + }, + ], + "name": "obj", + "references": Array [ + Object { + "$ref": 1, + }, + Object { + "$ref": 2, + }, + ], + "scope": Object { + "$ref": 3, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/typeof-in-assertions.ts 1`] = ` +Object { + "$id": 8, + "block": Object { + "range": Array [ + 0, + 63, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 1, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 4, + 7, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 10, + 22, + ], + "type": "ObjectExpression", + }, + }, + Object { + "$id": 2, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 23, + 24, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": null, + "writeExpr": Object { + "range": Array [ + 27, + 40, + ], + "type": "TSTypeAssertionExpression", + }, + }, + Object { + "$id": 3, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 35, + 38, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 4, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "b", + "range": Array [ + 39, + 40, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + Object { + "$id": 5, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 42, + 43, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": null, + "writeExpr": Object { + "range": Array [ + 46, + 61, + ], + "type": "TSAsExpression", + }, + }, + Object { + "$id": 6, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "b", + "range": Array [ + 46, + 47, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + Object { + "$id": 7, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 58, + 61, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 2, + }, + Object { + "$ref": 4, + }, + Object { + "$ref": 5, + }, + Object { + "$ref": 6, + }, + ], + "type": "global", + "upperScope": null, + "variableMap": Object { + "obj": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 8, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "obj", + "range": Array [ + 4, + 7, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 4, + 22, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 22, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "obj", + "range": Array [ + 4, + 7, + ], + "type": "Identifier", + }, + ], + "name": "obj", + "references": Array [ + Object { + "$ref": 1, + }, + Object { + "$ref": 3, + }, + Object { + "$ref": 7, + }, + ], + "scope": Object { + "$ref": 8, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/typeof-in-call-signature.ts 1`] = ` +Object { + "$id": 8, + "block": Object { + "range": Array [ + 0, + 165, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 1, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 6, + 9, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 12, + 24, + ], + "type": "ObjectExpression", + }, + }, + Object { + "$id": 2, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 61, + 64, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 3, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 76, + 79, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 4, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 95, + 98, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 5, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 125, + 128, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 6, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 140, + 143, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 7, + "from": Object { + "$ref": 8, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 159, + 162, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "obj": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 8, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "obj", + "range": Array [ + 6, + 9, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 6, + 24, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 24, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "obj", + "range": Array [ + 6, + 9, + ], + "type": "Identifier", + }, + ], + "name": "obj", + "references": Array [ + Object { + "$ref": 1, + }, + Object { + "$ref": 2, + }, + Object { + "$ref": 3, + }, + Object { + "$ref": 4, + }, + Object { + "$ref": 5, + }, + Object { + "$ref": 6, + }, + Object { + "$ref": 7, + }, + ], + "scope": Object { + "$ref": 8, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/typeof-in-return-type.ts 1`] = ` +Object { + "$id": 5, + "block": Object { + "range": Array [ + 0, + 83, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 4, + "block": Object { + "range": Array [ + 0, + 82, + ], + "type": "FunctionDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 3, + "from": Object { + "$ref": 4, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 30, + 31, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 5, + }, + "variableMap": Object { + "a": Object { + "$ref": 2, + }, + "arguments": Object { + "$ref": 1, + }, + }, + "variableScope": Object { + "$ref": 4, + }, + "variables": Array [ + Object { + "$id": 1, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 4, + }, + }, + Object { + "$id": 2, + "defs": Array [ + Object { + "name": Object { + "name": "a", + "range": Array [ + 11, + 20, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 82, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "a", + "range": Array [ + 11, + 20, + ], + "type": "Identifier", + }, + ], + "name": "a", + "references": Array [ + Object { + "$ref": 3, + }, + ], + "scope": Object { + "$ref": 4, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "f": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 5, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "f", + "range": Array [ + 9, + 10, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 82, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "f", + "range": Array [ + 9, + 10, + ], + "type": "Identifier", + }, + ], + "name": "f", + "references": Array [], + "scope": Object { + "$ref": 5, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/typeof-in-type-parameters.ts 1`] = ` +Object { + "$id": 5, + "block": Object { + "range": Array [ + 0, + 62, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 4, + "block": Object { + "range": Array [ + 0, + 61, + ], + "type": "FunctionDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 5, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 2, + }, + "g": Object { + "$ref": 3, + }, + }, + "variableScope": Object { + "$ref": 4, + }, + "variables": Array [ + Object { + "$id": 2, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 4, + }, + }, + Object { + "$id": 3, + "defs": Array [ + Object { + "name": Object { + "name": "g", + "range": Array [ + 31, + 35, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 61, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "g", + "range": Array [ + 31, + 35, + ], + "type": "Identifier", + }, + ], + "name": "g", + "references": Array [], + "scope": Object { + "$ref": 4, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 1, + "from": Object { + "$ref": 5, + }, + "identifier": Object { + "name": "g", + "range": Array [ + 28, + 29, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "g": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 5, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "g", + "range": Array [ + 9, + 10, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 61, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "g", + "range": Array [ + 9, + 10, + ], + "type": "Identifier", + }, + ], + "name": "g", + "references": Array [ + Object { + "$ref": 1, + }, + ], + "scope": Object { + "$ref": 5, + }, + }, + ], +} +`; + +exports[`TypeScript scope analysis tests/fixtures/scope-analysis/typeof-in-var.ts 1`] = ` +Object { + "$id": 11, + "block": Object { + "range": Array [ + 0, + 147, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [ + Object { + "$id": 4, + "from": Object { + "$ref": 11, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 4, + 7, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 10, + 22, + ], + "type": "ObjectExpression", + }, + }, + Object { + "$id": 5, + "from": Object { + "$ref": 11, + }, + "identifier": Object { + "name": "obj2", + "range": Array [ + 27, + 43, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 1, + }, + "writeExpr": Object { + "range": Array [ + 46, + 58, + ], + "type": "ObjectExpression", + }, + }, + Object { + "$id": 6, + "from": Object { + "$ref": 11, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 40, + 43, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 7, + "from": Object { + "$ref": 11, + }, + "identifier": Object { + "name": "value", + "range": Array [ + 65, + 70, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": Object { + "range": Array [ + 87, + 99, + ], + "type": "ObjectExpression", + }, + }, + Object { + "$id": 8, + "from": Object { + "$ref": 11, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 81, + 84, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 9, + "from": Object { + "$ref": 11, + }, + "identifier": Object { + "name": "element", + "range": Array [ + 105, + 112, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 3, + }, + "writeExpr": Object { + "range": Array [ + 132, + 146, + ], + "type": "ArrayExpression", + }, + }, + Object { + "$id": 10, + "from": Object { + "$ref": 11, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 123, + 126, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object { + "element": Object { + "$ref": 3, + }, + "obj": Object { + "$ref": 0, + }, + "obj2": Object { + "$ref": 1, + }, + "value": Object { + "$ref": 2, + }, + }, + "variableScope": Object { + "$ref": 11, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "obj", + "range": Array [ + 4, + 7, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 4, + 22, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 22, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "obj", + "range": Array [ + 4, + 7, + ], + "type": "Identifier", + }, + ], + "name": "obj", + "references": Array [ + Object { + "$ref": 4, + }, + Object { + "$ref": 6, + }, + Object { + "$ref": 8, + }, + Object { + "$ref": 10, + }, + ], + "scope": Object { + "$ref": 11, + }, + }, + Object { + "$id": 1, + "defs": Array [ + Object { + "name": Object { + "name": "obj2", + "range": Array [ + 27, + 43, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 27, + 58, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 23, + 58, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "obj2", + "range": Array [ + 27, + 43, + ], + "type": "Identifier", + }, + ], + "name": "obj2", + "references": Array [ + Object { + "$ref": 5, + }, + ], + "scope": Object { + "$ref": 11, + }, + }, + Object { + "$id": 2, + "defs": Array [ + Object { + "name": Object { + "name": "value", + "range": Array [ + 65, + 70, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 63, + 99, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 59, + 99, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "value", + "range": Array [ + 65, + 70, + ], + "type": "Identifier", + }, + ], + "name": "value", + "references": Array [ + Object { + "$ref": 7, + }, + ], + "scope": Object { + "$ref": 11, + }, + }, + Object { + "$id": 3, + "defs": Array [ + Object { + "name": Object { + "name": "element", + "range": Array [ + 105, + 112, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 104, + 146, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 100, + 146, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "element", + "range": Array [ + 105, + 112, + ], + "type": "Identifier", + }, + ], + "name": "element", + "references": Array [ + Object { + "$ref": 9, + }, + ], + "scope": Object { + "$ref": 11, + }, + }, + ], +} +`; diff --git a/tests/lib/basics.js b/tests/lib/basics.js index 0217f66..6542baf 100644 --- a/tests/lib/basics.js +++ b/tests/lib/basics.js @@ -12,9 +12,12 @@ // Requirements //------------------------------------------------------------------------------ -const path = require("path"), +const + path = require("path"), + { Linter } = require("eslint"), shelljs = require("shelljs"), - testUtils = require("../../tools/test-utils"); + testUtils = require("../../tools/test-utils"), + parser = require("../../"); //------------------------------------------------------------------------------ // Setup @@ -36,4 +39,56 @@ describe("basics", () => { const code = shelljs.cat(`${path.resolve(FIXTURES_DIR, filename)}.src.js`); test(`fixtures/${filename}.src`, testUtils.createSnapshotTestBlock(code)); }); + + test("https://github.com/eslint/typescript-eslint-parser/issues/476", () => { + const linter = new Linter(); + const code = ` +export const Price: React.SFC = function Price(props) {} +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + test: "error" + } + }; + + linter.defineParser("typescript-eslint-parser", parser); + linter.defineRule("test", context => ({ + TSTypeReference(node) { + const name = context.getSourceCode().getText(node.typeName); + context.report({ + node, + message: "called on {{name}}", + data: { name } + }); + } + })); + + const messages = linter.verify(code, config, { filename: "issue.ts" }); + + expect(messages).toStrictEqual([ + { + column: 21, + endColumn: 42, + endLine: 2, + line: 2, + message: "called on React.SFC", + nodeType: "TSTypeReference", + ruleId: "test", + severity: 2, + source: "export const Price: React.SFC = function Price(props) {}" + }, + { + column: 31, + endColumn: 41, + endLine: 2, + line: 2, + message: "called on PriceProps", + nodeType: "TSTypeReference", + ruleId: "test", + severity: 2, + source: "export const Price: React.SFC = function Price(props) {}" + } + ]); + }); }); diff --git a/tests/lib/scope-analysis.js b/tests/lib/scope-analysis.js new file mode 100644 index 0000000..6fb0f9a --- /dev/null +++ b/tests/lib/scope-analysis.js @@ -0,0 +1,354 @@ +/** + * @fileoverview Tests for TypeScript-specific scope analysis + * @author Toru Nagashima + */ +"use strict"; + +const fs = require("fs"); +const path = require("path"); +const { Linter } = require("eslint"); +const parser = require("../.."); + +/** Reference resolver. */ +class ReferenceResolver { + constructor() { + this.map = new Map(); + } + + resolve(obj, properties) { + const resolved = Object.assign({ $id: this.map.size }, properties); + this.map.set(obj, resolved); + return resolved; + } + + ref(obj) { + if (typeof obj !== "object" || obj === null) { + return obj; + } + + const { map } = this; + return { + get $ref() { + return map.get(obj).$id; + } + }; + } +} + +/** + * Convert a given node object to JSON object. + * This saves only type and range to know what the node is. + * @param {ASTNode} node The AST node object. + * @returns {Object} The object that can be used for JSON.stringify. + */ +function nodeToJSON(node) { + if (!node) { + return node; + } + + const { type, name, range } = node; + if (node.type === "Identifier") { + return { type, name, range }; + } + return { type, range }; +} + +/** + * Convert a given variable object to JSON object. + * @param {Variable} variable The eslint-scope's variable object. + * @param {ReferenceResolver} resolver The reference resolver. + * @returns {Object} The object that can be used for JSON.stringify. + */ +function variableToJSON(variable, resolver) { + const { name, eslintUsed } = variable; + const defs = variable.defs.map(d => ({ + type: d.type, + name: nodeToJSON(d.name), + node: nodeToJSON(d.node), + parent: nodeToJSON(d.parent) + })); + const identifiers = variable.identifiers.map(nodeToJSON); + const references = variable.references.map(resolver.ref, resolver); + const scope = resolver.ref(variable.scope); + + return resolver.resolve(variable, { + name, + defs, + identifiers, + references, + scope, + eslintUsed + }); +} + +/** + * Convert a given reference object to JSON object. + * @param {Reference} reference The eslint-scope's reference object. + * @param {ReferenceResolver} resolver The reference resolver. + * @returns {Object} The object that can be used for JSON.stringify. + */ +function referenceToJSON(reference, resolver) { + const kind = `${reference.isRead() ? "r" : ""}${reference.isWrite() ? "w" : ""}`; + const from = resolver.ref(reference.from); + const identifier = nodeToJSON(reference.identifier); + const writeExpr = nodeToJSON(reference.writeExpr); + const resolved = resolver.ref(reference.resolved); + + return resolver.resolve(reference, { + kind, + from, + identifier, + writeExpr, + resolved + }); +} + +/** + * Convert a given scope object to JSON object. + * @param {Scope} scope The eslint-scope's scope object. + * @param {ReferenceResolver} resolver The reference resolver. + * @returns {Object} The object that can be used for JSON.stringify. + */ +function scopeToJSON(scope, resolver = new ReferenceResolver()) { + const { type, functionExpressionScope, isStrict } = scope; + const block = nodeToJSON(scope.block); + const variables = scope.variables.map(v => variableToJSON(v, resolver)); + const references = scope.references.map(r => referenceToJSON(r, resolver)); + const variableMap = Array.from(scope.set.entries()).reduce((map, [name, variable]) => { + map[name] = resolver.ref(variable); + return map; + }, {}); + const throughReferences = scope.through.map(resolver.ref, resolver); + const variableScope = resolver.ref(scope.variableScope); + const upperScope = resolver.ref(scope.upper); + const childScopes = scope.childScopes.map(c => scopeToJSON(c, resolver)); + + return resolver.resolve(scope, { + type, + functionExpressionScope, + isStrict, + block, + variables, + references, + variableMap, + throughReferences, + variableScope, + upperScope, + childScopes + }); +} + +describe("TypeScript scope analysis", () => { + const root = "tests/fixtures/scope-analysis"; + const files = fs.readdirSync(root).map(filename => path.join(root, filename).replace(/\\/g, "/")); + + for (const filePath of files) { + test(filePath, () => { + const code = fs.readFileSync(filePath, "utf8"); + const { scopeManager } = parser.parseForESLint(code, { + loc: true, + range: true, + tokens: true, + ecmaFeatures: {} + }); + const { globalScope } = scopeManager; + + // Do the postprocess to test. + // https://github.com/eslint/eslint/blob/4fe328787dd02d7a1f6fc21167f6175c860825e3/lib/linter.js#L222 + globalScope.through = globalScope.through.filter(reference => { + const name = reference.identifier.name; + const variable = globalScope.set.get(name); + if (variable) { + reference.resolved = variable; + variable.references.push(reference); + return false; + } + return true; + }); + + const scopeTree = scopeToJSON(globalScope); + expect(scopeTree).toMatchSnapshot(); + }); + } + + const linter = new Linter(); + linter.defineParser("typescript-eslint-parser", parser); + + test("https://github.com/eslint/typescript-eslint-parser/issues/416", () => { + const code = ` +export type SomeThing = { + id: string; +} +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + "no-undef": "error" + } + }; + const messages = linter.verify(code, config, { filename: "issue416.ts" }); + + expect(messages).toStrictEqual([]); + }); + + test("https://github.com/eslint/typescript-eslint-parser/issues/435", () => { + const code = ` +interface Foo { + bar: string +} +const bar = 'blah' +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + "no-use-before-define": "error" + } + }; + const messages = linter.verify(code, config, { filename: "issue435.ts" }); + + expect(messages).toStrictEqual([]); + }); + + test("https://github.com/eslint/typescript-eslint-parser/issues/437", () => { + const code = ` +interface Runnable { + run (): Result + toString (): string +} +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + "no-undef": "error" + } + }; + const messages = linter.verify(code, config, { filename: "issue437.ts" }); + + expect(messages).toStrictEqual([]); + }); + + test("https://github.com/eslint/typescript-eslint-parser/issues/443", () => { + const code = ` +const Foo = 1; +type Foo = 1; +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + "no-redeclare": "error" + } + }; + const messages = linter.verify(code, config, { filename: "issue443.ts" }); + + expect(messages).toStrictEqual([]); + }); + + test("https://github.com/eslint/typescript-eslint-parser/issues/459", () => { + const code = ` +type foo = any; +function bar(foo: any) {} +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + "no-shadow": "error" + } + }; + const messages = linter.verify(code, config, { filename: "issue.ts" }); + + expect(messages).toStrictEqual([]); + }); + + test("https://github.com/eslint/typescript-eslint-parser/issues/466", () => { + const code = ` +/*globals document, selector */ +const links = document.querySelectorAll( selector ) as NodeListOf +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + "no-undef": "error" + } + }; + const messages = linter.verify(code, config, { filename: "issue.ts" }); + + expect(messages).toStrictEqual([]); + }); + + test("https://github.com/eslint/typescript-eslint-parser/issues/471", () => { + const code = ` +class X { + field = {} +} +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + "no-undef": "error" + } + }; + const messages = linter.verify(code, config, { filename: "issue.ts" }); + + expect(messages).toStrictEqual([]); + }); + + test("https://github.com/eslint/typescript-eslint-parser/issues/487", () => { + const code = ` +export default class Test { + private status: string; + getStatus() { + return this.status; + } +} +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + "no-restricted-globals": ["error", "status"] + } + }; + const messages = linter.verify(code, config, { filename: "issue.ts" }); + + expect(messages).toStrictEqual([]); + }); + + test("https://github.com/eslint/typescript-eslint-parser/issues/535", () => { + const code = ` +function foo({ bar }: { bar: string }) { + console.log(bar); +} +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + "no-dupe-args": "error", + "no-redeclare": "error" + } + }; + const messages = linter.verify(code, config, { filename: "issue.ts" }); + + expect(messages).toStrictEqual([]); + }); + + test("https://github.com/eslint/typescript-eslint-parser/issues/535", () => { + const code = ` +import { + observable, +} from 'mobx'; + +export default class ListModalStore { + @observable + orderList: IObservableArray = observable([]); +} +`; + const config = { + parser: "typescript-eslint-parser", + rules: { + "no-unused-vars": "error" + } + }; + const messages = linter.verify(code, config, { filename: "issue.ts" }); + + expect(messages).toStrictEqual([]); + }); +}); diff --git a/visitor-keys.js b/visitor-keys.js index 18cf592..2fbefd5 100644 --- a/visitor-keys.js +++ b/visitor-keys.js @@ -9,28 +9,20 @@ const Evk = require("eslint-visitor-keys"); module.exports = Evk.unionWith({ - ArrayPattern: ["typeAnnotation"], - ArrowFunctionExpression: ["returnType", "typeParameters"], - AssignmentPattern: ["typeAnnotation"], - CallExpression: ["typeParameters"], - ClassDeclaration: ["superTypeParameters", "typeParameters"], - ClassExpression: ["superTypeParameters", "typeParameters"], - ClassImplements: ["typeParameters"], - ClassProperty: ["typeAnnotation"], - FunctionDeclaration: ["returnType", "typeParameters"], - FunctionExpression: ["returnType", "typeParameters"], + // Additional Properties. + ArrayPattern: ["elements", "typeAnnotation"], + ArrowFunctionExpression: ["typeParameters", "params", "returnType", "body"], + ClassDeclaration: ["decorators", "id", "typeParameters", "superClass", "body"], + ClassExpression: ["decorators", "id", "typeParameters", "superClass", "body"], + FunctionDeclaration: ["id", "typeParameters", "params", "returnType", "body"], + FunctionExpression: ["id", "typeParameters", "params", "returnType", "body"], Identifier: ["typeAnnotation"], - InterfaceDeclaration: ["typeParameters"], - NewExpression: ["typeParameters"], - ObjectPattern: ["typeAnnotation"], - /** - * According to https://github.com/estree/estree/blob/master/extensions/type-annotations.md - * RestElement should have "typeAnnotation", but has not. Annotation is added on the "parameter" node - */ - RestElement: [], - TaggedTemplateExpression: ["typeParameters"], - VariableDeclarator: ["typeParameters"], + MethodDefinition: ["decorators", "key", "value"], + ObjectPattern: ["properties", "typeAnnotation"], + // Additional Nodes. + ClassProperty: ["decorators", "key", "typeAnnotation", "value"], + Decorator: ["expression"], TSAbstractClassProperty: ["typeAnnotation", "key", "value"], TSAbstractClassDeclaration: ["id", "body", "superClass", "implements"], TSAbstractKeyword: [], @@ -39,9 +31,13 @@ module.exports = Evk.unionWith({ TSArrayType: ["elementType"], TSAsyncKeyword: [], TSBooleanKeyword: [], + TSCallSignature: ["typeParameters", "parameters", "typeAnnotation"], + TSConstructSignature: ["typeParameters", "params", "typeAnnotation"], TSConstructorType: ["typeAnnotation", "parameters"], - TSConstructSignature: ["typeAnnotation", "typeParameters"], TSDeclareKeyword: [], + TSEmptyBodyDeclareFunction: ["id", "typeParameters", "params", "returnType"], + TSEmptyBodyFunctionDeclaration: ["id", "typeParameters", "params", "returnType"], + TSEmptyBodyFunctionExpression: ["id", "typeParameters", "params", "returnType"], TSEnumDeclaration: ["members"], TSEnumMember: ["initializer"], TSExportAssignment: ["expression"], @@ -81,6 +77,7 @@ module.exports = Evk.unionWith({ TSTypeParameterInstantiation: ["params"], TSTypePredicate: ["typeAnnotation", "parameterName"], TSTypeReference: ["typeName", "typeParameters"], + TSTypeQuery: ["exprName"], TSUnionType: ["types"], TSUndefinedKeyword: [], TSVoidKeyword: []