diff options
| author | akiyamn | 2023-09-24 23:22:21 +1000 |
|---|---|---|
| committer | akiyamn | 2023-09-24 23:22:21 +1000 |
| commit | 4e87195739f2a5d9a05451b48773c8afdc680765 (patch) | |
| tree | 9cba501844a4a11dcbdffc4050ed8189561c55ed /node_modules/rollup-pluginutils/src/attachScopes.ts | |
| download | price-tracker-worker-4e87195739f2a5d9a05451b48773c8afdc680765.tar.gz price-tracker-worker-4e87195739f2a5d9a05451b48773c8afdc680765.zip | |
Initial commit (by create-cloudflare CLI)
Diffstat (limited to 'node_modules/rollup-pluginutils/src/attachScopes.ts')
| -rw-r--r-- | node_modules/rollup-pluginutils/src/attachScopes.ts | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/node_modules/rollup-pluginutils/src/attachScopes.ts b/node_modules/rollup-pluginutils/src/attachScopes.ts new file mode 100644 index 0000000..0809039 --- /dev/null +++ b/node_modules/rollup-pluginutils/src/attachScopes.ts @@ -0,0 +1,125 @@ +import { Node, walk } from 'estree-walker'; +import extractAssignedNames from './extractAssignedNames'; +import { AttachedScope, AttachScopes } from './pluginutils'; + +const blockDeclarations = { + const: true, + let: true +}; + +interface ScopeOptions { + parent?: AttachedScope; + block?: boolean; + params?: Array<Node>; +} + +class Scope implements AttachedScope { + parent?: AttachedScope; + isBlockScope: boolean; + declarations: { [key: string]: boolean }; + + constructor(options: ScopeOptions = {}) { + this.parent = options.parent; + this.isBlockScope = !!options.block; + + this.declarations = Object.create(null); + + if (options.params) { + options.params.forEach(param => { + extractAssignedNames(param).forEach(name => { + this.declarations[name] = true; + }); + }); + } + } + + addDeclaration(node: Node, isBlockDeclaration: boolean, isVar: boolean): void { + if (!isBlockDeclaration && this.isBlockScope) { + // it's a `var` or function node, and this + // is a block scope, so we need to go up + this.parent!.addDeclaration(node, isBlockDeclaration, isVar); + } else if (node.id) { + extractAssignedNames(node.id).forEach(name => { + this.declarations[name] = true; + }); + } + } + + contains(name: string): boolean { + return this.declarations[name] || (this.parent ? this.parent.contains(name) : false); + } +} + +const attachScopes: AttachScopes = function attachScopes(ast, propertyName = 'scope') { + let scope = new Scope(); + + walk(ast, { + enter(node, parent) { + // function foo () {...} + // class Foo {...} + if (/(Function|Class)Declaration/.test(node.type)) { + scope.addDeclaration(node, false, false); + } + + // var foo = 1 + if (node.type === 'VariableDeclaration') { + const kind: keyof typeof blockDeclarations = node.kind; + const isBlockDeclaration = blockDeclarations[kind]; + + node.declarations.forEach((declaration: Node) => { + scope.addDeclaration(declaration, isBlockDeclaration, true); + }); + } + + let newScope: AttachedScope | undefined; + + // create new function scope + if (/Function/.test(node.type)) { + newScope = new Scope({ + parent: scope, + block: false, + params: node.params + }); + + // named function expressions - the name is considered + // part of the function's scope + if (node.type === 'FunctionExpression' && node.id) { + newScope.addDeclaration(node, false, false); + } + } + + // create new block scope + if (node.type === 'BlockStatement' && !/Function/.test(parent!.type)) { + newScope = new Scope({ + parent: scope, + block: true + }); + } + + // catch clause has its own block scope + if (node.type === 'CatchClause') { + newScope = new Scope({ + parent: scope, + params: node.param ? [node.param] : [], + block: true + }); + } + + if (newScope) { + Object.defineProperty(node, propertyName, { + value: newScope, + configurable: true + }); + + scope = newScope; + } + }, + leave(node) { + if (node[propertyName]) scope = scope.parent!; + } + }); + + return scope; +}; + +export { attachScopes as default }; |
