(function (root, factory) { 'use strict'; // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers. if (typeof define === 'function' && define.amd) { define('error-stack-parser', ['stackframe'], factory); } else if (typeof exports === 'object') { module.exports = factory(require('stackframe')); } else { root.ErrorStackParser = factory(root.StackFrame); } }(this, function ErrorStackParser(StackFrame) { 'use strict'; var FIREFOX_SAFARI_STACK_REGEXP = /\S+\:\d+/; var CHROME_IE_STACK_REGEXP = /\s+at /; return { /** * Given an Error object, extract the most information from it. * @param error {Error} * @return Array[StackFrame] */ 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)) { return this.parseFFOrSafari(error); } else { throw new Error('Cannot parse given Error object'); } }, /** * Separate line and column numbers from a URL-like string. * @param urlLike String * @return Array[String] */ extractLocation: function ErrorStackParser$$extractLocation(urlLike) { var locationParts = urlLike.split(':'); var lastNumber = locationParts.pop(); var possibleNumber = locationParts[locationParts.length - 1]; if (!isNaN(parseFloat(possibleNumber)) && isFinite(possibleNumber)) { var lineNumber = locationParts.pop(); return [locationParts.join(':'), lineNumber, lastNumber]; } else { return [locationParts.join(':'), lastNumber, undefined]; } }, parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) { return error.stack.split('\n').slice(1).map(function (line) { var tokens = line.replace(/^\s+/, '').split(/\s+/).slice(1); var locationParts = this.extractLocation(tokens.pop().replace(/[\(\)\s]/g, '')); var functionName = (!tokens[0] || tokens[0] === 'Anonymous') ? undefined : tokens[0]; return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2]); }, 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]); }, this); }, parseOpera: function ErrorStackParser$$parseOpera(e) { if (!e.stacktrace || (e.message.indexOf('\n') > -1 && e.message.split('\n').length > e.stacktrace.split('\n').length)) { return this.parseOpera9(e); } else if (!e.stack) { return this.parseOpera10(e); } else { return this.parseOpera11(e); } }, parseOpera9: function ErrorStackParser$$parseOpera9(e) { var lineRE = /Line (\d+).*script (?:in )?(\S+)/i; var lines = e.message.split('\n'); var result = []; for (var i = 2, len = lines.length; i < len; i += 2) { var match = lineRE.exec(lines[i]); if (match) { result.push(new StackFrame(undefined, undefined, match[2], match[1])); } } return result; }, parseOpera10: function ErrorStackParser$$parseOpera10(e) { var lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i; var lines = e.stacktrace.split('\n'); var result = []; 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])); } } return result; }, // 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 tokens = line.split('@'); var locationParts = this.extractLocation(tokens.pop()); var functionCall = (tokens.shift() || ''); var functionName = functionCall .replace(//, '$2') .replace(/\([^\)]*\)/g, '') || undefined; var argsRaw; 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]); }, this); } }; }));