疑问
书摘&心得
Traverse的实现是vistor访问者模式的体现
这个东西没有官方文档的么?先记录一下
path {// 属性:node 当前 AST 节点parent 父 AST 节点parentPath 父 AST 节点的 pathscope 作用域hub path.hub.file 拿到最外层 File 对象;path.hub.getScope 拿到最外层作用域;path.hub.getCode 拿到源码字符串container (不常用)当前 AST 节点所在的父节点属性的属性值key (不常用)当前 AST 节点所在父节点属性的属性名或所在数组的下标listKey (不常用)当前 AST 节点所在父节点属性的属性值为数组时 listkey 为该属性名,否则为 undefined// 方法get(key) 获取某个属性的 pathset(key, node) 设置某个属性的值inList() 判断节点是否在数组中,有 listkey 的时候,返回 truegetSibling(key) 获取某个下标的兄弟节点getNextSibling() 获取下一个兄弟节点getPrevSibling() 获取上一个兄弟节点getAllPrevSiblings() 获取之前的所有兄弟节点getAllNextSiblings() 获取之后的所有兄弟节点isXxx(opts) 判断当前节点是否是某个类型,可以传入属性和属性值进一步判断,比如path.isIdentifier({name: 'a'})assertXxx(opts) 同 isXxx,但是不返回布尔值,而是抛出异常find(callback) 从当前节点到根节点来查找节点(包括当前节点),调用 callback(传入 path)来决定是否终止查找findParent(callback) 从当前节点到根节点来查找节点(不包括当前节点),调用 callback(传入 path)来决定是否终止查找insertBefore(nodes) 在之前插入节点,可以是单个节点或者节点数组insertAfter(nodes) 在之后插入节点,可以是单个节点或者节点数组replaceWith(replacement) 用某个节点替换当前节点replaceWithMultiple(nodes) 用多个节点替换当前节点replaceWithSourceString(replacement) 解析源码成 AST,然后替换当前节点remove() 删除当前节点traverse(visitor, state) 遍历当前节点的子节点skip() 跳过当前节点的子节点的遍历stop() 结束所有遍历}
作用域path.scope
这里的作用域就是指js中的作用域
path.scope {bindings 当前作用域内声明的所有变量block 生成作用域的 block,详见下文parentparentBlockpath 生成作用域的节点对应的 pathreferences 所有 binding 的引用对应的 path,详见下文dump() 打印作用域链的所有 binding 到控制台parentBlock() 父级作用域的 blockgetAllBindings() 从当前作用域到根作用域的所有 binding 的合并getBinding(name) 查找某个 binding,从当前作用域一直查找到根作用域hasBinding(name,noGlobals) 从当前作用域查找 bindinggetOwnBinding(name) 从当前作用域查找 bindingparentHasBinding(name) 查找某个 binding,从父作用域查到根作用域,不包括当前作用域。可以通过 noGlobals 参数指定是否算上全局变量,默认是 falseremoveBinding(name) 删除某个 bindingmoveBindingTo(name, scope) 把当前作用域中的某个 binding 移动到其他作用域generateUid(name) 生成作用域内唯一的名字,根据 name 添加下划线}
block
不是所有节点都可以生成scope,只有部分可以,按常识就是各种会生成作用域的语句,这些节点又称block节点
binding
在当前 scope 中声明了 a 这个变量,所以 bindings 中有 a 的 binding
bindings: {a: {constant: true, 变量是否被修改过constantViolations: [], 所有修改的语句的 pathidentifier: {type: 'Identifier', ...} 标识符的 ASTkind:'const', 绑定的类型path: {node,...} 整个声明语句的 ASTreferenced: false 声明的变量是否被引用referencePaths: [], 所有引用的语句的 pathreferences: 0,scope: ...}}
2、state
原生state
opts,也就是插件的配置项
- file 对象,该对象也可以通过path.hub.file获取
主要用途:
- 除了原生state以外,可以挂载一些自己定义的state来在节点间传递,babel-plugin-import中大量使用了这种数据传递。
- 可以在遍历的过程中在 state 中存一些状态信息,用于后续的 AST 处理。
不是遍历过程中的数据,可以通过 file.set、file.get 来保存。
3、AST的别名
所谓别名,更像是指是要处理一个更广泛的节点还是更具体的节点。
- 比如:更广泛的节点是Declarations.,而更具体的节点是ClassDeclaration
- 可以在文档中查到某个 AST 类型的别名是啥
某个别名都包含哪些 AST 类型可以在babel-types的类型定义处查。
4、节点创建
节点创建需要借助@babel/types
- 每一个 AST 节点怎么创建、怎么校验、怎么遍历,其实都与 AST 的结构有关系,这些都在 babel-types 里面定义,具体使用具体查看即可
- 个人觉得@babel/templete可能更容易上手
