Home » Nodejs » Line number of SyntaxError in Node.js

Line number of SyntaxError in Node.js

Posted by: admin November 30, 2017 Leave a comment

Questions:

I have some code that uses vm module and runInNewContext function and executes dynamically generated JavaScript code. Basically a safer option of eval.

The code (variable code) can possibly contain syntax errors, so I would like to catch them and print some useful information.

try {
    vm.runInNewContext(code, sandbox, filename);
}
catch (e) {
    if (e instanceof SyntaxError) { // always false
        console.log(e.toString()); // "SyntaxError: Unexpected token ||" for example
        console.log(e.line); // how to get the line number?
    }
}

I’d like to print the number of the line with the syntax error, but I have two problems:

  • I don’t know how to recognize whether the exception is SyntaxError or something else. instaceof doesn’t work (update – I can use e.name === "SyntaxError").
  • Even if I was able to recognize it, how could I get the line number? Is it possible?

Thanks in advance.

Update: I can get some information from e.stack – however, the topmost call in the stack trace is runInNewContext (with its line number), but I still can’t find the line number inside code, which caused the exception (SyntaxError).

Answers:

1) Use if (e.name === "SyntaxError").

2) All data associated with the error is kept in e.stack.

Questions:
Answers:

use a try/catch

store the stack in a global variable

log the sandbox

var util = require('util');
var vm = require('vm');
var sandbox = {e:null};
var src = 'try{count += 1;}catch(err) {e=err.stack}';

vm.runInNewContext(src , sandbox, 'myfile.vm');
console.log(util.inspect(sandbox));

this will log:

{ e: ‘ReferenceError: count is not defined\n at myfile.vm:1:13\n

now you can see that the error occurs at line 1, character 13 of myfile.vm
this will still require you to place some try/cathc blocks at various places
but at least you can get feedback now

EDIT:

Adding a method to detect Syntax errors from within your running code

var acorn = require('acorn');
var src = "try{\n"+
    "   {" +
    "       count += 1;\n"+
    "   }catch(err) {\n" +
    "       e=err.stack\n" +
    "}";

var result = acorn.parse(src);

doing this will result in a thrown Exception with
“SyntaxError: Unexpected token (3:4)”
eg. line 3, character 4 is the unexpected token, (the extra { that shouldnt be there)

Questions:
Answers:

Although a bit (very) old, you can use the stackedy module, which can help you manipulate stack traces. It isn’t the perfect solution though, as the line number displayed is the line number inside the function call, and not the line number in the source file.

In particular, look at the simple example:

index.js

var stackedy = require('stackedy');
var fs = require('fs');

var src = fs.readFileSync(__dirname + '/src.js');
var stack = stackedy(src, { filename : 'stax.js' }).run();

stack.on('error', function (err, c) {
    stack.stop();
    console.log('Error: ' + err);

    var cur = c.current;
    console.log('  in ' + cur.filename + ' at line ' + cur.start.line);

    c.stack.forEach(function (s) {
        console.log('  in ' + s.filename + ', '
            + s.functionName + '() at line ' + s.start.line
        );
    });
});

src.js

function f () { g() }
function g () { h() }
function h () { throw new SyntaxError('woops') }

f();

Output:

~/tmp ❯❯❯ node index.js
Error: SyntaxError: woops
  in stax.js at line 2
  in stax.js, h() at line 1
  in stax.js, g() at line 0
  in stax.js, f() at line 4

As noted in the comments, you can use err.name === 'SyntaxError' to check for the error type.

Questions:
Answers:

For *nix:

if (err) console.log(err.stack.split('\n')[1]);

It will log second line of stacktrace, the point where the error occured.

Windows or mac can require other split symbol (depends on system line endings)