mirror of
https://github.com/luzhisheng/js_reverse.git
synced 2025-04-20 10:25:01 +08:00
Merge branch 'master' of github.com:luzhisheng/js_reverse
This commit is contained in:
commit
dce06701b7
312
AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/README.md
Normal file
312
AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/README.md
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
# AST操作之API用法-path路径-path属性-path方法
|
||||||
|
|
||||||
|
## path 路径
|
||||||
|
|
||||||
|
在`@babel/traverse`模块中,path对象表示一个节点(node)在AST树中的位置,提供了一些属性和方法,
|
||||||
|
用于访问节点的属性、子节点、父节点、兄弟节点等,并且可以对AST树进行修改。
|
||||||
|
|
||||||
|
读取js代码并转换为ast树
|
||||||
|
|
||||||
|
```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, {
|
||||||
|
sourceType: 'module',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## path 属性
|
||||||
|
|
||||||
|
`path`属性相关的源代码在这个js文件中
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
\node_modules\@babel\traverse\lib\path
|
||||||
|
```
|
||||||
|
|
||||||
|
**下面是一些常见的path对象的属性API:**
|
||||||
|
|
||||||
|
| api | 功能 |
|
||||||
|
|--------------------------------|--------------------------------------------------------------------|
|
||||||
|
| path.node | 获取当前路径对应的节点。 |
|
||||||
|
| path.parent | 获取当前路径对应节点的父节点。 |
|
||||||
|
| path.parentPath | 获取当前路径对应节点的父路径。 |
|
||||||
|
| path.scope | 表示当前path下的作用域,这个也是写插件经常会用到的。 |
|
||||||
|
| path.container | 用于获取当前path下的所有兄弟节点(包括自身)。 |
|
||||||
|
| path.type | 获取当前path的节点类型。 |
|
||||||
|
| path.key | 获取当前path的key值,key通常用于path.get函数。 |
|
||||||
|
|
||||||
|
**1.打印当前路径所对应的某个节点信息**
|
||||||
|
|
||||||
|
需求:打印type、start、end、loc、sourceType、interpreter、body等信息
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
编写代码
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
[]
|
||||||
|
```
|
||||||
|
|
||||||
|
**2.判断path是什么type,使用path.isXXX 这个方法**
|
||||||
|
|
||||||
|
需求:遍历所有节点,输出节点类型为NumericLiteral的value值
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const visitor = {
|
||||||
|
enter(path) {
|
||||||
|
if (path.isNumericLiteral()) {
|
||||||
|
console.log(path.type);
|
||||||
|
console.log(path.node.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse(ast, visitor);
|
||||||
|
```
|
||||||
|
|
||||||
|
打印内容:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
NumericLiteral
|
||||||
|
123
|
||||||
|
```
|
||||||
|
|
||||||
|
**3.获取path的上一级路径path.parentPath;**
|
||||||
|
|
||||||
|
需求:获取上一级路径节点类型
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const visitor = {
|
||||||
|
enter(path) {
|
||||||
|
if (path.isNumericLiteral()) {
|
||||||
|
console.log('当前节点类型:' + path.type);
|
||||||
|
console.log('上层节点类型:' + path.parentPath.type);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse(ast, visitor);
|
||||||
|
```
|
||||||
|
|
||||||
|
打印内容:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
当前节点类型:NumericLiteral
|
||||||
|
上层节点类型:VariableDeclarator
|
||||||
|
```
|
||||||
|
|
||||||
|
**4.获取当前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);
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## path 方法
|
||||||
|
|
||||||
|
`path`方法相关的源代码在这个js文件中
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
node_modules\@babel\traverse\lib\path\index.js
|
||||||
|
\node_modules\@babel\traverse\lib\path
|
||||||
|
```
|
||||||
|
|
||||||
|
**下面是一些常见的path对象的方法API:**
|
||||||
|
|
||||||
|
| api | 功能 |
|
||||||
|
|------------------------------------|--------------------------------------------------------------------|
|
||||||
|
| path.get(key) | 获取当前路径下指定属性名(key)对应的子路径。例如,path.get("body") 获取当前路径下名为 "body" 的子路径。 |
|
||||||
|
| path.getSibling(index) | 获取当前路径对应节点的兄弟节点的路径。通过指定索引(index)可以获取相应的兄弟路径。 |
|
||||||
|
| path.getFunctionParent() | 获取当前路径对应节点的最近的函数父节点的路径。 |
|
||||||
|
| path.getPrevSibling() | 获取当前path的前一个兄弟节点,返回的是path类型。 |
|
||||||
|
| path.getAllPrevSiblings() | 获取当前path的所有前兄弟节点,返回的是Array类型,其元素都是path类型。 |
|
||||||
|
| path.getNextSibling() | 获取当前path的后一个兄弟节点,返回的是path类型。 |
|
||||||
|
| path.getAllNextSiblings() | 获取当前path的所有后兄弟节点,返回的是Array类型,其元素都是path类型。 |
|
||||||
|
| path.evaluate() | 用于计算表达式的值,大家可以参考 constantFold 插件的写法。 |
|
||||||
|
| path.findParent() | 向上查找满足回调函数特征的path,即判断上级路径是否包含有XXX类型的节点。 |
|
||||||
|
| path.find() | 功能与 path.findParent 方法一样,只不过从当前path开始进行遍历。 |
|
||||||
|
| path.getFunctionParent() | 获取函数类型父节点,如果不存在,返回 null。 |
|
||||||
|
| path.getStatementParent() | 获取Statement类型父节点,这个基本上都会有返回值,如果当前遍历的是 Program 或者 File 节点,则会报错。 |
|
||||||
|
| path.getAncestry() | 获取所有的祖先节点,没有实参,返回的是一个Array对象。 |
|
||||||
|
| path.isAncestor(maybeDescendant) | 判断当前遍历的节点是否为实参的祖先节点. |
|
||||||
|
| path.isDescendant(maybeAncestor) | 判断当前遍历的节点是否为实参的子孙节点. |
|
||||||
|
| path.traverse(visitor) | 遍历当前路径下的所有子节点,并应用指定的 visitor。 |
|
||||||
|
| path.replaceWith(node) | 用指定的节点替换当前路径对应的节点。 |
|
||||||
|
| path.remove() | 从 AST 中移除当前路径对应的节点。 |
|
||||||
|
| path.insertBefore(nodes) | 在当前路径对应节点之前插入一个或多个节点。 |
|
||||||
|
| path.insertAfter(nodes) | 在当前路径对应节点之后插入一个或多个节点。 |
|
||||||
|
| path.insertAfter(nodes) | 在当前路径对应节点之后插入一个或多个节点。 |
|
||||||
|
| path.toString() | 用于将 AST 节点转换回对应的源代码字符串。 |
|
||||||
|
|
||||||
|
**1.删除path,使用remove方法**
|
||||||
|
|
||||||
|
需求:删除变量值
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const visitor = {
|
||||||
|
enter(path) {
|
||||||
|
if (path.isNumericLiteral()) {
|
||||||
|
path.remove()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse(ast, visitor);
|
||||||
|
|
||||||
|
let {code} = generator(ast);
|
||||||
|
console.log(code)
|
||||||
|
```
|
||||||
|
|
||||||
|
打印内容:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var a;
|
||||||
|
```
|
||||||
|
|
||||||
|
**2.替换path,单路径可以使用`replaceWith`方法,多路径则使用`replaceWithMultiple`方法**
|
||||||
|
|
||||||
|
需求:把var a = 123; 修改成var a = 3 ,用replaceWith方法
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const visitor = {
|
||||||
|
enter(path) {
|
||||||
|
if (path.isNumericLiteral() && path.node.value == 123) {
|
||||||
|
path.replaceWith({type: "NumericLiteral", value: 3});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse(ast, visitor);
|
||||||
|
```
|
||||||
|
|
||||||
|
打印内容:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var a = 3;
|
||||||
|
```
|
||||||
|
|
||||||
|
注意点,必须加上`&& path.node.value == 123`判断,否则就是无限循环
|
||||||
|
|
||||||
|
**3.当前路径所对应的源代码**
|
||||||
|
|
||||||
|
需求:打印当前路径所对应的源代码
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const visitor = {
|
||||||
|
VariableDeclaration(path) {
|
||||||
|
console.log(path.toString());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse(ast, visitor);
|
||||||
|
```
|
||||||
|
|
||||||
|
打印内容:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var a = 123;
|
||||||
|
```
|
@ -0,0 +1,16 @@
|
|||||||
|
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);
|
1
AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/encode.js
Normal file
1
AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/encode.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
let jscode = "var a = 1 + 2;";
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
BIN
AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/img/2.png
Normal file
BIN
AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/img/2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
@ -1,268 +0,0 @@
|
|||||||
# 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等信息
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
编写代码
|
|
||||||
|
|
||||||
```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;
|
|
||||||
```
|
|
||||||
|
|
||||||
**替换path,单路径可以使用`replaceWith`方法,多路径则使用`replaceWithMultiple`方法**
|
|
||||||
|
|
||||||
需求:把var a = 123; 修改成var a = 3 ,用replaceWith方法
|
|
||||||
|
|
||||||
```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, {
|
|
||||||
sourceType: 'module',
|
|
||||||
});
|
|
||||||
|
|
||||||
const visitor = {
|
|
||||||
enter(path) {
|
|
||||||
if (path.isNumericLiteral() && path.node.value == 123) {
|
|
||||||
path.replaceWith({type: "NumericLiteral", value: 3});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
traverse(ast, visitor);
|
|
||||||
|
|
||||||
// 写入文件
|
|
||||||
let {code} = generator(ast);
|
|
||||||
console.log(code)
|
|
||||||
fs.writeFile('decode.js', code, (err) => {
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
打印内容:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var a = 3;
|
|
||||||
```
|
|
||||||
|
|
||||||
注意点,必须加上`&& path.node.value == 123`判断,否则就是无限循环
|
|
@ -1 +0,0 @@
|
|||||||
var a = 3;
|
|
122
AST抽象语法树/6.AST操作之API用法-node节点/README.md
Normal file
122
AST抽象语法树/6.AST操作之API用法-node节点/README.md
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
# AST操作之API用法-node节点
|
||||||
|
|
||||||
|
在抽象语法树(Abstract Syntax Tree,AST)中,`path.node` 是指表示当前节点的 AST 节点对象。它提供了关于该节点的信息,包括节点的类型和其他属性。
|
||||||
|
|
||||||
|
看语法就可以猜到`node`就是path的一个属性
|
||||||
|
|
||||||
|
| api | 功能 |
|
||||||
|
|:------------------------------------|--------------------------------------|
|
||||||
|
| path.node.type | 获取当前节点的类型。 |
|
||||||
|
| path.node.declarations | 对于 VariableDeclaration 节点, 获取变量声明列表。 |
|
||||||
|
| path.node.init.value | 获取某个节点的值。 |
|
||||||
|
| delete path.node.init; | 删除节点,使用系统的 delete 方法。 |
|
||||||
|
|
||||||
|
**1.遍历打印出节点类型**
|
||||||
|
|
||||||
|
```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, {
|
||||||
|
sourceType: 'module',
|
||||||
|
});
|
||||||
|
|
||||||
|
const visitor = {
|
||||||
|
enter(path) {
|
||||||
|
console.log(path.node.type)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse(ast, visitor);
|
||||||
|
```
|
||||||
|
|
||||||
|
输出
|
||||||
|
```javascript
|
||||||
|
Program
|
||||||
|
VariableDeclaration
|
||||||
|
VariableDeclarator
|
||||||
|
Identifier
|
||||||
|
NumericLiteral
|
||||||
|
var a = 123;
|
||||||
|
```
|
||||||
|
|
||||||
|
**2.遍历节点打印出 VariableDeclaration 节点的变量声明列表**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const visitor = {
|
||||||
|
enter(path) {
|
||||||
|
console.log(path.node.declarations)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
输出
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
undefined
|
||||||
|
[
|
||||||
|
Node {
|
||||||
|
type: 'VariableDeclarator',
|
||||||
|
start: 4,
|
||||||
|
end: 11,
|
||||||
|
loc: SourceLocation {
|
||||||
|
start: [Position],
|
||||||
|
end: [Position],
|
||||||
|
filename: undefined,
|
||||||
|
identifierName: undefined
|
||||||
|
},
|
||||||
|
id: Node {
|
||||||
|
type: 'Identifier',
|
||||||
|
start: 4,
|
||||||
|
end: 5,
|
||||||
|
loc: [SourceLocation],
|
||||||
|
name: 'a'
|
||||||
|
},
|
||||||
|
init: Node {
|
||||||
|
type: 'NumericLiteral',
|
||||||
|
start: 8,
|
||||||
|
end: 11,
|
||||||
|
loc: [SourceLocation],
|
||||||
|
extra: [Object],
|
||||||
|
value: 123
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
undefined
|
||||||
|
undefined
|
||||||
|
undefined
|
||||||
|
var a = 123;
|
||||||
|
```
|
||||||
|
|
||||||
|
**3.获取某个节点的值**
|
||||||
|
```javascript
|
||||||
|
const visitor = {
|
||||||
|
VariableDeclarator(path) {
|
||||||
|
console.log(path.node.init.value)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
输出
|
||||||
|
```javascript
|
||||||
|
123
|
||||||
|
```
|
||||||
|
|
||||||
|
**4.删除某个节点的值**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const visitor = {
|
||||||
|
VariableDeclarator(path) {
|
||||||
|
delete path.node.init.value
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
输出
|
||||||
|
```javascript
|
||||||
|
var a = undefined;
|
||||||
|
```
|
@ -1,21 +1,24 @@
|
|||||||
const fs = require('fs');
|
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;
|
const generator = require("@babel/generator").default;
|
||||||
let encode_file = './encode.js';
|
let encode_file = "./encode.js";
|
||||||
|
|
||||||
let js_code = fs.readFileSync(encode_file, { encoding: 'utf-8' });
|
let js_code = fs.readFileSync(encode_file, {encoding: "utf-8"});
|
||||||
let ast = parse(js_code, {
|
let ast = parse(js_code, {
|
||||||
sourceType: 'module',
|
sourceType: 'module',
|
||||||
});
|
});
|
||||||
|
|
||||||
traverse(ast, {
|
const visitor = {
|
||||||
NumericLiteral(path) {
|
VariableDeclarator(path) {
|
||||||
path.replaceWith(
|
delete path.node.init.value
|
||||||
parse(3).program.body[0].expression
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
}
|
||||||
|
|
||||||
const output = generator(ast).code;
|
traverse(ast, visitor);
|
||||||
console.log(output);
|
|
||||||
|
// 写入文件
|
||||||
|
let {code} = generator(ast);
|
||||||
|
console.log(code)
|
||||||
|
fs.writeFile('decode.js', code, (err) => {
|
||||||
|
});
|
||||||
|
39
AST抽象语法树/7.AST操作之API用法-path.scope属性和方法/README.md
Normal file
39
AST抽象语法树/7.AST操作之API用法-path.scope属性和方法/README.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# AST操作之API用法-path.scope属性和方法
|
||||||
|
|
||||||
|
**scope相关的源代码在这个js文件中**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
node_modules\@babel\traverse\lib\scope\index.js
|
||||||
|
```
|
||||||
|
| api | 说明 |
|
||||||
|
|:--------------------------------------|-------------------------------------------------------------------------------|
|
||||||
|
| scope.block | 表示当前作用域下的所有node,参考上面的 this.block = node; |
|
||||||
|
| scope.dump() | 输出当前每个变量的作用域信息。调用后直接打印,不需要加打印函数 |
|
||||||
|
| scope.crawl() | 重构scope,在某种情况下会报错,不过还是建议在每一个插件的最后一行加上。 |
|
||||||
|
| scope.rename(oldName, newName, block) | 修改当前作用域下的的指定的变量名,oldname、newname表示替换前后的变量名,为字符串。注意,oldName需要有binding,否则无法重命名。 |
|
||||||
|
| scope.traverse(node, opts, state) | 遍历当前作用域下的某些(个)插件。和全局的traverse用法一样。 |
|
||||||
|
| scope.getBinding(name) | 获取某个变量的binding,可以理解为其生命周期。包含引用,修改之类的信息 |
|
||||||
|
|
||||||
|
**binding常用方法及属性总结**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
node_modules\@babel\traverse\lib\scope\binding.js
|
||||||
|
```
|
||||||
|
|
||||||
|
目前我看到的只有 变量定义 和 函数定义 拥有binding,其他的获取binding都是undefined。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let binding = scope.getBinding(name);
|
||||||
|
```
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
var a = 123; 这里的 a 就拥有 binding。 而 function test(a,b,c) {}; 函数名test以及形参a,b,c均拥有 binding。
|
||||||
|
|
||||||
|
| api | 说明 |
|
||||||
|
|:---------------------------|------------------------------------------------------------------|
|
||||||
|
| binding.path | 用于定位初始拥有binding的path; |
|
||||||
|
| binding.constant | 用于判断当前变量是否被更改,true表示未改变,false表示有更改变量值。 |
|
||||||
|
| binding.referenced | 用于判断当前变量是否被引用,true表示代码下面有引用该变量的地方,false表示没有地方引用该变量。注意,引用和改变是分开的。 |
|
||||||
|
| binding.referencePaths | 它是一个Array类型,包含所有引用的path,多用于替换。 |
|
||||||
|
| binding.constantViolations | 它是一个Array类型,包含所有改变的path,多用于判断。 |
|
33
AST抽象语法树/8.AST操作之获得当前节点的源代码/RADME.md
Normal file
33
AST抽象语法树/8.AST操作之获得当前节点的源代码/RADME.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# AST操作之获得当前节点的源代码
|
||||||
|
|
||||||
|
path: path.toString()
|
||||||
|
|
||||||
|
node: generator(node).code;
|
||||||
|
|
||||||
|
```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, {
|
||||||
|
sourceType: 'module',
|
||||||
|
});
|
||||||
|
|
||||||
|
const visitor = {
|
||||||
|
VariableDeclarator(path) {
|
||||||
|
console.log(path.toString())
|
||||||
|
let {code} = generator(path.node);
|
||||||
|
console.log(code)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse(ast, visitor);
|
||||||
|
```
|
||||||
|
|
||||||
|
输出:
|
||||||
|
|
||||||
|
a = 123
|
||||||
|
a = 123
|
@ -10,17 +10,12 @@ let ast = parse(js_code, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const visitor = {
|
const visitor = {
|
||||||
enter(path) {
|
VariableDeclarator(path) {
|
||||||
if (path.isNumericLiteral() && path.node.value == 123) {
|
console.log(path.toString())
|
||||||
path.replaceWith({type: "NumericLiteral", value: 3});
|
let {code} = generator(path.node);
|
||||||
}
|
console.log(code)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
traverse(ast, visitor);
|
traverse(ast, visitor);
|
||||||
|
|
||||||
// 写入文件
|
|
||||||
let {code} = generator(ast);
|
|
||||||
console.log(code)
|
|
||||||
fs.writeFile('decode.js', code, (err) => {
|
|
||||||
});
|
|
1
AST抽象语法树/8.AST操作之获得当前节点的源代码/encode.js
Normal file
1
AST抽象语法树/8.AST操作之获得当前节点的源代码/encode.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
var a = 123;
|
46
AST抽象语法树/9.AST操作之构造节点信息/README.md
Normal file
46
AST抽象语法树/9.AST操作之构造节点信息/README.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# AST操作之构造节点信息
|
||||||
|
|
||||||
|
需求:将var a;将其转化为var a = 1 + 2;
|
||||||
|
|
||||||
|
```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, {
|
||||||
|
sourceType: 'module',
|
||||||
|
});
|
||||||
|
|
||||||
|
const visitor = {
|
||||||
|
VariableDeclarator(path) {
|
||||||
|
// 使用解构赋值语法 {} 是用来从对象中提取特定属性或方法
|
||||||
|
const {init} = path.node
|
||||||
|
console.log({init})
|
||||||
|
const node = {
|
||||||
|
type: "BinaryExpression",
|
||||||
|
operator: "+",
|
||||||
|
left: {
|
||||||
|
type: "NumericLiteral",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
type: "NumericLiteral",
|
||||||
|
value: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 在 JavaScript 中,|| 是逻辑运算符之一,表示逻辑或(OR)
|
||||||
|
init || path.set("init", node)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse(ast, visitor);
|
||||||
|
let {code} = generator(ast);
|
||||||
|
console.log(code)
|
||||||
|
```
|
||||||
|
打印数据:
|
||||||
|
|
||||||
|
{ init: null }
|
||||||
|
var a = 1 + 2;
|
36
AST抽象语法树/9.AST操作之构造节点信息/decode_obfuscator.js
Normal file
36
AST抽象语法树/9.AST操作之构造节点信息/decode_obfuscator.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
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, {
|
||||||
|
sourceType: 'module',
|
||||||
|
});
|
||||||
|
|
||||||
|
const visitor = {
|
||||||
|
VariableDeclarator(path) {
|
||||||
|
// 使用解构赋值语法 {} 是用来从对象中提取特定属性或方法
|
||||||
|
const {init} = path.node
|
||||||
|
console.log({init})
|
||||||
|
const node = {
|
||||||
|
type: "BinaryExpression",
|
||||||
|
operator: "+",
|
||||||
|
left: {
|
||||||
|
type: "NumericLiteral",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
type: "NumericLiteral",
|
||||||
|
value: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init || path.set("init", node)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse(ast, visitor);
|
||||||
|
let {code} = generator(ast);
|
||||||
|
console.log(code)
|
1
AST抽象语法树/9.AST操作之构造节点信息/encode.js
Normal file
1
AST抽象语法树/9.AST操作之构造节点信息/encode.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
var a;
|
@ -4,3 +4,7 @@
|
|||||||
|
|
||||||
https://blog.csdn.net/weixin_52057903/article/details/129131582
|
https://blog.csdn.net/weixin_52057903/article/details/129131582
|
||||||
|
|
||||||
|
babel文档
|
||||||
|
|
||||||
|
https://babeljs.io/docs/babel-types
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ CREATE TABLE `clean_buyin_authorStatData_authorProfile` (
|
|||||||
`act_info` varchar(255) DEFAULT '',
|
`act_info` varchar(255) DEFAULT '',
|
||||||
`deduplication` varchar(100) DEFAULT '' COMMENT '去重字段',
|
`deduplication` varchar(100) DEFAULT '' COMMENT '去重字段',
|
||||||
`spider_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '爬虫抓取时间',
|
`spider_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '爬虫抓取时间',
|
||||||
UNIQUE KEY `task_id` (`deduplication`) USING BTREE,
|
UNIQUE KEY `account_douyin` (`account_douyin`) USING BTREE,
|
||||||
KEY `uid` (`uid`) USING BTREE
|
KEY `uid` (`uid`) USING BTREE
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
@ -230,8 +230,7 @@ CREATE TABLE `clean_buyin_authorStatData_seekAuthor` (
|
|||||||
`author_tag_is_star` smallint(1) DEFAULT '0' COMMENT '是否明星',
|
`author_tag_is_star` smallint(1) DEFAULT '0' COMMENT '是否明星',
|
||||||
`deduplication` varchar(100) DEFAULT '' COMMENT '去重字段',
|
`deduplication` varchar(100) DEFAULT '' COMMENT '去重字段',
|
||||||
`spider_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '爬虫抓取时间',
|
`spider_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '爬虫抓取时间',
|
||||||
UNIQUE KEY `task_id` (`deduplication`) USING BTREE,
|
UNIQUE KEY `deduplication` (`deduplication`) USING BTREE
|
||||||
KEY `author_base_uid` (`author_base_uid`) USING BTREE
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@ -283,4 +282,4 @@ CREATE TABLE `project_buyin_authorStatData` (
|
|||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
-- Dump completed on 2023-07-13 12:09:55
|
-- Dump completed on 2023-07-18 16:58:29
|
||||||
|
Loading…
x
Reference in New Issue
Block a user