UNPKG

@mypaas/hcm-cli

Version:

Vant Cli 是一个 Vue 组件库构建工具,通过 Vant Cli 可以快速搭建一套功能完备的 Vue 组件库。

163 lines (162 loc) 8.6 kB
"use strict"; 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;