Skip to content

Commit 03350db

Browse files
committed
Considering V8-specific goodies for V8 in error parser, issue stacktracejs#21
1 parent 2d369d7 commit 03350db

File tree

3 files changed

+165
-185
lines changed

3 files changed

+165
-185
lines changed

error-parser.js

Lines changed: 94 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,108 @@
11
// TODO: AMD/CommonJS/etc wrapper
22
(function() {
3-
function StackEntry(functionName, srcUrl, lineNumber, charNumber) {
4-
// TODO: if used without `new` create a new instance
5-
return {
6-
fn: functionName,
7-
args: [],
8-
src: srcUrl,
9-
line: lineNumber,
10-
char: charNumber
3+
// V8 Only: See http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
4+
// TODO: configurable Error.stackTraceLimit = 20;
5+
Error.prepareStackTrace = function(error, stack) {
6+
var stackEntries = [];
7+
for(var i = 1, len = stack.length; i < len; i++) {
8+
var cur = stack[i];
9+
// IDEA: utilize getEvalOrigin: if this function was created using a call to eval returns a CallSite object representing the location where eval was called
10+
if (!cur.isNative()) {
11+
stackEntries.push(new StackEntry(cur.getFunctionName(), cur.getFileName(), cur.getLineNumber(), cur.getColumnNumber()))
12+
}
1113
}
14+
};
15+
16+
function StackEntry(functionName, srcUrl, lineNumber, charNumber) {
17+
this.fn = functionName;
18+
this.args = [];
19+
this.src = srcUrl;
20+
this.line = lineNumber;
21+
this.char = charNumber;
1222
}
23+
1324
function ErrorInfo(stack, message) {
14-
return {
15-
stack: stack,
16-
message: message
17-
}
25+
this.stack = stack;
26+
this.message = message;
1827
}
28+
1929
function ErrorParser() {
2030
// TODO: declare regexps here
21-
return {
22-
/**
23-
* Given an Error object, return the function that
24-
* will extract the most information from it.
25-
* @param e {Error}
26-
* @return Function parser
31+
32+
/**
33+
* Given an Error object, return the function that
34+
* will extract the most information from it.
35+
* @param e {Error}
36+
* @return Function parser
37+
*/
38+
this.chooseParser = function(e) {
39+
if (e['arguments'] && e.stack) {
40+
return this.parseV8;
41+
} else if (e.stack && e.sourceURL) {
42+
return this.parseNitro;
43+
} else if (e.stack && e.number) {
44+
return this.parseChakra;
45+
} else if (e['opera#sourceloc'] || e.stacktrace) {
46+
return this.parseOPERA;
47+
} else if (e.stack) {
48+
return this.parseSpiderMonkey;
49+
}
50+
return this.parseOther;
51+
};
52+
53+
this.parseV8 = function(e) { // Chrome and node.js
54+
return new ErrorInfo(e.stack, e.message);
55+
};
56+
57+
this.parseNitro = function(e) { //Safari 6
58+
/*
59+
stack: "@file:///Users/eric/src/javascript-stacktrace/test/functional/ExceptionLab.html:48\n" +
60+
"dumpException3@file:///Users/eric/src/javascript-stacktrace/test/functional/ExceptionLab.html:52\n" +
61+
"onclick@file:///Users/eric/src/javascript-stacktrace/test/functional/ExceptionLab.html:82\n" +
62+
"[native code]"
2763
*/
28-
chooseParser: function(e) {
29-
if (e['arguments'] && e.stack) {
30-
return this.parseV8;
31-
} else if (e.stack && e.sourceURL) {
32-
return this.parseNitro;
33-
} else if (e.stack && e.number) {
34-
return this.parseChakra;
35-
} else if (e['opera#sourceloc'] || e.stacktrace) {
36-
return this.parseOPERA;
37-
} else if (e.stack) {
38-
return this.parseSpiderMonkey;
39-
}
40-
return this.parseOther;
41-
},
42-
parseV8: function(e) { //Chrome and node.js
43-
/*
44-
stack: "TypeError: Object #<Object> has no method 'undef'\n" +
45-
" at Object.createException (http://127.0.0.1:8000/js/stacktrace.js:42:18)\n" +
46-
" at Object.run (http://127.0.0.1:8000/js/stacktrace.js:31:25)\n" +
47-
" at printStackTrace (http://127.0.0.1:8000/js/stacktrace.js:18:62)\n" +
48-
" at bar (http://127.0.0.1:8000/js/test/functional/testcase1.html:13:17)\n" +
49-
" at bar (http://127.0.0.1:8000/js/test/functional/testcase1.html:16:5)\n" +
50-
" at foo (http://127.0.0.1:8000/js/test/functional/testcase1.html:20:5)\n" +
51-
" at http://127.0.0.1:8000/js/test/functional/testcase1.html:24:4"
52-
*/
53-
var raw = (e.stack + '\n').replace(/^\S[^\(]+?[\n$]/gm, '')
54-
.replace(/^\s+(at eval )?at\s+/gm, '')
55-
.replace(/^([^\(]+?)([\n$])/gm, '{anonymous}()@$1$2')
56-
.replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm, '{anonymous}()@$1')
57-
.split('\n');
64+
// TODO: optimization - can pull these RegExps out and only compile them once
65+
var raw = e.stack.replace(/\[native code\]\n/m, '')
66+
.replace(/^(?=\w+Error\:).*$\n/m, '')
67+
.replace(/^@/gm, '{anonymous}@')
68+
.split('\n');
69+
// TODO: check function identifier defn
70+
var re = /^([\{\}\w]+)@(.*)\:(\d+)(\:(\d+))?$/;
71+
var enhancedStack = raw.filter(function(entry) {
72+
return entry.indexOf('@') !== -1;
73+
}).map(function(entry) {
74+
var m = entry.match(re);
75+
return new StackEntry(m[1], m[2], m[3], m[5]);
76+
});
77+
return new ErrorInfo(enhancedStack, e.message);
78+
};
5879

59-
var re = /^\s+at ([\{\}\w]+) \((.*)\:(\d+)(\:(\d+))?$/;
60-
var enhancedStack = raw.filter(function(entry) {
61-
return entry.indexOf(' (') !== -1;
62-
}).map(function(entry) {
63-
var m = entry.match(re);
64-
return new StackEntry(m[1], m[2], m[3], m[5]);
65-
});
66-
return new ErrorInfo(enhancedStack, e.message);
67-
},
68-
parseNitro: function(e) { //Safari 6
69-
/*
70-
stack: "@file:///Users/eric/src/javascript-stacktrace/test/functional/ExceptionLab.html:48\n" +
71-
"dumpException3@file:///Users/eric/src/javascript-stacktrace/test/functional/ExceptionLab.html:52\n" +
72-
"onclick@file:///Users/eric/src/javascript-stacktrace/test/functional/ExceptionLab.html:82\n" +
73-
"[native code]"
74-
*/
75-
// TODO: optimization - can pull these RegExps out and only compile them once
76-
var raw = e.stack.replace(/\[native code\]\n/m, '')
77-
.replace(/^(?=\w+Error\:).*$\n/m, '')
78-
.replace(/^@/gm, '{anonymous}@')
79-
.split('\n');
80-
// TODO: check function identifier defn
81-
var re = /^([\{\}\w]+)@(.*)\:(\d+)(\:(\d+))?$/;
82-
var enhancedStack = raw.filter(function(entry) {
83-
return entry.indexOf('@') !== -1;
84-
}).map(function(entry) {
85-
var m = entry.match(re);
86-
return new StackEntry(m[1], m[2], m[3], m[5]);
87-
});
88-
return new ErrorInfo(enhancedStack, e.message);
89-
},
90-
parseChakra: function(e) {},
91-
parseSpiderMonkey: function(e) {},
92-
parseOPERA: function(e) {
93-
// e.message.indexOf("Backtrace:") > -1 -> opera
94-
// !e.stacktrace -> opera
95-
if (!e.stacktrace) {
96-
return 'opera9'; // use e.message
97-
}
98-
// 'opera#sourceloc' in e -> opera9, opera10a
99-
if (e.message.indexOf('\n') > -1 && e.message.split('\n').length > e.stacktrace.split('\n').length) {
100-
return 'opera9'; // use e.message
101-
}
102-
// e.stacktrace && !e.stack -> opera10a
103-
if (!e.stack) {
104-
return 'opera10a'; // use e.stacktrace
105-
}
106-
// e.stacktrace && e.stack -> opera10b
107-
if (e.stacktrace.indexOf("called from line") < 0) {
108-
return 'opera10b'; // use e.stacktrace, format differs from 'opera10a'
109-
}
110-
// e.stacktrace && e.stack -> opera11
111-
return 'opera11'; // use e.stacktrace, format differs from 'opera10a', 'opera10b'
112-
},
113-
parseOther: function(e) {},
114-
guessAnonymousFunctionName: function() {
115-
// IDEA: can we use sourcemaps here?
80+
this.parseChakra = function(e) {};
81+
this.parseSpiderMonkey = function(e) {};
82+
this.parseOPERA = function(e) {
83+
// e.message.indexOf("Backtrace:") > -1 -> opera
84+
// !e.stacktrace -> opera
85+
if (!e.stacktrace) {
86+
return 'opera9'; // use e.message
11687
}
88+
// 'opera#sourceloc' in e -> opera9, opera10a
89+
if (e.message.indexOf('\n') > -1 && e.message.split('\n').length > e.stacktrace.split('\n').length) {
90+
return 'opera9'; // use e.message
91+
}
92+
// e.stacktrace && !e.stack -> opera10a
93+
if (!e.stack) {
94+
return 'opera10a'; // use e.stacktrace
95+
}
96+
// e.stacktrace && e.stack -> opera10b
97+
if (e.stacktrace.indexOf("called from line") < 0) {
98+
return 'opera10b'; // use e.stacktrace, format differs from 'opera10a'
99+
}
100+
// e.stacktrace && e.stack -> opera11
101+
return 'opera11'; // use e.stacktrace, format differs from 'opera10a', 'opera10b'
102+
};
103+
this.parseOther = function(e) {};
104+
this.guessAnonymousFunctionName = function() {
105+
// IDEA: can we use sourcemaps here?
117106
};
118107
}
119108

0 commit comments

Comments
 (0)