2 Object.defineProperty(exports, "__esModule", { value: true });
3 exports.analyzeScope = void 0;
4 const experimental_utils_1 = require("@typescript-eslint/experimental-utils");
5 const types_1 = require("@typescript-eslint/types");
6 const typescript_estree_1 = require("@typescript-eslint/typescript-estree");
7 const eslint_visitor_keys_1 = require("eslint-visitor-keys");
8 const scope_manager_1 = require("./scope/scope-manager");
10 * Define the override function of `Scope#__define` for global augmentation.
11 * @param {Function} define The original Scope#__define method.
12 * @returns {Function} The override function.
14 function overrideDefine(define) {
15 return function (node, definition) {
16 define.call(this, node, definition);
17 // Set `variable.eslintUsed` to tell ESLint that the variable is exported.
18 const variable = 'name' in node &&
19 typeof node.name === 'string' &&
20 this.set.get(node.name);
22 variable.eslintUsed = true;
26 class PatternVisitor extends experimental_utils_1.TSESLintScope.PatternVisitor {
27 constructor(options, rootPattern, callback) {
28 super(options, rootPattern, callback);
31 super.Identifier(node);
32 if (node.decorators) {
33 this.rightHandNodes.push(...node.decorators);
35 if (node.typeAnnotation) {
36 this.rightHandNodes.push(node.typeAnnotation);
40 node.elements.forEach(this.visit, this);
41 if (node.decorators) {
42 this.rightHandNodes.push(...node.decorators);
44 if (node.typeAnnotation) {
45 this.rightHandNodes.push(node.typeAnnotation);
49 node.properties.forEach(this.visit, this);
50 if (node.decorators) {
51 this.rightHandNodes.push(...node.decorators);
53 if (node.typeAnnotation) {
54 this.rightHandNodes.push(node.typeAnnotation);
58 super.RestElement(node);
59 if (node.decorators) {
60 this.rightHandNodes.push(...node.decorators);
62 if (node.typeAnnotation) {
63 this.rightHandNodes.push(node.typeAnnotation);
66 TSParameterProperty(node) {
67 this.visit(node.parameter);
68 if (node.decorators) {
69 this.rightHandNodes.push(...node.decorators);
73 class Referencer extends experimental_utils_1.TSESLintScope.Referencer {
74 constructor(options, scopeManager) {
75 super(options, scopeManager);
76 this.typeMode = false;
79 * Override to use PatternVisitor we overrode.
80 * @param node The Identifier node to visit.
81 * @param [options] The flag to visit right-hand side nodes.
82 * @param callback The callback function for left-hand side nodes.
84 visitPattern(node, options, callback) {
88 if (typeof options === 'function') {
90 options = { processRightHandNodes: false };
92 const visitor = new PatternVisitor(this.options, node, callback);
94 if (options.processRightHandNodes) {
95 visitor.rightHandNodes.forEach(this.visit, this);
100 * Visit `node.typeParameters` and `node.returnType` additionally to find `typeof` expressions.
101 * @param node The function node to visit.
103 visitFunction(node) {
104 const { type, id, typeParameters, params, returnType, body } = node;
105 const scopeManager = this.scopeManager;
106 const upperScope = this.currentScope();
108 if (type === types_1.AST_NODE_TYPES.FunctionDeclaration && id) {
109 upperScope.__define(id, new experimental_utils_1.TSESLintScope.Definition('FunctionName', id, node, null, null, null));
110 // Remove overload definition to avoid confusion of no-redeclare rule.
111 const { defs, identifiers } = upperScope.set.get(id.name);
112 for (let i = 0; i < defs.length; ++i) {
114 if (def.type === 'FunctionName' &&
115 def.node.type === types_1.AST_NODE_TYPES.TSDeclareFunction) {
117 identifiers.splice(i, 1);
122 else if (type === types_1.AST_NODE_TYPES.FunctionExpression && id) {
123 scopeManager.__nestFunctionExpressionNameScope(node);
125 // Open the function scope.
126 scopeManager.__nestFunctionScope(node, this.isInnerMethodDefinition);
127 const innerScope = this.currentScope();
128 // Process the type parameters
129 this.visit(typeParameters);
130 // Process parameter declarations.
131 for (let i = 0; i < params.length; ++i) {
132 this.visitPattern(params[i], { processRightHandNodes: true }, (pattern, info) => {
133 if (pattern.type !== types_1.AST_NODE_TYPES.Identifier ||
134 pattern.name !== 'this') {
135 innerScope.__define(pattern, new experimental_utils_1.TSESLintScope.ParameterDefinition(pattern, node, i, info.rest));
136 this.referencingDefaultValue(pattern, info.assignments, null, true);
140 // Process the return type.
141 this.visit(returnType);
143 if (body && body.type === types_1.AST_NODE_TYPES.BlockStatement) {
144 this.visitChildren(body);
149 // Close the function scope.
155 * @param node The class node to visit.
158 this.visitDecorators(node.decorators);
159 const upperTypeMode = this.typeMode;
160 this.typeMode = true;
161 if (node.superTypeParameters) {
162 this.visit(node.superTypeParameters);
164 if (node.implements) {
165 node.implements.forEach(this.visit, this);
167 this.typeMode = upperTypeMode;
168 super.visitClass(node);
171 * Visit typeParameters.
172 * @param node The node to visit.
174 visitTypeParameters(node) {
175 if (node.typeParameters) {
176 const upperTypeMode = this.typeMode;
177 this.typeMode = true;
178 this.visit(node.typeParameters);
179 this.typeMode = upperTypeMode;
185 JSXOpeningElement(node) {
186 this.visit(node.name);
187 this.visitTypeParameters(node);
188 node.attributes.forEach(this.visit, this);
192 * Don't create the reference object in the type mode.
193 * @param node The Identifier node to visit.
196 this.visitDecorators(node.decorators);
197 if (!this.typeMode) {
198 super.Identifier(node);
200 this.visit(node.typeAnnotation);
205 * @param node The MethodDefinition node to visit.
207 MethodDefinition(node) {
208 this.visitDecorators(node.decorators);
209 super.MethodDefinition(node);
212 * Don't create the reference object for the key if not computed.
213 * @param node The ClassProperty node to visit.
215 ClassProperty(node) {
216 const upperTypeMode = this.typeMode;
217 const { computed, decorators, key, typeAnnotation, value } = node;
218 this.typeMode = false;
219 this.visitDecorators(decorators);
223 this.typeMode = true;
224 this.visit(typeAnnotation);
225 this.typeMode = false;
227 this.typeMode = upperTypeMode;
230 * Visit new expression.
231 * @param node The NewExpression node to visit.
233 NewExpression(node) {
234 this.visitTypeParameters(node);
235 this.visit(node.callee);
236 node.arguments.forEach(this.visit, this);
240 * Visit call expression.
241 * @param node The CallExpression node to visit.
243 CallExpression(node) {
244 this.visitTypeParameters(node);
245 this.visit(node.callee);
246 node.arguments.forEach(this.visit, this);
249 * Visit optional member expression.
250 * @param node The OptionalMemberExpression node to visit.
252 OptionalMemberExpression(node) {
253 this.visit(node.object);
255 this.visit(node.property);
259 * Visit optional call expression.
260 * @param node The OptionalMemberExpression node to visit.
262 OptionalCallExpression(node) {
263 this.visitTypeParameters(node);
264 this.visit(node.callee);
265 node.arguments.forEach(this.visit, this);
268 * Define the variable of this function declaration only once.
269 * Because to avoid confusion of `no-redeclare` rule by overloading.
270 * @param node The TSDeclareFunction node to visit.
272 TSDeclareFunction(node) {
273 const scopeManager = this.scopeManager;
274 const upperScope = this.currentScope();
275 const { id, typeParameters, params, returnType } = node;
276 // Ignore this if other overload have already existed.
278 const variable = upperScope.set.get(id.name);
279 const defs = variable === null || variable === void 0 ? void 0 : variable.defs;
280 const existed = defs === null || defs === void 0 ? void 0 : defs.some((d) => d.type === 'FunctionName');
282 upperScope.__define(id, new experimental_utils_1.TSESLintScope.Definition('FunctionName', id, node, null, null, null));
285 // Open the function scope.
286 scopeManager.__nestEmptyFunctionScope(node);
287 const innerScope = this.currentScope();
288 // Process the type parameters
289 this.visit(typeParameters);
290 // Process parameter declarations.
291 for (let i = 0; i < params.length; ++i) {
292 this.visitPattern(params[i], { processRightHandNodes: true }, (pattern, info) => {
293 innerScope.__define(pattern, new experimental_utils_1.TSESLintScope.ParameterDefinition(pattern, node, i, info.rest));
294 // Set `variable.eslintUsed` to tell ESLint that the variable is used.
295 const variable = innerScope.set.get(pattern.name);
297 variable.eslintUsed = true;
299 this.referencingDefaultValue(pattern, info.assignments, null, true);
302 // Process the return type.
303 this.visit(returnType);
304 // Close the function scope.
308 * Create reference objects for the references in parameters and return type.
309 * @param node The TSEmptyBodyFunctionExpression node to visit.
311 TSEmptyBodyFunctionExpression(node) {
312 const upperTypeMode = this.typeMode;
313 const { typeParameters, params, returnType } = node;
314 this.typeMode = true;
315 this.visit(typeParameters);
316 params.forEach(this.visit, this);
317 this.visit(returnType);
318 this.typeMode = upperTypeMode;
321 * Don't make variable because it declares only types.
322 * Switch to the type mode and visit child nodes to find `typeof x` expression in type declarations.
323 * @param node The TSInterfaceDeclaration node to visit.
325 TSInterfaceDeclaration(node) {
326 this.visitTypeNodes(node);
329 * Don't make variable because it declares only types.
330 * Switch to the type mode and visit child nodes to find `typeof x` expression in type declarations.
331 * @param node The TSClassImplements node to visit.
333 TSClassImplements(node) {
334 this.visitTypeNodes(node);
337 * Don't make variable because it declares only types.
338 * Switch to the type mode and visit child nodes to find `typeof x` expression in type declarations.
339 * @param node The TSIndexSignature node to visit.
341 TSIndexSignature(node) {
342 this.visitTypeNodes(node);
345 * Visit type assertion.
346 * @param node The TSTypeAssertion node to visit.
348 TSTypeAssertion(node) {
350 this.visit(node.typeAnnotation);
353 this.typeMode = true;
354 this.visit(node.typeAnnotation);
355 this.typeMode = false;
357 this.visit(node.expression);
360 * Visit as expression.
361 * @param node The TSAsExpression node to visit.
363 TSAsExpression(node) {
364 this.visit(node.expression);
366 this.visit(node.typeAnnotation);
369 this.typeMode = true;
370 this.visit(node.typeAnnotation);
371 this.typeMode = false;
375 * Switch to the type mode and visit child nodes to find `typeof x` expression in type declarations.
376 * @param node The TSTypeAnnotation node to visit.
378 TSTypeAnnotation(node) {
379 this.visitTypeNodes(node);
382 * Switch to the type mode and visit child nodes to find `typeof x` expression in type declarations.
383 * @param node The TSTypeParameterDeclaration node to visit.
385 TSTypeParameterDeclaration(node) {
386 this.visitTypeNodes(node);
389 * Create reference objects for the references in `typeof` expression.
390 * @param node The TSTypeQuery node to visit.
394 this.typeMode = false;
395 this.visitChildren(node);
396 this.typeMode = true;
399 this.visitChildren(node);
403 * @param node The TSTypeParameter node to visit.
405 TSTypeParameter(node) {
406 this.visitTypeNodes(node);
409 * @param node The TSInferType node to visit.
412 this.visitTypeNodes(node);
415 * @param node The TSTypeReference node to visit.
417 TSTypeReference(node) {
418 this.visitTypeNodes(node);
421 * @param node The TSTypeLiteral node to visit.
423 TSTypeLiteral(node) {
424 this.visitTypeNodes(node);
427 * @param node The TSLiteralType node to visit.
429 TSLiteralType(node) {
430 this.visitTypeNodes(node);
433 * @param node The TSIntersectionType node to visit.
435 TSIntersectionType(node) {
436 this.visitTypeNodes(node);
439 * @param node The TSConditionalType node to visit.
441 TSConditionalType(node) {
442 this.visitTypeNodes(node);
445 * @param node The TSIndexedAccessType node to visit.
447 TSIndexedAccessType(node) {
448 this.visitTypeNodes(node);
451 * @param node The TSMappedType node to visit.
454 this.visitTypeNodes(node);
457 * @param node The TSOptionalType node to visit.
459 TSOptionalType(node) {
460 this.visitTypeNodes(node);
463 * @param node The TSParenthesizedType node to visit.
465 TSParenthesizedType(node) {
466 this.visitTypeNodes(node);
469 * @param node The TSRestType node to visit.
472 this.visitTypeNodes(node);
475 * @param node The TSTupleType node to visit.
478 this.visitTypeNodes(node);
481 * Create reference objects for the object part. (This is `obj.prop`)
482 * @param node The TSQualifiedName node to visit.
484 TSQualifiedName(node) {
485 this.visit(node.left);
488 * Create reference objects for the references in computed keys.
489 * @param node The TSPropertySignature node to visit.
491 TSPropertySignature(node) {
492 const upperTypeMode = this.typeMode;
493 const { computed, key, typeAnnotation, initializer } = node;
495 this.typeMode = false;
497 this.typeMode = true;
500 this.typeMode = true;
503 this.visit(typeAnnotation);
504 this.visit(initializer);
505 this.typeMode = upperTypeMode;
508 * Create reference objects for the references in computed keys.
509 * @param node The TSMethodSignature node to visit.
511 TSMethodSignature(node) {
512 const upperTypeMode = this.typeMode;
513 const { computed, key, typeParameters, params, returnType } = node;
515 this.typeMode = false;
517 this.typeMode = true;
520 this.typeMode = true;
523 this.visit(typeParameters);
524 params.forEach(this.visit, this);
525 this.visit(returnType);
526 this.typeMode = upperTypeMode;
529 * Create variable object for the enum.
530 * The enum declaration creates a scope for the enum members.
535 * C = A + B // A and B are references to the enum member.
540 * A = a // a is above constant.
543 * @param node The TSEnumDeclaration node to visit.
545 TSEnumDeclaration(node) {
546 const { id, members } = node;
547 const scopeManager = this.scopeManager;
548 const scope = this.currentScope();
550 scope.__define(id, new experimental_utils_1.TSESLintScope.Definition('EnumName', id, node));
552 scopeManager.__nestEnumScope(node);
553 for (const member of members) {
559 * Create variable object for the enum member and create reference object for the initializer.
560 * And visit the initializer.
562 * @param node The TSEnumMember node to visit.
565 const { id, initializer } = node;
566 const scope = this.currentScope();
567 scope.__define(id, new experimental_utils_1.TSESLintScope.Definition('EnumMemberName', id, node));
569 scope.__referencing(id, experimental_utils_1.TSESLintScope.Reference.WRITE, initializer, null, false, true);
570 this.visit(initializer);
574 * Create the variable object for the module name, and visit children.
575 * @param node The TSModuleDeclaration node to visit.
577 TSModuleDeclaration(node) {
578 const scope = this.currentScope();
579 const { id, body } = node;
581 this.visitGlobalAugmentation(node);
584 if (id && id.type === types_1.AST_NODE_TYPES.Identifier) {
585 scope.__define(id, new experimental_utils_1.TSESLintScope.Definition('NamespaceName', id, node, null, null, null));
589 TSTypeAliasDeclaration(node) {
590 this.typeMode = true;
591 this.visitChildren(node);
592 this.typeMode = false;
595 * Process the module block.
596 * @param node The TSModuleBlock node to visit.
598 TSModuleBlock(node) {
599 this.scopeManager.__nestBlockScope(node);
600 this.visitChildren(node);
603 TSAbstractClassProperty(node) {
604 this.ClassProperty(node);
606 TSAbstractMethodDefinition(node) {
607 this.MethodDefinition(node);
610 * Process import equal declaration
611 * @param node The TSImportEqualsDeclaration node to visit.
613 TSImportEqualsDeclaration(node) {
614 const { id, moduleReference } = node;
615 if (id && id.type === types_1.AST_NODE_TYPES.Identifier) {
616 this.currentScope().__define(id, new experimental_utils_1.TSESLintScope.Definition('ImportBinding', id, node, null, null, null));
618 this.visit(moduleReference);
621 * Process the global augmentation.
622 * 1. Set the global scope as the current scope.
623 * 2. Configure the global scope to set `variable.eslintUsed = true` for all defined variables. This means `no-unused-vars` doesn't warn those.
624 * @param node The TSModuleDeclaration node to visit.
626 visitGlobalAugmentation(node) {
627 const scopeManager = this.scopeManager;
628 const currentScope = this.currentScope();
629 const globalScope = scopeManager.globalScope;
630 const originalDefine = globalScope.__define;
631 globalScope.__define = overrideDefine(originalDefine);
632 scopeManager.__currentScope = globalScope;
633 // Skip TSModuleBlock to avoid to create that block scope.
634 if (node.body && node.body.type === types_1.AST_NODE_TYPES.TSModuleBlock) {
635 node.body.body.forEach(this.visit, this);
637 scopeManager.__currentScope = currentScope;
638 globalScope.__define = originalDefine;
641 * Process decorators.
642 * @param decorators The decorator nodes to visit.
644 visitDecorators(decorators) {
646 decorators.forEach(this.visit, this);
650 * Process all child of type nodes
651 * @param node node to be processed
653 visitTypeNodes(node) {
655 this.visitChildren(node);
658 this.typeMode = true;
659 this.visitChildren(node);
660 this.typeMode = false;
664 function analyzeScope(ast, parserOptions) {
670 nodejsScope: parserOptions.sourceType === 'script' &&
671 ((_a = parserOptions.ecmaFeatures) === null || _a === void 0 ? void 0 : _a.globalReturn) === true,
672 impliedStrict: false,
673 sourceType: parserOptions.sourceType,
674 ecmaVersion: (_b = parserOptions.ecmaVersion) !== null && _b !== void 0 ? _b : 2018,
675 childVisitorKeys: typescript_estree_1.visitorKeys,
676 fallback: eslint_visitor_keys_1.getKeys,
678 const scopeManager = new scope_manager_1.ScopeManager(options);
679 const referencer = new Referencer(options, scopeManager);
680 referencer.visit(ast);
683 exports.analyzeScope = analyzeScope;
684 //# sourceMappingURL=analyze-scope.js.map