抽象语法树(Abstract Syntax Tree)
webpack和Lint等很多工具和库的核心都是通过Abstract Syntax Tree这个概念来实现对代码的检查,分析等操作的。通过了解Abstract Syntax Tree这个概念。就可以实现自己手写类似工具。
ast
esprima
- 解析语法 js=> 语法树
estraverse
- 遍历树 (深度优先)=> 更改树的内容
escodegen
- 把语法树生成新的内容
栗子 改变方法名
let esprima =require('esprima');
let estraverse = require('estraverse');
let escodegen = require('escodegen');
// 先声明一个方法
let code = `function a (){}`;
// 通过esprima生成AST
let tree = esprima.parseScript(code);
// {
// "type": "Program",
// "body": [
// {
// "type": "FunctionDeclaration",
// "id": {
// "type": "Identifier",
// "name": "a"
// },
// "params": [],
// "body": {
// "type": "BlockStatement",
// "body": []
// },
// "generator": false,
// "expression": false,
// "async": false
// }
// ],
// "sourceType": "script"
// }
// 通过estraverse遍历和更新AST
// 通过enter和leave的顺序我们可以看出这是个深度优先的实现
estraverse.traverse(tree,{
enter(node){
if(node.type==='Identifier'){
node.name='fly'
}
console.log('enter'+node.type);
},
leave(node){
console.log('leave'+node.type);
}
});
// enterProgram
// enterFunctionDeclaration
// enterIdentifier
// leaveIdentifier
// enterBlockStatement
// leaveBlockStatement
// leaveFunctionDeclaration
// leaveProgram
// 通过escodegen将AST重新生成源码
let r = escodegen.generate(tree);
console.log(r)
// function fly() {
// }
babel 插件 babel-plugin-arrow-function
// 直接用babel实现
// babel-core 转化
// 改AST babel-types
let babel = require('babel-core');
let types = require('babel-types');
// 生成AST
// 判断节点类型
let code = `let sum = (a,b)=>{return a=b}`;
let arrowPlugin = {
visitor:{
// path 是AST的路径
ArrowFunctionExpression(path){
let node = path.node;
let params = node.params;
let body = node.body;
// 如果不是代码块
if(!types.isBinaryExpression){
let returnStatement = types.returnStatement;
body=types.blockStatement([returnStatement])
}
// 生成一个函数表达式
let funcs = types.functionExpression(null,params,body,false,false);
// 重写替换
path.replaceWith(funcs);
}
}
};
let r = babel.transform(code,{
plugins:[
arrowPlugin
]
});
console.log(r.code);