AST抽象语法树学习笔记

736 阅读2分钟

最基础的javascript重点知识,我的理解就是把一个方法,一个声明变量等代码,拆解成一棵树,我们进入方法就是访问(visitor)这棵树,每个属性就是树的节点,既然知道如何用AST访问这棵树,那么相应的也可以用来修改这棵树,比如修改方法名,变量名啥的,例如可用recast来实现一个源码修改工具

实战:实现简单的babel插件:修改变量名, 把所有变量名为a的变成b

1、新建文件夹,babel-plugin-import,建一个test.js文件做测试,node_modeles文件夹下再建一个babel-plugin-import,里面放一个index,js和package.json文件

步骤:

​ a、首先我们要找到定义变量的地方,然后判断变量名是不是a,如果是就把它换成b

​ b、找到定义变量的语句,节点类型是VariableDeclarator,

​ c、VariableDeclarator 的id.name属性就是变量名

2、登陆ast语法树在线生成网站esprima.org/demo/parse.…

var a =45 生成的语法树:

{ "type": "Program", "body": [ { "type": "VariableDeclaration", "declarations": [ { "type": "VariableDeclarator", "id": { "type": "Identifier", "name": "a" }, "init": { "type": "Literal", "value": 45, "raw": "45" } } ], "kind": "var" } ], "sourceType": "script" }

3、 index.js文件:module.exports=({types})=>({

​ VariableDeclarator(path,state){

​ var { node, parent} = path;

​ var { id,type,start,end ,init} = node;

​ if(id.name == 'a'){

​ // ast语法树想改变某个值,就是用对应的ast来换。所以要构建b的Identifier

​ path.node.id = types.identifier('b'); // 用 "path.node.id" 而不能直接用解构的"id"

​ }

​ },

})

4、test.js文件测试:

​ var code1 ="var a = 45";

​ console.log(transformcode(code1));

function transformcode(code){

var ast = babel.transform(code,{

​ plugins:["import"] // 使用自己编写的 babel-plugin-import插件

}).ast;

//transformFromAst AST转码

return babel.transformFromAst(ast,null,{babelrc:true,extends:path.resolve(__dirname,'./.babelrc')}).code;

}

执行 node test.js ,输出 var b = 45,执行成功~

5、其他:@babel/core 是babel的核心包 Babel.transform(code, options,function(){ Result }); Transform 函数可以传入code,返回转换后的代码

所以写插件的思路:1、确认修改的节点类型,2、找到修改的节点属性,3、根据旧的ast构建新的ast并替换

构建ast 结合babel type和 AST explorer