-
Notifications
You must be signed in to change notification settings - Fork 1
/
getStackTrace.js
95 lines (80 loc) · 2.89 KB
/
getStackTrace.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
(function () {
/**
* Ientifies the available logic fork.
* 1 : Error().stack (FireFox)
* 2 : Error().message (Opera)
* 3 : arguments.callee.caller (IE, Safari - not a true stack trace)
*/
var mode;
try {0()} catch (e) {
mode = e.stack ? 1 : e.message.indexOf('stacktrace') > -1 ? 2 : 3;
}
YOUR_NAMESPACE.getStackTrace = (
// Firefox includes a stack string in thrown Errors
mode === 1 :
function () {
try {0()} catch (e) {
return e.stack.replace(/^.*?\n/,'').
replace(/(?:\n@:0)?\s+$/m,'').
replace(/^\(/gm,'{anonymous}(').
split("\n");
}
} :
// Opera includes stack info in thrown Errors' .message
mode === 2 :
function () {
try {0()} catch (e) {
var lines = e.message.split("\n"),
ANON = '{anonymous}(..)@',
lineRE = /Line\s+(\d+).*?(http\S+)(?:.*?in\s+function\s+(\S+))?/i,
i,j,len,m;
for (i=4,j=0,len=lines.length; i<len; i+=2) {
m = lines[i].match(lineRE);
if (m) {
lines[j++] = (m[3] ? m[3] + '(..)@' + m[2] + m[1] :
ANON + m[2] + ':' + m[1]) + ' -- ' +
lines[i+1].replace(/^\s+/,'');
}
}
lines.splice(j,lines.length-j);
return lines;
}
} :
// IE and Safari support fn.caller, which is limited to the function's
// last execution rather than tracing each execution context, and thus is
// unable to trace across recursive functions.
function () {
var curr = arguments.callee.caller,
FUNC = 'function', ANON = "{anonymous}",
fnRE = /function\s*([\w\-$]+)?\s*\(/i,
callers = [arguments.callee],
stack = [],j=0,
fn,args,i;
trace: while (curr) {
// recursion protection
i = callers.length;
while (i--) {
if (curr === callers[i]) {
curr = null;
break trace;
}
}
callers.push(curr);
fn = (curr.toString().match(fnRE) || [])[1] || ANON;
args = stack.slice.call(curr.arguments);
i = args.length;
while (i--) {
switch (typeof args[i]) {
case 'string' : args[i] = '"'+args[i].replace(/"/g,'\\"')+'"'; break;
// TODO: use fnRE to get function's name
case 'function': args[i] = FUNC; break;
// TODO: better type forking
default : args[i] = args[i] == null ? 'null' : args[i].toString();
}
}
stack[j++] = fn + '(' + args.join() + ')';
curr = curr.caller;
}
return stack;
});
})();