Node.jsで内部変数・関数の取得
概要
テストやちょっとしたツールを作りたいときに内部変数・関数にアクセスしたい時がありますが、
そんなときに便利なのがvm
モジュールです。しかしvm
ではvar
の変数は取得できるものの、let
やconst
の変数は取得できません。
そこで色々試行錯誤して作ったツールについて書きます。
vmを用いた内部関数の取得
vm.runInNewContext
ではコードを実行時にglobalオブジェクトをセットすることができます。vm.runInThisContext
は自動的に現在のglobalオブジェクトが使われます。
この関数は実行時にglobalスコープ上のvar
をglobalオブジェクトに代入することで外からのアクセスを可能にしてくれますが、let
やconst
は変換されません。
sample.js
const test1 = 'test1'; let test2 = 'test2'; var test3 = 'test3'; function test(arg1, arg2, arg3) { const sum = arg1 + arg2 + arg3; let num1 = 1; var num2 = 2; num3 = 3; return sum + num1 + num2 + num3; }
exec.js
const vm = require('vm'); const fs = require('fs'); const path = require('path'); const filepath = path.resolve(__dirname, 'sample.js'); const file = fs.readFileSync(filepath, 'utf8'); const context = {}; vm.runInNewContext(file, context); console.log(context); /* * { test3: 'test3', * test: [Function: test] } // let, constが取得できない */
vm-agent
今回作ったツールはlet
, const
が取得できるのと、関数を自動実行して値を取得できるツールを作りました。
また関数の実行も可能です。
const fs = require('fs'); const path = require('path'); const { Agent } = require('vm-agent'); const filepath = path.resolve(__dirname, ''sample.js'); const file = fs.readFileSync(filepath, 'utf8'); const result1 = new Agent(file) .run() .getInnerVariable(); console.log(result1); /* * { test1: 'test1', * test2: 'test2', * test3: 'test3', * test: [Function: test] } */ const result2 = new Agent(result1.test) .setArguments(4, 5, 6) .run() .getInnerVariable(); console.log(result2); /* * { arg1: 4, * arg2: 5, * arg3: 6, * sum: 15, * num1: 1, * num2: 2, * num3: 3 } */
vm-agent/example at master · suguru03/vm-agent · GitHub
実装内容
実装内容はesprima
を用いてlet
, const
をvar
に変換し、escodegen
を用いてコードを再構築し実行するというものです。const
が上書きできてしまったりパフォーマンスが低下したりしますが、テスト用なのでいったん良しとします。
また関数の実行については、関数の引数を解析し変数に変換することでvm
モジュールでのアクセスを可能にしています。