Skip to content

webaifei/ast-examples

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AST (abstract syntax tree)

官方描述: 是源代码的抽象语法结构的树状表现形式 简单的来说,就是js代码的map描述(普通的js对象)

能做什么?

抽象语法树的用处非常多,比如我们常见的代码压缩(之前我天真的以为代码压缩应该就是正则匹配替换掉换行和空格,在一次使用uglifyjs压缩代码测试的时候,发现一个没有用到的函数声明在压缩后的代码中彻底没找到!!),IDE的代码提示,错误提示,编译器等等。

就拿上面的我遇到的问题来说,它是怎么实现的检测到我定义了这个函数,但是没有使用呢。其实内部原来就是把整个代码解析成一棵树,包含了各种类型的节点,类似于我们熟悉的dom树(这点来看,其实很多技术的思想都是相通的)

我是在研究yeoman生成器mock-server的时候,需要修改已经存在的文件内容,遇到这个问题。

//AST
{
  "type": "Program",
  "body": [
      {
          "type": "FunctionDeclaration",
          "id": {
              "type": "Identifier",
              "name": "sau"//函数名
          },
          "params": [],
          "defaults": [],
          "body": {
              "type": "BlockStatement",
              "body": [
                  {
                      "type": "VariableDeclaration",
                      "declarations": [
                          {
                              "type": "VariableDeclarator",
                              "id": {
                                  "type": "Identifier",
                                  "name": "inner"
                              },
                              "init": {
                                  "type": "Identifier",
                                  "name": "answer"
                              }
                          }
                      ],
                      "kind": "var"
                  }
              ]
          },
          "generator": false,
          "expression": false
      },
      {
          "type": "ExpressionStatement",//节点类型
          "expression": {
              "type": "CallExpression",
              "callee": {
                  "type": "Identifier",
                  "name": "sau"//调用的函数名
              },
              "arguments": []
          }
      }
  ],
  "sourceType": "script"
}
  1. tree结构
tree
  - node
  - node
  ...
  1. tree根节点结构
{
  type:'Program',
  body:[

  ]
}
  1. node 结构
{
  type:'xxx',
  body:[

  ],
  ...
}
  1. 除了变量node,其他的大概都有的两个属性 type body
  2. 除了type,body两个属性 每个节点上还包含了很多其他描述属性。比如:我们的函数声明node中包含一个id.name 就是我们的函数名, 而函数调用中有个expression.callee指向调用的函数名,我们只需要遍历整个树,查看定义的node 的id.name 在expression.callee中是否存在 就能知道我们的这个函数是否被调用过,如果没有调用过 我们就可以把这个函数定义的node删除掉!然后再把抽象语法树转换成js代码就ok了

上面的实现中,有三个比较重要的步骤

  1. js => ast
  2. 遍历ast 修改
  3. ast => js

如何把js解析成语法树

这里,个人能力的缘故还不到去关注js=>ast转换的实现细节的时候,我们只要能实现就行,比较流行的有两个库:

  1. esprima 把js转换成ast
  2. esprima-fb 来自facebook,基于esprima 兼容jsx js|jsx => ast

demos: esprima-fb/

  1. js2ast.js => js解析成ast
  2. js2ast-with-options.js 通过配置不同的解析参数 [在线查看不同配置参数的解析结果](http://esprima.org/demo/parse.html)

遍历ast树

  1. estraverse
  2. esprima-walk

demos: esprima-walk

  1. walk.js

操作ast树

  1. 生成的抽象语法树 是一个js对象 所以对树的操作 就和修改普通的js对象一样

demos: escodegen-wallaby/

  1. gen.js 修改tree属性 重新生成js代码 保存

ast转换成js

  1. escodegen
  2. escodegen-wallaby 兼容jsx 对应上面的esprima-fb

About

abstract syntax tree examples, ast examples

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published