Skip to content

Commit

Permalink
Make named-asset-import plugin work with export-as syntax (#5573)
Browse files Browse the repository at this point in the history
* update named-asset-import babel plugin

* add tests to named-asset-import plugin

* add more plugin test

* extract generateNewSource method, renaming variables

* extract replaceNotVisitedSpecifiers for export and import visitors

* remove visited list update from importDeclaration

* renaming methods and removing return directly instead of saving
  • Loading branch information
NShahri authored and iansu committed Nov 20, 2018
1 parent e1c4d27 commit fb465a3
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 41 deletions.
120 changes: 79 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,98 @@ const { extname } = require('path');
function namedAssetImportPlugin({ types: t }) {
const visited = new WeakSet();

function generateNewSourcePath(loaderMap, moduleName, sourcePath) {
const ext = extname(sourcePath).substr(1);
const extMap = loaderMap[ext];
return extMap[moduleName]
? extMap[moduleName].replace(/\[path\]/, sourcePath)
: sourcePath;
}

function replaceMatchingSpecifiers(path, loaderMap, callback) {
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(
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) {
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
)
);
replaceMatchingSpecifiers(path, loaderMap, (specifier, sourcePath) => {
if (t.isExportDefaultSpecifier(specifier)) {
return t.exportDeclaration(
[t.exportDefaultSpecifier(t.identifier(specifier.local.name))],
t.stringLiteral(sourcePath)
);
}

visited.add(newImport);
return newImport;
})
return t.exportNamedDeclaration(
null,
[
t.exportSpecifier(
t.identifier(specifier.local.name),
t.identifier(specifier.exported.name)
),
],
t.stringLiteral(
generateNewSourcePath(loaderMap, specifier.local.name, sourcePath)
)
);
});
},
ImportDeclaration(
path,
{
opts: { loaderMap },
}
) {
replaceMatchingSpecifiers(path, loaderMap, (specifier, sourcePath) => {
if (t.isImportDefaultSpecifier(specifier)) {
return t.importDeclaration(
[t.importDefaultSpecifier(t.identifier(specifier.local.name))],
t.stringLiteral(sourcePath)
);
}

return t.importDeclaration(
[
t.importSpecifier(
t.identifier(specifier.local.name),
t.identifier(specifier.imported.name)
),
],
t.stringLiteral(
generateNewSourcePath(
loaderMap,
specifier.imported.name,
sourcePath
)
)
);
});
},
},
};
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";',
},
},
});

0 comments on commit fb465a3

Please sign in to comment.