efcl’s blog

GitHub英語のメモや引用が中心です。

Acorn-cspのできた流れ

RReverser/acorn-csp についての話

  1. Not working for web workers · Issue #90 · marijnh/acorn
  2. acornがnew Functionを使うので、CodeMirror経由でacorn使ってる人等がひっかかる
  3. Chrome Appとかも同じ問題
  4. @RReverserさんがAST変換をしたCSP対応バージョンを作る - Not working for web workers · Issue #90 · marijnh/acorn

RReverser/acorn-csprecastを使ってAST変換をしてる。

アプローチ

new FunctionmakePredicateという関数のみで使ってるので、 これを置き換えた関数に一度書き換えてる。

acorn/acorn.js at a246bf83d00f6888268997dbf55533bb33e66bd3 · marijnh/acorn

'function makePredicate(words) {' +
' var generatedFn = _makePredicate(words);' +
' makePredicateCache[words] = generatedFn.toString();' +
' return generatedFn;' +
'}'

書き換えた関数は、オリジナルのmakePredicateの実行結果をキャッシュにいれていくだけ。 (元コード見てないけど、多分これでnew Functionによって展開されたものを回収してそう)

書き換えたものをnodeのvmモジュールを使って、 evalを展開した中身を回収してる。

var makePredicateCache = {}; // makePredicateCache[words] に値をnew Functionの結果を入れていってる
vm.runInNewContext(
   recast.prettyPrint(ast).code,
   {makePredicateCache: makePredicateCache}
);

最後、展開した中身をもう一度AST変換して、最初に書き換えていたmakePredicateが、 先ほど作った展開済みの値を返すように書き換えてる。

properties: Object.keys(makePredicateCache).map(function (key) {
    var fnNode = esprima.parse('(' + this[key] + ')').body[0].expression;
    fnNode.id = null;
    return {
        type: 'Property',
        kind: 'init',
        key: {type: 'Literal', value: key},
        value: fnNode
    };
}, makePredicateCache)

vmモジュールを使ってインライン展開チックな事やってるのが面白い