Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dynamically load code and get line number of parse error

Tags:

javascript

I have a tool, similar in ways to JSFiddle, that allows me to dynamically type in javascript and run it on a page. The code can be multiple lines, and typically will be.

Unfortunately if there is an exception in the code I type in, I can't get the line number of the exception if I use eval() to run the code.

I found a partial solution, which is instead of using

try{
 eval(code);
 }
catch(e) {
 processException(e);
 }

to instead do something like this:

var s = document.createElement('script');
s.appendChild(document.createTextNode(
    "try{\n" + 
     code +
     "}catch(e){processException(e)}"));
document.body.appendChild(s);

Now, if the code throws an exception, and I look at the stack trace(in my processException() function) I can get a line number of the exception (in firefox and chrome, anyway).

That's all well and good if it is actually a runtime exception, such as a variable not being defined. The problem is if there is a parse error / syntax error, such as mismatched parens or the like. I get nothing.

Is there any crazy workaround for this, that works on firefox and chrome, at a minimum? Eval within eval within script tag within Function object? I'm trying everything and haven't found anything that works.

like image 640
rob Avatar asked Oct 04 '11 05:10

rob


2 Answers

I found a reasonable solution finally.

First, I set window.onerror to some function. This doesn't get a full stack trace, but will get a file and line number.

Then, I do this:

var s = document.createElement('script');
s.appendChild(document.createTextNode(
    "var someUniqueGlobalName = function () {\n" +
     code +
     "\n};";
document.body.appendChild(s);

Note that this doesn't actually run my code, as it simply creates a function (in global scope, with the name 'someUniqueGlobalName' -- which of course I'd really come up with a different name each time I do this).

If there is a syntax error, it will be caught in the window.onerror function, and I can get the error type and line number (which of course I'll have to subtract one from, since I added one line at the beginning).

Now, I unset window.onerror.

Finally, I run the code by calling someUniqueGlobalName() in a try/catch block. Here I can get a full stack trace with line numbers if there is a runtime error.

like image 134
rob Avatar answered Nov 19 '22 03:11

rob


You could take it a step further and integrate JSLINT: https://github.com/douglascrockford/JSLint

It's pretty straightforward.. here's a quick test...

Download: https://raw.github.com/douglascrockford/JSLint/master/jslint.js

jshint_test.html:

<script type="text/javascript" src="jslint.js"></script>
<script>

var result = JSLINT("var some = true;\nif (some) {");

if (result)
{
  alert('Looking good');
}
else
{
  var error_message = '';
  for (i in JSLINT.errors)
  {
    var error = JSLINT.errors[i];
    error_message += error.reason + ' on line: ' + error.line + ' character: ' + error.character + "\n";
  }
  alert(error_message);
}
</script>

Check out the documentation. The second argument to JSLINT is an options object.. there are TONS of options.

like image 29
Jake Avatar answered Nov 19 '22 03:11

Jake