forked from opentiny/tiny-vue
145 lines
4.3 KiB
JavaScript
145 lines
4.3 KiB
JavaScript
|
import gulp from 'gulp'
|
|||
|
import fs from 'fs-extra'
|
|||
|
import transform from 'gulp-transform'
|
|||
|
import xlsx from 'node-xlsx'
|
|||
|
import aliasCompName from './themeJson.alias.mjs'
|
|||
|
|
|||
|
const build = gulp.series(parseVars, writeJson, buildExcel)
|
|||
|
build.description = '生成theme.json 和 themeExcel文件'
|
|||
|
|
|||
|
export default build
|
|||
|
|
|||
|
// 指定哪些目录的`vars.less`不需要处理
|
|||
|
const ignoreNames = ['src', 'base']
|
|||
|
// css规则的正则: '--color: var(--color);' => [str, --color, var(--color)]
|
|||
|
const ruleReg = /([\w|\-|_]*): *([\w|\-|\_|(|)]*);/
|
|||
|
|
|||
|
function formatRule(name, key, value, desc) {
|
|||
|
const hasHide = desc.includes('(hide)')
|
|||
|
desc = desc.replace('(hide)', '')
|
|||
|
|
|||
|
return `
|
|||
|
"${key}": {
|
|||
|
"id": "${key}",
|
|||
|
"key": "${key}",
|
|||
|
"variable": "${value}",
|
|||
|
"value": "${value}",
|
|||
|
"desc": "${desc}",
|
|||
|
"descEn": "${desc}",
|
|||
|
"component": "${name}",
|
|||
|
"componentDesc": "",
|
|||
|
"componentDescEn": "",
|
|||
|
"selector": ".tiny-${name}",
|
|||
|
"type": "",
|
|||
|
"group": "",
|
|||
|
"isImportant": "false",
|
|||
|
"ui": "",
|
|||
|
"show": 1,
|
|||
|
"configurable": ${hasHide ? 0 : 1},
|
|||
|
"isOpen": true
|
|||
|
},`
|
|||
|
}
|
|||
|
|
|||
|
// 处理一个vars.less文件
|
|||
|
function parseFile(component) {
|
|||
|
const name = aliasCompName[component.name] || component.name
|
|||
|
let formated = []
|
|||
|
let lessLines = component.content.split('\n')
|
|||
|
lessLines = lessLines.map((line) => line.trim())
|
|||
|
|
|||
|
// 以 .component-css.........为起点行搜索。没找到,则跳出
|
|||
|
let startRow = 0
|
|||
|
while (startRow < lessLines.length && !lessLines[startRow].startsWith('.')) {
|
|||
|
startRow++
|
|||
|
}
|
|||
|
if (startRow === lessLines.length) {
|
|||
|
return []
|
|||
|
}
|
|||
|
let desc = '未知变量'
|
|||
|
|
|||
|
for (let row = startRow + 1; row < lessLines.length; row++) {
|
|||
|
const line = lessLines[row]
|
|||
|
// 跳过空行
|
|||
|
if (line.length === 0) continue
|
|||
|
// 注释行
|
|||
|
if (line.startsWith('//')) {
|
|||
|
desc = line.slice(2).trim()
|
|||
|
continue
|
|||
|
}
|
|||
|
// 规则行
|
|||
|
const matches = line.match(ruleReg)
|
|||
|
if (matches) {
|
|||
|
if (desc === '未知变量') component.noDescCount++
|
|||
|
|
|||
|
let [_, key, value] = matches
|
|||
|
formated.push(formatRule(name, key, value, desc))
|
|||
|
desc = '未知变量'
|
|||
|
}
|
|||
|
}
|
|||
|
component.ruleCount = formated.length
|
|||
|
return formated
|
|||
|
}
|
|||
|
|
|||
|
const components = []
|
|||
|
// 解析每个文件,将结果保存到 components 数据
|
|||
|
function parseVars() {
|
|||
|
return gulp.src('packages/theme/src/**/vars.less').pipe(
|
|||
|
transform('utf8', (content, fileObj) => {
|
|||
|
const path = fileObj.path
|
|||
|
const name = path.split('\\').slice(-2)[0]
|
|||
|
if (!ignoreNames.includes(name)) {
|
|||
|
components.push({
|
|||
|
name,
|
|||
|
content: parseFile({ name, content, ruleCount: 0, noDescCount: 0 })
|
|||
|
})
|
|||
|
}
|
|||
|
return '' // 不写文件
|
|||
|
})
|
|||
|
)
|
|||
|
}
|
|||
|
|
|||
|
// 将 components 数据写入文件
|
|||
|
function writeJson(cb) {
|
|||
|
// 此处应用使用reduce插件来合并结果。 但gulp的reduce不好用。
|
|||
|
const parsed = components.map((comp) => comp.content).flat()
|
|||
|
let writedContent = parsed.join('').slice(1, -1) // 去除最后一个逗号
|
|||
|
writedContent = `{\n${writedContent}\n}`
|
|||
|
fs.writeFileSync('packages/theme/scripts/theme.json', writedContent)
|
|||
|
cb()
|
|||
|
}
|
|||
|
|
|||
|
const titleArr = (
|
|||
|
'id,key,variable(可选),value(可选),desc,descEn,component,componentDesc,componentDescEn,' +
|
|||
|
'selector,type,group,isImportant,ui(所属的框架),show,configurable'
|
|||
|
).split(',')
|
|||
|
const fileName = 'themeExcel'
|
|||
|
|
|||
|
export function buildExcel(cb) {
|
|||
|
let themeData = fs.readFileSync('packages/theme/scripts/theme.json', 'utf-8').toString()
|
|||
|
themeData = JSON.parse(themeData)
|
|||
|
const openXlsxObj = {} // 输出: {button:[ [标题行], [每一个变量的一行值] ]}
|
|||
|
Object.values(themeData)
|
|||
|
.filter((item) => item.isOpen)
|
|||
|
.forEach((item) => {
|
|||
|
delete item.isOpen
|
|||
|
item.ui = '@opentiny/vue'
|
|||
|
openXlsxObj[item.component] = openXlsxObj[item.component]
|
|||
|
? [...openXlsxObj[item.component], Object.values(item)]
|
|||
|
: [titleArr, Object.values(item)]
|
|||
|
})
|
|||
|
// 输出: [ {name:button, data:[ [],[] ]}]
|
|||
|
const excelData = Object.entries(openXlsxObj).map(([key, value]) => {
|
|||
|
return { name: key + '配置化', data: value }
|
|||
|
})
|
|||
|
|
|||
|
// 写excel
|
|||
|
const buffer = xlsx.build(excelData)
|
|||
|
fs.writeFile(`packages/theme/scripts/${fileName}.xlsx`, buffer, (err) => {
|
|||
|
if (err) {
|
|||
|
return console.warn(`写入${fileName}失败`)
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
cb()
|
|||
|
}
|