| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 | const fs = require('fs');const path = require('path');const lodash = require('lodash');const { mergeWith } = require("lodash");const isComment = codeLine => lodash.startsWith(codeLine, '//') || lodash.startsWith(codeLine, '/*');const getTokenCategory = codeLine => {    const categorySet = new Set(['color', 'width', 'height', 'spacing', 'radius', 'font', 'motion', "animation", "transition"]);    const firstWord = lodash.get(codeLine.match(/\$([\w\W]+?)[-_]/), 1, { toLowerCase: () => null }).toLowerCase();    if (firstWord) {        return categorySet.has(firstWord) ? firstWord : 'other';    } else {        return 'other';    }};const codeLineSplit = codeLine => {    const [key, value, comment] = codeLine.split(/:|\/\/|\/\*/).map(code => code.trim()).filter(code => code);    let category = getTokenCategory(codeLine);    if (category==='transition') {        category = "animation";    }    return { key, value: lodash.trimEnd(value, ';'), comment: comment && comment.replace("ignore-semi-css-trans", ""), category: category, raw: codeLine };};const getGlobalDesignToken = () => {    const globalScssContentArray = fs.readFileSync(path.join(__dirname, '../packages/semi-theme-default/scss/global.scss'), { encoding: 'utf-8' }).split('\n');    const paletteScssContentArray = fs.readFileSync(path.join(__dirname, '../packages/semi-theme-default/scss/_palette.scss'), { encoding: 'utf-8' }).split('\n');    const animationScssContentArray = fs.readFileSync(path.join(__dirname, '../packages/semi-theme-default/scss/animation.scss'), { encoding: 'utf-8' }).split('\n');    const normalContentArray = fs.readFileSync(path.join(__dirname, '../packages/semi-theme-default/scss/variables.scss'), { encoding: 'utf-8' }).split('\n');    const getLightAndDarkScss = scssFileContentArray => {        const contentArray = scssFileContentArray.map(codeLine => codeLine.trim())            .filter(codeLine => codeLine && !isComment(codeLine))            .filter(codeLine => !codeLine.startsWith('}'))            .filter(codeLine => !codeLine.startsWith('@'));        // {key,value,category,raw};        const rawData = {            light: [],            dark: []        };        let currentMode = 'light';        for (let i in contentArray) {            i = Number(i);            const codeLine = contentArray[i];            if (/body/.test(codeLine)) {                if (/semi-always-dark/.test(codeLine)) {                    currentMode = 'dark';                }                continue;            }            rawData[currentMode].push(codeLineSplit(codeLine));        }        return rawData;    };    let globalScssContent = getLightAndDarkScss(globalScssContentArray);    let paletteContent = getLightAndDarkScss(paletteScssContentArray);    const mergeCommentLightToDark = content => {        const map = new Map();        content.light.forEach(token => {            const { key } = token;            map.set(key, { light: token });        });        content.dark.forEach(token => {            const { key } = token;            const data = map.get(key);            if (!data) {                console.warn(`${key} in dark but not in light`);                return;            }            data.dark = token;        });        Array.from(map.values()).forEach(({ light, dark }) => {            if (!dark.comment) {                dark.comment = light.comment;            }        });        return content;    };    globalScssContent = mergeCommentLightToDark(globalScssContent);    paletteContent = mergeCommentLightToDark(paletteContent);    const normalContent = normalContentArray.map(codeLine => codeLine.trim())        .filter(codeLine => codeLine && !isComment(codeLine))        .map(codeLine => codeLineSplit(codeLine));    const animationContent = animationScssContentArray.map(codeLine => codeLine.trim())        .filter(codeLine => codeLine && !isComment(codeLine))        .filter(codeLine => !codeLine.startsWith('body'))        .filter(codeLine => !codeLine.startsWith('}'))        .filter(codeLine => !codeLine.startsWith('@'))        .map(codeLine=>codeLineSplit(codeLine)).map(token=>{            token.category="animation";            return token;        });    return { global: globalScssContent, palette: paletteContent, normal: normalContent, animation: animationContent };};// 官网组件 design token 注入async function main() {    const componentVariablesMap = {};    const animationVariablesMap = {};    const semiUIDir = path.join(__dirname, '../packages/semi-foundation');    fs.readdirSync(semiUIDir).map(dirname => {        const variableSCSSPath = path.join(semiUIDir, dirname, 'variables.scss');        if (fs.existsSync(variableSCSSPath)) {            const raw = fs.readFileSync(variableSCSSPath, { encoding: 'utf-8' });            const scssCodeLineList = raw.split('\n').filter(codeLine => codeLine && !isComment(codeLine));            componentVariablesMap[dirname.toLowerCase()] = scssCodeLineList.map(codeLine => codeLineSplit(codeLine));        }        const animationSCSSPath = path.join(semiUIDir, dirname, 'animation.scss');        if (fs.existsSync(animationSCSSPath)) {            const raw = fs.readFileSync(animationSCSSPath, { encoding: 'utf-8' });            const scssCodeLineList = raw.split('\n').filter(codeLine => codeLine && !isComment(codeLine));            animationVariablesMap[dirname.toLowerCase()] = scssCodeLineList.map(codeLine => codeLineSplit(codeLine));        }    });    mergeWith(componentVariablesMap, animationVariablesMap, (objValue, srcValue)=>{        if (Array.isArray(objValue)) {            return objValue.concat(srcValue);        }    });    componentVariablesMap.global = getGlobalDesignToken();    const [_, __, savePath] = process.argv;    fs.writeFileSync(savePath || './designToken.json', JSON.stringify(componentVariablesMap));}main();
 |