-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
132 lines (129 loc) · 5.49 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
const fs = require('fs')
const promisify = require('util').promisify
const templateStr = [
'<template>',
'\t<div v-if="isShow" class="skeleton-wrapper">',
'\t\tskeletonContent',
'\t</div>',
'</template>'
].join('\n')
const scriptStr = [
'<script>',
'export default {',
'\tname: "Skeleton",',
'\tprops: {',
'\t\tisShow:{',
'\t\t\ttype: Boolean,',
'\t\t\tdefault: false',
'\t\t}',
'\t}',
'}',
'</script>'
].join('\n')
const styleStr = [
'<style scoped>',
'cssContent',
'</style>'
].join('\n')
function generateTemplate(htmlAst, hasScrollerColumn = false) {
htmlAst = htmlAst.filter(item => item.type === 'element')
let skeletonContentStr = ''
htmlAst.forEach(htmlItem => {
let classValues = ['skeleton-block']
let ultiStyleArray = []
const classes = htmlItem.attributes && htmlItem.attributes.filter(item => item.key === 'class') || []
const styles = htmlItem.attributes && htmlItem.attributes.filter(item => item.key === 'style') || []
const dataVs = htmlItem.attributes && htmlItem.attributes.filter(item => /data-v-([\w\W]+)/.test(item.key)) || []
if (classes.length > 0) {
let classValue = classes[0].value
classValue = classValue.replace(/weex-(\w*)\s/g, '')
const classArray = classValue.split(" ")
if (hasScrollerColumn && classArray.includes('weex-scroller-inner')) {
ultiStyleArray.push("flexDirection: 'column'")
}
if (classArray.includes('weex-scroller-vertical')) {
hasScrollerColumn = true
} else {
hasScrollerColumn = false
}
classValue = classArray.map(item => {
if (/sk-([\w\-]*)/.test(item) || /weex-([\w\-]*)/.test(item)) {
return item
} else {
return dataVs.length > 0 ? dataVs.map(v => `${item}-${v.key}`).join(' ') : item
}
}).join(' ')
classValues.push(classValue)
}
if (styles.length > 0) {
const styleValue = styles[0].value
let styleArray = styleValue.trim().split(';')
if (!/\w/.test(styleArray[styleArray.length - 1])) {
styleArray.pop()
}
styleArray = styleArray.filter(item => !/url\(([^\)]*)\)/.test(item)).map(item => {
const theMap = item.split(':')
const key = theMap[0]
const value = theMap[1]
const ultiKey = key.replace(/\-[a-z]/g, (a, l) => a.toUpperCase().replace('-', ''))
return `${ultiKey}: '${value.trim()}'`
})
ultiStyleArray = ultiStyleArray.concat(styleArray)
}
let styleStr = ultiStyleArray.length > 0 ? `:style="{${ultiStyleArray.join(',')}}"` : 'styleContent'
skeletonContentStr += `<div class="${classValues.join(' ')}" ${styleStr}>`.replace(/\sstyleContent/, '').replace(/skeleton-block\s/g, '')
if (htmlItem.children && htmlItem.children.length > 0) {
skeletonContentStr += generateTemplate(htmlItem.children, hasScrollerColumn)
}
skeletonContentStr += '</div>'
})
return skeletonContentStr
}
function processStyle(cssAst, stringify) {
const currentRules = cssAst.stylesheet.rules
let ultiRules = currentRules.filter((item) => {
return item.selectors && item.selectors.every(selectItem => {
return selectItem !== 'html' && !/body([\:\w]*)/.test(selectItem) && !['.weex-ct', '.weex-div'].includes(selectItem)
})
}).map(item => {
item.declarations = item.declarations.map(declareItem => {
const valueMatch = declareItem.value.match(/([\.\d]+)rem/)
if (valueMatch) {
declareItem.value = `${Number(valueMatch[1]) * 75}px`
}
// thanos不支持important css语法
declareItem.value = declareItem.value.replace(/(\s*)!important/, '')
return declareItem
})
item.selectors = item.selectors.map((selectItem) => {
// 处理.container[data-v-507ee5e2]类型的选择器
const dataVMatch = selectItem.match(/\[([\w\d\-]+)\]/)
if (dataVMatch) {
selectItem = selectItem.replace(dataVMatch[0], `-${dataVMatch[1]}`)
}
let selectItemStrs = selectItem.split(/\s?\./)
const ultiSelectorStr = selectItemStrs[selectItemStrs.length - 1]
selectItem = /^\./.test(selectItem) ? `.${ultiSelectorStr}` : ultiSelectorStr
return selectItem
})
return item
})
cssAst.stylesheet.rules = ultiRules
return stringify(cssAst)
}
module.exports = async function generateSkeletonComponent(astInfo, route, projectDir) {
const htmlAst = astInfo.html.ast
const cssAst = astInfo.css.ast
const cssStringify = astInfo.css.stringify
let skeletonContent = generateTemplate(htmlAst)
let template = templateStr.replace('skeletonContent', skeletonContent)
let style = styleStr.replace('cssContent', processStyle(cssAst, cssStringify))
let skeletonComponent = [template, scriptStr, style].join('\n')
const outDir = `${projectDir}/src${route.replace(/\/([^.\/]+).html/, '')}`
if (!fs.existsSync(outDir)) {
await promisify(fs.mkdir)(outDir)
}
const outputFilePath = `${outDir}/skeleton.vue`
await promisify(fs.writeFile)(outputFilePath, skeletonComponent, { encoding: 'utf-8' })
return skeletonComponent
}