-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcodegen.ts
144 lines (125 loc) · 3.1 KB
/
codegen.ts
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
133
134
135
136
137
138
139
140
141
142
143
144
import { isString } from '../shared'
import { NodeTypes } from './ast'
import {
CREATE_ELEMENT_VNODE,
helperMapName,
TO_DISPLAY_STRING,
} from './runtimeHelpers'
export function generate(ast) {
// 生成render函数形式的字符串
const context = createCodegenContext()
const { push } = context
// push(`const {toDisplayString: _toDisplayString } = Vue`)
genFunctionPreamble(ast, context)
const functionName = 'render'
const args = ['_ctx', '_cache']
const signature = args.join(', ')
push(`function ${functionName}(${signature}){`)
push(`return `)
genNode(ast.codegenNode, context)
push('}')
return {
code: context.code,
}
}
function genFunctionPreamble(ast: any, context) {
const { push } = context
const VueBinging = 'Vue'
const aliasHelper = (s) => `${helperMapName[s]}: _${helperMapName[s]}`
if (ast.helpers.length > 0) {
push(`const { ${ast.helpers.map(aliasHelper).join(', ')} } = ${VueBinging}`)
}
push('\n')
push('return ')
}
// 将code放到上下文context,文件全局可以访问
function createCodegenContext() {
const context = {
code: '',
push(source) {
context.code += source
},
helper(key) {
return `_${helperMapName[key]}`
},
}
return context
}
// 生成节点
function genNode(node, context) {
switch (node.type) {
case NodeTypes.TEXT:
genText(node, context)
break
case NodeTypes.INTERPOLATION:
genInterpolation(node, context)
break
case NodeTypes.SIMPLE_EXPERSSION:
genExpression(node, context)
break
case NodeTypes.ELEMENT:
genElement(node, context)
break
case NodeTypes.COMPOUND_EXPRESSION:
getCompoundExpression(node, context)
break
default:
break
}
}
// 生成文本节点
function genText(node: any, context: any) {
const { push } = context
push(`'${node.content}'`)
}
// 生成插值节点
function genInterpolation(node: any, context: any) {
const { push, helper } = context
push(`${helper(TO_DISPLAY_STRING)}(`)
genNode(node.content, context)
push(')')
}
// 生成表达式
function genExpression(node: any, context: any) {
const { push } = context
push(`${node.content}`)
}
// 生成元素节点
function genElement(node, context) {
const { push, helper } = context
const { tag, children, props } = node
push(`${helper(CREATE_ELEMENT_VNODE)}(`)
genNodeList(genNullable([tag, props, children]), context)
// genNode(children, context)
push(')')
}
function genNodeList(nodes, context) {
const { push } = context
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
if (isString(node)) {
push(node)
} else {
genNode(node, context)
}
if(i < nodes.length - 1){
push(', ')
}
}
}
function genNullable(args) {
return args.map((arg) => arg || 'null')
}
// 生成复合类型
function getCompoundExpression(node, context) {
const children = node.children
const { push } = context
for (let i = 0; i < children.length; i++) {
const child = children[i]
if (isString(child)) {
push(child)
} else {
genNode(child, context)
}
}
}