通过前两篇文章的介绍,大家已经了解了Create
和Retrieve
,我们接着介绍Update
和 Remove
操作。Update
操作通常配合Create
来完成。我们这篇文章主要介绍几个常用的NodePath`
API:
replace、
insert、
remove`。具体也可以看babel-handbook中的Manipulation章节。
replaceWith 使用新的节点进行替换
将加法运算替换成乘法
const code = `const c = a + b`
const ast = babylon.parse(code)
traverse(ast, {
BinaryExpression(path) {
// 注意这里要有判断,否则会无限进入`BinaryExpression`
// https://stackoverflow.com/questions/37539432/babel-maximum-call-stack-size-exceeded-while-using-path-replacewith
if (path.node.operator === '+') {
path.replaceWith(t.binaryExpression('*', path.node.left, path.node.right))
}
}
})
console.log(generate(ast, {}, code).code) // const c = a * b;
将this.count
替换为this.data.count
转换前后的AST
展示如下图:
我们需要做的是,找到符合this.count
的ThisExpression
,然后把它替换为this.data
const code = `this.count`
const ast = babylon.parse(code)
traverse(ast, {
MemberExpression(path) {
if (
t.isThisExpression(path.node.object) &&
t.isIdentifier(path.node.property, {
name: 'count'
})
) {
path
.get('object') // 获取`ThisExpresssion`
.replaceWith(
t.memberExpression(t.thisExpression(), t.identifier('data'))
)
}
}
})
console.log(generate(ast, {}, code).code) // this.data.count;
replaceWithSourceString 直接使用代码替换
上个例子中将this.count
替换为this.data.count
的部分,通过t.memberExpression
可以构造node
。更简单的操作可以直接使用replaceWithSourceString
,个人觉得这个API
很好用。
path.get('object').replaceWithSourceString('this.data')
插入操作
插入是树操作的一种常见操作。子节点是个Array
,前、中、后各种位置都可以插入新节点。下面来介绍下pushContainer
、unshiftContainer
、insertBefore
、insertAfter
操作。
这里以给obj
对象新增一个属性myprop: 'hello my property'
为例:
const code = `
const obj = {
count: 0,
message: 'hello world'
}
`
const ast = babylon.parse(code)
const property = t.objectProperty(
t.identifier('myprop'),
t.stringLiteral('hello my property')
)
pushContainer 父节点的操作
父节点为子节点Array
插入一个node
traverse(ast, {
ObjectExpression(path) {
path.pushContainer('properties', property)
}
})
insertAfter 兄弟节点的操作
insertAfter
也可以完成上述操作,需要找到message
属性,然后在后面插入node
就搞定啦
traverse(ast, {
ObjectProperty(path) {
if (
t.isIdentifier(path.node.key, {
name: 'message'
})
) {
path.insertAfter(property)
}
}
})
unshiftContainer
和insertBefore
与上面两个相对应,这里不再举例了,大家可以自己试一试。
因为properties
是个数组,因此,我们可以直接使用数组操作
traverse(ast, {
ObjectExpression(path) {
// path.pushContainer('properties', property)
path.node.properties.push(property)
}
})
Remove 自我毁灭
Remove
方法极为简单,找到要删除的NodePath
,执行Remove
就结束了。如上述代码,我们要删除message
属性,代码如下:
traverse(ast, {
ObjectProperty(path) {
if (
t.isIdentifier(path.node.key, {
name: 'message'
})
) {
path.remove()
}
}
})
到目前为止,AST的CURD
我们都介绍完了,下面一篇文章以vue
转小程序
为例,我们来实战一波。