通過前兩篇文章的介紹,大家已經瞭解了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
轉小程式
為例,我們來實戰一波。