UNPKG

fixclosure

Version:

JavaScript dependency checker/fixer for Closure Library based on ECMAScript AST

110 lines (109 loc) 3.61 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.leave = void 0; /** * Visitor for estraverse. */ function leave(node, uses) { switch (node.type) { case "MemberExpression": case "JSXMemberExpression": if (hasComputedProperty_(node)) { return; } if (isIdentifierType_(node.object) && !isLocalVar_(node.object, this.parents())) { const parents = this.parents().concat(node).reverse(); const path = nonNullable(this.path()).concat("object").reverse(); const use = registerIdentifier_(node.object, parents, path); if (use) { uses.push(use); } } break; default: break; } } exports.leave = leave; function nonNullable(value) { /* istanbul ignore if */ if (value == null) { throw new TypeError(`The value must be non-nullable, but actually ${value}`); } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return value; } /** * @return True if the property is computed like `foo["bar"]` not `foo.bar`. */ function hasComputedProperty_(node) { return node.type === "MemberExpression" && node.computed; } /** * @return True if the type is Identifier or JSXIdentifier. */ function isIdentifierType_(node) { return node.type === "Identifier" || node.type === "JSXIdentifier"; } /** * @return True if the object is a local variable, not a global object. * TODO: use escope to support complicated patterns like destructuring. */ function isLocalVar_(object, parents) { const nodeName = object.name; let node; parents = parents.slice(); while ((node = parents.pop())) { switch (node.type) { case "FunctionExpression": case "FunctionDeclaration": if (node.params && node.params.some((param) => param.type === "Identifier" && param.name === nodeName)) { return true; } break; case "BlockStatement": if (node.body && node.body.some((bodyPart) => bodyPart.type === "VariableDeclaration" && bodyPart.declarations.some((declaration) => declaration.type === "VariableDeclarator" && declaration.id.type === "Identifier" && declaration.id.name === nodeName))) { return true; } break; default: break; } } return false; } function registerIdentifier_(node, parents, path) { const namespace = [node.name]; for (let i = 0; i < parents.length; i++) { const current = parents[i]; const parentKey = path[i]; switch (current.type) { case "MemberExpression": case "JSXMemberExpression": if (!hasComputedProperty_(current) && isIdentifierType_(current.property)) { namespace.push(current.property.name); } else { return createMemberObject_(namespace, current, parentKey); } break; default: return createMemberObject_(namespace, current, parentKey); } } return null; } function createMemberObject_(namespace, node, parentKey) { return { name: namespace, node, key: parentKey, }; }