diff --git a/AST抽象语法树/5.AST操作之API用法-path路径/README.md b/AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/README.md similarity index 58% rename from AST抽象语法树/5.AST操作之API用法-path路径/README.md rename to AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/README.md index e781476..854deaf 100644 --- a/AST抽象语法树/5.AST操作之API用法-path路径/README.md +++ b/AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/README.md @@ -5,62 +5,40 @@ 在`@babel/traverse`模块中,path对象表示一个节点(node)在AST树中的位置,提供了一些属性和方法, 用于访问节点的属性、子节点、父节点、兄弟节点等,并且可以对AST树进行修改。 -`path`相关的源代码在这个js文件中 +读取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:** +**下面是一些常见的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) | 在当前路径对应节点之后插入一个或多个节点。 | -| path.insertAfter(nodes) | 在当前路径对应节点之后插入一个或多个节点。 | | path.scope | 表示当前path下的作用域,这个也是写插件经常会用到的。 | | path.container | 用于获取当前path下的所有兄弟节点(包括自身)。 | | path.type | 获取当前path的节点类型。 | | path.key | 获取当前path的key值,key通常用于path.get函数。 | -| path.toString() | 用于将 AST 节点转换回对应的源代码字符串。 | - -**当前路径所对应的源代码** - -需求:打印当前路径所对应的源代码 - -```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; -``` **打印当前路径所对应的某个节点信息** @@ -83,7 +61,6 @@ const visitor = { console.log(path.node.directives); }, } - traverse(ast, visitor); ``` @@ -204,75 +181,6 @@ traverse(ast, visitor); 上层节点类型:VariableDeclarator ``` -**删除path,使用remove方法** - -需求:删除变量值 - -```javascript -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`判断,否则就是无限循环 - **获取当前path的key值** 需求:打印节点VariableDeclarator|BinaryExpression|Identifier的key值 @@ -289,11 +197,114 @@ let ast = parse(js_code, { const visitor = { "VariableDeclarator|BinaryExpression|Identifier"(path) { - console.log(path.key) + console.log(path.key) }, } traverse(ast, visitor); ``` -![debugger](./img/2.png) \ No newline at end of file +![debugger](./img/2.png) + +## path 方法 + +`path`方法相关的源代码在这个js文件中 + +```javascript +node_modules\@babel\traverse\lib\path\index.js +\node_modules\@babel\traverse\lib\path +``` + +| 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 节点转换回对应的源代码字符串。 | + +**删除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; +``` + +**替换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`判断,否则就是无限循环 + +**当前路径所对应的源代码** + +需求:打印当前路径所对应的源代码 + +```javascript +const visitor = { + VariableDeclaration(path) { + console.log(path.toString()); + }, +} + +traverse(ast, visitor); +``` + +打印内容: + +```javascript +var a = 123; +``` \ No newline at end of file diff --git a/AST抽象语法树/5.AST操作之API用法-path路径/decode.js b/AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/decode.js similarity index 100% rename from AST抽象语法树/5.AST操作之API用法-path路径/decode.js rename to AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/decode.js diff --git a/AST抽象语法树/5.AST操作之API用法-path路径/decode_obfuscator.js b/AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/decode_obfuscator.js similarity index 100% rename from AST抽象语法树/5.AST操作之API用法-path路径/decode_obfuscator.js rename to AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/decode_obfuscator.js diff --git a/AST抽象语法树/5.AST操作之API用法-path路径/encode.js b/AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/encode.js similarity index 100% rename from AST抽象语法树/5.AST操作之API用法-path路径/encode.js rename to AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/encode.js diff --git a/AST抽象语法树/5.AST操作之API用法-path路径/img/1.png b/AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/img/1.png similarity index 100% rename from AST抽象语法树/5.AST操作之API用法-path路径/img/1.png rename to AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/img/1.png diff --git a/AST抽象语法树/5.AST操作之API用法-path路径/img/2.png b/AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/img/2.png similarity index 100% rename from AST抽象语法树/5.AST操作之API用法-path路径/img/2.png rename to AST抽象语法树/5.AST操作之API用法-path路径-path属性-path方法/img/2.png