AST操作之API用法-path路径

This commit is contained in:
aiyingfeng 2023-07-17 18:36:17 +08:00
parent eb825b6502
commit 414311bd0e
6 changed files with 259 additions and 0 deletions

View File

@ -0,0 +1,227 @@
# AST操作之API用法-path路径
## path 路径
`@babel/traverse`模块中path对象表示一个节点node在AST树中的位置提供了一些属性和方法
用于访问节点的属性、子节点、父节点、兄弟节点等并且可以对AST树进行修改。
**下面是一些常见的 path 对象的 API**
| api | 功能 |
|--------------------------|--------------------------------------------------------------------|
| path.node | 获取当前路径对应的节点。 |
| path.parent | 获取当前路径对应节点的父节点。 |
| path.parentPath | 获取当前路径对应节点的父路径。 |
| path.get(key) | 获取当前路径下指定属性名key对应的子路径。例如path.get("body") 获取当前路径下名为 "body" 的子路径。 |
| path.getSibling(index) | 获取当前路径对应节点的兄弟节点的路径。通过指定索引index可以获取相应的兄弟路径。 |
| path.getFunctionParent() | 获取当前路径对应节点的最近的函数父节点的路径。 |
| path.traverse(visitor) | 遍历当前路径下的所有子节点,并应用指定的 visitor。 |
| path.replaceWith(node) | 用指定的节点替换当前路径对应的节点。 |
| path.remove() | 从 AST 中移除当前路径对应的节点。 |
| path.insertBefore(nodes) | 在当前路径对应节点之前插入一个或多个节点。 |
| path.insertAfter(nodes) | 在当前路径对应节点之后插入一个或多个节点。 |
**当前路径所对应的源代码**
需求:打印当前路径所对应的源代码
```javascript
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
let encode_file = "./encode.js";
let js_code = fs.readFileSync(encode_file, {encoding: "utf-8"});
let ast = parse(js_code);
const visitor = {
VariableDeclaration(path)
{
console.log(path.toString());
},
}
traverse(ast, visitor);
```
打印内容:
```javascript
var a = 123;
```
**打印当前路径所对应的某个节点信息**
需求打印type、start、end、loc、sourceType、interpreter、body等信息
![debugger](./img/1.png)
编写代码
```javascript
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
let encode_file = "./encode.js";
let js_code = fs.readFileSync(encode_file, {encoding: "utf-8"});
let ast = parse(js_code);
const visitor = {
Program(path)
{
console.log(path.node.type);
console.log(path.node.start);
console.log(path.node.end);
console.log(path.node.loc);
console.log(path.node.sourceType);
console.log(path.node.interpreter);
console.log(path.node.body);
console.log(path.node.directives);
},
}
traverse(ast, visitor);
```
打印内容:
```javascript
Program
0
12
SourceLocation {
start: Position { line: 1, column: 0, index: 0 },
end: Position { line: 1, column: 12, index: 12 },
filename: undefined,
identifierName: undefined
}
script
null
[
Node {
type: 'VariableDeclaration',
start: 0,
end: 12,
loc: SourceLocation {
start: [Position],
end: [Position],
filename: undefined,
identifierName: undefined
},
declarations: [ [Node] ],
kind: 'var'
}
]
[]
```
**判断path是什么type使用path.isXXX 这个方法**
需求遍历所有节点输出节点类型为NumericLiteral的value值
```javascript
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
let encode_file = "./encode.js";
let js_code = fs.readFileSync(encode_file, {encoding: "utf-8"});
let ast = parse(js_code);
const visitor = {
enter(path)
{
if(path.isNumericLiteral())
{
console.log(path.type);
console.log(path.node.value);
}
},
}
traverse(ast, visitor);
```
打印内容:
```javascript
NumericLiteral
123
```
**获取path的上一级路径path.parentPath;**
需求:获取上一级路径节点类型
```javascript
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
let encode_file = "./encode.js";
let js_code = fs.readFileSync(encode_file, {encoding: "utf-8"});
let ast = parse(js_code);
const visitor = {
enter(path)
{
if(path.isNumericLiteral())
{
console.log('当前节点类型:'+path.type);
console.log('上层节点类型:'+path.parentPath.type);
}
},
}
traverse(ast, visitor);
```
打印内容:
```javascript
当前节点类型:NumericLiteral
上层节点类型:VariableDeclarator
```
**删除path使用remove方法**
需求:删除变量值
```javascript
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;
let encode_file = "./encode.js";
let js_code = fs.readFileSync(encode_file, {encoding: "utf-8"});
let ast = parse(js_code);
const visitor = {
enter(path)
{
if(path.isNumericLiteral())
{
path.remove()
}
},
}
traverse(ast, visitor);
// 写入文件
let {code} = generator(ast);
console.log(code)
fs.writeFile('decode.js', code, (err) => {});
```
打印内容:
```javascript
var a;
```

View File

@ -0,0 +1 @@
var a;

View File

@ -0,0 +1,25 @@
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;
let encode_file = "./encode.js";
let js_code = fs.readFileSync(encode_file, {encoding: "utf-8"});
let ast = parse(js_code);
const visitor = {
enter(path)
{
if(path.isNumericLiteral())
{
path.remove()
}
},
}
traverse(ast, visitor);
// 写入文件
let {code} = generator(ast);
console.log(code)
fs.writeFile('decode.js', code, (err) => {});

View File

@ -0,0 +1 @@
var a = 123;

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -0,0 +1,5 @@
# 参考文档
深入学习 JavaScript 转译器 Babel AST还原混淆代码
https://blog.csdn.net/weixin_52057903/article/details/129131582