estraverseを若干使いやすくする小技
生estraverseの問題
estraverse
は素直に書くと
↓みたいになるのでif文が増えて結構見づらくなってきます。
estraverse.traverse(ast, { enter: function (node, parent) { if (node.type == 'FunctionExpression' || node.type == 'FunctionDeclaration') return estraverse.VisitorOption.Skip; }, leave: function (node, parent) { if (node.type == 'VariableDeclarator') console.log(node.id.name); } });
理想
ESLintのルールみたいにnodeのtype毎かつenter/leave時で処理を分けたい。
https://github.com/eslint/eslint/blob/master/lib/rules/complexity.js
module.exports = function(context) { // ... // ESLintだと↓な感じで書ける return { "FunctionDeclaration": startFunction, "FunctionExpression": startFunction, "ArrowFunctionExpression": startFunction, "FunctionDeclaration:exit": endFunction, "FunctionExpression:exit": endFunction, "ArrowFunctionExpression:exit": endFunction, // ... }; };
解決案
ラップしてあげればいいんじゃないかと。
function walk(ast, visitors) { return estraverse.traverse(ast, { enter: function(node, parent) { var visitor = visitors[node.type]; if (visitor) { return visitor.call(this, node, parent); } }, leave: function(node, parent) { var visitor = visitors[node.type + ':exit']; if (visitor) { return visitor.call(this, node, parent); } }, }); } // ↓みたいに書ける walk(ast, { "FunctionDeclaration": startFunction, "FunctionExpression": startFunction, "ArrowFunctionExpression": startFunction, "FunctionDeclaration:exit": endFunction, "FunctionExpression:exit": endFunction, "ArrowFunctionExpression:exit": endFunction });
ちなみに
ESLint内部ではEventEmitterを使っていますが、
eslint/eslint.js at 7ebb027a12b4ec49fa6996abd05ef99dd91f5932 · eslint/eslint · GitHub
return this.skip()
とかできた方が良いと思うので、この書き方で。