Javascript : Error position evaluating a JS Function('...my code as string')

291 views Asked by At

We've some user defined fields defining javascript functions and would like to show the user the position ( line, column ) when an error is thrown. For example :

userFunc = new Function('context',  '{  let a = 0; \n context.missingFunction(); return 2; }');

When evaluating userFunc

userFunc({});

an exception is thrown, that looks like :

 context.missingMeethod is not a function 

Is there a library to retrieve the position of the error in all modern browsers (e.g. : line 2, column 12 )

error-stack-parser library (from StacktraceJS) is not retrieving the information. In Chrome the stacktrace looks like (the position is in anonymous):

TypeError: context.missingMeethod is not a function
    at eval (eval at <anonymous> (http://localhost:3000/icCube/reporting/static/js/main.chunk.js:28541:66), <anonymous>:2:12)
1

There are 1 answers

0
Wouter Raateland On

This seems to be possible in Chrome, Firefox and Safari at least. I'm not sure how well this generalizes, but it might give you something to work from!

In Chrome:

getErrorPosition = (userFunc) => {
    try {
        userFunc({});
        return null;
    } catch (error) {
        const relevantLine = error.stack.split('\n')[1];
        const regex = /<anonymous>:(\d+):(\d+)\)/g;
        const match = regex.exec(relevantLine);
        if (match) {
            return {
                line: parseInt(match[1], 10),
                column: parseInt(match[2], 10)
            };
        } else {
            return null;
        }
    }
}

In Safari:

getErrorPosition = (userFunc) => {
    try {
        userFunc({});
        return null;
    } catch (error) {
        return {
            line: error.line,
            column: error.column,
        };
    }
}

In Firefox:

getErrorPosition = (userFunc) => {
    try {
        userFunc({});
        return null;
    } catch (error) {
        const relevantLine = error.stack.split('\n')[0];
        const regex = /Function:(\d+):(\d+)/g;
        const match = regex.exec(relevantLine);
        if (match) {
            return {
                line: parseInt(match[1], 10),
                column: parseInt(match[2], 10)
            };
        } else {
            return null;
        }
    }
}