Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I hide a function call from transpiled code using source maps?

Let's say I have a language that looks like

print "Hello World"

which transpiles to

var $__Helpers = {
    print: function(s) {
        if (typeof s != 'string')
            throw new TypeError('String expected');
        console.log(s);
    }
};

$__Helpers.print("Hello World");

If a user of this language does

print 5

a TypeError will be thrown by $__Helpers.print saying "String expected". I want the developer tools to show the print 5 line as the originating call for this error. I know how to get my source map to show a call stack that looks like

transpiled_script.js:2
original_script.os:1

where transpiled_script.js:2 is the script and line number for the call to the $__Helpers.print function and original_script.os:1 is the script and line number for the call to print 5. I want to have the dev tools just ignore the top call to transpiled_script.js (which is only an implementation detail of my transpiler) and only show the call from the original script (which is the part that they should debug in their own script).

I clearly can't simply map transpiled_script.js:2 to original_script.os:1 because there could be multiple calls to print inside original_script.os, so it's not a 1 to 1 relationship.

Is there any way to do this?

(I am using escodegen to generate my source and my source map (escodegen uses the Node mozilla/source-map module), so having a way to tell escodegen or mozilla/source-map to do this would be ideal, but I can override escodegen's output if that's not possible.)

like image 637
Nathan Wall Avatar asked Sep 29 '13 02:09

Nathan Wall


1 Answers

You may split the trace and print the required lines of it

var $__Helpers = {
    print: function(s) {
        if (typeof s != 'string'){
            var err = new TypeError('String expected');
            var trace = err.stack.split('\n')
            console.error(trace[0]); // TypeError: string expected
            console.error(trace[2]); // the line who called the function, probably 
            //original_script.os:1, or whatever line number the call was from
            //quit the script

        }
        console.log(s);
    } };

EDIT: a better solution, is to replace the trace of the error, than throw it, the code now look like this:

var $__Helpers = {
    print: function(s) {
        if (typeof s != 'string'){
            var err = new TypeError('String expected: Got'+s);
            err.stack = err.stack.replace(/\n.*transpiled_script\.js.*?\n/g,"\n");
            throw err;

        }
        console.log(s);
    } };

this will work for errors in nested called too.

like image 57
Ohad Cohen Avatar answered Nov 03 '22 06:11

Ohad Cohen