diff --git a/.changeset/big-gifts-reflect.md b/.changeset/big-gifts-reflect.md new file mode 100644 index 000000000..013cdd964 --- /dev/null +++ b/.changeset/big-gifts-reflect.md @@ -0,0 +1,5 @@ +--- +'providence-analytics': patch +--- + +fix: corrected export path for MatchImportAnalyzer diff --git a/packages-node/providence-analytics/src/program/utils/swc-traverse.js b/packages-node/providence-analytics/src/program/utils/swc-traverse.js index 90a4b0c03..88d228360 100644 --- a/packages-node/providence-analytics/src/program/utils/swc-traverse.js +++ b/packages-node/providence-analytics/src/program/utils/swc-traverse.js @@ -107,7 +107,7 @@ function createSwcPath(node, parent, stop, scope) { */ function isBindingNode(parent, identifierValue) { if (parent.type === 'VariableDeclarator') { - // @ts-ignore + // @ts-expect-error return parent.id.value === identifierValue; } return [ @@ -120,10 +120,7 @@ function isBindingNode(parent, identifierValue) { } /** - * Is the node: - * - a declaration (like "const a = 1")? - * - an import specifier (like "import { a } from 'b'")? - * Handy to know if the parents of Identifiers mark a binding + * Is the node a reference to a binding (like "alert(a);")? * @param {SwcNode} parent */ function isBindingRefNode(parent) { @@ -184,7 +181,8 @@ function addPotentialBindingOrRefToScope(swcPathForIdentifier) { } // In other cases, we are dealing with a reference that must be bound to a binding else if (isBindingRefNode(parent)) { - const binding = scope.bindings[node.value]; + // eslint-disable-next-line no-prototype-builtins + const binding = scope.bindings.hasOwnProperty(node.value) && scope.bindings[node.value]; if (binding) { binding.refs.push(parentPath); } else { @@ -297,7 +295,7 @@ export function swcTraverse(swcAst, visitor, { needsAdvancedPaths = false } = {} const newOrCurScope = getNewScope(swcPath, scope, traversalContext) || scope; swcPath.scope = newOrCurScope; addPotentialBindingOrRefToScope(swcPath); - return { newOrCurScope, swcPath }; + return { swcPath, newOrCurScope }; }; /** @@ -355,6 +353,6 @@ export function swcTraverse(swcAst, visitor, { needsAdvancedPaths = false } = {} prepareTree(swcAst, null, initialScope, traversalContext); } visitTree(swcAst, null, initialScope, { hasPreparedTree: needsAdvancedPaths }, traversalContext); - // @ts-ignore + // @ts-expect-error traversalContext.visitOnExitFns.reverse().forEach(fn => fn()); } diff --git a/packages-node/providence-analytics/test-node/program/utils/swc-traverse.test.js b/packages-node/providence-analytics/test-node/program/utils/swc-traverse.test.js index 719dd8c1c..9143bf891 100644 --- a/packages-node/providence-analytics/test-node/program/utils/swc-traverse.test.js +++ b/packages-node/providence-analytics/test-node/program/utils/swc-traverse.test.js @@ -113,6 +113,13 @@ describe('swcTraverse', () => { // TODO: also add case for Script expect(rootPath.node.type).to.equal('Module'); }); + + it('does not fail on object prototype built-ins (like "toString")', async () => { + const code = `const { toString } = x;`; + const swcAst = await AstService._getSwcAst(code); + + expect(swcTraverse(swcAst, {})).to.not.throw; + }); }); describe.skip('Paths', () => {