简介
Oast是一款专门用于解析和操作JS AST(抽象语法树)的npm包。AST代表了代码的语法结构,而且被广泛地用于代码编辑器(如VSCode、Atom、Sublime)和代码工具(如Babel、ESLint、Uglify)中。Oast提供了完整的AST节点和一个方便的规则引擎,同时也支持AST操作的可扩展性。
安装和使用
使用npm进行安装:
npm install oast
使用NodeJS将JS代码解析成AST对象并编辑:
-- -------------------- ---- ------- ----- ---- - ---------------- -- ------------- ----- --- - -------------------- ------ - ------ - - -- ---- -- ----------- ------------------ - ----------- ------- - -- ---------- --- ---------------------- - ------------------------ --- ------------ - - --- -- ------------- ----- ---- - ------------------- ------------------ -- --------- ------ - -- ------ - - -- -- --
节点对象
节点通常包含一些元信息(如行号、开始位置、结束位置),并且由AST解析器创建。要访问某个节点的元信息,可以使用node.start和node.end属性。
每个节点都会有一个type属性表示其类型。
让我们看一些基本的节点类型:
Identifier
标识符节点表示变量或函数的名称。
const ast = oast.parse("const a = 5;"); console.log(ast.body[0].declarations[0].id); // output: Identifier {type: "Identifier", name: "a", start: 6, end: 7}
Literal
字面量节点表示语言中的常量。
const ast = oast.parse("const a = 5;"); console.log(ast.body[0].declarations[0].init); // output: Literal {type: "Literal", value: 5, start: 10, end: 11}
BinaryExpression
二元表达式节点表示常见的二元操作(如加减乘除)。
const ast = oast.parse("const a = 3 + 4;"); console.log(ast.body[0].declarations[0].init); // output: BinaryExpression {type: "BinaryExpression", operator: "+", start: 10, end: 15}
ExpressionStatement
表达式语句节点表示表达式组成的语句,如赋值语句、调用语句等。
const ast = oast.parse("a = 5 + 3;"); console.log(ast.body[0]); // output: ExpressionStatement {type: "ExpressionStatement", expression: BinaryExpression}
属性访问
访问AST节点对象的属性,你可以使用以下两种方式:
- 直接访问节点对象的属性:比如
node.property
或node.body.body[0]
- 使用遍历方法:如
oast.traverse()
或oast.traverseTree()
对AST树进行遍历
遍历方法需要第二个参数作为代表访问节点的函数:
oast.traverse(ast, { enter(node, parent) { console.log(node.type); } });
这个例子会遍历AST树,并且使用函数enter()
得到每个节点对象。你会发现这个函数在遍历阶段会重复地调用多次,因为它将为每个节点调用一次。
相似地,oast.traverseTree()
遍历的时候也可以返回父对象:
oast.traverseTree(ast, (node, parent) => { console.log(node.type, parent && parent.type); });
节点操作
在操作AST树之前,你要知道以下这些有用的函数:
oast.buildNode(type, props)
这个函数可以帮助你构建一个节点对象,它接受一个AST节点类型和一个包含该节点类型的属性的对象。
const node = oast.buildNode("Identifier", {name: "someName"});
oast.append(parent, node)
添加一个节点,将其作为子节点连接到父节点中。
const decl = oast.buildNode("VariableDeclaration", {kind: "const"}); oast.append(ast.body[0], decl);
oast.insert(parent, node, index)
添加一个节点,将其作为子节点连接到父节点中,将其插入在子节点数组中的指定位置。
const decl = oast.buildNode("VariableDeclaration", {kind: "const"}); oast.insert(ast.body, decl, 1);
oast.replace(parent, node, newNode)
替换一个节点,将其替换为另一个节点。注意,这个函数不会修改原对象,而是返回一个新的节点对象。
const newBinary = oast.buildNode("BinaryExpression"); const oldBinary = ast.body[0].declarations[0].init; const newAst = oast.replace(ast, oldBinary, newBinary);
oast.remove(parent, node)
删除一个节点,可以将其从父节点中分离并返回,或者你可以传递一个true
参数,以仅仅分离节点。
// remove and return const binary = ast.body[0].declarations[0].init; const removed = oast.remove(ast, binary); // just remove oast.remove(ast, binary, true);
规则引擎
规则引擎是Oast的一个方便功能。它可以让你创建一组规则以操作AST树,如遍历、过滤、添加、编辑等。你可以使用createRule()
函数建立规则:
const rule = oast.createRule({ enter(node, parent) {}, leave(node, parent) {} }); oast.applyRule(rule, ast);
请注意,createRule()
创建一个规则对象,它有两个函数:enter()
和leave()
,在每个节点进入和离开时调用。这些函数都有两个参数:节点本身和它的父节点。在调用这些函数时,当前节点的子节点还没有被访问并扫描。因此,你可以使用规则引擎来进行许多操作:
-- -------------------- ---- ------- -- -------------- ----- ------ - ----------------- ----------- ------- - -- ---------- --- ----------------- - ------------------- --- ------------ - - --- ---------------------- -----
skip()
通过skip()
函数让规则引擎跳过当前节点并遍历它的子节点。
-- -------------------- ---- ------- ----- ------ - ----------------- ----------- ------- - -- ---------- --- -------------- - ------------ ----------------------- - - --- ---------------------- -----
这个例子中,当访问IfStatement
节点时会使用skip()
函数跳过它,防止它被规则引擎访问两次。
remove()
通过remove()
函数从AST树中删除节点。
-- -------------------- ---- ------- ----- ------ - ----------------- ----------- ------- - -- ---------- --- ----------------- - ------------------- ------ - - --- ---------------------- -----
这个例子中,当访问BlockStatement
节点时,会删除它并将其从当前节点的子节点中删除。
总结
Oast是一个出色的工具,可以用于操作AST。它可以轻松地构建、操作和遍历AST树,提供了一些有用的函数和规则引擎功能。本教程介绍了节点对象、属性访问和节点操作的基本知识,同时详细展示了它如何在实际场景中使用。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/60066f953d1de16d83a66ce6