diff --git a/README.md b/README.md index 4ca1b5c..3044295 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,9 @@ git clone git@github.com:ant-design/codemod.git antd-codemod npx jscodeshift -t antd-codemod/transforms/v3-Icon-to-v4-Icon.js src/**/*.js --parser=babylon npx jscodeshift -t antd-codemod/transforms/v3-Icon-to-v4-Form.js src/**/*.js --parser=babylon npx jscodeshift -t antd-codemod/transforms/v3-LocaleProvider-to-v4-ConfigProvider.js src/**/*.js --parser=babylon +npx jscodeshift -t antd-codemod/transforms/v4-Icon-Outlined.js src/**/*.js --parser=babylon ``` + +**tips** + +If you are using typescript, you can use `--parser=tsx` option. diff --git a/transforms/__testfixtures__/v4-Icon-Outlined/alias-import.input.js b/transforms/__testfixtures__/v4-Icon-Outlined/alias-import.input.js new file mode 100644 index 0000000..2b7d90a --- /dev/null +++ b/transforms/__testfixtures__/v4-Icon-Outlined/alias-import.input.js @@ -0,0 +1,13 @@ +import { Smile as SmileO, SmileFilled, SmileTwoTone } from '@ant-design/icons'; + +const Component = () => { + return ; +}; + +const Component1 = props => { + return ; +}; + +const Component2 = props => { + return ; +}; diff --git a/transforms/__testfixtures__/v4-Icon-Outlined/alias-import.output.js b/transforms/__testfixtures__/v4-Icon-Outlined/alias-import.output.js new file mode 100644 index 0000000..df22182 --- /dev/null +++ b/transforms/__testfixtures__/v4-Icon-Outlined/alias-import.output.js @@ -0,0 +1,13 @@ +import { SmileFilled, SmileOutlined as SmileO, SmileTwoTone } from '@ant-design/icons'; + +const Component = () => { + return ; +}; + +const Component1 = props => { + return ; +}; + +const Component2 = props => { + return ; +}; diff --git a/transforms/__testfixtures__/v4-Icon-Outlined/basic.input.js b/transforms/__testfixtures__/v4-Icon-Outlined/basic.input.js new file mode 100644 index 0000000..7fd9bd6 --- /dev/null +++ b/transforms/__testfixtures__/v4-Icon-Outlined/basic.input.js @@ -0,0 +1,13 @@ +import { Smile, SmileFilled, SmileTwoTone } from '@ant-design/icons'; + +const Component = () => { + return ; +}; + +const Component1 = props => { + return ; +}; + +const Component2 = props => { + return ; +}; diff --git a/transforms/__testfixtures__/v4-Icon-Outlined/basic.output.js b/transforms/__testfixtures__/v4-Icon-Outlined/basic.output.js new file mode 100644 index 0000000..ffb8dea --- /dev/null +++ b/transforms/__testfixtures__/v4-Icon-Outlined/basic.output.js @@ -0,0 +1,13 @@ +import { SmileFilled, SmileOutlined, SmileTwoTone } from '@ant-design/icons'; + +const Component = () => { + return ; +}; + +const Component1 = props => { + return ; +}; + +const Component2 = props => { + return ; +}; diff --git a/transforms/__tests__/v4-Icon-Outlined.test.js b/transforms/__tests__/v4-Icon-Outlined.test.js new file mode 100644 index 0000000..035437c --- /dev/null +++ b/transforms/__tests__/v4-Icon-Outlined.test.js @@ -0,0 +1,11 @@ +const tests = ['basic', 'alias-import']; + +const defineTest = require('jscodeshift/dist/testUtils').defineTest; + +const testUnit = 'v4-Icon-Outlined'; + +describe(testUnit, () => { + tests.forEach(test => + defineTest(__dirname, testUnit, null, `${testUnit}/${test}`), + ); +}); diff --git a/transforms/v4-Icon-Outlined.js b/transforms/v4-Icon-Outlined.js new file mode 100644 index 0000000..a8b60df --- /dev/null +++ b/transforms/v4-Icon-Outlined.js @@ -0,0 +1,80 @@ +const allIcons = require('@ant-design/icons/lib/icons'); + +const { printOptions } = require('./utils/config'); +const { removeEmptyModuleImport, addSubmoduleImport } = require('./utils'); + +const outlinedIcons = Object.keys(allIcons) + .filter(n => n.endsWith('Outlined')) + .map(n => n.replace(/Outlined$/, '')); + +module.exports = (file, api, options) => { + const j = api.jscodeshift; + const root = j(file.source); + + // remove old LocaleProvider imports + function renameV4IconWithoutOutlinedImport(j, root) { + let hasChanged = false; + + // import { LocaleProvider } from 'antd'; + root + .find(j.Identifier) + .filter( + path => + outlinedIcons.includes(path.node.name) && + path.parent.node.type === 'ImportSpecifier' && + path.parent.parent.node.source.value === '@ant-design/icons', + ) + .forEach(path => { + hasChanged = true; + const localComponentName = path.parent.node.local.name; + const importComponentName = path.parent.node.imported.name; + + const importDeclaration = path.parent.parent.node; + importDeclaration.specifiers = importDeclaration.specifiers.filter( + specifier => + !specifier.imported || + specifier.imported.name !== importComponentName, + ); + + const outlinedIconName = importComponentName + 'Outlined'; + + if (localComponentName === importComponentName) { + addSubmoduleImport(j, root, '@ant-design/icons', outlinedIconName); + if (localComponentName === importComponentName) { + root + .findJSXElements(localComponentName) + .find(j.JSXIdentifier, { + name: localComponentName, + }) + .forEach(nodePath => { + nodePath.node.name = outlinedIconName; + }); + } + } else { + addSubmoduleImport( + j, + root, + '@ant-design/icons', + outlinedIconName, + localComponentName, + ); + } + }); + + return hasChanged; + } + + // step1. remove LocaleProvider import from antd + // step2. add ConfigProvider import from antd + // step3. cleanup antd import if empty + let hasChanged = false; + hasChanged = renameV4IconWithoutOutlinedImport(j, root) || hasChanged; + + if (hasChanged) { + removeEmptyModuleImport(j, root, 'antd'); + } + + return hasChanged + ? root.toSource(options.printOptions || printOptions) + : null; +};