@babel-AST常用方法

发布时间 2023-05-06 13:21:17作者: Maple_feng

@babel常用方法

一、js对应AST

  1. obj变量名对应Identifier,常量串对应StringLiteral,数字对应NumericLiteral

  2. CallExpression主要关注calleearguments属性,分别表示被调用的函数和参数列表。

  3. MemberExpression主要关注objectpropertycomputed属性,分别表示对象,属性和是否是计算属性。Dot NotationArray Notationcomputed分别为falsetrue

二、@babel/parser方法

  • parser.parse(code, [{options}]):解析一段 JavaScript 代码;

  • parser.parseExpression(code, [{options}]):考虑到了性能问题,解析单个 JavaScript 表达式。

    部分可选参数 options

    参数描述
    allowImportExportEverywhere 默认 importexport 声明语句只能出现在程序的最顶层,设置为 true 则在任何地方都可以声明
    allowReturnOutsideFunction 默认如果在顶层中使用 return 语句会引起错误,设置为 true 就不会报错
    sourceType 默认为 script,当代码中含有 importexport 等关键字时会报错,需要指定为 module
    errorRecovery 默认如果 babel 发现一些不正常的代码就会抛出错误,设置为 true 则会在保存解析错误的同时继续解析代码,错误的记录将被保存在最终生成的 AST 的 errors 属性中,当然如果遇到严重的错误,依然会终止解析

三、@babel/generator方法

可以将 AST 还原成 JavaScript 代码,提供了一个 generate 方法:generate(ast, [{options}], code)

部分可选参数 options

参数描述
auxiliaryCommentBefore 在输出文件内容的头部添加注释块文字
auxiliaryCommentAfter 在输出文件内容的末尾添加注释块文字
comments 输出内容是否包含注释
compact 输出内容是否不添加空格,避免格式化
concise 输出内容是否减少空格使其更紧凑一些
minified 是否压缩输出代码
retainLines 尝试在输出代码中使用与源代码中相同的行号

四、@babel/traverse方法

通常和 visitor 一起使用,visitor 是一个对象,这个名字是可以随意取的,visitor 里可以定义一些方法来过滤节点

path 对象,该对象的类型是 NodePath,该对象有非常多的属性,以下介绍几种最常用的:

属性描述
toString() 当前路径的源码
node 当前路径的节点
parent 当前路径的父级节点
parentPath 当前路径的父级路径
type 当前路径的类型
  • replaceWith:用一个节点替换另一个节点;

  • replaceWithMultiple:用多个节点替换另一个节点;

  • replaceWithSourceString:将传入的源码字符串解析成对应 Node 后再替换,性能较差,不建议使用;

  • replaceInline:用一个或多个节点替换另一个节点,相当于同时有了前两个函数的功能。

五、@babel/types方法

主要用于构建新的 AST 节点或者节点类型判断

const parser = require("@babel/parser");
const generate = require("@babel/generator").default
const traverse = require("@babel/traverse").default
const types = require("@babel/types")

const code = `
const a = 1;
`
const ast = parser.parse(code)
const visitor = {
   //从VariableDeclaration这个节点开始遍历添加
   VariableDeclaration(path) {

       left = types.identifier("b")
       right = types.identifier("a")
       //将左右节点用+符号拼接
       let BinaryExpression = types.binaryExpression("+", left, right)
       //添加到return节点
       let returnStatement = types.returnStatement(BinaryExpression)
       //添加到作用域{}节点
       let BlockStatement = types.blockStatement([returnStatement])
       //添加函数节点,函数名为func,参数为a,b
       declaration = types.functionDeclaration(types.identifier("func"), [types.identifier("a"),types.identifier("b")], BlockStatement)
       path.insertAfter(declaration)

       //将a节点和数字节点用*符号拼接
       left = types.binaryExpression("*", types.identifier("a"), types.numericLiteral(5))
       right = types.numericLiteral(1)
       //将左右节点用+符号拼接
       let value = types.binaryExpression("+", left, right)
       //创建一个变量b,将value赋值于b
       let declarator = types.variableDeclarator(types.identifier("b"), value)
       declaration = types.variableDeclaration("const", [declarator])
       path.insertAfter(declaration) //插入节点

       path.stop() //停止遍历节点
  },

}

traverse(ast, visitor)
const result = generate(ast)
console.log(result.code)
const parser = require("@babel/parser");
const generate = require("@babel/generator").default
const traverse = require("@babel/traverse").default
const types = require('@babel/types');

const code = `
const example = function () {
   let a;
   if (false) {
       a = 1;
   } else {
       if (1) {
           a = 2;
       }
       else {
           a = 3;
       }
   }
   return a;
};
`
const ast = parser.parse(code)

const visitor = {
   enter(path) {
       if (types.isBooleanLiteral(path.node.test) || types.isNumericLiteral(path.node.test)) {
           //判断一定为真,就替换
           //if 对应的是 consequent 节点,else 对应的是 alternate 节点
           if (path.node.test.value) {
               path.replaceInline(path.node.consequent.body); //方法将节点替换成计算结果生成的新节点
          } else {
               if (path.node.alternate) {
                   path.replaceInline(path.node.alternate.body);
              } else {
                   path.remove()
              }
          }
      }
  }
}

traverse(ast, visitor)
const result = generate(ast)
console.log(result.code)