@babel/traverse 遍历和修改 AST 常用的traverse 方法

1,352 阅读6分钟

@babel/traverse 遍历和修改 AST 常用的traverse 方法

在使用 @babel 编写插件会经常用到 visitor 插件函数参数上的属性 和 API方法。

visitor-function

  • visitor 插件函数 与 babel 解析器一起用于遍历和更新节点
  • visitor 插件函数默认是在开始遍历时调用,可以指定插件回调函数执行时机
traverse(ast, {
 Identifier: {
  enter() {
   console.log("Entered!");
  },
  exit() {
   console.log("Exited!");
  }
 }
});

每种节点类型对应一个 Visitor 函数,这些函数会在 Babel 遍历 AST 时被调用,允许开发者对节点进行分析、修改或替换操作 以下是一些常见的 Visitor 函数及其作用:

  • Program 处理整个程序的顶级节点

  • FunctionDeclaration 处理函数声明节点

  • BinaryExpression 处理二元表达式节点

  • VariableDeclaration 处理变量声明节点

  • ClassDeclaration 处理类声明节点

  • ImportDeclaration 处理导入声明节点

  • ExportDeclaration 处理导出声明节点

  • CallExpression 处理调用表达式节点

  • ConditionalExpression 处理条件表达式节点

  • MemberExpression 处理成员表达式节点

  • Identifier 处理标识符节点

  • Literal 处理字面量节点

  • TemplateLiteral 处理字面量节点

  • JSXElement 处理 JSX 元素节点

  • JSXOpeningElement 处理 JSX 开始元素节点

  • JSXClosingElement 处理 JSX 结束元素节点

  • StringLiteral 处理字符串字面量节点

  • ClassProperty 处理类属性(class properties)的 AST 节点

  • ClassMethod 处理类方法的节点

  • Scopable 该节点是否具有作用域

visitor-path 属性方法

traverse(ast, { FunctionDeclaration(path, state) {} })

visitor 插件函数参数 path 常用属性和方法说明如下:

  • node: 当前 AST 节点。

    • leadingComments:访问 AST 中某个节点之前的注释信息。
    • source.value:访问 AST 中某个节点之前的注释信息。
    • callee: 代表被调用函数的 AST 节点的引用
      • type: 表示节点的类型,通常为 "Identifier"(标识符)或 "MemberExpression"(成员表达式)等
      • name: 如果 path.node.callee.type 是 "Identifier",则表示函数的名称(例如函数名)
      • object: 如果 path.node.callee.type 是 "MemberExpression",则表示成员表达式的对象部分
      • property: 如果 path.node.callee.type 是 "MemberExpression",则表示成员表达式的属性部分(通常是一个标识符节点)
  • parent: 当前 AST 父节点。

  • parentPath: 父 AST 节点的 path。

  • scope: 当前节点的作用域对象,提供了有关变量绑定和作用域链的信息。

    • bindings: 当前作用域内声明的所有变量。
    • block: 当前作用域所在的块级别节点(通常是函数或者块语句)。
    • parent: 当前作用域的父级作用域对象。
    • parentBlock: 当前作用域的父级块级别节点。
    • path: 生成作用域的节点对应的 path。
    • references: 所有 binding 的引用对应的 path。
    • referenced: 该声明是否被引用。
    • dump(): 打印作用域链的所有 binding 到控制台。
    • getAllBindings(): 从当前作用域到根作用域的所有 binding 的合并。
    • getBinding(name): 查找某个 binding,从当前作用域一直查找到根作用域。
    • hasBinding(name): 判断当前作用域是否包含指定名称的绑定(变量或函数)。
    • getOwnBinding(name): 从当前作用域查找 binding。
    • parentHasBinding(name): 找某个 binding,从父作用域查到根作用域,不包括当前作用域。可以通过 noGlobals 参数指定是否算上全局变量(比如 console,不需要声明就可用),默认是 false。
    • removeBinding(name): 移除当前作用域中指定名称的绑定。
    • moveBindingTo(name, scope): 把当前作用域中的某个 binding 移动到其他作用域。
    • generateUid(name): 在当前作用域生成一个唯一的标识符,通常用于生成临时变量名。
    • isPure(node): 判断节点是否是纯函数
    • rename(oldName,newName,blockScoping): 重命名变量或函数
  • context: 提供了有关当前节点的上下文信息,包括插件的配置选项等。

  • hub: 提供了与 Babel 编译过程相关的核心方法和工具,可以通过 path.hub.file 拿到最外层 File 对象, path.hub.getScope 拿到最外层作用域,path.hub.getCode 拿到源码字符串。

  • type: 当前 AST 节点的类型,可以用来识别节点的具体种类(如 Identifier、FunctionDeclaration 等)。

  • container: 当前 AST 节点所在的父节点属性的属性值。

  • key: 当前 AST 节点所在父节点属性的属性名或所在数组的下标。

  • listKey: 当前 AST 节点所在父节点属性的属性值为数组时 listkey 为该属性名,否则为 undefined

  • assertXxx(opts): 同 isXxx,但是不返回布尔值,而是抛出异常。

  • set(key+ , node): 设置某个属性的值。

  • inList():判断节点是否在数组中,如果 container 为数组,也就是有 listkey 的时候,返回 true。

  • get(key): 获取某个属性的 path。

  • getSibling(key): 获取某个下标的兄弟节点。

  • getNextSibling(): 获取下一个兄弟节点。

  • getPrevSibling(): 获取上一个兄弟节点。

  • getAllPrevSiblings(): 获取之前的所有兄弟节点。

  • getAllNextSiblings(): 获取之后的所有兄弟节点。

  • getSource(): 获取当前节点的源代码字符串表示。

  • getStatementParent(): 获取当前节点的语句父级节点。

  • getTypeAnnotation(): 获得声明时的类型。

  • find(callback): 从当前节点到根节点来查找节点(包括当前节点),调用 callback(传入 path)来决定是否终止查找。

  • findParent(callback): 从当前节点到根节点来查找节点(不包括当前节点),调用 callback(传入 path)来决定是否终止查找。

  • inList(nodes): 判断节点是否在数组中,如果 container 为数组,也就是有 listkey 的时候,返回 true。

  • isXxx(opts): 判断当前节点是否是某个类型,可以传入属性和属性值进一步判断,比如 path.isIdentifier({name: 'a'})。

  • insertBefore(nodes): 在当前节点前插入新的 AST 节点,可以是单个节点或者节点数组。

  • insertAfter(nodes): 在当前节点后插入新的 AST 节点可以是单个节点或者节点数组。

  • remove(): 移除当前节点

  • replaceWith(replacement): 用某个节点替换当前节点。

  • replaceWithMultiple(nodes): 用多个节点替换当前节点。

  • replaceWithSourceString(replacement): 解析源码成 AST,然后替换当前节点。

  • traverse(visitor, state): 遍历当前节点及其子节点,并对它们应用访问者对象中定义的操作。

  • skip(): 跳过当前节点的子节点的遍历。

  • stop(): 结束所有遍历。

  • buildCodeFrameError(message, ErrorConstructor): 创建带有代码框架的错误对象。

  • path.get('xxx').toString(): 获取 AST(抽象语法树)中某个节点的标识符(identifier)部分的源代码表示形式。

  • path.get('params'): 获取函数的参数列表

  • path.get('id'): 获取变量声明的标识符

  • path.get('init'): 获取初始赋值的变量

visitor-state 属性和方法

traverse(ast, { FunctionDeclaration(path, state) {} })
  • file: 表示当前正在处理的文件对象,包含有关文件路径、文件内容等信息。

    • file.opts: 包含 Babel 配置文件中的选项。
    • file.code: 当前文件的源代码字符串。
    • file.ast: 当前文件的抽象语法树 (AST) 表示。
  • opts: 表示插件在 Babel 配置文件中的选项。

    • state.opts: 插件的配置选项,可以根据插件需求来自定义配置。
  • filename: 当前正在处理的文件的完整路径。

  • cwd: 当前工作目录的路径。

  • sourceMap: 表示是否启用了源映射(source map)。

  • code: 当前文件的源代码字符串。

  • ast: 当前文件的抽象语法树 (AST) 表示。

  • env: 表示 Babel 编译器的环境信息,如 "devlopment""production"

有错误之处,欢迎指正!❤❤❤