Utility for analyzing scopes belonging to an ESTree-compliant AST.
import { analyze } from 'periscopic';
const ast = acorn.parse(`
const a = b;
console.log(a);
`);
const { map, globals, scope } = analyze(ast);
map
is aWeakMap<Node, Scope>
, where the keys are the nodes of your AST that create a scopeglobals
is aMap<string, Node>
of all the identifiers that are referenced without being declared anywhere in the program (in this case,b
andconsole
)scope
is the top-levelScope
belonging to the program
Each Scope
instance has the following properties:
scope.block
— true if the scope is created by a block statement (i.e.let
,const
andclass
are contained to it), false otherwisescope.parent
— the parent scope objectscope.declarations
— aMap<string, Node>
of all the variables declared in this scope, the node value referes to the declaration statementscope.initialised_declarations
— aSet<string>
of all the variables declared and initialised in this scopescope.references
— aSet<string>
of all the names referenced in this scope (or child scopes)
It also has two methods:
scope.has(name)
— returnstrue
ifname
is declared in this scope or an ancestor scopescope.find_owner(name)
— returns the scope object in whichname
is declared (ornull
if it is not declared)
This package also exposes utilities for extracting the identifiers contained in a declaration or a function parameter:
import { extract_identifiers, extract_names } from 'periscopic';
const ast = acorn.parse(`
const { a, b: [c, d] = e } = opts;
`);
const lhs = ast.body[0].declarations[0].id;
extract_identifiers(lhs);
/*
[
{ type: 'Identifier', name: 'a', start: 9, end: 10 },
{ type: 'Identifier', name: 'c', start: 16, end: 17 },
{ type: 'Identifier', name: 'd', start: 19, end: 20 }
]
*/
extract_names(lhs);
/*
['a', 'c', 'd']
*/