@oceanbase/codemod 1.0.0-alpha.8 → 1.0.0-alpha.9

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 (36) hide show
  1. package/README.md +85 -0
  2. package/bin/cli.js +39 -3
  3. package/package.json +4 -4
  4. package/transforms/__testfixtures__/less-to-cssvar/basic.input.less +16 -0
  5. package/transforms/__testfixtures__/less-to-cssvar/basic.output.less +14 -0
  6. package/transforms/__testfixtures__/less-to-cssvar/color-scales.input.less +23 -0
  7. package/transforms/__testfixtures__/less-to-cssvar/color-scales.output.less +21 -0
  8. package/transforms/__testfixtures__/less-to-cssvar/complex-values.input.less +22 -0
  9. package/transforms/__testfixtures__/less-to-cssvar/complex-values.output.less +20 -0
  10. package/transforms/__testfixtures__/less-to-cssvar/control-tokens.input.less +29 -0
  11. package/transforms/__testfixtures__/less-to-cssvar/control-tokens.output.less +27 -0
  12. package/transforms/__testfixtures__/less-to-cssvar/css-modules-global.input.less +21 -0
  13. package/transforms/__testfixtures__/less-to-cssvar/css-modules-global.output.less +19 -0
  14. package/transforms/__testfixtures__/less-to-cssvar/custom-prefix.input.less +9 -0
  15. package/transforms/__testfixtures__/less-to-cssvar/custom-prefix.output.less +7 -0
  16. package/transforms/__testfixtures__/less-to-cssvar/fill-tokens.input.less +36 -0
  17. package/transforms/__testfixtures__/less-to-cssvar/fill-tokens.output.less +34 -0
  18. package/transforms/__testfixtures__/less-to-cssvar/mixed-values.input.less +21 -0
  19. package/transforms/__testfixtures__/less-to-cssvar/mixed-values.output.less +19 -0
  20. package/transforms/__testfixtures__/less-to-cssvar/multiple-imports.input.less +9 -0
  21. package/transforms/__testfixtures__/less-to-cssvar/multiple-imports.output.less +8 -0
  22. package/transforms/__testfixtures__/less-to-cssvar/nested-selectors.input.less +24 -0
  23. package/transforms/__testfixtures__/less-to-cssvar/nested-selectors.output.less +22 -0
  24. package/transforms/__testfixtures__/less-to-cssvar/no-transform.input.less +8 -0
  25. package/transforms/__testfixtures__/less-to-cssvar/no-transform.output.less +8 -0
  26. package/transforms/__testfixtures__/less-to-cssvar/obui-import.input.less +7 -0
  27. package/transforms/__testfixtures__/less-to-cssvar/obui-import.output.less +5 -0
  28. package/transforms/__testfixtures__/less-to-cssvar/status-colors.input.less +25 -0
  29. package/transforms/__testfixtures__/less-to-cssvar/status-colors.output.less +23 -0
  30. package/transforms/__testfixtures__/less-to-token/case-insensitive.input.less +4 -0
  31. package/transforms/__testfixtures__/less-to-token/case-insensitive.output.less +4 -0
  32. package/transforms/__testfixtures__/style-to-token/function-component.input.js +2 -2
  33. package/transforms/__testfixtures__/style-to-token/function-component.output.js +2 -2
  34. package/transforms/__tests__/less-to-cssvar.test.ts +124 -0
  35. package/transforms/less-to-cssvar.js +482 -0
  36. package/transforms/utils/token.js +19 -0
@@ -0,0 +1,482 @@
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 { glob } = require('glob');
7
+
8
+ /**
9
+ * Get Less tokens from @oceanbase/design theme Less file
10
+ * This reads all @variableName definitions from the theme file
11
+ */
12
+ function getLessTokensFromTheme() {
13
+ try {
14
+ // Try to find the Less theme file from @oceanbase/design
15
+ const themeLessPath = require.resolve('@oceanbase/design/es/theme/style/default.less');
16
+ const content = fs.readFileSync(themeLessPath, 'utf-8');
17
+
18
+ // Extract all @variableName: definitions
19
+ const tokenRegex = /@([a-zA-Z][a-zA-Z0-9]*):/g;
20
+ const tokens = new Set();
21
+ let match;
22
+ while ((match = tokenRegex.exec(content)) !== null) {
23
+ tokens.add(match[1]);
24
+ }
25
+ return Array.from(tokens);
26
+ } catch (e) {
27
+ // Fallback: try lib path
28
+ try {
29
+ const themeLessPath = require.resolve('@oceanbase/design/lib/theme/style/default.less');
30
+ const content = fs.readFileSync(themeLessPath, 'utf-8');
31
+
32
+ const tokenRegex = /@([a-zA-Z][a-zA-Z0-9]*):/g;
33
+ const tokens = new Set();
34
+ let match;
35
+ while ((match = tokenRegex.exec(content)) !== null) {
36
+ tokens.add(match[1]);
37
+ }
38
+ return Array.from(tokens);
39
+ } catch (e2) {
40
+ // Final fallback: use theme token object
41
+ try {
42
+ const { default: defaultTheme } = require('@oceanbase/design/lib/theme/default');
43
+ return Object.keys(defaultTheme.token || {});
44
+ } catch (e3) {
45
+ console.warn('Warning: Could not load tokens from @oceanbase/design, using empty list');
46
+ return [];
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ // Get Less variable tokens dynamically from @oceanbase/design theme
53
+ const LESS_TOKENS = getLessTokensFromTheme();
54
+
55
+ /**
56
+ * Convert camelCase to kebab-case
57
+ * @param {string} str - camelCase string
58
+ * @returns {string} - kebab-case string
59
+ */
60
+ function camelToKebab(str) {
61
+ return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
62
+ }
63
+
64
+ /**
65
+ * Find all less files in the directory
66
+ * @param dir
67
+ * @returns
68
+ */
69
+ const findAllLessFiles = dir => {
70
+ const lessFiles = [];
71
+ const isDir = isDirectory.sync(dir);
72
+ if (isDir) {
73
+ const files = fs.readdirSync(dir);
74
+ files.forEach(file => {
75
+ const filePath = path.join(dir, file);
76
+ if (isDirectory.sync(filePath)) {
77
+ if (filePath.includes('.umi') || filePath.includes('.umi-production')) {
78
+ return;
79
+ }
80
+ lessFiles.push(...findAllLessFiles(filePath));
81
+ } else if (file.endsWith('.less')) {
82
+ lessFiles.push(filePath);
83
+ }
84
+ });
85
+ } else if (dir.endsWith('.less')) {
86
+ lessFiles.push(dir);
87
+ }
88
+ return lessFiles;
89
+ };
90
+
91
+ /**
92
+ * Transform Less variable to CSS variable
93
+ * @param {string} value - CSS value that may contain Less variables
94
+ * @param {string} prefix - CSS variable prefix (default: 'ant')
95
+ * @returns {string} - Transformed value with CSS variables
96
+ */
97
+ function transformLessVarToCssVar(value, prefix = 'ant') {
98
+ if (!value || typeof value !== 'string') {
99
+ return value;
100
+ }
101
+
102
+ let result = value;
103
+
104
+ // Match Less variables like @colorPrimary, @fontSize, etc.
105
+ // Support both @tokenName and @{tokenName} syntax
106
+ const lessVarRegex = /@\{?([a-zA-Z][a-zA-Z0-9]*)\}?/g;
107
+
108
+ result = result.replace(lessVarRegex, (match, varName) => {
109
+ // Check if this is a known token
110
+ if (LESS_TOKENS.includes(varName)) {
111
+ const kebabName = camelToKebab(varName);
112
+ return `var(--${prefix}-${kebabName})`;
113
+ }
114
+ // Return original if not a known token
115
+ return match;
116
+ });
117
+
118
+ return result;
119
+ }
120
+
121
+ /**
122
+ * Transform a single Less file to use CSS variables
123
+ * @param {string} file - File path
124
+ * @param {object} options - Transform options
125
+ * @param {string} options.prefix - CSS variable prefix (default: 'ant')
126
+ * @returns {Promise<string>} - Transformed content
127
+ */
128
+ async function transform(file, options = {}) {
129
+ const { prefix = 'ant' } = options;
130
+ const content = fs.readFileSync(file, 'utf-8');
131
+ const { root: ast } = await postcss([]).process(content, {
132
+ syntax: postcssLess,
133
+ from: file,
134
+ });
135
+
136
+ // Track whether any transformations were made
137
+ let hasTransformations = false;
138
+
139
+ // Traverse AST
140
+ ast.walk(node => {
141
+ if (node.type === 'decl') {
142
+ // Transform property values that contain Less variables
143
+ const newValue = transformLessVarToCssVar(node.value, prefix);
144
+ if (newValue !== node.value) {
145
+ node.value = newValue;
146
+ hasTransformations = true;
147
+ }
148
+ } else if (node.type === 'atrule') {
149
+ // Remove the theme import
150
+ if (node.name === 'import') {
151
+ if (
152
+ node.params?.includes("'~@oceanbase/design/es/theme/index.less'") ||
153
+ node.params?.includes('"~@oceanbase/design/es/theme/index.less"') ||
154
+ node.params?.includes("'~@alipay/ob-ui/es/theme/index.less'") ||
155
+ node.params?.includes('"~@alipay/ob-ui/es/theme/index.less"')
156
+ ) {
157
+ node.remove();
158
+ hasTransformations = true;
159
+ }
160
+ }
161
+ // Transform Less variables in at-rule params (e.g., media queries)
162
+ if (node.params) {
163
+ const newParams = transformLessVarToCssVar(node.params, prefix);
164
+ if (newParams !== node.params) {
165
+ node.params = newParams;
166
+ hasTransformations = true;
167
+ }
168
+ }
169
+ }
170
+ });
171
+
172
+ return {
173
+ content: ast.toString(postcssLess.stringify),
174
+ hasTransformations,
175
+ };
176
+ }
177
+
178
+ /**
179
+ * Convert Less single-line comments (//) to CSS block comments
180
+ * @param {string} content - File content
181
+ * @returns {string} - Content with converted comments
182
+ */
183
+ function convertLessCommentsToCss(content) {
184
+ // Convert // comments to /* */ comments
185
+ // Match // at the start of a line or after whitespace, but not inside strings or existing block comments
186
+ const lines = content.split('\n');
187
+ const result = lines.map(line => {
188
+ // Skip if line is inside a block comment or contains a URL
189
+ if (line.includes('://')) {
190
+ // Handle URLs - only convert comments that are not part of URLs
191
+ return line.replace(/(?<!:)\/\/(.*)$/gm, (match, comment) => {
192
+ // Check if this is really a comment (not a URL protocol)
193
+ const beforeMatch = line.substring(0, line.lastIndexOf(match));
194
+ if (beforeMatch.match(/https?:$/) || beforeMatch.match(/url\([^)]*$/)) {
195
+ return match; // Keep as is for URLs
196
+ }
197
+ return `/* ${comment.trim()} */`;
198
+ });
199
+ }
200
+ // Convert standalone // comments
201
+ return line.replace(/^(\s*)\/\/(.*)$/, '$1/* $2 */').replace(/(\s)\/\/(.*)$/, '$1/* $2 */');
202
+ });
203
+ return result.join('\n');
204
+ }
205
+
206
+ /**
207
+ * Update import references in JS/TS files
208
+ * @param {string} baseDir - Base directory to search for JS/TS files
209
+ * @param {Array<{oldPath: string, newPath: string}>} renamedFiles - List of renamed files
210
+ */
211
+ async function updateImportReferences(baseDir, renamedFiles) {
212
+ if (renamedFiles.length === 0) return;
213
+
214
+ // Find all JS/TS/JSX/TSX files
215
+ const jsFiles = await glob('**/*.{js,jsx,ts,tsx}', {
216
+ cwd: baseDir,
217
+ absolute: true,
218
+ ignore: ['**/node_modules/**', '**/.umi/**', '**/.umi-production/**'],
219
+ });
220
+
221
+ for (const jsFile of jsFiles) {
222
+ let content = fs.readFileSync(jsFile, 'utf-8');
223
+ let hasChanges = false;
224
+
225
+ for (const { oldPath, newPath } of renamedFiles) {
226
+ // Calculate relative paths from the JS file to the Less/CSS files
227
+ const jsFileDir = path.dirname(jsFile);
228
+
229
+ // Get the relative path from the JS file to the old Less file
230
+ let relativeOldPath = path.relative(jsFileDir, oldPath);
231
+ let relativeNewPath = path.relative(jsFileDir, newPath);
232
+
233
+ // Normalize path separators for the regex
234
+ relativeOldPath = relativeOldPath.replace(/\\/g, '/');
235
+ relativeNewPath = relativeNewPath.replace(/\\/g, '/');
236
+
237
+ // Add ./ prefix if needed
238
+ if (!relativeOldPath.startsWith('.') && !relativeOldPath.startsWith('/')) {
239
+ relativeOldPath = './' + relativeOldPath;
240
+ }
241
+ if (!relativeNewPath.startsWith('.') && !relativeNewPath.startsWith('/')) {
242
+ relativeNewPath = './' + relativeNewPath;
243
+ }
244
+
245
+ // Also handle the case without ./ prefix
246
+ const relativeOldPathNoDot = relativeOldPath.replace(/^\.\//, '');
247
+ const relativeNewPathNoDot = relativeNewPath.replace(/^\.\//, '');
248
+
249
+ // Create regex patterns to match import statements
250
+ // Match: import './style.less', import "./style.less", require('./style.less'), require("./style.less")
251
+ const patterns = [
252
+ // With ./ prefix
253
+ new RegExp(`(['"])${escapeRegExp(relativeOldPath)}\\1`, 'g'),
254
+ // Without ./ prefix (for some bundler configurations)
255
+ new RegExp(`(['"])${escapeRegExp(relativeOldPathNoDot)}\\1`, 'g'),
256
+ ];
257
+
258
+ for (const pattern of patterns) {
259
+ const newContent = content.replace(pattern, (match, quote) => {
260
+ return `${quote}${relativeNewPath}${quote}`;
261
+ });
262
+ if (newContent !== content) {
263
+ content = newContent;
264
+ hasChanges = true;
265
+ }
266
+ }
267
+ }
268
+
269
+ if (hasChanges) {
270
+ fs.writeFileSync(jsFile, content);
271
+ console.log(` Updated imports: ${jsFile}`);
272
+ }
273
+ }
274
+ }
275
+
276
+ /**
277
+ * Escape special regex characters in a string
278
+ * @param {string} string - String to escape
279
+ * @returns {string} - Escaped string
280
+ */
281
+ function escapeRegExp(string) {
282
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
283
+ }
284
+
285
+ // Common global style file name patterns (case insensitive)
286
+ const GLOBAL_STYLE_PATTERNS = [
287
+ /^global\.less$/i,
288
+ /^globals\.less$/i,
289
+ /^reset\.less$/i,
290
+ /^normalize\.less$/i,
291
+ /^base\.less$/i,
292
+ /^common\.less$/i,
293
+ /^app\.less$/i,
294
+ /^index\.less$/i,
295
+ /^main\.less$/i,
296
+ /^style\.less$/i,
297
+ /^styles\.less$/i,
298
+ /^variables\.less$/i,
299
+ /^mixins\.less$/i,
300
+ /^theme\.less$/i,
301
+ ];
302
+
303
+ /**
304
+ * Check if a Less file is imported as a CSS Module in any JS/TS file
305
+ * CSS Module import: import styles from './xxx.less'
306
+ * Global import: import './xxx.less'
307
+ * @param {string} lessFilePath - Path to the Less file
308
+ * @param {string} baseDir - Base directory to search for JS/TS files
309
+ * @returns {Promise<boolean>} - True if imported as CSS Module, false if global or not found
310
+ */
311
+ async function isImportedAsCssModule(lessFilePath, baseDir) {
312
+ const fileName = path.basename(lessFilePath);
313
+
314
+ // Check if file name matches common global style patterns
315
+ for (const pattern of GLOBAL_STYLE_PATTERNS) {
316
+ if (pattern.test(fileName)) {
317
+ return false;
318
+ }
319
+ }
320
+
321
+ // Check if file already has .module in the name
322
+ if (/\.module\.less$/.test(lessFilePath)) {
323
+ return true;
324
+ }
325
+
326
+ try {
327
+ // Find all JS/TS/JSX/TSX files
328
+ const jsFiles = await glob('**/*.{js,jsx,ts,tsx}', {
329
+ cwd: baseDir,
330
+ absolute: true,
331
+ ignore: ['**/node_modules/**', '**/.umi/**', '**/.umi-production/**'],
332
+ });
333
+
334
+ for (const jsFile of jsFiles) {
335
+ const content = fs.readFileSync(jsFile, 'utf-8');
336
+ const jsFileDir = path.dirname(jsFile);
337
+
338
+ // Calculate relative path from JS file to Less file
339
+ let relativePath = path.relative(jsFileDir, lessFilePath).replace(/\\/g, '/');
340
+ if (!relativePath.startsWith('.') && !relativePath.startsWith('/')) {
341
+ relativePath = './' + relativePath;
342
+ }
343
+ const relativePathNoDot = relativePath.replace(/^\.\//, '');
344
+
345
+ // Escape for regex
346
+ const escapedPath = escapeRegExp(relativePath);
347
+ const escapedPathNoDot = escapeRegExp(relativePathNoDot);
348
+
349
+ // Check for CSS Module import pattern: import xxx from './xxx.less'
350
+ // Match: import styles from './xxx.less', import * as styles from './xxx.less'
351
+ const cssModuleImportRegex = new RegExp(
352
+ `import\\s+(?:\\*\\s+as\\s+)?\\w+\\s+from\\s+(['"])(?:${escapedPath}|${escapedPathNoDot})\\1`,
353
+ 'm'
354
+ );
355
+
356
+ // Check for global import pattern: import './xxx.less'
357
+ const globalImportRegex = new RegExp(
358
+ `import\\s+(['"])(?:${escapedPath}|${escapedPathNoDot})\\1`,
359
+ 'm'
360
+ );
361
+
362
+ // Check for require with assignment: const styles = require('./xxx.less')
363
+ const cssModuleRequireRegex = new RegExp(
364
+ `(?:const|let|var)\\s+\\w+\\s*=\\s*require\\s*\\(\\s*(['"])(?:${escapedPath}|${escapedPathNoDot})\\1\\s*\\)`,
365
+ 'm'
366
+ );
367
+
368
+ // Check for require without assignment: require('./xxx.less')
369
+ const globalRequireRegex = new RegExp(
370
+ `(?<!(?:const|let|var)\\s+\\w+\\s*=\\s*)require\\s*\\(\\s*(['"])(?:${escapedPath}|${escapedPathNoDot})\\1\\s*\\)`,
371
+ 'm'
372
+ );
373
+
374
+ if (cssModuleImportRegex.test(content) || cssModuleRequireRegex.test(content)) {
375
+ return true;
376
+ }
377
+
378
+ if (globalImportRegex.test(content) || globalRequireRegex.test(content)) {
379
+ // Found as global import, but continue checking other files
380
+ // in case it's also imported as CSS Module elsewhere
381
+ continue;
382
+ }
383
+ }
384
+
385
+ // Default to false (treat as global) if not found or only found as global import
386
+ return false;
387
+ } catch (e) {
388
+ // If scanning fails, default to user's preference
389
+ return true;
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Get the new file path when renaming from .less to .css
395
+ * @param {string} filePath - Original file path
396
+ * @param {boolean} shouldAddModule - Whether to add .module suffix
397
+ * @returns {string} - New file path
398
+ */
399
+ function getNewCssPath(filePath, shouldAddModule) {
400
+ // Check if file already has .module in the name
401
+ const hasModule = /\.module\.less$/.test(filePath);
402
+
403
+ if (hasModule) {
404
+ // Already has .module, just change extension
405
+ return filePath.replace(/\.less$/, '.css');
406
+ } else if (shouldAddModule) {
407
+ // Add .module before .css
408
+ return filePath.replace(/\.less$/, '.module.css');
409
+ } else {
410
+ // Just change extension
411
+ return filePath.replace(/\.less$/, '.css');
412
+ }
413
+ }
414
+
415
+ /**
416
+ * Run the less-to-cssvar transformation
417
+ * @param {string} file - File or directory path
418
+ * @param {object} options - Transform options
419
+ * @param {string} options.prefix - CSS variable prefix (default: 'ant')
420
+ * @param {boolean} options.renameToCss - Whether to rename .less to .css (default: true)
421
+ * @param {boolean} options.addModule - Whether to add .module suffix when renaming (default: true)
422
+ * - true (default): Auto-detect based on import style (CSS Module import → .module.css, global import → .css)
423
+ * - false: Skip detection, never add .module suffix
424
+ */
425
+ async function lessToCssvar(file, options = {}) {
426
+ const { prefix = 'ant', renameToCss = true, addModule = true } = options;
427
+ const allLessFiles = findAllLessFiles(file);
428
+ const renamedFiles = [];
429
+ const baseDir = isDirectory.sync(file) ? file : path.dirname(file);
430
+
431
+ for await (const item of allLessFiles) {
432
+ let { content, hasTransformations } = await transform(item, { prefix });
433
+
434
+ // If renaming to CSS, convert Less comments to CSS comments
435
+ if (renameToCss) {
436
+ const convertedContent = convertLessCommentsToCss(content);
437
+ if (convertedContent !== content) {
438
+ content = convertedContent;
439
+ hasTransformations = true;
440
+ }
441
+ }
442
+
443
+ fs.writeFileSync(item, content);
444
+
445
+ // Rename .less to .css if option is enabled
446
+ if (renameToCss && hasTransformations) {
447
+ // Determine whether to add .module suffix
448
+ let shouldAddModule;
449
+ if (addModule) {
450
+ // Auto-detect based on import style
451
+ shouldAddModule = await isImportedAsCssModule(item, baseDir);
452
+ } else {
453
+ // Skip detection, never add .module
454
+ shouldAddModule = false;
455
+ }
456
+
457
+ const newPath = getNewCssPath(item, shouldAddModule);
458
+ if (newPath !== item) {
459
+ fs.renameSync(item, newPath);
460
+ console.log(` Renamed: ${item} -> ${newPath}`);
461
+ renamedFiles.push({ oldPath: item, newPath });
462
+ }
463
+ }
464
+ }
465
+
466
+ // Update import references in JS/TS files
467
+ if (renameToCss && renamedFiles.length > 0) {
468
+ console.log(`\n Updating import references...`);
469
+ await updateImportReferences(baseDir, renamedFiles);
470
+ }
471
+ }
472
+
473
+ module.exports = {
474
+ transform,
475
+ lessToCssvar,
476
+ transformLessVarToCssVar,
477
+ convertLessCommentsToCss,
478
+ updateImportReferences,
479
+ getLessTokensFromTheme,
480
+ camelToKebab,
481
+ LESS_TOKENS,
482
+ };
@@ -36,18 +36,24 @@ const TOKEN_MAP = {
36
36
  '#1890ff': 'colorInfo',
37
37
  '#40a9ff': 'colorInfo',
38
38
  '#006aff': 'colorInfo',
39
+ '#1843ff': 'colorInfo',
40
+ '#597ef7': 'colorInfo',
39
41
  '#f7f9fb': 'colorInfoBg',
42
+ '#91a9f8': 'colorInfoBg',
40
43
  '#e6f7ff': 'colorInfoBgHover',
41
44
  '#f3f9ff': 'colorInfoBgHover',
42
45
  '#e6f7ff': 'colorInfoBgHover',
43
46
  '#73d13d': 'colorSuccess',
44
47
  '#52c41a': 'colorSuccess',
45
48
  '#faad14': 'colorWarning',
49
+ '#ffa940': 'colorWarning',
46
50
  '#fef6e7': 'colorWarningBg',
51
+ '#fed59c': 'colorWarningBg',
47
52
  '#ff4d4f': 'colorError',
48
53
  '#f5222d': 'colorError',
49
54
  '#f8636b': 'colorError',
50
55
  '#f93939': 'colorError',
56
+ '#eb4444': 'colorError',
51
57
  '#d9d9d9': 'colorBorder',
52
58
  '#bfbfbf': 'colorBorder',
53
59
  '#e8e8e8': 'colorBorder',
@@ -70,6 +76,7 @@ const TOKEN_MAP = {
70
76
  'rgba(0,0,0,0.45)': 'colorTextTertiary',
71
77
  '#5c6b8a': 'colorTextSecondary',
72
78
  '#5C6B8A': 'colorTextSecondary',
79
+ '#ced5e3': '@colorTextPlaceholder',
73
80
  'rgba(0,0,0,0.25)': 'colorTextQuaternary',
74
81
  'rgba(0,0,0,.85)': 'colorText',
75
82
  'rgba(0,0,0,.65)': 'colorTextSecondary',
@@ -173,6 +180,18 @@ const PROPERTY_TOKEN_MAP = {
173
180
  15: 'fontSizeLG',
174
181
  16: 'fontSizeLG',
175
182
  },
183
+ fontWeight: {
184
+ 300: 'fontWeightWeak',
185
+ 400: 'fontWeight',
186
+ 500: 'fontWeightStrong',
187
+ 600: 'fontWeightStrong',
188
+ },
189
+ borderRadius: {
190
+ 2: 'borderRadiusSM',
191
+ 4: 'borderRadius',
192
+ 6: 'borderRadiusMD',
193
+ 8: 'borderRadiusLG',
194
+ },
176
195
  };
177
196
 
178
197
  function propertyTokenParse(propertyName, value) {