UNPKG

estree-toolkit

Version:

Traverser, scope tracker, and more tools for working with ESTree AST

193 lines (192 loc) 7.37 kB
export const hasBinding = (() => { const findInPattern = (node, bindingName) => { switch (node.type) { case 'Identifier': return node.name === bindingName; case 'ObjectPattern': { const { properties } = node; for (let i = 0; i < properties.length; i++) { const property = properties[i]; if (property.type === 'RestElement') { if (findInPattern(property.argument, bindingName)) return true; } else { /* istanbul ignore else */ if (property.value != null) { if (findInPattern(property.value, bindingName)) return true; } else { if (!property.computed && property.key.type === 'Identifier' && property.key.name === bindingName) { return true; } } } } break; } case 'ArrayPattern': { const { elements } = node; for (let i = 0; i < elements.length; i++) { const element = elements[i]; if (element == null) continue; if (findInPattern(element, bindingName)) return true; } break; } case 'RestElement': return findInPattern(node.argument, bindingName); case 'AssignmentPattern': return findInPattern(node.left, bindingName); } return false; }; const findInVariableDeclaration = (node, bindingName) => { const { declarations } = node; for (let i = 0; i < declarations.length; i++) { if (findInPattern(declarations[i].id, bindingName)) return true; } return false; }; const findInImportDeclaration = (node, bindingName) => { for (let i = 0; i < node.specifiers.length; i++) { const specifier = node.specifiers[i]; switch (specifier.type) { case 'ImportDefaultSpecifier': case 'ImportNamespaceSpecifier': if (specifier.local.name === bindingName) return true; break; case 'ImportSpecifier': /* istanbul ignore else */ if (specifier.local != null) { if (specifier.local.name === bindingName) return true; } else { if (specifier.imported.type === 'Identifier' && specifier.imported.name === bindingName) return true; } break; } } return false; }; const findInStatements = (statements, bindingName) => { var _a; for (let i = 0; i < statements.length; i++) { const statement = statements[i]; switch (statement.type) { case 'ImportDeclaration': { if (findInImportDeclaration(statement, bindingName)) { return true; } break; } case 'VariableDeclaration': { if (findInVariableDeclaration(statement, bindingName)) { return true; } break; } case 'FunctionDeclaration': case 'ClassDeclaration': { if (((_a = statement.id) === null || _a === void 0 ? void 0 : _a.name) === bindingName) return true; break; } } } return false; }; const parentTypes = [ 'BlockStatement', 'CatchClause', 'ForStatement', 'ForInStatement', 'ForOfStatement', 'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression', 'ClassDeclaration', 'ClassExpression', 'Program' ]; const findInParent = (path, bindingName) => { var _a, _b; const parent = path.findParent((p) => parentTypes.includes(p.type)); if (parent != null && parent.node != null) { const { node } = parent; switch (node.type) { case 'BlockStatement': { if (findInStatements(node.body, bindingName)) { return true; } break; } case 'CatchClause': { if (node.param != null && findInPattern(node.param, bindingName)) { return true; } break; } case 'ForStatement': { /* istanbul ignore else */ if (node.init != null && node.init.type === 'VariableDeclaration') { if (findInVariableDeclaration(node.init, bindingName)) { return true; } } break; } case 'ForInStatement': case 'ForOfStatement': { /* istanbul ignore else */ if (node.left.type === 'VariableDeclaration') { if (findInVariableDeclaration(node.left, bindingName)) { return true; } } break; } case 'FunctionDeclaration': case 'FunctionExpression': case 'ArrowFunctionExpression': { if (node.type !== 'ArrowFunctionExpression' && ((_a = node.id) === null || _a === void 0 ? void 0 : _a.name) === bindingName) return true; for (let i = 0; i < node.params.length; i++) { if (findInPattern(node.params[i], bindingName)) { return true; } } break; } case 'ClassExpression': case 'ClassDeclaration': { /* istanbul ignore else */ if (((_b = node.id) === null || _b === void 0 ? void 0 : _b.name) === bindingName) return true; break; } case 'Program': { if (findInStatements(node.body, bindingName)) { return true; } break; } } return findInParent(parent, bindingName); } return false; }; return (path, bindingName) => { return findInParent(path, bindingName); }; })();