From 9a2ffcde5d3fad6fcc44eb8630c6551e7b266564 Mon Sep 17 00:00:00 2001 From: dengfuping Date: Thu, 29 Aug 2024 21:47:17 +0800 Subject: [PATCH] fix(codemod): normal function and anonymous function should use token object --- .../function-component.input.js | 15 +++++++- .../function-component.output.js | 16 +++++++- .../style-to-token/function.input.js | 37 +++++++++++++++++++ .../style-to-token/function.output.js | 37 +++++++++++++++++++ .../style-to-token/hooks.input.js | 26 +++++++++++++ .../style-to-token/hooks.output.js | 28 ++++++++++++++ .../__tests__/style-to-token.test.ts | 2 + packages/codemod/transforms/style-to-token.js | 25 ++++++++++--- 8 files changed, 177 insertions(+), 9 deletions(-) create mode 100644 packages/codemod/transforms/__testfixtures__/style-to-token/function.input.js create mode 100644 packages/codemod/transforms/__testfixtures__/style-to-token/function.output.js create mode 100644 packages/codemod/transforms/__testfixtures__/style-to-token/hooks.input.js create mode 100644 packages/codemod/transforms/__testfixtures__/style-to-token/hooks.output.js diff --git a/packages/codemod/transforms/__testfixtures__/style-to-token/function-component.input.js b/packages/codemod/transforms/__testfixtures__/style-to-token/function-component.input.js index 42db1d3f1..0abd47283 100644 --- a/packages/codemod/transforms/__testfixtures__/style-to-token/function-component.input.js +++ b/packages/codemod/transforms/__testfixtures__/style-to-token/function-component.input.js @@ -1,7 +1,7 @@ import React from 'react'; import { Alert, Button, Tooltip } from '@oceanbase/design'; -const Demo = () => { +function Demo1() { const tokenList = ['rgb(0 0 0 / 45%)', '#006AFF', '#f3f6fc']; return (
@@ -12,4 +12,15 @@ const Demo = () => { ); }; -export default Demo; +const Demo2 = () => { + const tokenList = ['rgb(0 0 0 / 45%)', '#006AFF', '#f3f6fc']; + return ( +
+ + + +
+ ); +}; + +export { Demo1, Demo2 }; diff --git a/packages/codemod/transforms/__testfixtures__/style-to-token/function-component.output.js b/packages/codemod/transforms/__testfixtures__/style-to-token/function-component.output.js index ae44027d7..16e0ac2ed 100644 --- a/packages/codemod/transforms/__testfixtures__/style-to-token/function-component.output.js +++ b/packages/codemod/transforms/__testfixtures__/style-to-token/function-component.output.js @@ -1,7 +1,7 @@ import React from 'react'; import { Alert, Button, theme, Tooltip } from '@oceanbase/design'; -const Demo = () => { +function Demo1() { const { token } = theme.useToken(); const tokenList = [token.colorTextTertiary, token.colorInfo, token.colorBgLayout]; return ( @@ -13,4 +13,16 @@ const Demo = () => { ); }; -export default Demo; +const Demo2 = () => { + const { token } = theme.useToken(); + const tokenList = [token.colorTextTertiary, token.colorInfo, token.colorBgLayout]; + return ( + (
+ + + +
) + ); +}; + +export { Demo1, Demo2 }; diff --git a/packages/codemod/transforms/__testfixtures__/style-to-token/function.input.js b/packages/codemod/transforms/__testfixtures__/style-to-token/function.input.js new file mode 100644 index 000000000..8d0f8c9f3 --- /dev/null +++ b/packages/codemod/transforms/__testfixtures__/style-to-token/function.input.js @@ -0,0 +1,37 @@ +import React from 'react'; +import { Alert, Button, Tooltip } from '@oceanbase/design'; + +function getComponent1() { + const tokenList = ['rgb(0 0 0 / 45%)', '#006AFF', '#f3f6fc']; + return ( +
+ + + +
+ ); +}; + +const getComponent2 = () => { + const tokenList = ['rgb(0 0 0 / 45%)', '#006AFF', '#f3f6fc']; + return ( +
+ + + +
+ ); +}; + +export default () => { + const tokenList = ['rgb(0 0 0 / 45%)', '#006AFF', '#f3f6fc']; + return ( +
+ + + +
+ ); +}; + +export { getComponent1, getComponent2 }; diff --git a/packages/codemod/transforms/__testfixtures__/style-to-token/function.output.js b/packages/codemod/transforms/__testfixtures__/style-to-token/function.output.js new file mode 100644 index 000000000..b3101371e --- /dev/null +++ b/packages/codemod/transforms/__testfixtures__/style-to-token/function.output.js @@ -0,0 +1,37 @@ +import React from 'react'; +import { Alert, Button, token, Tooltip } from '@oceanbase/design'; + +function getComponent1() { + const tokenList = [token.colorTextTertiary, token.colorInfo, token.colorBgLayout]; + return ( + (
+ + + +
) + ); +}; + +const getComponent2 = () => { + const tokenList = [token.colorTextTertiary, token.colorInfo, token.colorBgLayout]; + return ( + (
+ + + +
) + ); +}; + +export default () => { + const tokenList = [token.colorTextTertiary, token.colorInfo, token.colorBgLayout]; + return ( + (
+ + + +
) + ); +}; + +export { getComponent1, getComponent2 }; diff --git a/packages/codemod/transforms/__testfixtures__/style-to-token/hooks.input.js b/packages/codemod/transforms/__testfixtures__/style-to-token/hooks.input.js new file mode 100644 index 000000000..c9bc63d51 --- /dev/null +++ b/packages/codemod/transforms/__testfixtures__/style-to-token/hooks.input.js @@ -0,0 +1,26 @@ +import React from 'react'; +import { Alert, Button, Tooltip } from '@oceanbase/design'; + +function useComponent1 () { + const tokenList = ['rgb(0 0 0 / 45%)', '#006AFF', '#f3f6fc']; + return ( +
+ + + +
+ ); +}; + +const useComponent2 = () => { + const tokenList = ['rgb(0 0 0 / 45%)', '#006AFF', '#f3f6fc']; + return ( +
+ + + +
+ ); +}; + +export { useComponent1, useComponent2 }; diff --git a/packages/codemod/transforms/__testfixtures__/style-to-token/hooks.output.js b/packages/codemod/transforms/__testfixtures__/style-to-token/hooks.output.js new file mode 100644 index 000000000..a0e5c5251 --- /dev/null +++ b/packages/codemod/transforms/__testfixtures__/style-to-token/hooks.output.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { Alert, Button, theme, Tooltip } from '@oceanbase/design'; + +function useComponent1 () { + const { token } = theme.useToken(); + const tokenList = [token.colorTextTertiary, token.colorInfo, token.colorBgLayout]; + return ( + (
+ + + +
) + ); +}; + +const useComponent2 = () => { + const { token } = theme.useToken(); + const tokenList = [token.colorTextTertiary, token.colorInfo, token.colorBgLayout]; + return ( + (
+ + + +
) + ); +}; + +export { useComponent1, useComponent2 }; diff --git a/packages/codemod/transforms/__tests__/style-to-token.test.ts b/packages/codemod/transforms/__tests__/style-to-token.test.ts index d87d1bb4e..bd66228e3 100644 --- a/packages/codemod/transforms/__tests__/style-to-token.test.ts +++ b/packages/codemod/transforms/__tests__/style-to-token.test.ts @@ -3,6 +3,8 @@ import { defineTest } from 'jscodeshift/src/testUtils'; const testUnit = 'style-to-token'; const tests = [ 'function-component', + 'function', + 'hooks', 'class-component', 'block-statement', 'nested-block-statement', diff --git a/packages/codemod/transforms/style-to-token.js b/packages/codemod/transforms/style-to-token.js index be6585a7e..c0e801340 100644 --- a/packages/codemod/transforms/style-to-token.js +++ b/packages/codemod/transforms/style-to-token.js @@ -1,3 +1,4 @@ +const { upperFirst } = require('lodash'); const { addSubmoduleImport } = require('./utils'); const { tokenParse } = require('./utils/token'); const { printOptions } = require('./utils/config'); @@ -31,6 +32,10 @@ function isTopIdentifier(path) { return isTop; } +function isFirstUpperCase(str) { + return upperFirst(str) === str; +} + function importComponent(j, root, options) { let hasChanged = false; @@ -72,14 +77,24 @@ function importComponent(j, root, options) { name: name => name.includes('useToken'), }).length > 0; const parentType = path.parentPath.value?.type; - // React function component - if (includeJSXElement && parentType !== 'ClassMethod') { + const functionName = + parentType === 'FunctionDeclaration' + ? path.parentPath.value?.id?.name + : parentType === 'ArrowFunctionExpression' + ? path.parentPath.parentPath?.value?.id?.name + : undefined; + if ( + includeJSXElement && + functionName && + // React function component or React hooks + (isFirstUpperCase(functionName) || functionName.startsWith('use')) + ) { // avoid duplicate insert when it's existed if (!includeUseTokenStatement) { const insertString = 'const { token } = theme.useToken()'; // insert `const { token } = theme.useToken()` path.get('body').value.unshift(j.expressionStatement(j.identifier(insertString))); - // import theme from @oceanbase/design + // import `theme` from @oceanbase/design addSubmoduleImport(j, root, { moduleName: '@oceanbase/design', importedName: 'theme', @@ -88,7 +103,7 @@ function importComponent(j, root, options) { } } else { // React class component and static file (not react component) - // import token from @oceanbase/design + // import `token` from @oceanbase/design addSubmoduleImport(j, root, { moduleName: '@oceanbase/design', importedName: 'token', @@ -102,7 +117,7 @@ function importComponent(j, root, options) { .find(j.Identifier) .filter(path => isTopIdentifier(path) && path.value.name?.includes('token.')) .forEach(() => { - // import token from @oceanbase/design + // import `token` from @oceanbase/design addSubmoduleImport(j, root, { moduleName: '@oceanbase/design', importedName: 'token',