babel的AST實踐

提及 AST 語法,不少前端小夥伴都是不陌生,可是真正使用的卻少之又少,本文簡單總結一下本身學習和使用 ast 的心路歷程。前端

首先什麼是 AST 呢?node

JavaScript 是一種解釋類型語言,在執行前要經歷詞法分析、語法分析(AST)、代碼生成 三個階段api

  • 詞法分析:JavaScript將代碼串進行分析爲詞法單元babel

    例如代碼塊 var answer = 6; 會被分解成爲 var、answer、=、六、;
    
    [
      {
          "type": "Keyword",
          "value": "var"
      },
      {
          "type": "Identifier",
          "value": "answer"
      },
      {
          "type": "Punctuator",
          "value": "="
      },
      {
          "type": "Numeric",
          "value": "6"
      },
      {
          "type": "Punctuator",
          "value": ";"
      }
    ]
    複製代碼

    具體的 type 值能夠參考 @babel/types 官方介紹 @babel/typesmarkdown

  • 語法分析:ide

    將詞法單元轉爲由元素嵌套組成的語法結構樹,就是咱們所說的抽象語法樹(abstract syntax code,AST)工具

    {
      "type": "File",
      "start": 0,
      "end": 16,
      "loc": {
        "start": {
          "line": 1,
          "column": 0
        },
        "end": {
          "line": 2,
          "column": 0
        }
      },
      "errors": [],
      "program": {
        "type": "Program",
        "start": 0,
        "end": 16,
        "loc": {
          "start": {
            "line": 1,
            "column": 0
          },
          "end": {
            "line": 2,
            "column": 0
          }
        },
        "sourceType": "module",
        "interpreter": null,
        "body": [
          {
            "type": "VariableDeclaration",
            "start": 0,
            "end": 15,
            "loc": {
              "start": {
                "line": 1,
                "column": 0
              },
              "end": {
                "line": 1,
                "column": 15
              }
            },
            "declarations": [
              {
                "type": "VariableDeclarator",
                "start": 4,
                "end": 14,
                "loc": {
                  "start": {
                    "line": 1,
                    "column": 4
                  },
                  "end": {
                    "line": 1,
                    "column": 14
                  }
                },
                "id": {
                  "type": "Identifier",
                  "start": 4,
                  "end": 10,
                  "loc": {
                    "start": {
                      "line": 1,
                      "column": 4
                    },
                    "end": {
                      "line": 1,
                      "column": 10
                    },
                    "identifierName": "answer"
                  },
                  "name": "answer"
                },
                "init": {
                  "type": "NumericLiteral",
                  "start": 13,
                  "end": 14,
                  "loc": {
                    "start": {
                      "line": 1,
                      "column": 13
                    },
                    "end": {
                      "line": 1,
                      "column": 14
                    }
                  },
                  "extra": {
                    "rawValue": 6,
                    "raw": "6"
                  },
                  "value": 6
                }
              }
            ],
            "kind": "var"
          }
        ],
        "directives": []
      },
      "comments": []
    }
    複製代碼

    其實咱們單看 body 就能夠,它裏面包含了咱們的語法樹結構,其實裏面的一些字段 startendloc 這三個值對咱們來講基本上是沒有大做用的oop

    咱們能夠在這一步中對源代碼進行添加、更新和刪除節點,學習

    1. 使用 @babel/parser 將字符串轉爲 AST 語法樹,
    2. 使用 @babel/traverse 轉換代碼
    const parser = require('@babel/parser');
    const traverse = require('@babel/traverse');
    
    var answer = 6;
    
    const ast = parser.parse(code);
    
    traverse.default(ast, {
      enter(path) {
        if(path.isIdentifier({name: "answer"})) {
          path.node.name = 'question';
        }
        if(path.isLiteral({value: 6})) {
          path.node.value = 666;
        }
      },
    });
    
    const newCode = generator.default(ast, {}, code).code;
    
    console.log('newCode: ', newCode) // newCode:  var question = 666;
    
    複製代碼

    咱們也能夠在語法樹中使用 node type 進行代碼的修改ui

    traverse.default(ast, {
      VariableDeclarator(path) {
        if(path.node.id.name ==='answer'){
          path.node.init.value ='666'
        }
      }
    });
    複製代碼
  • 代碼生成:

const generator = require('@babel/generator');
  const newCode = generator.default(ast, {}, code).code;

  console.log('newCode: ', newCode) // newCode:  var question = 666;
複製代碼

在前端的開發過程當中,難免的須要去開發一些代碼工具,咱們經過工具能夠去修改咱們的源代碼,從而提高開發效率。在這個狀況下,咱們就須要分析源代碼、修改源代碼、生產新的代碼。這就會用到 AST 的語法分析

相關文章
相關標籤/搜索