@oceanbase/codemod 1.0.0-alpha.1 → 1.0.0-alpha.3
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.
- package/package.json +4 -4
- package/transforms/__testfixtures__/less-to-token/antd-v4-less-to-token.input.less +2 -0
- package/transforms/__testfixtures__/less-to-token/antd-v4-less-to-token.output.less +2 -0
- package/transforms/__testfixtures__/less-to-token/exist-import-url.input.less +10 -0
- package/transforms/__testfixtures__/less-to-token/exist-import-url.output.less +10 -0
- package/transforms/__testfixtures__/less-to-token/exist-import.input.less +10 -0
- package/transforms/__testfixtures__/less-to-token/exist-import.output.less +10 -0
- package/transforms/__testfixtures__/style-to-token/antd-style.input.js +1 -0
- package/transforms/__testfixtures__/style-to-token/antd-style.output.js +1 -0
- package/transforms/__testfixtures__/style-to-token/nested-object.input.js +12 -0
- package/transforms/__testfixtures__/style-to-token/nested-object.output.js +13 -0
- package/transforms/__tests__/less-to-token.test.ts +2 -0
- package/transforms/__tests__/style-to-token.test.ts +1 -0
- package/transforms/less-to-token.js +45 -6
- package/transforms/style-to-token.js +124 -11
- package/transforms/utils/token.js +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oceanbase/codemod",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.3",
|
|
4
4
|
"description": "Codemod for OceanBase Design upgrade",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oceanbase",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"build": "father build"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@oceanbase/design": "^1.0.0-alpha.
|
|
26
|
+
"@oceanbase/design": "^1.0.0-alpha.3",
|
|
27
27
|
"chalk": "^3.0.0",
|
|
28
28
|
"command-exists": "^1.2.9",
|
|
29
29
|
"execa": "^5.1.1",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"postcss-less": "^6.0.0",
|
|
38
38
|
"prettier": "^3.6.2",
|
|
39
39
|
"read-pkg-up": "^10.1.0",
|
|
40
|
-
"semver": "^7.7.
|
|
40
|
+
"semver": "^7.7.3",
|
|
41
41
|
"update-check": "^1.5.4",
|
|
42
42
|
"yargs-parser": "^21.1.1"
|
|
43
43
|
},
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"enzyme": "^3.11.0",
|
|
48
48
|
"enzyme-to-json": "^3.6.2"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "62c3cf2b25248d70e4f1826e69c019a38e03753e"
|
|
51
51
|
}
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
border-color: #ff4d4f;
|
|
6
6
|
scrollbar-color: #ffffff;
|
|
7
7
|
font-size: 14px;
|
|
8
|
+
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03),
|
|
9
|
+
0 1px 6px -1px @colorFillQuaternary, 0 2px 4px 0 rgba(0, 0, 0, 0.02);
|
|
8
10
|
.content {
|
|
9
11
|
color: rgba(0, 0, 0, 0.85);
|
|
10
12
|
background: rgba(0, 0, 0,0.65);
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
border-color: @colorError;
|
|
7
7
|
scrollbar-color: @colorBgContainer;
|
|
8
8
|
font-size: @fontSize;
|
|
9
|
+
box-shadow: 0 1px 2px 0 @colorFillQuaternary,
|
|
10
|
+
0 1px 6px -1px @colorFillQuaternary, 0 2px 4px 0 @colorFillQuaternary;
|
|
9
11
|
.content {
|
|
10
12
|
color: @colorText;
|
|
11
13
|
background: @colorTextSecondary;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
@import url('~@oceanbase/design/es/theme/index.less');
|
|
2
|
+
|
|
3
|
+
.container {
|
|
4
|
+
color: @colorText;
|
|
5
|
+
background: @colorTextSecondary;
|
|
6
|
+
background-color: @colorTextTertiary;
|
|
7
|
+
border-color: @colorTextTertiary;
|
|
8
|
+
border: 1px solid @colorBorder;
|
|
9
|
+
font-size: @fontSize;
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
@import '~@oceanbase/design/es/theme/index.less';
|
|
2
|
+
|
|
3
|
+
.container {
|
|
4
|
+
color: @colorText;
|
|
5
|
+
background: @colorTextSecondary;
|
|
6
|
+
background-color: @colorTextTertiary;
|
|
7
|
+
border-color: @colorTextTertiary;
|
|
8
|
+
border: 1px solid @colorBorder;
|
|
9
|
+
font-size: @fontSize;
|
|
10
|
+
}
|
|
@@ -9,6 +9,7 @@ const useStyle1 = createStyles((
|
|
|
9
9
|
main: {
|
|
10
10
|
background: token.colorInfo,
|
|
11
11
|
fontSize: token.fontSize,
|
|
12
|
+
boxShadow: `0 1px 2px 0 ${token.colorFillQuaternary}, 0 1px 6px -1px ${token.colorFillQuaternary}, 0 2px 4px 0 ${token.colorFillQuaternary}`,
|
|
12
13
|
},
|
|
13
14
|
};
|
|
14
15
|
});
|
|
@@ -6,7 +6,7 @@ const isDirectory = require('is-directory');
|
|
|
6
6
|
const { tokenParse, propertyTokenParse } = require('./utils/token');
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Find all less files in the directory
|
|
10
10
|
* @param dir
|
|
11
11
|
* @returns
|
|
12
12
|
*/
|
|
@@ -36,6 +36,7 @@ async function transform(file) {
|
|
|
36
36
|
const content = fs.readFileSync(file, 'utf-8');
|
|
37
37
|
const { root: ast } = await postcss([]).process(content, {
|
|
38
38
|
syntax: postcssLess,
|
|
39
|
+
from: file, // 添加 from 选项以避免警告
|
|
39
40
|
});
|
|
40
41
|
let hasToken = false;
|
|
41
42
|
let tokenLessImported = false;
|
|
@@ -51,18 +52,56 @@ async function transform(file) {
|
|
|
51
52
|
hasToken = true;
|
|
52
53
|
} else {
|
|
53
54
|
// 然后尝试基于值的 token 转换
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
let newValue = node.value;
|
|
56
|
+
let valueHasToken = false;
|
|
57
|
+
|
|
58
|
+
// 检查是否为复合值(包含多个值或颜色值)
|
|
59
|
+
const isCompositeValue =
|
|
60
|
+
node.value.includes(',') ||
|
|
61
|
+
/rgba?\([^)]+\)|#[0-9a-fA-F]{3,8}|rgb\([^)]+\)|hsl\([^)]+\)|hsla?\([^)]+\)/.test(
|
|
62
|
+
node.value
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (isCompositeValue) {
|
|
66
|
+
// 对于复合值,只替换其中的颜色值
|
|
67
|
+
const colorRegex =
|
|
68
|
+
/rgba?\([^)]+\)|#[0-9a-fA-F]{3,8}|rgb\([^)]+\)|hsl\([^)]+\)|hsla?\([^)]+\)/g;
|
|
69
|
+
const colorMatches = node.value.match(colorRegex);
|
|
70
|
+
if (colorMatches) {
|
|
71
|
+
colorMatches.forEach(match => {
|
|
72
|
+
const colorResult = tokenParse(match);
|
|
73
|
+
if (colorResult.token) {
|
|
74
|
+
newValue = newValue.replace(match, `@${colorResult.token}`);
|
|
75
|
+
valueHasToken = true;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
// 对于简单值,尝试完整的 token 转换
|
|
81
|
+
const { key, token, formattedValue } = tokenParse(node.value);
|
|
82
|
+
if (token) {
|
|
83
|
+
newValue = formattedValue.replace(key, `@${token}`);
|
|
84
|
+
valueHasToken = true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (valueHasToken) {
|
|
89
|
+
node.value = newValue;
|
|
57
90
|
hasToken = true;
|
|
58
91
|
} else if (node.value?.includes('@')) {
|
|
59
92
|
hasToken = true;
|
|
60
93
|
}
|
|
61
94
|
}
|
|
62
95
|
} else if (node.type === 'atrule' && node.name === 'import') {
|
|
63
|
-
if (
|
|
96
|
+
if (
|
|
97
|
+
node.params?.includes("'~@oceanbase/design/es/theme/index.less'") ||
|
|
98
|
+
node.params?.includes('"~@oceanbase/design/es/theme/index.less"')
|
|
99
|
+
) {
|
|
64
100
|
tokenLessImported = true;
|
|
65
|
-
} else if (
|
|
101
|
+
} else if (
|
|
102
|
+
node.params?.includes("'~@alipay/ob-ui/es/theme/index.less'") ||
|
|
103
|
+
node.params?.includes('"~@alipay/ob-ui/es/theme/index.less"')
|
|
104
|
+
) {
|
|
66
105
|
node.remove();
|
|
67
106
|
}
|
|
68
107
|
}
|
|
@@ -65,8 +65,8 @@ function isReactComponentOrHook(functionName, path) {
|
|
|
65
65
|
// 检查 BlockStatement 中是否包含 token 使用
|
|
66
66
|
function hasTokenUsage(j, path) {
|
|
67
67
|
return (
|
|
68
|
-
j(path).find(j.
|
|
69
|
-
|
|
68
|
+
j(path).find(j.MemberExpression, {
|
|
69
|
+
object: { name: 'token' },
|
|
70
70
|
}).length > 0
|
|
71
71
|
);
|
|
72
72
|
}
|
|
@@ -261,12 +261,71 @@ function processStringLiterals(j, root) {
|
|
|
261
261
|
return hasChanged;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
// 处理模板字符串中的颜色值
|
|
265
|
+
function processTemplateLiterals(j, root) {
|
|
266
|
+
let hasChanged = false;
|
|
267
|
+
|
|
268
|
+
const templateList = root.find(j.TemplateLiteral);
|
|
269
|
+
|
|
270
|
+
if (templateList.length > 0) {
|
|
271
|
+
templateList.forEach(path => {
|
|
272
|
+
const templateLiteral = path.value;
|
|
273
|
+
const quasis = templateLiteral.quasis;
|
|
274
|
+
|
|
275
|
+
// 检查每个模板字符串片段是否包含需要转换的颜色值
|
|
276
|
+
for (let i = 0; i < quasis.length; i++) {
|
|
277
|
+
const quasi = quasis[i];
|
|
278
|
+
let value = quasi.value.raw;
|
|
279
|
+
let newValue = value;
|
|
280
|
+
let valueChanged = false;
|
|
281
|
+
|
|
282
|
+
// 查找需要转换的颜色值
|
|
283
|
+
const colorMatch = newValue.match(
|
|
284
|
+
/rgba?\([^)]+\)|#[0-9a-fA-F]{3,8}|rgb\([^)]+\)|hsl\([^)]+\)|hsla?\([^)]+\)/g
|
|
285
|
+
);
|
|
286
|
+
if (colorMatch) {
|
|
287
|
+
hasChanged = true;
|
|
288
|
+
valueChanged = true;
|
|
289
|
+
|
|
290
|
+
colorMatch.forEach(match => {
|
|
291
|
+
const { token } = tokenParse(match);
|
|
292
|
+
if (token) {
|
|
293
|
+
newValue = newValue.replace(match, `\${token.${token}}`);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// 如果值发生了变化,更新模板字符串片段
|
|
299
|
+
if (valueChanged) {
|
|
300
|
+
quasi.value.raw = newValue;
|
|
301
|
+
quasi.value.cooked = newValue;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// 为包含 token 使用的顶级 BlockStatement 添加导入
|
|
307
|
+
root
|
|
308
|
+
.find(j.BlockStatement)
|
|
309
|
+
.filter(path => isTopBlockStatement(path))
|
|
310
|
+
.forEach(path => {
|
|
311
|
+
if (hasTokenUsage(j, path) && !hasUseTokenStatement(j, path)) {
|
|
312
|
+
addTokenImportToBlockStatement(j, root, path);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return hasChanged;
|
|
318
|
+
}
|
|
319
|
+
|
|
264
320
|
function importComponent(j, root, options) {
|
|
265
321
|
let hasChanged = false;
|
|
266
322
|
|
|
267
323
|
// 处理字符串字面量
|
|
268
324
|
hasChanged = processStringLiterals(j, root) || hasChanged;
|
|
269
325
|
|
|
326
|
+
// 处理模板字符串中的颜色值
|
|
327
|
+
hasChanged = processTemplateLiterals(j, root) || hasChanged;
|
|
328
|
+
|
|
270
329
|
// 处理对象属性值(如 fontSize: 14)
|
|
271
330
|
const objectPropertyChanged = processObjectProperties(j, root);
|
|
272
331
|
hasChanged = objectPropertyChanged || hasChanged;
|
|
@@ -293,8 +352,11 @@ function processObjectProperties(j, root) {
|
|
|
293
352
|
if (tokenResult) {
|
|
294
353
|
hasChanged = true;
|
|
295
354
|
const isJSXAttribute = path.parentPath.value.type === 'JSXAttribute';
|
|
296
|
-
const
|
|
297
|
-
|
|
355
|
+
const memberExpression = j.memberExpression(
|
|
356
|
+
j.identifier('token'),
|
|
357
|
+
j.identifier(tokenResult.token)
|
|
358
|
+
);
|
|
359
|
+
return j.objectProperty(j.identifier(propertyName), memberExpression);
|
|
298
360
|
}
|
|
299
361
|
return path.value;
|
|
300
362
|
});
|
|
@@ -315,23 +377,22 @@ function processObjectProperties(j, root) {
|
|
|
315
377
|
if (tokenResult) {
|
|
316
378
|
hasChanged = true;
|
|
317
379
|
const isJSXAttribute = path.parentPath.value.type === 'JSXAttribute';
|
|
318
|
-
const
|
|
319
|
-
|
|
380
|
+
const memberExpression = j.memberExpression(
|
|
381
|
+
j.identifier('token'),
|
|
382
|
+
j.identifier(tokenResult.token)
|
|
383
|
+
);
|
|
384
|
+
return j.objectProperty(j.identifier(propertyName), memberExpression);
|
|
320
385
|
}
|
|
321
386
|
return path.value;
|
|
322
387
|
});
|
|
323
388
|
}
|
|
324
389
|
|
|
325
|
-
// 如果发生了替换,需要添加 token 导入
|
|
326
|
-
if (hasChanged) {
|
|
327
|
-
addTokenImportsForObjectProperties(j, root);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
390
|
return hasChanged;
|
|
331
391
|
}
|
|
332
392
|
|
|
333
393
|
// 为对象属性添加 token 导入
|
|
334
394
|
function addTokenImportsForObjectProperties(j, root) {
|
|
395
|
+
// 处理 BlockStatement 中的 token 使用
|
|
335
396
|
root
|
|
336
397
|
.find(j.BlockStatement)
|
|
337
398
|
.filter(path => isTopBlockStatement(path))
|
|
@@ -344,6 +405,31 @@ function addTokenImportsForObjectProperties(j, root) {
|
|
|
344
405
|
}
|
|
345
406
|
}
|
|
346
407
|
});
|
|
408
|
+
|
|
409
|
+
// 处理顶层导出语句中的 token 使用
|
|
410
|
+
const hasTokenUsageInRoot =
|
|
411
|
+
root.find(j.MemberExpression, {
|
|
412
|
+
object: { name: 'token' },
|
|
413
|
+
}).length > 0;
|
|
414
|
+
|
|
415
|
+
if (hasTokenUsageInRoot) {
|
|
416
|
+
// 检查是否应该添加顶层 token 导入
|
|
417
|
+
if (shouldAddTopLevelTokenImport(j, root)) {
|
|
418
|
+
// 检查是否有 @oceanbase/design 的导入
|
|
419
|
+
const hasOceanbaseImport =
|
|
420
|
+
root.find(j.ImportDeclaration, {
|
|
421
|
+
source: { value: '@oceanbase/design' },
|
|
422
|
+
}).length > 0;
|
|
423
|
+
|
|
424
|
+
if (hasOceanbaseImport) {
|
|
425
|
+
// 如果有 @oceanbase/design 导入,添加到现有导入
|
|
426
|
+
addTokenToExistingImport(j, root);
|
|
427
|
+
} else {
|
|
428
|
+
// 如果没有 @oceanbase/design 导入,添加顶层 token 导入
|
|
429
|
+
addTopLevelTokenImport(j, root);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
347
433
|
}
|
|
348
434
|
|
|
349
435
|
// 检查是否应该添加顶层 token 导入
|
|
@@ -425,6 +511,33 @@ module.exports = (file, api, options) => {
|
|
|
425
511
|
processCreateStylesParams(j, root);
|
|
426
512
|
}
|
|
427
513
|
|
|
514
|
+
// 为对象属性添加 token 导入(只在没有其他 token 导入逻辑时调用)
|
|
515
|
+
if (hasChanged) {
|
|
516
|
+
// 检查是否已经有其他 token 导入逻辑在处理
|
|
517
|
+
const hasOtherTokenLogic =
|
|
518
|
+
root.find(j.CallExpression, {
|
|
519
|
+
callee: { name: 'createStyles' },
|
|
520
|
+
}).length > 0 ||
|
|
521
|
+
root.find(j.CallExpression, {
|
|
522
|
+
callee: {
|
|
523
|
+
type: 'MemberExpression',
|
|
524
|
+
object: { name: 'theme' },
|
|
525
|
+
property: { name: 'useToken' },
|
|
526
|
+
},
|
|
527
|
+
}).length > 0 ||
|
|
528
|
+
root
|
|
529
|
+
.find(j.ImportDeclaration, {
|
|
530
|
+
source: { value: '@oceanbase/design' },
|
|
531
|
+
})
|
|
532
|
+
.find(j.ImportSpecifier, {
|
|
533
|
+
imported: { name: 'theme' },
|
|
534
|
+
}).length > 0;
|
|
535
|
+
|
|
536
|
+
if (!hasOtherTokenLogic) {
|
|
537
|
+
addTokenImportsForObjectProperties(j, root);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
428
541
|
// 如果有变化,检查是否需要添加 token 导入
|
|
429
542
|
if (hasChanged) {
|
|
430
543
|
// 检查是否有 token 使用
|
|
@@ -47,6 +47,7 @@ const TOKEN_MAP = {
|
|
|
47
47
|
'#ff4d4f': 'colorError',
|
|
48
48
|
'#f5222d': 'colorError',
|
|
49
49
|
'#f8636b': 'colorError',
|
|
50
|
+
'#f93939': 'colorError',
|
|
50
51
|
'#d9d9d9': 'colorBorder',
|
|
51
52
|
'#bfbfbf': 'colorBorder',
|
|
52
53
|
'#e8e8e8': 'colorBorder',
|
|
@@ -97,6 +98,7 @@ const TOKEN_MAP = {
|
|
|
97
98
|
'rgba(0,0,0,0.06)': 'colorFillSecondary',
|
|
98
99
|
'rgba(0,0,0,0.04)': 'colorFillTertiary',
|
|
99
100
|
'rgba(0,0,0,0.02)': 'colorFillQuaternary',
|
|
101
|
+
'rgba(0,0,0,0.03)': 'colorFillQuaternary',
|
|
100
102
|
'#f5f6fa': 'colorBgLayout',
|
|
101
103
|
'#edeff2': 'colorBgLayout',
|
|
102
104
|
// obui legacy style => token
|
|
@@ -122,12 +124,12 @@ const TOKEN_MAP = {
|
|
|
122
124
|
'#cdd5e4': 'colorBorder',
|
|
123
125
|
'#f5f8fe': 'colorBgLayout',
|
|
124
126
|
'#f5f7fa': 'colorBgLayout',
|
|
127
|
+
'#f8fafe': 'colorBgLayout',
|
|
125
128
|
'rgba(140,140,140,0.1)': 'colorBgLayout',
|
|
126
129
|
'rgb(240,242,245)': 'colorBgLayout',
|
|
127
130
|
'#132039': 'colorText',
|
|
128
131
|
'#364563': 'colorTextSecondary',
|
|
129
132
|
'#8592ad': 'colorTextTertiary',
|
|
130
|
-
'#f8fafe': 'colorFillQuaternary',
|
|
131
133
|
};
|
|
132
134
|
|
|
133
135
|
const TOKEN_MAP_KEYS = Object.keys(TOKEN_MAP).map(key => formatValue(key));
|