less-var-to-css-var
Version:
Convert Less Var To CSS Var
212 lines (164 loc) • 6.18 kB
JavaScript
const fs = require('fs');
const pkg = require('../package.json');
const isExecOnCLI = require.main === module;
// usage
// node index.js -i '~/styles/variables.less' -o '~/styles/variables-css2.less' -t ':root' -h "@import '/src/styles/variables.less';"
const lessVarToCssVar = (opts) => {
let inputPath = undefined;
let outputPath = undefined;
let scopeTag = ':root';
let header = '';
let jsOutputPath = undefined;
let jsVar = 'COLOR';
let jsheader = '';
// 没有传参进来,认为是 node cil 执行,读取 argv
if (!isExecOnCLI && opts) {
console.log(`\n⚡️ less-var-to-css-var via JS (v${pkg.version})\n`);
if (opts.inputPath) inputPath = opts.inputPath;
if (opts.outputPath) outputPath = opts.outputPath;
if (opts.scopeTag) scopeTag = opts.scopeTag;
if (opts.header) header = opts.header;
if (opts.jsOutputPath) jsOutputPath = opts.jsOutputPath;
if (opts.jsVar) jsVar = opts.jsVar;
if (opts.jsheader) jsheader = opts.jsheader;
}
if (isExecOnCLI) {
console.log(`\n⚡️ less-var-to-css-var via CIL (v${pkg.version})\n`);
process.argv.forEach((v, i, arr) => {
if (i < 2) return;
// 找到命令名称,那下一个一定是值
if (v === '-i' && arr[i + 1]) inputPath = arr[i + 1];
if (v === '-o' && arr[i + 1]) outputPath = arr[i + 1];
if (v === '-t' && arr[i + 1]) scopeTag = arr[i + 1];
if (v === '-h' && arr[i + 1]) header = arr[i + 1];
});
}
if (!inputPath || !outputPath || !scopeTag) {
console.log(''.padEnd(32, '-'));
console.log('\n⚠️ Missing Argv!\n');
console.log(''.padEnd(32, '-'));
return;
}
// Avoid too long formatting
const vars = fs.readFileSync(inputPath, 'utf-8').replace(/,\n/g, ',');
const matchs = vars.match(/^@.*/gm);
// eslint-disable-next-line array-callback-return,consistent-return
const allCssVars = matchs.map((m) => {
const mv = m.match(/^@(.*?)\s?:\s?(.*);/m);
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
if (mv && mv[1]) {
return {
key: mv[1] || '',
value: mv[2] || '',
};
}
});
const __CODE_GEN_COMMENT__ = `/\*\n ⚠️ PLEASE DO NOT MODIFY THIS FILE!\n\n All code is automatically generated by plugin \`less-var-to-css-var\`.\n*\/`;
const __ESLINT_STR__ = `/\* eslint-disable max-len \*/`;
//
// output CSS
if (outputPath) {
let ROOT_CSS_HEADER = `${__CODE_GEN_COMMENT__}\n${scopeTag} {\n`;
if (header) {
ROOT_CSS_HEADER = `${__CODE_GEN_COMMENT__}\n${header}\n\n${scopeTag} {\n`;
}
const ROOT_CSS_FOOTER = `}\n`;
let ROOT_CSS_CONTENT = '';
allCssVars.forEach((item) => {
// --screen-md: @screen-md;
if (!item?.key) return;
let val = `@${item.key}`;
// Use real CSS values instead of the --a: @a; mapping
if (opts.useRealValue) {
// 去找一下有没有这个 key 先
let fValue = '';
if (item.value.startsWith('@')) {
const fKey = item.value.replace('@', '');
fValue = allCssVars.find((item) => item?.key === fKey)?.value;
}
val = fValue || `${item.value}`;
}
// Replace the string of the less variable
if (opts.useRealValue && opts.useRealValueFilterLessVar) {
val = /[@]/.test(item.value)
? opts.useRealValueFilterLessVar
: item.value;
}
ROOT_CSS_CONTENT += ` --${item.key}: ${val};\n`;
});
// Dark Css Vars
if (opts.scopeTagDark) {
let DARK_CSS_HEADER = `\n${opts.scopeTagDark} {\n`;
let DARK_CSS_CONTENT = '';
const DARK_CSS_FOOTER = `}\n`;
let ROOT_CSS_CONTENT_CLONE = '';
// get all -auto-.*--dark vars
const darkCssVars = ROOT_CSS_CONTENT?.match(/--.*--dark:.*/gm, '');
ROOT_CSS_CONTENT_CLONE = ROOT_CSS_CONTENT;
// remove all --dark vars
if (opts.removeAllRootDarkVars) {
// ROOT_CSS_CONTENT = ROOT_CSS_CONTENT.replaceAll(/\n.*--.*--dark:.*/gm, '');
ROOT_CSS_CONTENT_CLONE = ROOT_CSS_CONTENT.replaceAll(/\n.*--.*--dark:.*/gm, '');
}
darkCssVars?.forEach((item) => {
if (opts.removeAllDarkDarkSuffix) {
item = item.replace('--dark:', ':');
}
DARK_CSS_CONTENT += ` ${item}\n`;
})
const CSS_RESULT = `${ROOT_CSS_HEADER}${ROOT_CSS_CONTENT_CLONE}${ROOT_CSS_FOOTER}` +
`${DARK_CSS_HEADER}${DARK_CSS_CONTENT}${DARK_CSS_FOOTER}`;
console.log(CSS_RESULT);
// output ROOT + DARK CSS
fs.writeFileSync(outputPath, CSS_RESULT);
// return;
} else {
// output ROOT CSS
fs.writeFileSync(outputPath, `${ROOT_CSS_HEADER}${ROOT_CSS_CONTENT}${ROOT_CSS_FOOTER}`);
}
}
//
// output JS
if (jsOutputPath) {
let JS_HEADER = `${__CODE_GEN_COMMENT__}\n\n${__ESLINT_STR__}\nexport const ${jsVar} = {\n`;
if (header) {
JS_HEADER = `${__CODE_GEN_COMMENT__}\n\n${__ESLINT_STR__}\n${jsheader}\n\nexport const ${jsVar} = {\n`;
}
// KEEP FORMAT ------------
const JS_FOOTER = `};
`;
// KEEP FORMAT ------------
let JS_CONTENT = '';
allCssVars.forEach((item) => {
// --screen-md: @screen-md;
if (!item?.key) return;
// 过滤掉不需要的符号
item.value = item.value.replace(/\\/g, '#'); // e.g. '\5FAE' --> '#5FAE'
item.value = item.value.replace(/~/g, '');
const val = /[@]/.test(item.value)
? `${opts.useRealValueFilterLessVar}`
: item.value;
// If there is a space ` `, use ` ` to enclose it
const wrapVal = val.includes(' ') ? `\`${val}\`` : `\'${val}\'`;
if (opts.jsValueObjectKv) {
JS_CONTENT += ` '--${item.key}': {
key: '--${item.key}',
value: ${wrapVal},
},\n`;
} else {
JS_CONTENT += ` '--${item.key}': ${wrapVal},\n`;
}
});
// all two `''` --> `'`
const result = `${JS_HEADER}${JS_CONTENT}${JS_FOOTER}`.replace(/''/g, "'");
fs.writeFileSync(jsOutputPath, result);
}
console.log(' -', outputPath, '\n');
};
//
//
//
//
if (isExecOnCLI) lessVarToCssVar(); // for CIL
module.exports = lessVarToCssVar;