27

In JavaScript I have a var str = ".a long string that contains many lines..." In case of exception that caused by eval(str);

I had like to catch it and print the the line number that caused the exception. (the line internal to str..)

Is it possible?

EDIT As part of the Alligator project (http://github.com/mrohad/Alligator), an application server for JavaScript, I am reading files from the disk and eval() anything that is nested to a scriplet( < ? ? > )

I am running this script outside a browser, using NodeJS (on top of V8).

DuduAlul
  • 6,313
  • 7
  • 39
  • 63
  • 2
    Not sure this can be done at all without splitting the multi-line command into separate instructions and eval() calls. – Pekka Aug 15 '10 at 20:01
  • 2
    It's pretty ugly to use "eval" in the first place. Perhaps you could describe what you're trying to do, and somebody might have a better idea. – Pointy Aug 15 '10 at 20:06
  • 1
    The problem with splitting the eval to multi lines is for example when you have if(cond) <- line #1 {some code} <- line #2, line 1 will throw exception since it depends on line #2 – DuduAlul Aug 15 '10 at 20:12
  • 1
    I assumed that in an age of AJAX someone would want a solution to this. I am having the same [problem](http://stackoverflow.com/questions/7265371/how-to-properly-generate-exceptions-in-php-dojo-when-returning-javascript-code) – puk Oct 22 '11 at 23:30
  • 1
    @MrOhad - checkout this Google V8 issue http://code.google.com/p/v8/issues/detail?id=1914 – BMiner May 30 '12 at 14:11

5 Answers5

5

Try adding the try/catch to the string instead of around the eval:

var code = 'try{\nvar c = thisFuncIsNotDefined();\n}catch(e){alert(e.lineNumber);}';
Steve Brewer
  • 2,062
  • 2
  • 14
  • 15
  • I thought it's even better than my solution, but I have tested it and it doesn't work, same stack as if the try{} catch{} wasn't part of the eval – DuduAlul Aug 15 '10 at 21:20
  • combine this with the solution from @AndreyKo and you have a solution that will work in Firefox – Michael Oct 23 '13 at 18:14
  • 4
    also doesn't work if the string has a syntax error, because the try/catch isn't even able to be constructed properly to catch the error! – Michael Oct 19 '14 at 02:24
  • 1
    The question was about **NodeJS** with which this answer **doesn't work**. `e.lineNumber` is `undefined` there. – Serg Oct 25 '18 at 11:51
3

1) Run:

var javascript_offset;
try {
  undefined_function();
} catch(ex1) {
  javascript_offset = ex1.lineNumber;
}
try {
  YOUR_STRING_WITH_JS
} catch (ex2) {
  var line_that_caused_it = ex2.lineNumber - javascript_offset -2;
  HANDLE_THE_EXCEPTION_HERE
}
AndreyKo
  • 901
  • 7
  • 16
3

I found a solution which is pretty inefficient, yet I only use it when debug_mode==1 so it's not that bad..

I write the eval_str to a file, I "import that file, and invoke it inside a try{}catch{} and I parse the error line from the stack trace...

In my specific case, this is how the code looks like:

var errFileContent = "exports.run = "+evalStringAsAFunction+";";
fs.writeFile('/home/vadmin/Alligator/lib/debugging.js', errFileContent, function (err) {
    var debug = require('./debugging');
    try{
         debug.run(args...);
    }
    catch(er){
         log.debug(parseg(er));
    }
});
DuduAlul
  • 6,313
  • 7
  • 39
  • 63
  • 1
    This is an inefficient hack, but it's definitely a workaround until Google V8 supports this feature. Nice, thx. – BMiner May 30 '12 at 14:12
0
replaceErrors(key, value) {
    if (value instanceof Error) {
      var error = {};
      Object.
        getOwnPropertyNames(value).
        forEach(function (key) {
          error[key] = value[key];
        });
      return error;
    }
    return value;
  }
const errorStr = JSON.stringify(error.stack, this.replaceErrors);
const regexp = 'your reg';
          let isHasLineNum = regexp.exec(errorStr);
          let lineNum
          if (isHasLineNum) {
            lineNum = isHasLineNum[0];
          }
-2

This solves your problem?

try {
    eval(str);
} catch (e) {
    console.log(e.lineNumber)
}
Topera
  • 12,223
  • 15
  • 67
  • 104
  • 5
    @MrOhad, the `lineNumber` property on Error objects is *non-standard*, it will work only on Mozilla implementations, but I'm afraid that it will return you the line number where you invoked `eval`, not the actual line number inside the evaluated text. – Christian C. Salvadó Aug 15 '10 at 20:24
  • 1
    Works in Firefox, but not other browsers. In Chrome/Iron, you can get the row number close to the end of `e.stack`. – Gert Grenander Aug 15 '10 at 20:24
  • e.stack doesn't return undefined yet it does return the line of the eval and not the line internal to the eval string – DuduAlul Aug 15 '10 at 20:27
  • Can you say what does e contain? – AndreyKo Aug 15 '10 at 20:33
  • Sure: message: aasas is not defined; stack: ReferenceError: aasas is not defined at eval at serverSideScripting (/home/vadmin/Alligator/lib/jssp.js:262:4)...; type: not_defined; arguments: aasas; name: ReferenceError; – DuduAlul Aug 15 '10 at 20:37
  • e is an exception. In firefox it has many properties, like: fileName, lineNumber, message, name and stack. Why I get -1? – Topera Aug 15 '10 at 20:48
  • 3
    This answer is incorrect. The question asks if you can get the line number inside the eval'ed text, not the line number where eval() was called. – BMiner May 30 '12 at 14:07
  • @BMiner, this answer is not correct. It doesn't work consistently in all JS environments. `e.lineNumber = undefined` in NodeJS for example. And the question was exactly about NodeJS. – Serg Oct 25 '18 at 07:41
  • V8 has long been fixed so _runtime_ errors inside eval() show `:LINE:COLUMN` of where it happened inside the eval'd code (https://bugs.chromium.org/p/v8/issues/detail?id=1914). E.g. that part works for me on NodeJS 18. However _SyntaxError_ stack still reports caller of eval() :-( – Beni Cherniavsky-Paskin Jun 11 '23 at 15:26