diff --git a/.gitignore b/.gitignore index 3ec4681..faff30a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.pid *.gz +bower_components node_modules build coverage diff --git a/.jshintrc b/.jshintrc index 3b23b9b..7d58452 100644 --- a/.jshintrc +++ b/.jshintrc @@ -14,6 +14,7 @@ "es3": true, "camelcase": true, "nonbsp": true, + "maxlen": 130, "predef": { "afterEach": false, "beforeEach": false, diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index d0e8c69..0000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -0.10.32 diff --git a/.travis.yml b/.travis.yml index 60d4d6d..a13d299 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,15 @@ language: node_js -node_js: -- '0.12' -script: gulp ci -install: -- npm install -- npm install bower -g sudo: false +node_js: stable addons: sauce_connect: true -env: - global: - - secure: hNvLoSVYWY+O2Oz5usb5+IFUMgWdM21xxZuCR4+qh1yJhlQYTaFANBDYJ5vhC74DbzLHRmy8ZUYa1G/4R4w8KXX9cCt6PFD2ETPpmZPJROHzoAoaYKahOAqdcMSVHn0BVKZCeAvPeLoBhvIfMJx4DOcRTTkKPzTJzg4ewzR/v3g= - - secure: hnc8EGbHzAlz6lAfVoGSf47pecv7G/LxbDHCIN2jn23SgU9SdScY9LT9K0X69smFsdBmOSCWDRRqPgX859sS/tz3lGHW6lCRn3mqclCNVhFNM6Vd+dB4hwAEvJQXhtMAaxM5Bqop+8C8OQ4NdoHgSYcdEvMT0CaWU1ZFrpjiBs4= + firefox: latest + apt: + sources: + - google-chrome + packages: + - google-chrome-stable +before_script: +- npm install +script: +- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then gulp ci; else gulp pr; fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ae893e..2ce8a3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ -## v1.1.2 +## v1.3.2 +* Handle Safari stack entries with no location information + +## v1.3.0 +* Significantly improved handling of eval() +* Add many browsers to CI + +## v1.2.2 * Handle native functions in V8 stack traces ## v1.2.0 diff --git a/README.md b/README.md index 6703e17..207163c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,10 @@ an Array of [StackFrame](http://git.io/stackframe)s. Once you have parsed out StackFrames, you can do much more interesting things. See [stacktrace-gps](http://git.io/stacktrace-gps). Note that in IE9 and earlier, `Error` objects don't have enough information to extract much of anything. In IE 10, `Error`s -are given a `stack` once they're `throw`n. +are given a `stack` once they're `throw`n. + +## Browser Support +[![Sauce Test Status](https://saucelabs.com/browser-matrix/stacktracejs.svg)](https://saucelabs.com/u/stacktracejs) ## Usage ```js @@ -29,15 +32,6 @@ bower install error-stack-parser https://raw.githubusercontent.com/stacktracejs/error-stack-parser/master/dist/error-stack-parser.min.js ``` -## Browser Support -* Chrome 1+ -* Firefox 3.6+ -* Safari 7+ -* Opera 9+ -* IE 10+ -* iOS 7+ -* Android 4.2+ - ## Contributing Want to be listed as a *Contributor*? Start with the [Contributing Guide](CONTRIBUTING.md)! diff --git a/bower.json b/bower.json index 36f2958..04bc6ea 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "error-stack-parser", - "main": "./error-stack-parser.js", + "main": "./dist/error-stack-parser.js", "homepage": "https://github.com/stacktracejs/error-stack-parser", "authors": [ "Eric Wendelin (http://www.eriwen.com)", @@ -8,7 +8,7 @@ ], "description": "Extract meaning from JS Errors", "dependencies": { - "stackframe": "~0" + "stackframe": "~0.3.1" }, "moduleType": [ "amd", diff --git a/component.json b/component.json index 267a81c..6fa34cc 100644 --- a/component.json +++ b/component.json @@ -2,7 +2,7 @@ "name": "error-stack-parser", "repository": "stacktracejs/error-stack-parser", "description": "Extract meaning from JS Errors", - "version": "1.2.2", + "version": "1.3.3", "keywords": [ "stacktrace", "error", diff --git a/dist/error-stack-parser-with-polyfills.min.js b/dist/error-stack-parser-with-polyfills.min.js deleted file mode 100644 index 2ee61d7..0000000 --- a/dist/error-stack-parser-with-polyfills.min.js +++ /dev/null @@ -1,2 +0,0 @@ -Array.prototype.map||(Array.prototype.map=function(t,e){var r,n=Object(this),i=n.length>>>0;arguments.length>1&&(r=e);for(var s=new Array(i),o=0;i>o;){var a,u;o in n&&(a=n[o],u=t.call(r,a,o,n),s[o]=u),o++}return s}),Array.prototype.filter||(Array.prototype.filter=function(t){for(var e=Object(this),r=e.length>>>0,n=[],i=arguments.length>=2?arguments[1]:void 0,s=0;r>s;s++)if(s in e){var o=e[s];t.call(i,o,s,e)&&n.push(o)}return n}),function(t,e){"use strict";"function"==typeof define&&define.amd?define("stackframe",[],e):"object"==typeof exports?module.exports=e():t.StackFrame=e()}(this,function(){"use strict";function t(t){return!isNaN(parseFloat(t))&&isFinite(t)}function e(t,e,r,n,i,s){void 0!==t&&this.setFunctionName(t),void 0!==e&&this.setArgs(e),void 0!==r&&this.setFileName(r),void 0!==n&&this.setLineNumber(n),void 0!==i&&this.setColumnNumber(i),void 0!==s&&this.setSource(s)}return e.prototype={getFunctionName:function(){return this.functionName},setFunctionName:function(t){this.functionName=String(t)},getArgs:function(){return this.args},setArgs:function(t){if("[object Array]"!==Object.prototype.toString.call(t))throw new TypeError("Args must be an Array");this.args=t},getFileName:function(){return this.fileName},setFileName:function(t){this.fileName=String(t)},getLineNumber:function(){return this.lineNumber},setLineNumber:function(e){if(!t(e))throw new TypeError("Line Number must be a Number");this.lineNumber=Number(e)},getColumnNumber:function(){return this.columnNumber},setColumnNumber:function(e){if(!t(e))throw new TypeError("Column Number must be a Number");this.columnNumber=Number(e)},getSource:function(){return this.source},setSource:function(t){this.source=String(t)},toString:function(){var e=this.getFunctionName()||"{anonymous}",r="("+(this.getArgs()||[]).join(",")+")",n=this.getFileName()?"@"+this.getFileName():"",i=t(this.getLineNumber())?":"+this.getLineNumber():"",s=t(this.getColumnNumber())?":"+this.getColumnNumber():"";return e+r+n+i+s}},e}),function(t,e){"use strict";"function"==typeof define&&define.amd?define("error-stack-parser",["stackframe"],e):"object"==typeof exports?module.exports=e(require("stackframe")):t.ErrorStackParser=e(t.StackFrame)}(this,function(t){"use strict";var e=/(^|@)\S+\:\d+/,r=/\s+at .*(\S+\:\d+|\(native\))/;return{parse:function(t){if("undefined"!=typeof t.stacktrace||"undefined"!=typeof t["opera#sourceloc"])return this.parseOpera(t);if(t.stack&&t.stack.match(r))return this.parseV8OrIE(t);if(t.stack&&t.stack.match(e))return this.parseFFOrSafari(t);throw new Error("Cannot parse given Error object")},extractLocation:function(t){if(-1===t.indexOf(":"))return[t];var e=t.replace(/[\(\)\s]/g,"").split(":"),r=e.pop(),n=e[e.length-1];if(!isNaN(parseFloat(n))&&isFinite(n)){var i=e.pop();return[e.join(":"),i,r]}return[e.join(":"),r,void 0]},parseV8OrIE:function(e){return e.stack.split("\n").filter(function(t){return!!t.match(r)},this).map(function(e){var r=e.replace(/^\s+/,"").split(/\s+/).slice(1),n=this.extractLocation(r.pop()),i=r[0]&&"Anonymous"!==r[0]?r[0]:void 0;return new t(i,void 0,n[0],n[1],n[2],e)},this)},parseFFOrSafari:function(r){return r.stack.split("\n").filter(function(t){return!!t.match(e)},this).map(function(e){var r=e.split("@"),n=this.extractLocation(r.pop()),i=r.shift()||void 0;return new t(i,void 0,n[0],n[1],n[2],e)},this)},parseOpera:function(t){return!t.stacktrace||t.message.indexOf("\n")>-1&&t.message.split("\n").length>t.stacktrace.split("\n").length?this.parseOpera9(t):t.stack?this.parseOpera11(t):this.parseOpera10(t)},parseOpera9:function(e){for(var r=/Line (\d+).*script (?:in )?(\S+)/i,n=e.message.split("\n"),i=[],s=2,o=n.length;o>s;s+=2){var a=r.exec(n[s]);a&&i.push(new t(void 0,void 0,a[2],a[1],void 0,n[s]))}return i},parseOpera10:function(e){for(var r=/Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i,n=e.stacktrace.split("\n"),i=[],s=0,o=n.length;o>s;s+=2){var a=r.exec(n[s]);a&&i.push(new t(a[3]||void 0,void 0,a[2],a[1],void 0,n[s]))}return i},parseOpera11:function(r){return r.stack.split("\n").filter(function(t){return!!t.match(e)&&!t.match(/^Error created at/)},this).map(function(e){var r,n=e.split("@"),i=this.extractLocation(n.pop()),s=n.shift()||"",o=s.replace(//,"$2").replace(/\([^\)]*\)/g,"")||void 0;s.match(/\(([^\)]*)\)/)&&(r=s.replace(/^[^\(]+\(([^\)]*)\)$/,"$1"));var a=void 0===r||"[arguments not available]"===r?void 0:r.split(",");return new t(o,a,i[0],i[1],i[2],e)},this)}}}); -//# sourceMappingURL=error-stack-parser-with-polyfills.min.js.map \ No newline at end of file diff --git a/dist/error-stack-parser-with-polyfills.min.js.map b/dist/error-stack-parser-with-polyfills.min.js.map deleted file mode 100644 index 30acee9..0000000 --- a/dist/error-stack-parser-with-polyfills.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["polyfills.js","stackframe.js","error-stack-parser.js"],"names":["Array","prototype","map","callback","thisArg","T","O","Object","this","len","length","arguments","A","k","kValue","mappedValue","call","filter","t","res","i","val","push","root","factory","define","amd","exports","module","StackFrame","_isNumber","n","isNaN","parseFloat","isFinite","functionName","args","fileName","lineNumber","columnNumber","source","undefined","setFunctionName","setArgs","setFileName","setLineNumber","setColumnNumber","setSource","getFunctionName","v","String","getArgs","toString","TypeError","getFileName","getLineNumber","Number","getColumnNumber","getSource","join","require","ErrorStackParser","FIREFOX_SAFARI_STACK_REGEXP","CHROME_IE_STACK_REGEXP","parse","error","stacktrace","parseOpera","stack","match","parseV8OrIE","parseFFOrSafari","Error","extractLocation","urlLike","indexOf","locationParts","replace","split","lastNumber","pop","possibleNumber","line","tokens","slice","shift","e","message","parseOpera9","parseOpera11","parseOpera10","lineRE","lines","result","exec","argsRaw","functionCall"],"mappings":"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","file":"error-stack-parser-with-polyfills.min.js","sourcesContent":["// ES5 Polyfills\n// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map\nif (!Array.prototype.map) {\n Array.prototype.map = function(callback, thisArg) {\n var O = Object(this);\n var len = O.length >>> 0;\n var T;\n if (arguments.length > 1) {\n T = thisArg;\n }\n\n var A = new Array(len);\n var k = 0;\n\n while (k < len) {\n var kValue, mappedValue;\n if (k in O) {\n kValue = O[k];\n mappedValue = callback.call(T, kValue, k, O);\n A[k] = mappedValue;\n }\n k++;\n }\n\n return A;\n };\n}\n\n// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter\nif (!Array.prototype.filter) {\n Array.prototype.filter = function(callback/*, thisArg*/) {\n var t = Object(this);\n var len = t.length >>> 0;\n\n var res = [];\n var thisArg = arguments.length >= 2 ? arguments[1] : void 0;\n for (var i = 0; i < len; i++) {\n if (i in t) {\n var val = t[i];\n if (callback.call(thisArg, val, i, t)) {\n res.push(val);\n }\n }\n }\n\n return res;\n };\n}\n","(function (root, factory) {\n 'use strict';\n // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.\n if (typeof define === 'function' && define.amd) {\n define('stackframe', [], factory);\n } else if (typeof exports === 'object') {\n module.exports = factory();\n } else {\n root.StackFrame = factory();\n }\n}(this, function () {\n 'use strict';\n function _isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n function StackFrame(functionName, args, fileName, lineNumber, columnNumber, source) {\n if (functionName !== undefined) {\n this.setFunctionName(functionName);\n }\n if (args !== undefined) {\n this.setArgs(args);\n }\n if (fileName !== undefined) {\n this.setFileName(fileName);\n }\n if (lineNumber !== undefined) {\n this.setLineNumber(lineNumber);\n }\n if (columnNumber !== undefined) {\n this.setColumnNumber(columnNumber);\n }\n if (source !== undefined) {\n this.setSource(source);\n }\n }\n\n StackFrame.prototype = {\n getFunctionName: function () {\n return this.functionName;\n },\n setFunctionName: function (v) {\n this.functionName = String(v);\n },\n\n getArgs: function () {\n return this.args;\n },\n setArgs: function (v) {\n if (Object.prototype.toString.call(v) !== '[object Array]') {\n throw new TypeError('Args must be an Array');\n }\n this.args = v;\n },\n\n // NOTE: Property name may be misleading as it includes the path,\n // but it somewhat mirrors V8's JavaScriptStackTraceApi\n // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi and Gecko's\n // http://mxr.mozilla.org/mozilla-central/source/xpcom/base/nsIException.idl#14\n getFileName: function () {\n return this.fileName;\n },\n setFileName: function (v) {\n this.fileName = String(v);\n },\n\n getLineNumber: function () {\n return this.lineNumber;\n },\n setLineNumber: function (v) {\n if (!_isNumber(v)) {\n throw new TypeError('Line Number must be a Number');\n }\n this.lineNumber = Number(v);\n },\n\n getColumnNumber: function () {\n return this.columnNumber;\n },\n setColumnNumber: function (v) {\n if (!_isNumber(v)) {\n throw new TypeError('Column Number must be a Number');\n }\n this.columnNumber = Number(v);\n },\n\n getSource: function () {\n return this.source;\n },\n setSource: function (v) {\n this.source = String(v);\n },\n\n toString: function() {\n var functionName = this.getFunctionName() || '{anonymous}';\n var args = '(' + (this.getArgs() || []).join(',') + ')';\n var fileName = this.getFileName() ? ('@' + this.getFileName()) : '';\n var lineNumber = _isNumber(this.getLineNumber()) ? (':' + this.getLineNumber()) : '';\n var columnNumber = _isNumber(this.getColumnNumber()) ? (':' + this.getColumnNumber()) : '';\n return functionName + args + fileName + lineNumber + columnNumber;\n }\n };\n\n return StackFrame;\n}));\n","(function (root, factory) {\n 'use strict';\n // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.\n\n /* istanbul ignore next */\n if (typeof define === 'function' && define.amd) {\n define('error-stack-parser', ['stackframe'], factory);\n } else if (typeof exports === 'object') {\n module.exports = factory(require('stackframe'));\n } else {\n root.ErrorStackParser = factory(root.StackFrame);\n }\n}(this, function ErrorStackParser(StackFrame) {\n 'use strict';\n\n var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\\S+\\:\\d+/;\n var CHROME_IE_STACK_REGEXP = /\\s+at .*(\\S+\\:\\d+|\\(native\\))/;\n\n return {\n /**\n * Given an Error object, extract the most information from it.\n * @param error {Error}\n * @return Array[StackFrame]\n */\n parse: function ErrorStackParser$$parse(error) {\n if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') {\n return this.parseOpera(error);\n } else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) {\n return this.parseV8OrIE(error);\n } else if (error.stack && error.stack.match(FIREFOX_SAFARI_STACK_REGEXP)) {\n return this.parseFFOrSafari(error);\n } else {\n throw new Error('Cannot parse given Error object');\n }\n },\n\n /**\n * Separate line and column numbers from a URL-like string.\n * @param urlLike String\n * @return Array[String]\n */\n extractLocation: function ErrorStackParser$$extractLocation(urlLike) {\n // Fail-fast but return locations like \"(native)\"\n if (urlLike.indexOf(':') === -1) {\n return [urlLike];\n }\n\n var locationParts = urlLike.replace(/[\\(\\)\\s]/g, '').split(':');\n var lastNumber = locationParts.pop();\n var possibleNumber = locationParts[locationParts.length - 1];\n if (!isNaN(parseFloat(possibleNumber)) && isFinite(possibleNumber)) {\n var lineNumber = locationParts.pop();\n return [locationParts.join(':'), lineNumber, lastNumber];\n } else {\n return [locationParts.join(':'), lastNumber, undefined];\n }\n },\n\n parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) {\n return error.stack.split('\\n').filter(function (line) {\n return !!line.match(CHROME_IE_STACK_REGEXP);\n }, this).map(function (line) {\n var tokens = line.replace(/^\\s+/, '').split(/\\s+/).slice(1);\n var locationParts = this.extractLocation(tokens.pop());\n var functionName = (!tokens[0] || tokens[0] === 'Anonymous') ? undefined : tokens[0];\n return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2], line);\n }, this);\n },\n\n parseFFOrSafari: function ErrorStackParser$$parseFFOrSafari(error) {\n return error.stack.split('\\n').filter(function (line) {\n return !!line.match(FIREFOX_SAFARI_STACK_REGEXP);\n }, this).map(function (line) {\n var tokens = line.split('@');\n var locationParts = this.extractLocation(tokens.pop());\n var functionName = tokens.shift() || undefined;\n return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2], line);\n }, this);\n },\n\n parseOpera: function ErrorStackParser$$parseOpera(e) {\n if (!e.stacktrace || (e.message.indexOf('\\n') > -1 &&\n e.message.split('\\n').length > e.stacktrace.split('\\n').length)) {\n return this.parseOpera9(e);\n } else if (!e.stack) {\n return this.parseOpera10(e);\n } else {\n return this.parseOpera11(e);\n }\n },\n\n parseOpera9: function ErrorStackParser$$parseOpera9(e) {\n var lineRE = /Line (\\d+).*script (?:in )?(\\S+)/i;\n var lines = e.message.split('\\n');\n var result = [];\n\n for (var i = 2, len = lines.length; i < len; i += 2) {\n var match = lineRE.exec(lines[i]);\n if (match) {\n result.push(new StackFrame(undefined, undefined, match[2], match[1], undefined, lines[i]));\n }\n }\n\n return result;\n },\n\n parseOpera10: function ErrorStackParser$$parseOpera10(e) {\n var lineRE = /Line (\\d+).*script (?:in )?(\\S+)(?:: In function (\\S+))?$/i;\n var lines = e.stacktrace.split('\\n');\n var result = [];\n\n for (var i = 0, len = lines.length; i < len; i += 2) {\n var match = lineRE.exec(lines[i]);\n if (match) {\n result.push(new StackFrame(match[3] || undefined, undefined, match[2], match[1], undefined, lines[i]));\n }\n }\n\n return result;\n },\n\n // Opera 10.65+ Error.stack very similar to FF/Safari\n parseOpera11: function ErrorStackParser$$parseOpera11(error) {\n return error.stack.split('\\n').filter(function (line) {\n return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) &&\n !line.match(/^Error created at/);\n }, this).map(function (line) {\n var tokens = line.split('@');\n var locationParts = this.extractLocation(tokens.pop());\n var functionCall = (tokens.shift() || '');\n var functionName = functionCall\n .replace(//, '$2')\n .replace(/\\([^\\)]*\\)/g, '') || undefined;\n var argsRaw;\n if (functionCall.match(/\\(([^\\)]*)\\)/)) {\n argsRaw = functionCall.replace(/^[^\\(]+\\(([^\\)]*)\\)$/, '$1');\n }\n var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ? undefined : argsRaw.split(',');\n return new StackFrame(functionName, args, locationParts[0], locationParts[1], locationParts[2], line);\n }, this);\n }\n };\n}));\n\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/error-stack-parser.js b/dist/error-stack-parser.js index a4b64dd..fa70105 100644 --- a/dist/error-stack-parser.js +++ b/dist/error-stack-parser.js @@ -14,7 +14,34 @@ 'use strict'; var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\S+\:\d+/; - var CHROME_IE_STACK_REGEXP = /\s+at .*(\S+\:\d+|\(native\))/; + var CHROME_IE_STACK_REGEXP = /^\s*at .*(\S+\:\d+|\(native\))/m; + var SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code\])?$/; + + function _map(array, fn, thisArg) { + if (typeof Array.prototype.map === 'function') { + return array.map(fn, thisArg); + } else { + var output = new Array(array.length); + for (var i = 0; i < array.length; i++) { + output[i] = fn.call(thisArg, array[i]); + } + return output; + } + } + + function _filter(array, fn, thisArg) { + if (typeof Array.prototype.filter === 'function') { + return array.filter(fn, thisArg); + } else { + var output = []; + for (var i = 0; i < array.length; i++) { + if (fn.call(thisArg, array[i])) { + output.push(array[i]); + } + } + return output; + } + } return { /** @@ -27,7 +54,7 @@ return this.parseOpera(error); } else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) { return this.parseV8OrIE(error); - } else if (error.stack && error.stack.match(FIREFOX_SAFARI_STACK_REGEXP)) { + } else if (error.stack) { return this.parseFFOrSafari(error); } else { throw new Error('Cannot parse given Error object'); @@ -57,24 +84,44 @@ }, parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) { - return error.stack.split('\n').filter(function (line) { + var filtered = _filter(error.stack.split('\n'), function (line) { return !!line.match(CHROME_IE_STACK_REGEXP); - }, this).map(function (line) { - var tokens = line.replace(/^\s+/, '').split(/\s+/).slice(1); + }, this); + + return _map(filtered, function (line) { + if (line.indexOf('(eval ') > -1) { + // Throw away eval information until we implement stacktrace.js/stackframe#8 + line = line.replace(/eval code/g, 'eval').replace(/(\(eval at [^\()]*)|(\)\,.*$)/g, ''); + } + var tokens = line.replace(/^\s+/, '').replace(/\(eval code/g, '(').split(/\s+/).slice(1); var locationParts = this.extractLocation(tokens.pop()); - var functionName = (!tokens[0] || tokens[0] === 'Anonymous') ? undefined : tokens[0]; - return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2], line); + var functionName = tokens.join(' ') || undefined; + var fileName = locationParts[0] === 'eval' ? undefined : locationParts[0]; + + return new StackFrame(functionName, undefined, fileName, locationParts[1], locationParts[2], line); }, this); }, parseFFOrSafari: function ErrorStackParser$$parseFFOrSafari(error) { - return error.stack.split('\n').filter(function (line) { - return !!line.match(FIREFOX_SAFARI_STACK_REGEXP); - }, this).map(function (line) { - var tokens = line.split('@'); - var locationParts = this.extractLocation(tokens.pop()); - var functionName = tokens.shift() || undefined; - return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2], line); + var filtered = _filter(error.stack.split('\n'), function (line) { + return !line.match(SAFARI_NATIVE_CODE_REGEXP); + }, this); + + return _map(filtered, function (line) { + // Throw away eval information until we implement stacktrace.js/stackframe#8 + if (line.indexOf(' > eval') > -1) { + line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval\:\d+\:\d+/g, ':$1'); + } + + if (line.indexOf('@') === -1 && line.indexOf(':') === -1) { + // Safari eval frames only have function names and nothing else + return new StackFrame(line); + } else { + var tokens = line.split('@'); + var locationParts = this.extractLocation(tokens.pop()); + var functionName = tokens.shift() || undefined; + return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2], line); + } }, this); }, @@ -121,10 +168,12 @@ // Opera 10.65+ Error.stack very similar to FF/Safari parseOpera11: function ErrorStackParser$$parseOpera11(error) { - return error.stack.split('\n').filter(function (line) { + var filtered = _filter(error.stack.split('\n'), function (line) { return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/); - }, this).map(function (line) { + }, this); + + return _map(filtered, function (line) { var tokens = line.split('@'); var locationParts = this.extractLocation(tokens.pop()); var functionCall = (tokens.shift() || ''); diff --git a/dist/error-stack-parser.min.js b/dist/error-stack-parser.min.js index 9f9193d..18c7ba6 100644 --- a/dist/error-stack-parser.min.js +++ b/dist/error-stack-parser.min.js @@ -1,2 +1,2 @@ -!function(t,e){"use strict";"function"==typeof define&&define.amd?define("stackframe",[],e):"object"==typeof exports?module.exports=e():t.StackFrame=e()}(this,function(){"use strict";function t(t){return!isNaN(parseFloat(t))&&isFinite(t)}function e(t,e,r,n,i,s){void 0!==t&&this.setFunctionName(t),void 0!==e&&this.setArgs(e),void 0!==r&&this.setFileName(r),void 0!==n&&this.setLineNumber(n),void 0!==i&&this.setColumnNumber(i),void 0!==s&&this.setSource(s)}return e.prototype={getFunctionName:function(){return this.functionName},setFunctionName:function(t){this.functionName=String(t)},getArgs:function(){return this.args},setArgs:function(t){if("[object Array]"!==Object.prototype.toString.call(t))throw new TypeError("Args must be an Array");this.args=t},getFileName:function(){return this.fileName},setFileName:function(t){this.fileName=String(t)},getLineNumber:function(){return this.lineNumber},setLineNumber:function(e){if(!t(e))throw new TypeError("Line Number must be a Number");this.lineNumber=Number(e)},getColumnNumber:function(){return this.columnNumber},setColumnNumber:function(e){if(!t(e))throw new TypeError("Column Number must be a Number");this.columnNumber=Number(e)},getSource:function(){return this.source},setSource:function(t){this.source=String(t)},toString:function(){var e=this.getFunctionName()||"{anonymous}",r="("+(this.getArgs()||[]).join(",")+")",n=this.getFileName()?"@"+this.getFileName():"",i=t(this.getLineNumber())?":"+this.getLineNumber():"",s=t(this.getColumnNumber())?":"+this.getColumnNumber():"";return e+r+n+i+s}},e}),function(t,e){"use strict";"function"==typeof define&&define.amd?define("error-stack-parser",["stackframe"],e):"object"==typeof exports?module.exports=e(require("stackframe")):t.ErrorStackParser=e(t.StackFrame)}(this,function(t){"use strict";var e=/(^|@)\S+\:\d+/,r=/\s+at .*(\S+\:\d+|\(native\))/;return{parse:function(t){if("undefined"!=typeof t.stacktrace||"undefined"!=typeof t["opera#sourceloc"])return this.parseOpera(t);if(t.stack&&t.stack.match(r))return this.parseV8OrIE(t);if(t.stack&&t.stack.match(e))return this.parseFFOrSafari(t);throw new Error("Cannot parse given Error object")},extractLocation:function(t){if(-1===t.indexOf(":"))return[t];var e=t.replace(/[\(\)\s]/g,"").split(":"),r=e.pop(),n=e[e.length-1];if(!isNaN(parseFloat(n))&&isFinite(n)){var i=e.pop();return[e.join(":"),i,r]}return[e.join(":"),r,void 0]},parseV8OrIE:function(e){return e.stack.split("\n").filter(function(t){return!!t.match(r)},this).map(function(e){var r=e.replace(/^\s+/,"").split(/\s+/).slice(1),n=this.extractLocation(r.pop()),i=r[0]&&"Anonymous"!==r[0]?r[0]:void 0;return new t(i,void 0,n[0],n[1],n[2],e)},this)},parseFFOrSafari:function(r){return r.stack.split("\n").filter(function(t){return!!t.match(e)},this).map(function(e){var r=e.split("@"),n=this.extractLocation(r.pop()),i=r.shift()||void 0;return new t(i,void 0,n[0],n[1],n[2],e)},this)},parseOpera:function(t){return!t.stacktrace||t.message.indexOf("\n")>-1&&t.message.split("\n").length>t.stacktrace.split("\n").length?this.parseOpera9(t):t.stack?this.parseOpera11(t):this.parseOpera10(t)},parseOpera9:function(e){for(var r=/Line (\d+).*script (?:in )?(\S+)/i,n=e.message.split("\n"),i=[],s=2,o=n.length;o>s;s+=2){var a=r.exec(n[s]);a&&i.push(new t(void 0,void 0,a[2],a[1],void 0,n[s]))}return i},parseOpera10:function(e){for(var r=/Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i,n=e.stacktrace.split("\n"),i=[],s=0,o=n.length;o>s;s+=2){var a=r.exec(n[s]);a&&i.push(new t(a[3]||void 0,void 0,a[2],a[1],void 0,n[s]))}return i},parseOpera11:function(r){return r.stack.split("\n").filter(function(t){return!!t.match(e)&&!t.match(/^Error created at/)},this).map(function(e){var r,n=e.split("@"),i=this.extractLocation(n.pop()),s=n.shift()||"",o=s.replace(//,"$2").replace(/\([^\)]*\)/g,"")||void 0;s.match(/\(([^\)]*)\)/)&&(r=s.replace(/^[^\(]+\(([^\)]*)\)$/,"$1"));var a=void 0===r||"[arguments not available]"===r?void 0:r.split(",");return new t(o,a,i[0],i[1],i[2],e)},this)}}}); -//# sourceMappingURL=error-stack-parser.min.js.map \ No newline at end of file +!function(e,t){"use strict";"function"==typeof define&&define.amd?define("stackframe",[],t):"object"==typeof exports?module.exports=t():e.StackFrame=t()}(this,function(){"use strict";function e(e){return!isNaN(parseFloat(e))&&isFinite(e)}function t(e,t,r,n,i,a){void 0!==e&&this.setFunctionName(e),void 0!==t&&this.setArgs(t),void 0!==r&&this.setFileName(r),void 0!==n&&this.setLineNumber(n),void 0!==i&&this.setColumnNumber(i),void 0!==a&&this.setSource(a)}return t.prototype={getFunctionName:function(){return this.functionName},setFunctionName:function(e){this.functionName=String(e)},getArgs:function(){return this.args},setArgs:function(e){if("[object Array]"!==Object.prototype.toString.call(e))throw new TypeError("Args must be an Array");this.args=e},getFileName:function(){return this.fileName},setFileName:function(e){this.fileName=String(e)},getLineNumber:function(){return this.lineNumber},setLineNumber:function(t){if(!e(t))throw new TypeError("Line Number must be a Number");this.lineNumber=Number(t)},getColumnNumber:function(){return this.columnNumber},setColumnNumber:function(t){if(!e(t))throw new TypeError("Column Number must be a Number");this.columnNumber=Number(t)},getSource:function(){return this.source},setSource:function(e){this.source=String(e)},toString:function(){var t=this.getFunctionName()||"{anonymous}",r="("+(this.getArgs()||[]).join(",")+")",n=this.getFileName()?"@"+this.getFileName():"",i=e(this.getLineNumber())?":"+this.getLineNumber():"",a=e(this.getColumnNumber())?":"+this.getColumnNumber():"";return t+r+n+i+a}},t}),function(e,t){"use strict";"function"==typeof define&&define.amd?define("error-stack-parser",["stackframe"],t):"object"==typeof exports?module.exports=t(require("stackframe")):e.ErrorStackParser=t(e.StackFrame)}(this,function(e){"use strict";function t(e,t,r){if("function"==typeof Array.prototype.map)return e.map(t,r);for(var n=new Array(e.length),i=0;i-1&&(t=t.replace(/eval code/g,"eval").replace(/(\(eval at [^\()]*)|(\)\,.*$)/g,""));var r=t.replace(/^\s+/,"").replace(/\(eval code/g,"(").split(/\s+/).slice(1),n=this.extractLocation(r.pop()),i=r.join(" ")||void 0,a="eval"===n[0]?void 0:n[0];return new e(i,void 0,a,n[1],n[2],t)},this)},parseFFOrSafari:function(n){var i=r(n.stack.split("\n"),function(e){return!e.match(a)},this);return t(i,function(t){if(t.indexOf(" > eval")>-1&&(t=t.replace(/ line (\d+)(?: > eval line \d+)* > eval\:\d+\:\d+/g,":$1")),-1===t.indexOf("@")&&-1===t.indexOf(":"))return new e(t);var r=t.split("@"),n=this.extractLocation(r.pop()),i=r.shift()||void 0;return new e(i,void 0,n[0],n[1],n[2],t)},this)},parseOpera:function(e){return!e.stacktrace||e.message.indexOf("\n")>-1&&e.message.split("\n").length>e.stacktrace.split("\n").length?this.parseOpera9(e):e.stack?this.parseOpera11(e):this.parseOpera10(e)},parseOpera9:function(t){for(var r=/Line (\d+).*script (?:in )?(\S+)/i,n=t.message.split("\n"),i=[],a=2,o=n.length;o>a;a+=2){var s=r.exec(n[a]);s&&i.push(new e(void 0,void 0,s[2],s[1],void 0,n[a]))}return i},parseOpera10:function(t){for(var r=/Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i,n=t.stacktrace.split("\n"),i=[],a=0,o=n.length;o>a;a+=2){var s=r.exec(n[a]);s&&i.push(new e(s[3]||void 0,void 0,s[2],s[1],void 0,n[a]))}return i},parseOpera11:function(i){var a=r(i.stack.split("\n"),function(e){return!!e.match(n)&&!e.match(/^Error created at/)},this);return t(a,function(t){var r,n=t.split("@"),i=this.extractLocation(n.pop()),a=n.shift()||"",o=a.replace(//,"$2").replace(/\([^\)]*\)/g,"")||void 0;a.match(/\(([^\)]*)\)/)&&(r=a.replace(/^[^\(]+\(([^\)]*)\)$/,"$1"));var s=void 0===r||"[arguments not available]"===r?void 0:r.split(",");return new e(o,s,i[0],i[1],i[2],t)},this)}}}); +//# sourceMappingURL=error-stack-parser.min.js.map diff --git a/dist/error-stack-parser.min.js.map b/dist/error-stack-parser.min.js.map index f79aa6c..4ef8993 100644 --- a/dist/error-stack-parser.min.js.map +++ b/dist/error-stack-parser.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["stackframe.js","error-stack-parser.js"],"names":["root","factory","define","amd","exports","module","StackFrame","this","_isNumber","n","isNaN","parseFloat","isFinite","functionName","args","fileName","lineNumber","columnNumber","source","undefined","setFunctionName","setArgs","setFileName","setLineNumber","setColumnNumber","setSource","prototype","getFunctionName","v","String","getArgs","Object","toString","call","TypeError","getFileName","getLineNumber","Number","getColumnNumber","getSource","join","require","ErrorStackParser","FIREFOX_SAFARI_STACK_REGEXP","CHROME_IE_STACK_REGEXP","parse","error","stacktrace","parseOpera","stack","match","parseV8OrIE","parseFFOrSafari","Error","extractLocation","urlLike","indexOf","locationParts","replace","split","lastNumber","pop","possibleNumber","length","filter","line","map","tokens","slice","shift","e","message","parseOpera9","parseOpera11","parseOpera10","lineRE","lines","result","i","len","exec","push","argsRaw","functionCall"],"mappings":"CAAA,SAAAA,EAAAC,GACA,YAEA,mBAAAC,SAAAA,OAAAC,IACAD,OAAA,gBAAAD,GACA,gBAAAG,SACAC,OAAAD,QAAAH,IAEAD,EAAAM,WAAAL,KAEAM,KAAA,WACA,YACA,SAAAC,GAAAC,GACA,OAAAC,MAAAC,WAAAF,KAAAG,SAAAH,GAGA,QAAAH,GAAAO,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,GACAC,SAAAN,GACAN,KAAAa,gBAAAP,GAEAM,SAAAL,GACAP,KAAAc,QAAAP,GAEAK,SAAAJ,GACAR,KAAAe,YAAAP,GAEAI,SAAAH,GACAT,KAAAgB,cAAAP,GAEAG,SAAAF,GACAV,KAAAiB,gBAAAP,GAEAE,SAAAD,GACAX,KAAAkB,UAAAP,GAsEA,MAlEAZ,GAAAoB,WACAC,gBAAA,WACA,MAAApB,MAAAM,cAEAO,gBAAA,SAAAQ,GACArB,KAAAM,aAAAgB,OAAAD,IAGAE,QAAA,WACA,MAAAvB,MAAAO,MAEAO,QAAA,SAAAO,GACA,GAAA,mBAAAG,OAAAL,UAAAM,SAAAC,KAAAL,GACA,KAAA,IAAAM,WAAA,wBAEA3B,MAAAO,KAAAc,GAOAO,YAAA,WACA,MAAA5B,MAAAQ,UAEAO,YAAA,SAAAM,GACArB,KAAAQ,SAAAc,OAAAD,IAGAQ,cAAA,WACA,MAAA7B,MAAAS,YAEAO,cAAA,SAAAK,GACA,IAAApB,EAAAoB,GACA,KAAA,IAAAM,WAAA,+BAEA3B,MAAAS,WAAAqB,OAAAT,IAGAU,gBAAA,WACA,MAAA/B,MAAAU,cAEAO,gBAAA,SAAAI,GACA,IAAApB,EAAAoB,GACA,KAAA,IAAAM,WAAA,iCAEA3B,MAAAU,aAAAoB,OAAAT,IAGAW,UAAA,WACA,MAAAhC,MAAAW,QAEAO,UAAA,SAAAG,GACArB,KAAAW,OAAAW,OAAAD,IAGAI,SAAA,WACA,GAAAnB,GAAAN,KAAAoB,mBAAA,cACAb,EAAA,KAAAP,KAAAuB,eAAAU,KAAA,KAAA,IACAzB,EAAAR,KAAA4B,cAAA,IAAA5B,KAAA4B,cAAA,GACAnB,EAAAR,EAAAD,KAAA6B,iBAAA,IAAA7B,KAAA6B,gBAAA,GACAnB,EAAAT,EAAAD,KAAA+B,mBAAA,IAAA/B,KAAA+B,kBAAA,EACA,OAAAzB,GAAAC,EAAAC,EAAAC,EAAAC,IAIAX,ICvGA,SAAAN,EAAAC,GACA,YAIA,mBAAAC,SAAAA,OAAAC,IACAD,OAAA,sBAAA,cAAAD,GACA,gBAAAG,SACAC,OAAAD,QAAAH,EAAAwC,QAAA,eAEAzC,EAAA0C,iBAAAzC,EAAAD,EAAAM,aAEAC,KAAA,SAAAD,GACA,YAEA,IAAAqC,GAAA,gBACAC,EAAA,+BAEA,QAMAC,MAAA,SAAAC,GACA,GAAA,mBAAAA,GAAAC,YAAA,mBAAAD,GAAA,mBACA,MAAAvC,MAAAyC,WAAAF,EACA,IAAAA,EAAAG,OAAAH,EAAAG,MAAAC,MAAAN,GACA,MAAArC,MAAA4C,YAAAL,EACA,IAAAA,EAAAG,OAAAH,EAAAG,MAAAC,MAAAP,GACA,MAAApC,MAAA6C,gBAAAN,EAEA,MAAA,IAAAO,OAAA,oCASAC,gBAAA,SAAAC,GAEA,GAAA,KAAAA,EAAAC,QAAA,KACA,OAAAD,EAGA,IAAAE,GAAAF,EAAAG,QAAA,YAAA,IAAAC,MAAA,KACAC,EAAAH,EAAAI,MACAC,EAAAL,EAAAA,EAAAM,OAAA,EACA,KAAArD,MAAAC,WAAAmD,KAAAlD,SAAAkD,GAAA,CACA,GAAA9C,GAAAyC,EAAAI,KACA,QAAAJ,EAAAjB,KAAA,KAAAxB,EAAA4C,GAEA,OAAAH,EAAAjB,KAAA,KAAAoB,EAAAzC,SAIAgC,YAAA,SAAAL,GACA,MAAAA,GAAAG,MAAAU,MAAA,MAAAK,OAAA,SAAAC,GACA,QAAAA,EAAAf,MAAAN,IACArC,MAAA2D,IAAA,SAAAD,GACA,GAAAE,GAAAF,EAAAP,QAAA,OAAA,IAAAC,MAAA,OAAAS,MAAA,GACAX,EAAAlD,KAAA+C,gBAAAa,EAAAN,OACAhD,EAAAsD,EAAA,IAAA,cAAAA,EAAA,GAAAA,EAAA,GAAAhD,MACA,OAAA,IAAAb,GAAAO,EAAAM,OAAAsC,EAAA,GAAAA,EAAA,GAAAA,EAAA,GAAAQ,IACA1D,OAGA6C,gBAAA,SAAAN,GACA,MAAAA,GAAAG,MAAAU,MAAA,MAAAK,OAAA,SAAAC,GACA,QAAAA,EAAAf,MAAAP,IACApC,MAAA2D,IAAA,SAAAD,GACA,GAAAE,GAAAF,EAAAN,MAAA,KACAF,EAAAlD,KAAA+C,gBAAAa,EAAAN,OACAhD,EAAAsD,EAAAE,SAAAlD,MACA,OAAA,IAAAb,GAAAO,EAAAM,OAAAsC,EAAA,GAAAA,EAAA,GAAAA,EAAA,GAAAQ,IACA1D,OAGAyC,WAAA,SAAAsB,GACA,OAAAA,EAAAvB,YAAAuB,EAAAC,QAAAf,QAAA,MAAA,IACAc,EAAAC,QAAAZ,MAAA,MAAAI,OAAAO,EAAAvB,WAAAY,MAAA,MAAAI,OACAxD,KAAAiE,YAAAF,GACAA,EAAArB,MAGA1C,KAAAkE,aAAAH,GAFA/D,KAAAmE,aAAAJ,IAMAE,YAAA,SAAAF,GAKA,IAAA,GAJAK,GAAA,oCACAC,EAAAN,EAAAC,QAAAZ,MAAA,MACAkB,KAEAC,EAAA,EAAAC,EAAAH,EAAAb,OAAAgB,EAAAD,EAAAA,GAAA,EAAA,CACA,GAAA5B,GAAAyB,EAAAK,KAAAJ,EAAAE,GACA5B,IACA2B,EAAAI,KAAA,GAAA3E,GAAAa,OAAAA,OAAA+B,EAAA,GAAAA,EAAA,GAAA/B,OAAAyD,EAAAE,KAIA,MAAAD,IAGAH,aAAA,SAAAJ,GAKA,IAAA,GAJAK,GAAA,6DACAC,EAAAN,EAAAvB,WAAAY,MAAA,MACAkB,KAEAC,EAAA,EAAAC,EAAAH,EAAAb,OAAAgB,EAAAD,EAAAA,GAAA,EAAA,CACA,GAAA5B,GAAAyB,EAAAK,KAAAJ,EAAAE,GACA5B,IACA2B,EAAAI,KAAA,GAAA3E,GAAA4C,EAAA,IAAA/B,OAAAA,OAAA+B,EAAA,GAAAA,EAAA,GAAA/B,OAAAyD,EAAAE,KAIA,MAAAD,IAIAJ,aAAA,SAAA3B,GACA,MAAAA,GAAAG,MAAAU,MAAA,MAAAK,OAAA,SAAAC,GACA,QAAAA,EAAAf,MAAAP,KACAsB,EAAAf,MAAA,sBACA3C,MAAA2D,IAAA,SAAAD,GACA,GAMAiB,GANAf,EAAAF,EAAAN,MAAA,KACAF,EAAAlD,KAAA+C,gBAAAa,EAAAN,OACAsB,EAAAhB,EAAAE,SAAA,GACAxD,EAAAsE,EACAzB,QAAA,iCAAA,MACAA,QAAA,cAAA,KAAAvC,MAEAgE,GAAAjC,MAAA,kBACAgC,EAAAC,EAAAzB,QAAA,uBAAA,MAEA,IAAA5C,GAAAK,SAAA+D,GAAA,8BAAAA,EAAA/D,OAAA+D,EAAAvB,MAAA,IACA,OAAA,IAAArD,GAAAO,EAAAC,EAAA2C,EAAA,GAAAA,EAAA,GAAAA,EAAA,GAAAQ,IACA1D","file":"error-stack-parser.min.js","sourcesContent":["(function (root, factory) {\n 'use strict';\n // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.\n if (typeof define === 'function' && define.amd) {\n define('stackframe', [], factory);\n } else if (typeof exports === 'object') {\n module.exports = factory();\n } else {\n root.StackFrame = factory();\n }\n}(this, function () {\n 'use strict';\n function _isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n function StackFrame(functionName, args, fileName, lineNumber, columnNumber, source) {\n if (functionName !== undefined) {\n this.setFunctionName(functionName);\n }\n if (args !== undefined) {\n this.setArgs(args);\n }\n if (fileName !== undefined) {\n this.setFileName(fileName);\n }\n if (lineNumber !== undefined) {\n this.setLineNumber(lineNumber);\n }\n if (columnNumber !== undefined) {\n this.setColumnNumber(columnNumber);\n }\n if (source !== undefined) {\n this.setSource(source);\n }\n }\n\n StackFrame.prototype = {\n getFunctionName: function () {\n return this.functionName;\n },\n setFunctionName: function (v) {\n this.functionName = String(v);\n },\n\n getArgs: function () {\n return this.args;\n },\n setArgs: function (v) {\n if (Object.prototype.toString.call(v) !== '[object Array]') {\n throw new TypeError('Args must be an Array');\n }\n this.args = v;\n },\n\n // NOTE: Property name may be misleading as it includes the path,\n // but it somewhat mirrors V8's JavaScriptStackTraceApi\n // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi and Gecko's\n // http://mxr.mozilla.org/mozilla-central/source/xpcom/base/nsIException.idl#14\n getFileName: function () {\n return this.fileName;\n },\n setFileName: function (v) {\n this.fileName = String(v);\n },\n\n getLineNumber: function () {\n return this.lineNumber;\n },\n setLineNumber: function (v) {\n if (!_isNumber(v)) {\n throw new TypeError('Line Number must be a Number');\n }\n this.lineNumber = Number(v);\n },\n\n getColumnNumber: function () {\n return this.columnNumber;\n },\n setColumnNumber: function (v) {\n if (!_isNumber(v)) {\n throw new TypeError('Column Number must be a Number');\n }\n this.columnNumber = Number(v);\n },\n\n getSource: function () {\n return this.source;\n },\n setSource: function (v) {\n this.source = String(v);\n },\n\n toString: function() {\n var functionName = this.getFunctionName() || '{anonymous}';\n var args = '(' + (this.getArgs() || []).join(',') + ')';\n var fileName = this.getFileName() ? ('@' + this.getFileName()) : '';\n var lineNumber = _isNumber(this.getLineNumber()) ? (':' + this.getLineNumber()) : '';\n var columnNumber = _isNumber(this.getColumnNumber()) ? (':' + this.getColumnNumber()) : '';\n return functionName + args + fileName + lineNumber + columnNumber;\n }\n };\n\n return StackFrame;\n}));\n","(function (root, factory) {\n 'use strict';\n // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.\n\n /* istanbul ignore next */\n if (typeof define === 'function' && define.amd) {\n define('error-stack-parser', ['stackframe'], factory);\n } else if (typeof exports === 'object') {\n module.exports = factory(require('stackframe'));\n } else {\n root.ErrorStackParser = factory(root.StackFrame);\n }\n}(this, function ErrorStackParser(StackFrame) {\n 'use strict';\n\n var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\\S+\\:\\d+/;\n var CHROME_IE_STACK_REGEXP = /\\s+at .*(\\S+\\:\\d+|\\(native\\))/;\n\n return {\n /**\n * Given an Error object, extract the most information from it.\n * @param error {Error}\n * @return Array[StackFrame]\n */\n parse: function ErrorStackParser$$parse(error) {\n if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') {\n return this.parseOpera(error);\n } else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) {\n return this.parseV8OrIE(error);\n } else if (error.stack && error.stack.match(FIREFOX_SAFARI_STACK_REGEXP)) {\n return this.parseFFOrSafari(error);\n } else {\n throw new Error('Cannot parse given Error object');\n }\n },\n\n /**\n * Separate line and column numbers from a URL-like string.\n * @param urlLike String\n * @return Array[String]\n */\n extractLocation: function ErrorStackParser$$extractLocation(urlLike) {\n // Fail-fast but return locations like \"(native)\"\n if (urlLike.indexOf(':') === -1) {\n return [urlLike];\n }\n\n var locationParts = urlLike.replace(/[\\(\\)\\s]/g, '').split(':');\n var lastNumber = locationParts.pop();\n var possibleNumber = locationParts[locationParts.length - 1];\n if (!isNaN(parseFloat(possibleNumber)) && isFinite(possibleNumber)) {\n var lineNumber = locationParts.pop();\n return [locationParts.join(':'), lineNumber, lastNumber];\n } else {\n return [locationParts.join(':'), lastNumber, undefined];\n }\n },\n\n parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) {\n return error.stack.split('\\n').filter(function (line) {\n return !!line.match(CHROME_IE_STACK_REGEXP);\n }, this).map(function (line) {\n var tokens = line.replace(/^\\s+/, '').split(/\\s+/).slice(1);\n var locationParts = this.extractLocation(tokens.pop());\n var functionName = (!tokens[0] || tokens[0] === 'Anonymous') ? undefined : tokens[0];\n return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2], line);\n }, this);\n },\n\n parseFFOrSafari: function ErrorStackParser$$parseFFOrSafari(error) {\n return error.stack.split('\\n').filter(function (line) {\n return !!line.match(FIREFOX_SAFARI_STACK_REGEXP);\n }, this).map(function (line) {\n var tokens = line.split('@');\n var locationParts = this.extractLocation(tokens.pop());\n var functionName = tokens.shift() || undefined;\n return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2], line);\n }, this);\n },\n\n parseOpera: function ErrorStackParser$$parseOpera(e) {\n if (!e.stacktrace || (e.message.indexOf('\\n') > -1 &&\n e.message.split('\\n').length > e.stacktrace.split('\\n').length)) {\n return this.parseOpera9(e);\n } else if (!e.stack) {\n return this.parseOpera10(e);\n } else {\n return this.parseOpera11(e);\n }\n },\n\n parseOpera9: function ErrorStackParser$$parseOpera9(e) {\n var lineRE = /Line (\\d+).*script (?:in )?(\\S+)/i;\n var lines = e.message.split('\\n');\n var result = [];\n\n for (var i = 2, len = lines.length; i < len; i += 2) {\n var match = lineRE.exec(lines[i]);\n if (match) {\n result.push(new StackFrame(undefined, undefined, match[2], match[1], undefined, lines[i]));\n }\n }\n\n return result;\n },\n\n parseOpera10: function ErrorStackParser$$parseOpera10(e) {\n var lineRE = /Line (\\d+).*script (?:in )?(\\S+)(?:: In function (\\S+))?$/i;\n var lines = e.stacktrace.split('\\n');\n var result = [];\n\n for (var i = 0, len = lines.length; i < len; i += 2) {\n var match = lineRE.exec(lines[i]);\n if (match) {\n result.push(new StackFrame(match[3] || undefined, undefined, match[2], match[1], undefined, lines[i]));\n }\n }\n\n return result;\n },\n\n // Opera 10.65+ Error.stack very similar to FF/Safari\n parseOpera11: function ErrorStackParser$$parseOpera11(error) {\n return error.stack.split('\\n').filter(function (line) {\n return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) &&\n !line.match(/^Error created at/);\n }, this).map(function (line) {\n var tokens = line.split('@');\n var locationParts = this.extractLocation(tokens.pop());\n var functionCall = (tokens.shift() || '');\n var functionName = functionCall\n .replace(//, '$2')\n .replace(/\\([^\\)]*\\)/g, '') || undefined;\n var argsRaw;\n if (functionCall.match(/\\(([^\\)]*)\\)/)) {\n argsRaw = functionCall.replace(/^[^\\(]+\\(([^\\)]*)\\)$/, '$1');\n }\n var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ? undefined : argsRaw.split(',');\n return new StackFrame(functionName, args, locationParts[0], locationParts[1], locationParts[2], line);\n }, this);\n }\n };\n}));\n\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["stackframe.js","error-stack-parser.js"],"names":["root","factory","define","amd","exports","module","StackFrame","this","_isNumber","n","isNaN","parseFloat","isFinite","functionName","args","fileName","lineNumber","columnNumber","source","undefined","setFunctionName","setArgs","setFileName","setLineNumber","setColumnNumber","setSource","prototype","getFunctionName","v","String","getArgs","Object","toString","call","TypeError","getFileName","getLineNumber","Number","getColumnNumber","getSource","join","require","ErrorStackParser","_map","array","fn","thisArg","Array","map","output","length","i","_filter","filter","push","FIREFOX_SAFARI_STACK_REGEXP","CHROME_IE_STACK_REGEXP","SAFARI_NATIVE_CODE_REGEXP","parse","error","stacktrace","parseOpera","stack","match","parseV8OrIE","parseFFOrSafari","Error","extractLocation","urlLike","indexOf","locationParts","replace","split","lastNumber","pop","possibleNumber","filtered","line","tokens","slice","shift","e","message","parseOpera9","parseOpera11","parseOpera10","lineRE","lines","result","len","exec","argsRaw","functionCall"],"mappings":"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","file":"error-stack-parser.min.js","sourcesContent":["(function (root, factory) {\n 'use strict';\n // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.\n\n /* istanbul ignore next */\n if (typeof define === 'function' && define.amd) {\n define('stackframe', [], factory);\n } else if (typeof exports === 'object') {\n module.exports = factory();\n } else {\n root.StackFrame = factory();\n }\n}(this, function () {\n 'use strict';\n function _isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n function StackFrame(functionName, args, fileName, lineNumber, columnNumber, source) {\n if (functionName !== undefined) {\n this.setFunctionName(functionName);\n }\n if (args !== undefined) {\n this.setArgs(args);\n }\n if (fileName !== undefined) {\n this.setFileName(fileName);\n }\n if (lineNumber !== undefined) {\n this.setLineNumber(lineNumber);\n }\n if (columnNumber !== undefined) {\n this.setColumnNumber(columnNumber);\n }\n if (source !== undefined) {\n this.setSource(source);\n }\n }\n\n StackFrame.prototype = {\n getFunctionName: function () {\n return this.functionName;\n },\n setFunctionName: function (v) {\n this.functionName = String(v);\n },\n\n getArgs: function () {\n return this.args;\n },\n setArgs: function (v) {\n if (Object.prototype.toString.call(v) !== '[object Array]') {\n throw new TypeError('Args must be an Array');\n }\n this.args = v;\n },\n\n // NOTE: Property name may be misleading as it includes the path,\n // but it somewhat mirrors V8's JavaScriptStackTraceApi\n // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi and Gecko's\n // http://mxr.mozilla.org/mozilla-central/source/xpcom/base/nsIException.idl#14\n getFileName: function () {\n return this.fileName;\n },\n setFileName: function (v) {\n this.fileName = String(v);\n },\n\n getLineNumber: function () {\n return this.lineNumber;\n },\n setLineNumber: function (v) {\n if (!_isNumber(v)) {\n throw new TypeError('Line Number must be a Number');\n }\n this.lineNumber = Number(v);\n },\n\n getColumnNumber: function () {\n return this.columnNumber;\n },\n setColumnNumber: function (v) {\n if (!_isNumber(v)) {\n throw new TypeError('Column Number must be a Number');\n }\n this.columnNumber = Number(v);\n },\n\n getSource: function () {\n return this.source;\n },\n setSource: function (v) {\n this.source = String(v);\n },\n\n toString: function() {\n var functionName = this.getFunctionName() || '{anonymous}';\n var args = '(' + (this.getArgs() || []).join(',') + ')';\n var fileName = this.getFileName() ? ('@' + this.getFileName()) : '';\n var lineNumber = _isNumber(this.getLineNumber()) ? (':' + this.getLineNumber()) : '';\n var columnNumber = _isNumber(this.getColumnNumber()) ? (':' + this.getColumnNumber()) : '';\n return functionName + args + fileName + lineNumber + columnNumber;\n }\n };\n\n return StackFrame;\n}));\n","(function (root, factory) {\n 'use strict';\n // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.\n\n /* istanbul ignore next */\n if (typeof define === 'function' && define.amd) {\n define('error-stack-parser', ['stackframe'], factory);\n } else if (typeof exports === 'object') {\n module.exports = factory(require('stackframe'));\n } else {\n root.ErrorStackParser = factory(root.StackFrame);\n }\n}(this, function ErrorStackParser(StackFrame) {\n 'use strict';\n\n var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\\S+\\:\\d+/;\n var CHROME_IE_STACK_REGEXP = /^\\s*at .*(\\S+\\:\\d+|\\(native\\))/m;\n var SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\\[native code\\])?$/;\n\n function _map(array, fn, thisArg) {\n if (typeof Array.prototype.map === 'function') {\n return array.map(fn, thisArg);\n } else {\n var output = new Array(array.length);\n for (var i = 0; i < array.length; i++) {\n output[i] = fn.call(thisArg, array[i]);\n }\n return output;\n }\n }\n\n function _filter(array, fn, thisArg) {\n if (typeof Array.prototype.filter === 'function') {\n return array.filter(fn, thisArg);\n } else {\n var output = [];\n for (var i = 0; i < array.length; i++) {\n if (fn.call(thisArg, array[i])) {\n output.push(array[i]);\n }\n }\n return output;\n }\n }\n\n return {\n /**\n * Given an Error object, extract the most information from it.\n * @param error {Error}\n * @return Array[StackFrame]\n */\n parse: function ErrorStackParser$$parse(error) {\n if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') {\n return this.parseOpera(error);\n } else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) {\n return this.parseV8OrIE(error);\n } else if (error.stack) {\n return this.parseFFOrSafari(error);\n } else {\n throw new Error('Cannot parse given Error object');\n }\n },\n\n /**\n * Separate line and column numbers from a URL-like string.\n * @param urlLike String\n * @return Array[String]\n */\n extractLocation: function ErrorStackParser$$extractLocation(urlLike) {\n // Fail-fast but return locations like \"(native)\"\n if (urlLike.indexOf(':') === -1) {\n return [urlLike];\n }\n\n var locationParts = urlLike.replace(/[\\(\\)\\s]/g, '').split(':');\n var lastNumber = locationParts.pop();\n var possibleNumber = locationParts[locationParts.length - 1];\n if (!isNaN(parseFloat(possibleNumber)) && isFinite(possibleNumber)) {\n var lineNumber = locationParts.pop();\n return [locationParts.join(':'), lineNumber, lastNumber];\n } else {\n return [locationParts.join(':'), lastNumber, undefined];\n }\n },\n\n parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) {\n var filtered = _filter(error.stack.split('\\n'), function (line) {\n return !!line.match(CHROME_IE_STACK_REGEXP);\n }, this);\n\n return _map(filtered, function (line) {\n if (line.indexOf('(eval ') > -1) {\n // Throw away eval information until we implement stacktrace.js/stackframe#8\n line = line.replace(/eval code/g, 'eval').replace(/(\\(eval at [^\\()]*)|(\\)\\,.*$)/g, '');\n }\n var tokens = line.replace(/^\\s+/, '').replace(/\\(eval code/g, '(').split(/\\s+/).slice(1);\n var locationParts = this.extractLocation(tokens.pop());\n var functionName = tokens.join(' ') || undefined;\n var fileName = locationParts[0] === 'eval' ? undefined : locationParts[0];\n\n return new StackFrame(functionName, undefined, fileName, locationParts[1], locationParts[2], line);\n }, this);\n },\n\n parseFFOrSafari: function ErrorStackParser$$parseFFOrSafari(error) {\n var filtered = _filter(error.stack.split('\\n'), function (line) {\n return !line.match(SAFARI_NATIVE_CODE_REGEXP);\n }, this);\n\n return _map(filtered, function (line) {\n // Throw away eval information until we implement stacktrace.js/stackframe#8\n if (line.indexOf(' > eval') > -1) {\n line = line.replace(/ line (\\d+)(?: > eval line \\d+)* > eval\\:\\d+\\:\\d+/g, ':$1');\n }\n\n if (line.indexOf('@') === -1 && line.indexOf(':') === -1) {\n // Safari eval frames only have function names and nothing else\n return new StackFrame(line);\n } else {\n var tokens = line.split('@');\n var locationParts = this.extractLocation(tokens.pop());\n var functionName = tokens.shift() || undefined;\n return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2], line);\n }\n }, this);\n },\n\n parseOpera: function ErrorStackParser$$parseOpera(e) {\n if (!e.stacktrace || (e.message.indexOf('\\n') > -1 &&\n e.message.split('\\n').length > e.stacktrace.split('\\n').length)) {\n return this.parseOpera9(e);\n } else if (!e.stack) {\n return this.parseOpera10(e);\n } else {\n return this.parseOpera11(e);\n }\n },\n\n parseOpera9: function ErrorStackParser$$parseOpera9(e) {\n var lineRE = /Line (\\d+).*script (?:in )?(\\S+)/i;\n var lines = e.message.split('\\n');\n var result = [];\n\n for (var i = 2, len = lines.length; i < len; i += 2) {\n var match = lineRE.exec(lines[i]);\n if (match) {\n result.push(new StackFrame(undefined, undefined, match[2], match[1], undefined, lines[i]));\n }\n }\n\n return result;\n },\n\n parseOpera10: function ErrorStackParser$$parseOpera10(e) {\n var lineRE = /Line (\\d+).*script (?:in )?(\\S+)(?:: In function (\\S+))?$/i;\n var lines = e.stacktrace.split('\\n');\n var result = [];\n\n for (var i = 0, len = lines.length; i < len; i += 2) {\n var match = lineRE.exec(lines[i]);\n if (match) {\n result.push(new StackFrame(match[3] || undefined, undefined, match[2], match[1], undefined, lines[i]));\n }\n }\n\n return result;\n },\n\n // Opera 10.65+ Error.stack very similar to FF/Safari\n parseOpera11: function ErrorStackParser$$parseOpera11(error) {\n var filtered = _filter(error.stack.split('\\n'), function (line) {\n return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) &&\n !line.match(/^Error created at/);\n }, this);\n\n return _map(filtered, function (line) {\n var tokens = line.split('@');\n var locationParts = this.extractLocation(tokens.pop());\n var functionCall = (tokens.shift() || '');\n var functionName = functionCall\n .replace(//, '$2')\n .replace(/\\([^\\)]*\\)/g, '') || undefined;\n var argsRaw;\n if (functionCall.match(/\\(([^\\)]*)\\)/)) {\n argsRaw = functionCall.replace(/^[^\\(]+\\(([^\\)]*)\\)$/, '$1');\n }\n var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ? undefined : argsRaw.split(',');\n return new StackFrame(functionName, args, locationParts[0], locationParts[1], locationParts[2], line);\n }, this);\n }\n };\n}));\n\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/error-stack-parser.js b/error-stack-parser.js index a4b64dd..d01659f 100644 --- a/error-stack-parser.js +++ b/error-stack-parser.js @@ -14,7 +14,34 @@ 'use strict'; var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\S+\:\d+/; - var CHROME_IE_STACK_REGEXP = /\s+at .*(\S+\:\d+|\(native\))/; + var CHROME_IE_STACK_REGEXP = /^\s*at .*(\S+\:\d+|\(native\))/m; + var SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code\])?$/; + + function _map(array, fn, thisArg) { + if (typeof Array.prototype.map === 'function') { + return array.map(fn, thisArg); + } else { + var output = new Array(array.length); + for (var i = 0; i < array.length; i++) { + output[i] = fn.call(thisArg, array[i]); + } + return output; + } + } + + function _filter(array, fn, thisArg) { + if (typeof Array.prototype.filter === 'function') { + return array.filter(fn, thisArg); + } else { + var output = []; + for (var i = 0; i < array.length; i++) { + if (fn.call(thisArg, array[i])) { + output.push(array[i]); + } + } + return output; + } + } return { /** @@ -27,7 +54,7 @@ return this.parseOpera(error); } else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) { return this.parseV8OrIE(error); - } else if (error.stack && error.stack.match(FIREFOX_SAFARI_STACK_REGEXP)) { + } else if (error.stack) { return this.parseFFOrSafari(error); } else { throw new Error('Cannot parse given Error object'); @@ -57,24 +84,56 @@ }, parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) { - return error.stack.split('\n').filter(function (line) { + var filtered = _filter(error.stack.split('\n'), function (line) { return !!line.match(CHROME_IE_STACK_REGEXP); - }, this).map(function (line) { - var tokens = line.replace(/^\s+/, '').split(/\s+/).slice(1); + }, this); + + return _map(filtered, function (line) { + if (line.indexOf('(eval ') > -1) { + // Throw away eval information until we implement stacktrace.js/stackframe#8 + line = line.replace(/eval code/g, 'eval').replace(/(\(eval at [^\()]*)|(\)\,.*$)/g, ''); + } + var tokens = line.replace(/^\s+/, '').replace(/\(eval code/g, '(').split(/\s+/).slice(1); var locationParts = this.extractLocation(tokens.pop()); - var functionName = (!tokens[0] || tokens[0] === 'Anonymous') ? undefined : tokens[0]; - return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2], line); + var functionName = tokens.join(' ') || undefined; + var fileName = locationParts[0] === 'eval' ? undefined : locationParts[0]; + + return new StackFrame({ + functionName: functionName, + fileName: fileName, + lineNumber: locationParts[1], + columnNumber: locationParts[2], + source: line + }); }, this); }, parseFFOrSafari: function ErrorStackParser$$parseFFOrSafari(error) { - return error.stack.split('\n').filter(function (line) { - return !!line.match(FIREFOX_SAFARI_STACK_REGEXP); - }, this).map(function (line) { - var tokens = line.split('@'); - var locationParts = this.extractLocation(tokens.pop()); - var functionName = tokens.shift() || undefined; - return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2], line); + var filtered = _filter(error.stack.split('\n'), function (line) { + return !line.match(SAFARI_NATIVE_CODE_REGEXP); + }, this); + + return _map(filtered, function (line) { + // Throw away eval information until we implement stacktrace.js/stackframe#8 + if (line.indexOf(' > eval') > -1) { + line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval\:\d+\:\d+/g, ':$1'); + } + + if (line.indexOf('@') === -1 && line.indexOf(':') === -1) { + // Safari eval frames only have function names and nothing else + return new StackFrame({ functionName: line }); + } else { + var tokens = line.split('@'); + var locationParts = this.extractLocation(tokens.pop()); + var functionName = tokens.join('@') || undefined; + return new StackFrame({ + functionName: functionName, + fileName: locationParts[0], + lineNumber: locationParts[1], + columnNumber: locationParts[2], + source: line + }); + } }, this); }, @@ -97,7 +156,11 @@ for (var i = 2, len = lines.length; i < len; i += 2) { var match = lineRE.exec(lines[i]); if (match) { - result.push(new StackFrame(undefined, undefined, match[2], match[1], undefined, lines[i])); + result.push(new StackFrame({ + fileName: match[2], + lineNumber: match[1], + source: lines[i] + })); } } @@ -112,7 +175,12 @@ for (var i = 0, len = lines.length; i < len; i += 2) { var match = lineRE.exec(lines[i]); if (match) { - result.push(new StackFrame(match[3] || undefined, undefined, match[2], match[1], undefined, lines[i])); + result.push(new StackFrame({ + functionName: match[3] || undefined, + fileName: match[2], + lineNumber: match[1], + source: lines[i] + })); } } @@ -121,10 +189,12 @@ // Opera 10.65+ Error.stack very similar to FF/Safari parseOpera11: function ErrorStackParser$$parseOpera11(error) { - return error.stack.split('\n').filter(function (line) { + var filtered = _filter(error.stack.split('\n'), function (line) { return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/); - }, this).map(function (line) { + }, this); + + return _map(filtered, function (line) { var tokens = line.split('@'); var locationParts = this.extractLocation(tokens.pop()); var functionCall = (tokens.shift() || ''); @@ -136,9 +206,15 @@ argsRaw = functionCall.replace(/^[^\(]+\(([^\)]*)\)$/, '$1'); } var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ? undefined : argsRaw.split(','); - return new StackFrame(functionName, args, locationParts[0], locationParts[1], locationParts[2], line); + return new StackFrame({ + functionName: functionName, + args: args, + fileName: locationParts[0], + lineNumber: locationParts[1], + columnNumber: locationParts[2], + source: line + }); }, this); } }; })); - diff --git a/gulpfile.js b/gulpfile.js index cb068d7..a3374f7 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -3,12 +3,11 @@ var coveralls = require('gulp-coveralls'); var del = require('del'); var gulp = require('gulp'); var jshint = require('gulp-jshint'); -var karma = require('karma').server; +var karma = require('karma'); var runSequence = require('run-sequence'); var sourcemaps = require('gulp-sourcemaps'); var uglify = require('gulp-uglify'); -var polyfills = ['./polyfills.js']; var dependencies = ['./node_modules/stackframe/dist/stackframe.js']; var source = 'error-stack-parser.js'; @@ -20,17 +19,25 @@ gulp.task('lint', function () { }); gulp.task('test', function (done) { - karma.start({ + new karma.Server({ configFile: __dirname + '/karma.conf.js', singleRun: true - }, done); + }, done).start(); +}); + +gulp.task('test-pr', ['copy', 'dist'], function (done) { + new karma.Server({ + configFile: __dirname + '/karma.conf.js', + browsers: ['Firefox', 'Chrome'], + singleRun: true + }, done).start(); }); gulp.task('test-ci', ['dist'], function (done) { - karma.start({ + new karma.Server({ configFile: __dirname + '/karma.conf.ci.js', singleRun: true - }, done); + }, done).start(); }); gulp.task('copy', function () { @@ -39,14 +46,6 @@ gulp.task('copy', function () { }); gulp.task('dist', ['copy'], function() { - // Separate distribution for old browsers - gulp.src(polyfills.concat(dependencies.concat(source))) - .pipe(sourcemaps.init()) - .pipe(concat(source.replace('.js', '-with-polyfills.min.js'))) - .pipe(uglify()) - .pipe(sourcemaps.write('./')) - .pipe(gulp.dest('dist')); - return gulp.src(dependencies.concat(source)) .pipe(sourcemaps.init()) .pipe(concat(source.replace('.js', '.min.js'))) @@ -57,6 +56,8 @@ gulp.task('dist', ['copy'], function() { gulp.task('clean', del.bind(null, ['build', 'coverage', 'dist'])); +gulp.task('pr', ['lint', 'test-pr']); + gulp.task('ci', ['lint', 'test-ci'], function () { gulp.src('./coverage/**/lcov.info') .pipe(coveralls()); diff --git a/karma.conf.ci.js b/karma.conf.ci.js index d03a283..bb14ce6 100644 --- a/karma.conf.ci.js +++ b/karma.conf.ci.js @@ -6,79 +6,114 @@ module.exports = function (config) { // Check out https://saucelabs.com/platforms for all browser/platform combos var customLaunchers = { - //slIOS7: { - // base: 'SauceLabs', - // browserName: 'iPhone', - // platform: 'OS X 10.9', - // version: '7.1' - //}, slIOS8: { base: 'SauceLabs', browserName: 'iPhone', - platform: 'OS X 10.9', - version: '8.1' + platform: 'OS X 10.10', + version: '8.4' + }, + slIOS9: { + base: 'SauceLabs', + browserName: 'iPhone', + platform: 'OS X 10.11', + version: '9.2' + }, + slAndroid4: { + base: 'SauceLabs', + browserName: 'Android', + platform: 'Linux', + version: '4.4' + }, + slAndroid5: { + base: 'SauceLabs', + browserName: 'Android', + platform: 'Linux', + version: '5.1' }, - //slAndroid4: { - // base: 'SauceLabs', - // browserName: 'Android', - // platform: 'Linux', - // version: '4.4' - //}, slChrome: { base: 'SauceLabs', browserName: 'chrome' }, - slFirefox: { + slChromeBeta: { base: 'SauceLabs', - browserName: 'firefox' + browserName: 'chrome', + version: 'beta' + }, + slChromeCanary: { + base: 'SauceLabs', + browserName: 'chrome', + version: 'dev' + }, + slFirefox42: { + base: 'SauceLabs', + browserName: 'firefox', + platform: 'Windows 8.1', + version: '43.0' + }, + slFirefoxDev: { + base: 'SauceLabs', + browserName: 'firefox', + version: 'dev' + }, + slSafari8: { + base: 'SauceLabs', + browserName: 'safari', + platform: 'OS X 10.10', + version: '8' + }, + slSafari9: { + base: 'SauceLabs', + browserName: 'safari', + platform: 'OS X 10.11', + version: '9' }, - //slSafari6: { - // base: 'SauceLabs', - // browserName: 'safari', - // platform: 'OS X 10.8', - // version: '6' - //}, - //slSafari7: { - // base: 'SauceLabs', - // browserName: 'safari', - // platform: 'OS X 10.9', - // version: '7' - //}, - //slSafari8: { - // base: 'SauceLabs', - // browserName: 'safari', - // platform: 'OS X 10.10', - // version: '8' - //} slOpera: { base: 'SauceLabs', browserName: 'opera' }, + slEdge20: { + base: 'SauceLabs', + browserName: 'microsoftedge', + platform: 'Windows 10', + version: '20.10240' + }, slIE11: { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 8.1', version: '11' }, - //slIE10: { - // base: 'SauceLabs', - // browserName: 'internet explorer', - // platform: 'Windows 8', - // version: '10' - //}, - slIE7: { + slIE10: { + base: 'SauceLabs', + browserName: 'internet explorer', + platform: 'Windows 8', + version: '10' + }, + slIE9: { + base: 'SauceLabs', + browserName: 'internet explorer', + platform: 'Windows 7', + version: '9' + }, + slIE8: { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows XP', - version: '7' + version: '8' } + // Too unreliable on Sauce :( + //slIE7: { + // base: 'SauceLabs', + // browserName: 'internet explorer', + // platform: 'Windows XP', + // version: '7' + //} }; config.set({ basePath: '', frameworks: ['jasmine'], files: [ - 'polyfills.js', 'node_modules/stackframe/dist/stackframe.js', 'error-stack-parser.js', 'spec/fixtures/captured-errors.js', @@ -104,7 +139,7 @@ module.exports = function (config) { }, customLaunchers: customLaunchers, browsers: Object.keys(customLaunchers), - reporters: ['progress', 'saucelabs', 'coverage'], + reporters: ['dots', 'saucelabs', 'coverage'], preprocessors: { 'error-stack-parser.js': 'coverage' }, diff --git a/karma.conf.js b/karma.conf.js index 05dc32f..1e26799 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -9,19 +9,11 @@ module.exports = function (config) { 'spec/spec-helper.js', 'spec/*-spec.js' ], - reporters: ['progress', 'coverage'], - preprocessors: { - 'error-stack-parser.js': 'coverage' - }, - coverageReporter: { - type: 'lcov', - dir: 'coverage' - }, + reporters: ['spec'], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher //browsers: ['ChromeCanary', 'Firefox', 'Opera', 'Safari'], browsers: ['PhantomJS2'], singleRun: false diff --git a/package.json b/package.json index d4410be..83b159e 100644 --- a/package.json +++ b/package.json @@ -6,16 +6,17 @@ "Victor Homyakov (https://github.com/victor-homyakov)", "Oliver Salzburg (https://github.com/oliversalzburg)" ], - "version": "1.2.2", - "license": "SEE LICENSE IN LICENSE", + "version": "1.3.3", + "license": "Unlicense", "keywords": [ "stacktrace", "error", - "stack" + "stack", + "parser" ], - "homepage": "http://www.stacktracejs.com", + "homepage": "https://www.stacktracejs.com", "dependencies": { - "stackframe": "^0.3.1" + "stackframe": "^1.0.0" }, "repository": { "type": "git", @@ -27,21 +28,24 @@ "gulp": "^3.9.0", "gulp-concat": "^2.6.0", "gulp-coveralls": "^0.1.4", - "gulp-jshint": "^1.11.2", - "gulp-sourcemaps": "^1.5.2", - "gulp-uglify": "^1.4.1", - "jasmine-node": "~1.14", - "karma": "~0.12", - "karma-chrome-launcher": "^0.1.5", - "karma-coverage": "^0.5.2", - "karma-firefox-launcher": "^0.1.3", - "karma-ie-launcher": "^0.1.5", - "karma-jasmine": "^0.1.6", + "gulp-jshint": "^2.0.0", + "gulp-sourcemaps": "^1.6.0", + "gulp-uglify": "^1.5.1", + "jasmine": "^2.3.2", + "jasmine-core": "^2.3.4", + "jshint": "^2.8.0", + "karma": "~0.13", + "karma-chrome-launcher": "^0.1.12", + "karma-coverage": "^0.5.3", + "karma-firefox-launcher": "^0.1.7", + "karma-ie-launcher": "^0.2.0", + "karma-jasmine": "^0.3.6", "karma-opera-launcher": "^0.1.0", "karma-phantomjs2-launcher": "^0.3.2", "karma-safari-launcher": "^0.1.1", - "karma-sauce-launcher": "^0.2.10", - "run-sequence": "^1.1.1" + "karma-sauce-launcher": "^0.3.0", + "karma-spec-reporter": "0.0.23", + "run-sequence": "^1.1.5" }, "bugs": { "url": "https://github.com/stacktracejs/error-stack-parser/issues" diff --git a/polyfills.js b/polyfills.js deleted file mode 100644 index 56fca7b..0000000 --- a/polyfills.js +++ /dev/null @@ -1,48 +0,0 @@ -// ES5 Polyfills -// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map -if (!Array.prototype.map) { - Array.prototype.map = function(callback, thisArg) { - var O = Object(this); - var len = O.length >>> 0; - var T; - if (arguments.length > 1) { - T = thisArg; - } - - var A = new Array(len); - var k = 0; - - while (k < len) { - var kValue, mappedValue; - if (k in O) { - kValue = O[k]; - mappedValue = callback.call(T, kValue, k, O); - A[k] = mappedValue; - } - k++; - } - - return A; - }; -} - -// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter -if (!Array.prototype.filter) { - Array.prototype.filter = function(callback/*, thisArg*/) { - var t = Object(this); - var len = t.length >>> 0; - - var res = []; - var thisArg = arguments.length >= 2 ? arguments[1] : void 0; - for (var i = 0; i < len; i++) { - if (i in t) { - var val = t[i]; - if (callback.call(thisArg, val, i, t)) { - res.push(val); - } - } - } - - return res; - }; -} diff --git a/spec/error-stack-parser-spec.js b/spec/error-stack-parser-spec.js index 3100e36..de8bf9a 100644 --- a/spec/error-stack-parser-spec.js +++ b/spec/error-stack-parser-spec.js @@ -35,6 +35,17 @@ describe('ErrorStackParser', function () { expect(stackFrames[2]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 108, 23]); }); + it('should parse nested eval() from Safari 9', function() { + var stackFrames = unit.parse(CapturedExceptions.SAFARI_9_NESTED_EVAL); + expect(stackFrames).toBeTruthy(); + expect(stackFrames.length).toBe(5); + expect(stackFrames[0]).toMatchStackFrame(['baz', undefined, undefined, undefined, undefined]); + expect(stackFrames[1]).toMatchStackFrame(['foo', undefined, undefined, undefined, undefined]); + expect(stackFrames[2]).toMatchStackFrame(['eval code', undefined, undefined, undefined, undefined]); + expect(stackFrames[3]).toMatchStackFrame(['speak', undefined, 'http://localhost:8080/file.js', 26, 21]); + expect(stackFrames[4]).toMatchStackFrame(['global code', undefined, 'http://localhost:8080/file.js', 33, 18]); + }); + it('should parse Firefox 31 Error.stack', function () { var stackFrames = unit.parse(CapturedExceptions.FIREFOX_31); expect(stackFrames).toBeTruthy(); @@ -43,6 +54,25 @@ describe('ErrorStackParser', function () { expect(stackFrames[1]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 1, 1]); }); + it('should parse nested eval() from Firefox 43', function() { + var stackFrames = unit.parse(CapturedExceptions.FIREFOX_43_NESTED_EVAL); + expect(stackFrames).toBeTruthy(); + expect(stackFrames.length).toBe(5); + expect(stackFrames[0]).toMatchStackFrame(['baz', undefined, 'http://localhost:8080/file.js', 26, undefined]); + expect(stackFrames[1]).toMatchStackFrame(['foo', undefined, 'http://localhost:8080/file.js', 26, undefined]); + expect(stackFrames[2]).toMatchStackFrame([undefined, undefined, 'http://localhost:8080/file.js', 26, undefined]); + expect(stackFrames[3]).toMatchStackFrame(['speak', undefined, 'http://localhost:8080/file.js', 26, 17]); + expect(stackFrames[4]).toMatchStackFrame([undefined, undefined, 'http://localhost:8080/file.js', 33, 9]); + }); + + it('should parse function names containing @ in Firefox 43 Error.stack', function () { + var stackFrames = unit.parse(CapturedExceptions.FIREFOX_43_FUNCTION_NAME_WITH_AT_SIGN); + expect(stackFrames).toBeTruthy(); + expect(stackFrames.length).toBe(2); + expect(stackFrames[0]).toMatchStackFrame(['obj["@fn"]', undefined, 'Scratchpad/1', 10, 29]); + expect(stackFrames[1]).toMatchStackFrame([undefined, undefined, 'Scratchpad/1', 11, 1]); + }); + it('should parse V8 Error.stack', function () { var stackFrames = unit.parse(CapturedExceptions.CHROME_15); expect(stackFrames).toBeTruthy(); @@ -66,11 +96,30 @@ describe('ErrorStackParser', function () { expect(stackFrames[0]).toMatchStackFrame(['dumpExceptionError', undefined, 'http://localhost:8080/file.js', 41, 27]); }); + it('should parse error stacks with Constructors', function () { + var stackFrames = unit.parse(CapturedExceptions.CHROME_46); + expect(stackFrames).toBeTruthy(); + expect(stackFrames.length).toBe(2); + expect(stackFrames[0]).toMatchStackFrame(['new CustomError', undefined, 'http://localhost:8080/file.js', 41, 27]); + expect(stackFrames[1]).toMatchStackFrame(['HTMLButtonElement.onclick', undefined, 'http://localhost:8080/file.js', 107, 146]); + }); + + it('should parse nested eval() from V8', function() { + var stackFrames = unit.parse(CapturedExceptions.CHROME_48_NESTED_EVAL); + expect(stackFrames).toBeTruthy(); + expect(stackFrames.length).toBe(5); + expect(stackFrames[0]).toMatchStackFrame(['baz', undefined, 'http://localhost:8080/file.js', 21, 17]); + expect(stackFrames[1]).toMatchStackFrame(['foo', undefined, 'http://localhost:8080/file.js', 21, 17]); + expect(stackFrames[2]).toMatchStackFrame(['eval', undefined, 'http://localhost:8080/file.js', 21, 17]); + expect(stackFrames[3]).toMatchStackFrame(['Object.speak', undefined, 'http://localhost:8080/file.js', 21, 17]); + expect(stackFrames[4]).toMatchStackFrame([undefined, undefined, 'http://localhost:8080/file.js', 31, 13]); + }); + it('should parse IE 10 Error stacks', function () { var stackFrames = unit.parse(CapturedExceptions.IE_10); expect(stackFrames).toBeTruthy(); expect(stackFrames.length).toBe(3); - expect(stackFrames[0]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 48, 13]); + expect(stackFrames[0]).toMatchStackFrame(['Anonymous function', undefined, 'http://path/to/file.js', 48, 13]); expect(stackFrames[1]).toMatchStackFrame(['foo', undefined, 'http://path/to/file.js', 46, 9]); expect(stackFrames[2]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 82, 1]); }); @@ -79,11 +128,33 @@ describe('ErrorStackParser', function () { var stackFrames = unit.parse(CapturedExceptions.IE_11); expect(stackFrames).toBeTruthy(); expect(stackFrames.length).toBe(3); - expect(stackFrames[0]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 47, 21]); + expect(stackFrames[0]).toMatchStackFrame(['Anonymous function', undefined, 'http://path/to/file.js', 47, 21]); expect(stackFrames[1]).toMatchStackFrame(['foo', undefined, 'http://path/to/file.js', 45, 13]); expect(stackFrames[2]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 108, 1]); }); + it('should parse nested eval() from Edge', function() { + var stackFrames = unit.parse(CapturedExceptions.EDGE_20_NESTED_EVAL); + expect(stackFrames).toBeTruthy(); + expect(stackFrames.length).toBe(5); + expect(stackFrames[0]).toMatchStackFrame(['baz', undefined, undefined, 1, 18]); + expect(stackFrames[1]).toMatchStackFrame(['foo', undefined, undefined, 2, 90]); + expect(stackFrames[2]).toMatchStackFrame(['eval', undefined, undefined, 4, 18]); + expect(stackFrames[3]).toMatchStackFrame(['speak', undefined, 'http://localhost:8080/file.js', 25, 17]); + expect(stackFrames[4]).toMatchStackFrame(['Global code', undefined, 'http://localhost:8080/file.js', 32, 9]); + }); + + it('should parse nested eval() from V8', function() { + var stackFrames = unit.parse(CapturedExceptions.CHROME_48_NESTED_EVAL); + expect(stackFrames).toBeTruthy(); + expect(stackFrames.length).toBe(5); + expect(stackFrames[0]).toMatchStackFrame(['baz', undefined, 'http://localhost:8080/file.js', 21, 17]); + expect(stackFrames[1]).toMatchStackFrame(['foo', undefined, 'http://localhost:8080/file.js', 21, 17]); + expect(stackFrames[2]).toMatchStackFrame(['eval', undefined, 'http://localhost:8080/file.js', 21, 17]); + expect(stackFrames[3]).toMatchStackFrame(['Object.speak', undefined, 'http://localhost:8080/file.js', 21, 17]); + expect(stackFrames[4]).toMatchStackFrame([undefined, undefined, 'http://localhost:8080/file.js', 31, 13]); + }); + it('should parse Opera 9.27 Error messages', function () { var stackFrames = unit.parse(CapturedExceptions.OPERA_927); expect(stackFrames).toBeTruthy(); diff --git a/spec/fixtures/captured-errors.js b/spec/fixtures/captured-errors.js index e9a7aae..8ab3e6d 100644 --- a/spec/fixtures/captured-errors.js +++ b/spec/fixtures/captured-errors.js @@ -173,6 +173,25 @@ CapturedExceptions.CHROME_36 = { " at HTMLButtonElement.onclick (http://localhost:8080/file.js:107:146)" }; +CapturedExceptions.CHROME_46 = { + message: "Default error", + name: "Error", + stack: "Error: Default error\n" + + " at new CustomError (http://localhost:8080/file.js:41:27)\n" + + " at HTMLButtonElement.onclick (http://localhost:8080/file.js:107:146)" +}; + +CapturedExceptions.CHROME_48_NESTED_EVAL = { + message: "message string", + name: "Error", + stack: "Error: message string\n" + + "at baz (eval at foo (eval at speak (http://localhost:8080/file.js:21:17)), :1:30)\n" + + "at foo (eval at speak (http://localhost:8080/file.js:21:17), :2:96)\n" + + "at eval (eval at speak (http://localhost:8080/file.js:21:17), :4:18)\n" + + "at Object.speak (http://localhost:8080/file.js:21:17)\n" + + "at http://localhost:8080/file.js:31:13\n" +}; + CapturedExceptions.FIREFOX_3 = { fileName: "http://127.0.0.1:8000/js/stacktrace.js", lineNumber: 44, @@ -222,6 +241,29 @@ CapturedExceptions.FIREFOX_31 = { columnNumber: 12 }; +CapturedExceptions.FIREFOX_43_NESTED_EVAL = { + columnNumber: 30, + fileName: "http://localhost:8080/file.js line 25 > eval line 2 > eval", + lineNumber: 1, + message: "message string", + stack: "baz@http://localhost:8080/file.js line 26 > eval line 2 > eval:1:30\n" + + "foo@http://localhost:8080/file.js line 26 > eval:2:96\n" + + "@http://localhost:8080/file.js line 26 > eval:4:18\n" + + "speak@http://localhost:8080/file.js:26:17\n" + + "@http://localhost:8080/file.js:33:9" +}; + +CapturedExceptions.FIREFOX_43_FUNCTION_NAME_WITH_AT_SIGN = { + message: "Dummy error", + name: "Error", + stack: 'obj["@fn"]@Scratchpad/1:10:29\n' + + "@Scratchpad/1:11:1\n" + + "", + fileName: "Scratchpad/1", + lineNumber: 10, + columnNumber: 29 +}; + CapturedExceptions.SAFARI_6 = { message: "'null' is not an object (evaluating 'x.undef')", stack: "@http://path/to/file.js:48\n" + @@ -264,6 +306,18 @@ CapturedExceptions.SAFARI_8_EVAL = { column: 18 }; +CapturedExceptions.SAFARI_9_NESTED_EVAL = { + column: 39, + line: 1, + message: "message string", + stack: "baz\n" + + "foo\n" + + "eval code\n" + + "eval@[native code]\n" + + "speak@http://localhost:8080/file.js:26:21\n" + + "global code@http://localhost:8080/file.js:33:18" +}; + CapturedExceptions.IE_9 = { message: "Unable to get property 'undef' of undefined or null reference", description: "Unable to get property 'undef' of undefined or null reference" @@ -290,13 +344,14 @@ CapturedExceptions.IE_11 = { number: -2146823281 }; -CapturedExceptions.IE_11_EVAL = { - message: "'getExceptionProps' is undefined", - name: "ReferenceError", - stack: "ReferenceError: 'getExceptionProps' is undefined\n" + - " at eval code (eval code:1:1)\n" + - " at foo (http://path/to/file.js:58:17)\n" + - " at bar (http://path/to/file.js:109:1)", - description: "'getExceptionProps' is undefined", - number: -2146823279 +CapturedExceptions.EDGE_20_NESTED_EVAL = { + description: "message string", + message: "message string", + name: "Error", + stack: "Error: message string\n" + + " at baz (eval code:1:18)\n" + + " at foo (eval code:2:90)\n" + + " at eval code (eval code:4:18)\n" + + " at speak (http://localhost:8080/file.js:25:17)\n" + + " at Global code (http://localhost:8080/file.js:32:9)" }; diff --git a/spec/spec-helper.js b/spec/spec-helper.js index 79a2795..15667df 100644 --- a/spec/spec-helper.js +++ b/spec/spec-helper.js @@ -7,31 +7,33 @@ if (!Array.isArray) { } beforeEach(function() { - this.addMatchers({ - toMatchStackFrame: function(expected) { - var actual = this.actual; - var message = ''; - if (actual.getFunctionName() !== expected[0]) { - message += 'expected functionName: ' + actual.getFunctionName() + ' to equal ' + expected[0] + '\n'; - } - if (Array.isArray(actual.getArgs()) && Array.isArray(expected[1])) { - if (actual.getArgs().join() !== expected[1].join()) { - message += 'expected args: ' + actual.getArgs() + ' to equal ' + expected[1] + '\n'; + jasmine.addMatchers({ + toMatchStackFrame: function() { + return { + compare: function(actual, expected) { + var message = ''; + if (actual.getFunctionName() !== expected[0]) { + message += 'expected functionName: ' + actual.getFunctionName() + ' to equal ' + expected[0] + '\n'; + } + if (Array.isArray(actual.getArgs()) && Array.isArray(expected[1])) { + if (actual.getArgs().join() !== expected[1].join()) { + message += 'expected args: ' + actual.getArgs() + ' to equal ' + expected[1] + '\n'; + } + } else if (actual.getArgs() !== expected[1]) { + message += 'expected args: ' + actual.getArgs() + ' to equal ' + expected[1] + '\n'; + } + if (actual.getFileName() !== expected[2]) { + message += 'expected fileName: ' + actual.getFileName() + ' to equal ' + expected[2] + '\n'; + } + if (actual.getLineNumber() !== expected[3]) { + message += 'expected lineNumber: ' + actual.getLineNumber() + ' to equal ' + expected[3] + '\n'; + } + if (actual.getColumnNumber() !== expected[4]) { + message += 'expected columnNumber: ' + actual.getColumnNumber() + ' to equal ' + expected[4] + '\n'; + } + return {pass: message === '', message: message}; } - } else if (actual.getArgs() !== expected[1]) { - message += 'expected args: ' + actual.getArgs() + ' to equal ' + expected[1] + '\n'; - } - if (actual.getFileName() !== expected[2]) { - message += 'expected fileName: ' + actual.getFileName() + ' to equal ' + expected[2] + '\n'; - } - if (actual.getLineNumber() !== expected[3]) { - message += 'expected lineNumber: ' + actual.getLineNumber() + ' to equal ' + expected[3] + '\n'; - } - if (actual.getColumnNumber() !== expected[4]) { - message += 'expected columnNumber: ' + actual.getColumnNumber() + ' to equal ' + expected[4] + '\n'; - } - this.message = function() { return message }; - return message === ''; + }; } }); });