Website Structure
This commit is contained in:
parent
62812f2090
commit
71f0676a62
22365 changed files with 4265753 additions and 791 deletions
323
Frontend-Learner/node_modules/oxc-walker/dist/index.d.mts
generated
vendored
Normal file
323
Frontend-Learner/node_modules/oxc-walker/dist/index.d.mts
generated
vendored
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
import { Node, Program, IdentifierName, IdentifierReference, BindingIdentifier, LabelIdentifier, TSIndexSignatureName, ParseResult, ParserOptions, Function, ArrowFunctionExpression, VariableDeclaration, ImportDeclarationSpecifier, ImportDeclaration, CatchClause } from 'oxc-parser';
|
||||
|
||||
interface WalkerCallbackContext {
|
||||
/**
|
||||
* The key of the current node within its parent node object, if applicable.
|
||||
*
|
||||
* For instance, when processing a `VariableDeclarator` node, this would be the `declarations` key of the parent `VariableDeclaration` node.
|
||||
* @example
|
||||
* {
|
||||
* type: 'VariableDeclaration',
|
||||
* declarations: [[Object]],
|
||||
* // ...
|
||||
* },
|
||||
* { // <-- when processing this, the key would be 'declarations'
|
||||
* type: 'VariableDeclarator',
|
||||
* // ...
|
||||
* },
|
||||
*/
|
||||
key: string | number | symbol | null | undefined;
|
||||
/**
|
||||
* The zero-based index of the current node within its parent's children array, if applicable.
|
||||
* For instance, when processing a `VariableDeclarator` node,
|
||||
* this would be the index of the current `VariableDeclarator` node within the `declarations` array.
|
||||
*
|
||||
* This is `null` when the node is not part of an array.
|
||||
*
|
||||
* @example
|
||||
* {
|
||||
* type: 'VariableDeclaration',
|
||||
* declarations: [[Object]],
|
||||
* // ...
|
||||
* },
|
||||
* { // <-- when processing this, the index would be 0
|
||||
* type: 'VariableDeclarator',
|
||||
* // ...
|
||||
* },
|
||||
*/
|
||||
index: number | null;
|
||||
/**
|
||||
* The full Abstract Syntax Tree (AST) that is being walked, starting from the root node.
|
||||
*/
|
||||
ast: Program | Node;
|
||||
}
|
||||
interface WalkerThisContextLeave {
|
||||
/**
|
||||
* Remove the current node from the AST.
|
||||
* @remarks
|
||||
* - The `ScopeTracker` currently does not support node removal
|
||||
* @see ScopeTracker
|
||||
*/
|
||||
remove: () => void;
|
||||
/**
|
||||
* Replace the current node with another node.
|
||||
* After replacement, the walker will continue with the next sibling of the replaced node.
|
||||
*
|
||||
* In case the current node was removed in the `enter` phase, this will put the new node in
|
||||
* the place of the removed node - essentially undoing the removal.
|
||||
* @remarks
|
||||
* - The `ScopeTracker` currently does not support node replacement
|
||||
* @see ScopeTracker
|
||||
*/
|
||||
replace: (node: Node) => void;
|
||||
}
|
||||
interface WalkerThisContextEnter extends WalkerThisContextLeave {
|
||||
/**
|
||||
* Skip traversing the child nodes of the current node.
|
||||
*/
|
||||
skip: () => void;
|
||||
/**
|
||||
* Remove the current node and all of its children from the AST.
|
||||
* @remarks
|
||||
* - The `ScopeTracker` currently does not support node removal
|
||||
* @see ScopeTracker
|
||||
*/
|
||||
remove: () => void;
|
||||
/**
|
||||
* Replace the current node with another node.
|
||||
* After replacement, the walker will continue to traverse the children of the new node.
|
||||
*
|
||||
* If you want to replace the current node and skip traversing its children, call `this.skip()` after calling `this.replace(newNode)`.
|
||||
* @remarks
|
||||
* - The `ScopeTracker` currently does not support node replacement
|
||||
* @see this.skip
|
||||
* @see ScopeTracker
|
||||
*/
|
||||
replace: (node: Node) => void;
|
||||
}
|
||||
type WalkerCallback<T extends WalkerThisContextLeave> = (this: T, node: Node, parent: Node | null, ctx: WalkerCallbackContext) => void;
|
||||
type WalkerEnter = WalkerCallback<WalkerThisContextEnter>;
|
||||
type WalkerLeave = WalkerCallback<WalkerThisContextLeave>;
|
||||
|
||||
interface _WalkOptions {
|
||||
/**
|
||||
* The instance of `ScopeTracker` to use for tracking declarations and references.
|
||||
* @see ScopeTracker
|
||||
* @default undefined
|
||||
*/
|
||||
scopeTracker: ScopeTracker;
|
||||
}
|
||||
interface WalkOptions extends Partial<_WalkOptions> {
|
||||
/**
|
||||
* The function to be called when entering a node.
|
||||
*/
|
||||
enter: WalkerEnter;
|
||||
/**
|
||||
* The function to be called when leaving a node.
|
||||
*/
|
||||
leave: WalkerLeave;
|
||||
}
|
||||
|
||||
type Identifier = IdentifierName | IdentifierReference | BindingIdentifier | LabelIdentifier | TSIndexSignatureName;
|
||||
/**
|
||||
* Walk the AST with the given options.
|
||||
* @param input The AST to walk.
|
||||
* @param options The options to be used when walking the AST. Here you can specify the callbacks for entering and leaving nodes, as well as other options.
|
||||
*/
|
||||
declare function walk(input: Program | Node, options: Partial<WalkOptions>): Node | null;
|
||||
interface ParseAndWalkOptions extends WalkOptions {
|
||||
/**
|
||||
* The options for `oxc-parser` to use when parsing the code.
|
||||
*/
|
||||
parseOptions: ParserOptions;
|
||||
}
|
||||
/**
|
||||
* Parse the code and walk the AST with the given callback, which is called when entering a node.
|
||||
* @param code The string with the code to parse and walk. This can be JavaScript, TypeScript, jsx, or tsx.
|
||||
* @param sourceFilename The filename of the source code. This is used to determine the language of the code, unless
|
||||
* it is specified in the parse options.
|
||||
* @param callback The callback to be called when entering a node.
|
||||
*/
|
||||
declare function parseAndWalk(code: string, sourceFilename: string, callback: WalkerEnter): ParseResult;
|
||||
/**
|
||||
* Parse the code and walk the AST with the given callback(s).
|
||||
* @param code The string with the code to parse and walk. This can be JavaScript, TypeScript, jsx, or tsx.
|
||||
* @param sourceFilename The filename of the source code. This is used to determine the language of the code, unless
|
||||
* it is specified in the parse options.
|
||||
* @param options The options to be used when walking the AST. Here you can specify the callbacks for entering and leaving nodes, as well as other options.
|
||||
*/
|
||||
declare function parseAndWalk(code: string, sourceFilename: string, options: Partial<ParseAndWalkOptions>): ParseResult;
|
||||
|
||||
interface ScopeTrackerProtected {
|
||||
processNodeEnter: (node: Node) => void;
|
||||
processNodeLeave: (node: Node) => void;
|
||||
}
|
||||
/**
|
||||
* Tracks variable scopes and identifier declarations within a JavaScript AST.
|
||||
*
|
||||
* Maintains a stack of scopes, each represented as a map from identifier names to their declaration nodes,
|
||||
* enabling efficient lookup of the declaration.
|
||||
*
|
||||
* The ScopeTracker is designed to integrate with the `walk` function,
|
||||
* it automatically manages scope creation and identifier tracking,
|
||||
* so only query and inspection methods are exposed for external use.
|
||||
*
|
||||
* ### Scope tracking
|
||||
* A new scope is created when entering blocks, function parameters, loop variables, etc.
|
||||
* Note that this representation may split a single JavaScript lexical scope into multiple internal scopes,
|
||||
* meaning it doesn't mirror JavaScript’s scoping 1:1.
|
||||
*
|
||||
* Scopes are represented using a string-based index like `"0-1-2"`, which tracks depth and ancestry.
|
||||
*
|
||||
* #### Root scope
|
||||
* The root scope is represented by an empty string `""`.
|
||||
*
|
||||
* #### Scope key format
|
||||
* Scope keys are hierarchical strings that uniquely identify each scope and its position in the tree.
|
||||
* They are constructed using a depth-based indexing scheme, where:
|
||||
*
|
||||
* - the root scope is represented by an empty string `""`.
|
||||
* - the first child scope is `"0"`.
|
||||
* - a parallel sibling of `"0"` becomes `"1"`, `"2"`, etc.
|
||||
* - a nested scope under `"0"` is `"0-0"`, then its sibling is `"0-1"`, and so on.
|
||||
*
|
||||
* Each segment in the key corresponds to the zero-based index of the scope at that depth level in
|
||||
* the order of AST traversal.
|
||||
*
|
||||
* ### Additional features
|
||||
* - supports freezing the tracker to allow for second passes through the AST without modifying the scope data
|
||||
* (useful for doing a pre-pass to collect all identifiers before walking).
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const scopeTracker = new ScopeTracker()
|
||||
* walk(code, {
|
||||
* scopeTracker,
|
||||
* enter(node) {
|
||||
* // ...
|
||||
* },
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @see parseAndWalk
|
||||
* @see walk
|
||||
*/
|
||||
declare class ScopeTracker {
|
||||
protected scopeIndexStack: number[];
|
||||
protected scopeIndexKey: string;
|
||||
protected scopes: Map<string, Map<string, ScopeTrackerNode>>;
|
||||
protected options: Partial<ScopeTrackerOptions>;
|
||||
protected isFrozen: boolean;
|
||||
constructor(options?: ScopeTrackerOptions);
|
||||
protected updateScopeIndexKey(): void;
|
||||
protected pushScope(): void;
|
||||
protected popScope(): void;
|
||||
protected declareIdentifier(name: string, data: ScopeTrackerNode): void;
|
||||
protected declareFunctionParameter(param: Node, fn: Function | ArrowFunctionExpression): void;
|
||||
protected declarePattern(pattern: Node, parent: VariableDeclaration | ArrowFunctionExpression | CatchClause | Function): void;
|
||||
protected processNodeEnter: ScopeTrackerProtected["processNodeEnter"];
|
||||
protected processNodeLeave: ScopeTrackerProtected["processNodeLeave"];
|
||||
/**
|
||||
* Check if an identifier is declared in the current scope or any parent scope.
|
||||
* @param name the identifier name to check
|
||||
*/
|
||||
isDeclared(name: string): boolean;
|
||||
/**
|
||||
* Get the declaration node for a given identifier name.
|
||||
* @param name the identifier name to look up
|
||||
*/
|
||||
getDeclaration(name: string): ScopeTrackerNode | null;
|
||||
/**
|
||||
* Get the current scope key.
|
||||
*/
|
||||
getCurrentScope(): string;
|
||||
/**
|
||||
* Check if the current scope is a child of a specific scope.
|
||||
* @example
|
||||
* ```ts
|
||||
* // current scope is 0-1
|
||||
* isCurrentScopeUnder('0') // true
|
||||
* isCurrentScopeUnder('0-1') // false
|
||||
* ```
|
||||
*
|
||||
* @param scope the parent scope key to check against
|
||||
* @returns `true` if the current scope is a child of the specified scope, `false` otherwise (also when they are the same)
|
||||
*/
|
||||
isCurrentScopeUnder(scope: string): boolean;
|
||||
/**
|
||||
* Freezes the ScopeTracker, preventing further modifications to its state.
|
||||
* It also resets the scope index stack to its initial state so that the tracker can be reused.
|
||||
*
|
||||
* This is useful for second passes through the AST.
|
||||
*/
|
||||
freeze(): void;
|
||||
}
|
||||
declare function isBindingIdentifier(node: Node, parent: Node | null): boolean;
|
||||
declare function getUndeclaredIdentifiersInFunction(node: Function | ArrowFunctionExpression): string[];
|
||||
declare abstract class BaseNode<T extends Node = Node> {
|
||||
abstract type: string;
|
||||
readonly scope: string;
|
||||
node: T;
|
||||
constructor(node: T, scope: string);
|
||||
/**
|
||||
* The starting position of the entire node relevant for code transformation.
|
||||
* For instance, for a reference to a variable (ScopeTrackerVariable -> Identifier), this would refer to the start of the VariableDeclaration.
|
||||
*/
|
||||
abstract get start(): number;
|
||||
/**
|
||||
* The ending position of the entire node relevant for code transformation.
|
||||
* For instance, for a reference to a variable (ScopeTrackerVariable -> Identifier), this would refer to the end of the VariableDeclaration.
|
||||
*/
|
||||
abstract get end(): number;
|
||||
/**
|
||||
* Check if the node is defined under a specific scope.
|
||||
* @param scope
|
||||
*/
|
||||
isUnderScope(scope: string): boolean;
|
||||
}
|
||||
declare class ScopeTrackerIdentifier extends BaseNode<Identifier> {
|
||||
type: "Identifier";
|
||||
get start(): number;
|
||||
get end(): number;
|
||||
}
|
||||
declare class ScopeTrackerFunctionParam extends BaseNode {
|
||||
type: "FunctionParam";
|
||||
fnNode: Function | ArrowFunctionExpression;
|
||||
constructor(node: Node, scope: string, fnNode: Function | ArrowFunctionExpression);
|
||||
/**
|
||||
* @deprecated The representation of this position may change in the future. Use `.fnNode.start` instead for now.
|
||||
*/
|
||||
get start(): number;
|
||||
/**
|
||||
* @deprecated The representation of this position may change in the future. Use `.fnNode.end` instead for now.
|
||||
*/
|
||||
get end(): number;
|
||||
}
|
||||
declare class ScopeTrackerFunction extends BaseNode<Function | ArrowFunctionExpression> {
|
||||
type: "Function";
|
||||
get start(): number;
|
||||
get end(): number;
|
||||
}
|
||||
declare class ScopeTrackerVariable extends BaseNode<Identifier> {
|
||||
type: "Variable";
|
||||
variableNode: VariableDeclaration;
|
||||
constructor(node: Identifier, scope: string, variableNode: VariableDeclaration);
|
||||
get start(): number;
|
||||
get end(): number;
|
||||
}
|
||||
declare class ScopeTrackerImport extends BaseNode<ImportDeclarationSpecifier> {
|
||||
type: "Import";
|
||||
importNode: ImportDeclaration;
|
||||
constructor(node: ImportDeclarationSpecifier, scope: string, importNode: ImportDeclaration);
|
||||
get start(): number;
|
||||
get end(): number;
|
||||
}
|
||||
declare class ScopeTrackerCatchParam extends BaseNode {
|
||||
type: "CatchParam";
|
||||
catchNode: CatchClause;
|
||||
constructor(node: Node, scope: string, catchNode: CatchClause);
|
||||
get start(): number;
|
||||
get end(): number;
|
||||
}
|
||||
type ScopeTrackerNode = ScopeTrackerFunctionParam | ScopeTrackerFunction | ScopeTrackerVariable | ScopeTrackerIdentifier | ScopeTrackerImport | ScopeTrackerCatchParam;
|
||||
interface ScopeTrackerOptions {
|
||||
/**
|
||||
* If true, the scope tracker will preserve exited scopes in memory.
|
||||
* This is necessary when you want to do a pre-pass to collect all identifiers before walking, for example.
|
||||
* @default false
|
||||
*/
|
||||
preserveExitedScopes?: boolean;
|
||||
}
|
||||
|
||||
export { ScopeTracker, getUndeclaredIdentifiersInFunction, isBindingIdentifier, parseAndWalk, walk };
|
||||
export type { Identifier, ScopeTrackerNode };
|
||||
323
Frontend-Learner/node_modules/oxc-walker/dist/index.d.ts
generated
vendored
Normal file
323
Frontend-Learner/node_modules/oxc-walker/dist/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
import { Node, Program, IdentifierName, IdentifierReference, BindingIdentifier, LabelIdentifier, TSIndexSignatureName, ParseResult, ParserOptions, Function, ArrowFunctionExpression, VariableDeclaration, ImportDeclarationSpecifier, ImportDeclaration, CatchClause } from 'oxc-parser';
|
||||
|
||||
interface WalkerCallbackContext {
|
||||
/**
|
||||
* The key of the current node within its parent node object, if applicable.
|
||||
*
|
||||
* For instance, when processing a `VariableDeclarator` node, this would be the `declarations` key of the parent `VariableDeclaration` node.
|
||||
* @example
|
||||
* {
|
||||
* type: 'VariableDeclaration',
|
||||
* declarations: [[Object]],
|
||||
* // ...
|
||||
* },
|
||||
* { // <-- when processing this, the key would be 'declarations'
|
||||
* type: 'VariableDeclarator',
|
||||
* // ...
|
||||
* },
|
||||
*/
|
||||
key: string | number | symbol | null | undefined;
|
||||
/**
|
||||
* The zero-based index of the current node within its parent's children array, if applicable.
|
||||
* For instance, when processing a `VariableDeclarator` node,
|
||||
* this would be the index of the current `VariableDeclarator` node within the `declarations` array.
|
||||
*
|
||||
* This is `null` when the node is not part of an array.
|
||||
*
|
||||
* @example
|
||||
* {
|
||||
* type: 'VariableDeclaration',
|
||||
* declarations: [[Object]],
|
||||
* // ...
|
||||
* },
|
||||
* { // <-- when processing this, the index would be 0
|
||||
* type: 'VariableDeclarator',
|
||||
* // ...
|
||||
* },
|
||||
*/
|
||||
index: number | null;
|
||||
/**
|
||||
* The full Abstract Syntax Tree (AST) that is being walked, starting from the root node.
|
||||
*/
|
||||
ast: Program | Node;
|
||||
}
|
||||
interface WalkerThisContextLeave {
|
||||
/**
|
||||
* Remove the current node from the AST.
|
||||
* @remarks
|
||||
* - The `ScopeTracker` currently does not support node removal
|
||||
* @see ScopeTracker
|
||||
*/
|
||||
remove: () => void;
|
||||
/**
|
||||
* Replace the current node with another node.
|
||||
* After replacement, the walker will continue with the next sibling of the replaced node.
|
||||
*
|
||||
* In case the current node was removed in the `enter` phase, this will put the new node in
|
||||
* the place of the removed node - essentially undoing the removal.
|
||||
* @remarks
|
||||
* - The `ScopeTracker` currently does not support node replacement
|
||||
* @see ScopeTracker
|
||||
*/
|
||||
replace: (node: Node) => void;
|
||||
}
|
||||
interface WalkerThisContextEnter extends WalkerThisContextLeave {
|
||||
/**
|
||||
* Skip traversing the child nodes of the current node.
|
||||
*/
|
||||
skip: () => void;
|
||||
/**
|
||||
* Remove the current node and all of its children from the AST.
|
||||
* @remarks
|
||||
* - The `ScopeTracker` currently does not support node removal
|
||||
* @see ScopeTracker
|
||||
*/
|
||||
remove: () => void;
|
||||
/**
|
||||
* Replace the current node with another node.
|
||||
* After replacement, the walker will continue to traverse the children of the new node.
|
||||
*
|
||||
* If you want to replace the current node and skip traversing its children, call `this.skip()` after calling `this.replace(newNode)`.
|
||||
* @remarks
|
||||
* - The `ScopeTracker` currently does not support node replacement
|
||||
* @see this.skip
|
||||
* @see ScopeTracker
|
||||
*/
|
||||
replace: (node: Node) => void;
|
||||
}
|
||||
type WalkerCallback<T extends WalkerThisContextLeave> = (this: T, node: Node, parent: Node | null, ctx: WalkerCallbackContext) => void;
|
||||
type WalkerEnter = WalkerCallback<WalkerThisContextEnter>;
|
||||
type WalkerLeave = WalkerCallback<WalkerThisContextLeave>;
|
||||
|
||||
interface _WalkOptions {
|
||||
/**
|
||||
* The instance of `ScopeTracker` to use for tracking declarations and references.
|
||||
* @see ScopeTracker
|
||||
* @default undefined
|
||||
*/
|
||||
scopeTracker: ScopeTracker;
|
||||
}
|
||||
interface WalkOptions extends Partial<_WalkOptions> {
|
||||
/**
|
||||
* The function to be called when entering a node.
|
||||
*/
|
||||
enter: WalkerEnter;
|
||||
/**
|
||||
* The function to be called when leaving a node.
|
||||
*/
|
||||
leave: WalkerLeave;
|
||||
}
|
||||
|
||||
type Identifier = IdentifierName | IdentifierReference | BindingIdentifier | LabelIdentifier | TSIndexSignatureName;
|
||||
/**
|
||||
* Walk the AST with the given options.
|
||||
* @param input The AST to walk.
|
||||
* @param options The options to be used when walking the AST. Here you can specify the callbacks for entering and leaving nodes, as well as other options.
|
||||
*/
|
||||
declare function walk(input: Program | Node, options: Partial<WalkOptions>): Node | null;
|
||||
interface ParseAndWalkOptions extends WalkOptions {
|
||||
/**
|
||||
* The options for `oxc-parser` to use when parsing the code.
|
||||
*/
|
||||
parseOptions: ParserOptions;
|
||||
}
|
||||
/**
|
||||
* Parse the code and walk the AST with the given callback, which is called when entering a node.
|
||||
* @param code The string with the code to parse and walk. This can be JavaScript, TypeScript, jsx, or tsx.
|
||||
* @param sourceFilename The filename of the source code. This is used to determine the language of the code, unless
|
||||
* it is specified in the parse options.
|
||||
* @param callback The callback to be called when entering a node.
|
||||
*/
|
||||
declare function parseAndWalk(code: string, sourceFilename: string, callback: WalkerEnter): ParseResult;
|
||||
/**
|
||||
* Parse the code and walk the AST with the given callback(s).
|
||||
* @param code The string with the code to parse and walk. This can be JavaScript, TypeScript, jsx, or tsx.
|
||||
* @param sourceFilename The filename of the source code. This is used to determine the language of the code, unless
|
||||
* it is specified in the parse options.
|
||||
* @param options The options to be used when walking the AST. Here you can specify the callbacks for entering and leaving nodes, as well as other options.
|
||||
*/
|
||||
declare function parseAndWalk(code: string, sourceFilename: string, options: Partial<ParseAndWalkOptions>): ParseResult;
|
||||
|
||||
interface ScopeTrackerProtected {
|
||||
processNodeEnter: (node: Node) => void;
|
||||
processNodeLeave: (node: Node) => void;
|
||||
}
|
||||
/**
|
||||
* Tracks variable scopes and identifier declarations within a JavaScript AST.
|
||||
*
|
||||
* Maintains a stack of scopes, each represented as a map from identifier names to their declaration nodes,
|
||||
* enabling efficient lookup of the declaration.
|
||||
*
|
||||
* The ScopeTracker is designed to integrate with the `walk` function,
|
||||
* it automatically manages scope creation and identifier tracking,
|
||||
* so only query and inspection methods are exposed for external use.
|
||||
*
|
||||
* ### Scope tracking
|
||||
* A new scope is created when entering blocks, function parameters, loop variables, etc.
|
||||
* Note that this representation may split a single JavaScript lexical scope into multiple internal scopes,
|
||||
* meaning it doesn't mirror JavaScript’s scoping 1:1.
|
||||
*
|
||||
* Scopes are represented using a string-based index like `"0-1-2"`, which tracks depth and ancestry.
|
||||
*
|
||||
* #### Root scope
|
||||
* The root scope is represented by an empty string `""`.
|
||||
*
|
||||
* #### Scope key format
|
||||
* Scope keys are hierarchical strings that uniquely identify each scope and its position in the tree.
|
||||
* They are constructed using a depth-based indexing scheme, where:
|
||||
*
|
||||
* - the root scope is represented by an empty string `""`.
|
||||
* - the first child scope is `"0"`.
|
||||
* - a parallel sibling of `"0"` becomes `"1"`, `"2"`, etc.
|
||||
* - a nested scope under `"0"` is `"0-0"`, then its sibling is `"0-1"`, and so on.
|
||||
*
|
||||
* Each segment in the key corresponds to the zero-based index of the scope at that depth level in
|
||||
* the order of AST traversal.
|
||||
*
|
||||
* ### Additional features
|
||||
* - supports freezing the tracker to allow for second passes through the AST without modifying the scope data
|
||||
* (useful for doing a pre-pass to collect all identifiers before walking).
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const scopeTracker = new ScopeTracker()
|
||||
* walk(code, {
|
||||
* scopeTracker,
|
||||
* enter(node) {
|
||||
* // ...
|
||||
* },
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @see parseAndWalk
|
||||
* @see walk
|
||||
*/
|
||||
declare class ScopeTracker {
|
||||
protected scopeIndexStack: number[];
|
||||
protected scopeIndexKey: string;
|
||||
protected scopes: Map<string, Map<string, ScopeTrackerNode>>;
|
||||
protected options: Partial<ScopeTrackerOptions>;
|
||||
protected isFrozen: boolean;
|
||||
constructor(options?: ScopeTrackerOptions);
|
||||
protected updateScopeIndexKey(): void;
|
||||
protected pushScope(): void;
|
||||
protected popScope(): void;
|
||||
protected declareIdentifier(name: string, data: ScopeTrackerNode): void;
|
||||
protected declareFunctionParameter(param: Node, fn: Function | ArrowFunctionExpression): void;
|
||||
protected declarePattern(pattern: Node, parent: VariableDeclaration | ArrowFunctionExpression | CatchClause | Function): void;
|
||||
protected processNodeEnter: ScopeTrackerProtected["processNodeEnter"];
|
||||
protected processNodeLeave: ScopeTrackerProtected["processNodeLeave"];
|
||||
/**
|
||||
* Check if an identifier is declared in the current scope or any parent scope.
|
||||
* @param name the identifier name to check
|
||||
*/
|
||||
isDeclared(name: string): boolean;
|
||||
/**
|
||||
* Get the declaration node for a given identifier name.
|
||||
* @param name the identifier name to look up
|
||||
*/
|
||||
getDeclaration(name: string): ScopeTrackerNode | null;
|
||||
/**
|
||||
* Get the current scope key.
|
||||
*/
|
||||
getCurrentScope(): string;
|
||||
/**
|
||||
* Check if the current scope is a child of a specific scope.
|
||||
* @example
|
||||
* ```ts
|
||||
* // current scope is 0-1
|
||||
* isCurrentScopeUnder('0') // true
|
||||
* isCurrentScopeUnder('0-1') // false
|
||||
* ```
|
||||
*
|
||||
* @param scope the parent scope key to check against
|
||||
* @returns `true` if the current scope is a child of the specified scope, `false` otherwise (also when they are the same)
|
||||
*/
|
||||
isCurrentScopeUnder(scope: string): boolean;
|
||||
/**
|
||||
* Freezes the ScopeTracker, preventing further modifications to its state.
|
||||
* It also resets the scope index stack to its initial state so that the tracker can be reused.
|
||||
*
|
||||
* This is useful for second passes through the AST.
|
||||
*/
|
||||
freeze(): void;
|
||||
}
|
||||
declare function isBindingIdentifier(node: Node, parent: Node | null): boolean;
|
||||
declare function getUndeclaredIdentifiersInFunction(node: Function | ArrowFunctionExpression): string[];
|
||||
declare abstract class BaseNode<T extends Node = Node> {
|
||||
abstract type: string;
|
||||
readonly scope: string;
|
||||
node: T;
|
||||
constructor(node: T, scope: string);
|
||||
/**
|
||||
* The starting position of the entire node relevant for code transformation.
|
||||
* For instance, for a reference to a variable (ScopeTrackerVariable -> Identifier), this would refer to the start of the VariableDeclaration.
|
||||
*/
|
||||
abstract get start(): number;
|
||||
/**
|
||||
* The ending position of the entire node relevant for code transformation.
|
||||
* For instance, for a reference to a variable (ScopeTrackerVariable -> Identifier), this would refer to the end of the VariableDeclaration.
|
||||
*/
|
||||
abstract get end(): number;
|
||||
/**
|
||||
* Check if the node is defined under a specific scope.
|
||||
* @param scope
|
||||
*/
|
||||
isUnderScope(scope: string): boolean;
|
||||
}
|
||||
declare class ScopeTrackerIdentifier extends BaseNode<Identifier> {
|
||||
type: "Identifier";
|
||||
get start(): number;
|
||||
get end(): number;
|
||||
}
|
||||
declare class ScopeTrackerFunctionParam extends BaseNode {
|
||||
type: "FunctionParam";
|
||||
fnNode: Function | ArrowFunctionExpression;
|
||||
constructor(node: Node, scope: string, fnNode: Function | ArrowFunctionExpression);
|
||||
/**
|
||||
* @deprecated The representation of this position may change in the future. Use `.fnNode.start` instead for now.
|
||||
*/
|
||||
get start(): number;
|
||||
/**
|
||||
* @deprecated The representation of this position may change in the future. Use `.fnNode.end` instead for now.
|
||||
*/
|
||||
get end(): number;
|
||||
}
|
||||
declare class ScopeTrackerFunction extends BaseNode<Function | ArrowFunctionExpression> {
|
||||
type: "Function";
|
||||
get start(): number;
|
||||
get end(): number;
|
||||
}
|
||||
declare class ScopeTrackerVariable extends BaseNode<Identifier> {
|
||||
type: "Variable";
|
||||
variableNode: VariableDeclaration;
|
||||
constructor(node: Identifier, scope: string, variableNode: VariableDeclaration);
|
||||
get start(): number;
|
||||
get end(): number;
|
||||
}
|
||||
declare class ScopeTrackerImport extends BaseNode<ImportDeclarationSpecifier> {
|
||||
type: "Import";
|
||||
importNode: ImportDeclaration;
|
||||
constructor(node: ImportDeclarationSpecifier, scope: string, importNode: ImportDeclaration);
|
||||
get start(): number;
|
||||
get end(): number;
|
||||
}
|
||||
declare class ScopeTrackerCatchParam extends BaseNode {
|
||||
type: "CatchParam";
|
||||
catchNode: CatchClause;
|
||||
constructor(node: Node, scope: string, catchNode: CatchClause);
|
||||
get start(): number;
|
||||
get end(): number;
|
||||
}
|
||||
type ScopeTrackerNode = ScopeTrackerFunctionParam | ScopeTrackerFunction | ScopeTrackerVariable | ScopeTrackerIdentifier | ScopeTrackerImport | ScopeTrackerCatchParam;
|
||||
interface ScopeTrackerOptions {
|
||||
/**
|
||||
* If true, the scope tracker will preserve exited scopes in memory.
|
||||
* This is necessary when you want to do a pre-pass to collect all identifiers before walking, for example.
|
||||
* @default false
|
||||
*/
|
||||
preserveExitedScopes?: boolean;
|
||||
}
|
||||
|
||||
export { ScopeTracker, getUndeclaredIdentifiersInFunction, isBindingIdentifier, parseAndWalk, walk };
|
||||
export type { Identifier, ScopeTrackerNode };
|
||||
627
Frontend-Learner/node_modules/oxc-walker/dist/index.mjs
generated
vendored
Normal file
627
Frontend-Learner/node_modules/oxc-walker/dist/index.mjs
generated
vendored
Normal file
|
|
@ -0,0 +1,627 @@
|
|||
import { createRegExp, exactly, anyOf } from 'magic-regexp/further-magic';
|
||||
import { parseSync } from 'oxc-parser';
|
||||
|
||||
function isNode(v) {
|
||||
return v !== null && typeof v === "object" && v.type != null && typeof v.type === "string";
|
||||
}
|
||||
|
||||
class WalkerBase {
|
||||
scopeTracker;
|
||||
enter;
|
||||
leave;
|
||||
contextEnter = {
|
||||
skip: () => {
|
||||
this._skip = true;
|
||||
},
|
||||
remove: () => {
|
||||
this._remove = true;
|
||||
},
|
||||
replace: (node) => {
|
||||
this._replacement = node;
|
||||
}
|
||||
};
|
||||
contextLeave = {
|
||||
remove: this.contextEnter.remove,
|
||||
replace: this.contextEnter.replace
|
||||
};
|
||||
_skip = false;
|
||||
_remove = false;
|
||||
_replacement = null;
|
||||
constructor(handler, options) {
|
||||
this.enter = handler.enter;
|
||||
this.leave = handler.leave;
|
||||
this.scopeTracker = options?.scopeTracker;
|
||||
}
|
||||
replace(parent, key, index, node) {
|
||||
if (!parent || key === null) {
|
||||
return;
|
||||
}
|
||||
if (index !== null) {
|
||||
parent[key][index] = node;
|
||||
} else {
|
||||
parent[key] = node;
|
||||
}
|
||||
}
|
||||
insert(parent, key, index, node) {
|
||||
if (!parent || key === null) return;
|
||||
if (index !== null) {
|
||||
parent[key].splice(index, 0, node);
|
||||
} else {
|
||||
parent[key] = node;
|
||||
}
|
||||
}
|
||||
remove(parent, key, index) {
|
||||
if (!parent || key === null) {
|
||||
return;
|
||||
}
|
||||
if (index !== null) {
|
||||
parent[key].splice(index, 1);
|
||||
} else {
|
||||
delete parent[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WalkerSync extends WalkerBase {
|
||||
constructor(handler, options) {
|
||||
super(handler, options);
|
||||
}
|
||||
traverse(input, key, index, parent) {
|
||||
const ast = input;
|
||||
const ctx = { key: null, index: index ?? null, ast };
|
||||
const hasScopeTracker = !!this.scopeTracker;
|
||||
const _walk = (input2, parent2, key2, index2, skip) => {
|
||||
if (!isNode(input2)) {
|
||||
return null;
|
||||
}
|
||||
this.scopeTracker?.processNodeEnter(input2);
|
||||
let currentNode = input2;
|
||||
let removedInEnter = false;
|
||||
let skipChildren = skip;
|
||||
if (this.enter && !skip) {
|
||||
const _skip = this._skip;
|
||||
const _remove = this._remove;
|
||||
const _replacement = this._replacement;
|
||||
this._skip = false;
|
||||
this._remove = false;
|
||||
this._replacement = null;
|
||||
ctx.key = key2;
|
||||
ctx.index = index2;
|
||||
this.enter.call(this.contextEnter, input2, parent2, ctx);
|
||||
if (this._replacement && !this._remove) {
|
||||
currentNode = this._replacement;
|
||||
this.replace(parent2, key2, index2, this._replacement);
|
||||
}
|
||||
if (this._remove) {
|
||||
removedInEnter = true;
|
||||
currentNode = null;
|
||||
this.remove(parent2, key2, index2);
|
||||
}
|
||||
if (this._skip) {
|
||||
skipChildren = true;
|
||||
}
|
||||
this._skip = _skip;
|
||||
this._remove = _remove;
|
||||
this._replacement = _replacement;
|
||||
}
|
||||
if ((!skipChildren || hasScopeTracker) && currentNode) {
|
||||
for (const k in currentNode) {
|
||||
const node = currentNode[k];
|
||||
if (!node || typeof node !== "object") {
|
||||
continue;
|
||||
}
|
||||
if (Array.isArray(node)) {
|
||||
for (let i = 0; i < node.length; i++) {
|
||||
const child = node[i];
|
||||
if (isNode(child)) {
|
||||
if (_walk(
|
||||
child,
|
||||
currentNode,
|
||||
k,
|
||||
i,
|
||||
skipChildren
|
||||
) === null) {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isNode(node)) {
|
||||
_walk(node, currentNode, k, null, skipChildren);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.scopeTracker?.processNodeLeave(input2);
|
||||
if (this.leave && !skip) {
|
||||
const _replacement = this._replacement;
|
||||
const _remove = this._remove;
|
||||
this._replacement = null;
|
||||
this._remove = false;
|
||||
ctx.key = key2;
|
||||
ctx.index = index2;
|
||||
this.leave.call(this.contextLeave, input2, parent2, ctx);
|
||||
if (this._replacement && !this._remove) {
|
||||
currentNode = this._replacement;
|
||||
if (removedInEnter) {
|
||||
this.insert(parent2, key2, index2, this._replacement);
|
||||
} else {
|
||||
this.replace(parent2, key2, index2, this._replacement);
|
||||
}
|
||||
}
|
||||
if (this._remove) {
|
||||
currentNode = null;
|
||||
this.remove(parent2, key2, index2);
|
||||
}
|
||||
this._replacement = _replacement;
|
||||
this._remove = _remove;
|
||||
}
|
||||
return currentNode;
|
||||
};
|
||||
return _walk(input, parent ?? null, key ?? null, index ?? null, false);
|
||||
}
|
||||
}
|
||||
|
||||
function walk(input, options) {
|
||||
return new WalkerSync(
|
||||
{
|
||||
enter: options.enter,
|
||||
leave: options.leave
|
||||
},
|
||||
{
|
||||
scopeTracker: options.scopeTracker
|
||||
}
|
||||
).traverse(input);
|
||||
}
|
||||
const LANG_RE = createRegExp(
|
||||
exactly("jsx").or("tsx").or("js").or("ts").groupedAs("lang").after(exactly(".").and(anyOf("c", "m").optionally())).at.lineEnd()
|
||||
);
|
||||
function parseAndWalk(code, sourceFilename, arg3) {
|
||||
const lang = sourceFilename?.match(LANG_RE)?.groups?.lang;
|
||||
const { parseOptions: _parseOptions = {}, ...options } = typeof arg3 === "function" ? { enter: arg3 } : arg3;
|
||||
const parseOptions = {
|
||||
sourceType: "module",
|
||||
lang,
|
||||
..._parseOptions
|
||||
};
|
||||
const ast = parseSync(sourceFilename, code, parseOptions);
|
||||
walk(ast.program, options);
|
||||
return ast;
|
||||
}
|
||||
|
||||
class ScopeTracker {
|
||||
scopeIndexStack = [];
|
||||
scopeIndexKey = "";
|
||||
scopes = /* @__PURE__ */ new Map();
|
||||
options;
|
||||
isFrozen = false;
|
||||
constructor(options = {}) {
|
||||
this.options = options;
|
||||
}
|
||||
updateScopeIndexKey() {
|
||||
this.scopeIndexKey = this.scopeIndexStack.slice(0, -1).join("-");
|
||||
}
|
||||
pushScope() {
|
||||
this.scopeIndexStack.push(0);
|
||||
this.updateScopeIndexKey();
|
||||
}
|
||||
popScope() {
|
||||
this.scopeIndexStack.pop();
|
||||
if (this.scopeIndexStack[this.scopeIndexStack.length - 1] !== void 0) {
|
||||
this.scopeIndexStack[this.scopeIndexStack.length - 1]++;
|
||||
}
|
||||
if (!this.options.preserveExitedScopes) {
|
||||
this.scopes.delete(this.scopeIndexKey);
|
||||
}
|
||||
this.updateScopeIndexKey();
|
||||
}
|
||||
declareIdentifier(name, data) {
|
||||
if (this.isFrozen) {
|
||||
return;
|
||||
}
|
||||
let scope = this.scopes.get(this.scopeIndexKey);
|
||||
if (!scope) {
|
||||
scope = /* @__PURE__ */ new Map();
|
||||
this.scopes.set(this.scopeIndexKey, scope);
|
||||
}
|
||||
scope.set(name, data);
|
||||
}
|
||||
declareFunctionParameter(param, fn) {
|
||||
if (this.isFrozen) {
|
||||
return;
|
||||
}
|
||||
const identifiers = getPatternIdentifiers(param);
|
||||
for (const identifier of identifiers) {
|
||||
this.declareIdentifier(
|
||||
identifier.name,
|
||||
new ScopeTrackerFunctionParam(identifier, this.scopeIndexKey, fn)
|
||||
);
|
||||
}
|
||||
}
|
||||
declarePattern(pattern, parent) {
|
||||
if (this.isFrozen) {
|
||||
return;
|
||||
}
|
||||
const identifiers = getPatternIdentifiers(pattern);
|
||||
for (const identifier of identifiers) {
|
||||
this.declareIdentifier(
|
||||
identifier.name,
|
||||
parent.type === "VariableDeclaration" ? new ScopeTrackerVariable(identifier, this.scopeIndexKey, parent) : parent.type === "CatchClause" ? new ScopeTrackerCatchParam(identifier, this.scopeIndexKey, parent) : new ScopeTrackerFunctionParam(
|
||||
identifier,
|
||||
this.scopeIndexKey,
|
||||
parent
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
processNodeEnter = (node) => {
|
||||
switch (node.type) {
|
||||
case "Program":
|
||||
case "BlockStatement":
|
||||
case "StaticBlock":
|
||||
this.pushScope();
|
||||
break;
|
||||
case "FunctionDeclaration":
|
||||
if (node.id?.name) {
|
||||
this.declareIdentifier(
|
||||
node.id.name,
|
||||
new ScopeTrackerFunction(node, this.scopeIndexKey)
|
||||
);
|
||||
}
|
||||
this.pushScope();
|
||||
for (const param of node.params) {
|
||||
this.declareFunctionParameter(param, node);
|
||||
}
|
||||
break;
|
||||
case "FunctionExpression":
|
||||
this.pushScope();
|
||||
if (node.id?.name) {
|
||||
this.declareIdentifier(
|
||||
node.id.name,
|
||||
new ScopeTrackerFunction(node, this.scopeIndexKey)
|
||||
);
|
||||
}
|
||||
this.pushScope();
|
||||
for (const param of node.params) {
|
||||
this.declareFunctionParameter(param, node);
|
||||
}
|
||||
break;
|
||||
case "ArrowFunctionExpression":
|
||||
this.pushScope();
|
||||
for (const param of node.params) {
|
||||
this.declareFunctionParameter(param, node);
|
||||
}
|
||||
break;
|
||||
case "VariableDeclaration":
|
||||
for (const decl of node.declarations) {
|
||||
this.declarePattern(decl.id, node);
|
||||
}
|
||||
break;
|
||||
case "ClassDeclaration":
|
||||
if (node.id?.name) {
|
||||
this.declareIdentifier(
|
||||
node.id.name,
|
||||
new ScopeTrackerIdentifier(node.id, this.scopeIndexKey)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "ClassExpression":
|
||||
this.pushScope();
|
||||
if (node.id?.name) {
|
||||
this.declareIdentifier(
|
||||
node.id.name,
|
||||
new ScopeTrackerIdentifier(node.id, this.scopeIndexKey)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "ImportDeclaration":
|
||||
for (const specifier of node.specifiers) {
|
||||
this.declareIdentifier(
|
||||
specifier.local.name,
|
||||
new ScopeTrackerImport(specifier, this.scopeIndexKey, node)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "CatchClause":
|
||||
this.pushScope();
|
||||
if (node.param) {
|
||||
this.declarePattern(node.param, node);
|
||||
}
|
||||
break;
|
||||
case "ForStatement":
|
||||
case "ForOfStatement":
|
||||
case "ForInStatement":
|
||||
this.pushScope();
|
||||
if (node.type === "ForStatement" && node.init?.type === "VariableDeclaration") {
|
||||
for (const decl of node.init.declarations) {
|
||||
this.declarePattern(decl.id, node.init);
|
||||
}
|
||||
} else if ((node.type === "ForOfStatement" || node.type === "ForInStatement") && node.left.type === "VariableDeclaration") {
|
||||
for (const decl of node.left.declarations) {
|
||||
this.declarePattern(decl.id, node.left);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
processNodeLeave = (node) => {
|
||||
switch (node.type) {
|
||||
case "Program":
|
||||
case "BlockStatement":
|
||||
case "CatchClause":
|
||||
case "FunctionDeclaration":
|
||||
case "ArrowFunctionExpression":
|
||||
case "StaticBlock":
|
||||
case "ClassExpression":
|
||||
case "ForStatement":
|
||||
case "ForOfStatement":
|
||||
case "ForInStatement":
|
||||
this.popScope();
|
||||
break;
|
||||
case "FunctionExpression":
|
||||
this.popScope();
|
||||
this.popScope();
|
||||
break;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Check if an identifier is declared in the current scope or any parent scope.
|
||||
* @param name the identifier name to check
|
||||
*/
|
||||
isDeclared(name) {
|
||||
if (!this.scopeIndexKey) {
|
||||
return this.scopes.get("")?.has(name) || false;
|
||||
}
|
||||
const indices = this.scopeIndexKey.split("-").map(Number);
|
||||
for (let i = indices.length; i >= 0; i--) {
|
||||
if (this.scopes.get(indices.slice(0, i).join("-"))?.has(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Get the declaration node for a given identifier name.
|
||||
* @param name the identifier name to look up
|
||||
*/
|
||||
getDeclaration(name) {
|
||||
if (!this.scopeIndexKey) {
|
||||
return this.scopes.get("")?.get(name) ?? null;
|
||||
}
|
||||
const indices = this.scopeIndexKey.split("-").map(Number);
|
||||
for (let i = indices.length; i >= 0; i--) {
|
||||
const node = this.scopes.get(indices.slice(0, i).join("-"))?.get(name);
|
||||
if (node) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Get the current scope key.
|
||||
*/
|
||||
getCurrentScope() {
|
||||
return this.scopeIndexKey;
|
||||
}
|
||||
/**
|
||||
* Check if the current scope is a child of a specific scope.
|
||||
* @example
|
||||
* ```ts
|
||||
* // current scope is 0-1
|
||||
* isCurrentScopeUnder('0') // true
|
||||
* isCurrentScopeUnder('0-1') // false
|
||||
* ```
|
||||
*
|
||||
* @param scope the parent scope key to check against
|
||||
* @returns `true` if the current scope is a child of the specified scope, `false` otherwise (also when they are the same)
|
||||
*/
|
||||
isCurrentScopeUnder(scope) {
|
||||
return isChildScope(this.scopeIndexKey, scope);
|
||||
}
|
||||
/**
|
||||
* Freezes the ScopeTracker, preventing further modifications to its state.
|
||||
* It also resets the scope index stack to its initial state so that the tracker can be reused.
|
||||
*
|
||||
* This is useful for second passes through the AST.
|
||||
*/
|
||||
freeze() {
|
||||
this.isFrozen = true;
|
||||
this.scopeIndexStack = [];
|
||||
this.updateScopeIndexKey();
|
||||
}
|
||||
}
|
||||
function getPatternIdentifiers(pattern) {
|
||||
const identifiers = [];
|
||||
function collectIdentifiers(pattern2) {
|
||||
switch (pattern2.type) {
|
||||
case "Identifier":
|
||||
identifiers.push(pattern2);
|
||||
break;
|
||||
case "AssignmentPattern":
|
||||
collectIdentifiers(pattern2.left);
|
||||
break;
|
||||
case "RestElement":
|
||||
collectIdentifiers(pattern2.argument);
|
||||
break;
|
||||
case "ArrayPattern":
|
||||
for (const element of pattern2.elements) {
|
||||
if (element) {
|
||||
collectIdentifiers(
|
||||
element.type === "RestElement" ? element.argument : element
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "ObjectPattern":
|
||||
for (const property of pattern2.properties) {
|
||||
collectIdentifiers(
|
||||
property.type === "RestElement" ? property.argument : property.value
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
collectIdentifiers(pattern);
|
||||
return identifiers;
|
||||
}
|
||||
function isBindingIdentifier(node, parent) {
|
||||
if (!parent || node.type !== "Identifier") {
|
||||
return false;
|
||||
}
|
||||
switch (parent.type) {
|
||||
case "FunctionDeclaration":
|
||||
case "FunctionExpression":
|
||||
case "ArrowFunctionExpression":
|
||||
if (parent.type !== "ArrowFunctionExpression" && parent.id === node) {
|
||||
return true;
|
||||
}
|
||||
if (parent.params.length) {
|
||||
for (const param of parent.params) {
|
||||
const identifiers = getPatternIdentifiers(param);
|
||||
if (identifiers.includes(node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case "ClassDeclaration":
|
||||
case "ClassExpression":
|
||||
return parent.id === node;
|
||||
case "MethodDefinition":
|
||||
return parent.key === node;
|
||||
case "PropertyDefinition":
|
||||
return parent.key === node;
|
||||
case "VariableDeclarator":
|
||||
return getPatternIdentifiers(parent.id).includes(node);
|
||||
case "CatchClause":
|
||||
if (!parent.param) {
|
||||
return false;
|
||||
}
|
||||
return getPatternIdentifiers(parent.param).includes(node);
|
||||
case "Property":
|
||||
return parent.key === node && parent.value !== node;
|
||||
case "MemberExpression":
|
||||
return parent.property === node;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function getUndeclaredIdentifiersInFunction(node) {
|
||||
const scopeTracker = new ScopeTracker({
|
||||
preserveExitedScopes: true
|
||||
});
|
||||
const undeclaredIdentifiers = /* @__PURE__ */ new Set();
|
||||
function isIdentifierUndeclared(node2, parent) {
|
||||
return !isBindingIdentifier(node2, parent) && !scopeTracker.isDeclared(node2.name);
|
||||
}
|
||||
walk(node, {
|
||||
scopeTracker
|
||||
});
|
||||
scopeTracker.freeze();
|
||||
walk(node, {
|
||||
scopeTracker,
|
||||
enter(node2, parent) {
|
||||
if (node2.type === "Identifier" && isIdentifierUndeclared(node2, parent)) {
|
||||
undeclaredIdentifiers.add(node2.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
return Array.from(undeclaredIdentifiers);
|
||||
}
|
||||
function isChildScope(a, b) {
|
||||
return a.startsWith(b) && a.length > b.length;
|
||||
}
|
||||
class BaseNode {
|
||||
scope;
|
||||
node;
|
||||
constructor(node, scope) {
|
||||
this.node = node;
|
||||
this.scope = scope;
|
||||
}
|
||||
/**
|
||||
* Check if the node is defined under a specific scope.
|
||||
* @param scope
|
||||
*/
|
||||
isUnderScope(scope) {
|
||||
return isChildScope(this.scope, scope);
|
||||
}
|
||||
}
|
||||
class ScopeTrackerIdentifier extends BaseNode {
|
||||
type = "Identifier";
|
||||
get start() {
|
||||
return this.node.start;
|
||||
}
|
||||
get end() {
|
||||
return this.node.end;
|
||||
}
|
||||
}
|
||||
class ScopeTrackerFunctionParam extends BaseNode {
|
||||
type = "FunctionParam";
|
||||
fnNode;
|
||||
constructor(node, scope, fnNode) {
|
||||
super(node, scope);
|
||||
this.fnNode = fnNode;
|
||||
}
|
||||
/**
|
||||
* @deprecated The representation of this position may change in the future. Use `.fnNode.start` instead for now.
|
||||
*/
|
||||
get start() {
|
||||
return this.fnNode.start;
|
||||
}
|
||||
/**
|
||||
* @deprecated The representation of this position may change in the future. Use `.fnNode.end` instead for now.
|
||||
*/
|
||||
get end() {
|
||||
return this.fnNode.end;
|
||||
}
|
||||
}
|
||||
class ScopeTrackerFunction extends BaseNode {
|
||||
type = "Function";
|
||||
get start() {
|
||||
return this.node.start;
|
||||
}
|
||||
get end() {
|
||||
return this.node.end;
|
||||
}
|
||||
}
|
||||
class ScopeTrackerVariable extends BaseNode {
|
||||
type = "Variable";
|
||||
variableNode;
|
||||
constructor(node, scope, variableNode) {
|
||||
super(node, scope);
|
||||
this.variableNode = variableNode;
|
||||
}
|
||||
get start() {
|
||||
return this.variableNode.start;
|
||||
}
|
||||
get end() {
|
||||
return this.variableNode.end;
|
||||
}
|
||||
}
|
||||
class ScopeTrackerImport extends BaseNode {
|
||||
type = "Import";
|
||||
importNode;
|
||||
constructor(node, scope, importNode) {
|
||||
super(node, scope);
|
||||
this.importNode = importNode;
|
||||
}
|
||||
get start() {
|
||||
return this.importNode.start;
|
||||
}
|
||||
get end() {
|
||||
return this.importNode.end;
|
||||
}
|
||||
}
|
||||
class ScopeTrackerCatchParam extends BaseNode {
|
||||
type = "CatchParam";
|
||||
catchNode;
|
||||
constructor(node, scope, catchNode) {
|
||||
super(node, scope);
|
||||
this.catchNode = catchNode;
|
||||
}
|
||||
get start() {
|
||||
return this.catchNode.start;
|
||||
}
|
||||
get end() {
|
||||
return this.catchNode.end;
|
||||
}
|
||||
}
|
||||
|
||||
export { ScopeTracker, getUndeclaredIdentifiersInFunction, isBindingIdentifier, parseAndWalk, walk };
|
||||
Loading…
Add table
Add a link
Reference in a new issue