Skip to content

Commit c64317f

Browse files
author
Eric Wendelin
committed
Separate StackFrame dependency. Pull StackFrame in via bower for testing.
1 parent 89af53d commit c64317f

File tree

8 files changed

+114
-107
lines changed

8 files changed

+114
-107
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ pids
1111
logs
1212
results
1313

14-
npm-debug.log
1514
node_modules
1615
bower_components
1716

bower.json

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
11
{
2-
"name": "stack-parser",
3-
"version": "0.1.0",
4-
"main": "./stack-parser.js",
5-
"homepage": "https://github.com/stacktracejs/stack-parser.js",
6-
"authors": [
7-
"Eric Wendelin <me@eriwen.com>"
8-
],
9-
"description": "Extract meaning from JS Errors",
10-
"moduleType": [
11-
"amd",
12-
"globals",
13-
"node"
14-
],
15-
"keywords": [
16-
"stacktrace",
17-
"stack-trace",
18-
"backtrace",
19-
"cross-browser",
20-
"framework-agnostic",
21-
"error"
22-
],
23-
"license": "MIT",
24-
"ignore": [
25-
"**/.*",
26-
"node_modules",
27-
"bower_components",
28-
"spec"
29-
],
30-
"devDependencies": {
31-
"jasmine": "~1.3.1",
32-
"jasmine-jstd-adapter": "~1.1.2"
33-
}
2+
"name": "stack-parser",
3+
"version": "0.1.0",
4+
"main": "./stack-parser.js",
5+
"homepage": "https://github.com/stacktracejs/stack-parser.js",
6+
"authors": [
7+
"Eric Wendelin <me@eriwen.com>"
8+
],
9+
"description": "Extract meaning from JS Errors",
10+
"dependencies": {
11+
"stackframe": "0.1.0"
12+
},
13+
"devDependencies": {
14+
"jasmine": "~1.3.1",
15+
"jasmine-jstd-adapter": "~1.1.2"
16+
},
17+
"moduleType": [
18+
"amd",
19+
"globals",
20+
"node"
21+
],
22+
"keywords": [
23+
"stacktrace",
24+
"stack-trace",
25+
"backtrace",
26+
"cross-browser",
27+
"framework-agnostic",
28+
"error"
29+
],
30+
"license": "MIT",
31+
"ignore": [
32+
"**/.*",
33+
"node_modules",
34+
"bower_components",
35+
"spec"
36+
]
3437
}

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
"author": "Eric Wendelin <me@eriwen.com> (http://eriwen.com)",
55
"version": "0.1.0",
66
"keywords": ["stacktrace", "error"],
7-
"homepage": "http://stacktracejs.com",
7+
"homepage": "http://www.stacktracejs.com",
8+
"dependencies": {
9+
"stackframe": "0.1.0"
10+
},
811
"repository": {
912
"type": "git",
1013
"url": "git://github.com/stacktracejs/stack-parser.git"

spec/SpecRunner.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77

88
<script type="text/javascript" src="../bower_components/jasmine/lib/jasmine-core/jasmine.js"></script>
99
<script type="text/javascript" src="../bower_components/jasmine/lib/jasmine-core/jasmine-html.js"></script>
10-
<script type="text/javascript" src="../bower_components/jasmine/lib/jasmine-core/boot.js"></script>
10+
<script type="text/javascript" src="../bower_components/stackframe/stackframe.js"></script>
1111

1212
<script type="text/javascript" src="../stack-parser.js"></script>
1313

1414
<script type="text/javascript" src="captured-errors.js"></script>
15+
<script type="text/javascript" src="spec-helper.js"></script>
1516
<script type="text/javascript" src="stack-parser-spec.js"></script>
1617

1718
<script type="text/javascript">

spec/jsTestDriver.conf

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ server: http://localhost:4224
33
load:
44
- ../bower_components/jasmine/lib/jasmine-core/jasmine.js
55
- ../bower_components/jasmine-jstd-adapter/src/JasmineAdapter.js
6+
- ../bower_components/stackframe/stackframe.js
67
- captured-errors.js
78
- ../stack-parser.js
9+
- spec-helper.js
810
test:
911
- stack-parser-spec.js
1012

11-
timeout: 15
13+
timeout: 30

spec/spec-helper.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
beforeEach(function() {
2+
this.addMatchers({
3+
toMatchStackFrame: function(expected) {
4+
var actual = this.actual;
5+
var message = '';
6+
if (actual.getFunctionName() !== expected[0]) {
7+
message += 'expected functionName: ' + actual.getFunctionName() + ' to equal ' + expected[0] + '\n';
8+
}
9+
if (actual.getArgs() !== expected[1]) {
10+
message += 'expected args: ' + actual.getArgs() + ' to equal ' + expected[1] + '\n';
11+
}
12+
if (actual.getFileName() !== expected[2]) {
13+
message += 'expected fileName: ' + actual.getFileName() + ' to equal ' + expected[2] + '\n';
14+
}
15+
if (actual.getLineNumber() !== expected[3]) {
16+
message += 'expected lineNumber: ' + actual.getLineNumber() + ' to equal ' + expected[3] + '\n';
17+
}
18+
if (actual.getColumnNumber() !== expected[4]) {
19+
message += 'expected columnNumber: ' + actual.getColumnNumber() + ' to equal ' + expected[4] + '\n';
20+
}
21+
this.message = function() { return message };
22+
return message === '';
23+
}
24+
});
25+
});
26+
27+
28+

spec/stack-parser-spec.js

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,64 +6,64 @@ describe('StackParser', function () {
66
var stackFrames = unit.parse(CapturedExceptions.SAFARI_6);
77
expect(stackFrames).toBeTruthy();
88
expect(stackFrames.length).toBe(3);
9-
expect(stackFrames[0]).toEqual(new StackFrame('', [], 'http://path/to/file.js', '48'));
10-
expect(stackFrames[1]).toEqual(new StackFrame('dumpException3', [], 'http://path/to/file.js', '52'));
11-
expect(stackFrames[2]).toEqual(new StackFrame('onclick', [], 'http://path/to/file.js', '82'));
9+
expect(stackFrames[0]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 48]);
10+
expect(stackFrames[1]).toMatchStackFrame(['dumpException3', undefined, 'http://path/to/file.js', 52]);
11+
expect(stackFrames[2]).toMatchStackFrame(['onclick', undefined, 'http://path/to/file.js', 82]);
1212
});
1313

1414
it('should parse Safari 7 Error.stack', function () {
1515
var stackFrames = unit.parse(CapturedExceptions.SAFARI_7);
1616
expect(stackFrames).toBeTruthy();
1717
expect(stackFrames.length).toBe(3);
18-
expect(stackFrames[0]).toEqual(new StackFrame('', [], 'http://path/to/file.js', '48', '22'));
19-
expect(stackFrames[1]).toEqual(new StackFrame('foo', [], 'http://path/to/file.js', '52', '15'));
20-
expect(stackFrames[2]).toEqual(new StackFrame('bar', [], 'http://path/to/file.js', '108', '107'));
18+
expect(stackFrames[0]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 48, 22]);
19+
expect(stackFrames[1]).toMatchStackFrame(['foo', undefined, 'http://path/to/file.js', 52, 15]);
20+
expect(stackFrames[2]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 108, 107]);
2121
});
2222

2323
it('should parse Firefox 31 Error.stack', function () {
2424
var stackFrames = unit.parse(CapturedExceptions.FIREFOX_31);
2525
expect(stackFrames).toBeTruthy();
2626
expect(stackFrames.length).toBe(2);
27-
expect(stackFrames[0]).toEqual(new StackFrame('foo', [], 'http://path/to/file.js', '41', '13'));
28-
expect(stackFrames[1]).toEqual(new StackFrame('bar', [], 'http://path/to/file.js', '1', '1'));
27+
expect(stackFrames[0]).toMatchStackFrame(['foo', undefined, 'http://path/to/file.js', 41, 13]);
28+
expect(stackFrames[1]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 1, 1]);
2929
});
3030

3131
it('should parse V8 Error stacks', function () {
3232
var stackFrames = unit.parse(CapturedExceptions.CHROME_15);
3333
expect(stackFrames).toBeTruthy();
3434
expect(stackFrames.length).toBe(4);
35-
expect(stackFrames[0]).toEqual(new StackFrame('bar', [], 'http://path/to/file.js', '13', '17'));
36-
expect(stackFrames[1]).toEqual(new StackFrame('bar', [], 'http://path/to/file.js', '16', '5'));
37-
expect(stackFrames[2]).toEqual(new StackFrame('foo', [], 'http://path/to/file.js', '20', '5'));
38-
expect(stackFrames[3]).toEqual(new StackFrame('', [], 'http://path/to/file.js', '24', '4'));
35+
expect(stackFrames[0]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 13, 17]);
36+
expect(stackFrames[1]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 16, 5]);
37+
expect(stackFrames[2]).toMatchStackFrame(['foo', undefined, 'http://path/to/file.js', 20, 5]);
38+
expect(stackFrames[3]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 24, 4]);
3939
});
4040

4141
it('should parse IE 10 Error stacks', function () {
4242
var stackFrames = unit.parse(CapturedExceptions.IE_10);
4343
expect(stackFrames).toBeTruthy();
4444
expect(stackFrames.length).toBe(3);
45-
expect(stackFrames[0]).toEqual(new StackFrame('', [], 'http://path/to/file.js', '48', '13'));
46-
expect(stackFrames[1]).toEqual(new StackFrame('foo', [], 'http://path/to/file.js', '46', '9'));
47-
expect(stackFrames[2]).toEqual(new StackFrame('bar', [], 'http://path/to/file.js', '82', '1'));
45+
expect(stackFrames[0]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 48, 13]);
46+
expect(stackFrames[1]).toMatchStackFrame(['foo', undefined, 'http://path/to/file.js', 46, 9]);
47+
expect(stackFrames[2]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 82, 1]);
4848
});
4949

5050
it('should parse Opera 9.27 Error messages', function () {
5151
var stackFrames = unit.parse(CapturedExceptions.OPERA_927);
5252
expect(stackFrames).toBeTruthy();
5353
expect(stackFrames.length).toBe(3);
54-
expect(stackFrames[0]).toEqual(new StackFrame('bar', [], 'http://path/to/file.js', '42'));
55-
expect(stackFrames[1]).toEqual(new StackFrame('bar', [], 'http://path/to/file.js', '27'));
56-
expect(stackFrames[2]).toEqual(new StackFrame('foo', [], 'http://path/to/file.js', '18'));
54+
expect(stackFrames[0]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 43]);
55+
expect(stackFrames[1]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 31]);
56+
expect(stackFrames[2]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 18]);
5757
});
5858

5959
it('should parse Opera 11 Error messages', function () {
6060
var stackFrames = unit.parse(CapturedExceptions.OPERA_11);
6161
expect(stackFrames).toBeTruthy();
6262
expect(stackFrames.length).toBe(4);
63-
expect(stackFrames[0]).toEqual(new StackFrame('run', [], 'http://path/to/file.js', '27'));
64-
expect(stackFrames[0]).toEqual(new StackFrame('bar', [], 'http://path/to/file.js', '18'));
65-
expect(stackFrames[1]).toEqual(new StackFrame('bar', [], 'http://path/to/file.js', '11'));
66-
expect(stackFrames[2]).toEqual(new StackFrame('', [], 'http://path/to/file.js', '15'));
63+
expect(stackFrames[0]).toMatchStackFrame(['run', undefined, 'http://path/to/file.js', 27]);
64+
expect(stackFrames[1]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 18]);
65+
expect(stackFrames[2]).toMatchStackFrame(['foo', undefined, 'http://path/to/file.js', 11]);
66+
expect(stackFrames[3]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 15]);
6767
});
6868
});
6969
});

stack-parser.js

Lines changed: 20 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,16 @@
1-
// TODO: split into new module
1+
/* global StackFrame: false */
22
(function (root, factory) {
3+
'use strict';
4+
// Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.
35
if (typeof define === 'function' && define.amd) {
4-
define([], factory);
6+
define(['stackframe'], factory);
57
} else if (typeof exports === 'object') {
6-
module.exports = factory();
8+
module.exports = factory(require('stackframe'));
79
} else {
8-
root.StackFrame = factory();
9-
}
10-
}(this, function () {
11-
return function StackFrame(functionName, args, srcUrl, lineNumber, columnNumber) {
12-
this.fn = functionName;
13-
this.args = args;
14-
this.src = srcUrl;
15-
this.line = lineNumber;
16-
this.column = columnNumber;
17-
}
18-
}));
19-
20-
// TODO?: Error.prototype.parseError = function parseError(e) {};
21-
(function (root, factory) {
22-
if (typeof define === 'function' && define.amd) {
23-
define([], factory);
24-
} else if (typeof exports === 'object') {
25-
module.exports = factory();
26-
} else {
27-
root.StackParser = factory();
10+
root.StackParser = factory(root.StackFrame);
2811
}
2912
}(this, function () {
13+
'use strict';
3014
return function StackParser() {
3115
this.firefoxSafariStackEntryRegExp = /\S+\:\d+/;
3216
this.chromeIEStackEntryRegExp = /\s+at /;
@@ -37,7 +21,7 @@
3721
* @return Array[StackFrame]
3822
*/
3923
this.parse = function parse(error) {
40-
if (typeof error.stacktrace === 'string') {
24+
if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') {
4125
return this.parseOpera(error);
4226
} else if (error.stack.match(this.chromeIEStackEntryRegExp)) {
4327
return this.parseV8OrIE(error);
@@ -49,38 +33,28 @@
4933
};
5034

5135
this.parseV8OrIE = function parseV8OrIE(error) {
52-
/* stack: "TypeError: Object #<Object> has no method 'undef'\n" +
53-
" at Object.bar (http://path/to/stacktrace.js:42:18)\n" +
54-
" at foo (http://path/to/file.js:20:5)\n" +
55-
" at http://path/to/file.js:24:4"*/
56-
5736
return error.stack.split('\n').splice(1).map(function (line) {
5837
var tokens = line.split(/\s+/).splice(2);
5938
var location = tokens.pop().replace(/[\(\)\s]/g, '').split(':');
60-
var functionName = (!tokens[0] || tokens[0] === 'Anonymous') ? '' : tokens[0];
61-
return new StackFrame(functionName, [], location[0] + ':' + location[1], location[2], location[3]);
39+
var functionName = (!tokens[0] || tokens[0] === 'Anonymous') ? undefined : tokens[0];
40+
return new StackFrame(functionName, undefined, location[0] + ':' + location[1], location[2], location[3]);
6241
});
6342
};
6443

6544
this.parseFFOrSafari = function parseFFOrSafari(error) {
66-
/* stack: "@http://path/to/file.js:48\n" +
67-
"bar@http://path/to/file.js:52\n" +
68-
"foo@http://path/to/file.js:82\n" +
69-
"[native code]" */
70-
7145
return error.stack.split('\n').filter(function (line) {
7246
return !!line.match(this.firefoxSafariStackEntryRegExp);
7347
}.bind(this)).map(function (line) {
7448
var tokens = line.split('@');
7549
var location = tokens.pop().split(':');
76-
var functionName = tokens.shift() || '';
77-
return new StackFrame(functionName, [], location[0] + ':' + location[1], location[2], location[3]);
50+
var functionName = tokens.shift() || undefined;
51+
return new StackFrame(functionName, undefined, location[0] + ':' + location[1], location[2], location[3]);
7852
});
7953
};
8054

8155
this.parseOpera = function parseOpera(e) {
82-
if (!e.stacktrace || (e.message.indexOf('\n') > -1
83-
&& e.message.split('\n').length > e.stacktrace.split('\n').length)) {
56+
if (!e.stacktrace || (e.message.indexOf('\n') > -1 &&
57+
e.message.split('\n').length > e.stacktrace.split('\n').length)) {
8458
return this.parseOpera9(e);
8559
} else if (!e.stack) {
8660
return this.parseOpera10a(e);
@@ -92,25 +66,21 @@
9266
};
9367

9468
this.parseOpera9 = function parseOpera9(e) {
95-
// " Line 43 of linked script http://path/to.js\n"
96-
// " Line 7 of inline#1 script in http://path/to.js\n"
9769
var lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
9870
var lines = e.message.split('\n');
9971
var result = [];
10072

10173
for (var i = 2, len = lines.length; i < len; i += 2) {
10274
var match = lineRE.exec(lines[i]);
10375
if (match) {
104-
result.push(new StackFrame('', [], match[2], match[1]));
76+
result.push(new StackFrame(undefined, undefined, match[2], match[1]));
10577
}
10678
}
10779

10880
return result;
10981
};
11082

11183
this.parseOpera10a = function parseOpera10a(e) {
112-
// " Line 27 of linked script http://path/to.js\n"
113-
// " Line 11 of inline#1 script in http://path/to.js: In function foo\n"
11484
var ANON = '{anonymous}', lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
11585
var lines = e.stacktrace.split('\n'), result = [];
11686

@@ -133,11 +103,12 @@
133103
var tokens = line.split('@');
134104
var location = tokens.pop().split(':');
135105
var functionCall = (tokens.shift() || '');
136-
var functionName = functionCall.replace(/<anonymous function: (\S+)(\([^\(]*\))?>/, '$1');
137-
var args = functionCall.replace(/^[^\(]+\(([^\)]*)\)$/, '$1').replace('arguments not available', '').split(',');
106+
var functionName = functionCall.replace(/<anonymous function: (\w+)>/, '$1').replace(/\([^\)]*\)/, '') || undefined;
107+
var argsRaw = functionCall.replace(/^[^\(]+\(([^\)]*)\)$/, '$1') || undefined;
108+
var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ? undefined : argsRaw.split(',');
138109
return new StackFrame(functionName, args, location[0] + ':' + location[1], location[2], location[3]);
139110
});
140-
}
141-
}
111+
};
112+
};
142113
}));
143114

0 commit comments

Comments
 (0)