JSのASTを扱うライブラリをつかって、不要なeval呼び出しを除くコードを書いてみた

こんばんは。寿司とサンドイッチとケーキをたべました、きたけーです。

今日は 東京Node学園祭2014 に参加しました。
個人的にt-wadaさんのセッションが面白くて( power-assert, mechanism and philosophy )、自分が思っていたよりもJSでASTを扱うことがカジュアルにできるようだったので、いっちょ自分もやってみました。

不要なevalを消す

仕事で、使う必要がないのにevalをつかっているコードをちょくちょく見かけます。こんなかんじのやつです

var frm = eval("document.frm");
frm.name = "foo";

パフォーマンスが悪くなるし、害なだけなので消したいんですけど、検索してポチポチ消していくのは面倒ですし、プログラムにやらせて楽をします( この程度だったらASTに変換する必要はなくて正規表現で十分だと思うんですけどよしとしましょう... )。
こんなかんじ

var esprima = require('esprima');
var estraverse = require('estraverse');
var escodegen = require('escodegen');
var fs = require('fs');

fs.readFile('./source.js', function (err, source) {
  if (err !== null) {
    return;
  }
  var ast = esprima.parse(source);
  estraverse.traverse(ast, {
    enter: function (node, parent) {
      if (node.type === 'CallExpression' && node.callee.name === 'eval' && node.arguments[0].type === 'Literal') {
        node = esprima.parse(node.arguments[0].value).body[0];
        parent.init = node.expression;
      }
    }
  });
  console.log(escodegen.generate(ast));
});

いくつかライブラリを使っていますが、

  • esprima はJSのコードをASTに変換するJSのライブラリ
  • estraverse はASTを走査するJSのライブラリ
  • escodegen はASTからJSのコードを生成するJSのライブラリ

です。

さきほどの例を食わせるとこうなります。

var frm = document.frm;
frm.name = 'foo';

便利。