Javascript 使用节点js中的抽象语法树获取行号

Javascript 使用节点js中的抽象语法树获取行号,javascript,node.js,abstract-syntax-tree,Javascript,Node.js,Abstract Syntax Tree,我正在制作一个程序,通过参数获取一些代码,并在代码中添加一些console.log来转换代码。以下是节目: const escodegen = require('escodegen'); const espree = require('espree'); const estraverse = require('estraverse'); function addLogging(code) { const ast = espree.parse(code); estraverse.

我正在制作一个程序,通过参数获取一些代码,并在代码中添加一些console.log来转换代码。以下是节目:

const escodegen = require('escodegen');
const espree = require('espree');
const estraverse = require('estraverse');

function addLogging(code) {
    const ast = espree.parse(code);
    estraverse.traverse(ast, {
        enter: function(node, parent) {
            if (node.type === 'FunctionDeclaration' ||
                node.type === 'FunctionExpression') {
                addBeforeCode(node);
            }
        }
    });
    return escodegen.generate(ast);
}

function addBeforeCode(node) {
    const name = node.id ? node.id.name : '<anonymous function>';
    const beforeCode = "console.log('Entering " + name + "()');";
    const beforeNodes = espree.parse(beforeCode).body;
    node.body.body = beforeNodes.concat(node.body.body);
}
这是该程序的输出:

function foo(a, b) {
    console.log('Entering foo()');
    var x = 'blah';
    var y = function () {
        console.log('Entering <anonymous function>()');
        return 3;
    }();
}
foo(1, 'wut', 3);
函数foo(a,b){ log('输入foo()'); 变量x=‘废话’; 变量y=函数(){ console.log('输入

因此,我想在控制台日志中添加更多信息,例如我们所在的行号。据我所知,在ast中,节点有一个标有“开始”和“结束”的值,该值指示节点从哪个字符开始以及在哪里结束。我如何使用该值来获取我们所在的行号?老实说,这对我来说似乎很困惑。我认为It’我正在考虑用“\n”来拆分文件,这样我就可以得到总行号,但是我怎么知道我在哪一行呢


提前谢谢。

您的想法很好。首先找到原始代码中每行开始的偏移量。然后将节点的
开始
索引与收集的索引进行比较,以确定行号

这里我假设您希望报告的行号引用原始代码,而不是函数返回的代码

因此,自下而上,进行以下更改。首先,将行号作为
addBeforeCode
的参数:

function addBeforeCode(node, lineNum) {
    const name = node.id ? node.id.name : '<anonymous function>';
    const beforeCode = `console.log("${lineNum}: Entering ${name}()");`;
    const beforeNodes = espree.parse(beforeCode).body;
    node.body.body = beforeNodes.concat(node.body.body);
}
注意:如果您支持
matchAll
,那么上面的内容可以写得更简洁一些

然后在主要功能中使用上述功能:

console.log(addLogging(`
function foo(a, b) {   
  var x = 'blah';   
  var y = (function () {
    return 3;
  })();
}
foo(1, 'wut', 3);
`));
function addLogging(code) {
    const lineStarts = getLineOffsets(code);   // <---
    let lineNum = 0;                           // <---
    const ast = espree.parse(code);
    estraverse.traverse(ast, {
        enter: function(node, parent) {
            if (node.type === 'FunctionDeclaration' ||
                     node.type === 'FunctionExpression') {
                // Look for the corresponding line number in the source code:
                while (lineStarts[lineNum] < node.body.body[0].start) lineNum++;
                // Actually we now went one line too far, so pass one less:
                addBeforeCode(node, lineNum-1);
            }
        }
    });
    return escodegen.generate(ast);
}
函数addLogging(代码){

const linestart=getlineoffset(代码);//由于代码将在最后重新生成,源代码中的行号将与结果中的行号不同。删除空行,可以添加换行符,
控制台.log
additions会添加行。那么:行号应该引用哪个版本的代码?源代码还是返回的代码?
function addLogging(code) {
    const lineStarts = getLineOffsets(code);   // <---
    let lineNum = 0;                           // <---
    const ast = espree.parse(code);
    estraverse.traverse(ast, {
        enter: function(node, parent) {
            if (node.type === 'FunctionDeclaration' ||
                     node.type === 'FunctionExpression') {
                // Look for the corresponding line number in the source code:
                while (lineStarts[lineNum] < node.body.body[0].start) lineNum++;
                // Actually we now went one line too far, so pass one less:
                addBeforeCode(node, lineNum-1);
            }
        }
    });
    return escodegen.generate(ast);
}