无调试器时如何为JavaScript每行添加console.log(行号)?
为每行代码添加执行日志的AST实现问题
调试器并非追踪代码执行的理想方式,我希望在控制台输出程序的完整执行轨迹,以此查看代码的执行时机。我认为使用**抽象语法树(AST)**是可行方案,但编写的实现代码无法正常工作。
例如,输入代码:
if (true) alert('hi');
我希望将其转换为:
if (true) {console.log(16); alert('hi');}
我并非JavaScript专家,无法独立实现该功能,恳请帮助!
已尝试的方案
- 需要为每一行代码添加日志,而非仅为函数添加
- 尝试了以下基于esprima和escodegen的代码,思路看似正确,但未达到预期效果,遗漏了大部分代码行:
const esprima = require('esprima'); const escodegen = require('escodegen'); const fs = require('fs'); // 从文件读取JavaScript代码 const code = fs.readFileSync('input.js', 'utf-8'); // 将JavaScript代码解析为AST const ast = esprima.parseScript(code, { loc: true }); // 用于在代码行末尾添加console.log语句的函数 function addConsoleLog(node) { const consoleLogNode = { type: 'ExpressionStatement', expression: { type: 'CallExpression', callee: { type: 'MemberExpression', object: { type: 'Identifier', name: 'console' }, property: { type: 'Identifier', name: 'log' }, }, arguments: [{ type: 'Literal', value: node.loc.end.line }], }, }; return consoleLogNode; } // 遍历AST并添加console.log语句 function traverseAST(node) { if (node.type === 'Program' || node.type === 'BlockStatement') { for (let i = 0; i < node.body.length; i++) { traverseAST(node.body[i]); if (node.body[i].type !== 'FunctionDeclaration' && node.body[i].type !== 'VariableDeclaration') { node.body.splice(i + 1, 0, addConsoleLog(node.body[i])); i++; } } } else if (node.type === 'IfStatement') { traverseAST(node.consequent); if (node.alternate) { traverseAST(node.alternate); } } else if (node.type === 'ForStatement' || node.type === 'WhileStatement' || node.type === 'DoWhileStatement') { traverseAST(node.body); } else if (node.type === 'TryStatement') { traverseAST(node.block); if (node.handler) { traverseAST(node.handler.body); } if (node.finalizer) { traverseAST(node.finalizer); } } else if (node.type === 'SwitchStatement') { node.cases.forEach(traverseAST); } else if (node.type === 'ConditionalExpression') { if (node.consequent.type !== 'CallExpression' && node.consequent.type !== 'AssignmentExpression') { node.consequent = { type: 'SequenceExpression', expressions: [node.consequent, addConsoleLog(node)], }; } if (node.alternate.type !== 'CallExpression' && node.alternate.type !== 'AssignmentExpression') { node.alternate = { type: 'SequenceExpression', expressions: [node.alternate, addConsoleLog(node)], }; } } } // 遍历AST并添加console.log语句 traverseAST(ast); // 生成修改后的JavaScript代码 const modifiedCode = escodegen.generate(ast); // 将修改后的代码写入文件 fs.writeFileSync('output.js', modifiedCode);
内容的提问来源于stack exchange,提问作者William Dvorak
相关产品推荐
相关产品推荐

