AST(抽象语法树)是对 JS 代码抽象语法结构的表示,Babel 可以帮我们把代码解析成 AST,方便我们进行转换,操作,生成。社区的 eslint,代码转换工具 taro 等,都离不开 AST 进行操作。下面整理下 AST 常见的使用方法。
创建 AST
Babel 提供了 @babel/parser
的 parse
方法进行代码字符串解析,可以创建 AST 对象。
const parser = require("@babel/parser");const code = `const a = 5;`;const ast = parser.parse(code, { sourceType: "module" });
遍历 AST
有了 AST 对象之后,就可以使用 @babel/traverse
库进行遍历,该库方便我们在不同类型节点进行操作。
比如我们要把代码 const a = 5;
中的 a 替换成 b,可以这样操作:
const traverse = require("@babel/traverse").default;traverse(ast, { Identifier(path) { // 替换name path.node.name = "b"; },});
或者 const a = 1 + 2;
替换成 const a = 3;
const traverse = require("@babel/traverse").default;const t = require("@babel/types");traverse(ast, { BinaryExpression(path) { // 替换name path.replaceWith(t.numericLiteral(3)); },});
生成新的代码
有了修改后的 AST 对象,我们可以使用 @babel/generator
库生成新的代码。
const generator = require("@babel/generator").default;const { code } = generator(ast);console.log(code); // const a = 3;
下面是完整的代码示例
const parser = require("@babel/parser");const traverse = require("@babel/traverse").default;const generator = require("@babel/generator").default;const code = "const a = 5;";const ast = parser.parse(code, { sourceType: "module" });traverse(ast, { Identifier(path) { // 替换name path.node.name = "b"; },});const { code: output } = generator(ast);console.log(output); // const b = 5;
我们也可以自己通过 @babel/template
创建模板字符串生成代码,通过占位符来注入动态变量。
const proxyAst = template.ast( ` new Proxy($0, { get: function(target, key) { return target[key] || 0; } })`, { placeholderPattern: /^\$\d+/, preserveComments: true, });const objectStr = "People";proxyAst.expression.arguments[0].name = objectStr;const ProxyCode = generator(proxyAst).code;console.log(ProxyCode); // new Proxy(People, { get: function(target, key) { return target[key] || 0; } })