14

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

1

4 Answers 4

4
+50

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)

Sign up to request clarification or add additional context in comments.

8 Comments

any error youll be able to catch really, just place the try/catch at strategic places
also you can run the file trough some tools like jslint, and set the 'use strict' directive globally for the file, to catch some errors outside of the vm
Thanks for the answer, but unfortunately, this cannot catch SyntaxError.
@MartinMajer ah syntaxerrors, then why should this have to catch that, you ahv eth file, contents, and you know its javascript. Open a browser and load the file, include the file with node require, use js lint, all of these will tell you the error, line and character location
The source code is dynamically generated (compiled from a template file to JavaScript), so I can't do this.
|
3

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

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

2 Comments

Thanks. Unfortunately, e.stack contains only the line number of the vm.runInNewContext call (not the line number in the executed code).
@MartinMajer You can try using util.inspect(e); ( nodejs.org/api/util.html ) however I doubt you'll be able to get more info.
0

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.

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.