![](/style/images/good.png)
![](/style/images/bad.png)
GitHub - thx/gogocode: The simplest tool to parse/transform/generate code on ast
source link: https://github.com/thx/gogocode
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
GOGOCODE
全网最简单易上手,可读性最强的 AST 处理工具!
来 Playground 体验一下:https://play.gogocode.io
GoGoCode服务+交流钉钉群:34266233;qq群:735216094
Install
npm install gogocode
对于下面的代码
const code = ` const moment = require('moment'); var a = 1; const b = 2; function log (x, y = 'World') { console.log('a') console.log(a, x, y); } `;
创建一个 AST 实例
const $ = require('gogocode'); const AST = $(code);
- 小明想将 所有的
a
变量名替换为c
,只需要
$(code).replace('a', 'c')
-
小明改主意了,只想把
var a = 1
里的变量名改为c
,需要两步:- 取变量 a 的定义赋值,
$(code).find('var a = 1');
- 将
a
变量名替换为c
,并输出整体代码
$(code) .find('var a = 1') .attr('declarations.0.id.name', 'c') .root() .generate();
这是直接操作AST的方式,有没有更简单的方法呢?有!
$(code).replace(`var a = 1`, `var c = 1`)
replace确实用起来爽,但当你在分析转换代码时遇到replace覆盖不到的场景时,请用GoGoCode提供的其他api来精准操作AST吧!Babel、jscodeshift能做到的gogocode都能更简单的做到。
- 小明又改主意了,想把所有定义语句的
a
都改成c
,只需要将目标语句改一下写成:
$(code).replace(`var a = $_$`, `var c = $_$`)
看到这里,你应该已经理解
find
和replace
的第一参有点类似‘jquery 选择器’,而这里的选择器是你需要查找的代码片段,无论想要匹配多么复杂的代码都可以匹配到,其中$_$
通配符可以匹配任意确定代码,代码选择器及通配符详细介绍 看这里
- 小明想试试将代码里的
var
改为let
,require
改为import
,他发现用 GoGoCode 真的可以像字符串的 replace 一样简单!
$(code) .replace('var $_$1 = $_$2', 'let $_$1 = $_$2'); .replace('const $_$1 = require($_$2)', 'import $_$1 from $_$2')
这里注意,选择器中出现两个通配符时,一定要紧接着一个key,才能保证准确性
关于如何书写选择器,以及replace详解,请见GoGoCode详细文档
所有的节点获取操作都会返回一个新的AST实例,实例中可能包含多个AST节点路径,如find()
、siblings()
等,某些api返回的实例只会存在一个AST节点路径,如next()
AST.find(selector, options)
入参
说明
类型
默认值
selector
代码选择器,可以是代码也可以将代码中的部分内容挖空替换为通配符
string
无
options
ignoreSequence
匹配时是否忽略顺序
忽略顺序的情况:{a:$_$}
匹配{b:1, a:2}
需要严格按照顺序匹配的情况:function($_$, b){}
匹配function(a, b){}
boolean
false
parseOptions
同构造函数的parseOptions
当selector中存在 $_$
通配符时,返回的AST实例中存在 match
属性,也就是被 $_$
匹配到的AST节点,按照$_$紧接着的key做聚合
如:$('const a = { key: 1, value: "gogo" }').find('const $_$1 = $_$2')
下图是是 $_$1
和 $_$2
分别匹配到的节点以及对应的输出
.parent(level)
获取某个父节点
入参 说明 类型 默认值level
自内向外第n层父元素
number
0
.parents()
获取所有父节
.root()
获取根节点,对于js来说是type
为'File'的节点,对于html来说是nodeType
为'document'的节点
通常对AST进行操作之后需要获取root元素之后再输出
.siblings()
获取所有兄弟节点
.prev()
获取前一个节点
.prevAll()
获取当前节点之前的同级节点
.next()
获取后一个节点
.nextAll()
获取当前节点之后的同级节点
.each(callback)
以每一个匹配的元素作为上下文来执行一个函数。
入参 说明 类型 默认值callback
对于每个匹配的元素所要执行的函数�执行函数时,会给函数传递当前节点
node
和index
function
无
.eq(index)
获取当前链式操作中第N个AST对象
入参 说明 类型 默认值index
需要获取的AST对象的位置
number
0
.attr()
获取或修改AST节点的属性,入参可分三种情况:
- 返回属性名称对应的节点或属性值
attrName
ast节点的属性名称,支持多层属性,通过.连接
string
无
declarationsdeclarations.0.id.name
- 修改属性名称对应的节点或属性值
入参
说明
类型
举例
attrName
ast节点的属性名称,支持多层属性,通过.连接
string
declarations
declarations.0.id.name
attrValue
将第一个入参获取到的节点或属性修改为该入参
注意:字符串不会被解析为ast节点而是直接替换原有属性
node string
- 修改多个属性名称对应的节点或属性值
入参
类型
默认值
举例
attrMap
attrName
string
无
declarations
declarations.0.id.name
attrValue
node
string
无
未匹配到某个属性时,会直接返回null
AST.attr('init', initNode) AST.attr({ init: initNode, 'program.body.0.params.0.name': 'a' }) AST.attr('program.body.0.params.0.name')
.has(selector, options)
判断是否有某个子节点,返回值为boolean类型
入参同.find()
.clone()
返回由当前节点深度复制的新节点
.replace(selector, replacer)
在当前节点内部用replacer
替换selector
匹配到的代码,返回当前节点
入参
解释
类型
例
selector
代码选择器,可以是代码也可以将代码中的部分内容挖空替换为通配符
string
var $_$1 = $_$2
replacer
替换代码,同代码选择器通配符顺序与selector的保持一致
也可以是确定的ast节点
string
node
options
ignoreSequence
匹配时是否忽略顺序
object
无
parseOptions
解析入参
object
无
这里注意,选择器中出现两个通配符时,一定要紧接着一个key,才能保证准确性
AST.replace(`Component`, `module.exports = Magix.View.extend`); AST.replace( `export default function calculateData($_$1){$_$2}`, `function calculateData($_$1){$_$2}` ) AST.replace( `navigateToOutside({url: $_$})`, `jm.attachUrlParams($_$)`, options: { ignoreSequence: true } )
.replaceBy(replacerAST)
用replacerAST替换当前节点,返回新节点
入参 类型replacerAST
AST node
string
.after(ast)
在当前节点后面插入一个同级别的节点,返回当前节点
入参 类型ast
AST node
string
.before()
在当前节点前面插入一个同级别的节点,返回当前节点
入参 类型ast
AST node
string
.append(attr, ast)
在当前节点内部某个数组属性的末尾插入一个子节点,返回当前节点
入参 类型attr
当前节点的数组属性名称
ast
AST node
string
- 为什么需要传入
attr
?
因为某些节点中多个属性都为数组,如函数,存在入参params和函数体body两个数组子节点,必须通过attr来判断插入节点的位置
AST .find('function $_$() {}') .append('params', 'b') .prepend('body', 'b = b || 1;')
.prepend()
在当前节点内部某个数组属性的首位插入一个子节点,返回当前节点
.empty()
清空当前节点所有子节点,返回当前节点
.remove()
移除当前节点,返回根节点
.generate()
将AST对象输出为代码
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK