diff --git a/core/instrument/src/babel/extract-component.ts b/core/instrument/src/babel/extract-component.ts index 57337ee01..85dd79669 100644 --- a/core/instrument/src/babel/extract-component.ts +++ b/core/instrument/src/babel/extract-component.ts @@ -63,7 +63,7 @@ export const extractComponent = async ( request: follow.filePath, loc: follow.loc, source: follow.source, - repository: await packageInfo(follow.filePath), + repository: await packageInfo(follow.originalFilePath), } : undefined; }; diff --git a/core/instrument/src/babel/extract-exports.ts b/core/instrument/src/babel/extract-exports.ts index c790047b9..5c0ab43c3 100644 --- a/core/instrument/src/babel/extract-exports.ts +++ b/core/instrument/src/babel/extract-exports.ts @@ -28,14 +28,15 @@ export const traverseExports = (results: ExportTypes) => { const globals: NamedExportTypes = {}; const localExports: NamedExportTypes = {}; - const extractArrowFunction = (declaration: any): ExportType | undefined => { - if ( - declaration.init && - declaration.init.type === 'ArrowFunctionExpression' - ) { + const extractExportVariable = (declaration: any): ExportType | undefined => { + if (declaration.init && declaration.id.name) { const name = declaration.id.name; const exportType: ExportType = { - loc: sourceLocation(declaration.init.body.loc), + loc: sourceLocation( + declaration.init.body + ? declaration.init.body.loc + : declaration.init.loc, + ), name, internalName: name, }; @@ -80,7 +81,7 @@ export const traverseExports = (results: ExportTypes) => { const name = declaration.id.name; //check if it was a named export if (!results.named[name]) { - const namedExport = extractArrowFunction(declaration); + const namedExport = extractExportVariable(declaration); if (namedExport && namedExport.name) { localExports[namedExport.name] = namedExport; } @@ -139,7 +140,7 @@ export const traverseExports = (results: ExportTypes) => { const { declarations } = declaration; if (Array.isArray(declarations)) { declarations.forEach(declaration => { - const namedExport = extractArrowFunction(declaration); + const namedExport = extractExportVariable(declaration); if (namedExport) { const name = namedExport.name || ''; const global = globals[name]; diff --git a/core/instrument/src/babel/follow-imports.ts b/core/instrument/src/babel/follow-imports.ts index bafee8eb1..312733539 100644 --- a/core/instrument/src/babel/follow-imports.ts +++ b/core/instrument/src/babel/follow-imports.ts @@ -18,6 +18,7 @@ export interface FollowImportType { exportedAs: string; from: string; filePath?: string; + originalFilePath?: string; loc?: CodeLocation; source?: string; } @@ -29,9 +30,16 @@ export const followImports = ( options?: InstrumentOptions, initialAST?: File, ): FollowImportType | undefined => { - const { parser: parserOptions, resolve: resolveOptions } = options || {}; - - const source = fileSource || fs.readFileSync(filePath, 'utf8'); + const { parser: parserOptions, resolve: resolveOptions, component } = + options || {}; + const fileName = + component && component.resolveFile + ? component.resolveFile(importName, filePath) + : filePath; + if (!fileName) { + return undefined; + } + const source = fileSource || fs.readFileSync(fileName, 'utf8'); const ast = initialAST || parser.parse(source, parserOptions); const baseImportedName = importName.split('.')[0]; @@ -39,7 +47,7 @@ export const followImports = ( named: {}, }; traverse(ast, traverseExports(exports)); - const folderName = path.dirname(filePath); + const folderName = path.dirname(fileName); const findExport = baseImportedName === 'default' || baseImportedName === 'namespace' ? exports.default @@ -47,7 +55,8 @@ export const followImports = ( if (findExport !== undefined) { if (!findExport.from) { return { - filePath, + filePath: fileName, + originalFilePath: filePath, exportedAs: findExport.name, loc: findExport.loc, from: '', diff --git a/core/instrument/src/types.ts b/core/instrument/src/types.ts index a7afed3de..1630f9094 100644 --- a/core/instrument/src/types.ts +++ b/core/instrument/src/types.ts @@ -16,10 +16,7 @@ export const defaultParserOptions: parser.ParserOptions = { }; export interface ComponentOptions { - resolveComponent?: ( - componentName: string, - FilePath: string, - ) => string | undefined; + resolveFile?: (componentName: string, FilePath: string) => string | undefined; } export type ParserOptions = parser.ParserOptions; diff --git a/core/instrument/test/__snapshots__/extract-component.test.ts.snap b/core/instrument/test/__snapshots__/extract-component.test.ts.snap index 7a7f7468e..9f0294fb3 100644 --- a/core/instrument/test/__snapshots__/extract-component.test.ts.snap +++ b/core/instrument/test/__snapshots__/extract-component.test.ts.snap @@ -3,10 +3,49 @@ exports[`extract-component node-modules.js 1`] = ` Object { "from": "theme-ui", - "loc": undefined, + "loc": Object { + "end": Object { + "column": 2, + "line": 26, + }, + "start": Object { + "column": 22, + "line": 4, + }, + }, "name": "Button", - "repository": undefined, - "request": undefined, - "source": undefined, + "repository": Object { + "browse": "https://github.com/system-ui/theme-ui/tree/master/dist/index.js", + "docs": "https://github.com/system-ui/theme-ui/tree/master#readme", + "issues": "https://github.com/system-ui/theme-ui/issues", + }, + "request": "/Users/atanasster/component-controls/node_modules/@theme-ui/components/src/Button.js", + "source": "import React from 'react' +import Box from './Box' + +export const Button = React.forwardRef((props, ref) => ( + +)) +", } `; diff --git a/core/instrument/test/__snapshots__/follow-imports.test.ts.snap b/core/instrument/test/__snapshots__/follow-imports.test.ts.snap index 37cb9ecfc..4a1950b15 100644 --- a/core/instrument/test/__snapshots__/follow-imports.test.ts.snap +++ b/core/instrument/test/__snapshots__/follow-imports.test.ts.snap @@ -15,6 +15,7 @@ Object { "line": 1, }, }, + "originalFilePath": "/Users/atanasster/component-controls/core/instrument/test/examples/exports/cjs-named-export.js", "source": "const Button = () => {}; exports.Button = Button; ", @@ -36,6 +37,7 @@ Object { "line": 1, }, }, + "originalFilePath": "/Users/atanasster/component-controls/core/instrument/test/examples/follow-imports/button-named-export.js", "source": "export const Button = () => {}; ", } @@ -56,6 +58,7 @@ Object { "line": 18, }, }, + "originalFilePath": "/Users/atanasster/component-controls/node_modules/@component-controls/storybook/dist/index.js", "source": "'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -180,6 +183,7 @@ Object { "line": 1, }, }, + "originalFilePath": "/Users/atanasster/component-controls/core/instrument/test/examples/follow-imports/button-default-export.js", "source": "export default () => {}; ", } @@ -200,6 +204,7 @@ Object { "line": 1, }, }, + "originalFilePath": "/Users/atanasster/component-controls/core/instrument/test/examples/follow-imports/button-named-export.js", "source": "export const Button = () => {}; ", } @@ -220,6 +225,7 @@ Object { "line": 1, }, }, + "originalFilePath": "/Users/atanasster/component-controls/core/instrument/test/examples/follow-imports/button-named-export.js", "source": "export const Button = () => {}; ", } @@ -240,6 +246,7 @@ Object { "line": 1, }, }, + "originalFilePath": "/Users/atanasster/component-controls/core/instrument/test/examples/follow-imports/button-default-export.js", "source": "export default () => {}; ", } @@ -260,6 +267,7 @@ Object { "line": 1, }, }, + "originalFilePath": "/Users/atanasster/component-controls/core/instrument/test/examples/follow-imports/direct-import.js", "source": "export const Button = () => {}; ", } diff --git a/core/instrument/test/extract-component.test.ts b/core/instrument/test/extract-component.test.ts index a05ab7897..a8d1a8737 100644 --- a/core/instrument/test/extract-component.test.ts +++ b/core/instrument/test/extract-component.test.ts @@ -15,6 +15,16 @@ describe('extract-component', () => { await extractComponent('Button', fileName, undefined, { parser: defaultParserOptions, resolve: defaultResolveOptions, + component: { + resolveFile: (componentName: string, filePath: string) => { + if (filePath.includes('/theme-ui/dist')) { + return `${ + filePath.split('/theme-ui/dist')[0] + }/@theme-ui/components/src/${componentName}.js`; + } + return filePath; + }, + }, }), ).toMatchSnapshot(); });