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 的语法分析

相关文章
相关标签/搜索