@mypaas/hcm-cli
Version:
Vant Cli 是一个 Vue 组件库构建工具,通过 Vant Cli 可以快速搭建一套功能完备的 Vue 组件库。
163 lines (162 loc) • 8.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertCssVar = void 0;
const fs_extra_1 = require("fs-extra");
const less_1 = require("less");
const VariablesOutput = require('less-plugin-variables-output');
// 禁用文件级 css 变量转换
const TO_CSS_VAR_DISABLE_COMMENT = '/* to-css-var-disable */';
// 开启文件级 css 变量转换
const TO_CSS_VAR_ENABLE_COMMENT = '/* to-css-var-enable */';
// 禁用行级 css 变量转换
const TO_CSS_VAR_DISABLE_NEXT_LINE_COMMENT = '// to-css-var-disable-next-line';
// 强制开启行级 css 变量转换
const TO_CSS_VAR_ENABLE_NEXT_LINE_COMMENT = '// to-css-var-enable-next-line';
async function convertCssVar(file) {
const source = await fs_extra_1.readFile(file, 'utf-8');
// 将所有 less 变量保存为 json
await less_1.render(source, {
plugins: [
new VariablesOutput({
filename: file,
}),
],
});
const variables = await fs_extra_1.readJSON(file);
const { css } = await less_1.render(source, {
filename: file,
plugins: [
{
install({ tree: { Call, Anonymous, Expression, Ruleset, Declaration, Selector, Element, Combinator, Comment, Color, Variable, }, visitors, }, manager, functions) {
const call = (name, ...args) => new Call(name, [new Expression(args)]);
const disableIndexMap = {};
const enableIndexMap = {};
const disabledConfig = {};
const addDisableIndex = (value, disabled) => {
if (value instanceof Variable) {
if (disabled) {
disableIndexMap[value._index] = true;
}
else {
enableIndexMap[value._index] = true;
}
}
if (Array.isArray(value)) {
value.forEach((v) => {
addDisableIndex(v, disabled);
});
}
else if (value.value) {
addDisableIndex(value.value, disabled);
}
};
class Visitor {
constructor() {
this.native = new visitors.Visitor(this);
this.isPreEvalVisitor = true;
this.isReplacing = true;
this.root = new Ruleset([new Selector([new Element(new Combinator(' '), ':root')], [])], []);
this.return = false;
this.root.appendRule = this.appendRule.bind(this.root);
}
appendRule(rule) {
const { rules } = this;
if (rules) {
const index = rules.findIndex((d) => d.name === rule.name);
if (index >= 0) {
rules[index] = rule;
return;
}
rules.push(rule);
}
else {
this.rules = [rule];
}
this.setParent(rule, this);
}
run(root) {
return this.native.visit(root);
}
visitOperation(node) {
return call('calc', node.operands[0], new Anonymous(node.op), node.operands[1]);
}
visitComment(commentNode) {
if (!commentNode.isLineComment &&
commentNode.value === TO_CSS_VAR_DISABLE_COMMENT) {
disabledConfig[commentNode._fileInfo.filename] =
commentNode._index;
}
else if (!commentNode.isLineComment &&
commentNode.value === TO_CSS_VAR_ENABLE_COMMENT) {
delete disabledConfig[commentNode._fileInfo.filename];
}
return commentNode;
}
visitDeclaration(node) {
if (!(typeof node.name === 'string') || !node.name.match(/^@/)) {
return node;
}
const cssVariableName = node.name.replace(/^@/, '--hcm-');
const declaration = new Declaration(cssVariableName, node.value);
const comment = new Comment(`${node.name}: var(${node.name.replace(/^@/, '--hcm-')});`);
const prevNode = node.parent.rules[node.parent.rules.indexOf(node) - 1];
// 添加 css 转换控制注释
if (prevNode instanceof Comment) {
if (prevNode.value === TO_CSS_VAR_DISABLE_NEXT_LINE_COMMENT) {
addDisableIndex(node.value, true);
}
else if (prevNode.value === TO_CSS_VAR_ENABLE_NEXT_LINE_COMMENT) {
addDisableIndex(node.value, false);
}
}
if (node.parent.root ||
(node.parent.parent &&
node.parent.parent.type === 'Media' &&
node.parent.parent.parent.root)) {
this.root.appendRule(declaration);
if (!this.return) {
this.return = true;
return [this.root, new Comment(), comment];
}
return [node, comment];
}
return declaration;
}
visitNegative(node) {
return call('calc', new Anonymous('-1'), new Anonymous('*'), node.value);
}
visitVariable(node) {
const replaceFunc = () => call('var', new Anonymous(node.name.replace(/^@/, '--hcm-')));
// 如果当前变量上一行已开启禁用时,不转换为 css 变量
if (node._index in disableIndexMap)
return node;
// 行 enable 优先于文件级转换禁用条件
if (node._index in enableIndexMap)
return replaceFunc();
// 当前索引之前已开启文件级 css 转换禁用时,不转换为 css 变量
if (disabledConfig[node._fileInfo.filename] &&
disabledConfig[node._fileInfo.filename] < node._index)
return node;
return replaceFunc();
}
}
manager.addVisitor(new Visitor());
const originalFade = functions.get('fade');
functions.add('fade', function (color, count) {
// 处理变量模式
if (color.type && color.type === 'Call') {
const varName = color.args && color.args[0] && color.args[0].value;
const value = variables[varName.replace(/^--hcm-/, '')];
// 将颜色值转换为颜色对象
const colorValue = new Color(value.replace(/^#(.+)$/g, '$1'));
return originalFade(colorValue, count);
}
return originalFade(color, count);
});
},
},
],
});
await fs_extra_1.writeFile(file, css, 'utf-8');
}
exports.convertCssVar = convertCssVar;