成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Babylon-AST初探-代碼查詢(Retrieve)

wangdai / 3071人閱讀

摘要:針對(duì)語法樹節(jié)點(diǎn)的查詢操作通常伴隨著和這兩種方法見下一篇文章。注意上述代碼打印出的和中的并不完全一致。如函數(shù),在中的為,但其實(shí)際的為。這個(gè)大家一定要注意哦,因?yàn)樵谖覀兒竺娴膶?shí)際代碼中也有用到。

??在上一篇文章中,我們介紹了ASTCreate。在這篇文章中,我們接著來介紹ASTRetrieve。
??針對(duì)語法樹節(jié)點(diǎn)的查詢(Retrieve)操作通常伴隨著UpdateRemove(這兩種方法見下一篇文章)。這里介紹兩種方式:直接訪問和traverse。

??本文中所有對(duì)AST的操作均基于以下這一段代碼

const babylon = require("babylon")
const t = require("@babel/types")
const generate = require("@babel/generator").default
const traverse = require("@babel/traverse").default

const code = `
export default {
  data() {
    return {
      message: "hello vue",
      count: 0
    }
  },
  methods: {
    add() {
      ++this.count
    },
    minus() {
      --this.count
    }
  }
}
`

const ast = babylon.parse(code, {
  sourceType: "module",
  plugins: ["flow"]
})

??對(duì)應(yīng)的AST explorer的表示如下圖所示,大家可以自行拷貝過去查看:

直接訪問

??如上圖中,有很多節(jié)點(diǎn)Node,如需要獲取ExportDefaultDeclaration下的data函數(shù),直接訪問的方式如下:

const dataProperty = ast.program.body[0].declaration.properties[0]
console.log(dataProperty)

程序輸出:

Node {
  type: "ObjectMethod",
  start: 20,
  end: 94,
  loc:
   SourceLocation {
     start: Position { line: 3, column: 2 },
     end: Position { line: 8, column: 3 } },
  method: true,
  shorthand: false,
  computed: false,
  key:
   Node {
     type: "Identifier",
     start: 20,
     end: 24,
     loc: SourceLocation { start: [Object], end: [Object], identifierName: "data" },
     name: "data" },
  kind: "method",
  id: null,
  generator: false,
  expression: false,
  async: false,
  params: [],
  body:
   Node {
     type: "BlockStatement",
     start: 27,
     end: 94,
     loc: SourceLocation { start: [Object], end: [Object] },
     body: [ [Object] ],
     directives: [] } }

??這種直接訪問的方式可以用于固定程序結(jié)構(gòu)下的節(jié)點(diǎn)訪問,當(dāng)然也可以使用遍歷樹的方式來訪問每個(gè)Node。

??這里插播一個(gè)Update操作,把data函數(shù)修改為mydata

const dataProperty = ast.program.body[0].declaration.properties[0]
dataProperty.key.name = "mydata"

const output = generate(ast, {}, code)
console.log(output.code)

程序輸出:

export default {
  mydata() {
    return {
      message: "hello vue",
      count: 0
    };
  },

  methods: {
    add() {
      ++this.count;
    },

    minus() {
      --this.count;
    }

  }
};
使用Traverse訪問

??使用直接訪問Node的方式,在簡單場景下比較好用。可是對(duì)于一些復(fù)雜場景,存在以下幾個(gè)問題:

需要處理某一類型的Node,比如ThisExpression、ArrowFunctionExpression等,這時(shí)候我們可能需要多次遍歷AST才能完成操作

到達(dá)特定Node后,要訪問他的parent、sibling時(shí),不方便,但是這個(gè)也很常用

??@babel/traverse庫可以很好的解決這一問題。traverse的基本用法如下:

// 該代碼打印所有 node.type。 可以使用`path.type`,可以使用`path.node.type`
let space = 0

traverse(ast, {
  enter(path) {
    console.log(new Array(space).fill(" ").join(""), ">", path.node.type)
    space += 2
  },
  exit(path) {
    space -= 2
    // console.log(new Array(space).fill(" ").join(""), "<", path.type)
  }
})

程序輸出:

 > Program
   > ExportDefaultDeclaration
     > ObjectExpression
       > ObjectMethod
         > Identifier
         > BlockStatement
           > ReturnStatement
             > ObjectExpression
               > ObjectProperty
                 > Identifier
                 > StringLiteral
               > ObjectProperty
                 > Identifier
                 > NumericLiteral
       > ObjectProperty
         > Identifier
         > ObjectExpression
           > ObjectMethod
             > Identifier
             > BlockStatement
               > ExpressionStatement
                 > UpdateExpression
                   > MemberExpression
                     > ThisExpression
                     > Identifier
           > ObjectMethod
             > Identifier
             > BlockStatement
               > ExpressionStatement
                 > UpdateExpression
                   > MemberExpression
                     > ThisExpression
                     > Identifier

??traverse引入了一個(gè)NodePath的概念,通過NodePathAPI可以方便的訪問父子、兄弟節(jié)點(diǎn)。

??注意: 上述代碼打印出的node.type和AST explorer中的type并不完全一致。實(shí)際在使用traverse時(shí),需要以上述打印出的node.type為準(zhǔn)。如data函數(shù),在AST explorer中的typeProperty,但其實(shí)際的typeObjectMethod。這個(gè)大家一定要注意哦,因?yàn)樵谖覀兒竺娴膶?shí)際代碼中也有用到。

??仍以上述的訪問data函數(shù)為例,traverse的寫法如下:

traverse(ast, {
  ObjectMethod(path) {
    // 1
    if (
      t.isIdentifier(path.node.key, {
        name: "data"
      })
    ) {
      console.log(path.node)
    }

    // 2
    if (path.node.key.name === "data") {
      console.log(path.node)
    }
  }
})

??上面兩種判斷Node的方法都可以,哪個(gè)更好一些,我也沒有研究。

??通過travase獲取到的是NodePath,NodePath.node等價(jià)于直接訪問獲取的Node節(jié)點(diǎn),可以進(jìn)行需要的操作。

??以下是一些從babel-handbook中看到的NodePathAPI,寫的一些測試代碼,大家可以參考看下,都是比較常用的:

parent

traverse(ast, {
  ObjectMethod(path) {
    if (path.node.key.name === "data") {
      const parent = path.parent
      console.log(parent.type)    // output: ObjectExpression
    }
  }
})

findParent

traverse(ast, {
  ObjectMethod(path) {
    if (path.node.key.name === "data") {
      const parent = path.findParent(p => p.isExportDefaultDeclaration())
      console.log(parent.type)
    }
  }
})

findNode節(jié)點(diǎn)找起

traverse(ast, {
  ObjectMethod(path) {
    if (path.node.key.name === "data") {
      const parent = path.find(p => p.isObjectMethod())
      console.log(parent.type) // output: ObjectMethod
    }
  }
})

container 沒太搞清楚,訪問的NodePath如果是在array中的時(shí)候比較有用

traverse(ast, {
  ObjectMethod(path) {
    if (path.node.key.name === "data") {
      const container = path.container
      console.log(container) // output: [...]
    }
  }
})

getSibling 根據(jù)index獲取兄弟節(jié)點(diǎn)

traverse(ast, {
  ObjectMethod(path) {
    if (path.node.key.name === "data") {
      const sibling0 = path.getSibling(0)
      console.log(sibling0 === path) // true
      const sibling1 = path.getSibling(path.key + 1)
      console.log(sibling1.node.key.name) // methods
    }
  }
})

skip 最后介紹一下skip,執(zhí)行之后,就不會(huì)在對(duì)葉節(jié)點(diǎn)進(jìn)行遍歷

traverse(ast, {
  enter(path) {
    console.log(path.type)
    path.skip()
  }
})

程序輸出根節(jié)點(diǎn)Program后結(jié)束。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/107869.html

相關(guān)文章

  • Babylon-AST初探-代碼更新&刪除(Update & Remove)

    摘要:操作通常配合來完成。因?yàn)槭莻€(gè)數(shù)組,因此,我們可以直接使用數(shù)組操作自我毀滅方法極為簡單,找到要?jiǎng)h除的,執(zhí)行就結(jié)束了。如上述代碼,我們要?jiǎng)h除屬性,代碼如下到目前為止,的我們都介紹完了,下面一篇文章以轉(zhuǎn)小程序?yàn)槔?,我們來?shí)戰(zhàn)一波。 ??通過前兩篇文章的介紹,大家已經(jīng)了解了Create和Retrieve,我們接著介紹Update和 Remove操作。Update操作通常配合Create來完成。...

    levius 評(píng)論0 收藏0
  • Babylon-AST初探-實(shí)戰(zhàn)

    摘要:生成屬性這一步,我們要先提取原函數(shù)中的的對(duì)象。所以這里我們還是主要使用來訪問節(jié)點(diǎn)獲取第一級(jí)的,也就是函數(shù)體將合并的寫法用生成生成生成插入到原函數(shù)下方刪除原函數(shù)程序輸出將中的屬性提升一級(jí)這里遍歷中的屬性沒有再采用,因?yàn)檫@里結(jié)構(gòu)是固定的。 ??經(jīng)過之前的三篇文章介紹,AST的CRUD都已經(jīng)完成。下面主要通過vue轉(zhuǎn)小程序過程中需要用到的部分關(guān)鍵技術(shù)來實(shí)戰(zhàn)。 下面的例子的核心代碼依然是最簡單...

    godiscoder 評(píng)論0 收藏0
  • 宿舍得

    摘要:序列化輸出定義序列化器字段的作用補(bǔ)充為列表,關(guān)系屬性字段的三種方式獲取序列化后的數(shù)據(jù),,反序列化輸入驗(yàn)證驗(yàn)證的調(diào)用接收數(shù)據(jù)繼承獲取查詢字符串中的某個(gè)參數(shù)值獲取查詢字符串中的所有值返回一個(gè)字典獲取請(qǐng)求體中的參數(shù)包括表單創(chuàng)建序列化器對(duì)象類字典進(jìn) 1.序列化輸出: 1.定義序列化器字段的作用 1. 2. 補(bǔ)充:read_only,write_only 2.`Json...

    lx1036 評(píng)論0 收藏0
  • drf實(shí)現(xiàn)常用數(shù)據(jù)緩存

    摘要:使用擴(kuò)展類使用了視圖集用于緩存返回列表數(shù)據(jù)的視圖,與擴(kuò)展類配合使用,實(shí)際是為方法添加了裝飾器用于緩存返回單一數(shù)據(jù)的視圖,與擴(kuò)展類配合使用,實(shí)際是為方法添加了裝飾器為視圖集同時(shí)補(bǔ)充和兩種緩存,與和一起配合使用。 在以往的后臺(tái)數(shù)據(jù)訪問時(shí),我們往往都會(huì)進(jìn)行數(shù)據(jù)庫查詢,基本的流程是這樣的: showImg(https://segmentfault.com/img/bVbooYc?w=784&h...

    yanest 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<