diff --git a/.changeset/brown-dodos-own.md b/.changeset/brown-dodos-own.md new file mode 100644 index 000000000..c149de059 --- /dev/null +++ b/.changeset/brown-dodos-own.md @@ -0,0 +1,5 @@ +--- +'providence-analytics': patch +--- + +correctly handle exports like "const x=3; export {x};" diff --git a/packages-node/providence-analytics/src/program/analyzers/helpers/track-down-identifier.js b/packages-node/providence-analytics/src/program/analyzers/helpers/track-down-identifier.js index f5059398a..2daa95da3 100644 --- a/packages-node/providence-analytics/src/program/analyzers/helpers/track-down-identifier.js +++ b/packages-node/providence-analytics/src/program/analyzers/helpers/track-down-identifier.js @@ -37,7 +37,7 @@ function getBindingAndSourceReexports(astPath, identifierName) { if (found) { bindingPath = path; bindingType = 'ExportSpecifier'; - source = path.parentPath.node.source.value; + source = path.parentPath.node.source ? path.parentPath.node.source.value : '[current]'; path.stop(); } }, @@ -46,11 +46,14 @@ function getBindingAndSourceReexports(astPath, identifierName) { } /** - * @desc returns source and importedIdentifierName: We might be an import that was locally renamed. + * Retrieves source (like '@lion/core') and importedIdentifierName (like 'lit') from ast for + * current file. + * We might be an import that was locally renamed. * Since we are traversing, we are interested in the imported name. Or in case of a re-export, * the local name. * @param {object} astPath Babel ast traversal path * @param {string} identifierName the name that should be tracked (and that exists inside scope of astPath) + * @returns {{ source:string, importedIdentifierName:string }} */ function getImportSourceFromAst(astPath, identifierName) { let source; @@ -183,7 +186,8 @@ async function trackDownIdentifierFn(source, identifierName, currentFilePath, ro * export { x } */ newSource = getImportSourceFromAst(path, identifierName).source; - if (!newSource) { + + if (!newSource || newSource === '[current]') { /** * @example * const x = 12; @@ -222,7 +226,7 @@ async function trackDownIdentifierFn(source, identifierName, currentFilePath, ro rootFilePath = resObj.file; rootSpecifier = resObj.specifier; } - return /** @type {RootFile } */ { file: rootFilePath, specifier: rootSpecifier }; + return /** @type { RootFile } */ { file: rootFilePath, specifier: rootSpecifier }; } trackDownIdentifier = memoizeAsync(trackDownIdentifierFn); diff --git a/packages-node/providence-analytics/test-node/program/analyzers/helpers/track-down-identifier.test.js b/packages-node/providence-analytics/test-node/program/analyzers/helpers/track-down-identifier.test.js index edd4b943f..9b9a3bc68 100644 --- a/packages-node/providence-analytics/test-node/program/analyzers/helpers/track-down-identifier.test.js +++ b/packages-node/providence-analytics/test-node/program/analyzers/helpers/track-down-identifier.test.js @@ -137,6 +137,37 @@ describe('trackdownIdentifier', () => { }); }); + it(`tracks down locally declared, reexported identifiers (without a source defined)`, async () => { + mockProject( + { + './src/declarationOfMyNumber.js': ` + const myNumber = 3; + + export { myNumber }; + `, + './currentFile.js': ` + import { myNumber } from './src/declarationOfMyNumber.js'; + `, + }, + { + projectName: 'my-project', + projectPath: '/my/project', + }, + ); + + // Let's say we want to track down 'MyClass' in the code above + const source = './src/declarationOfMyNumber.js'; + const identifierName = 'myNumber'; + const currentFilePath = '/my/project/currentFile.js'; + const rootPath = '/my/project'; + + const rootFile = await trackDownIdentifier(source, identifierName, currentFilePath, rootPath); + expect(rootFile).to.eql({ + file: './src/declarationOfMyNumber.js', + specifier: 'myNumber', + }); + }); + // TODO: improve perf describe.skip('Caching', () => {}); });