TypeScript scope analyser for ESLint that provides comprehensive scope analysis capabilities for JavaScript and TypeScript code
—
The ScopeManager class is the central manager for all scopes in analyzed code. It maintains scope hierarchies, variable mappings, and provides scope navigation and querying capabilities.
The main class that manages all scopes created during AST analysis.
/**
* Central manager for all scopes in analyzed code
* @see https://eslint.org/docs/latest/developer-guide/scope-manager-interface#scopemanager-interface
*/
class ScopeManager {
/** Current scope being processed during analysis */
currentScope: Scope | null;
/** WeakMap associating AST nodes with the variables they declare */
readonly declaredVariables: WeakMap<TSESTree.Node, Variable[]>;
/** The root scope (global scope) */
globalScope: GlobalScope | null;
/** WeakMap associating AST nodes with their scopes */
readonly nodeToScope: WeakMap<TSESTree.Node, Scope[]>;
/** All scopes in the analysis */
readonly scopes: Scope[];
/** All variables across all scopes */
get variables(): Variable[];
}Methods to determine the analysis environment and configuration.
/**
* Check if ES6 features are enabled
* @returns Always true in TypeScript scope manager
*/
isES6(): boolean;
/**
* Check if global return is enabled
* @returns True if globalReturn option was set during analysis
*/
isGlobalReturn(): boolean;
/**
* Check if implied strict mode is enabled
* @returns True if impliedStrict option was set during analysis
*/
isImpliedStrict(): boolean;
/**
* Check if source is a module
* @returns True if sourceType was set to 'module' during analysis
*/
isModule(): boolean;
/**
* Check if strict mode is supported
* @returns Always true in TypeScript scope manager
*/
isStrictModeSupported(): boolean;Methods to find variables declared by specific AST nodes.
/**
* Get the variables that a given AST node defines. The gotten variables'
* def[].node/def[].parent property is the node.
* If the node does not define any variable, this returns an empty array.
* @param node - An AST node to get their variables
* @returns Array of variables declared by the node
*/
getDeclaredVariables(node: TSESTree.Node): Variable[];Methods to navigate and query the scope hierarchy.
/**
* Get the scope of a given AST node. The gotten scope's block property is the node.
* This method never returns function-expression-name scope. If the node does not
* have their scope, this returns null.
*
* @param node - An AST node to get their scope
* @param inner - If the node has multiple scopes, this returns the outermost scope normally.
* If inner is true then this returns the innermost scope.
* @returns The scope associated with the node, or null if none exists
*/
acquire(node: TSESTree.Node, inner?: boolean): Scope | null;Usage Examples:
import { analyze } from "@typescript-eslint/scope-manager";
import { parse } from "@typescript-eslint/parser";
const code = `
function outer(x: number) {
const y = x * 2;
function inner(z: number) {
return y + z;
}
return inner;
}
`;
const ast = parse(code);
const scopeManager = analyze(ast, { sourceType: 'module' });
// Check environment
console.log(scopeManager.isModule()); // true
console.log(scopeManager.isES6()); // true
// Get all scopes
console.log(`Total scopes: ${scopeManager.scopes.length}`);
scopeManager.scopes.forEach((scope, index) => {
console.log(`Scope ${index}: ${scope.type}`);
});
// Get variables in global scope
if (scopeManager.globalScope) {
console.log('Global variables:',
scopeManager.globalScope.variables.map(v => v.name)
);
}
// Find scope for a specific node
const functionNodes = []; // collect function nodes during AST traversal
functionNodes.forEach(node => {
const scope = scopeManager.acquire(node);
if (scope) {
console.log(`Function scope type: ${scope.type}`);
console.log(`Variables in scope: ${scope.variables.map(v => v.name)}`);
}
});
// Get declared variables for each node
const declarationNodes = []; // collect declaration nodes during AST traversal
declarationNodes.forEach(node => {
const variables = scopeManager.getDeclaredVariables(node);
variables.forEach(variable => {
console.log(`Variable ${variable.name} declared by node type ${node.type}`);
});
});
// Get all variables across all scopes
const allVariables = scopeManager.variables;
console.log(`Total variables: ${allVariables.length}`);
allVariables.forEach(variable => {
console.log(`${variable.name} in ${variable.scope.type} scope`);
});The ScopeManager provides methods to create different types of scopes during analysis. These are typically used internally but are part of the public API:
// Block scopes
nestBlockScope(node: TSESTree.BlockStatement): BlockScope;
nestCatchScope(node: TSESTree.CatchClause): CatchScope;
nestForScope(node: TSESTree.ForStatement | TSESTree.ForInStatement | TSESTree.ForOfStatement): ForScope;
nestSwitchScope(node: TSESTree.SwitchStatement): SwitchScope;
nestWithScope(node: TSESTree.WithStatement): WithScope;
// Function scopes
nestFunctionScope(node: TSESTree.Function, isMethodDefinition: boolean): FunctionScope;
nestFunctionExpressionNameScope(node: TSESTree.FunctionExpression): FunctionExpressionNameScope;
// Class and type scopes
nestClassScope(node: TSESTree.ClassDeclaration | TSESTree.ClassExpression): ClassScope;
nestClassFieldInitializerScope(node: TSESTree.PropertyDefinition): ClassFieldInitializerScope;
nestClassStaticBlockScope(node: TSESTree.StaticBlock): ClassStaticBlockScope;
nestTypeScope(node: TSESTree.TSTypeAnnotation): TypeScope;
nestFunctionTypeScope(node: TSESTree.TSFunctionType): FunctionTypeScope;
nestConditionalTypeScope(node: TSESTree.TSConditionalType): ConditionalTypeScope;
nestMappedTypeScope(node: TSESTree.TSMappedType): MappedTypeScope;
// Module and namespace scopes
nestModuleScope(node: TSESTree.Program): ModuleScope;
nestTSModuleScope(node: TSESTree.TSModuleDeclaration): TSModuleScope;
nestTSEnumScope(node: TSESTree.TSEnumDeclaration): TSEnumScope;
// Global scope
nestGlobalScope(node: TSESTree.Program): GlobalScope;// Navigate scope hierarchy
const currentScope = scopeManager.currentScope;
if (currentScope) {
console.log(`Current scope: ${currentScope.type}`);
// Parent scope
if (currentScope.upper) {
console.log(`Parent scope: ${currentScope.upper.type}`);
}
// Child scopes
currentScope.childScopes.forEach((child, index) => {
console.log(`Child ${index}: ${child.type}`);
});
// Variables in current scope
currentScope.variables.forEach(variable => {
console.log(`Variable: ${variable.name}`);
console.log(`References: ${variable.references.length}`);
});
}Install with Tessl CLI
npx tessl i tessl/npm-typescript-eslint--scope-manager