@babel-AST常用方法

@babel常用方法

一、js对应AST

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

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

  3. MemberExpression主要关注object、property和computed属性,分别表示对象,属性和是否是计算属性。Dot Notation和Array Notation的computed分别为false和true。

二、@babel/parser方法

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

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

    部分可选参数 options:

    参数描述
    allowImportExportEverywhere 默认 import 和 export 声明语句只能出现在程序的最顶层,设置为 true 则在任何地方都可以声明
    allowReturnOutsideFunction 默认如果在顶层中使用 return 语句会引起错误,设置为 true 就不会报错
    sourceType 默认为 script,当代码中含有 import 、export 等关键字时会报错,需要指定为 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)
 
posted @ 2023-05-06 13:15  Maple_feng  阅读(388)  评论(0)    收藏  举报