[Vue] Generate JS code based on JSAST
通过前面的代码,其实我们已经完成了从模板AST到Javascript AST的转换
const ast = parse(template);
transform(ast);
那接下来,我们只需要再根据Javascript AST生成具体的js代码就行了,比如再执行下面的函数:
generate(ast.jsnode)
因为我们之前是把JSAST存储在jsnode对象中的。
而这个generate函数,无非也就是拼字符串,根据JSAST中不同的类型,进行不同的字符串拼接就行,当然,还需要注意代码格式。
因此,为了更好的处理代码拼接,我们还是用变量将要拼接的字符串缓存处理,同时为了处理代码格式,我们还是依照之前的处理方式,使用一个上下文对象方便维护代码生成过程中的运行状态:
function generate(node){
const context = {
// 最终生成的渲染代码字符串
code: '',
// 通过调用push函数完成代码拼接
push(code){
context.code += code;
},
// 当前缩进级别,初始值为0,表示没有缩进
currentIndent: 0,
// 用来换行,并且换行后的代码会增加缩进
newline(){
context.push('\n' + ' '.repeat(context.currentIndent));
},
// 缩进函数,让currentIndent自增后,调用newline函数
indent(){
context.currentIndent ++;
context.newline();
},
// 取消缩进函数,让currentIndent自减后,调用newline函数
deIndent(){
context.currentIndent --;
context.newline();
}
}
// 调用genNode完成代码生成工作
genNode(node, context);
// 返回渲染函数代码
return context.code;
}
所以下面的主要问题,就是genNode函数的编写,那也就是根据我们之前JSAST的几种状态去拼接字符串,我们现在直接拼接给context.code就行了
function genNode(node, context) {
switch (node.type) {
case "FunctionDecl":
// 生成函数声明代码
genFunctionDecl(node, context);
break;
case "ReturnStatement":
// 生成return语句代码
genReturnStatement(node, context);
break;
case "CallExpression":
// 生成函数调用代码
genCallExpression(node, context);
break;
case "StringLiteral":
// 生成字符串字面量代码
genStringLiteral(node, context);
break;
case "ArrayExpression":
// 生成数组字面量代码
genArrayExpression(node, context);
break;
}
}
下面就是依次根据类型来拼接字符串
function genFunctionDecl(node, context) {
// 从context中取出够函数
const { push, indent, deIndent } = context;
// 拼接函数名
push(`function ${node.id.name} `);
push(`(`);
// 生成函数参数列表
genNodeList(node.params, context);
push(`) `);
push(`{`);
// 缩进
indent();
// 生成函数体,这里只需要递归调用genNode函数即可
node.body.forEach((n) => genNode(n, context));
// 取消缩进
deIndent();
push(`}`);
}
function genNodeList(nodes, context) {
nodes.forEach((node, index) => {
genNode(node, context);
if (index < nodes.length - 1) {
context.push(`, `);
}
});
}
function genReturnStatement(node, context) {
const { push } = context;
push(`return `);
genNode(node.return, context);
}
function genCallExpression(node, context) {
const { push } = context;
const { callee, arguments: args } = node;
push(`${callee.name}(`);
genNodeList(args, context);
push(`)`);
}
function genStringLiteral(node, context) {
const { push } = context;
push(`'${node.value}'`);
}
function genArrayExpression(node, context) {
const { push } = context;
push("[");
genNodeList(node.elements, context);
push("]");
}
const ast = parse(template);
transform(ast);
console.log(generate(ast.jsNode));

浙公网安备 33010602011771号