Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix named-asset-import plugin to work with export-as syntax #5573

Merged
merged 8 commits into from
Nov 20, 2018
136 changes: 95 additions & 41 deletions packages/babel-plugin-named-asset-import/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,60 +5,114 @@ const { extname } = require('path');
function namedAssetImportPlugin({ types: t }) {
const visited = new WeakSet();

function generateNewSource(loaderMap, moduleName, sourcePath) {
NShahri marked this conversation as resolved.
Show resolved Hide resolved
const ext = extname(sourcePath).substr(1);
const extMap = loaderMap[ext];
return extMap[moduleName]
? extMap[moduleName].replace(/\[path\]/, sourcePath)
: sourcePath;
}

function replaceNotVisitedSpecifiers(path, loaderMap, callback) {
NShahri marked this conversation as resolved.
Show resolved Hide resolved
const sourcePath = path.node.source.value;
const ext = extname(sourcePath).substr(1);

if (visited.has(path.node) || sourcePath.indexOf('!') !== -1) {
return;
}

if (loaderMap[ext]) {
path.replaceWithMultiple(
path.node.specifiers.map(specifier => {
const newSpecifier = callback(specifier, sourcePath);
visited.add(newSpecifier);

return newSpecifier;
})
);
}
}

return {
visitor: {
ImportDeclaration(
ExportNamedDeclaration(
NShahri marked this conversation as resolved.
Show resolved Hide resolved
path,
{
opts: { loaderMap },
}
) {
const sourcePath = path.node.source.value;
const ext = extname(sourcePath).substr(1);

if (visited.has(path.node) || sourcePath.indexOf('!') !== -1) {
if (!path.node.source) {
NShahri marked this conversation as resolved.
Show resolved Hide resolved
return;
}

if (loaderMap[ext]) {
path.replaceWithMultiple(
path.node.specifiers.map(specifier => {
if (t.isImportDefaultSpecifier(specifier)) {
const newDefaultImport = t.importDeclaration(
[
t.importDefaultSpecifier(
t.identifier(specifier.local.name)
),
],
t.stringLiteral(sourcePath)
);

visited.add(newDefaultImport);
return newDefaultImport;
}

const newImport = t.importDeclaration(
[
t.importSpecifier(
t.identifier(specifier.local.name),
t.identifier(specifier.imported.name)
),
],
t.stringLiteral(
loaderMap[ext][specifier.imported.name]
? loaderMap[ext][specifier.imported.name].replace(
/\[path\]/,
sourcePath
)
: sourcePath
)
replaceNotVisitedSpecifiers(
path,
loaderMap,
(specifier, sourcePath) => {
if (t.isExportDefaultSpecifier(specifier)) {
const defaultDeclaration = t.exportDeclaration(
[t.exportDefaultSpecifier(t.identifier(specifier.local.name))],
t.stringLiteral(sourcePath)
);

visited.add(newImport);
return newImport;
})
);
return defaultDeclaration;
}

const namedDeclaration = t.exportNamedDeclaration(
NShahri marked this conversation as resolved.
Show resolved Hide resolved
null,
[
t.exportSpecifier(
t.identifier(specifier.local.name),
t.identifier(specifier.exported.name)
),
],
t.stringLiteral(
generateNewSource(loaderMap, specifier.local.name, sourcePath)
)
);

return namedDeclaration;
}
);
},
ImportDeclaration(
path,
{
opts: { loaderMap },
}
) {
replaceNotVisitedSpecifiers(
path,
loaderMap,
(specifier, sourcePath) => {
if (t.isImportDefaultSpecifier(specifier)) {
const defaultDeclaration = t.importDeclaration(
[t.importDefaultSpecifier(t.identifier(specifier.local.name))],
t.stringLiteral(sourcePath)
);

return defaultDeclaration;
}

const namedDeclaration = t.importDeclaration(
NShahri marked this conversation as resolved.
Show resolved Hide resolved
[
t.importSpecifier(
t.identifier(specifier.local.name),
t.identifier(specifier.imported.name)
),
],
t.stringLiteral(
generateNewSource(
loaderMap,
specifier.imported.name,
sourcePath
)
)
);

return namedDeclaration;
}
);
},
},
};
Expand Down
48 changes: 48 additions & 0 deletions packages/babel-plugin-named-asset-import/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,53 @@ pluginTester({
'import { logoUrl } from "logo.svg";\n' +
'import { ReactComponent as Logo } from "@svgr/webpack?-prettier,-svgo!logo.svg";',
},
defaultExport: {
code: 'export default logo;',
output: 'export default logo;',
},
constExport: {
code: 'export const token = "token";',
output: 'export const token = "token";',
},
classExport: {
code: 'export class Logo {}',
output: 'export class Logo {}',
},
namedExport: {
code: 'export { logo } from "logo";',
output: 'export { logo } from "logo";',
},
namedExportRenamed: {
code: 'export { Url as logo } from "logo";',
output: 'export { Url as logo } from "logo";',
},
allExport: {
code: 'export * from "logo";',
output: 'export * from "logo";',
},
svgNamedExport: {
code: 'export { logo } from "logo.svg";',
output: 'export { logo } from "logo.svg";',
},
svgAllExport: {
code: 'export * from "logo.svg";',
output: 'export * from "logo.svg";',
},
svgReactComponentNamedExport: {
code: 'export { ReactComponent as Logo } from "logo.svg";',
output:
'export { ReactComponent as Logo } from "@svgr/webpack?-prettier,-svgo!logo.svg";',
},
svgReactComponentExport: {
code: 'export { ReactComponent } from "logo.svg";',
output:
'export { ReactComponent } from "@svgr/webpack?-prettier,-svgo!logo.svg";',
},
svgMultipleExport: {
code: 'export { logoUrl , ReactComponent as Logo } from "logo.svg";',
output:
'export { logoUrl } from "logo.svg";\n' +
'export { ReactComponent as Logo } from "@svgr/webpack?-prettier,-svgo!logo.svg";',
},
},
});