| | import { walk } from 'estree-walker'; |
| |
|
| | const isNodeInPatternWeakSet = new WeakSet(); |
| | function setIsNodeInPattern(node) { |
| | return isNodeInPatternWeakSet.add(node); |
| | } |
| | function isNodeInPattern(node) { |
| | return isNodeInPatternWeakSet.has(node); |
| | } |
| | function esmWalker(root, { onIdentifier, onImportMeta, onDynamicImport, onCallExpression }) { |
| | const parentStack = []; |
| | const varKindStack = []; |
| | const scopeMap = new WeakMap(); |
| | const identifiers = []; |
| | const setScope = (node, name) => { |
| | let scopeIds = scopeMap.get(node); |
| | if (scopeIds && scopeIds.has(name)) |
| | return; |
| | if (!scopeIds) { |
| | scopeIds = new Set(); |
| | scopeMap.set(node, scopeIds); |
| | } |
| | scopeIds.add(name); |
| | }; |
| | function isInScope(name, parents) { |
| | return parents.some((node) => { |
| | var _a; |
| | return node && ((_a = scopeMap.get(node)) == null ? void 0 : _a.has(name)); |
| | }); |
| | } |
| | function handlePattern(p, parentScope) { |
| | if (p.type === "Identifier") { |
| | setScope(parentScope, p.name); |
| | } else if (p.type === "RestElement") { |
| | handlePattern(p.argument, parentScope); |
| | } else if (p.type === "ObjectPattern") { |
| | p.properties.forEach((property) => { |
| | if (property.type === "RestElement") |
| | setScope(parentScope, property.argument.name); |
| | else |
| | handlePattern(property.value, parentScope); |
| | }); |
| | } else if (p.type === "ArrayPattern") { |
| | p.elements.forEach((element) => { |
| | if (element) |
| | handlePattern(element, parentScope); |
| | }); |
| | } else if (p.type === "AssignmentPattern") { |
| | handlePattern(p.left, parentScope); |
| | } else { |
| | setScope(parentScope, p.name); |
| | } |
| | } |
| | walk(root, { |
| | enter(node, parent) { |
| | if (node.type === "ImportDeclaration") |
| | return this.skip(); |
| | if (parent && !(parent.type === "IfStatement" && node === parent.alternate)) |
| | parentStack.unshift(parent); |
| | if (node.type === "VariableDeclaration") |
| | varKindStack.unshift(node.kind); |
| | if (node.type === "CallExpression") |
| | onCallExpression == null ? void 0 : onCallExpression(node); |
| | if (node.type === "MetaProperty" && node.meta.name === "import") |
| | onImportMeta == null ? void 0 : onImportMeta(node); |
| | else if (node.type === "ImportExpression") |
| | onDynamicImport == null ? void 0 : onDynamicImport(node); |
| | if (node.type === "Identifier") { |
| | if (!isInScope(node.name, parentStack) && isRefIdentifier(node, parent, parentStack)) { |
| | identifiers.push([node, parentStack.slice(0)]); |
| | } |
| | } else if (isFunctionNode(node)) { |
| | if (node.type === "FunctionDeclaration") { |
| | const parentScope = findParentScope(parentStack); |
| | if (parentScope) |
| | setScope(parentScope, node.id.name); |
| | } |
| | node.params.forEach((p) => { |
| | if (p.type === "ObjectPattern" || p.type === "ArrayPattern") { |
| | handlePattern(p, node); |
| | return; |
| | } |
| | walk(p.type === "AssignmentPattern" ? p.left : p, { |
| | enter(child, parent2) { |
| | if ((parent2 == null ? void 0 : parent2.type) === "AssignmentPattern" && (parent2 == null ? void 0 : parent2.right) === child) |
| | return this.skip(); |
| | if (child.type !== "Identifier") |
| | return; |
| | if (isStaticPropertyKey(child, parent2)) |
| | return; |
| | if ((parent2 == null ? void 0 : parent2.type) === "TemplateLiteral" && (parent2 == null ? void 0 : parent2.expressions.includes(child)) || (parent2 == null ? void 0 : parent2.type) === "CallExpression" && (parent2 == null ? void 0 : parent2.callee) === child) |
| | return; |
| | setScope(node, child.name); |
| | } |
| | }); |
| | }); |
| | } else if (node.type === "Property" && parent.type === "ObjectPattern") { |
| | setIsNodeInPattern(node); |
| | } else if (node.type === "VariableDeclarator") { |
| | const parentFunction = findParentScope( |
| | parentStack, |
| | varKindStack[0] === "var" |
| | ); |
| | if (parentFunction) |
| | handlePattern(node.id, parentFunction); |
| | } else if (node.type === "CatchClause" && node.param) { |
| | handlePattern(node.param, node); |
| | } |
| | }, |
| | leave(node, parent) { |
| | if (parent && !(parent.type === "IfStatement" && node === parent.alternate)) |
| | parentStack.shift(); |
| | if (node.type === "VariableDeclaration") |
| | varKindStack.shift(); |
| | } |
| | }); |
| | identifiers.forEach(([node, stack]) => { |
| | if (!isInScope(node.name, stack)) { |
| | const parent = stack[0]; |
| | const grandparent = stack[1]; |
| | const hasBindingShortcut = isStaticProperty(parent) && parent.shorthand && (!isNodeInPattern(parent) || isInDestructuringAssignment(parent, parentStack)); |
| | const classDeclaration = parent.type === "PropertyDefinition" && (grandparent == null ? void 0 : grandparent.type) === "ClassBody" || parent.type === "ClassDeclaration" && node === parent.superClass; |
| | const classExpression = parent.type === "ClassExpression" && node === parent.id; |
| | onIdentifier == null ? void 0 : onIdentifier(node, { |
| | hasBindingShortcut, |
| | classDeclaration, |
| | classExpression |
| | }, stack); |
| | } |
| | }); |
| | } |
| | function isRefIdentifier(id, parent, parentStack) { |
| | if (parent.type === "CatchClause" || (parent.type === "VariableDeclarator" || parent.type === "ClassDeclaration") && parent.id === id) |
| | return false; |
| | if (isFunctionNode(parent)) { |
| | if (parent.id === id) |
| | return false; |
| | if (parent.params.includes(id)) |
| | return false; |
| | } |
| | if (parent.type === "MethodDefinition" && !parent.computed) |
| | return false; |
| | if (isStaticPropertyKey(id, parent)) |
| | return false; |
| | if (isNodeInPattern(parent) && parent.value === id) |
| | return false; |
| | if (parent.type === "ArrayPattern" && !isInDestructuringAssignment(parent, parentStack)) |
| | return false; |
| | if (parent.type === "MemberExpression" && parent.property === id && !parent.computed) |
| | return false; |
| | if (parent.type === "ExportSpecifier") |
| | return false; |
| | if (id.name === "arguments") |
| | return false; |
| | return true; |
| | } |
| | function isStaticProperty(node) { |
| | return node && node.type === "Property" && !node.computed; |
| | } |
| | function isStaticPropertyKey(node, parent) { |
| | return isStaticProperty(parent) && parent.key === node; |
| | } |
| | const functionNodeTypeRE = /Function(?:Expression|Declaration)$|Method$/; |
| | function isFunctionNode(node) { |
| | return functionNodeTypeRE.test(node.type); |
| | } |
| | const blockNodeTypeRE = /^BlockStatement$|^For(?:In|Of)?Statement$/; |
| | function isBlock(node) { |
| | return blockNodeTypeRE.test(node.type); |
| | } |
| | function findParentScope(parentStack, isVar = false) { |
| | return parentStack.find(isVar ? isFunctionNode : isBlock); |
| | } |
| | function isInDestructuringAssignment(parent, parentStack) { |
| | if (parent && (parent.type === "Property" || parent.type === "ArrayPattern")) |
| | return parentStack.some((i) => i.type === "AssignmentExpression"); |
| | return false; |
| | } |
| |
|
| | export { esmWalker, isFunctionNode, isInDestructuringAssignment, isNodeInPattern, isStaticProperty, isStaticPropertyKey, setIsNodeInPattern }; |
| |
|