AST操作之API用法-path路径

This commit is contained in:
aiyingfeng 2023-07-18 12:17:33 +08:00
parent a4a2cb5513
commit b6281e129e
4 changed files with 125 additions and 104 deletions

View File

@ -5,10 +5,16 @@
`@babel/traverse`模块中path对象表示一个节点node在AST树中的位置提供了一些属性和方法 `@babel/traverse`模块中path对象表示一个节点node在AST树中的位置提供了一些属性和方法
用于访问节点的属性、子节点、父节点、兄弟节点等并且可以对AST树进行修改。 用于访问节点的属性、子节点、父节点、兄弟节点等并且可以对AST树进行修改。
`path`相关的源代码在这个js文件中
```javascript
\node_modules\@babel\traverse\lib\path
```
**下面是一些常见的 path 对象的 API** **下面是一些常见的 path 对象的 API**
| api | 功能 | | api | 功能 |
|--------------------------|--------------------------------------------------------------------| |--------------------------------|--------------------------------------------------------------------|
| path.node | 获取当前路径对应的节点。 | | path.node | 获取当前路径对应的节点。 |
| path.parent | 获取当前路径对应节点的父节点。 | | path.parent | 获取当前路径对应节点的父节点。 |
| path.parentPath | 获取当前路径对应节点的父路径。 | | path.parentPath | 获取当前路径对应节点的父路径。 |
@ -20,6 +26,12 @@
| path.remove() | 从 AST 中移除当前路径对应的节点。 | | path.remove() | 从 AST 中移除当前路径对应的节点。 |
| path.insertBefore(nodes) | 在当前路径对应节点之前插入一个或多个节点。 | | path.insertBefore(nodes) | 在当前路径对应节点之前插入一个或多个节点。 |
| path.insertAfter(nodes) | 在当前路径对应节点之后插入一个或多个节点。 | | path.insertAfter(nodes) | 在当前路径对应节点之后插入一个或多个节点。 |
| path.insertAfter(nodes) | 在当前路径对应节点之后插入一个或多个节点。 |
| path.scope | 表示当前path下的作用域这个也是写插件经常会用到的。 |
| path.container | 用于获取当前path下的所有兄弟节点(包括自身)。 |
| path.type | 获取当前path的节点类型。 |
| path.key | 获取当前path的key值key通常用于path.get函数。 |
| path.toString() | 用于将 AST 节点转换回对应的源代码字符串。 |
**当前路径所对应的源代码** **当前路径所对应的源代码**
@ -36,8 +48,7 @@ let js_code = fs.readFileSync(encode_file, {encoding: "utf-8"});
let ast = parse(js_code); let ast = parse(js_code);
const visitor = { const visitor = {
VariableDeclaration(path) VariableDeclaration(path) {
{
console.log(path.toString()); console.log(path.toString());
}, },
} }
@ -60,18 +71,8 @@ var a = 123;
编写代码 编写代码
```javascript ```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 = { const visitor = {
Program(path) Program(path) {
{
console.log(path.node.type); console.log(path.node.type);
console.log(path.node.start); console.log(path.node.start);
console.log(path.node.end); console.log(path.node.end);
@ -92,28 +93,64 @@ traverse(ast, visitor);
Program Program
0 0
12 12
SourceLocation { SourceLocation
start: Position { line: 1, column: 0, index: 0 }, {
end: Position { line: 1, column: 12, index: 12 }, start: Position
{
line: 1, column
:
0, index
:
0
}
,
end: Position
{
line: 1, column
:
12, index
:
12
}
,
filename: undefined, filename: undefined,
identifierName: undefined identifierName
:
undefined
} }
script script
null null
[ [
Node { Node
{
type: 'VariableDeclaration', type: 'VariableDeclaration',
start: 0, start
end: 12, :
loc: SourceLocation { 0,
end
:
12,
loc
:
SourceLocation
{
start: [Position], start: [Position],
end: [Position], end
filename: undefined, :
identifierName: undefined [Position],
}, filename
declarations: [ [Node] ], :
kind: 'var' undefined,
identifierName
:
undefined
} }
,
declarations: [[Node]],
kind
:
'var'
}
] ]
[] []
``` ```
@ -123,20 +160,9 @@ null
需求遍历所有节点输出节点类型为NumericLiteral的value值 需求遍历所有节点输出节点类型为NumericLiteral的value值
```javascript ```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 = { const visitor = {
enter(path) enter(path) {
{ if (path.isNumericLiteral()) {
if(path.isNumericLiteral())
{
console.log(path.type); console.log(path.type);
console.log(path.node.value); console.log(path.node.value);
} }
@ -159,22 +185,11 @@ NumericLiteral
需求:获取上一级路径节点类型 需求:获取上一级路径节点类型
```javascript ```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 = { const visitor = {
enter(path) enter(path) {
{ if (path.isNumericLiteral()) {
if(path.isNumericLiteral()) console.log('当前节点类型:' + path.type);
{ console.log('上层节点类型:' + path.parentPath.type);
console.log('当前节点类型:'+path.type);
console.log('上层节点类型:'+path.parentPath.type);
} }
}, },
} }
@ -194,20 +209,9 @@ traverse(ast, visitor);
需求:删除变量值 需求:删除变量值
```javascript ```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 = { const visitor = {
enter(path) enter(path) {
{ if (path.isNumericLiteral()) {
if(path.isNumericLiteral())
{
path.remove() path.remove()
} }
}, },
@ -218,8 +222,10 @@ traverse(ast, visitor);
// 写入文件 // 写入文件
let {code} = generator(ast); let {code} = generator(ast);
console.log(code) console.log(code)
fs.writeFile('decode.js', code, (err) => {}); fs.writeFile('decode.js', code, (err) => {
});
``` ```
打印内容: 打印内容:
```javascript ```javascript
@ -266,3 +272,28 @@ var a = 3;
``` ```
注意点,必须加上`&& path.node.value == 123`判断,否则就是无限循环 注意点,必须加上`&& path.node.value == 123`判断,否则就是无限循环
**获取当前path的key值**
需求打印节点VariableDeclarator|BinaryExpression|Identifier的key值
```javascript
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
let js_code = "var a = 1 + 2;";
let ast = parse(js_code, {
sourceType: 'module',
});
const visitor = {
"VariableDeclarator|BinaryExpression|Identifier"(path) {
console.log(path.key)
},
}
traverse(ast, visitor);
```
![debugger](./img/2.png)

View File

@ -1 +1 @@
var a = 3; var a = 123;

View File

@ -1,26 +1,16 @@
const fs = require('fs');
const {parse} = require("@babel/parser"); const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default; 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 js_code = "var a = 1 + 2;";
let ast = parse(js_code, { let ast = parse(js_code, {
sourceType: 'module', sourceType: 'module',
}); });
const visitor = { const visitor = {
enter(path) { "VariableDeclarator|BinaryExpression|Identifier"(path) {
if (path.isNumericLiteral() && path.node.value == 123) { console.log(path.key)
path.replaceWith({type: "NumericLiteral", value: 3});
}
}, },
} }
traverse(ast, visitor); traverse(ast, visitor);
// 写入文件
let {code} = generator(ast);
console.log(code)
fs.writeFile('decode.js', code, (err) => {
});

View File

@ -1 +1 @@
var a = 123; let jscode = "var a = 1 + 2;";