UNPKG

gulp-convert-css-var

Version:

convert css variable to refer value, and add it to the top of corresponding css rule.

162 lines (135 loc) 4.88 kB
let through = require('through2') let gutil = require('gulp-util') let PluginError = gutil.PluginError let csstree = require('css-tree') let cssbeautify = require('cssbeautify') // 常量 const PLUGIN_NAME = 'gulp-convert-css-var'; //颜色map let colorMap = {} //检查是否在媒体查询中有dark mode function checkIsDarkRule(ast){ let isDark = false if(!ast) return false csstree.walk(ast, (node) => { if(node.type == 'MediaFeature' && node.name == 'prefers-color-scheme' && node.value.name == 'dark'){ isDark = true } }) return isDark } //检查是否是在body或者root中 function checkIsRootTag(ast){ let isRoot = false if(!ast) return false csstree.walk(ast, (node, item) => { if( (node.type == 'TypeSelector' && node.name == 'body') || (node.type == 'PseudoClassSelector' && node.name == 'root') ){ isRoot = true } }) return isRoot } // 检查是否是单纯的选择器,没有属性选择器之类的。 function checkIsSingleRoot(ast){ let isSingle = false if(!ast) return false csstree.walk(ast, { enter(node, item){ if( (node.type == 'TypeSelector' && node.name == 'body') || (node.type == 'PseudoClassSelector' && node.name == 'root') ){ if(!item.prev && !item.next){ isSingle = true } } } }) return isSingle } function gulpProfixer(){ //创建一个 stream 通道,让每个文件通过 let stream = through.obj(function(file, enc, cb){ //不支持stream if(file.isStream()){ this.emit('error', new PluginError(PLUGIN_NAME, 'It does not support stream for now, contact the developers for further support.')) return cb() } let contents = file.contents.toString() let ast = csstree.parse(contents) csstree.walk(ast,{ visit:'Declaration', enter(node){ //找出变量定义的规则 if( node.property && node.property.match(/^--/) ){ let isMediaDark = checkIsDarkRule(this.atrule), isRootTag = checkIsRootTag(this.rule.prelude), isSingle = checkIsSingleRoot(this.rule.prelude) // 是黑暗模式的变量 if(isMediaDark && isRootTag){ colorMap[`${node.property}_dark`]= node.value } // 是默认模式的变量 else if(!isMediaDark && isSingle){ colorMap[node.property]= node.value } } } }) // 给所有通过变量赋值的颜色多加一个保底的颜色 csstree.walk(ast, function(pnode, item, list) { if(pnode.type == "Declaration"){ let varNames = [] csstree.walk(pnode, function(node) { if(node.type === 'Function' && node.name === 'var'){ // 取出颜色的变量名字 let varName = '' csstree.walk(node, (cnode) => { if(cnode.type == 'Identifier'){ varName = cnode.name varNames.push(cnode.name) } }) } }) // 证明有变量 if(varNames.length){ let cssStyle = csstree.generate(pnode) for(name of varNames){ if(colorMap[name]){ let reg = new RegExp("var\\(\\s*" + name + "\\s*\\)") cssStyle = cssStyle.replace(reg, colorMap[name].value.trim()) } } let rule = { prev: null, next: null, data: csstree.parse(cssStyle, { context:'declaration' }) } list.insert(rule, item) } } }) let css = csstree.generate(ast) let bu = Buffer.from(cssbeautify(css,{ indent: ' ', openbrace: 'end-of-line', autosemicolon: true })) file.contents = bu // 给下一个插件提供文件 this.push(file) // 告诉stream引擎,我们已经处理完成了这个文件 cb() }) return stream } module.exports = gulpProfixer