@oceanbase/codemod 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +149 -2
  2. package/bin/cli.js +14 -9
  3. package/package.json +8 -6
  4. package/transforms/__testfixtures__/less-to-token/antd-v4-less-to-token.input.less +13 -0
  5. package/transforms/__testfixtures__/less-to-token/antd-v4-less-to-token.output.less +14 -0
  6. package/transforms/__testfixtures__/less-to-token/case-insensitive.input.less +13 -0
  7. package/transforms/__testfixtures__/less-to-token/case-insensitive.output.less +14 -0
  8. package/transforms/__testfixtures__/less-to-token/obui-less-to-token.input.less +14 -0
  9. package/transforms/__testfixtures__/less-to-token/obui-less-to-token.output.less +13 -0
  10. package/transforms/__testfixtures__/style-to-token/block-statement.input.js +24 -0
  11. package/transforms/__testfixtures__/style-to-token/block-statement.output.js +25 -0
  12. package/transforms/__testfixtures__/style-to-token/case-insensitive.input.js +10 -0
  13. package/transforms/__testfixtures__/style-to-token/case-insensitive.output.js +11 -0
  14. package/transforms/__testfixtures__/style-to-token/class-component.input.js +20 -0
  15. package/transforms/__testfixtures__/style-to-token/class-component.output.js +20 -0
  16. package/transforms/__testfixtures__/style-to-token/existed-useToken.input.js +15 -0
  17. package/transforms/__testfixtures__/style-to-token/existed-useToken.output.js +15 -0
  18. package/transforms/__testfixtures__/style-to-token/function-component.input.js +14 -0
  19. package/transforms/__testfixtures__/style-to-token/function-component.output.js +15 -0
  20. package/transforms/__testfixtures__/style-to-token/nested-block-statement.input.js +18 -0
  21. package/transforms/__testfixtures__/style-to-token/nested-block-statement.output.js +19 -0
  22. package/transforms/__testfixtures__/style-to-token/top-identifier.input.js +10 -0
  23. package/transforms/__testfixtures__/style-to-token/top-identifier.output.js +11 -0
  24. package/transforms/__tests__/less-to-token.test.ts +21 -0
  25. package/transforms/__tests__/style-to-token.test.ts +18 -0
  26. package/transforms/__tests__/token.test.ts +11 -0
  27. package/transforms/less-to-token.js +87 -0
  28. package/transforms/style-to-token.js +125 -0
  29. package/transforms/utils/index.js +1 -1
  30. package/transforms/utils/token.js +114 -0
package/README.md CHANGED
@@ -1,8 +1,12 @@
1
1
  # OceanBase Codemod
2
2
 
3
- A collection of codemod scripts that help migrate to OceanBase Design using [jscodeshift](https://github.com/facebook/jscodeshift) and [postcss](https://github.com/postcss/postcss).(Inspired by [@oceanbase/codemod](https://github.com/ant-design/codemod-v5))
3
+ A collection of codemod scripts that help migrate from `antd`, `@alipay/ob-ui`, `@alipay/tech-ui`, `@ant-design/pro-components` and `@ant-design/charts` to OceanBase Design System by using [jscodeshift](https://github.com/facebook/jscodeshift) and [postcss](https://github.com/postcss/postcss). (Inspired by [@ant-design/codemod-v5](https://github.com/ant-design/codemod-v5))
4
4
 
5
- [![NPM version](https://img.shields.io/npm/v/@oceanbase/codemod.svg?style=flat)](https://npmjs.org/package/@oceanbase/codemod) [![NPM downloads](http://img.shields.io/npm/dm/@oceanbase/codemod.svg?style=flat)](https://npmjs.org/package/@oceanbase/codemod) [![Github Action](https://github.com/oceanbase/design/actions/workflows/ci.yml/badge.svg)](https://github.com/oceanbase/design/actions/workflows/ci.yml)
5
+ [![NPM version](https://img.shields.io/npm/v/@oceanbase/codemod.svg?style=flat)](https://npmjs.org/package/@oceanbase/codemod) [![NPM downloads](http://img.shields.io/npm/dm/@oceanbase/codemod.svg?style=flat)](https://npmjs.org/package/@oceanbase/codemod) [![Github Action](https://github.com/oceanbase/oceanbase-design/actions/workflows/ci.yml/badge.svg)](https://github.com/oceanbase/oceanbase-design/actions/workflows/ci.yml)
6
+
7
+ ## Prerequisite
8
+
9
+ - `antd v5` is the prerequisite. If you are using `antd v4`, please refer to [Upgrade Guideline](https://ant-design.antgroup.com/docs/react/migration-v5).
6
10
 
7
11
  ## Usage
8
12
 
@@ -10,7 +14,10 @@ Before run codemod scripts, you'd better make sure to commit your local git chan
10
14
 
11
15
  ```shell
12
16
  # Run directly through npx
17
+ # `src` is the target directory or file that you want to transform.
13
18
  npx -p @oceanbase/codemod codemod src
19
+ # options
20
+ # --disablePrettier // disable prettier
14
21
  ```
15
22
 
16
23
  ## Codemod scripts introduction
@@ -133,3 +140,143 @@ import utils and hooks from `@alipay/ob-util` to `@oceanbase/util`. Additionally
133
140
 
134
141
  export default Demo;
135
142
  ```
143
+
144
+ ### `style-to-token`
145
+
146
+ transform fixed style to antd v5 design token.
147
+
148
+ - React function components:
149
+
150
+ ```diff
151
+ import React from 'react';
152
+ - import { Alert, Button } from '@oceanbase/design';
153
+ + import { Alert, Button, theme } from '@oceanbase/design';
154
+
155
+ const Demo = () => {
156
+ + const { token } = theme.useToken();
157
+ return (
158
+ - <div>
159
+ - <Alert style={{ color: 'rgba(0, 0, 0, 0.85)', background: 'rgba(0, 0, 0,0.65)', backgroundColor: 'rgba(0,0,0,0.45)', border: '1px solid #d9d9d9' }} />
160
+ - <Button style={{ color: '#1890ff', background: '#52c41a', backgroundColor: '#faad14', borderColor: '#ff4d4f' }}></Button>
161
+ - </div>
162
+ + (<div>
163
+ + <Alert style={{ color: token.colorText, background: token.colorTextSecondary, backgroundColor: token.colorTextTertiary, border: `1px solid ${token.colorBorder}` }} />
164
+ + <Button style={{ color: token.colorInfo, background: token.colorSuccess, backgroundColor: token.colorWarning, borderColor: token.colorError }}></Button>
165
+ + </div>)
166
+ );
167
+ };
168
+
169
+ export default Demo;
170
+ ```
171
+
172
+ - React class components:
173
+
174
+ ```diff
175
+ import React from 'react';
176
+ - import { Alert, Button } from '@oceanbase/design';
177
+ + import { Alert, Button, token } from '@oceanbase/design';
178
+
179
+ class Demo extends React.PureComponent {
180
+ constructor(props) {
181
+ super(props);
182
+ this.state = {};
183
+ }
184
+
185
+ render() {
186
+ return (
187
+ - <div>
188
+ - <Alert style={{ color: 'rgba(0, 0, 0, 0.85)', background: 'rgba(0, 0, 0,0.65)', backgroundColor: 'rgba(0,0,0,0.45)', border: '#d9d9d9' }} />
189
+ - <Button style={{ color: '#1890ff', background: '#52c41a', backgroundColor: '#faad14', borderColor: '#ff4d4f' }}></Button>
190
+ - <div color="#fafafa" border="1px solid #fafafa" />
191
+ - </div>
192
+ + (<div>
193
+ + <Alert style={{ color: token.colorText, background: token.colorTextSecondary, backgroundColor: token.colorTextTertiary, border: `1px solid ${token.colorBgLayout}` }} />
194
+ + <Button style={{ color: token.colorInfo, background: token.colorSuccess, backgroundColor: token.colorWarning, borderColor: token.colorError }}></Button>
195
+ + <div color={token.colorBgLayout} border={`1px solid ${token.colorBgLayout}`} />
196
+ + </div>)
197
+ );
198
+ }
199
+ }
200
+
201
+ export default Demo;
202
+ ```
203
+
204
+ - Static file (not react components):
205
+
206
+ ```diff
207
+ + import { token } from '@oceanbase/design';
208
+ - const color = '#fafafa';
209
+ - const border = '1px solid #fafafa';
210
+ + const color = token.colorBgLayout;
211
+ + const border = `1px solid ${token.colorBgLayout}`;
212
+ const colorMap = {
213
+ - info: '#1890ff',
214
+ - success: '#52c41a',
215
+ - warning: '#faad14',
216
+ - error: '#ff4d4f',
217
+ - border: '1px solid #d9d9d9',
218
+ + info: token.colorInfo,
219
+ + success: token.colorSuccess,
220
+ + warning: token.colorWarning,
221
+ + error: token.colorError,
222
+ + border: `1px solid ${token.colorBorder}`,
223
+ };
224
+
225
+ function getColorList() {
226
+ return [
227
+ {
228
+ type: 'info',
229
+ - color: '#1890ff',
230
+ + color: token.colorInfo,
231
+ },
232
+ {
233
+ type: 'success',
234
+ - color: '#52c41a',
235
+ + color: token.colorSuccess,
236
+ },
237
+ {
238
+ type: 'warning',
239
+ - color: '#faad14',
240
+ + color: token.colorWarning,
241
+ },
242
+ {
243
+ type: 'error',
244
+ - color: '#ff4d4f',
245
+ + color: token.colorError,
246
+ },
247
+ {
248
+ type: 'border',
249
+ - color: '1px solid #d9d9d9',
250
+ + color: `1px solid ${token.colorBorder}`,
251
+ },
252
+ ];
253
+ }
254
+ ```
255
+
256
+ ### `less-to-token`
257
+
258
+ transform fixed less style to antd v5 design token.
259
+
260
+ ```diff
261
+ + @import '~@oceanbase/design/es/theme/index.less';
262
+ .container {
263
+ - color: #1890ff;
264
+ - background: #52c41a;
265
+ - background-color: #faad14;
266
+ - border-color: #ff4d4f;
267
+ + color: @colorInfo;
268
+ + background: @colorSuccess;
269
+ + background-color: @colorWarning;
270
+ + border-color: @colorError;
271
+ .content {
272
+ - color: rgba(0, 0, 0, 0.85);
273
+ - background: rgba(0, 0, 0,0.65);
274
+ - background-color: rgba(0,0,0,0.45);
275
+ - border: 1px solid #d9d9d9;
276
+ + color: @colorText;
277
+ + background: @colorTextSecondary;
278
+ + background-color: @colorTextTertiary;
279
+ + border: 1px solid @colorBorder;
280
+ }
281
+ }
282
+ ```
package/bin/cli.js CHANGED
@@ -8,7 +8,6 @@ const _ = require('lodash');
8
8
  const chalk = require('chalk');
9
9
  const isGitClean = require('is-git-clean');
10
10
  const updateCheck = require('update-check');
11
- const findUp = require('find-up');
12
11
  const semver = require('semver');
13
12
  const { run: jscodeshift } = require('jscodeshift/src/Runner');
14
13
  const execa = require('execa');
@@ -18,6 +17,7 @@ const commandExistsSync = require('command-exists').sync;
18
17
  const pkg = require('../package.json');
19
18
  const pkgUpgradeList = require('./upgrade-list');
20
19
  const { getDependencies } = require('../transforms/utils/marker');
20
+ const { lessToToken } = require('../transforms/less-to-token');
21
21
 
22
22
  // jscodeshift codemod scripts dir
23
23
  const transformersDir = path.join(__dirname, '../transforms');
@@ -31,6 +31,8 @@ const transformers = [
31
31
  'obui-to-oceanbase-design-and-ui',
32
32
  'obutil-to-oceanbase-util',
33
33
  'page-container-to-oceanbase-ui',
34
+ 'style-to-token',
35
+ 'less-to-token',
34
36
  ];
35
37
 
36
38
  const dependencyProperties = [
@@ -89,7 +91,7 @@ function getRunnerArgs(transformerPath, parser = 'babylon', options = {}) {
89
91
  // override default babylon parser config to enable `decorator-legacy`
90
92
  // https://github.com/facebook/jscodeshift/blob/master/parser/babylon.js
91
93
  parserConfig: require('./babylon.config.json'),
92
- extensions: ['js', 'jsx', 'ts', 'tsx', 'd.ts'].join(','),
94
+ extensions: ['js', 'jsx', 'ts', 'tsx'].join(','),
93
95
  transform: transformerPath,
94
96
  ignorePattern: '**/node_modules',
95
97
  ignoreConfig,
@@ -113,12 +115,15 @@ async function transform(transformer, parser, filePath, options) {
113
115
  });
114
116
 
115
117
  try {
116
- if (process.env.NODE_ENV === 'local') {
117
- console.log(`Running jscodeshift with: ${JSON.stringify(args)}`);
118
+ if (transformer === 'less-to-token') {
119
+ await lessToToken(filePath);
120
+ } else {
121
+ if (process.env.NODE_ENV === 'local') {
122
+ console.log(`Running jscodeshift with: ${JSON.stringify(args)}`);
123
+ }
124
+ // js part
125
+ await jscodeshift(transformerPath, [filePath], args);
118
126
  }
119
-
120
- // js part
121
- await jscodeshift(transformerPath, [filePath], args);
122
127
  console.log();
123
128
  } catch (err) {
124
129
  console.error(err);
@@ -286,9 +291,9 @@ async function bootstrap() {
286
291
  console.log('[Prettier] format files running...');
287
292
  try {
288
293
  const isDir = isDirectory.sync(dir);
289
- const path = isDir ? '**/*.{js,jsx,tsx,ts,d.ts}' : dir;
294
+ const targetPath = isDir ? path.join(dir, '**/*.{js,jsx,ts,tsx}') : dir;
290
295
  const npxCommand = commandExistsSync('tnpx') ? 'tnpx' : 'npx';
291
- await execa(npxCommand, ['prettier', '--write', path], { stdio: 'inherit' });
296
+ await execa(npxCommand, ['prettier', '--write', targetPath], { stdio: 'inherit' });
292
297
  console.log('\n[Prettier] format files completed!\n');
293
298
  } catch (err) {
294
299
  console.log('\n[Prettier] format files failed, please format it by yourself.\n', err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oceanbase/codemod",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Codemod for OceanBase Design upgrade",
5
5
  "keywords": [
6
6
  "oceanbase",
@@ -10,7 +10,7 @@
10
10
  "homepage": "https://github.com/oceanbase/oceanbase-design/packages/codemod",
11
11
  "repository": {
12
12
  "type": "git",
13
- "url": "git@github.com:oceanbase/design.git"
13
+ "url": "git@github.com:oceanbase/oceanbase-design.git"
14
14
  },
15
15
  "publishConfig": {
16
16
  "registry": "https://registry.npmjs.org",
@@ -26,23 +26,25 @@
26
26
  "chalk": "^3.0.0",
27
27
  "command-exists": "^1.2.9",
28
28
  "execa": "^5.1.1",
29
- "find-up": "^4.1.0",
29
+ "find-up": "^6.3.0",
30
30
  "glob": "^10.3.10",
31
31
  "is-directory": "^0.3.1",
32
32
  "is-git-clean": "^1.1.0",
33
33
  "jscodeshift": "^0.15.0",
34
34
  "lodash": "^4.17.21",
35
+ "postcss": "^8.4.31",
36
+ "postcss-less": "^6.0.0",
35
37
  "prettier": "^3.0.3",
36
- "read-pkg-up": "^9.1.0",
38
+ "read-pkg-up": "^10.1.0",
37
39
  "semver": "^7.5.4",
38
40
  "update-check": "^1.5.4",
39
41
  "yargs-parser": "^21.1.1"
40
42
  },
41
43
  "devDependencies": {
42
- "@types/jest": "^29.5.5",
44
+ "@types/jest": "^29.5.6",
43
45
  "@types/jscodeshift": "^0.11.7",
44
46
  "enzyme": "^3.11.0",
45
47
  "enzyme-to-json": "^3.6.2"
46
48
  },
47
- "gitHead": "1138341df7a35d3d4939ccea79225ddf220de2cc"
49
+ "gitHead": "98cd4d8a2af9b6e5dcde6210fc61f9efb74c7e01"
48
50
  }
@@ -0,0 +1,13 @@
1
+ .container {
2
+ color: #1890ff;
3
+ background: #52c41a;
4
+ background-color: #faad14;
5
+ border-color: #ff4d4f;
6
+ scrollbar-color: #ffffff;
7
+ .content {
8
+ color: rgba(0, 0, 0, 0.85);
9
+ background: rgba(0, 0, 0,0.65);
10
+ background-color: rgba(0,0,0,0.45);
11
+ border: 1px solid #d9d9d9;
12
+ }
13
+ }
@@ -0,0 +1,14 @@
1
+ @import '~@oceanbase/design/es/theme/index.less';
2
+ .container {
3
+ color: @colorInfo;
4
+ background: @colorSuccess;
5
+ background-color: @colorWarning;
6
+ border-color: @colorError;
7
+ scrollbar-color: @colorBgContainer;
8
+ .content {
9
+ color: @colorText;
10
+ background: @colorTextSecondary;
11
+ background-color: @colorTextTertiary;
12
+ border: 1px solid @colorBorder;
13
+ }
14
+ }
@@ -0,0 +1,13 @@
1
+ .container {
2
+ color: #1890FF;
3
+ background: #52C41A;
4
+ background-color: #FAAD14;
5
+ border-color: #FF4D4F;
6
+ scrollbar-color: #FFFFFF;
7
+ .content {
8
+ color: rgba(0, 0, 0, 0.85);
9
+ background: rgba(0, 0, 0,0.65);
10
+ background-color: rgba(0,0,0,0.45);
11
+ border: 1px solid #D9D9D9;
12
+ }
13
+ }
@@ -0,0 +1,14 @@
1
+ @import '~@oceanbase/design/es/theme/index.less';
2
+ .container {
3
+ color: @colorInfo;
4
+ background: @colorSuccess;
5
+ background-color: @colorWarning;
6
+ border-color: @colorError;
7
+ scrollbar-color: @colorBgContainer;
8
+ .content {
9
+ color: @colorText;
10
+ background: @colorTextSecondary;
11
+ background-color: @colorTextTertiary;
12
+ border: 1px solid @colorBorder;
13
+ }
14
+ }
@@ -0,0 +1,14 @@
1
+ @import '~@alipay/ob-ui/es/theme/index.less';
2
+
3
+ .container {
4
+ color: @colorInfo;
5
+ background: @colorSuccess;
6
+ background-color: @colorWarning;
7
+ border-color: @colorError;
8
+ .content {
9
+ color: rgba(0, 0, 0, 0.85);
10
+ background: rgba(0, 0, 0,0.65);
11
+ background-color: rgba(0,0,0,0.45);
12
+ border: 1px solid #d9d9d9;
13
+ }
14
+ }
@@ -0,0 +1,13 @@
1
+ @import '~@oceanbase/design/es/theme/index.less';
2
+ .container {
3
+ color: @colorInfo;
4
+ background: @colorSuccess;
5
+ background-color: @colorWarning;
6
+ border-color: @colorError;
7
+ .content {
8
+ color: @colorText;
9
+ background: @colorTextSecondary;
10
+ background-color: @colorTextTertiary;
11
+ border: 1px solid @colorBorder;
12
+ }
13
+ }
@@ -0,0 +1,24 @@
1
+ function getColorList() {
2
+ return [
3
+ {
4
+ type: 'info',
5
+ color: '#1890ff',
6
+ },
7
+ {
8
+ type: 'success',
9
+ color: '#52c41a',
10
+ },
11
+ {
12
+ type: 'warning',
13
+ color: '#faad14',
14
+ },
15
+ {
16
+ type: 'error',
17
+ color: '#ff4D4F',
18
+ },
19
+ {
20
+ type: 'border',
21
+ color: '1px solid #d9d9d9',
22
+ },
23
+ ];
24
+ }
@@ -0,0 +1,25 @@
1
+ import { token } from '@oceanbase/design';
2
+ function getColorList() {
3
+ return [
4
+ {
5
+ type: 'info',
6
+ color: token.colorInfo,
7
+ },
8
+ {
9
+ type: 'success',
10
+ color: token.colorSuccess,
11
+ },
12
+ {
13
+ type: 'warning',
14
+ color: token.colorWarning,
15
+ },
16
+ {
17
+ type: 'error',
18
+ color: token.colorError,
19
+ },
20
+ {
21
+ type: 'border',
22
+ color: `1px solid ${token.colorBorder}`,
23
+ },
24
+ ];
25
+ }
@@ -0,0 +1,10 @@
1
+ const color = '#FAFAFA';
2
+ const border = '1px solid #FAFAFA';
3
+
4
+ const colorMap = {
5
+ info: '#1890FF',
6
+ success: '#52C41A',
7
+ warning: '#FAAD14',
8
+ error: '#FF4D4F',
9
+ border: '1px solid #D9D9D9',
10
+ };
@@ -0,0 +1,11 @@
1
+ import { token } from '@oceanbase/design';
2
+ const color = token.colorBgLayout;
3
+ const border = `1px solid ${token.colorBgLayout}`;
4
+
5
+ const colorMap = {
6
+ info: token.colorInfo,
7
+ success: token.colorSuccess,
8
+ warning: token.colorWarning,
9
+ error: token.colorError,
10
+ border: `1px solid ${token.colorBorder}`,
11
+ };
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { Alert, Button } from '@oceanbase/design';
3
+
4
+ class Demo extends React.PureComponent {
5
+ constructor(props) {
6
+ super(props);
7
+ this.state = {};
8
+ }
9
+
10
+ render() {
11
+ return (
12
+ <div>
13
+ <Alert style={{ color: 'rgba(0, 0, 0, 0.85)', background: 'rgba(0, 0, 0,0.65)', backgroundColor: 'rgba(0,0,0,0.45)', border: '1px solid #d9d9d9' }} />
14
+ <Button style={{ color: '#1890ff', background: '#52c41a', backgroundColor: '#faad14', borderColor: '#ff4D4F' }}></Button>
15
+ </div>
16
+ );
17
+ }
18
+ }
19
+
20
+ export default Demo;
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { Alert, Button, token } from '@oceanbase/design';
3
+
4
+ class Demo extends React.PureComponent {
5
+ constructor(props) {
6
+ super(props);
7
+ this.state = {};
8
+ }
9
+
10
+ render() {
11
+ return (
12
+ (<div>
13
+ <Alert style={{ color: token.colorText, background: token.colorTextSecondary, backgroundColor: token.colorTextTertiary, border: `1px solid ${token.colorBorder}` }} />
14
+ <Button style={{ color: token.colorInfo, background: token.colorSuccess, backgroundColor: token.colorWarning, borderColor: token.colorError }}></Button>
15
+ </div>)
16
+ );
17
+ }
18
+ }
19
+
20
+ export default Demo;
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { Alert, Button, theme, Tooltip } from '@oceanbase/design';
3
+
4
+ const Demo = () => {
5
+ const { token } = theme.useToken();
6
+ return (
7
+ <div>
8
+ <Alert style={{ color: 'rgba(0, 0, 0, 0.85)', background: 'rgba(0, 0, 0,0.65)', backgroundColor: 'rgba(0,0,0,0.45)', border: '1px solid #d9d9d9' }} />
9
+ <Button style={{ color: '#1890ff', background: '#52c41a', backgroundColor: '#faad14', borderColor: '#ff4D4F' }}></Button>
10
+ <Tooltip color="#ffffff" backgroundColor="#fff1f0" borderColor="#fafafa" border="1px solid #fafafa" />
11
+ </div>
12
+ );
13
+ };
14
+
15
+ export default Demo;
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { Alert, Button, theme, Tooltip } from '@oceanbase/design';
3
+
4
+ const Demo = () => {
5
+ const { token } = theme.useToken();
6
+ return (
7
+ (<div>
8
+ <Alert style={{ color: token.colorText, background: token.colorTextSecondary, backgroundColor: token.colorTextTertiary, border: `1px solid ${token.colorBorder}` }} />
9
+ <Button style={{ color: token.colorInfo, background: token.colorSuccess, backgroundColor: token.colorWarning, borderColor: token.colorError }}></Button>
10
+ <Tooltip color={token.colorBgContainer} backgroundColor={token.colorErrorBg} borderColor={token.colorBgLayout} border={`1px solid ${token.colorBgLayout}`} />
11
+ </div>)
12
+ );
13
+ };
14
+
15
+ export default Demo;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { Alert, Button, Tooltip } from '@oceanbase/design';
3
+
4
+ const Demo = () => {
5
+ return (
6
+ <div>
7
+ <Alert style={{ color: 'rgba(0, 0, 0, 0.85)', background: 'rgba(0, 0, 0,0.65)', backgroundColor: 'rgba(0,0,0,0.45)', border: '1px solid #d9d9d9' }} />
8
+ <Button style={{ color: '#1890ff', background: '#52c41a', backgroundColor: '#faad14', borderColor: '#ff4D4F' }}></Button>
9
+ <Tooltip color="#ffffff" backgroundColor="#fff1f0" borderColor="#fafafa" border="1px solid #fafafa" />
10
+ </div>
11
+ );
12
+ };
13
+
14
+ export default Demo;
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { Alert, Button, theme, Tooltip } from '@oceanbase/design';
3
+
4
+ const Demo = () => {
5
+ const { token } = theme.useToken();
6
+ return (
7
+ (<div>
8
+ <Alert style={{ color: token.colorText, background: token.colorTextSecondary, backgroundColor: token.colorTextTertiary, border: `1px solid ${token.colorBorder}` }} />
9
+ <Button style={{ color: token.colorInfo, background: token.colorSuccess, backgroundColor: token.colorWarning, borderColor: token.colorError }}></Button>
10
+ <Tooltip color={token.colorBgContainer} backgroundColor={token.colorErrorBg} borderColor={token.colorBgLayout} border={`1px solid ${token.colorBgLayout}`} />
11
+ </div>)
12
+ );
13
+ };
14
+
15
+ export default Demo;
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { Alert, Button, Tooltip } from '@oceanbase/design';
3
+
4
+ const Demo = () => {
5
+ const columns = [{
6
+ render: () => {
7
+ return <Tooltip color="#ffffff" backgroundColor="#fff1f0" borderColor="#fafafa" border="1px solid #fafafa" />;
8
+ },
9
+ }];
10
+ return (
11
+ <div>
12
+ <Alert style={{ color: 'rgba(0, 0, 0, 0.85)', background: 'rgba(0, 0, 0,0.65)', backgroundColor: 'rgba(0,0,0,0.45)', border: '1px solid #d9d9d9' }} />
13
+ <Button style={{ color: '#1890ff', background: '#52c41a', backgroundColor: '#faad14', borderColor: '#ff4D4F' }}></Button>
14
+ </div>
15
+ );
16
+ };
17
+
18
+ export default Demo;
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { Alert, Button, theme, Tooltip } from '@oceanbase/design';
3
+
4
+ const Demo = () => {
5
+ const { token } = theme.useToken();
6
+ const columns = [{
7
+ render: () => {
8
+ return <Tooltip color={token.colorBgContainer} backgroundColor={token.colorErrorBg} borderColor={token.colorBgLayout} border={`1px solid ${token.colorBgLayout}`} />;
9
+ },
10
+ }];
11
+ return (
12
+ (<div>
13
+ <Alert style={{ color: token.colorText, background: token.colorTextSecondary, backgroundColor: token.colorTextTertiary, border: `1px solid ${token.colorBorder}` }} />
14
+ <Button style={{ color: token.colorInfo, background: token.colorSuccess, backgroundColor: token.colorWarning, borderColor: token.colorError }}></Button>
15
+ </div>)
16
+ );
17
+ };
18
+
19
+ export default Demo;
@@ -0,0 +1,10 @@
1
+ const color = '#fafafa';
2
+ const border = '1px solid #fafafa';
3
+
4
+ const colorMap = {
5
+ info: '#1890ff',
6
+ success: '#52c41a',
7
+ warning: '#faad14',
8
+ error: '#ff4d4f',
9
+ border: '1px solid #d9d9d9',
10
+ };
@@ -0,0 +1,11 @@
1
+ import { token } from '@oceanbase/design';
2
+ const color = token.colorBgLayout;
3
+ const border = `1px solid ${token.colorBgLayout}`;
4
+
5
+ const colorMap = {
6
+ info: token.colorInfo,
7
+ success: token.colorSuccess,
8
+ warning: token.colorWarning,
9
+ error: token.colorError,
10
+ border: `1px solid ${token.colorBorder}`,
11
+ };
@@ -0,0 +1,21 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { transform } from '../less-to-token';
4
+
5
+ const testUnit = 'less-to-token';
6
+ const tests = ['antd-v4-less-to-token', 'obui-less-to-token', 'case-insensitive'];
7
+
8
+ describe(testUnit, () => {
9
+ tests.forEach(test => {
10
+ it(test, async () => {
11
+ const result = await transform(
12
+ path.join(__dirname, `../__testfixtures__/less-to-token/${test}.input.less`)
13
+ );
14
+ const output = fs.readFileSync(
15
+ path.join(__dirname, `../__testfixtures__/less-to-token/${test}.output.less`),
16
+ 'utf-8'
17
+ );
18
+ expect(result).toEqual(output);
19
+ });
20
+ });
21
+ });
@@ -0,0 +1,18 @@
1
+ import { defineTest } from 'jscodeshift/src/testUtils';
2
+
3
+ const testUnit = 'style-to-token';
4
+ const tests = [
5
+ 'function-component',
6
+ 'class-component',
7
+ 'block-statement',
8
+ 'nested-block-statement',
9
+ 'existed-useToken',
10
+ 'top-identifier',
11
+ 'case-insensitive',
12
+ ];
13
+
14
+ describe(testUnit, () => {
15
+ tests.forEach(test =>
16
+ defineTest(__dirname, testUnit, {}, `${testUnit}/${test}`, { parser: 'babylon' })
17
+ );
18
+ });
@@ -0,0 +1,11 @@
1
+ import { TOKEN_MAP_KEYS, isLower } from '../utils/token';
2
+
3
+ describe('token', () => {
4
+ it('TOKEN_MAP_KEYS should be lower case', async () => {
5
+ expect(TOKEN_MAP_KEYS.every(key => isLower(key))).toEqual(true);
6
+ });
7
+
8
+ it('TOKEN_MAP_KEYS should not include blank space', async () => {
9
+ expect(TOKEN_MAP_KEYS.every(key => !key.includes(' '))).toEqual(true);
10
+ });
11
+ });
@@ -0,0 +1,87 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+ const postcss = require('postcss');
4
+ const postcssLess = require('postcss-less');
5
+ const isDirectory = require('is-directory');
6
+ const { tokenParse } = require('./utils/token');
7
+
8
+ /**
9
+ * 搜索目录下所有的less文件
10
+ * @param dir
11
+ * @returns
12
+ */
13
+ const findAllLessFiles = dir => {
14
+ const lessFiles = [];
15
+ const isDir = isDirectory.sync(dir);
16
+ if (isDir) {
17
+ const files = fs.readdirSync(dir);
18
+ files.forEach(file => {
19
+ const filePath = path.join(dir, file);
20
+ if (isDirectory.sync(filePath)) {
21
+ if (filePath.includes('.umi') || filePath.includes('.umi-production')) {
22
+ return;
23
+ }
24
+ lessFiles.push(...findAllLessFiles(filePath));
25
+ } else if (file.endsWith('.less')) {
26
+ lessFiles.push(filePath);
27
+ }
28
+ });
29
+ } else if (dir.endsWith('.less')) {
30
+ lessFiles.push(dir);
31
+ }
32
+ return lessFiles;
33
+ };
34
+
35
+ /**
36
+ * 将 lesscode 转化为 ast
37
+ * @returns ASR
38
+ */
39
+ const less2AST = code =>
40
+ postcss([])
41
+ .process(code, {
42
+ parser: postcssLess.parse,
43
+ from: undefined,
44
+ })
45
+ .then(result => result.root);
46
+
47
+ async function transform(file) {
48
+ const content = fs.readFileSync(file, 'utf-8');
49
+ const ast = await less2AST(content);
50
+ let modified = false;
51
+ let tokenLessImported = false;
52
+ // 遍历 AST
53
+ ast.walk(node => {
54
+ const { key, token, formattedValue } = tokenParse(node.value);
55
+ if (node.type === 'decl' && token) {
56
+ node.value = formattedValue.replace(key, `@${token}`);
57
+ modified = true;
58
+ } else if (node.type === 'atrule' && node.name === 'import') {
59
+ if (node.params === "'~@oceanbase/design/es/theme/index.less'") {
60
+ tokenLessImported = true;
61
+ } else if (node.params === "'~@alipay/ob-ui/es/theme/index.less'") {
62
+ node.remove();
63
+ }
64
+ }
65
+ });
66
+ // prepend @import '~@oceanbase/design/es/theme/index.less';
67
+ if (modified && !tokenLessImported) {
68
+ ast.prepend({
69
+ name: 'import',
70
+ params: "'~@oceanbase/design/es/theme/index.less'",
71
+ });
72
+ }
73
+ return ast.toString();
74
+ }
75
+
76
+ async function lessToToken(file) {
77
+ const allLessFiles = findAllLessFiles(file);
78
+ for await (const item of allLessFiles) {
79
+ const content = await transform(item);
80
+ fs.writeFileSync(item, content);
81
+ }
82
+ }
83
+
84
+ module.exports = {
85
+ transform,
86
+ lessToToken,
87
+ };
@@ -0,0 +1,125 @@
1
+ const { addSubmoduleImport } = require('./utils');
2
+ const { tokenParse } = require('./utils/token');
3
+ const { printOptions } = require('./utils/config');
4
+
5
+ function isTopBlockStatement(path) {
6
+ const isBlockStatement = path.value.type === 'BlockStatement';
7
+ let isTop = isBlockStatement && true;
8
+ path = path.parentPath;
9
+ while (isTop && path.value.type !== 'Program') {
10
+ // isTopBlockStatement => not wrapped by BlockStatement
11
+ if (path.value.type === 'BlockStatement') {
12
+ isTop = false;
13
+ break;
14
+ }
15
+ path = path.parentPath;
16
+ }
17
+ return isTop;
18
+ }
19
+
20
+ function isTopIdentifier(path) {
21
+ let isTop = true;
22
+ path = path.parentPath;
23
+ while (isTop && path.value.type !== 'Program') {
24
+ // isTopIdentifier => not wrapped by BlockStatement
25
+ if (path.value.type === 'BlockStatement') {
26
+ isTop = false;
27
+ break;
28
+ }
29
+ path = path.parentPath;
30
+ }
31
+ return isTop;
32
+ }
33
+
34
+ function importComponent(j, root, options) {
35
+ let hasChanged = false;
36
+
37
+ const stringList = root.find(j.StringLiteral, {
38
+ value: value => {
39
+ const { token } = tokenParse(value);
40
+ return !!token;
41
+ },
42
+ });
43
+ if (stringList.length > 0) {
44
+ // replace fixed style to token
45
+ stringList.replaceWith(path => {
46
+ hasChanged = true;
47
+ const { key, token, formattedValue } = tokenParse(path.value.value);
48
+ const isJSXAttribute = path.parentPath.value.type === 'JSXAttribute';
49
+ let stringValue = `token.${token}`;
50
+ let templateStringValue = `\`${formattedValue.replace(key, `\${token.${token}}`)}\``;
51
+ // add {} wrapper for JSXAttribute
52
+ if (isJSXAttribute) {
53
+ stringValue = `{${stringValue}}`;
54
+ templateStringValue = `{${templateStringValue}}`;
55
+ }
56
+ return formattedValue === key ? j.identifier(stringValue) : j.identifier(templateStringValue);
57
+ });
58
+
59
+ root
60
+ .find(j.BlockStatement)
61
+ // avoid duplicate insert for nested block statement
62
+ .filter(path => isTopBlockStatement(path))
63
+ .forEach(path => {
64
+ const includeToken =
65
+ j(path).find(j.Identifier, {
66
+ name: name => name?.includes('token.'),
67
+ }).length > 0;
68
+ if (includeToken) {
69
+ const includeJSXElement = j(path).find(j.JSXElement).length > 0;
70
+ const includeUseTokenStatement =
71
+ j(path).find(j.Identifier, {
72
+ name: name => name.includes('useToken'),
73
+ }).length > 0;
74
+ const parentType = path.parentPath.value?.type;
75
+ // React function component
76
+ if (includeJSXElement && parentType !== 'ClassMethod') {
77
+ // avoid duplicate insert when it's existed
78
+ if (!includeUseTokenStatement) {
79
+ const insertString = 'const { token } = theme.useToken()';
80
+ // insert `const { token } = theme.useToken()`
81
+ path.get('body').value.unshift(j.expressionStatement(j.identifier(insertString)));
82
+ // import theme from @oceanbase/design
83
+ addSubmoduleImport(j, root, {
84
+ moduleName: '@oceanbase/design',
85
+ importedName: 'theme',
86
+ importKind: 'value',
87
+ });
88
+ }
89
+ } else {
90
+ // React class component and static file (not react component)
91
+ // import token from @oceanbase/design
92
+ addSubmoduleImport(j, root, {
93
+ moduleName: '@oceanbase/design',
94
+ importedName: 'token',
95
+ importKind: 'value',
96
+ });
97
+ }
98
+ }
99
+ });
100
+
101
+ root
102
+ .find(j.Identifier)
103
+ .filter(path => isTopIdentifier(path) && path.value.name?.includes('token.'))
104
+ .forEach(() => {
105
+ // import token from @oceanbase/design
106
+ addSubmoduleImport(j, root, {
107
+ moduleName: '@oceanbase/design',
108
+ importedName: 'token',
109
+ importKind: 'value',
110
+ });
111
+ });
112
+ }
113
+
114
+ return hasChanged;
115
+ }
116
+
117
+ module.exports = (file, api, options) => {
118
+ const j = api.jscodeshift;
119
+ const root = j(file.source);
120
+
121
+ let hasChanged = false;
122
+ hasChanged = importComponent(j, root, options) || hasChanged;
123
+
124
+ return hasChanged ? root.toSource(options.printOptions || printOptions) : null;
125
+ };
@@ -151,7 +151,7 @@ function addModuleImport(j, root, { pkgName, importSpecifier, importKind, before
151
151
 
152
152
  if (before) {
153
153
  insertImportBefore(j, root, { importStatement, importKind, beforeModule: before });
154
- } else if (after) {
154
+ } else {
155
155
  insertImportAfter(j, root, { importStatement, importKind, afterModule: after });
156
156
  }
157
157
 
@@ -0,0 +1,114 @@
1
+ const { toLower } = require('lodash');
2
+
3
+ const TOKEN_MAP = {
4
+ // antd style => token
5
+ '#1677ff': 'colorInfo',
6
+ '#1890ff': 'colorInfo',
7
+ '#40a9ff': 'colorInfo',
8
+ '#f7f9fb': 'colorInfoBg',
9
+ '#e6f7ff': 'colorInfoBgHover',
10
+ '#f3f9ff': 'colorInfoBgHover',
11
+ '#e6f7ff': 'colorInfoBgHover',
12
+ '#73d13d': 'colorSuccess',
13
+ '#52c41a': 'colorSuccess',
14
+ '#faad14': 'colorWarning',
15
+ '#fef6e7': 'colorWarningBg',
16
+ '#ff4d4f': 'colorError',
17
+ '#f5222d': 'colorError',
18
+ '#f8636b': 'colorError',
19
+ '#d9d9d9': 'colorBorder',
20
+ '#bfbfbf': 'colorBorder',
21
+ '#e8e8e8': 'colorBorder',
22
+ '#f0f0f0': 'colorBorder',
23
+ '#dadada': 'colorBorder',
24
+ 'rgba(217,217,217,1)': 'colorBorder',
25
+ 'rgba(217,217,217,1.0)': 'colorBorder',
26
+ 'rgba(217,217,217)': 'colorBorder',
27
+ '#f0f2f5': 'colorBgLayout',
28
+ '#fafafa': 'colorBgLayout',
29
+ '#f7f8fc': 'colorBgLayout',
30
+ '#ffffff': 'colorBgContainer',
31
+ '#fff': 'colorBgContainer',
32
+ 'rgba(0,0,0,0.85)': 'colorText',
33
+ 'rgba(0,0,0,0.65)': 'colorTextSecondary',
34
+ 'rgba(0,0,0,0.45)': 'colorTextTertiary',
35
+ '#5c6b8a': 'colorTextTertiary',
36
+ 'rgba(0,0,0,0.25)': 'colorTextQuaternary',
37
+ 'rgba(0,0,0,.85)': 'colorText',
38
+ 'rgba(0,0,0,.65)': 'colorTextSecondary',
39
+ 'rgba(0,0,0,.45)': 'colorTextTertiary',
40
+ 'rgba(0,0,0,.25)': 'colorTextQuaternary',
41
+ 'rgba(0,0,0,0.2)': 'colorFillQuaternary',
42
+ '#00000073': 'colorTextDescription',
43
+ '#f5f5f5': 'colorFillQuaternary',
44
+ 'rgba(0,0,0,0.02)': 'colorBgLayout',
45
+ 'rgba(0,0,0,0.04)': 'colorBgLayout',
46
+ '#f5f6fa': 'colorBgLayout',
47
+ '#edeff2': 'colorBgLayout',
48
+ // obui style => token
49
+ '#006aff': 'colorInfo',
50
+ '#086fff': 'colorInfo',
51
+ 'rgba(24,144,255,0.1)': 'colorInfoBg',
52
+ 'rgba(95,149,255,0.10)': 'colorInfoBg',
53
+ 'rgba(95,149,255,0.1)': 'colorInfoBg',
54
+ 'rgba(95,149,255,1)': 'colorInfoBorder',
55
+ '#0ac185': 'colorSuccess',
56
+ '#4dcca2': 'colorSuccess',
57
+ 'rgba(10,193,133,1)': 'colorSuccess',
58
+ 'rgba(82,196,26,0.1)': 'colorSuccessBg',
59
+ '#ffac33': 'colorWarning',
60
+ '#ff9700': 'colorWarning',
61
+ '#fbba3a': 'colorWarning',
62
+ 'rgb(243,164,60)': 'colorWarning',
63
+ 'rgba(250,140,22,0.1)': 'colorWarningBg',
64
+ '#ff4b4b': 'colorError',
65
+ '#ff1a1a': 'colorError',
66
+ '#fff1f0': 'colorErrorBg',
67
+ 'rgba(245,34,45,0.1)': 'colorErrorBg',
68
+ '#ffa39e': 'colorErrorBorder',
69
+ '#cdd5e4': 'colorBorder',
70
+ '#f5f8fe': 'colorBgLayout',
71
+ '#f5f7fa': 'colorBgLayout',
72
+ 'rgba(140,140,140,0.1)': 'colorBgLayout',
73
+ '#132039': 'colorText',
74
+ '#364563': 'colorTextSecondary',
75
+ '#8592ad': 'colorTextTertiary',
76
+ '#f8fafe': 'colorFillQuaternary',
77
+ };
78
+
79
+ const TOKEN_MAP_KEYS = Object.keys(TOKEN_MAP);
80
+
81
+ function isLower(str) {
82
+ return toLower(str) === str;
83
+ }
84
+
85
+ function customTrim(str) {
86
+ return str?.replace(/(\s)*([,\(\)])(\s)*/g, '$2');
87
+ }
88
+
89
+ function formatValue(value) {
90
+ return customTrim(toLower(value));
91
+ }
92
+
93
+ function tokenParse(value) {
94
+ const formattedValue = formatValue(value);
95
+ const key = TOKEN_MAP_KEYS.find(
96
+ item =>
97
+ formattedValue.endsWith(item) ||
98
+ formattedValue.includes(`${item} `) ||
99
+ formattedValue.includes(`${item}, `) ||
100
+ formattedValue.includes(`${item},`)
101
+ );
102
+ return {
103
+ key,
104
+ token: TOKEN_MAP[key],
105
+ formattedValue,
106
+ };
107
+ }
108
+
109
+ module.exports = {
110
+ TOKEN_MAP,
111
+ TOKEN_MAP_KEYS,
112
+ tokenParse,
113
+ isLower,
114
+ };