如何从script.runInContext的结果中无损获取AST表示?
解决方案
核心问题原因
JSON.stringify会忽略对象中的函数属性,因此无法通过它获取函数源码;而acorn仅能解析字符串形式的JavaScript代码,不能直接处理JS对象,必须先把对象中的函数转换为源码字符串,再拼接成合法的对象代码文本。
方法1:利用函数toString()提取源码
执行vm得到result后,直接调用函数的toString()方法获取其源码,再手动拼接成目标格式的代码字符串:
const vm = require("vm"); const acorn = require("acorn"); let p = `(function (X) { var q = 0; for (; q < 5; ) { // do some stuff anotherfunc = function (a) { while (X === "somestring") { X += "_"; } }; q++; } return { anotherfunc: anotherfunc }; })("some arg"); `; const script = new vm.Script(p); const context = vm.createContext({}); const result = script.runInContext(context); // 提取函数源码 const funcSource = result.anotherfunc.toString(); // 拼接成合法的对象代码字符串(注意属性用逗号而非分号) const targetCode = `{ anotherfunc: ${funcSource} }`; // 传给acorn解析AST const ast = acorn.parse(targetCode, { ecmaVersion: "latest" }); console.log(ast);
方法2:在vm代码中直接返回函数源码
如果担心toString()返回格式不符合预期,可修改vm中的代码,让它同时返回函数和对应的源码字符串:
let p = `(function (X) { var q = 0; for (; q < 5; ) { // do some stuff anotherfunc = function (a) { while (X === "somestring") { X += "_"; } }; q++; } // 同时返回函数和其源码 return { anotherfunc: anotherfunc, anotherfuncSource: anotherfunc.toString() }; })("some arg"); `; // 后续直接使用result.anotherfuncSource拼接代码字符串即可
将结果保存到文件
拿到合法的targetCode后,用Node.js的fs模块即可写入文件:
const fs = require("fs"); // 写入文件 fs.writeFileSync("output.js", targetCode);
关键说明
- acorn无法直接解析JS对象,必须传入字符串形式的代码文本,这是由其JavaScript解析器的定位决定的。
- 函数的
toString()方法在Node.js环境中通常会返回完整的函数源码(除非代码被压缩或特殊处理),足以满足acorn的解析需求。
内容的提问来源于stack exchange,提问作者younes zeboudj
相关产品推荐
相关产品推荐

