UNPKG

5.14 kBJavaScriptView Raw
1const parse5 = require('parse5')
2const acorn = require('acorn')
3const escodegen = require('escodegen')
4
5function generateHTML(rs) {
6 try {
7 let processed = escodegen.generate(rs, {
8 format: {
9 semicolons: false,
10 quotes: 'single',
11 compact: false,
12 indent: {
13 style: '',
14 base: 0,
15 adjustMultilineComment: false
16 }
17 }
18 })
19 processed = processed.replace(/;$/, '')
20 .replace(/;\s/g, ' ')
21 .replace('let VALUE = ', '')
22 .replace(/;,/g, ',')
23 .replace(/;]/g, ']')
24 return processed
25 } catch (e) {
26 }
27}
28
29function parseExpression(list, key, map) {
30 list.forEach((one, index) => {
31 let value = one[key] || one
32 if (value.type === 'BinaryExpression') {
33
34 for (let i in value) {
35 if (i === 'left' || i === 'right') {
36 let expression = value[i]
37 if (expression.type === 'CallExpression' && expression.callee && expression.callee.name === '$t' && expression.arguments.length === 1) {
38 value[i] = buildStringExpression(map[expression.arguments[0].value] || expression.arguments[0].value)
39 }
40 }
41 }
42
43 } else if (value.type === 'CallExpression') {
44 const rs = buildStringExpression(map[value.arguments[0].value] || value.arguments[0].value)
45 if (key) {
46 list[index][key] = rs
47 } else {
48 list[index] = rs
49 }
50 }
51 })
52}
53
54function doParseExpression(code, map) {
55 if (typeof code === 'string' && !/\$t/.test(code)) {
56 return
57 }
58 let rs = code
59 if (typeof code === 'string') {
60 rs = acorn.parse(code, {
61 sourceType: 'module'
62 })
63 }
64
65 for (let i = 0; i < rs.body.length; i++) {
66 const one = rs.body[i]
67
68 if (one.type === 'ExpressionStatement' && one.expression.type === 'ArrayExpression') {
69 const elements = one.expression.elements
70 parseExpression(elements, '', map)
71 } else if (one.type === 'ExpressionStatement' && one.expression && one.expression.callee && one.expression.callee.name === '$t' && one.expression.arguments.length === 1 && one.expression.arguments[0].type !== 'BinaryExpression') {
72 one.expression = buildStringExpression(map[one.expression.arguments[0].value] || one.expression.arguments[0].value)
73 } else if (one.type === 'ExpressionStatement') { // 表达式模式
74 parseCallExpression(one.expression, map)
75 } else if (one.type === 'VariableDeclaration') { // 对象类型
76 var properties = one.declarations[0].init.properties
77 parseExpression(properties, 'value', map)
78 } else {
79 }
80 }
81 return rs
82}
83
84function parseAttrs(nodes, map) {
85 nodes.forEach(one => {
86 if (one.nodeName === '#text' && /{{/.test(one.value) && /}}/.test(one.value)) {
87 one.value = one.value.replace(/{{(.*?)}}/g, function (a, b) {
88 if (b.indexOf('$t(') === -1) {
89 return a
90 }
91
92 let rs = acorn.parse(b, {
93 sourceType: 'module'
94 })
95
96 if (rs.body.length === 1 && rs.body[0].expression && rs.body[0].type === 'ExpressionStatement' && rs.body[0].expression.type === 'CallExpression' && rs.body[0].expression.arguments[0].type === 'Literal') {
97 rs = doParseExpression(rs, map)
98 if (!rs) {
99 return a
100 } else {
101 let html = generateHTML(rs)
102 if (html) {
103 html = html.replace(/^'(.*?)'$/, '$1')
104 return html
105 }
106 }
107 } else {
108 return a
109 }
110
111 })
112 }
113 if (one.attrs) {
114 for (let i in one.attrs) {
115 let attr = one.attrs[i]
116
117 if (/\$t/.test(attr.value)) {
118 if (/^:/.test(attr.name) && /^{/.test(attr.value)) {
119 attr.value = 'let VALUE = ' + attr.value
120 }
121
122 let rs = doParseExpression(attr.value, map)
123 let processed = generateHTML(rs)
124 if (processed) {
125 attr.value = processed
126 } else {
127 // stay unchanged
128 }
129 }
130
131 }
132 }
133 if (one.childNodes && one.childNodes.length) {
134 parseAttrs(one.childNodes, map)
135 }
136 })
137
138}
139
140function parse(code, map) {
141 const documentFragment = parse5.parseFragment(code)
142 parseAttrs(documentFragment.childNodes, map)
143 const html = parse5.serialize(documentFragment)
144 return html
145}
146
147exports.parse = parse
148
149function parseCallExpression (expression, map) {
150 for (let i in expression) {
151 if (i === 'left' || i === 'right') {
152 let currentExpression = expression[i]
153 if (currentExpression.type === 'CallExpression' && currentExpression.callee && currentExpression.callee.name === '$t' && currentExpression.arguments.length === 1) {
154 expression[i] = buildStringExpression(map[currentExpression.arguments[0].value] || currentExpression.arguments[0].value)
155 } else {
156 if (currentExpression.type === 'BinaryExpression') {
157 parseCallExpression(currentExpression, map)
158 }
159 }
160 }
161 }
162}
163
164function buildStringExpression(value) {
165 return {
166 "type": "ExpressionStatement",
167 "expression": {
168 "type": "Literal",
169 "value": value,
170 "raw": "'" + value + "'"
171 }
172 }
173}
\No newline at end of file