Martin Majer
Martin Majer

Reputation: 3352

Line number of SyntaxError in Node.js

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:

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).

Upvotes: 14

Views: 11674

Answers (4)

fend25
fend25

Reputation: 163

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)

Upvotes: 0

Paul Scheltema
Paul Scheltema

Reputation: 2043

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)

Upvotes: 4

Paul Mougel
Paul Mougel

Reputation: 17048

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.

Upvotes: 0

freakish
freakish

Reputation: 56547

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

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

Upvotes: 3

Related Questions