designToken.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. const fs = require('fs');
  2. const path = require('path');
  3. const lodash = require('lodash');
  4. const isComment = codeLine => lodash.startsWith(codeLine, '//') || lodash.startsWith(codeLine, '/*');
  5. const getTokenCategory = codeLine => {
  6. const categorySet = new Set(['color', 'width', 'height', 'spacing', 'radius', 'font', 'motion']);
  7. const firstWord = lodash.get(codeLine.match(/\$([\w\W]+?)-/), 1, { toLowerCase: () => null }).toLowerCase();
  8. if (firstWord) {
  9. return categorySet.has(firstWord) ? firstWord : 'other';
  10. } else {
  11. return 'other';
  12. }
  13. };
  14. const codeLineSplit = codeLine => {
  15. const [key, value, comment] = codeLine.split(/:|\/\/|\/\*/).map(code => code.trim()).filter(code => code);
  16. return { key, value: lodash.trimEnd(value, ';'), comment, category: getTokenCategory(codeLine), raw: codeLine };
  17. };
  18. const getGlobalDesignToken = () => {
  19. const globalScssContentArray = fs.readFileSync(path.join(__dirname, '../packages/semi-theme-default/scss/global.scss'), { encoding: 'utf-8' }).split('\n');
  20. const paletteScssContentArray = fs.readFileSync(path.join(__dirname, '../packages/semi-theme-default/scss/_palette.scss'), { encoding: 'utf-8' }).split('\n');
  21. const normalContentArray = fs.readFileSync(path.join(__dirname, '../packages/semi-theme-default/scss/variables.scss'), { encoding: 'utf-8' }).split('\n');
  22. const getLightAndDarkScss = scssFileContentArray => {
  23. const contentArray = scssFileContentArray.map(codeLine => codeLine.trim())
  24. .filter(codeLine => codeLine && !isComment(codeLine))
  25. .filter(codeLine => !codeLine.startsWith('}'))
  26. .filter(codeLine => !codeLine.startsWith('@'));
  27. // {key,value,category,raw};
  28. const rawData = {
  29. light: [],
  30. dark: []
  31. };
  32. let currentMode = 'light';
  33. for (let i in contentArray) {
  34. i = Number(i);
  35. const codeLine = contentArray[i];
  36. if (/body/.test(codeLine)) {
  37. if (/semi-always-dark/.test(codeLine)) {
  38. currentMode = 'dark';
  39. }
  40. continue;
  41. }
  42. rawData[currentMode].push(codeLineSplit(codeLine));
  43. }
  44. return rawData;
  45. };
  46. let globalScssContent = getLightAndDarkScss(globalScssContentArray);
  47. let paletteContent = getLightAndDarkScss(paletteScssContentArray);
  48. const mergeCommentLightToDark = content => {
  49. const map = new Map();
  50. content.light.forEach(token => {
  51. const { key } = token;
  52. map.set(key, { light: token });
  53. });
  54. content.dark.forEach(token => {
  55. const { key } = token;
  56. const data = map.get(key);
  57. if (!data) {
  58. console.warn(`${key} in dark but not in light`);
  59. return;
  60. }
  61. data.dark = token;
  62. });
  63. Array.from(map.values()).forEach(({ light, dark }) => {
  64. if (!dark.comment) {
  65. dark.comment = light.comment;
  66. }
  67. });
  68. return content;
  69. };
  70. globalScssContent = mergeCommentLightToDark(globalScssContent);
  71. paletteContent = mergeCommentLightToDark(paletteContent);
  72. const normalContent = normalContentArray.map(codeLine => codeLine.trim())
  73. .filter(codeLine => codeLine && !isComment(codeLine))
  74. .map(codeLine => codeLineSplit(codeLine));
  75. return { global: globalScssContent, palette: paletteContent, normal: normalContent };
  76. };
  77. // 官网组件 design token 注入
  78. async function main() {
  79. const componentVariablesMap = {};
  80. const semiUIDir = path.join(__dirname, '../packages/semi-foundation');
  81. fs.readdirSync(semiUIDir).map(dirname => {
  82. const variableSCSSPath = path.join(semiUIDir, dirname, 'variables.scss');
  83. if (fs.existsSync(variableSCSSPath)) {
  84. const raw = fs.readFileSync(variableSCSSPath, { encoding: 'utf-8' });
  85. const scssCodeLineList = raw.split('\n').filter(codeLine => codeLine && !isComment(codeLine));
  86. componentVariablesMap[dirname.toLowerCase()] = scssCodeLineList.map(codeLine => codeLineSplit(codeLine));
  87. }
  88. });
  89. componentVariablesMap.global = getGlobalDesignToken();
  90. const [_, __, savePath] = process.argv;
  91. fs.writeFileSync(savePath || './designToken.json', JSON.stringify(componentVariablesMap));
  92. }
  93. main();