8000 Fix #45 and making it possible to only import the parse method · Jikstra/error-stack-parser@574293d · GitHub
[go: up one dir, main page]

Skip to content

Commit 574293d

Browse files
committed
Fix stacktracejs#45 and making it possible to only import the parse method
1 parent a3bf972 commit 574293d

File tree

1 file changed

+163
-161
lines changed

1 file changed

+163
-161
lines changed

error-stack-parser.js

Lines changed: 163 additions & 161 deletions
< 10000 tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -17,186 +17,188 @@
1717
var CHROME_IE_STACK_REGEXP = /^\s*at .*(\S+:\d+|\(native\))/m;
1818
var SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code])?$/;
1919

20-
return {
21-
/**
22-
* Given an Error object, extract the most information from it.
23-
*
24-
* @param {Error} error object
25-
* @return {Array} of StackFrames
26-
*/
27-
parse: function ErrorStackParser$$parse(error) {
28-
if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') {
29-
return this.parseOpera(error);
30-
} else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) {
31-
return this.parseV8OrIE(error);
32-
} else if (error.stack) {
33-
return this.parseFFOrSafari(error);
34-
} else {
35-
throw new Error('Cannot parse given Error object');
36-
}
37-
},
38-
39-
// Separate line and column numbers from a string of the form: (URI:Line:Column)
40-
extractLocation: function ErrorStackParser$$extractLocation(urlLike) {
41-
// Fail-fast but return locations like "(native)"
42-
if (urlLike.indexOf(':') === -1) {
43-
return [urlLike];
44-
}
45-
46-
var regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
47-
var parts = regExp.exec(urlLike.replace(/[()]/g, ''));
48-
return [parts[1], parts[2] || undefined, parts[3] || undefined];
49-
},
20+
var errorStackParser = {}
21+
22+
/**
23+
* Given an Error object, extract the most information from it.
24+
*
25+
* @param {Error} error object
26+
* @return {Array} of StackFrames
27+
*/
28+
errorStackParser.parse = function ErrorStackParser$$parse(error) {
29+
if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') {
30+
return this.parseOpera(error);
31+
} else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) {
32+
return this.parseV8OrIE(error);
33+
} else if (error.stack) {
34+
return this.parseFFOrSafari(error);
35+
} else {
36+
throw new Error('Cannot parse given Error object');
37+
}
38+
},
5039

51-
parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) {
52-
var filtered = error.stack.split('\n').filter(function(line) {
53-
return !!line.match(CHROME_IE_STACK_REGEXP);
54-
}, this);
40+
// Separate line and column numbers from a string of the form: (URI:Line:Column)
41+
errorStackParser.extractLocation = function ErrorStackParser$$extractLocation(urlLike) {
42+
// Fail-fast but return locations like "(native)"
43+
if (urlLike.indexOf(':') === -1) {
44+
return [urlLike];
45+
}
5546

56-
return filtered.map(function(line) {
57-
if (line.indexOf('(eval ') > -1) {
58-
// Throw away eval information until we implement stacktrace.js/stackframe#8
59-
line = line.replace(/eval code/g, 'eval').replace(/(\(eval at [^()]*)|(\),.*$)/g, '');
60-
}
61-
var sanitizedLine = line.replace(/^\s+/, '').replace(/\(eval code/g, '(');
47+
var regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
48+
var parts = regExp.exec(urlLike.replace(/[()]/g, ''));
49+
return [parts[1], parts[2] || undefined, parts[3] || undefined];
50+
}.bind(errorStackParser);
6251

63-
// capture and preseve the parenthesized location "(/foo/my bar.js:12:87)" in
64-
// case it has spaces in it, as the string is split on \s+ later on
65-
var location = sanitizedLine.match(/ (\((.+):(\d+):(\d+)\)$)/);
52+
errorStackParser.parseV8OrIE = function ErrorStackParser$$parseV8OrIE(error) {
53+
var filtered = error.stack.split('\n').filter(function(line) {
54+
return !!line.match(CHROME_IE_STACK_REGEXP);
55+
}, this);
6656

67-
// remove the parenthesized location from the line, if it was matched
68-
sanitizedLine = location ? sanitizedLine.replace(location[0], '') : sanitizedLine;
57+
return filtered.map(function(line) {
58+
if (line.indexOf('(eval ') > -1) {
59+
// Throw away eval information until we implement stacktrace.js/stackframe#8
60+
line = line.replace(/eval code/g, 'eval').replace(/(\(eval at [^()]*)|(\),.*$)/g, '');
61+
}
62+
var sanitizedLine = line.replace(/^\s+/, '').replace(/\(eval code/g, '(');
63+
64+
// capture and preseve the parenthesized location "(/foo/my bar.js:12:87)" in
65+
// case it has spaces in it, as the string is split on \s+ later on
66+
var location = sanitizedLine.match(/ (\((.+):(\d+):(\d+)\)$)/);
67+
68+
// remove the parenthesized location from the line, if it was matched
69+
sanitizedLine = location ? sanitizedLine.replace(location[0], '') : sanitizedLine;
70+
71+
var tokens = sanitizedLine.split(/\s+/).slice(1);
72+
// if a location was matched, pass it to extractLocation() otherwise pop the last token
73+
var locationParts = this.extractLocation(location ? location[1] : tokens.pop());
74+
var functionName = tokens.join(' ') || undefined;
75+
var fileName = ['eval', '<anonymous>'].indexOf(locationParts[0]) > -1 ? undefined : locationParts[0];
76+
77+
return new StackFrame({
78+
functionName: functionName,
79+
fileName: fileName,
80+
lineNumber: locationParts[1],
81+
columnNumber: locationParts[2],
82+
source: line
83+
});
84+
}, this);
85+
}.bind(errorStackParser);
86+
87+
errorStackParser.parseFFOrSafari = function ErrorStackParser$$parseFFOrSafari(error) {
88+
var filtered = error.stack.split('\n').filter(function(line) {
89+
return !line.match(SAFARI_NATIVE_CODE_REGEXP);
90+
}, this);
91+
92+
return filtered.map(function(line) {
93+
// Throw away eval information until we implement stacktrace.js/stackframe#8
94+
if (line.indexOf(' > eval') > -1) {
95+
line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g, ':$1');
96+
}
6997

70-
var tokens = sanitizedLine.split(/\s+/).slice(1);
71-
// if a location was matched, pass it to extractLocation() otherwise pop the last token
72-
var locationParts = this.extractLocation(location ? location[1] : tokens.pop());
73-
var functionName = tokens.join(' ') || undefined;
74-
var fileName = ['eval', '<anonymous>'].indexOf(locationParts[0]) > -1 ? undefined : locationParts[0];
98+
if (line.indexOf('@') === -1 && line.indexOf(':') === -1) {
99+
// Safari eval frames only have function names and nothing else
100+
return new StackFrame({
101+
functionName: line
102+
});
103+
} else {
104+
var functionNameRegex = /((.*".+"[^@]*)?[^@]*)(?:@)/;
105+
var matches = line.match(functionNameRegex);
106+
var functionName = matches && matches[1] ? matches[1] : undefined;
107+
var locationParts = this.extractLocation(line.replace(functionNameRegex, ''));
75108

76109
return new StackFrame({
77110
functionName: functionName,
78-
fileName: fileName,
111+
fileName: locationParts[0],
79112
lineNumber: locationParts[1],
80113
columnNumber: locationParts[2],
81114
source: line
82115
});
83-
}, this);
84-
},
85-
86-
parseFFOrSafari: function ErrorStackParser$$parseFFOrSafari(error) {
87-
var filtered = error.stack.split('\n').filter(function(line) {
88-
return !line.match(SAFARI_NATIVE_CODE_REGEXP);
89-
}, this);
90-
91-
return filtered.map(function(line) {
92-
// Throw away eval information until we implement stacktrace.js/stackframe#8
93-
if (line.indexOf(' > eval') > -1) {
94-
line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g, ':$1');
95-
}
96-
97-
if (line.indexOf('@') === -1 && line.indexOf(':') === -1) {
98-
// Safari eval frames only have function names and nothing else
99-
return new StackFrame({
100-
functionName: line
101-
});
102-
} else {
103-
var functionNameRegex = /((.*".+"[^@]*)?[^@]*)(?:@)/;
104-
var matches = line.match(functionNameRegex);
105-
var functionName = matches && matches[1] ? matches[1] : undefined;
106-
var locationParts = this.extractLocation(line.replace(functionNameRegex, ''));
107-
108-
return new StackFrame({
109-
functionName: functionName,
110-
fileName: locationParts[0],
111-
lineNumber: locationParts[1],
112-
columnNumber: locationParts[2],
113-
source: line
114-
});
115-
}
116-
}, this);
117-
},
118-
119-
parseOpera: function ErrorStackParser$$parseOpera(e) {
120-
if (!e.stacktrace || (e.message.indexOf('\n') > -1 &&
121-
e.message.split('\n').length > e.stacktrace.split('\n').length)) {
122-
return this.parseOpera9(e);
123-
} else if (!e.stack) {
124-
return this.parseOpera10(e);
125-
} else {
126-
return this.parseOpera11(e);
127116
}
128-
},
117+
}, this);
118+
}.bind(errorStackParser);
119+
120+
errorStackParser.parseOpera = function ErrorStackParser$$parseOpera(e) {
121+
if (!e.stacktrace || (e.message.indexOf('\n') > -1 &&
122+
e.message.split('\n').length > e.stacktrace.split('\n').length)) {
123+
return this.parseOpera9(e);
124+
} else if (!e.stack) {
125+
return this.parseOpera10(e);
126+
} else {
127+
return this.parseOpera11(e);
128+
}
129+
}.bind(errorStackParser);
130+
131+
errorStackParser.parseOpera9 = function ErrorStackParser$$parseOpera9(e) {
132+
var lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
133+
var lines = e.message.split('\n');
134+
var result = [];
135+
136+
for (var i = 2, len = lines.length; i < len; i += 2) {
137+
var match = lineRE.exec(lines[i]);
138+
if (match) {
139+
result.push(new StackFrame({
140+
fileName: match[2],
141+
lineNumber: match[1],
142+
source: lines[i]
143+
}));
144+
}
145+
}
129146

130-
parseOpera9: function ErrorStackParser$$parseOpera9(e) {
131-
var lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
132-
var lines = e.message.split('\n');
133-
var result = [];
147+
return result;
148+
}.bind(errorStackParser);
134149

135-
for (var i = 2, len = lines.length; i < len; i += 2) {
136-
var match = lineRE.exec(lines[i]);
137-
if (match) {
138-
result.push(new StackFrame({
150+
errorStackParser.parseOpera10 = function ErrorStackParser$$parseOpera10(e) {
151+
var lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
152+
var lines = e.stacktrace.split('\n');
153+
var result = [];
154+
155+
for (var i = 0, len = lines.length; i < len; i += 2) {
156+
var match = lineRE.exec(lines[i]);
157+
if (match) {
158+
result.push(
159+
new StackFrame({
160+
functionName: match[3] || undefined,
139161
fileName: match[2],
140162
lineNumber: match[1],
141163
source: lines[i]
142-
}));
143-
}
164+
})
165+
);
144166
}
167+
}
145168

146-
return result;
147-
},
148-
149-
parseOpera10: function ErrorStackParser$$parseOpera10(e) {
150-
var lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
151-
var lines = e.stacktrace.split('\n');
152-
var result = [];
153-
154-
for (var i = 0, len = lines.length; i < len; i += 2) {
155-
var match = lineRE.exec(lines[i]);
156-
if (match) {
157-
result.push(
158-
new StackFrame({
159-
functionName: match[3] || undefined,
160-
fileName: match[2],
161-
lineNumber: match[1],
162-
source: lines[i]
163-
})
164-
);
165-
}
169+
return result;
170+
}.bind(errorStackParser);
171+
172+
// Opera 10.65+ Error.stack very similar to FF/Safari
173+
errorStackParser.parseOpera11 = function ErrorStackParser$$parseOpera11(error) {
174+
var filtered = error.stack.split('\n').filter(function(line) {
175+
return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/);
176+
}, this);
177+
178+
return filtered.map(function(line) {
179+
var tokens = line.split('@');
180+
var locationParts = this.extractLocation(tokens.pop());
181+
var functionCall = (tokens.shift() || '');
182+
var functionName = functionCall
183+
.replace(/<anonymous function(: (\w+))?>/, '$2')
184+
.replace(/\([^)]*\)/g, '') || undefined;
185+
var argsRaw;
186+
if (functionCall.match(/\(([^)]*)\)/)) {
187+
argsRaw = functionCall.replace(/^[^(]+\(([^)]*)\)$/, '$1');
166188
}
167-
168-
return result;
169-
},
170-
171-
// Opera 10.65+ Error.stack very similar to FF/Safari
172-
parseOpera11: function ErrorStackParser$$parseOpera11(error) {
173-
var filtered = error.stack.split('\n').filter(function(line) {
174-
return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/);
175-
}, this);
176-
177-
return filtered.map(function(line) {
178-
var tokens = line.split('@');
179-
var locationParts = this.extractLocation(tokens.pop());
180-
var functionCall = (tokens.shift() || '');
181-
var functionName = functionCall
182-
.replace(/<anonymous function(: (\w+))?>/, '$2')
183-
.replace(/\([^)]*\)/g, '') || undefined;
184-
var argsRaw;
185-
if (functionCall.match(/\(([^)]*)\)/)) {
186-
argsRaw = functionCall.replace(/^[^(]+\(([^)]*)\)$/, '$1');
187-
}
188-
var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ?
189-
undefined : argsRaw.split(',');
190-
191-
return new StackFrame({
192-
functionName: functionName,
193-
args: args,
194-
fileName: locationParts[0],
195-
lineNumber: locationParts[1],
196-
columnNumber: locationParts[2],
197-
source: line
198-
});
199-
}, this);
200-
}
201-
};
189+
var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ?
190+
undefined : argsRaw.split(',');
191+
192+
return new StackFrame({
193+
functionName: functionName,
194+
args: args,
195+
fileName: locationParts[0],
196+
lineNumber: locationParts[1],
197+
columnNumber: locationParts[2],
198+
source: line
199+
});
200+
}, this);
201+
}.bind(errorStackParser);
202+
203+
return errorStackParser
202204
}));

0 commit comments

Comments
 (0)
0