diff --git a/src/index.js b/src/index.js
index 92dd3b8..89011f2 100644
--- a/src/index.js
+++ b/src/index.js
@@ -21,93 +21,106 @@ const buildSvgWithDefaults = template(`
let ignoreRegex;
-export default ({ types: t }) => ({
- visitor: {
- Program: {
- enter({ scope, node }, { file }) {
- if (!scope.hasBinding('React')) {
- const reactImportDeclaration = t.importDeclaration([
- t.importDefaultSpecifier(t.identifier('React')),
- ], t.stringLiteral('react'));
-
- file.set('ensureReact', () => { node.body.unshift(reactImportDeclaration); });
- } else {
- file.set('ensureReact', () => {});
- }
- },
- },
- ImportDeclaration(path, state) {
- const importPath = path.node.source.value;
- const { ignorePattern, caseSensitive } = state.opts;
- const { file } = state;
- if (ignorePattern) {
- // Only set the ignoreRegex once:
- ignoreRegex = ignoreRegex || new RegExp(ignorePattern);
- // Test if we should ignore this:
- if (ignoreRegex.test(importPath)) {
- return;
- }
+export default ({ types: t }) => {
+ function applyPlugin(importIdentifier, importPath, path, state) {
+ const { ignorePattern, caseSensitive } = state.opts;
+ const { file } = state;
+ if (ignorePattern) {
+ // Only set the ignoreRegex once:
+ ignoreRegex = ignoreRegex || new RegExp(ignorePattern);
+ // Test if we should ignore this:
+ if (ignoreRegex.test(importPath)) {
+ return;
}
- // This plugin only applies for SVGs:
- if (extname(importPath) === '.svg') {
- // We only support the import default specifier, so let's use that identifier:
- const importIdentifier = path.node.specifiers[0].local;
- const iconPath = state.file.opts.filename;
- const svgPath = resolveFrom(dirname(iconPath), importPath);
- if (caseSensitive && !fileExistsWithCaseSync(svgPath)) {
- throw new Error(`File path didn't match case of file on disk: ${svgPath}`);
- }
- if (!svgPath) {
- throw new Error(`File path does not exist: ${importPath}`);
- }
- const rawSource = readFileSync(svgPath, 'utf8');
- const optimizedSource = state.opts.svgo === false
- ? rawSource
- : optimize(rawSource, state.opts.svgo);
+ }
+ // This plugin only applies for SVGs:
+ if (extname(importPath) === '.svg') {
+ const iconPath = state.file.opts.filename;
+ const svgPath = resolveFrom(dirname(iconPath), importPath);
+ if (caseSensitive && !fileExistsWithCaseSync(svgPath)) {
+ throw new Error(`File path didn't match case of file on disk: ${svgPath}`);
+ }
+ if (!svgPath) {
+ throw new Error(`File path does not exist: ${importPath}`);
+ }
+ const rawSource = readFileSync(svgPath, 'utf8');
+ const optimizedSource = state.opts.svgo === false
+ ? rawSource
+ : optimize(rawSource, state.opts.svgo);
- const escapeSvgSource = escapeBraces(optimizedSource);
+ const escapeSvgSource = escapeBraces(optimizedSource);
- const parsedSvgAst = parse(escapeSvgSource, {
- sourceType: 'module',
- plugins: ['jsx'],
- });
+ const parsedSvgAst = parse(escapeSvgSource, {
+ sourceType: 'module',
+ plugins: ['jsx'],
+ });
+
+ traverse(parsedSvgAst, transformSvg(t));
- traverse(parsedSvgAst, transformSvg(t));
+ const svgCode = traverse.removeProperties(parsedSvgAst.program.body[0].expression);
- const svgCode = traverse.removeProperties(parsedSvgAst.program.body[0].expression);
+ const opts = {
+ SVG_NAME: importIdentifier,
+ SVG_CODE: svgCode,
+ };
- const opts = {
- SVG_NAME: importIdentifier,
- SVG_CODE: svgCode,
- };
+ // Move props off of element and into defaultProps
+ if (svgCode.openingElement.attributes.length > 1) {
+ const keepProps = [];
+ const defaultProps = [];
- // Move props off of element and into defaultProps
- if (svgCode.openingElement.attributes.length > 1) {
- const keepProps = [];
- const defaultProps = [];
+ svgCode.openingElement.attributes.forEach((prop) => {
+ if (prop.type === 'JSXSpreadAttribute') {
+ keepProps.push(prop);
+ } else {
+ defaultProps.push(t.objectProperty(t.identifier(prop.name.name), prop.value));
+ }
+ });
- svgCode.openingElement.attributes.forEach((prop) => {
- if (prop.type === 'JSXSpreadAttribute') {
- keepProps.push(prop);
- } else {
- defaultProps.push(t.objectProperty(t.identifier(prop.name.name), prop.value));
- }
- });
+ svgCode.openingElement.attributes = keepProps;
+ opts.SVG_DEFAULT_PROPS_CODE = t.objectExpression(defaultProps);
+ }
- svgCode.openingElement.attributes = keepProps;
- opts.SVG_DEFAULT_PROPS_CODE = t.objectExpression(defaultProps);
- }
+ if (opts.SVG_DEFAULT_PROPS_CODE) {
+ const svgReplacement = buildSvgWithDefaults(opts);
+ path.replaceWithMultiple(svgReplacement);
+ } else {
+ const svgReplacement = buildSvg(opts);
+ path.replaceWith(svgReplacement);
+ }
+ file.get('ensureReact')();
+ file.set('ensureReact', () => {});
+ }
+ }
+
+ return {
+ visitor: {
+ Program: {
+ enter({ scope, node }, { file }) {
+ if (!scope.hasBinding('React')) {
+ const reactImportDeclaration = t.importDeclaration([
+ t.importDefaultSpecifier(t.identifier('React')),
+ ], t.stringLiteral('react'));
- if (opts.SVG_DEFAULT_PROPS_CODE) {
- const svgReplacement = buildSvgWithDefaults(opts);
- path.replaceWithMultiple(svgReplacement);
- } else {
- const svgReplacement = buildSvg(opts);
- path.replaceWith(svgReplacement);
+ file.set('ensureReact', () => { node.body.unshift(reactImportDeclaration); });
+ } else {
+ file.set('ensureReact', () => {});
+ }
+ },
+ },
+ CallExpression(path, state) {
+ const { node } = path;
+ const filePath = node.arguments.length > 0 && node.arguments[0].value;
+ if (node.callee.name === 'require' && t.isVariableDeclarator(path.parent)) {
+ applyPlugin(path.parent.id, filePath, path.parentPath.parentPath, state);
}
- file.get('ensureReact')();
- file.set('ensureReact', () => {});
- }
+ },
+ ImportDeclaration(path, state) {
+ const { node } = path;
+ if (node.specifiers.length > 0) {
+ applyPlugin(node.specifiers[0].local, node.source.value, path, state);
+ }
+ },
},
- },
-});
+ };
+};
diff --git a/test/fixtures/test.jsx b/test/fixtures/test-import.jsx
similarity index 100%
rename from test/fixtures/test.jsx
rename to test/fixtures/test-import.jsx
diff --git a/test/fixtures/test-require.jsx b/test/fixtures/test-require.jsx
new file mode 100644
index 0000000..713cefd
--- /dev/null
+++ b/test/fixtures/test-require.jsx
@@ -0,0 +1,13 @@
+import React from 'react';
+
+const MySvg = require('./close.svg');
+
+export function MyFunctionIcon() {
+ return ;
+}
+
+export class MyClassIcon extends React.Component {
+ render() {
+ return ;
+ }
+}
diff --git a/test/sanity.js b/test/sanity.js
index 9f5d6f6..b105166 100644
--- a/test/sanity.js
+++ b/test/sanity.js
@@ -12,7 +12,7 @@ function assertReactImport(result) {
}
}
-transformFile('test/fixtures/test.jsx', {
+transformFile('test/fixtures/test-import.jsx', {
babelrc: false,
presets: ['react'],
plugins: [
@@ -21,7 +21,7 @@ transformFile('test/fixtures/test.jsx', {
}, (err, result) => {
if (err) throw err;
assertReactImport(result);
- console.log('test/fixtures/test.jsx', result.code);
+ console.log('test/fixtures/test-import.jsx', result.code);
});
transformFile('test/fixtures/test-multiple-svg.jsx', {
@@ -81,3 +81,24 @@ transformFile('test/fixtures/test-no-svg-or-react.js', {
throw new Error('Test failed: React import was present');
}
});
+
+transformFile('test/fixtures/test-import.jsx', {
+ presets: ['airbnb'],
+ plugins: [
+ '../../src/index',
+ ],
+}, (err1, importResult) => {
+ if (err1) throw err1;
+ console.log('test/fixtures/test-import.jsx', importResult.code);
+ transformFile('test/fixtures/test-require.jsx', {
+ presets: ['airbnb'],
+ plugins: [
+ '../../src/index',
+ ],
+ }, (err2, requireResult) => {
+ if (err2) throw err2;
+ if (importResult.code !== requireResult.code) {
+ throw new Error('Test failed: Import and require tests don\'t match');
+ }
+ });
+});