Babylon-AST初探-程式碼更新&刪除(Update & Remove)

Summer肉欣發表於2019-03-02

  通過前兩篇文章的介紹,大家已經瞭解了CreateRetrieve,我們接著介紹UpdateRemove操作。Update操作通常配合Create來完成。我們這篇文章主要介紹幾個常用的NodePath``APIreplaceinsertremove。具體也可以看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展示如下圖:

Babylon-AST初探-程式碼更新&刪除(Update & Remove)

  我們需要做的是,找到符合this.countThisExpression,然後把它替換為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,前、中、後各種位置都可以插入新節點。下面來介紹下pushContainerunshiftContainerinsertBeforeinsertAfter操作。

  這裡以給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)
    }
  }
})
複製程式碼

  unshiftContainerinsertBefore與上面兩個相對應,這裡不再舉例了,大家可以自己試一試。

  因為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小程式為例,我們來實戰一波。

相關文章