diff --git a/.editorconfig b/.editorconfig index 93a20e5..367dc4e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,13 +10,20 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[*.js] +[*.{js,json}] indent_style = space indent_size = 4 -[*.json] +[package.json] +indent_size = 2 + +[.{jshintrc,jscsrc}] indent_style = space indent_size = 4 +[*.{yml,yaml}] +indent_style = space +indent_size = 2 + [*.md] trim_trailing_whitespace = false 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/.jscsrc b/.jscsrc new file mode 100644 index 0000000..21f8767 --- /dev/null +++ b/.jscsrc @@ -0,0 +1,28 @@ +{ + "preset": "google", + "fileExtensions": [ + ".js" + ], + "requireSemicolons": true, + "requireParenthesesAroundIIFE": true, + "maximumLineLength": 120, + "validateLineBreaks": "LF", + "validateIndentation": 4, + "disallowTrailingComma": true, + "disallowSpacesInsideObjectBrackets": null, + "disallowImplicitTypeConversion": [ + "string" + ], + "jsDoc": { + "checkAnnotations": "closurecompiler", + "checkParamNames": true, + "requireParamTypes": true, + "checkRedundantParams": true, + "checkReturnTypes": true, + "checkRedundantReturns": true, + "requireReturnTypes": true, + "checkTypes": "capitalizedNativeCase", + "checkRedundantAccess": true, + "requireNewlineAfterDescription": true + } +} 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..851d043 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,19 @@ 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_install: +- export CHROME_BIN=chromium-browser +- export DISPLAY=:99.0 +- sh -e /etc/init.d/xvfb start +before_script: +- npm install +script: +- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then gulp ci; else gulp test-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..fdaa3ea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ error-stack-parser.js - Extract meaning from JS Errors =============== -[![Build Status](https://travis-ci.org/stacktracejs/error-stack-parser.svg?branch=master)](https://travis-ci.org/stacktracejs/error-stack-parser) [![Coverage Status](https://img.shields.io/coveralls/stacktracejs/error-stack-parser.svg)](https://coveralls.io/r/stacktracejs/error-stack-parser) [![Code Climate](https://codeclimate.com/github/stacktracejs/error-stack-parser/badges/gpa.svg)](https://codeclimate.com/github/stacktracejs/error-stack-parser) +[![Build Status](https://travis-ci.org/stacktracejs/error-stack-parser.svg?branch=master)](https://travis-ci.org/stacktracejs/error-stack-parser) [![Coverage Status](https://img.shields.io/coveralls/stacktracejs/error-stack-parser.svg)](https://coveralls.io/r/stacktracejs/error-stack-parser) [![GitHub license](https://img.shields.io/github/license/stacktracejs/error-stack-parser.svg)](http://unlicense.org) Simple, cross-browser [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) parser. This library parses and extracts function names, URLs, line numbers, and column numbers from the given Error's `stack` as @@ -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,17 +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)! -## License -This project is licensed to the [Public Domain](http://unlicense.org) 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..990611b 100644 --- a/dist/error-stack-parser.js +++ b/dist/error-stack-parser.js @@ -1,4 +1,4 @@ -(function (root, factory) { +(function(root, factory) { 'use strict'; // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers. @@ -14,20 +14,48 @@ '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 { /** * Given an Error object, extract the most information from it. - * @param error {Error} - * @return Array[StackFrame] + * + * @param {Error} error object + * @return {Array} of StackFrames */ parse: function ErrorStackParser$$parse(error) { if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') { 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'); @@ -36,8 +64,9 @@ /** * Separate line and column numbers from a URL-like string. - * @param urlLike String - * @return Array[String] + * + * @param {String} urlLike + * @return {Array} 3-tuple of URL, Line Number, and Column Number */ extractLocation: function ErrorStackParser$$extractLocation(urlLike) { // Fail-fast but return locations like "(native)" @@ -57,24 +86,49 @@ }, 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 = ['eval', ''].indexOf(locationParts[0]) > -1 ? 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.join('@') || undefined; + return new StackFrame(functionName, + undefined, + locationParts[0], + locationParts[1], + locationParts[2], + line); + } }, this); }, @@ -112,7 +166,16 @@ 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( + match[3] || undefined, + undefined, + match[2], + match[1], + undefined, + lines[i] + ) + ); } } @@ -121,10 +184,11 @@ // Opera 10.65+ Error.stack very similar to FF/Safari parseOpera11: function ErrorStackParser$$parseOpera11(error) { - return error.stack.split('\n').filter(function (line) { - return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && - !line.match(/^Error created at/); - }, this).map(function (line) { + var filtered = _filter(error.stack.split('\n'), function(line) { + return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/); + }, this); + + return _map(filtered, function(line) { var tokens = line.split('@'); var locationParts = this.extractLocation(tokens.pop()); var functionCall = (tokens.shift() || ''); @@ -135,8 +199,15 @@ if (functionCall.match(/\(([^\)]*)\)/)) { 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); + var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ? + undefined : argsRaw.split(','); + return new StackFrame( + functionName, + args, + locationParts[0], + locationParts[1], + locationParts[2], + line); }, this); } }; diff --git a/dist/error-stack-parser.min.js b/dist/error-stack-parser.min.js index 9f9193d..bc12bed 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",""].indexOf(n[0])>-1?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.join("@")||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..26f8c9a 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":"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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 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","e","message","parseOpera9","parseOpera11","parseOpera10","lineRE","lines","result","len","exec","argsRaw","functionCall","shift"],"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 *\n * @param {Error} error object\n * @return {Array} of StackFrames\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 *\n * @param {String} urlLike\n * @return {Array} 3-tuple of URL, Line Number, and Column Number\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 = ['eval', ''].indexOf(locationParts[0]) > -1 ? 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.join('@') || undefined;\n return new StackFrame(functionName,\n undefined,\n locationParts[0],\n locationParts[1],\n locationParts[2],\n 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(\n new StackFrame(\n match[3] || undefined,\n undefined,\n match[2],\n match[1],\n undefined,\n lines[i]\n )\n );\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) && !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]') ?\n undefined : argsRaw.split(',');\n return new StackFrame(\n functionName,\n args,\n locationParts[0],\n locationParts[1],\n locationParts[2],\n line);\n }, this);\n }\n };\n}));\n\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/error-stack-parser.d.ts b/error-stack-parser.d.ts new file mode 100644 index 0000000..ad722b0 --- /dev/null +++ b/error-stack-parser.d.ts @@ -0,0 +1,26 @@ +// Type definitions for ErrorStackParser v1.3.3 +// Project: https://github.com/stacktracejs/error-stack-parser +// Definitions by: Eric Wendelin +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +declare module ErrorStackParser { + export interface StackFrame { + constructor(functionName: string, args: any, fileName: string, lineNumber: number, columnNumber: number, source: string): StackFrame; + + functionName?: string; + args?: any[]; + fileName?: string; + lineNumber?: number; + columnNumber?: number; + source?: string; + toString(): string; + } + + /** + * Given an Error object, extract the most information from it. + * + * @param {Error} error object + * @return {Array} of StackFrames + */ + export function parse(error: Error): StackFrame[]; +} diff --git a/error-stack-parser.js b/error-stack-parser.js index a4b64dd..990611b 100644 --- a/error-stack-parser.js +++ b/error-stack-parser.js @@ -1,4 +1,4 @@ -(function (root, factory) { +(function(root, factory) { 'use strict'; // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers. @@ -14,20 +14,48 @@ '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 { /** * Given an Error object, extract the most information from it. - * @param error {Error} - * @return Array[StackFrame] + * + * @param {Error} error object + * @return {Array} of StackFrames */ parse: function ErrorStackParser$$parse(error) { if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') { 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'); @@ -36,8 +64,9 @@ /** * Separate line and column numbers from a URL-like string. - * @param urlLike String - * @return Array[String] + * + * @param {String} urlLike + * @return {Array} 3-tuple of URL, Line Number, and Column Number */ extractLocation: function ErrorStackParser$$extractLocation(urlLike) { // Fail-fast but return locations like "(native)" @@ -57,24 +86,49 @@ }, 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 = ['eval', ''].indexOf(locationParts[0]) > -1 ? 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.join('@') || undefined; + return new StackFrame(functionName, + undefined, + locationParts[0], + locationParts[1], + locationParts[2], + line); + } }, this); }, @@ -112,7 +166,16 @@ 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( + match[3] || undefined, + undefined, + match[2], + match[1], + undefined, + lines[i] + ) + ); } } @@ -121,10 +184,11 @@ // Opera 10.65+ Error.stack very similar to FF/Safari parseOpera11: function ErrorStackParser$$parseOpera11(error) { - return error.stack.split('\n').filter(function (line) { - return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && - !line.match(/^Error created at/); - }, this).map(function (line) { + var filtered = _filter(error.stack.split('\n'), function(line) { + return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/); + }, this); + + return _map(filtered, function(line) { var tokens = line.split('@'); var locationParts = this.extractLocation(tokens.pop()); var functionCall = (tokens.shift() || ''); @@ -135,8 +199,15 @@ if (functionCall.match(/\(([^\)]*)\)/)) { 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); + var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ? + undefined : argsRaw.split(','); + return new StackFrame( + functionName, + args, + locationParts[0], + locationParts[1], + locationParts[2], + line); }, this); } }; diff --git a/gulpfile.js b/gulpfile.js index cb068d7..f7e5390 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_Travis'], + 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..24bb50b 100644 --- a/karma.conf.ci.js +++ b/karma.conf.ci.js @@ -6,79 +6,109 @@ 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' + }, + slFirefox43: { + base: 'SauceLabs', + browserName: 'firefox', + platform: 'Windows 8.1', + version: '43.0' + }, + 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 +134,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..3a0818a 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -9,20 +9,17 @@ 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'], + customLaunchers: { + Chrome_Travis: { + base: 'Chrome', + flags: ['--no-sandbox'] + } + }, browsers: ['PhantomJS2'], singleRun: false }); diff --git a/package.json b/package.json index d4410be..7ee0096 100644 --- a/package.json +++ b/package.json @@ -1,59 +1,65 @@ { - "name": "error-stack-parser", - "description": "Extract meaning from JS Errors", - "maintainers": [ - "Eric Wendelin (http://www.eriwen.com)", - "Victor Homyakov (https://github.com/victor-homyakov)", - "Oliver Salzburg (https://github.com/oliversalzburg)" - ], - "version": "1.2.2", - "license": "SEE LICENSE IN LICENSE", - "keywords": [ - "stacktrace", - "error", - "stack" - ], - "homepage": "http://www.stacktracejs.com", - "dependencies": { - "stackframe": "^0.3.1" - }, - "repository": { - "type": "git", - "url": "git://github.com/stacktracejs/error-stack-parser.git" - }, - "devDependencies": { - "colors": "^1.1.2", - "del": "^1.2.1", - "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", - "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" - }, - "bugs": { - "url": "https://github.com/stacktracejs/error-stack-parser/issues" - }, - "main": "./error-stack-parser.js", - "files": [ - "LICENSE", - "README.md", - "error-stack-parser.js", - "dist/" - ], - "scripts": { - "test": "gulp test" - } + "name": "error-stack-parser", + "description": "Extract meaning from JS Errors", + "maintainers": [ + "Eric Wendelin (http://www.eriwen.com)", + "Victor Homyakov (https://github.com/victor-homyakov)", + "Oliver Salzburg (https://github.com/oliversalzburg)" + ], + "version": "1.3.5", + "license": "Unlicense", + "keywords": [ + "stacktrace", + "error", + "stack", + "parser" + ], + "homepage": "https://www.stacktracejs.com", + "dependencies": { + "stackframe": "^0.3.1" + }, + "repository": { + "type": "git", + "url": "git://github.com/stacktracejs/error-stack-parser.git" + }, + "devDependencies": { + "colors": "^1.1.2", + "del": "^1.2.1", + "gulp": "^3.9.0", + "gulp-concat": "^2.6.0", + "gulp-coveralls": "^0.1.4", + "gulp-jshint": "^2.0.0", + "gulp-sourcemaps": "^1.6.0", + "gulp-uglify": "^1.5.1", + "jasmine": "^2.3.2", + "jasmine-core": "^2.3.4", + "jscs": "^2.9.0", + "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.3.0", + "karma-spec-reporter": "0.0.23", + "run-sequence": "^1.1.5" + }, + "bugs": { + "url": "https://github.com/stacktracejs/error-stack-parser/issues" + }, + "main": "./error-stack-parser.js", + "files": [ + "LICENSE", + "README.md", + "error-stack-parser.js", + "dist/" + ], + "scripts": { + "test": "gulp test", + "prepublish": "gulp dist" + } } 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..6a116a5 100644 --- a/spec/error-stack-parser-spec.js +++ b/spec/error-stack-parser-spec.js @@ -1,14 +1,15 @@ +// jscs:disable maximumLineLength /* global StackFrame: false, ErrorStackParser: false, CapturedExceptions: false */ -describe('ErrorStackParser', function () { - describe('#parse', function () { +describe('ErrorStackParser', function() { + describe('#parse', function() { var unit = ErrorStackParser; - it('should not parse IE 9 Error', function () { - expect(function () { + it('should not parse IE 9 Error', function() { + expect(function() { unit.parse(CapturedExceptions.IE_9); }).toThrow(new Error('Cannot parse given Error object')); }); - it('should parse Safari 6 Error.stack', function () { + it('should parse Safari 6 Error.stack', function() { var stackFrames = unit.parse(CapturedExceptions.SAFARI_6); expect(stackFrames).toBeTruthy(); expect(stackFrames.length).toBe(3); @@ -17,7 +18,7 @@ describe('ErrorStackParser', function () { expect(stackFrames[2]).toMatchStackFrame(['onclick', undefined, 'http://path/to/file.js', 82]); }); - it('should parse Safari 7 Error.stack', function () { + it('should parse Safari 7 Error.stack', function() { var stackFrames = unit.parse(CapturedExceptions.SAFARI_7); expect(stackFrames).toBeTruthy(); expect(stackFrames.length).toBe(3); @@ -26,7 +27,7 @@ describe('ErrorStackParser', function () { expect(stackFrames[2]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 108, 107]); }); - it('should parse Safari 8 Error.stack', function () { + it('should parse Safari 8 Error.stack', function() { var stackFrames = unit.parse(CapturedExceptions.SAFARI_8); expect(stackFrames).toBeTruthy(); expect(stackFrames.length).toBe(3); @@ -35,7 +36,18 @@ describe('ErrorStackParser', function () { expect(stackFrames[2]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 108, 23]); }); - it('should parse Firefox 31 Error.stack', function () { + 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(); expect(stackFrames.length).toBe(2); @@ -43,7 +55,26 @@ describe('ErrorStackParser', function () { expect(stackFrames[1]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 1, 1]); }); - it('should parse V8 Error.stack', function () { + 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(); expect(stackFrames.length).toBe(4); @@ -53,38 +84,79 @@ describe('ErrorStackParser', function () { expect(stackFrames[3]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 24, 4]); }); - it('should parse V8 entries with no location', function () { - var stackFrames = unit.parse({stack: "Error\n at Array.forEach (native)"}); + it('should parse V8 entries with no location', function() { + var stackFrames = unit.parse({stack: 'Error\n at Array.forEach (native)'}); expect(stackFrames.length).toBe(1); expect(stackFrames[0]).toMatchStackFrame(['Array.forEach', undefined, '(native)', undefined, undefined]); }); - it('should parse V8 Error.stack entries with port numbers', function () { + it('should parse V8 Error.stack entries with port numbers', function() { var stackFrames = unit.parse(CapturedExceptions.CHROME_36); expect(stackFrames).toBeTruthy(); expect(stackFrames.length).toBe(2); expect(stackFrames[0]).toMatchStackFrame(['dumpExceptionError', undefined, 'http://localhost:8080/file.js', 41, 27]); }); - it('should parse IE 10 Error stacks', function () { + 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]); }); - it('should parse IE 11 Error stacks', function () { + it('should parse IE 11 Error stacks', 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 Opera 9.27 Error messages', function () { + 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(); expect(stackFrames.length).toBe(3); @@ -93,7 +165,7 @@ describe('ErrorStackParser', function () { expect(stackFrames[2]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 18]); }); - it('should parse Opera 10 Error messages', function () { + it('should parse Opera 10 Error messages', function() { var stackFrames = unit.parse(CapturedExceptions.OPERA_10); expect(stackFrames).toBeTruthy(); expect(stackFrames.length).toBe(7); @@ -106,7 +178,7 @@ describe('ErrorStackParser', function () { expect(stackFrames[6]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 15]); }); - it('should parse Opera 11 Error messages', function () { + it('should parse Opera 11 Error messages', function() { var stackFrames = unit.parse(CapturedExceptions.OPERA_11); expect(stackFrames).toBeTruthy(); expect(stackFrames.length).toBe(4); @@ -116,7 +188,7 @@ describe('ErrorStackParser', function () { expect(stackFrames[3]).toMatchStackFrame([undefined, undefined, 'http://path/to/file.js', 15]); }); - it('should parse Opera 25 Error stacks', function () { + it('should parse Opera 25 Error stacks', function() { var stackFrames = unit.parse(CapturedExceptions.OPERA_25); expect(stackFrames).toBeTruthy(); expect(stackFrames.length).toBe(3); @@ -125,11 +197,11 @@ describe('ErrorStackParser', function () { expect(stackFrames[2]).toMatchStackFrame(['bar', undefined, 'http://path/to/file.js', 108, 168]); }); - it('should handle newlines in Error stack messages', function () { + it('should handle newlines in Error stack messages', function() { var stackFrames = unit.parse({ - stack: "Error: Problem at this\nlocation. Error code:1234\n" + - " at http://path/to/file.js:47:22\n" + - " at foo (http://path/to/file.js:52:15)" + stack: 'Error: Problem at this\nlocation. Error code:1234\n' + + ' at http://path/to/file.js:47:22\n' + + ' at foo (http://path/to/file.js:52:15)' }); expect(stackFrames.length).toBe(2); diff --git a/spec/fixtures/captured-errors.js b/spec/fixtures/captured-errors.js index e9a7aae..e31eced 100644 --- a/spec/fixtures/captured-errors.js +++ b/spec/fixtures/captured-errors.js @@ -1,302 +1,359 @@ +// jscs:disable disallowImplicitTypeConversion +// jscs:disable maximumLineLength /* exported CapturedExceptions */ var CapturedExceptions = {}; CapturedExceptions.OPERA_854 = { - message: "Statement on line 44: Type mismatch (usually a non-object value used where an object is required)\n" + - "Backtrace:\n" + - " Line 44 of linked script http://path/to/file.js\n" + - " this.undef();\n" + - " Line 31 of linked script http://path/to/file.js\n" + - " ex = ex || this.createException();\n" + - " Line 18 of linked script http://path/to/file.js\n" + - " var p = new printStackTrace.implementation(), result = p.run(ex);\n" + - " Line 4 of inline#1 script in http://path/to/file.js\n" + - " printTrace(printStackTrace());\n" + - " Line 7 of inline#1 script in http://path/to/file.js\n" + - " bar(n - 1);\n" + - " Line 11 of inline#1 script in http://path/to/file.js\n" + - " bar(2);\n" + - " Line 15 of inline#1 script in http://path/to/file.js\n" + - " foo();\n" + - "", + message: 'Statement on line 44: Type mismatch (usually a non-object value used where an object is required)\n' + + 'Backtrace:\n' + + ' Line 44 of linked script http://path/to/file.js\n' + + ' this.undef();\n' + + ' Line 31 of linked script http://path/to/file.js\n' + + ' ex = ex || this.createException();\n' + + ' Line 18 of linked script http://path/to/file.js\n' + + ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + + ' Line 4 of inline#1 script in http://path/to/file.js\n' + + ' printTrace(printStackTrace());\n' + + ' Line 7 of inline#1 script in http://path/to/file.js\n' + + ' bar(n - 1);\n' + + ' Line 11 of inline#1 script in http://path/to/file.js\n' + + ' bar(2);\n' + + ' Line 15 of inline#1 script in http://path/to/file.js\n' + + ' foo();\n' + + '', 'opera#sourceloc': 44 }; CapturedExceptions.OPERA_902 = { - message: "Statement on line 44: Type mismatch (usually a non-object value used where an object is required)\n" + - "Backtrace:\n" + - " Line 44 of linked script http://path/to/file.js\n" + - " this.undef();\n" + - " Line 31 of linked script http://path/to/file.js\n" + - " ex = ex || this.createException();\n" + - " Line 18 of linked script http://path/to/file.js\n" + - " var p = new printStackTrace.implementation(), result = p.run(ex);\n" + - " Line 4 of inline#1 script in http://path/to/file.js\n" + - " printTrace(printStackTrace());\n" + - " Line 7 of inline#1 script in http://path/to/file.js\n" + - " bar(n - 1);\n" + - " Line 11 of inline#1 script in http://path/to/file.js\n" + - " bar(2);\n" + - " Line 15 of inline#1 script in http://path/to/file.js\n" + - " foo();\n" + - "", + message: 'Statement on line 44: Type mismatch (usually a non-object value used where an object is required)\n' + + 'Backtrace:\n' + + ' Line 44 of linked script http://path/to/file.js\n' + + ' this.undef();\n' + + ' Line 31 of linked script http://path/to/file.js\n' + + ' ex = ex || this.createException();\n' + + ' Line 18 of linked script http://path/to/file.js\n' + + ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + + ' Line 4 of inline#1 script in http://path/to/file.js\n' + + ' printTrace(printStackTrace());\n' + + ' Line 7 of inline#1 script in http://path/to/file.js\n' + + ' bar(n - 1);\n' + + ' Line 11 of inline#1 script in http://path/to/file.js\n' + + ' bar(2);\n' + + ' Line 15 of inline#1 script in http://path/to/file.js\n' + + ' foo();\n' + + '', 'opera#sourceloc': 44 }; CapturedExceptions.OPERA_927 = { - message: "Statement on line 43: Type mismatch (usually a non-object value used where an object is required)\n" + - "Backtrace:\n" + - " Line 43 of linked script http://path/to/file.js\n" + - " bar(n - 1);\n" + - " Line 31 of linked script http://path/to/file.js\n" + - " bar(2);\n" + - " Line 18 of linked script http://path/to/file.js\n" + - " foo();\n" + - "", + message: 'Statement on line 43: Type mismatch (usually a non-object value used where an object is required)\n' + + 'Backtrace:\n' + + ' Line 43 of linked script http://path/to/file.js\n' + + ' bar(n - 1);\n' + + ' Line 31 of linked script http://path/to/file.js\n' + + ' bar(2);\n' + + ' Line 18 of linked script http://path/to/file.js\n' + + ' foo();\n' + + '', 'opera#sourceloc': 43 }; CapturedExceptions.OPERA_964 = { - message: "Statement on line 42: Type mismatch (usually non-object value supplied where object required)\n" + - "Backtrace:\n" + - " Line 42 of linked script http://path/to/file.js\n" + - " this.undef();\n" + - " Line 27 of linked script http://path/to/file.js\n" + - " ex = ex || this.createException();\n" + - " Line 18 of linked script http://path/to/file.js: In function printStackTrace\n" + - " var p = new printStackTrace.implementation(), result = p.run(ex);\n" + - " Line 4 of inline#1 script in http://path/to/file.js: In function bar\n" + - " printTrace(printStackTrace());\n" + - " Line 7 of inline#1 script in http://path/to/file.js: In function bar\n" + - " bar(n - 1);\n" + - " Line 11 of inline#1 script in http://path/to/file.js: In function foo\n" + - " bar(2);\n" + - " Line 15 of inline#1 script in http://path/to/file.js\n" + - " foo();\n" + - "", + message: 'Statement on line 42: Type mismatch (usually non-object value supplied where object required)\n' + + 'Backtrace:\n' + + ' Line 42 of linked script http://path/to/file.js\n' + + ' this.undef();\n' + + ' Line 27 of linked script http://path/to/file.js\n' + + ' ex = ex || this.createException();\n' + + ' Line 18 of linked script http://path/to/file.js: In function printStackTrace\n' + + ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + + ' Line 4 of inline#1 script in http://path/to/file.js: In function bar\n' + + ' printTrace(printStackTrace());\n' + + ' Line 7 of inline#1 script in http://path/to/file.js: In function bar\n' + + ' bar(n - 1);\n' + + ' Line 11 of inline#1 script in http://path/to/file.js: In function foo\n' + + ' bar(2);\n' + + ' Line 15 of inline#1 script in http://path/to/file.js\n' + + ' foo();\n' + + '', 'opera#sourceloc': 42, - stacktrace: " ... Line 27 of linked script http://path/to/file.js\n" + - " ex = ex || this.createException();\n" + - " Line 18 of linked script http://path/to/file.js: In function printStackTrace\n" + - " var p = new printStackTrace.implementation(), result = p.run(ex);\n" + - " Line 4 of inline#1 script in http://path/to/file.js: In function bar\n" + - " printTrace(printStackTrace());\n" + - " Line 7 of inline#1 script in http://path/to/file.js: In function bar\n" + - " bar(n - 1);\n" + - " Line 11 of inline#1 script in http://path/to/file.js: In function foo\n" + - " bar(2);\n" + - " Line 15 of inline#1 script in http://path/to/file.js\n" + - " foo();\n" + - "" + stacktrace: ' ... Line 27 of linked script http://path/to/file.js\n' + + ' ex = ex || this.createException();\n' + + ' Line 18 of linked script http://path/to/file.js: In function printStackTrace\n' + + ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + + ' Line 4 of inline#1 script in http://path/to/file.js: In function bar\n' + + ' printTrace(printStackTrace());\n' + + ' Line 7 of inline#1 script in http://path/to/file.js: In function bar\n' + + ' bar(n - 1);\n' + + ' Line 11 of inline#1 script in http://path/to/file.js: In function foo\n' + + ' bar(2);\n' + + ' Line 15 of inline#1 script in http://path/to/file.js\n' + + ' foo();\n' + + '' }; CapturedExceptions.OPERA_10 = { - message: "Statement on line 42: Type mismatch (usually non-object value supplied where object required)", + message: 'Statement on line 42: Type mismatch (usually non-object value supplied where object required)', 'opera#sourceloc': 42, - stacktrace: " Line 42 of linked script http://path/to/file.js\n" + - " this.undef();\n" + - " Line 27 of linked script http://path/to/file.js\n" + - " ex = ex || this.createException();\n" + - " Line 18 of linked script http://path/to/file.js: In function printStackTrace\n" + - " var p = new printStackTrace.implementation(), result = p.run(ex);\n" + - " Line 4 of inline#1 script in http://path/to/file.js: In function bar\n" + - " printTrace(printStackTrace());\n" + - " Line 7 of inline#1 script in http://path/to/file.js: In function bar\n" + - " bar(n - 1);\n" + - " Line 11 of inline#1 script in http://path/to/file.js: In function foo\n" + - " bar(2);\n" + - " Line 15 of inline#1 script in http://path/to/file.js\n" + - " foo();\n" + - "" + stacktrace: ' Line 42 of linked script http://path/to/file.js\n' + + ' this.undef();\n' + + ' Line 27 of linked script http://path/to/file.js\n' + + ' ex = ex || this.createException();\n' + + ' Line 18 of linked script http://path/to/file.js: In function printStackTrace\n' + + ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + + ' Line 4 of inline#1 script in http://path/to/file.js: In function bar\n' + + ' printTrace(printStackTrace());\n' + + ' Line 7 of inline#1 script in http://path/to/file.js: In function bar\n' + + ' bar(n - 1);\n' + + ' Line 11 of inline#1 script in http://path/to/file.js: In function foo\n' + + ' bar(2);\n' + + ' Line 15 of inline#1 script in http://path/to/file.js\n' + + ' foo();\n' + + '' }; CapturedExceptions.OPERA_11 = { - message: "'this.undef' is not a function", - stack: "([arguments not available])@http://path/to/file.js:27\n" + - "bar([arguments not available])@http://domain.com:1234/path/to/file.js:18\n" + - "foo([arguments not available])@http://domain.com:1234/path/to/file.js:11\n" + - "@http://path/to/file.js:15\n" + - "Error created at @http://path/to/file.js:15", - stacktrace: "Error thrown at line 42, column 12 in () in http://path/to/file.js:\n" + - " this.undef();\n" + - "called from line 27, column 8 in (ex) in http://path/to/file.js:\n" + - " ex = ex || this.createException();\n" + - "called from line 18, column 4 in printStackTrace(options) in http://path/to/file.js:\n" + - " var p = new printStackTrace.implementation(), result = p.run(ex);\n" + - "called from line 4, column 5 in bar(n) in http://path/to/file.js:\n" + - " printTrace(printStackTrace());\n" + - "called from line 7, column 4 in bar(n) in http://path/to/file.js:\n" + - " bar(n - 1);\n" + - "called from line 11, column 4 in foo() in http://path/to/file.js:\n" + - " bar(2);\n" + - "called from line 15, column 3 in http://path/to/file.js:\n" + - " foo();" + message: '\'this.undef\' is not a function', + stack: '([arguments not available])@http://path/to/file.js:27\n' + + 'bar([arguments not available])@http://domain.com:1234/path/to/file.js:18\n' + + 'foo([arguments not available])@http://domain.com:1234/path/to/file.js:11\n' + + '@http://path/to/file.js:15\n' + + 'Error created at @http://path/to/file.js:15', + stacktrace: 'Error thrown at line 42, column 12 in () in http://path/to/file.js:\n' + + ' this.undef();\n' + + 'called from line 27, column 8 in (ex) in http://path/to/file.js:\n' + + ' ex = ex || this.createException();\n' + + 'called from line 18, column 4 in printStackTrace(options) in http://path/to/file.js:\n' + + ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + + 'called from line 4, column 5 in bar(n) in http://path/to/file.js:\n' + + ' printTrace(printStackTrace());\n' + + 'called from line 7, column 4 in bar(n) in http://path/to/file.js:\n' + + ' bar(n - 1);\n' + + 'called from line 11, column 4 in foo() in http://path/to/file.js:\n' + + ' bar(2);\n' + + 'called from line 15, column 3 in http://path/to/file.js:\n' + + ' foo();' }; CapturedExceptions.OPERA_12 = { - message: "Cannot convert 'x' to object", - stack: "([arguments not available])@http://localhost:8000/ExceptionLab.html:48\n" + - "dumpException3([arguments not available])@http://localhost:8000/ExceptionLab.html:46\n" + - "([arguments not available])@http://localhost:8000/ExceptionLab.html:1", - stacktrace: "Error thrown at line 48, column 12 in (x) in http://localhost:8000/ExceptionLab.html:\n" + - " x.undef();\n" + - "called from line 46, column 8 in dumpException3() in http://localhost:8000/ExceptionLab.html:\n" + - " dumpException((function(x) {\n" + - "called from line 1, column 0 in (event) in http://localhost:8000/ExceptionLab.html:\n" + - " dumpException3();" + message: 'Cannot convert \'x\' to object', + stack: '([arguments not available])@http://localhost:8000/ExceptionLab.html:48\n' + + 'dumpException3([arguments not available])@http://localhost:8000/ExceptionLab.html:46\n' + + '([arguments not available])@http://localhost:8000/ExceptionLab.html:1', + stacktrace: 'Error thrown at line 48, column 12 in (x) in http://localhost:8000/ExceptionLab.html:\n' + + ' x.undef();\n' + + 'called from line 46, column 8 in dumpException3() in http://localhost:8000/ExceptionLab.html:\n' + + ' dumpException((function(x) {\n' + + 'called from line 1, column 0 in (event) in http://localhost:8000/ExceptionLab.html:\n' + + ' dumpException3();' }; CapturedExceptions.OPERA_25 = { - message: "Cannot read property 'undef' of null", - name: "TypeError", - stack: "TypeError: Cannot read property 'undef' of null\n" + - " at http://path/to/file.js:47:22\n" + - " at foo (http://path/to/file.js:52:15)\n" + - " at bar (http://path/to/file.js:108:168)" + message: 'Cannot read property \'undef\' of null', + name: 'TypeError', + stack: 'TypeError: Cannot read property \'undef\' of null\n' + + ' at http://path/to/file.js:47:22\n' + + ' at foo (http://path/to/file.js:52:15)\n' + + ' at bar (http://path/to/file.js:108:168)' }; CapturedExceptions.CHROME_15 = { - 'arguments': ["undef"], - message: "Object # has no method 'undef'", - stack: "TypeError: Object # has no method 'undef'\n" + - " at bar (http://path/to/file.js:13:17)\n" + - " at bar (http://path/to/file.js:16:5)\n" + - " at foo (http://path/to/file.js:20:5)\n" + - " at http://path/to/file.js:24:4" + 'arguments': ['undef'], + message: 'Object # has no method \'undef\'', + stack: 'TypeError: Object # has no method \'undef\'\n' + + ' at bar (http://path/to/file.js:13:17)\n' + + ' at bar (http://path/to/file.js:16:5)\n' + + ' at foo (http://path/to/file.js:20:5)\n' + + ' at http://path/to/file.js:24:4' }; CapturedExceptions.CHROME_36 = { - message: "Default error", - name: "Error", - stack: "Error: Default error\n" + - " at dumpExceptionError (http://localhost:8080/file.js:41:27)\n" + - " at HTMLButtonElement.onclick (http://localhost:8080/file.js:107:146)" + message: 'Default error', + name: 'Error', + stack: 'Error: Default error\n' + + ' at dumpExceptionError (http://localhost:8080/file.js:41:27)\n' + + ' 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", + fileName: 'http://127.0.0.1:8000/js/stacktrace.js', lineNumber: 44, - message: "this.undef is not a function", - name: "TypeError", - stack: "()@http://127.0.0.1:8000/js/stacktrace.js:44\n" + - "(null)@http://127.0.0.1:8000/js/stacktrace.js:31\n" + - "printStackTrace()@http://127.0.0.1:8000/js/stacktrace.js:18\n" + - "bar(1)@http://127.0.0.1:8000/js/file.js:13\n" + - "bar(2)@http://127.0.0.1:8000/js/file.js:16\n" + - "foo()@http://127.0.0.1:8000/js/file.js:20\n" + - "@http://127.0.0.1:8000/js/file.js:24\n" + - "" + message: 'this.undef is not a function', + name: 'TypeError', + stack: '()@http://127.0.0.1:8000/js/stacktrace.js:44\n' + + '(null)@http://127.0.0.1:8000/js/stacktrace.js:31\n' + + 'printStackTrace()@http://127.0.0.1:8000/js/stacktrace.js:18\n' + + 'bar(1)@http://127.0.0.1:8000/js/file.js:13\n' + + 'bar(2)@http://127.0.0.1:8000/js/file.js:16\n' + + 'foo()@http://127.0.0.1:8000/js/file.js:20\n' + + '@http://127.0.0.1:8000/js/file.js:24\n' + + '' }; CapturedExceptions.FIREFOX_7 = { - fileName: "file:///G:/js/stacktrace.js", + fileName: 'file:///G:/js/stacktrace.js', lineNumber: 44, - stack: "()@file:///G:/js/stacktrace.js:44\n" + - "(null)@file:///G:/js/stacktrace.js:31\n" + - "printStackTrace()@file:///G:/js/stacktrace.js:18\n" + - "bar(1)@file:///G:/js/file.js:13\n" + - "bar(2)@file:///G:/js/file.js:16\n" + - "foo()@file:///G:/js/file.js:20\n" + - "@file:///G:/js/file.js:24\n" + - "" + stack: '()@file:///G:/js/stacktrace.js:44\n' + + '(null)@file:///G:/js/stacktrace.js:31\n' + + 'printStackTrace()@file:///G:/js/stacktrace.js:18\n' + + 'bar(1)@file:///G:/js/file.js:13\n' + + 'bar(2)@file:///G:/js/file.js:16\n' + + 'foo()@file:///G:/js/file.js:20\n' + + '@file:///G:/js/file.js:24\n' + + '' }; CapturedExceptions.FIREFOX_14 = { - message: "x is null", - stack: "@http://path/to/file.js:48\n" + - "dumpException3@http://path/to/file.js:52\n" + - "onclick@http://path/to/file.js:1\n" + - "", - fileName: "http://path/to/file.js", + message: 'x is null', + stack: '@http://path/to/file.js:48\n' + + 'dumpException3@http://path/to/file.js:52\n' + + 'onclick@http://path/to/file.js:1\n' + + '', + fileName: 'http://path/to/file.js', lineNumber: 48 }; CapturedExceptions.FIREFOX_31 = { - message: "Default error", - name: "Error", - stack: "foo@http://path/to/file.js:41:13\n" + - "bar@http://path/to/file.js:1:1\n" + - "", - fileName: "http://path/to/file.js", + message: 'Default error', + name: 'Error', + stack: 'foo@http://path/to/file.js:41:13\n' + + 'bar@http://path/to/file.js:1:1\n' + + '', + fileName: 'http://path/to/file.js', lineNumber: 41, 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" + - "dumpException3@http://path/to/file.js:52\n" + - "onclick@http://path/to/file.js:82\n" + - "[native code]", + message: '\'null\' is not an object (evaluating \'x.undef\')', + stack: '@http://path/to/file.js:48\n' + + 'dumpException3@http://path/to/file.js:52\n' + + 'onclick@http://path/to/file.js:82\n' + + '[native code]', line: 48, - sourceURL: "http://path/to/file.js" + sourceURL: 'http://path/to/file.js' }; CapturedExceptions.SAFARI_7 = { - message: "'null' is not an object (evaluating 'x.undef')", - name: "TypeError", - stack: "http://path/to/file.js:48:22\n" + - "foo@http://path/to/file.js:52:15\n" + - "bar@http://path/to/file.js:108:107", + message: '\'null\' is not an object (evaluating \'x.undef\')', + name: 'TypeError', + stack: 'http://path/to/file.js:48:22\n' + + 'foo@http://path/to/file.js:52:15\n' + + 'bar@http://path/to/file.js:108:107', line: 47, - sourceURL: "http://path/to/file.js" + sourceURL: 'http://path/to/file.js' }; CapturedExceptions.SAFARI_8 = { - message: "null is not an object (evaluating 'x.undef')", - name: "TypeError", - stack: "http://path/to/file.js:47:22\n" + - "foo@http://path/to/file.js:52:15\n" + - "bar@http://path/to/file.js:108:23", + message: 'null is not an object (evaluating \'x.undef\')', + name: 'TypeError', + stack: 'http://path/to/file.js:47:22\n' + + 'foo@http://path/to/file.js:52:15\n' + + 'bar@http://path/to/file.js:108:23', line: 47, column: 22, - sourceURL: "http://path/to/file.js" + sourceURL: 'http://path/to/file.js' }; CapturedExceptions.SAFARI_8_EVAL = { - message: "Can't find variable: getExceptionProps", - name: "ReferenceError", - stack: "eval code\n" + - "eval@[native code]\n" + - "foo@http://path/to/file.js:58:21\n" + - "bar@http://path/to/file.js:109:91", + message: 'Can\'t find variable: getExceptionProps', + name: 'ReferenceError', + stack: 'eval code\n' + + 'eval@[native code]\n' + + 'foo@http://path/to/file.js:58:21\n' + + 'bar@http://path/to/file.js:109:91', line: 1, 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" + message: 'Unable to get property \'undef\' of undefined or null reference', + description: 'Unable to get property \'undef\' of undefined or null reference' }; CapturedExceptions.IE_10 = { - message: "Unable to get property 'undef' of undefined or null reference", - stack: "TypeError: Unable to get property 'undef' of undefined or null reference\n" + - " at Anonymous function (http://path/to/file.js:48:13)\n" + - " at foo (http://path/to/file.js:46:9)\n" + - " at bar (http://path/to/file.js:82:1)", - description: "Unable to get property 'undef' of undefined or null reference", + message: 'Unable to get property \'undef\' of undefined or null reference', + stack: 'TypeError: Unable to get property \'undef\' of undefined or null reference\n' + + ' at Anonymous function (http://path/to/file.js:48:13)\n' + + ' at foo (http://path/to/file.js:46:9)\n' + + ' at bar (http://path/to/file.js:82:1)', + description: 'Unable to get property \'undef\' of undefined or null reference', number: -2146823281 }; CapturedExceptions.IE_11 = { - message: "Unable to get property 'undef' of undefined or null reference", - name: "TypeError", - stack: "TypeError: Unable to get property 'undef' of undefined or null reference\n" + - " at Anonymous function (http://path/to/file.js:47:21)\n" + - " at foo (http://path/to/file.js:45:13)\n" + - " at bar (http://path/to/file.js:108:1)", - description: "Unable to get property 'undef' of undefined or null reference", + message: 'Unable to get property \'undef\' of undefined or null reference', + name: 'TypeError', + stack: 'TypeError: Unable to get property \'undef\' of undefined or null reference\n' + + ' at Anonymous function (http://path/to/file.js:47:21)\n' + + ' at foo (http://path/to/file.js:45:13)\n' + + ' at bar (http://path/to/file.js:108:1)', + description: 'Unable to get property \'undef\' of undefined or null reference', 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 === ''; + }; } }); });