forked from opentiny/tiny-vue
ci: add automate script to transform demos to add "Tiny" prefix (#1832)
This commit is contained in:
parent
47a74045f5
commit
b32a7007f1
|
@ -7,6 +7,8 @@
|
|||
"scripts": {
|
||||
"start": "esno ./src/index.ts",
|
||||
"scan": "esno ./src/demos-scan.ts",
|
||||
"// ---------- 给文档组件加上Tiny前缀 ----------": "",
|
||||
"doc-prefix": "esno ./src/doc-prefix.ts",
|
||||
"diff": "esno ./src/aui-diff.ts",
|
||||
"add-dep": "esno ./src/add-dependencies.ts",
|
||||
"auto-build-pub": "esno ./src/publish/index.ts"
|
||||
|
@ -22,7 +24,12 @@
|
|||
"sheetjs-style": "^0.15.8",
|
||||
"commander": "^10.0.0",
|
||||
"semver": "^7.3.8",
|
||||
"chalk": "2.4.2"
|
||||
"chalk": "2.4.2",
|
||||
"@babel/parser": "^7.18.13",
|
||||
"@babel/traverse": "^7.18.13",
|
||||
"@babel/generator": "^7.18.13",
|
||||
"@babel/template": "^7.18.13",
|
||||
"@vue/compiler-sfc": "^3.4.21"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
import fg from 'fast-glob'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { parse } from '@vue/compiler-sfc'
|
||||
import { parse as babelParse } from '@babel/parser'
|
||||
import traverse from '@babel/traverse'
|
||||
import generate from '@babel/generator'
|
||||
import * as prettier from 'prettier'
|
||||
import { writeFile } from 'node:fs/promises'
|
||||
import { safeReadFile } from './utils/files'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
const docPath = path.join(__dirname, '../../../examples/sites/demos')
|
||||
|
||||
const generateTraverse = traverse.default
|
||||
|
||||
const addPrefix = async (code) => {
|
||||
const ast = babelParse(code, {
|
||||
sourceType: 'module',
|
||||
plugins: ['typescript', 'jsx']
|
||||
})
|
||||
|
||||
const renameVar = {}
|
||||
generateTraverse(
|
||||
ast,
|
||||
{
|
||||
ImportDeclaration(path) {
|
||||
// 解析@opentiny/vue的引入
|
||||
const depName = path.node?.source?.value
|
||||
if (depName === '@opentiny/vue') {
|
||||
const specifiers = path.node.specifiers
|
||||
specifiers?.forEach((importSpecifier) => {
|
||||
const { local, imported } = importSpecifier
|
||||
if (local.name.startsWith('Tiny')) {
|
||||
if (!imported.name.startsWith('Tiny')) {
|
||||
imported.name = 'Tiny' + imported.name
|
||||
}
|
||||
} else {
|
||||
renameVar[local.name] = 'Tiny' + local.name
|
||||
local.name = 'Tiny' + local.name
|
||||
imported.name = 'Tiny' + imported.name
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
Identifier(path) {
|
||||
const name = path.node.name
|
||||
// 不能用renameVar[name]代替,否则代码中包含原型链上方法会报错
|
||||
/* eslint-disable no-prototype-builtins */
|
||||
if (renameVar.hasOwnProperty(name)) {
|
||||
path.node.name = renameVar[name]
|
||||
}
|
||||
const parent = path.parentPath?.node
|
||||
if (parent.type === 'ObjectProperty') {
|
||||
const { key, value } = parent
|
||||
if (key.name === value.name) {
|
||||
parent.shorthand = true
|
||||
}
|
||||
}
|
||||
},
|
||||
ObjectProperty(path) {
|
||||
const node = path.node
|
||||
const { key, value } = node
|
||||
if (key.name === value.name) {
|
||||
node.shorthand = true
|
||||
}
|
||||
}
|
||||
},
|
||||
{}
|
||||
)
|
||||
let newCode
|
||||
|
||||
newCode = generate.default(ast, { retainLines: true }).code || ''
|
||||
const formatCode = await prettier.format(newCode, {
|
||||
semi: false,
|
||||
parser: 'typescript',
|
||||
singleQuote: true,
|
||||
trailingComma: 'none',
|
||||
'printWidth': 120,
|
||||
'endOfLine': 'auto',
|
||||
'bracketSpacing': true,
|
||||
'jsxBracketSameLine': true
|
||||
})
|
||||
return formatCode
|
||||
}
|
||||
|
||||
const getAttrsString = (attrs) => {
|
||||
let attrStr = ''
|
||||
if (!attrs) {
|
||||
return attrStr
|
||||
}
|
||||
|
||||
Object.keys(attrs).forEach((key) => {
|
||||
const val = attrs[key]
|
||||
if (val === true) {
|
||||
attrStr += ` ${key}`
|
||||
} else {
|
||||
attrStr += ` ${key}="${val}"`
|
||||
}
|
||||
})
|
||||
return attrStr
|
||||
}
|
||||
|
||||
const generateTagContent = (tagDescriptor) => {
|
||||
if (!tagDescriptor) {
|
||||
return ''
|
||||
}
|
||||
const { attrs, content, type } = tagDescriptor
|
||||
return `<${type}${getAttrsString(attrs)}>${content}</${type}>`
|
||||
}
|
||||
|
||||
// 拼接完整的SFC文件
|
||||
const generateSFC = (descriptor) => {
|
||||
const { script, scriptSetup, styles = [], template } = descriptor
|
||||
const contentArr = [
|
||||
generateTagContent(template),
|
||||
generateTagContent(script),
|
||||
generateTagContent(scriptSetup),
|
||||
...styles.map(generateTagContent)
|
||||
]
|
||||
return contentArr.filter((i) => i).join('\n\n') + '\n'
|
||||
}
|
||||
|
||||
// 解析SFC文件,获取其中的script标签内容后转换
|
||||
const transformSFC = async (code) => {
|
||||
const { descriptor } = parse(code)
|
||||
const { script, scriptSetup } = descriptor
|
||||
if (script) {
|
||||
script.content = '\n' + (await addPrefix(script.content)) || script.content
|
||||
}
|
||||
if (scriptSetup) {
|
||||
scriptSetup.content = '\n' + (await addPrefix(scriptSetup.content)) || scriptSetup.content
|
||||
}
|
||||
return generateSFC(descriptor)
|
||||
}
|
||||
|
||||
const transformDemos = async () => {
|
||||
const demoFiles = await fg(['**/*.vue'], {
|
||||
dot: true,
|
||||
cwd: docPath,
|
||||
ignore: ['**/node_modules', '__test__']
|
||||
})
|
||||
|
||||
let handelResolve
|
||||
|
||||
const len = demoFiles.length
|
||||
let finishNum = 0
|
||||
const promise = new Promise((resolve) => {
|
||||
handelResolve = resolve
|
||||
})
|
||||
|
||||
demoFiles.forEach(async (filename, index) => {
|
||||
if (index >= len) return
|
||||
const filePath = path.join(docPath, filename)
|
||||
const fileContent = await safeReadFile(filePath)
|
||||
const newContent = await transformSFC(fileContent)
|
||||
await writeFile(filePath, newContent)
|
||||
++finishNum
|
||||
if (finishNum === len) {
|
||||
handelResolve(finishNum)
|
||||
}
|
||||
})
|
||||
return promise
|
||||
}
|
||||
|
||||
transformDemos().then((finishNum) => {
|
||||
/* eslint-disable no-console */
|
||||
console.log(`${finishNum}个demos组件添加Tiny前缀任务完成`)
|
||||
})
|
Loading…
Reference in New Issue