1 | const parse5 = require('parse5')
|
2 | const acorn = require('acorn')
|
3 | const escodegen = require('escodegen')
|
4 |
|
5 | function 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 |
|
29 | function 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 |
|
54 | function 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 |
|
84 | function 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 |
|
128 | }
|
129 | }
|
130 |
|
131 | }
|
132 | }
|
133 | if (one.childNodes && one.childNodes.length) {
|
134 | parseAttrs(one.childNodes, map)
|
135 | }
|
136 | })
|
137 |
|
138 | }
|
139 |
|
140 | function 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 |
|
147 | exports.parse = parse
|
148 |
|
149 | function 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 |
|
164 | function 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 |