es**シリーズの仕様意訳第二回。前回はesprimaでした。今回はestraverse。
estraverse
estraverseはASTの巡回コードをお手軽に書けるようにするモジュール。 ASTは子ノードのプロパティ名がまちまちなので、巡回させるコードを書くのが結構手間なんで重宝する。
基本的にesprimaの吐いたASTをestraverse.traverseに喰わせるだけでOK。 ここらへんも本当によくできていて、esprimaとestraverseは疎結合を保っている(AST仕様のみで結びついているといってもよい)。
ではいってみよう。estraverseと、ASTを吐かせるためのesprimaをnpmからとってくる。
npm install esprima npm install estraverse
以下のようにコードを作成。
var esprima = require('esprima'); var estraverse = require('estraverse'); var code = 'console.log("Hello, World!");'; var ast = esprima.parse(code); estraverse.traverse(ast, { enter: function(currentNode, parentNode) { console.log(currentNode.type, parentNode && parentNode.type); // this.skip(); // スキップする。 // this.break(); // 巡回を終わらせる。 }, leave: unction(currentNode, parentNode) { console.log(currentNode.type, parentNode && parentNode.type); // this.skip(); // スキップする。 // this.break(); // 巡回を終わらせる。 } });
おわり。
/** * ASTを深さ優先探索で巡回する。 * @param {AstNode} root ASTのルートノード。 * @param {EstraverseVisitor} visitor 巡回オブジェクト(Visitorパターン)。 */ estraverse.traverse; /** * estraverse.traverseの第二引数。 */ EstraverseVisitor = { /** * ノードに訪れたときに実行される。thisにestraverse.Controllerのインスタンスにアクセスできる。 * @param {AstNode} currentNode 訪問したノード。 * @param {AstNode} parentNode 訪問したノードの親ノード。 * @this {estraverse.Controller} */ enter: function(currentNode, parentNode) {}, /** * ノードから去るときに実行される。thisにestraverse.Controllerのインスタンスにアクセスできる。 * @param {AstNode} currentNode 去るノード。 * @param {AstNode} parentNode 去るノードの親ノード。 * @this {estraverse.Controller} */ leave: function(currentNode, parentNode) {}, };
巡回の制御については、EstraverseVisitor.enter
EstraverseVisitor.leave
の this
に割り当てられた estraverse.Controll
インスタンスを通じておこなうか、戻り値に estraverse.VisitorOption.BREAK
、 estraverse.VisitorOption.SKIP
を指定することでおこなえる。また、訪問先のAstNodeの祖先ノード達は、 estraverse.Controll#parents
の実行(要するにthis.parents();
)で取得できる。
おわり。