From 9401676baf1d7b993a9771fe70e950426e1bc2a7 Mon Sep 17 00:00:00 2001 From: Wee Date: Thu, 18 Apr 2019 22:26:33 +0800 Subject: [PATCH] fix(babel-plugin-export-metadata): re-export causes meta error (#805) * fix(babel-plugin-export-metadata): re-export causes meta error * fix(babel-plugin-export-metadata): update snapshot * fix(babel-plugin-export-metadata): re-export name to default --- .../babel-plugin-export-metadata/src/index.js | 51 ++++++-- .../tests/__snapshots__/index.test.js.snap | 112 +++++++++++++++--- .../tests/fixtures/assets/a.js | 4 + .../fixtures/re-export/re-export-default.js | 2 + .../fixtures/re-export/re-export-multi.js | 2 + .../fixtures/re-export/re-export-rename1.js | 2 + .../fixtures/re-export/re-export-rename2.js | 2 + .../fixtures/re-export/re-export-rename3.js | 2 + .../tests/fixtures/re-export/re-export.js | 2 + .../tests/index.test.js | 94 +++++++++++++-- 10 files changed, 245 insertions(+), 28 deletions(-) create mode 100644 other-packages/babel-plugin-export-metadata/tests/fixtures/assets/a.js create mode 100644 other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-default.js create mode 100644 other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-multi.js create mode 100644 other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename1.js create mode 100644 other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename2.js create mode 100644 other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename3.js create mode 100644 other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export.js diff --git a/other-packages/babel-plugin-export-metadata/src/index.js b/other-packages/babel-plugin-export-metadata/src/index.js index 82bbf86e3..4951174b7 100644 --- a/other-packages/babel-plugin-export-metadata/src/index.js +++ b/other-packages/babel-plugin-export-metadata/src/index.js @@ -15,6 +15,11 @@ const buildFileMeta = template(` } `) +const replaceExportDefault = template(` + import NAME from 'SOURCE' + export default NAME +`) + const getFilename = state => { const filename = get(state, 'file.opts.filename') return filename && path.relative(process.cwd(), filename) @@ -40,6 +45,34 @@ const addFileMetaProperties = (t, path, filename, name) => { pathToInsert.insertAfter(newNode) } +const renameDefaultAddFileMetaProperties = (t, path, filename, name) => { + if (!filename || !name) { + return + } + + const sourceValue = get(path, 'node.source.value') + const localeName = get(path, 'node.specifiers[0].local.name') + const pathToInsert = findPathToInsert(path) + + const fallbackName = + localeName === 'default' ? '__DOCZ_DUMMY_EXPORT_DEFAULT' : localeName + + // replace + const nameExport = replaceExportDefault({ + NAME: fallbackName, + SOURCE: sourceValue, + }) + + // insert + const newNode = buildFileMeta({ + ID: t.identifier(fallbackName), + NAME: t.stringLiteral(fallbackName), + FILENAME: t.stringLiteral(filename), + }) + + pathToInsert.replaceWithMultiple(nameExport) +} + const insertNodeExport = t => (path, state) => { const filename = getFilename(state) if (/(\.cache|\.docz).+/.test(filename)) return @@ -57,13 +90,17 @@ const insertNodeExport = t => (path, state) => { } } else if (specifiers) { for (specifier of specifiers) { - let specifierName = get(specifier, 'local.name') - specifierName = - specifierName === 'default' - ? get(specifier, 'exported.name') - : specifierName - - addFileMetaProperties(t, path, filename, specifierName) + const localName = get(specifier, 'local.name') + const exportedName = get(specifier, 'exported.name') + const source = get(path, 'node.source') + if (source && exportedName === 'default') { + // case for: export default from './a.js'. `default` is a keyword, rename it + renameDefaultAddFileMetaProperties(t, path, filename, 'default') + } else { + // if there is `path.source`, the specifier is imported from another module. Then use its exportedName + const specifierName = source ? exportedName : localName + addFileMetaProperties(t, path, filename, specifierName) + } } } } diff --git a/other-packages/babel-plugin-export-metadata/tests/__snapshots__/index.test.js.snap b/other-packages/babel-plugin-export-metadata/tests/__snapshots__/index.test.js.snap index 2dde6b425..4ed32c721 100644 --- a/other-packages/babel-plugin-export-metadata/tests/__snapshots__/index.test.js.snap +++ b/other-packages/babel-plugin-export-metadata/tests/__snapshots__/index.test.js.snap @@ -8,7 +8,7 @@ let bar5 = () => {}; export default [foo5, bar5]; -if (typeof bar5 !== 'undefined' && bar5 && bar5 === Object(bar5)) { +if (typeof bar5 !== 'undefined' && bar5 && bar5 === Object(bar5) && Object.isExtensible(bar5)) { Object.defineProperty(bar5, '__filemeta', { enumerable: true, configurable: true, @@ -19,7 +19,7 @@ if (typeof bar5 !== 'undefined' && bar5 && bar5 === Object(bar5)) { }); } -if (typeof foo5 !== 'undefined' && foo5 && foo5 === Object(foo5)) { +if (typeof foo5 !== 'undefined' && foo5 && foo5 === Object(foo5) && Object.isExtensible(foo5)) { Object.defineProperty(foo5, '__filemeta', { enumerable: true, configurable: true, @@ -35,7 +35,7 @@ exports[`export-metadata export default works with Class declaration 1`] = ` "/* ExportDefaultDeclaration with Class declaration */ export default class Bar6 {} -if (typeof Bar6 !== 'undefined' && Bar6 && Bar6 === Object(Bar6)) { +if (typeof Bar6 !== 'undefined' && Bar6 && Bar6 === Object(Bar6) && Object.isExtensible(Bar6)) { Object.defineProperty(Bar6, '__filemeta', { enumerable: true, configurable: true, @@ -51,7 +51,7 @@ exports[`export-metadata export default works with Function declaration 1`] = ` "/* ExportDefaultDeclaration with Function declaration */ export default function foo6() {} -if (typeof foo6 !== 'undefined' && foo6 && foo6 === Object(foo6)) { +if (typeof foo6 !== 'undefined' && foo6 && foo6 === Object(foo6) && Object.isExtensible(foo6)) { Object.defineProperty(foo6, '__filemeta', { enumerable: true, configurable: true, @@ -68,7 +68,7 @@ exports[`export-metadata export default works with Identifier 1`] = ` let foo3 = 5; export default foo3; -if (typeof foo3 !== 'undefined' && foo3 && foo3 === Object(foo3)) { +if (typeof foo3 !== 'undefined' && foo3 && foo3 === Object(foo3) && Object.isExtensible(foo3)) { Object.defineProperty(foo3, '__filemeta', { enumerable: true, configurable: true, @@ -87,7 +87,7 @@ export default { bar4: () => {} }; -if (typeof bar4 !== 'undefined' && bar4 && bar4 === Object(bar4)) { +if (typeof bar4 !== 'undefined' && bar4 && bar4 === Object(bar4) && Object.isExtensible(bar4)) { Object.defineProperty(bar4, '__filemeta', { enumerable: true, configurable: true, @@ -98,7 +98,7 @@ if (typeof bar4 !== 'undefined' && bar4 && bar4 === Object(bar4)) { }); } -if (typeof foo4 !== 'undefined' && foo4 && foo4 === Object(foo4)) { +if (typeof foo4 !== 'undefined' && foo4 && foo4 === Object(foo4) && Object.isExtensible(foo4)) { Object.defineProperty(foo4, '__filemeta', { enumerable: true, configurable: true, @@ -120,7 +120,7 @@ let baz = 'baz'; export { foo as default, bar as foobar, baz }; /* ExportNamedDeclaration with Variable declarations */ -if (typeof baz !== 'undefined' && baz && baz === Object(baz)) { +if (typeof baz !== 'undefined' && baz && baz === Object(baz) && Object.isExtensible(baz)) { Object.defineProperty(baz, '__filemeta', { enumerable: true, configurable: true, @@ -131,7 +131,7 @@ if (typeof baz !== 'undefined' && baz && baz === Object(baz)) { }); } -if (typeof bar !== 'undefined' && bar && bar === Object(bar)) { +if (typeof bar !== 'undefined' && bar && bar === Object(bar) && Object.isExtensible(bar)) { Object.defineProperty(bar, '__filemeta', { enumerable: true, configurable: true, @@ -142,7 +142,7 @@ if (typeof bar !== 'undefined' && bar && bar === Object(bar)) { }); } -if (typeof foo !== 'undefined' && foo && foo === Object(foo)) { +if (typeof foo !== 'undefined' && foo && foo === Object(foo) && Object.isExtensible(foo)) { Object.defineProperty(foo, '__filemeta', { enumerable: true, configurable: true, @@ -157,7 +157,7 @@ export let foo1 = 5, bar1 = () => {}; /* ExportNamedDeclaration with Function and Class declarations */ -if (typeof bar1 !== 'undefined' && bar1 && bar1 === Object(bar1)) { +if (typeof bar1 !== 'undefined' && bar1 && bar1 === Object(bar1) && Object.isExtensible(bar1)) { Object.defineProperty(bar1, '__filemeta', { enumerable: true, configurable: true, @@ -168,7 +168,7 @@ if (typeof bar1 !== 'undefined' && bar1 && bar1 === Object(bar1)) { }); } -if (typeof foo1 !== 'undefined' && foo1 && foo1 === Object(foo1)) { +if (typeof foo1 !== 'undefined' && foo1 && foo1 === Object(foo1) && Object.isExtensible(foo1)) { Object.defineProperty(foo1, '__filemeta', { enumerable: true, configurable: true, @@ -181,7 +181,7 @@ if (typeof foo1 !== 'undefined' && foo1 && foo1 === Object(foo1)) { export function foo2() {} -if (typeof foo2 !== 'undefined' && foo2 && foo2 === Object(foo2)) { +if (typeof foo2 !== 'undefined' && foo2 && foo2 === Object(foo2) && Object.isExtensible(foo2)) { Object.defineProperty(foo2, '__filemeta', { enumerable: true, configurable: true, @@ -194,7 +194,7 @@ if (typeof foo2 !== 'undefined' && foo2 && foo2 === Object(foo2)) { export class Bar2 {} -if (typeof Bar2 !== 'undefined' && Bar2 && Bar2 === Object(Bar2)) { +if (typeof Bar2 !== 'undefined' && Bar2 && Bar2 === Object(Bar2) && Object.isExtensible(Bar2)) { Object.defineProperty(Bar2, '__filemeta', { enumerable: true, configurable: true, @@ -205,3 +205,87 @@ if (typeof Bar2 !== 'undefined' && Bar2 && Bar2 === Object(Bar2)) { }); }" `; + +exports[`export-metadata re-export re export default 1`] = ` +"/* Re-export */ +import __DOCZ_DUMMY_EXPORT_DEFAULT from \\"../assets/a\\"; +export default __DOCZ_DUMMY_EXPORT_DEFAULT; + +if (typeof __DOCZ_DUMMY_EXPORT_DEFAULT !== 'undefined' && __DOCZ_DUMMY_EXPORT_DEFAULT && __DOCZ_DUMMY_EXPORT_DEFAULT === Object(__DOCZ_DUMMY_EXPORT_DEFAULT) && Object.isExtensible(__DOCZ_DUMMY_EXPORT_DEFAULT)) { + Object.defineProperty(__DOCZ_DUMMY_EXPORT_DEFAULT, '__filemeta', { + enumerable: true, + configurable: true, + value: { + name: \\"__DOCZ_DUMMY_EXPORT_DEFAULT\\", + filename: \\"tests/fixtures/re-export/re-export-default.js\\" + } + }); +}" +`; + +exports[`export-metadata re-export re export default to name 1`] = ` +"/* Re-export */ +export { default as aDefault } from '../assets/a'; + +if (typeof aDefault !== 'undefined' && aDefault && aDefault === Object(aDefault) && Object.isExtensible(aDefault)) { + Object.defineProperty(aDefault, '__filemeta', { + enumerable: true, + configurable: true, + value: { + name: \\"aDefault\\", + filename: \\"tests/fixtures/re-export/re-export-rename1.js\\" + } + }); +}" +`; + +exports[`export-metadata re-export re export name 1`] = ` +"/* Re-export */ +export { a } from '../assets/a'; + +if (typeof a !== 'undefined' && a && a === Object(a) && Object.isExtensible(a)) { + Object.defineProperty(a, '__filemeta', { + enumerable: true, + configurable: true, + value: { + name: \\"a\\", + filename: \\"tests/fixtures/re-export/re-export.js\\" + } + }); +}" +`; + +exports[`export-metadata re-export re export name to default 1`] = ` +"/* Re-export */ +import a from \\"../assets/a\\"; +export default a; + +if (typeof a !== 'undefined' && a && a === Object(a) && Object.isExtensible(a)) { + Object.defineProperty(a, '__filemeta', { + enumerable: true, + configurable: true, + value: { + name: \\"a\\", + filename: \\"tests/fixtures/re-export/re-export-rename2.js\\" + } + }); +}" +`; + +exports[`export-metadata re-export re export name to name 1`] = ` +"/* Re-export */ +export { a as aa } from '../assets/a'; + +if (typeof aa !== 'undefined' && aa && aa === Object(aa) && Object.isExtensible(aa)) { + Object.defineProperty(aa, '__filemeta', { + enumerable: true, + configurable: true, + value: { + name: \\"aa\\", + filename: \\"tests/fixtures/re-export/re-export-rename3.js\\" + } + }); +}" +`; + +exports[`export-metadata re-export re-export default 1`] = `""`; diff --git a/other-packages/babel-plugin-export-metadata/tests/fixtures/assets/a.js b/other-packages/babel-plugin-export-metadata/tests/fixtures/assets/a.js new file mode 100644 index 000000000..e66350486 --- /dev/null +++ b/other-packages/babel-plugin-export-metadata/tests/fixtures/assets/a.js @@ -0,0 +1,4 @@ +const a = 1 +const ____a = 2 +export { a } +export default ____a diff --git a/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-default.js b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-default.js new file mode 100644 index 000000000..30e54e405 --- /dev/null +++ b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-default.js @@ -0,0 +1,2 @@ +/* Re-export */ +export { default } from '../assets/a' diff --git a/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-multi.js b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-multi.js new file mode 100644 index 000000000..e3308e39b --- /dev/null +++ b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-multi.js @@ -0,0 +1,2 @@ +/* Re-export */ +export aDefault, { a } from '../assets/a' diff --git a/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename1.js b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename1.js new file mode 100644 index 000000000..c7aa3ef5e --- /dev/null +++ b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename1.js @@ -0,0 +1,2 @@ +/* Re-export */ +export { default as aDefault } from '../assets/a' diff --git a/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename2.js b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename2.js new file mode 100644 index 000000000..af6d57453 --- /dev/null +++ b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename2.js @@ -0,0 +1,2 @@ +/* Re-export */ +export { a as default } from '../assets/a' diff --git a/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename3.js b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename3.js new file mode 100644 index 000000000..537ef82ea --- /dev/null +++ b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export-rename3.js @@ -0,0 +1,2 @@ +/* Re-export */ +export { a as aa } from '../assets/a' diff --git a/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export.js b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export.js new file mode 100644 index 000000000..4cd1d9e8c --- /dev/null +++ b/other-packages/babel-plugin-export-metadata/tests/fixtures/re-export/re-export.js @@ -0,0 +1,2 @@ +/* Re-export */ +export { a } from '../assets/a' diff --git a/other-packages/babel-plugin-export-metadata/tests/index.test.js b/other-packages/babel-plugin-export-metadata/tests/index.test.js index 10bd3a99b..6b471c957 100644 --- a/other-packages/babel-plugin-export-metadata/tests/index.test.js +++ b/other-packages/babel-plugin-export-metadata/tests/index.test.js @@ -6,6 +6,7 @@ const plugin = require('../src') const exportNamedFixture = path.resolve( './tests/fixtures/export-named/index.js' ) + const exportDefaultFixtures = { withArrExpression: path.resolve( './tests/fixtures/export-default/with-arr-expression.js' @@ -24,17 +25,49 @@ const exportDefaultFixtures = { ), } -const exportDefaultCode = Object.keys(exportDefaultFixtures).reduce( - (acc, key) => ({ - ...acc, - [key]: fs.readFileSync(exportDefaultFixtures[key]).toString(), - }), - {} -) +const reExportsFixtures = { + reExportName: path.resolve( + path.resolve('./tests/fixtures/re-export/re-export.js') + ), + reExportDefault: path.resolve( + path.resolve('./tests/fixtures/re-export/re-export-default.js') + ), + reExportDefaultToName: path.resolve( + path.resolve('./tests/fixtures/re-export/re-export-rename1.js') + ), + reExportNameToDefault: path.resolve( + path.resolve('./tests/fixtures/re-export/re-export-rename2.js') + ), + reExportNameToName: path.resolve( + path.resolve('./tests/fixtures/re-export/re-export-rename3.js') + ), +} + +const getCodeFromFilePath = paths => + Object.keys(paths).reduce( + (acc, key) => ({ + ...acc, + [key]: fs.readFileSync(paths[key]).toString(), + }), + {} + ) +const exportDefaultCode = getCodeFromFilePath(exportDefaultFixtures) const exportNamedCode = fs.readFileSync(exportNamedFixture).toString() +const reExportCode = getCodeFromFilePath(reExportsFixtures) describe('export-metadata', () => { + describe('re-export', () => { + it('re-export default', () => { + const result = transformSync(exportDefaultFixtures.reExportName, { + plugins: [plugin], + filename: exportNamedFixture.reExportName, + }) + + expect(result.code).toMatchSnapshot() + }) + }) + describe('export default', () => { it('works with Array expression', () => { const result = transformSync(exportDefaultCode.withArrExpression, { @@ -92,4 +125,51 @@ describe('export-metadata', () => { expect(result.code).toMatchSnapshot() }) }) + + describe('re-export', () => { + it('re export name', () => { + const result = transformSync(reExportCode.reExportName, { + plugins: [plugin], + filename: reExportsFixtures.reExportName, + }) + + expect(result.code).toMatchSnapshot() + }) + + it('re export default', () => { + const result = transformSync(reExportCode.reExportDefault, { + plugins: [plugin], + filename: reExportsFixtures.reExportDefault, + }) + + expect(result.code).toMatchSnapshot() + }) + + it('re export name to default', () => { + const result = transformSync(reExportCode.reExportNameToDefault, { + plugins: [plugin], + filename: reExportsFixtures.reExportNameToDefault, + }) + + expect(result.code).toMatchSnapshot() + }) + + it('re export default to name', () => { + const result = transformSync(reExportCode.reExportDefaultToName, { + plugins: [plugin], + filename: reExportsFixtures.reExportDefaultToName, + }) + + expect(result.code).toMatchSnapshot() + }) + + it('re export name to name', () => { + const result = transformSync(reExportCode.reExportNameToName, { + plugins: [plugin], + filename: reExportsFixtures.reExportNameToName, + }) + + expect(result.code).toMatchSnapshot() + }) + }) })