AST之path常用属性和方法总结笔记

news/2024/3/29 1:12:30/文章来源:https://blog.csdn.net/weixin_44327634/article/details/129198966

文章目录

    • 1. path常用属性总结
      • 1.1 path.node
      • 1.2 path.scope
      • 1.3 path.parentPath
      • 1.4 path.parent
      • 1.5 path.container
      • 1.6 path.type
      • 1.7 path.key
    • 2. path常用方法总结
      • 2.1 path.toString
      • 2.2 path.replaceWith
      • 2.3 path.replaceWithMultiple
      • 2.4 path.remove
      • 2.5 path.insertBefore
      • 2.6 path.insertAfter
      • 2.7 path.traverse

这一块儿可参考的总结资料不多,参考着蔡老板的文章学习一下,做下记录总结

1. path常用属性总结

path相关的源代码在这个js文件中,大家可以直接照着源码学习:

\node_modules\@babel\traverse\lib\path

这里选出部分常用的属性供大家参考。

path的属性定义:

class NodePath {constructor(hub, parent) {this.contexts = [];this.state = null;this.opts = null;this._traverseFlags = 0;this.skipKeys = null;this.parentPath = null;this.container = null;this.listKey = null;this.key = null;this.node = null;this.type = null;this.parent = parent;this.hub = hub;this.data = null;this.context = null;this.scope = null;}......
}

1.1 path.node

表示当前path下的node节点,通常写插件,函数体的第一行代码就是:

let {node,scope} = path;

1.2 path.scope

表示当前path下的作用域,这个也是写插件经常会用到的。

具体的可以参考蔡老板这篇文章 : Scope和Binding常用方法及属性总结

scope相关:
1.scope.block   表示当前作用域下的所有node,参考上面的 this.block = node;2.scope.dump()  输出当前每个变量的作用域信息。调用后直接打印,不需要加打印函数3.scope.crawl()   重构scope,在某种情况下会报错,不过还是建议在每一个插件的最后一行加上。4.scope.rename(oldName, newName, block)   修改当前作用域下的的指定的变量名,oldname、newname表示替换前后的变量名,为字符串。注意,oldName需要有binding,否则无法重命名。5.scope.traverse(node, opts, state)遍历当前作用域下的某些(个)插件。和全局的traverse用法一样。6.scope.getBinding(name)获取某个变量的binding,可以理解为其生命周期。包含引用,修改之类的信息
Binding:
目前我看到的只有 变量定义 和 函数定义 拥有binding,其他的获取binding都是undefined。let binding = scope.getBinding(name);
例如:
var a = 123; 这里的 a 就拥有 binding。而 function test(a,b,c) {};函数名test以及形参a,b,c均拥有 binding。1.binding.path用于定位初始拥有binding的path;2.binding.constant用于判断当前变量是否被更改,true表示未改变,false表示有更改变量值。3.binding.referenced用于判断当前变量是否被引用,true表示代码下面有引用该变量的地方,false表示没有地方引用该变量。注意,引用和改变是分开的。4.binding.referencePaths它是一个Array类型,包含所有引用的path,多用于替换。5. binding.constantViolations它是一个Array类型,包含所有改变的path,多用于判断。

例如我们可以利用Scope.getBinding()方法来获取Binding对象, 判断其引用情况来对语法树进行修改,

小例子,需求:想对以下js代码进行修改,删除所有定义了, 却从未使用的变量

var a = 1;
var b = 2;
function squire(){var c = 3;var d = 4;return a * d;var e = 5;
}
var f = 6;

可以这样写插件:

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;const jscode = `
var a = 1;
var b = 2;
function squire(){var c = 3;var d = 4;return a * d;var e = 5;
}
var f = 6;
`;
let ast = parser.parse(jscode);
const visitor = {VariableDeclarator(path){const func_name = path.node.id.name;const binding = path.scope.getBinding(func_name);// 如果变量没有被引用过,那么删除也没关系//   此处不能用有无修改过进行判断,因为没有被修改过并不意味着没用if(binding && !binding.referenced){path.remove();}},
}traverse(ast, visitor);
console.log(generator(ast)['code']);

运行出来的结果:

在这里插入图片描述

1.3 path.parentPath

用于获取当前path下的父path,多用于判断节点类型。

1.4 path.parent

用于获取当前path下的父node,多用于判断节点类型。其中:

path.parent == path.parentPath.node;//这两者是等价的

1.5 path.container

用于获取当前path下的所有兄弟节点(包括自身),container翻译过来是容器的意思,它是一个Array类型,可以写个简单的插件来看看效果:

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;
let jscode = "var a = 1,b = 2;var c = 3;";
let ast = parser.parse(jscode);
const getcontainer  =
{VariableDeclarator(path){console.log(path.toString())console.log(path.container.length);}
}traverse(ast,getcontainer);

在这里插入图片描述

代码中a,b互为兄弟节点,c只有一个节点,所以结果显示2,2,1。

这里要注意,是获取所有的所有兄弟节点(包括自身),不是path类型。

1.6 path.type

用于获取当前path的节点类型,写个简单的插件来看看效果 :

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;
let jscode = "var a = 1 + 3;";
let ast = parser.parse(jscode)
const getType  =
{"VariableDeclarator|BinaryExpression|Identifier"(path){console.log(path.toString());console.log(path.type);}
}traverse(ast,getType);

在这里插入图片描述

1.7 path.key

用于获取当前path的key值,key通常用于path.get函数,当然还有更多的用法等待大家去挖掘 ,写个简单的插件来看看效果 :

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;let jscode = "var a = 1 + 2;";
let ast = parser.parse(jscode)
const getPathKey  =
{"VariableDeclarator|BinaryExpression|Identifier"(path){   console.log('path:',path.toString());console.log(path.key);}
}traverse(ast,getPathKey);

在这里插入图片描述

第一个遍历的 path 是 VariableDeclarator 类型,对应源代码 是 a = 1+2 ;它的父节点是 VariableDeclaration 类型,而它处在 declarations 的第0的位置,因此输出是 0;

第二个遍历的 path 是 Identifier类型,对应源代码 是 a ;它是 id 节点,因此它的输出是 id;

第三个遍历的 path 是 BinaryExpression 类型,对应源代码 是 1+2 ;它是 init 节点,因此它的输出是 init。

2. path常用方法总结

2.1 path.toString

用来获取当前遍历path的js源代码,调用方式:

let sourceCode = path.toString();

这个非常有用,经常用于定于插件遍历的path,以便分析问题。

如果想通过 path.node来获取源代码,可以使用 generator 函数来获取:

let sourceCode = generator(path.node).code;

2.2 path.replaceWith

(单)节点替换函数,调用方式:

path.replaceWith(newNode);

实参一般是 node 类型,即将当前遍历的path替换为 实参里的 新节点。

注意,它不能用于 Array 的替换,即实参不能是Array类型。

2.3 path.replaceWithMultiple

(多)节点替换函数,调用方式:

path.rreplaceWithMultiple(ArrayNode);

实参一般是 Array 类型,它只能用于 Array 的替换。

即所有需要替换的节点在一个Array里面,常见的替换如 Block 类型节点里的 body.body。

2.4 path.remove

节点的删除,调用方式:

path.remove();

直接调用即可将当前遍历的所有符合条件的路径全部删除,所以使用的时候需要注意。

2.5 path.insertBefore

在当前节点前面插入新的节点。调用方式:

path.insertBefore(newNode);

2.6 path.insertAfter

在当前节点后面插入新的节点。调用方式:

path.insertAfter(newNode);

2.7 path.traverse

在当前节点下遍历其他的节点,比如有如下for循环:

for(;;)
{a = b;b = c;c =d;
}

想要遍历这个for循环下面的 赋值语句,可以借助该函数进行遍历:

const visitFor = 
{ForStatement(path){......path.traverse({AssignmentExpression(_path){......},}),......},
}

文章到此结束,感谢您的阅读,下篇文章见!

AST学习课程推荐:
蔡老板和风佬课程:AST入门实战+零基础JavaScript补环境课程
也可以看蔡老板的知识星球学习:AST入门与实战

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_75291.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 蓝牙开发——HCI log 分析(二十)

HCI log 是用来分析蓝牙设备之间的交互行为是否符合预期,是否符合蓝牙规范。对于蓝牙开发者来说,通过 HCI log 可以帮助我们更好地分析问题,理解蓝牙协议。 一、抓取HCI log 1、手机抓取HCI log 在开发者选项中打开启用蓝牙HCI信息收集日志开关,Android系统就开始自动地收…

在中外合作办学硕士领域似乎自己一直在纠结,也许是为了能遇见人大女王金融硕士

2023考研成绩如期而至,还记得考试时的一幕幕吗?在身体被高热侵蚀的情况下,我们似乎很难忘记这次考试所带给我们的经历。如今成绩下来了,可能与我们预期的几乎相同,但是在不断地寻找新的学习途径的过程中我们发现&#…

驾驭云安全:2023年云安全展望

由于其的良好的可扩展性和优质的事件处理效率,云技术已成为现代企业的必备的管理技术之一,目前他已经成为所有行业及企业的热门选择。然而,攻击面积的增加以及不针对云技术衍生出来的多类攻击方式,使许多企业更容易受到威胁和数据…

分层测试(2)单元测试【必备】

1. 什么是单元测试? 对代码中的逻辑隔离的最小代码片段进行测试,验证其逻辑是否符合预期,单元可以是函数,方法,类,功能模块。 2. 单元测试的优点 掌握代码:单元测试允许开发人员了解单元提供…

软件测试之场景法

场景法 1. 概述 1.1 为什么使用场景法设计测试用例 大多数业务软件由后台管理(比如:用户管理、角色管理、权限管理等等各种管理)和工作流等几个部分组成。终端用户,期望软件能够实现业务需求,而不是简单的功能的组合…

2023湖北土建施工员证报考条件考试时间及报考流程 启程别

2023湖北土建施工员证报考条件考试时间及报考流程 启程别 土建施工员证是建设厅七大员中的施工员证的一种。分为土建、装饰装修、市政、设备安装。土建施工员证怎么报考等一系列相关问题启程别告诉你 施工员证报考条件 其实施工员证的报考条件没有那么复杂,基本上年…

智慧扫码点餐系统源码

智慧餐厅扫码点餐小程序系统源码 1. 开发语言:JAVA 2. 数据库:MySQL 3. 原生小程序 4. Saas 模式 5. 带调试部署视频 6、总后台管理端商家端门店端小程序用户端 智慧扫码点餐系统支持多店铺运营,单店铺运营以及连锁店铺运营。系统功能支…

numpy常用操作

文章目录1 numpy库2 数组对象 ndarray2.1 数组对象的创建2.1.1 利用array函数创建ndarray对象2.1.2 np.ones()和np.zeros()函数2.1.3 np.random.rand()函数2.1.4 np.arange()函数2.1.5 np.linspace()函数2.1.6 np.empty()函数2.2 ndarray对象常用属性2.3 ndarray常用操作2.3.1 …

IAP初探

IAP(In-Application Programming)在应用编程,浅显易懂,按照字面意思即是在程序不关闭情况下,对应用进行再次写入程序,对程序的写入需要传输数据,而传输数据的前提是通信, IAP对代码进行更新可以简要分为以…

为什么需要学习shell、shell的作用

课程基于B站于超课程笔记 03 Shebang的正确玩法_哔哩哔哩_bilibili P1 shell的作用 P2 shell执行命令的流程 P3 Shebang的正确玩法 什么是shell及组成 shell概念 shelll组成 Shebang概念 /bin/sh /bin/bash一样,都是指向一个bash解释器 [rootlocalhost ~]#…

医疗床头卡(WIFI方案)

一、产品特性 7.5寸墨水屏显示WIFI无线通信,极简部署,远程控制按键及高亮LED指示灯指示800*480点阵屏幕锂电池供电,支持USB充电DIY界面支持文本/条码/二维码/图片超低功耗/超长寿命,一次充电可用一年基于现有Wifi环境&#xff0c…

Unity EasyObjectPool2.0 对象池插件

效果展示 运行时: 非运行时: 功能列表 支持预加载 支持动态扩容 支持代码新建pool 支持可视化内存管理 支持常规对象池化管理 支持延迟回收 工厂方法和案例 //生成var bullet EasyObjectPool.GetInstance().Spawn( "bullet" );//回收EasyObjectPool.GetInstanc…

模拟微信聊天-课后程序(JAVA基础案例教程-黑马程序员编著-第八章-课后作业)

【案例9-1】 模拟微信聊天 【案例介绍】 1.案例描述 在如今,微信聊天已经人们生活中必不可少的重要组成部分,人们的交流很多都是通过微信来进行的。本案例要求:将多线程与UDP通信相关知识结合,模拟实现微信聊天小程序。通过监…

微电影广告的内容突破方案

微电影作为新媒体时代背景的产物,深受大众的欢迎,同时,微电影广告在微电影模式环境下应运而生,以自己独特的传播优势,俘获了大量企业主的青睐,也获得了广大青年群体的喜爱。微电影广告欲确保可持续发展&…

springboot+pgbouncer+postgres数据库连接池集成方案及问题解决

期望通过每一次分享,让技术的门槛变低,落地更容易。 —— around 前言 旨在解决微服务项目全是连接池并影响数据库并发连接,作者的环境是基于sprongboot微服务连接postgres数据库,每个微服务的DAO层配置都使用了连接池技术。后续…

PGLBox 超大规模 GPU 端对端图学习训练框架正式发布

作者 | PGLBox项目组 导读 PGLBox是百度研发的基于GPU的大规模图模型训练框架,支持数百亿节点和边的图模型全GPU训练,已在百度广泛部署。相比业界主流的分布式 CPU 解决方案,PGLBox 具有超高性能、超大规模、算法丰富、灵活易用、落地广泛等优…

复习知识点十之方法的重载

目录 方法的重载 练习1: 练习1: 数组遍历 练习2: 数组的最大值 练习3: 练习4: 复制数组 基本数据类型和引用数据类型 方法的重载 Java虚拟机会通过参数的不同来区分同名的方法 练习1: public class Test4 {public static void main(String[] args) {//调用方法 // …

【架构师】零基础到精通——服务与网关

博客昵称:架构师Cool 最喜欢的座右铭:一以贯之的努力,不得懈怠的人生。 作者简介:一名Coder,软件设计师/鸿蒙高级工程师认证,在备战高级架构师/系统分析师,欢迎关注小弟! 博主小留言…

Raki的读paper小记:BART

Abstract&Introduction&Related Work 研究任务 预训练语言模型已有方法和相关工作 BERT等面临挑战 已有的方法依赖下游任务创新思路 融合了双向和自回归模型随机打乱原始句子的顺序,并同时使用一种novel的填空方案,文本的span只用一个masked to…

近期常见组件漏洞更新:

(1)mysql 5.7 在2023年1月17日,发布了到5.7.41版本 mysql 8.0 在2023年1月17日,发布了到8.0.32版本 MySQL :: Download MySQL Community Serverhttps://dev.mysql.com/downloads/mysql/ (2)Tomcat8在202…