diff --git a/.travis.yml b/.travis.yml index 5ab70bc..3ddc064 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,11 @@ language: node_js os: - linux node_js: + - "15" + - "14" + - "12" - "10" - - "9" - - "8" - - "6" + - "10.13" before_install: - 'nvm install-latest-npm' script: diff --git a/README.md b/README.md index e1ce600..babdcf6 100644 --- a/README.md +++ b/README.md @@ -54,13 +54,11 @@ npm install --save-dev babel-plugin-inline-react-svg "svgo": { "plugins": [ { - "removeAttrs": { "attrs": "(data-name)" } + "name": "removeAttrs", + "params": { "attrs": "(data-name)" } }, - { - "cleanupIDs": true - } + "cleanupIDs" ] - } } ] @@ -89,6 +87,31 @@ import MySvg from 'images/logo.svg'; import AnotherSvg from 'icons/cross.svg'; ``` +**Note:** If `plugins` field is specified the default enabled `svgo` plugins will be overrided. Alternatively, if your Babel config is in JavaScript, the default list of plugins can be extended by making use of the `extendDefaultPlugins` utility provided by `svgo`. + +```js +const { extendDefaultPlugins } = require('svgo'); + +module.exports = { + plugins: [ + [ + 'inline-react-svg', + { + svgo: { + plugins: extendDefaultPlugins([ + { + name: 'removeAttrs', + params: { attrs: '(data-name)' } + }, + 'cleanupIDs', + ]) + } + } + ] + ] +} +``` + ### Via CLI ```sh diff --git a/package.json b/package.json index 5570040..138164e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@nrako/babel-plugin-inline-react-svg", - "version": "1.2.0", + "version": "2.0.1", "description": "A babel plugin that optimizes and inlines SVGs for your react components.", "main": "lib/index.js", "scripts": { @@ -30,16 +30,16 @@ }, "homepage": "https://github.com/nrako/babel-plugin-inline-react-svg#readme", "devDependencies": { - "@babel/cli": "^7.4.3", + "@babel/cli": "^7.12.16", "@babel/core": "^7.0.0", - "@babel/node": "^7.2.2", - "@babel/preset-react": "^7.0.0", - "babel-preset-airbnb": "^3.2.1", - "eslint": "^5.16.0", - "eslint-config-airbnb": "^17.1.0", - "eslint-plugin-import": "^2.16.0", - "eslint-plugin-jsx-a11y": "^6.2.1", - "eslint-plugin-react": "^7.12.4", + "@babel/node": "^7.12.16", + "@babel/preset-react": "^7.12.13", + "babel-preset-airbnb": "^3.3.2", + "eslint": "^7.20.0", + "eslint-config-airbnb": "^18.2.1", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jsx-a11y": "^6.4.1", + "eslint-plugin-react": "^7.22.0", "react": "^15.3.1" }, "peerDependencies": { @@ -49,11 +49,10 @@ "@babel/helper-plugin-utils": "^7.0.0", "@babel/parser": "^7.0.0", "lodash.isplainobject": "^4.0.6", - "resolve": "^1.10.0", - "svgo": "^0.7.2" + "resolve": "^1.20.0", + "svgo": "^2.0.3" }, - "directories": { - "lib": "lib", - "test": "test" + "engines": { + "node": ">=10.13" } } diff --git a/src/camelize.js b/src/camelize.js index 2a9c6f5..3fa37f3 100644 --- a/src/camelize.js +++ b/src/camelize.js @@ -1,5 +1,5 @@ export function hyphenToCamel(name) { - return name.replace(/-([a-z])/g, g => g[1].toUpperCase()); + return name.replace(/-([a-z])/g, (g) => g[1].toUpperCase()); } export function namespaceToCamel(namespace, name) { diff --git a/src/cssToObj.js b/src/cssToObj.js index eefe041..8e74e5f 100644 --- a/src/cssToObj.js +++ b/src/cssToObj.js @@ -1,7 +1,7 @@ export default function cssToObj(css) { const o = {}; css.split(';') - .filter(el => !!el) + .filter((el) => !!el) .forEach((el) => { const s = el.split(':'); const key = s.shift().trim(); diff --git a/src/escapeBraces.js b/src/escapeBraces.js index 4cd0a16..eaa206a 100644 --- a/src/escapeBraces.js +++ b/src/escapeBraces.js @@ -7,5 +7,5 @@ export default function escapeBraces(raw) { // // to // - return raw.replace(/(\{|\})/g, '{`$1`}'); + return { ...raw, data: raw.data.replace(/(\{|\})/g, '{`$1`}') }; } diff --git a/src/index.js b/src/index.js index bc48e4e..34e3823 100644 --- a/src/index.js +++ b/src/index.js @@ -107,12 +107,12 @@ export default declare(({ const rawSource = readFileSync(chosenPath, 'utf8'); const optimizedSource = state.opts.svgo === false - ? rawSource + ? { data: rawSource } : optimize(rawSource, state.opts.svgo); const escapeSvgSource = escapeBraces(optimizedSource); - const parsedSvgAst = parse(escapeSvgSource, { + const parsedSvgAst = parse(escapeSvgSource.data, { sourceType: 'module', plugins: ['jsx'], }); @@ -197,7 +197,7 @@ export default declare(({ }, ExportNamedDeclaration(path, state) { const { node } = path; - if (node.specifiers.length > 0 && node.specifiers[0].local.name === 'default') { + if (node.specifiers.length > 0 && node.specifiers[0].local && node.specifiers[0].local.name === 'default') { const exportName = node.specifiers[0].exported.name; const filename = parseFilename(node.source.value).name; applyPlugin(exportName, node.source.value, path, state, true, filename); diff --git a/src/optimize.js b/src/optimize.js index 7849c5c..d9e56e0 100644 --- a/src/optimize.js +++ b/src/optimize.js @@ -1,7 +1,7 @@ // validates svgo opts // to contain minimal set of plugins that will strip some stuff // for the babylon JSX parser to work -import Svgo from 'svgo'; +import * as SVGO from 'svgo'; import isPlainObject from 'lodash.isplainobject'; const essentialPlugins = ['removeDoctype', 'removeComments']; @@ -48,23 +48,12 @@ function validateAndFix(opts) { }); Object.keys(state) - .filter(key => !state[key]) - .forEach(key => opts.plugins.push(key)); + .filter((key) => !state[key]) + .forEach((key) => opts.plugins.push(key)); } export default function optimize(content, opts = {}) { validateAndFix(opts); - const svgo = new Svgo(opts); - // Svgo isn't _really_ async, so let's do it this way: - let returnValue; - svgo.optimize(content, (response) => { - if (response.error) { - returnValue = response.error; - } else { - returnValue = response.data; - } - }); - - return returnValue; + return SVGO.optimize(content, opts); } diff --git a/src/transformSvg.js b/src/transformSvg.js index fcc84cf..bccb0a7 100644 --- a/src/transformSvg.js +++ b/src/transformSvg.js @@ -6,7 +6,7 @@ import { namespaceToCamel, hyphenToCamel } from './camelize'; import cssToObj from './cssToObj'; -export default t => ({ +export default (t) => ({ JSXAttribute({ node }) { const { name: originalName } = node; if (t.isJSXNamespacedName(originalName)) { @@ -33,7 +33,7 @@ export default t => ({ // if (originalName.name === 'style') { const csso = cssToObj(node.value.value); - const properties = Object.keys(csso).map(prop => t.objectProperty( + const properties = Object.keys(csso).map((prop) => t.objectProperty( t.identifier(hyphenToCamel(prop)), t.stringLiteral(csso[prop]), )); diff --git a/test/fixtures/commented.svg b/test/fixtures/commented.svg new file mode 100644 index 0000000..c54abbc --- /dev/null +++ b/test/fixtures/commented.svg @@ -0,0 +1 @@ + diff --git a/test/fixtures/test-commented.jsx b/test/fixtures/test-commented.jsx new file mode 100644 index 0000000..374f58c --- /dev/null +++ b/test/fixtures/test-commented.jsx @@ -0,0 +1,11 @@ +import SVG from './commented.svg'; + +export function MyFunctionIcon() { + return ; +} + +export class MyClassIcon extends React.Component { + render() { + return ; + } +} diff --git a/test/fixtures/test-export-all-as.jsx b/test/fixtures/test-export-all-as.jsx new file mode 100644 index 0000000..ee2c097 --- /dev/null +++ b/test/fixtures/test-export-all-as.jsx @@ -0,0 +1 @@ +export * as foo from 'bar'; diff --git a/test/sanity.js b/test/sanity.js index 62528d7..f8393dd 100644 --- a/test/sanity.js +++ b/test/sanity.js @@ -178,6 +178,28 @@ transformFile('test/fixtures/test-export-default-as.jsx', { console.log('test/fixtures/test-export-default-as.jsx', result.code); }); +transformFile('test/fixtures/test-export-all-as.jsx', { + presets: ['airbnb'], + plugins: [ + inlineReactSvgPlugin, + ], +}, (err, result) => { + if (err) throw err; + console.log('test/fixtures/test-export-all-as.jsx', result.code); +}); + +/* TODO: uncomment if babel fixes its parsing for SVGs +transformFile('test/fixtures/test-commented.jsx', { + presets: ['airbnb'], + plugins: [ + [inlineReactSvgPlugin, { svgo: false }], + ], +}, (err, result) => { + if (err) throw err; + console.log('test/fixtures/test-commented.jsx', result.code); +}); +*/ + /** * Alias tests */