babel-plugin-inline-react-svg
Advanced tools
Comparing version 0.5.2 to 0.5.3
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
@@ -10,6 +10,6 @@ exports['default'] = fileExistsWithCaseSync; | ||
function fileExistsWithCaseSync(filepath) { | ||
var dir = path.dirname(filepath); | ||
if (dir === '/' || dir === '.') return true; | ||
var filenames = fs.readdirSync(dir); | ||
return filenames.indexOf(path.basename(filepath)) !== -1; | ||
var dir = path.dirname(filepath); | ||
if (dir === '/' || dir === '.') return true; | ||
var filenames = fs.readdirSync(dir); | ||
return filenames.indexOf(path.basename(filepath)) !== -1; | ||
} |
172
lib/index.js
@@ -19,5 +19,5 @@ Object.defineProperty(exports, "__esModule", { | ||
var _resolveFrom = require('resolve-from'); | ||
var _resolve = require('resolve'); | ||
var _resolveFrom2 = _interopRequireDefault(_resolveFrom); | ||
var _resolve2 = _interopRequireDefault(_resolve); | ||
@@ -50,2 +50,75 @@ var _optimize = require('./optimize'); | ||
var t = _ref.types; | ||
function applyPlugin(importIdentifier, importPath, path, state) { | ||
var _state$opts = state.opts, | ||
ignorePattern = _state$opts.ignorePattern, | ||
caseSensitive = _state$opts.caseSensitive; | ||
var file = state.file; | ||
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 ((0, _path.extname)(importPath) === '.svg') { | ||
var iconPath = state.file.opts.filename; | ||
var svgPath = _resolve2['default'].sync(importPath, { basedir: (0, _path.dirname)(iconPath) }); | ||
if (caseSensitive && !(0, _fileExistsWithCaseSync2['default'])(svgPath)) { | ||
throw new Error('File path didn\'t match case of file on disk: ' + String(svgPath)); | ||
} | ||
if (!svgPath) { | ||
throw new Error('File path does not exist: ' + String(importPath)); | ||
} | ||
var rawSource = (0, _fs.readFileSync)(svgPath, 'utf8'); | ||
var optimizedSource = state.opts.svgo === false ? rawSource : (0, _optimize2['default'])(rawSource, state.opts.svgo); | ||
var escapeSvgSource = (0, _escapeBraces2['default'])(optimizedSource); | ||
var parsedSvgAst = (0, _babylon.parse)(escapeSvgSource, { | ||
sourceType: 'module', | ||
plugins: ['jsx'] | ||
}); | ||
(0, _babelTraverse2['default'])(parsedSvgAst, (0, _transformSvg2['default'])(t)); | ||
var svgCode = _babelTraverse2['default'].removeProperties(parsedSvgAst.program.body[0].expression); | ||
var opts = { | ||
SVG_NAME: importIdentifier, | ||
SVG_CODE: svgCode | ||
}; | ||
// Move props off of element and into defaultProps | ||
if (svgCode.openingElement.attributes.length > 1) { | ||
var keepProps = []; | ||
var defaultProps = []; | ||
svgCode.openingElement.attributes.forEach(function (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); | ||
} | ||
if (opts.SVG_DEFAULT_PROPS_CODE) { | ||
var svgReplacement = buildSvgWithDefaults(opts); | ||
path.replaceWithMultiple(svgReplacement); | ||
} else { | ||
var _svgReplacement = buildSvg(opts); | ||
path.replaceWith(_svgReplacement); | ||
} | ||
file.get('ensureReact')(); | ||
file.set('ensureReact', function () {}); | ||
} | ||
} | ||
return { | ||
@@ -56,14 +129,12 @@ visitor: { | ||
function enter(_ref2, _ref3) { | ||
var scope = _ref2.scope; | ||
var node = _ref2.node; | ||
var scope = _ref2.scope, | ||
node = _ref2.node; | ||
var file = _ref3.file; | ||
if (!scope.hasBinding('React')) { | ||
(function () { | ||
var reactImportDeclaration = t.importDeclaration([t.importDefaultSpecifier(t.identifier('React'))], t.stringLiteral('react')); | ||
var reactImportDeclaration = t.importDeclaration([t.importDefaultSpecifier(t.identifier('React'))], t.stringLiteral('react')); | ||
file.set('ensureReact', function () { | ||
node.body.unshift(reactImportDeclaration); | ||
}); | ||
})(); | ||
file.set('ensureReact', function () { | ||
node.body.unshift(reactImportDeclaration); | ||
}); | ||
} else { | ||
@@ -77,73 +148,20 @@ file.set('ensureReact', function () {}); | ||
}, | ||
ImportDeclaration: function () { | ||
function ImportDeclaration(path, state) { | ||
var importPath = path.node.source.value; | ||
var _state$opts = state.opts; | ||
var ignorePattern = _state$opts.ignorePattern; | ||
var caseSensitive = _state$opts.caseSensitive; | ||
var file = state.file; | ||
CallExpression: function () { | ||
function CallExpression(path, state) { | ||
var node = path.node; | ||
if (ignorePattern) { | ||
// Only set the ignoreRegex once: | ||
ignoreRegex = ignoreRegex || new RegExp(ignorePattern); | ||
// Test if we should ignore this: | ||
if (ignoreRegex.test(importPath)) { | ||
return; | ||
} | ||
var 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); | ||
} | ||
// This plugin only applies for SVGs: | ||
if ((0, _path.extname)(importPath) === '.svg') { | ||
// We only support the import default specifier, so let's use that identifier: | ||
var importIdentifier = path.node.specifiers[0].local; | ||
var iconPath = state.file.opts.filename; | ||
var svgPath = (0, _resolveFrom2['default'])((0, _path.dirname)(iconPath), importPath); | ||
if (caseSensitive && !(0, _fileExistsWithCaseSync2['default'])(svgPath)) { | ||
throw new Error('File path didn\'t match case of file on disk: ' + String(svgPath)); | ||
} | ||
var rawSource = (0, _fs.readFileSync)(svgPath, 'utf8'); | ||
var optimizedSource = state.opts.svgo === false ? rawSource : (0, _optimize2['default'])(rawSource, state.opts.svgo); | ||
} | ||
var escapeSvgSource = (0, _escapeBraces2['default'])(optimizedSource); | ||
return CallExpression; | ||
}(), | ||
ImportDeclaration: function () { | ||
function ImportDeclaration(path, state) { | ||
var node = path.node; | ||
var parsedSvgAst = (0, _babylon.parse)(escapeSvgSource, { | ||
sourceType: 'module', | ||
plugins: ['jsx'] | ||
}); | ||
(0, _babelTraverse2['default'])(parsedSvgAst, (0, _transformSvg2['default'])(t)); | ||
var svgCode = _babelTraverse2['default'].removeProperties(parsedSvgAst.program.body[0].expression); | ||
var opts = { | ||
SVG_NAME: importIdentifier, | ||
SVG_CODE: svgCode | ||
}; | ||
// Move props off of element and into defaultProps | ||
if (svgCode.openingElement.attributes.length > 1) { | ||
(function () { | ||
var keepProps = []; | ||
var defaultProps = []; | ||
svgCode.openingElement.attributes.forEach(function (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); | ||
})(); | ||
} | ||
if (opts.SVG_DEFAULT_PROPS_CODE) { | ||
var svgReplacement = buildSvgWithDefaults(opts); | ||
path.replaceWithMultiple(svgReplacement); | ||
} else { | ||
var _svgReplacement = buildSvg(opts); | ||
path.replaceWith(_svgReplacement); | ||
} | ||
file.get('ensureReact')(); | ||
if (node.specifiers.length > 0) { | ||
applyPlugin(node.specifiers[0].local, node.source.value, path, state); | ||
} | ||
@@ -150,0 +168,0 @@ } |
@@ -5,3 +5,3 @@ Object.defineProperty(exports, "__esModule", { | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
@@ -36,2 +36,3 @@ exports['default'] = optimize; | ||
if (typeof opts.plugins === 'undefined' || Array.isArray(opts.plugins) && opts.plugins.length === 0) { | ||
/* eslint no-param-reassign: 1 */ | ||
opts.plugins = [].concat(essentialPlugins); | ||
@@ -60,2 +61,3 @@ return; | ||
// and update state | ||
/* eslint no-param-reassign: 1 */ | ||
state[k] = true; | ||
@@ -75,3 +77,3 @@ } | ||
function optimize(content) { | ||
var opts = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
@@ -78,0 +80,0 @@ validateAndFix(opts); |
@@ -21,4 +21,7 @@ Object.defineProperty(exports, "__esModule", { | ||
JSXAttribute: function () { | ||
function JSXAttribute(path) { | ||
if (t.isJSXNamespacedName(path.node.name)) { | ||
function JSXAttribute(_ref) { | ||
var node = _ref.node; | ||
var originalName = node.name; | ||
if (t.isJSXNamespacedName(originalName)) { | ||
// converts | ||
@@ -28,4 +31,4 @@ // <svg xmlns:xlink="asdf"> | ||
// <svg xmlnsXlink="asdf"> | ||
path.node.name = t.jSXIdentifier((0, _camelize.namespaceToCamel)(path.node.name.namespace.name, path.node.name.name.name)); | ||
} else if (t.isJSXIdentifier(path.node.name)) { | ||
node.name = t.jSXIdentifier((0, _camelize.namespaceToCamel)(originalName.namespace.name, originalName.name.name)); | ||
} else if (t.isJSXIdentifier(originalName)) { | ||
// converts | ||
@@ -35,4 +38,4 @@ // <tag class="blah blah1"/> | ||
// <tag className="blah blah1"/> | ||
if (path.node.name.name === 'class') { | ||
path.node.name.name = 'className'; | ||
if (originalName.name === 'class') { | ||
originalName.name = 'className'; | ||
} | ||
@@ -44,10 +47,8 @@ | ||
// <tag style={{textAlign: 'center', width: '50px'}}> | ||
if (path.node.name.name === 'style') { | ||
(function () { | ||
var csso = (0, _cssToObj2['default'])(path.node.value.value); | ||
var properties = Object.keys(csso).map(function (prop) { | ||
return t.objectProperty(t.identifier((0, _camelize.hyphenToCamel)(prop)), t.stringLiteral(csso[prop])); | ||
}); | ||
path.node.value = t.jSXExpressionContainer(t.objectExpression(properties)); | ||
})(); | ||
if (originalName.name === 'style') { | ||
var csso = (0, _cssToObj2['default'])(node.value.value); | ||
var properties = Object.keys(csso).map(function (prop) { | ||
return t.objectProperty(t.identifier((0, _camelize.hyphenToCamel)(prop)), t.stringLiteral(csso[prop])); | ||
}); | ||
node.value = t.jSXExpressionContainer(t.objectExpression(properties)); | ||
} | ||
@@ -59,5 +60,7 @@ | ||
// <svg strokeWidth="5"> | ||
// don't convert any custom data-* attributes | ||
if (!path.node.name.name.startsWith('data-')) { | ||
path.node.name.name = (0, _camelize.hyphenToCamel)(path.node.name.name); | ||
// don't convert any custom data-* or aria-* attributes just wrap in quotes | ||
if (/^data-|^aria-/.test(originalName.name)) { | ||
originalName.name = '\'' + String(originalName.name) + '\''; | ||
} else { | ||
originalName.name = (0, _camelize.hyphenToCamel)(originalName.name); | ||
} | ||
@@ -77,6 +80,10 @@ } | ||
JSXOpeningElement: function () { | ||
function JSXOpeningElement(path) { | ||
if (path.node.name.name.toLowerCase() === 'svg') { | ||
function JSXOpeningElement(_ref2) { | ||
var _ref2$node = _ref2.node, | ||
name = _ref2$node.name, | ||
attributes = _ref2$node.attributes; | ||
if (name.name.toLowerCase() === 'svg') { | ||
// add spread props | ||
path.node.attributes.push(t.jSXSpreadAttribute(t.identifier('props'))); | ||
attributes.push(t.jSXSpreadAttribute(t.identifier('props'))); | ||
} | ||
@@ -83,0 +90,0 @@ } |
{ | ||
"name": "babel-plugin-inline-react-svg", | ||
"version": "0.5.2", | ||
"version": "0.5.3", | ||
"description": "A babel plugin that optimizes and inlines SVGs for your react components.", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"sanity": "babel-node test/sanity.js", | ||
"test": "npm run tests-only", | ||
"pretests-only": "npm run build", | ||
"tests-only": "babel-node test/sanity.js", | ||
"build": "babel src --out-dir lib", | ||
"lint": "eslint src/", | ||
"prepublish": "npm run build" | ||
"prepublish": "npm run build", | ||
"pretest": "npm run lint" | ||
}, | ||
@@ -31,21 +33,21 @@ "repository": { | ||
"devDependencies": { | ||
"babel-cli": "^6.14.0", | ||
"babel-core": "^6.14.0", | ||
"babel-preset-airbnb": "^2.0.0", | ||
"babel-cli": "^6.26.0", | ||
"babel-core": "^6.26.3", | ||
"babel-preset-airbnb": "^2.5.1", | ||
"babel-preset-react": "^6.24.1", | ||
"eslint": "^3.5.0", | ||
"eslint-config-airbnb": "^11.1.0", | ||
"eslint-plugin-import": "^1.15.0", | ||
"eslint-plugin-jsx-a11y": "^2.2.2", | ||
"eslint-plugin-react": "^6.2.2", | ||
"eslint": "^4.19.1", | ||
"eslint-config-airbnb": "^17.0.0", | ||
"eslint-plugin-import": "^2.13.0", | ||
"eslint-plugin-jsx-a11y": "^6.0.3", | ||
"eslint-plugin-react": "^7.10.0", | ||
"react": "^15.3.1" | ||
}, | ||
"dependencies": { | ||
"babel-template": "^6.15.0", | ||
"babel-traverse": "^6.15.0", | ||
"babylon": "^6.10.0", | ||
"babel-template": "^6.26.0", | ||
"babel-traverse": "^6.26.0", | ||
"babylon": "^6.18.0", | ||
"lodash.isplainobject": "^4.0.6", | ||
"resolve-from": "^2.0.0", | ||
"svgo": "^0.7.0" | ||
"resolve": "^1.8.1", | ||
"svgo": "^0.7.2" | ||
} | ||
} |
@@ -11,3 +11,3 @@ # babel-plugin-inline-react-svg | ||
const MyComponent = () => <CloseSvg />; | ||
const MyComponent = () => <CloseSVG />; | ||
``` | ||
@@ -21,3 +21,3 @@ | ||
const MyComponent = () => <CloseSvg />; | ||
const MyComponent = () => <CloseSVG />; | ||
``` | ||
@@ -24,0 +24,0 @@ |
import { transformFile } from 'babel-core'; | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
function assertReactImport(result) { | ||
const match = result.code.match(/import React from 'react'/); | ||
const match = result.code.match(/import React from 'react'/g); | ||
if (!match) { | ||
@@ -9,7 +11,13 @@ throw new Error('no React import found'); | ||
if (match.length !== 1) { | ||
throw new Error('more or less than one match found'); | ||
throw new Error(`more or less than one match found: ${match}\n${result.code}`); | ||
} | ||
} | ||
transformFile('test/fixtures/test.jsx', { | ||
function validateDefaultProps(result) { | ||
if (!(/'data-name':/g).test(result.code)) { | ||
throw new Error('data-* props need to be quoted'); | ||
} | ||
} | ||
transformFile('test/fixtures/test-import.jsx', { | ||
babelrc: false, | ||
@@ -23,6 +31,7 @@ presets: ['react'], | ||
assertReactImport(result); | ||
console.log('test/fixtures/test.jsx', result.code); | ||
validateDefaultProps(result); | ||
console.log('test/fixtures/test-import.jsx', result.code); | ||
}); | ||
transformFile('test/fixtures/test-no-react.jsx', { | ||
transformFile('test/fixtures/test-multiple-svg.jsx', { | ||
babelrc: false, | ||
@@ -35,22 +44,40 @@ presets: ['react'], | ||
if (err) throw err; | ||
console.log('test/fixtures/test-no-react.jsx', result.code); | ||
assertReactImport(result); | ||
validateDefaultProps(result); | ||
console.log('test/fixtures/test-multiple-svg.jsx', result.code); | ||
}); | ||
transformFile('test/fixtures/test-case-sensitive.jsx', { | ||
transformFile('test/fixtures/test-no-react.jsx', { | ||
babelrc: false, | ||
presets: ['react'], | ||
plugins: [ | ||
['../../src/index', { | ||
caseSensitive: true, | ||
}], | ||
'../../src/index', | ||
], | ||
}, (err) => { | ||
if (err && err.message.indexOf('match case') !== -1) { | ||
console.log('test/fixtures/test-case-sensitive.jsx', 'Test passed: Expected case sensitive error was thrown'); | ||
} else { | ||
throw new Error("Test failed: Expected case sensitive error wasn't thrown"); | ||
} | ||
}, (err, result) => { | ||
if (err) throw err; | ||
console.log('test/fixtures/test-no-react.jsx', result.code); | ||
assertReactImport(result); | ||
validateDefaultProps(result); | ||
}); | ||
if (fs.existsSync(path.resolve('./PACKAGE.JSON'))) { | ||
transformFile('test/fixtures/test-case-sensitive.jsx', { | ||
babelrc: false, | ||
presets: ['react'], | ||
plugins: [ | ||
['../../src/index', { | ||
caseSensitive: true, | ||
}], | ||
], | ||
}, (err) => { | ||
if (err && err.message.indexOf('match case') !== -1) { | ||
console.log('test/fixtures/test-case-sensitive.jsx', 'Test passed: Expected case sensitive error was thrown'); | ||
} else { | ||
throw new Error("Test failed: Expected case sensitive error wasn't thrown"); | ||
} | ||
}); | ||
} else { | ||
console.log('# SKIP: case-sensitive check; on a case-sensitive filesystem'); | ||
} | ||
transformFile('test/fixtures/test-no-svg-or-react.js', { | ||
@@ -69,1 +96,22 @@ babelrc: false, | ||
}); | ||
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'); | ||
} | ||
}); | ||
}); |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
22536
21
483
1
3
1
+ Addedresolve@^1.8.1
+ Addedfunction-bind@1.1.2(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedis-core-module@2.16.1(transitive)
+ Addedpath-parse@1.0.7(transitive)
+ Addedresolve@1.22.10(transitive)
+ Addedsupports-preserve-symlinks-flag@1.0.0(transitive)
- Removedresolve-from@^2.0.0
- Removedresolve-from@2.0.0(transitive)
Updatedbabel-template@^6.26.0
Updatedbabel-traverse@^6.26.0
Updatedbabylon@^6.18.0
Updatedsvgo@^0.7.2