Skip to content

Commit

Permalink
refactor: make default props emission disabled by default and use obj…
Browse files Browse the repository at this point in the history
…ect assign instead
  • Loading branch information
Grohden committed Dec 5, 2024
1 parent 5efa467 commit 0361226
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 25 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ npm install --save-dev babel-plugin-inline-react-svg

- `ignorePattern` - A pattern that imports will be tested against to selectively ignore imports.
- `caseSensitive` - A boolean value that if true will require file paths to match with case-sensitivity. Useful to ensure consistent behavior if working on both a case-sensitive operating system like Linux and a case-insensitive one like OS X or Windows.
- `emitDeprecatedDefaultProps` - A boolean value that if true will make the package keep emitting the [deprecated](https://github.com/facebook/react/pull/16210) `.defaultProps` declaration for the generated SVG components
- `svgo` - svgo options (`false` to disable). Example:
```json
{
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/parser": "^7.0.0",
"lodash.isplainobject": "^4.0.6",
"object.assign": "^4.1.5",
"resolve": "^2.0.0-next.5",
"svgo": "^2.8.0"
},
Expand Down
48 changes: 41 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,46 @@ export default declare(({
SVG_NAME,
SVG_CODE,
SVG_DEFAULT_PROPS_CODE,
EMIT_DEPRECATED_DEFAULT_PROPS,
}) => {
const defaultProps = SVG_DEFAULT_PROPS_CODE
? 'var props = objectAssign({}, SVG_DEFAULT_PROPS_CODE, overrides);'
: '';
const PROPS_NAME = SVG_DEFAULT_PROPS_CODE ? 'overrides' : 'props';

const namedTemplate = `
var SVG_NAME = function SVG_NAME(props) { return SVG_CODE; };
${SVG_DEFAULT_PROPS_CODE ? 'SVG_NAME.defaultProps = SVG_DEFAULT_PROPS_CODE;' : ''}
${SVG_DEFAULT_PROPS_CODE ? '' : ''}
var SVG_NAME = function SVG_NAME(PROPS_NAME) { ${defaultProps} return SVG_CODE; };
${SVG_DEFAULT_PROPS_CODE && EMIT_DEPRECATED_DEFAULT_PROPS ? 'SVG_NAME.defaultProps = SVG_DEFAULT_PROPS_CODE;' : ''}
${IS_EXPORT ? 'export { SVG_NAME };' : ''}
`;
const anonymousTemplate = `
var Component = function (props) { return SVG_CODE; };
${SVG_DEFAULT_PROPS_CODE ? 'Component.defaultProps = SVG_DEFAULT_PROPS_CODE;' : ''}
var Component = function (PROPS_NAME) { ${defaultProps}; return SVG_CODE; };
${SVG_DEFAULT_PROPS_CODE && EMIT_DEPRECATED_DEFAULT_PROPS ? 'Component.defaultProps = SVG_DEFAULT_PROPS_CODE;' : ''}
Component.displayName = 'EXPORT_FILENAME';
export default Component;
`;

if (SVG_NAME !== 'default') {
return template(namedTemplate)({ SVG_NAME, SVG_CODE, SVG_DEFAULT_PROPS_CODE });
return template(namedTemplate)({
SVG_NAME, SVG_CODE, SVG_DEFAULT_PROPS_CODE, PROPS_NAME,
});
}
return template(anonymousTemplate)({ SVG_CODE, SVG_DEFAULT_PROPS_CODE, EXPORT_FILENAME });
return template(anonymousTemplate)({
SVG_CODE, SVG_DEFAULT_PROPS_CODE, EXPORT_FILENAME, PROPS_NAME,
});
};

function applyPlugin(importIdentifier, importPath, path, state, isExport, exportFilename) {
if (typeof importPath !== 'string') {
throw new TypeError('`applyPlugin` `importPath` must be a string');
}
const { ignorePattern, caseSensitive, filename: providedFilename } = state.opts;
const {
ignorePattern,
caseSensitive,
filename: providedFilename,
emitDeprecatedDefaultProps = false,
} = state.opts;
const { file, filename } = state;
let newPath;
if (ignorePattern) {
Expand Down Expand Up @@ -93,6 +109,8 @@ export default declare(({
SVG_CODE: svgCode,
IS_EXPORT: isExport,
EXPORT_FILENAME: exportFilename,
// https://github.com/facebook/react/pull/16210
EMIT_DEPRECATED_DEFAULT_PROPS: emitDeprecatedDefaultProps,
};

// Move props off of element and into defaultProps
Expand Down Expand Up @@ -124,6 +142,8 @@ export default declare(({

file.get('ensureReact')();
file.set('ensureReact', () => {});
file.get('ensureObjectAssign')();
file.set('ensureObjectAssign', () => {});
}
return newPath;
}
Expand All @@ -138,6 +158,20 @@ export default declare(({
if (typeof filename === 'undefined' && typeof opts.filename !== 'string') {
throw new TypeError('the "filename" option is required when transforming code');
}

if (!path.scope.hasBinding('object.assign/implementation')) {
const assignDeclaration = t.importDeclaration([
t.importDefaultSpecifier(t.identifier('objectAssign')),
], t.stringLiteral('object.assign/implementation'));

file.set('ensureObjectAssign', () => {
const [newPath] = path.unshiftContainer('body', assignDeclaration);
newPath.get('specifiers').forEach((specifier) => { path.scope.registerBinding('module', specifier); });
});
} else {
file.set('ensureObjectAssign', () => {});
}

if (!path.scope.hasBinding('React')) {
const reactImportDeclaration = t.importDeclaration([
t.importDefaultSpecifier(t.identifier('React')),
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/test-props.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import SVG from './close.svg';

export function MyFunctionIcon() {
return <SVG />;
}
76 changes: 58 additions & 18 deletions test/sanity.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,34 @@ import path from 'path';
import transformTs from '@babel/plugin-transform-typescript';
import inlineReactSvgPlugin from '../src';

function assertReactImport(result) {
const match = result.code.match(/import React from ['"]react['"]/g);
if (!match) {
throw new Error('no React import found');
function assertMatchImport(name, matchRegex) {
return (result) => {
const match = result.code.match(matchRegex());
if (!match) {
throw new Error(`no ${name} import found`);
}
if (match.length !== 1) {
throw new Error(`more or less than one match found: ${match}\n${result.code}`);
}
};
}

const assertReactImport = assertMatchImport('React', () => /import React from ['"]react['"]/g);

const assertObjectAssignImport = assertMatchImport(
'object.assign/implementation',
() => /import objectAssign from ['"]object.assign\/implementation['"]/g,
);

function assertDefaultProps(shouldExist, result) {
const exists = (/\.defaultProps = /g).test(result.code);

if (!exists && shouldExist) {
throw new Error('defaultProps needs to be present');
}
if (match.length !== 1) {
throw new Error(`more or less than one match found: ${match}\n${result.code}`);

if (exists && !shouldExist) {
throw new Error('defaultProps shouldn\'t be present');
}
}

Expand All @@ -29,8 +50,10 @@ transformFile('test/fixtures/test-import.jsx', {
}, (err, result) => {
if (err) throw err;
assertReactImport(result);
assertObjectAssignImport(result);
assertDefaultProps(false, result);
validateDefaultProps(result);
console.log('test/fixtures/test-import.jsx', result.code);
console.log('test/fixtures/test-import.jsx\n', result.code);
});

transformFile('test/fixtures/test-multiple-svg.jsx', {
Expand All @@ -42,8 +65,10 @@ transformFile('test/fixtures/test-multiple-svg.jsx', {
}, (err, result) => {
if (err) throw err;
assertReactImport(result);
assertObjectAssignImport(result);
assertDefaultProps(false, result);
validateDefaultProps(result);
console.log('test/fixtures/test-multiple-svg.jsx', result.code);
console.log('test/fixtures/test-multiple-svg.jsx\n', result.code);
});

transformFile('test/fixtures/test-no-react.jsx', {
Expand All @@ -54,8 +79,10 @@ transformFile('test/fixtures/test-no-react.jsx', {
],
}, (err, result) => {
if (err) throw err;
console.log('test/fixtures/test-no-react.jsx', result.code);
console.log('test/fixtures/test-no-react.jsx\n', result.code);
assertReactImport(result);
assertObjectAssignImport(result);
assertDefaultProps(false, result);
validateDefaultProps(result);
});

Expand All @@ -78,8 +105,10 @@ transformFile('test/fixtures/test-no-duplicate-react.jsx', {
],
}, (err, result) => {
if (err) throw err;
console.log('test/fixtures/test-no-duplicate-react.jsx', result.code);
console.log('test/fixtures/test-no-duplicate-react.jsx\n', result.code);
assertReactImport(result);
assertObjectAssignImport(result);
assertDefaultProps(false, result);
validateDefaultProps(result);
});

Expand Down Expand Up @@ -111,7 +140,7 @@ transformFile('test/fixtures/test-no-svg-or-react.js', {
],
}, (err, result) => {
if (err) throw err;
console.log('test/fixtures/test-no-svg-or-react.js', result.code);
console.log('test/fixtures/test-no-svg-or-react.js\n', result.code);
if (/React/.test(result.code)) {
throw new Error('Test failed: React import was present');
}
Expand Down Expand Up @@ -145,7 +174,7 @@ transformFile('test/fixtures/test-dynamic-require.jsx', {
],
}, (err, result) => {
if (err) throw err;
console.log('test/fixtures/test-dynamic-require.jsx', result.code);
console.log('test/fixtures/test-dynamic-require.jsx\n', result.code);
});

const filename = 'test/fixtures/test-import-read-file.jsx';
Expand All @@ -156,7 +185,7 @@ transform(fs.readFileSync(filename), {
],
}, (err, result) => {
if (err) throw err;
console.log('test/fixtures/test-import-read-file.jsx', result.code);
console.log('test/fixtures/test-import-read-file.jsx\n', result.code);
});

transformFile('test/fixtures/test-export-default.jsx', {
Expand All @@ -166,7 +195,7 @@ transformFile('test/fixtures/test-export-default.jsx', {
],
}, (err, result) => {
if (err) throw err;
console.log('test/fixtures/test-export-default.jsx', result.code);
console.log('test/fixtures/test-export-default.jsx\n', result.code);
});

transformFile('test/fixtures/test-export-default-as.jsx', {
Expand All @@ -182,7 +211,7 @@ transformFile('test/fixtures/test-export-default-as.jsx', {
],
}, (err, result) => {
if (err) throw err;
console.log('test/fixtures/test-export-default-as.jsx', result.code);
console.log('test/fixtures/test-export-default-as.jsx\n', result.code);
});

transformFile('test/fixtures/test-export-all-as.jsx', {
Expand All @@ -192,7 +221,7 @@ transformFile('test/fixtures/test-export-all-as.jsx', {
],
}, (err, result) => {
if (err) throw err;
console.log('test/fixtures/test-export-all-as.jsx', result.code);
console.log('test/fixtures/test-export-all-as.jsx\n', result.code);
});

transformFile('test/fixtures/test-root-styled.jsx', {
Expand All @@ -202,7 +231,7 @@ transformFile('test/fixtures/test-root-styled.jsx', {
],
}, (err, result) => {
if (err) throw err;
console.log('test/fixtures/test-root-styled.jsx', result.code);
console.log('test/fixtures/test-root-styled.jsx\n', result.code);
});

transformFile('test/fixtures/test-commented.jsx', {
Expand All @@ -212,7 +241,18 @@ transformFile('test/fixtures/test-commented.jsx', {
],
}, (err, result) => {
if (err) throw err;
console.log('test/fixtures/test-commented.jsx', result.code);
console.log('test/fixtures/test-commented.jsx\n', result.code);
});

transformFile('test/fixtures/test-props.jsx', {
presets: ['airbnb'],
plugins: [
[inlineReactSvgPlugin, { emitDeprecatedDefaultProps: true }],
],
}, (err, result) => {
if (err) throw err;
assertDefaultProps(true, result);
console.log('test/fixtures/test-props.jsx\n', result.code);
});

/* TODO: uncomment if babel fixes its parsing for SVGs
Expand Down

0 comments on commit 0361226

Please sign in to comment.