123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- import { inject, injectable, } from 'inversify';
- import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
- import * as eslintScope from 'eslint-scope';
- import * as ESTree from 'estree';
- import { TNodeWithLexicalScope } from '../types/node/TNodeWithLexicalScope';
- import { TScopeIdentifiersTraverserCallback } from '../types/node/TScopeIdentifiersTraverserCallback';
- import { IScopeAnalyzer } from '../interfaces/analyzers/scope-analyzer/IScopeAnalyzer';
- import { IScopeIdentifiersTraverser } from '../interfaces/node/IScopeIdentifiersTraverser';
- import { IScopeIdentifiersTraverserCallbackData } from '../interfaces/node/IScopeIdentifiersTraverserCallbackData';
- import { IScopeThroughIdentifiersTraverserCallbackData } from '../interfaces/node/IScopeThroughIdentifiersTraverserCallbackData';
- import { NodeGuards } from './NodeGuards';
- /**
- * Scope traverser
- */
- @injectable()
- export class ScopeIdentifiersTraverser implements IScopeIdentifiersTraverser {
- /**
- * @type {string}
- */
- private static readonly argumentsVariableName: string = 'arguments';
- /**
- * @type {string[]}
- */
- private static readonly globalScopeNames: string[] = [
- 'global',
- 'module'
- ];
- /**
- * @type {IScopeAnalyzer}
- */
- private readonly scopeAnalyzer: IScopeAnalyzer;
- /**
- * @param {IScopeAnalyzer} scopeAnalyzer
- */
- public constructor (
- @inject(ServiceIdentifiers.IScopeAnalyzer) scopeAnalyzer: IScopeAnalyzer
- ) {
- this.scopeAnalyzer = scopeAnalyzer;
- }
- /**
- * @param {Program} programNode
- * @param {Node | null} parentNode
- * @param {TScopeIdentifiersTraverserCallback<IScopeIdentifiersTraverserCallbackData>} callback
- */
- public traverseScopeIdentifiers (
- programNode: ESTree.Program,
- parentNode: ESTree.Node | null,
- callback: TScopeIdentifiersTraverserCallback<IScopeIdentifiersTraverserCallbackData>
- ): void {
- this.scopeAnalyzer.analyze(programNode);
- const globalScope: eslintScope.Scope = this.scopeAnalyzer.acquireScope(programNode);
- this.traverseScopeIdentifiersRecursive(globalScope, globalScope, callback);
- }
- /**
- * @param {Program} programNode
- * @param {Node | null} parentNode
- * @param {TScopeIdentifiersTraverserCallback<IScopeThroughIdentifiersTraverserCallbackData>} callback
- */
- public traverseScopeThroughIdentifiers (
- programNode: ESTree.Program,
- parentNode: ESTree.Node | null,
- callback: TScopeIdentifiersTraverserCallback<IScopeThroughIdentifiersTraverserCallbackData>
- ): void {
- this.scopeAnalyzer.analyze(programNode);
- const globalScope: eslintScope.Scope = this.scopeAnalyzer.acquireScope(programNode);
- this.traverseScopeThroughIdentifiersRecursive(globalScope, globalScope, callback);
- }
- /**
- * @param {Scope} rootScope
- * @param {Scope} currentScope
- * @param {TScopeIdentifiersTraverserCallback<IScopeIdentifiersTraverserCallbackData>} callback
- */
- private traverseScopeIdentifiersRecursive (
- rootScope: eslintScope.Scope,
- currentScope: eslintScope.Scope,
- callback: TScopeIdentifiersTraverserCallback<IScopeIdentifiersTraverserCallbackData>
- ): void {
- const variableScope: eslintScope.Scope = currentScope.variableScope;
- const variableLexicalScopeNode: TNodeWithLexicalScope | null = NodeGuards.isNodeWithBlockLexicalScope(variableScope.block)
- ? variableScope.block
- : null;
- const isGlobalDeclaration: boolean = ScopeIdentifiersTraverser.globalScopeNames.includes(variableScope.type);
- if (!variableLexicalScopeNode) {
- return;
- }
- for (const variable of currentScope.variables) {
- if (variable.name === ScopeIdentifiersTraverser.argumentsVariableName) {
- continue;
- }
- const isBubblingDeclaration: boolean = variable
- .identifiers
- .some((identifier: ESTree.Node) =>
- identifier.parentNode
- && NodeGuards.isPropertyNode(identifier.parentNode)
- && identifier.parentNode.shorthand
- );
- callback({
- isGlobalDeclaration,
- isBubblingDeclaration,
- rootScope,
- variable,
- variableScope,
- variableLexicalScopeNode
- });
- }
- for (const childScope of currentScope.childScopes) {
- this.traverseScopeIdentifiersRecursive(rootScope, childScope, callback);
- }
- }
- /**
- * @param {Scope} rootScope
- * @param {Scope} currentScope
- * @param {TScopeIdentifiersTraverserCallback<IScopeThroughIdentifiersTraverserCallbackData>} callback
- */
- private traverseScopeThroughIdentifiersRecursive (
- rootScope: eslintScope.Scope,
- currentScope: eslintScope.Scope,
- callback: TScopeIdentifiersTraverserCallback<IScopeThroughIdentifiersTraverserCallbackData>
- ): void {
- const variableScope: eslintScope.Scope = currentScope.variableScope;
- const variableLexicalScopeNode: TNodeWithLexicalScope | null = NodeGuards.isNodeWithBlockLexicalScope(variableScope.block)
- ? variableScope.block
- : null;
- if (!variableLexicalScopeNode) {
- return;
- }
- for (const reference of currentScope.through) {
- callback({
- reference,
- variableLexicalScopeNode
- });
- }
- for (const childScope of currentScope.childScopes) {
- this.traverseScopeThroughIdentifiersRecursive(rootScope, childScope, callback);
- }
- }
- }
|