写点什么

Babel 插件开发 & 访问节点

作者:小鑫同学
  • 2022-10-12
    北京
  • 本文字数:1697 字

    阅读完需:约 6 分钟

Babel 插件开发&访问节点

1. 前言

大家好,我是小鑫同学。一位从事过 Android 开发混合开发,现在长期从事前端开发的编程爱好者,我觉得在编程之路上最重要的是知识的分享,所谓三人行必有我师。所以我开始在社区持续输出我所了解到、学习到、工作中遇到的各种编程知识,欢迎有想法、有同感的伙伴加我fe-xiaoxin微信交流~


整理一下 Babel 插件开发时用得到的转换操作相关的 API~

2. 访问节点

2.1 获取子节点的 Path:

我们在处理节点的属性之前必须要拿到节点对象才能进行操作,我们使用path.node.property来访问属性~


BinaryExpression(path) {  path.node.left;  path.node.right;  path.node.operator;}
复制代码


我们还可以使用 path 内置的 get 函数来指定属性名获取属性值~


BinaryExpression(path) {  path.get('left');}Program(path) {  path.get('body.0');}
复制代码

2.2 检查节点的类型:

检查节点的类型我们可以使用内置的工具类函数isXxx()~


BinaryExpression(path) {  if (t.isIdentifier(path.node.left)) {    // ...  }}
复制代码


我们在检查类型的时候还可以顺便检查其中的某些属性是否达到预期~


BinaryExpression(path) {  if (t.isIdentifier(path.node.left, { name: "n" })) {    // ...  }}
// 简化前的代码BinaryExpression(path) { if ( path.node.left != null && path.node.left.type === "Identifier" && path.node.left.name === "n" ) { // ... }}
复制代码

2.3 检查路径(Path)类型:

路径具有相同的方法检查节点的类型~


BinaryExpression(path) {  if (path.get('left').isIdentifier({ name: "n" })) {    // ...  }}
// 等价于BinaryExpression(path) { if (t.isIdentifier(path.node.left, { name: "n" })) { // ... }}
复制代码

2.4 检查标识符(Identifier)是否被引用:

Identifier(path) {  if (path.isReferencedIdentifier()) {    // ...  }}
// 或者
Identifier(path) { if (t.isReferenced(path.node, path.parent)) { // ... }}
复制代码

2.5 找到特定的父路径:

向上查找特定节点可以使用~


path.findParent((path) => path.isObjectExpression());
复制代码


如果也需要遍历当前节点~


path.find((path) => path.isObjectExpression());
复制代码


查找最接近的父函数或程序~


path.getFunctionParent();
复制代码


向上遍历语法树,直到找到在列表中的父节点路径~


path.getStatementParent();
复制代码

2.6 获取同级路径:

如果一个路径是在一个 FunctionProgram中的列表里面,它就有同级节点。


  • 使用path.inList来判断路径是否有同级节点,

  • 使用path.getSibling(index)来获得同级路径,

  • 使用 path.key获取路径所在容器的索引,

  • 使用 path.container获取路径的容器(包含所有同级节点的数组)

  • 使用 path.listKey获取容器的 key


这些 API 用于 babel-minify 中使用的 transform-merge-sibling-variables 插件.


var a = 1; // pathA, path.key = 0var b = 2; // pathB, path.key = 1var c = 3; // pathC, path.key = 2
复制代码


export default function({ types: t }) {  return {    visitor: {      VariableDeclaration(path) {        // if the current path is pathA        path.inList // true        path.listKey // "body"        path.key // 0        path.getSibling(0) // pathA        path.getSibling(path.key + 1) // pathB        path.container // [pathA, pathB, pathC]      }    }  };}
复制代码

2.7 停止遍历:

当我们遍历完成目的后应该尽早结束而不是继续遍历下去~


BinaryExpression(path) {  if (path.node.operator !== '**') return;}
复制代码


如果您在顶级路径中进行子遍历,则可以使用 2 个提供的 API 方法~


path.skip()跳过遍历当前路径的子路径~


path.stop()完全停止遍历~


outerPath.traverse({  Function(innerPath) {    innerPath.skip(); // if checking the children is irrelevant  },  ReferencedIdentifier(innerPath, state) {    state.iife = true;    innerPath.stop(); // if you want to save some state and then stop traversal, or deopt  }});
复制代码



如果看完觉得有收获,欢迎点赞、评论、分享支持一下。你的支持和肯定,是我坚持写作的动力~

发布于: 刚刚阅读数: 5
用户头像

小鑫同学

关注

⚡InfoQ签约作者 2018-12-10 加入

还未添加个人简介

评论

发布
暂无评论
Babel 插件开发&访问节点_前端_小鑫同学_InfoQ写作社区