AST使用(一)

news2024/11/22 10:18:04

关于安装及环境配置可以看https://mp.csdn.net/mp_blog/creation/editor/131155968

下面所有案例的JS原代码如下:

const a = 3;
let string = "hello";
for (let i = 0;i < 3;i++){
    string += "world"
}
console.log("string",string)

1.js代码生成ast:     

终端命令   babel-node code/basic1.js 可执行此js文件,code/basic1.js是js文件的路径

import { parse } from "@babel/parser";
import fs from "fs";

const code = fs.readFileSync("code/code1.js","utf-8");
let ast = parse(code);
console.log(ast)

2.ast复原js代码: 

import { parse } from "@babel/parser";
import generate from "@babel/generator";
import fs from "fs";

const code = fs.readFileSync("code/code1.js","utf-8");
let ast = parse(code);

const{ code: output } = generate(ast);
console.log(output)

此外关于generator方法,完整是这样的

const output = generate(ast, { /* options */ }, code)

第二个参数还可以配置一些选项,如下图,第三个参数可以接收原代码进行参考

3.ast中节点的遍历和字面量的修改

  // ast  traverse遍历节点
import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
import fs from "fs";
const code = fs.readFileSync("code/code1.js","utf-8");
let ast = parse(code);
//traverse可以遍历节点
traverse(ast,{
// enter方法是每个节点被遍历时都会调用的方法,path是节点的相关信息,path属于NodePath类型,有node,partent等属性,node属性就是当前节点,partent就是父节点
    enter(path){
        let node = path.node
        if (node.type === "NumericLiteral" && node.value === 3){
            node.value = 5;
        }
        if (node.type === "StringLiteral" && node.value === "hello"){
            node.value = "hi";
        }
    }
});
const{ code: output } = generate(ast);
console.log(output)

输出结果:

const a = 5;
let string = "hi";
for (let i = 0; i < 5; i++) {
  string += "world";
}
console.log("string", string);

可以看出现在的js代码与之前的js代码相比较,a的值由3变成5,string的初始值由hello变成了hi

除了enter方法获取遍历的节点以外,还可以用类型来捕获节点被调用,如下:

  // ast遍历及修改 traverse遍历节点
import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
import fs from "fs";
const code = fs.readFileSync("code/code1.js","utf-8");
let ast = parse(code);

traverse(ast,{
// NumericLiteral方法是每个数字字面量节点被遍历时都会调用的方法,StingLiteral就是字符串字面量
    NumericLiteral(path){
        let node = path.node
        if (node.value === 3){
            node.value = 5;
        }
    },
    StringLiteral(path){
        let node = path.node
        if (node.value === "hello") {
            node.value = "hi";
        }
    },
    
});
const{ code: output } = generate(ast);
console.log(output)

4.ast中语句的删除

我们以删除代码中最后一行console.log("string",string)为例:对应的就是下面圈出来的,只要把它删除就可以

 删除的代码如下

import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
import fs from "fs";
const code = fs.readFileSync("code/code1.js","utf-8");
let ast = parse(code);

traverse(ast,{
    //删除console.log
    ExpressionStatement(path) {
        // ?.是可选链操作符  使用.查找属性时,找不到会报错。  使用?.找不到会返回undefined
        if(path.node?.expression?.callee?.object?.name === "console"){
            path.remove()
        }
    },

});
const{ code: output } = generate(ast);
console.log(output)

删除节点的方法是:path.remove();   

5.ast中的语句的插入和修改

之前的代码是没有const b = a + 1;这句的,现在我想在const a = 3后插入const b = a + 1;这句实现下面的效果

const a = 3;
const b = a + 1;   //这是使用ast插入的代码
let string = "hello";
for (let i = 0;i < 3;i++){
    string += "world"
}
console.log("string",string)

首先,将想要的代码在AST explorer中打开,查看b变量是如何构造的:

 

将其展开后可以查看细节,我们若想构造b变量,就需要阅读官方的API了。

@babel/types · Babel 中文文档 - 印记中文 

 

结合babel/types 的官方API 及 我们在网站中AST得出的结果,可以写出如下代码来构建

let init = types.binaryExpression(
    "+",
    types.identifier("a"),
    types.numericLiteral(1)
);
let declarator = types.variableDeclarator(types.identifier("b"),init);
let declaration = types.variableDeclaration("const",[declarator])

完整的插入及替换代码:

import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
import * as types from "@babel/types";
import fs from "fs";
const code = fs.readFileSync("code/code1.js","utf-8");
let ast = parse(code);

traverse(ast,{
    VariableDeclaration(path){
        console.log(11111)
        //通过下列判断找到const a = 3所在的节点
        if(path.node?.kind === "const" && path.node?.declarations[0]?.id?.name === "a" && path.node?.declarations[0]?.init?.value === 3){
            let init = types.binaryExpression(
            "+",
            types.identifier("a"),
            types.numericLiteral(1)
            );
            let declarator = types.variableDeclarator(types.identifier("b"),init);
            let declaration = types.variableDeclaration("const",[declarator]);
            path.insertAfter(declaration);  //使用insertAfter插入节点
            path.stop()  //找到了就不再找了,类似于循环中的break
            // path.replaceWith(declaration)//替换为新的节点
            // path.remove() // 删除当前节点
            // let copyNode = types.cloneNode(path.node);//复制当前节点
            // traverse(copyNode, {
            //     enter(path){
            //         console.log(333333);
            //     }
            // }, {}, path);// 对子树进行遍历和替换,不影响当前的path
        };
    },
});
const{ code: output } = generate(ast);
console.log(output)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习QA之卷积神经网络

深度学习Q&A之卷积神经网络 前言1 卷积基础知识问题1 简述卷积的基本操作&#xff0c;并分析其与全连接层的区别 &#xff08;难度&#xff1a; ★ \bigstar ★&#xff09;分析与解答&#xff1a; ♣ \clubsuit ♣ 局部连接: ♣ \clubsuit ♣ 权值共享: ♣ \clubsuit ♣ 输…

ubuntu 20.04 aarch64 平台交叉编译 opencv

编译环境 win10 64 位 VMware Workstation Pro 16 虚拟机 虚拟机安装 ubuntu 20.04 opencv 版本&#xff1a; 来自 github 当前最新 4.7 目的 交叉编译 opencv&#xff0c;用于 嵌入式 aarch64 平台 下载 opencv 可以直接从 github 下载 release 版本或者 使用 git clon…

『2023北京智源大会』6月9日上午|开幕式及全体大会

『2023北京智源大会』6月9日上午|开幕式及全体大会 文章目录 一. 黄铁军丨智源研究院院长1. 大语言模型2. 大语言模型评测体系FlagEval3. 大语言模型生态(软硬件)4. 三大路线通向 AGI(另外2条路径) 二. Towards Machines that can Learn, Reason, and Plan(杨立昆丨图灵奖得主…

Spring Boot整合JPA

文章目录 一、Spring Boot整合JPA&#xff08;一&#xff09;创建Spring Boot项目JPADemo&#xff08;二&#xff09;创建ORM实体类1、创建评论实体类 - Comment2、创建文章实体类 - Article &#xff08;三&#xff09;创建自定义JpaRepository接口 - ArticleRepository&#…

【Flutter】Flutter 中处理 loading 状态

文章目录 一、引言二、在 Flutter 中处理 loading 状态三、用具体业务逻辑代码示例展示四、常见问题及解决方案五、结语 一、引言 今天我们将一起探讨在 Flutter 中如何控制 loading 状态。 Flutter&#xff0c;作为一个高效、简洁的 UI 框架&#xff0c;已经在全球范围内得到…

FPGA基础知识-数据流建模

目录 学习目标 学习内容 1.门的类型 2.门延迟 学习时间 学习小结 学习目标 学习Verilog 提供的门级原语 理解门的实例引用、门的符号以及andor&#xff0c;bufnot类型的门的真值表 学习如何根据电路的逻辑图来生成verilog描述 讲述门级设计中的上升、下降和关断延迟 …

【MyBatis学习】MyBatis操纵数据库进行查询操作 ?MyBatis与JDBC想比怎么样,赶快与我一起探索吧 ! ! !

前言: 大家好,我是良辰丫,从今天开始我们就要进入MyBatis的学习了,请君与我一起操纵数据库,MyBatis到底是什么呢?我们慢慢往下瞧! ! !&#x1f48c;&#x1f48c;&#x1f48c; &#x1f9d1;个人主页&#xff1a;良辰针不戳 &#x1f4d6;所属专栏&#xff1a;javaEE进阶篇之…

前端——自定义组件

目录 一、创作纪念日——6月7日&#xff08;机缘巧合&#xff09; 二、收获 三、前端组件 3.1、重要的CSS 3.2、实用组件 1、站点访问次数 2、鼠标样式 3、烟花点击特效 4、GIF动态小人&#xff08;出现在左下角&#xff09; 5、天气插件 6、音乐播放器 3.3、CSS组…

leetcode337. 打家劫舍 III(java)

打家劫舍 leetcode337. 打家劫舍 III题目描述 暴力递归解题思路代码演示 递归加缓存代码演示 动态规划专题 leetcode337. 打家劫舍 III 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/house-robber-iii 题目描述 小偷又…

湖南大学CS-2019期末考试解析

【特别注意】 答案来源于@wolf 是我在备考时自己做的,仅供参考,若有不同的地方欢迎讨论。 【试卷评析】 有必要一做。 【试卷与答案】 一. 填空题(10 分,每空 2 分) 1. 0xb1e56f07 存放在采用小端存储的机器上,地址为 0x3287 到 0x328a ,则 0x3288 处存…

远程仓库拉不下来怎么办

因为项目需要做一个word转pdf的功能, 当我想要从阿里的仓库引入依赖时发现版本一直报错,无论怎么引入都爆红😭😭 *我将aspose的包先下载到本地,然后再安装安装到本地的maven仓库* mvn install:install-file -Dfile=C:\Users\Administrator\Downloads\aspose-words-18.…

Day01 项目简介分布式基础概念 -谷粒商城

最近在改进公司开发的商城项目&#xff0c;看到了尚硅谷的谷粒商城&#xff0c;就快速学习了下&#xff0c;因为之前的Kafka,Redis都是在这学习的&#xff0c;还有大数据的Flink。所以感觉一定不错&#xff0c;就开始了。 这里做一下学习笔记 一、项目简介 1 、项目背景 1 &…

一文看懂分布式存储 Ceph 架构原理

【摘要】本文带你层层深入Ceph的架构原理、读写原理&#xff0c;从而理解Ceph的特性及其应用场景。 1. 什么是Ceph&#xff1f; 首先&#xff0c;我们从 Ceph的官方网站上&#xff0c;可以看到&#xff1a;“Ceph is a unified, distributed storage system designed for exc…

第六章volatile详解

文章目录 volatile修饰的变量有2大特点volatile的内存语义 内存屏障是什么内存屏障分类粗分两种细分四种 什么叫保证有序性happens-before之volatile变量规则JMM就将内存屏障插入策略分为4种规则 volatile特性如何保证可见性说明例子volatile变量的读写过程 为何没有原子性例子…

软件测试“学历低”?10条人生逆袭建议

最近有粉丝私信问我“我学历低&#xff0c;投的简历屡屡石沉大海&#xff0c;不知道该怎么办&#xff1f;”之前也回答过其他人&#xff0c;今天把我的建议整理分享给大家。 学历是一块敲门砖&#xff0c;它会影响毕业以后的我们相当长一段时间&#xff0c;但并不是决定了我们…

fiddler抓包番外————了解工具栏

前言 作为一款功能强大的工具&#xff0c;Fiddler 提供了许多实用的功能和工具栏&#xff0c;可以帮助用户更加高效地使用它。 如果您想了解 Fiddler 的工具栏及其功能&#xff0c;那么本篇文章就是为您准备的。 在这里&#xff0c;我将为大家详细介绍 Fiddler 的工具栏及其…

Redis缓存预热、缓存穿透、缓存击穿、缓存雪崩,Redis布隆过滤器怎么实现?

目录 一、缓存预热1、缓存预热常见步骤2、代码实现 二、缓存雪崩1、什么情况会发生缓存雪崩&#xff1f;2、Redis缓存集群实现高可用3、如何避免Redis缓存雪崩&#xff1f; 三、缓存穿透1、什么情况会发生缓存穿透&#xff1f;2、如何避免Redis缓存穿透&#xff1f; 四、通过空…

Vue中如何实现轮播图、滑块选择器

Vue中如何进行滑动组件实现 在Vue应用中&#xff0c;滑动组件是一个常见的UI组件&#xff0c;例如轮播图、滑块选择器等等。本文将介绍如何使用Vue实现这些滑动组件。 轮播图 轮播图是一种常用的滑动组件&#xff0c;它通常用于展示多个图片或广告。在Vue中&#xff0c;我们可…

【人工智能里的数学】多元函数的微分学

【人工智能里的数学】多元函数的微分学 系列文章目录 【人工智能学习笔记】人工智能里的数学——概述 【人工智能里的数学】一元函数微分学 【人工智能里的数学】线性代数基础 【人工智能里的数学】多元函数微分学 文章目录 文章目录 系列文章目录文章目录偏导数高阶偏导数梯…

论文笔记--LIMA: Less Is More for Alignment

论文笔记--LIMA: Less Is More for Alignment 1. 文章简介2. 文章概括3 文章重点技术3.1 表面对齐假设(Superfacial Alignment Hypothesis)3.2 对齐数据3.3 训练 4 数值实验5. 文章亮点5. 原文传送门6. References 1. 文章简介 标题&#xff1a;LIMA: Less Is More for Alignm…