181 lines
7.0 KiB
Plaintext
181 lines
7.0 KiB
Plaintext
import { walk } from 'estree-walker';
|
|
|
|
const isNodeInPatternWeakSet = /* @__PURE__ */ 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 = /* @__PURE__ */ new WeakMap();
|
|
const identifiers = [];
|
|
const setScope = (node, name) => {
|
|
let scopeIds = scopeMap.get(node);
|
|
if (scopeIds && scopeIds.has(name))
|
|
return;
|
|
if (!scopeIds) {
|
|
scopeIds = /* @__PURE__ */ 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 };
|