Merge branch 'QA_4_6'
This commit is contained in:
commit
e3a3f35db3
@ -1,10 +1,12 @@
|
||||
/*
|
||||
TraceKit - Cross brower stack traces - github.com/occ/TraceKit
|
||||
MIT license
|
||||
*/
|
||||
|
||||
;(function(window, undefined) {
|
||||
|
||||
/**
|
||||
* https://github.com/csnover/TraceKit
|
||||
* @license MIT
|
||||
* @namespace TraceKit
|
||||
*/
|
||||
(function(window, undefined) {
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
var TraceKit = {};
|
||||
var _oldTraceKit = window.TraceKit;
|
||||
@ -13,25 +15,34 @@ var _oldTraceKit = window.TraceKit;
|
||||
var _slice = [].slice;
|
||||
var UNKNOWN_FUNCTION = '?';
|
||||
|
||||
|
||||
/**
|
||||
* _has, a better form of hasOwnProperty
|
||||
* Example: _has(MainHostObject, property) === true/false
|
||||
* A better form of hasOwnProperty<br/>
|
||||
* Example: `_has(MainHostObject, property) === true/false`
|
||||
*
|
||||
* @param {Object} host object to check property
|
||||
* @param {Object} object to check property
|
||||
* @param {string} key to check
|
||||
* @return {Boolean} true if the object has the key and it is not inherited
|
||||
*/
|
||||
function _has(object, key) {
|
||||
return Object.prototype.hasOwnProperty.call(object, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the parameter is undefined<br/>
|
||||
* Example: `_isUndefined(val) === true/false`
|
||||
*
|
||||
* @param {*} what Value to check
|
||||
* @return {Boolean} true if undefined and false otherwise
|
||||
*/
|
||||
function _isUndefined(what) {
|
||||
return typeof what === 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* TraceKit.noConflict: Export TraceKit out to another variable
|
||||
* Example: var TK = TraceKit.noConflict()
|
||||
* Export TraceKit out to another variable<br/>
|
||||
* Example: `var TK = TraceKit.noConflict()`
|
||||
* @return {Object} The TraceKit object
|
||||
* @memberof TraceKit
|
||||
*/
|
||||
TraceKit.noConflict = function noConflict() {
|
||||
window.TraceKit = _oldTraceKit;
|
||||
@ -39,11 +50,12 @@ TraceKit.noConflict = function noConflict() {
|
||||
};
|
||||
|
||||
/**
|
||||
* TraceKit.wrap: Wrap any function in a TraceKit reporter
|
||||
* Example: func = TraceKit.wrap(func);
|
||||
* Wrap any function in a TraceKit reporter<br/>
|
||||
* Example: `func = TraceKit.wrap(func);`
|
||||
*
|
||||
* @param {Function} func Function to be wrapped
|
||||
* @return {Function} The wrapped func
|
||||
* @memberof TraceKit
|
||||
*/
|
||||
TraceKit.wrap = function traceKitWrapper(func) {
|
||||
function wrapped() {
|
||||
@ -58,23 +70,25 @@ TraceKit.wrap = function traceKitWrapper(func) {
|
||||
};
|
||||
|
||||
/**
|
||||
* TraceKit.report: cross-browser processing of unhandled exceptions
|
||||
* Cross-browser processing of unhandled exceptions
|
||||
*
|
||||
* Syntax:
|
||||
* ```js
|
||||
* TraceKit.report.subscribe(function(stackInfo) { ... })
|
||||
* TraceKit.report.unsubscribe(function(stackInfo) { ... })
|
||||
* TraceKit.report(exception)
|
||||
* try { ...code... } catch(ex) { TraceKit.report(ex); }
|
||||
* ```
|
||||
*
|
||||
* Supports:
|
||||
* - Firefox: full stack trace with line numbers, plus column number
|
||||
* on top frame; column number is not guaranteed
|
||||
* - Opera: full stack trace with line and column numbers
|
||||
* - Chrome: full stack trace with line and column numbers
|
||||
* - Safari: line and column number for the top frame only; some frames
|
||||
* may be missing, and column number is not guaranteed
|
||||
* - IE: line and column number for the top frame only; some frames
|
||||
* may be missing, and column number is not guaranteed
|
||||
* on top frame; column number is not guaranteed
|
||||
* - Opera: full stack trace with line and column numbers
|
||||
* - Chrome: full stack trace with line and column numbers
|
||||
* - Safari: line and column number for the top frame only; some frames
|
||||
* may be missing, and column number is not guaranteed
|
||||
* - IE: line and column number for the top frame only; some frames
|
||||
* may be missing, and column number is not guaranteed
|
||||
*
|
||||
* In theory, TraceKit should work on all of the following versions:
|
||||
* - IE5.5+ (only 8.0 tested)
|
||||
@ -93,17 +107,22 @@ TraceKit.wrap = function traceKitWrapper(func) {
|
||||
* If the exception does not reach the top of the browser, you will only
|
||||
* get a stack trace from the point where TraceKit.report was called.
|
||||
*
|
||||
* Handlers receive a stackInfo object as described in the
|
||||
* Handlers receive a TraceKit.StackTrace object as described in the
|
||||
* TraceKit.computeStackTrace docs.
|
||||
*
|
||||
* @memberof TraceKit
|
||||
* @namespace
|
||||
*/
|
||||
TraceKit.report = (function reportModuleWrapper() {
|
||||
var handlers = [],
|
||||
lastArgs = null,
|
||||
lastException = null,
|
||||
lastExceptionStack = null;
|
||||
|
||||
/**
|
||||
* Add a crash handler.
|
||||
* @param {Function} handler
|
||||
* @memberof TraceKit.report
|
||||
*/
|
||||
function subscribe(handler) {
|
||||
installGlobalHandler();
|
||||
@ -113,6 +132,7 @@ TraceKit.report = (function reportModuleWrapper() {
|
||||
/**
|
||||
* Remove a crash handler.
|
||||
* @param {Function} handler
|
||||
* @memberof TraceKit.report
|
||||
*/
|
||||
function unsubscribe(handler) {
|
||||
for (var i = handlers.length - 1; i >= 0; --i) {
|
||||
@ -124,11 +144,14 @@ TraceKit.report = (function reportModuleWrapper() {
|
||||
|
||||
/**
|
||||
* Dispatch stack information to all handlers.
|
||||
* @param {Object.<string, *>} stack
|
||||
* @param {TraceKit.StackTrace} stack
|
||||
* @param {boolean} isWindowError Is this a top-level window error?
|
||||
* @memberof TraceKit.report
|
||||
* @throws An exception if an error occurs while calling an handler.
|
||||
*/
|
||||
function notifyHandlers(stack, windowError) {
|
||||
function notifyHandlers(stack, isWindowError) {
|
||||
var exception = null;
|
||||
if (windowError && !TraceKit.collectWindowErrors) {
|
||||
if (isWindowError && !TraceKit.collectWindowErrors) {
|
||||
return;
|
||||
}
|
||||
for (var i in handlers) {
|
||||
@ -153,34 +176,36 @@ TraceKit.report = (function reportModuleWrapper() {
|
||||
* Supported by Gecko and IE.
|
||||
* @param {string} message Error message.
|
||||
* @param {string} url URL of script that generated the exception.
|
||||
* @param {(number|string)} lineNo The line number at which the error
|
||||
* occurred.
|
||||
* @param {(number|string)} lineNo The line number at which the error occurred.
|
||||
* @param {(number|string)=} columnNo The column number at which the error occurred.
|
||||
* @param {Error=} errorObj The actual Error object.
|
||||
* @memberof TraceKit.report
|
||||
*/
|
||||
function traceKitWindowOnError(message, url, lineNo) {
|
||||
function traceKitWindowOnError(message, url, lineNo, columnNo, errorObj) {
|
||||
var stack = null;
|
||||
|
||||
if (lastExceptionStack) {
|
||||
TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(lastExceptionStack, url, lineNo, message);
|
||||
stack = lastExceptionStack;
|
||||
lastExceptionStack = null;
|
||||
lastException = null;
|
||||
processLastException();
|
||||
} else if (errorObj) {
|
||||
stack = TraceKit.computeStackTrace(errorObj);
|
||||
notifyHandlers(stack, true);
|
||||
} else {
|
||||
var location = {
|
||||
'url': url,
|
||||
'line': lineNo
|
||||
'url': url,
|
||||
'line': lineNo,
|
||||
'column': columnNo
|
||||
};
|
||||
location.func = TraceKit.computeStackTrace.guessFunctionName(location.url, location.line);
|
||||
location.context = TraceKit.computeStackTrace.gatherContext(location.url, location.line);
|
||||
stack = {
|
||||
'mode': 'onerror',
|
||||
'message': message,
|
||||
'url': document.location.href,
|
||||
'stack': [location],
|
||||
'useragent': navigator.userAgent
|
||||
'mode': 'onerror',
|
||||
'message': message,
|
||||
'stack': [location]
|
||||
};
|
||||
}
|
||||
|
||||
notifyHandlers(stack, 'from window.onerror');
|
||||
notifyHandlers(stack, true);
|
||||
}
|
||||
|
||||
if (_oldOnerrorHandler) {
|
||||
return _oldOnerrorHandler.apply(this, arguments);
|
||||
@ -189,8 +214,11 @@ TraceKit.report = (function reportModuleWrapper() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function installGlobalHandler ()
|
||||
{
|
||||
/**
|
||||
* Install a global onerror handler
|
||||
* @memberof TraceKit.report
|
||||
*/
|
||||
function installGlobalHandler () {
|
||||
if (_onErrorHandlerInstalled === true) {
|
||||
return;
|
||||
}
|
||||
@ -199,26 +227,38 @@ TraceKit.report = (function reportModuleWrapper() {
|
||||
_onErrorHandlerInstalled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the most recent exception
|
||||
* @memberof TraceKit.report
|
||||
*/
|
||||
function processLastException() {
|
||||
var _lastExceptionStack = lastExceptionStack,
|
||||
_lastArgs = lastArgs;
|
||||
lastArgs = null;
|
||||
lastExceptionStack = null;
|
||||
lastException = null;
|
||||
notifyHandlers.apply(null, [_lastExceptionStack, false].concat(_lastArgs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an unhandled Error to TraceKit.
|
||||
* @param {Error} ex
|
||||
* @memberof TraceKit.report
|
||||
* @throws An exception if an incomplete stack trace is detected (old IE browsers).
|
||||
*/
|
||||
function report(ex) {
|
||||
var args = _slice.call(arguments, 1);
|
||||
if (lastExceptionStack) {
|
||||
if (lastException === ex) {
|
||||
return; // already caught by an inner catch block, ignore
|
||||
} else {
|
||||
var s = lastExceptionStack;
|
||||
lastExceptionStack = null;
|
||||
lastException = null;
|
||||
notifyHandlers.apply(null, [s, null].concat(args));
|
||||
processLastException();
|
||||
}
|
||||
}
|
||||
|
||||
var stack = TraceKit.computeStackTrace(ex);
|
||||
lastExceptionStack = stack;
|
||||
lastException = ex;
|
||||
lastArgs = _slice.call(arguments, 1);
|
||||
|
||||
// If the stack trace is incomplete, wait for 2 seconds for
|
||||
// slow slow IE to see if onerror occurs or not before reporting
|
||||
@ -226,9 +266,7 @@ TraceKit.report = (function reportModuleWrapper() {
|
||||
// stack trace
|
||||
window.setTimeout(function () {
|
||||
if (lastException === ex) {
|
||||
lastExceptionStack = null;
|
||||
lastException = null;
|
||||
notifyHandlers.apply(null, [stack, null].concat(args));
|
||||
processLastException();
|
||||
}
|
||||
}, (stack.incomplete ? 2000 : 0));
|
||||
|
||||
@ -240,22 +278,36 @@ TraceKit.report = (function reportModuleWrapper() {
|
||||
return report;
|
||||
}());
|
||||
|
||||
/**
|
||||
* An object representing a single stack frame.
|
||||
* @typedef {Object} StackFrame
|
||||
* @property {string} url The JavaScript or HTML file URL.
|
||||
* @property {string} func The function name, or empty for anonymous functions (if guessing did not work).
|
||||
* @property {string[]?} args The arguments passed to the function, if known.
|
||||
* @property {number=} line The line number, if known.
|
||||
* @property {number=} column The column number, if known.
|
||||
* @property {string[]} context An array of source code lines; the middle element corresponds to the correct line#.
|
||||
* @memberof TraceKit
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object representing a JavaScript stack trace.
|
||||
* @typedef {Object} StackTrace
|
||||
* @property {string} name The name of the thrown exception.
|
||||
* @property {string} message The exception error message.
|
||||
* @property {TraceKit.StackFrame[]} stack An array of stack frames.
|
||||
* @property {string} mode 'stack', 'stacktrace', 'multiline', 'callers', 'onerror', or 'failed' -- method used to collect the stack trace.
|
||||
* @memberof TraceKit
|
||||
*/
|
||||
|
||||
/**
|
||||
* TraceKit.computeStackTrace: cross-browser stack traces in JavaScript
|
||||
*
|
||||
* Syntax:
|
||||
* ```js
|
||||
* s = TraceKit.computeStackTrace.ofCaller([depth])
|
||||
* s = TraceKit.computeStackTrace(exception) // consider using TraceKit.report instead (see below)
|
||||
* Returns:
|
||||
* s.name - exception name
|
||||
* s.message - exception message
|
||||
* s.stack[i].url - JavaScript or HTML file URL
|
||||
* s.stack[i].func - function name, or empty for anonymous functions (if guessing did not work)
|
||||
* s.stack[i].args - arguments passed to the function, if known
|
||||
* s.stack[i].line - line number, if known
|
||||
* s.stack[i].column - column number, if known
|
||||
* s.stack[i].context - an array of source code lines; the middle element corresponds to the correct line#
|
||||
* s.mode - 'stack', 'stacktrace', 'multiline', 'callers', 'onerror', or 'failed' -- method used to collect the stack trace
|
||||
* ```
|
||||
*
|
||||
* Supports:
|
||||
* - Firefox: full stack trace with line numbers and unreliable column
|
||||
@ -294,6 +346,7 @@ TraceKit.report = (function reportModuleWrapper() {
|
||||
* inner function that actually caused the exception).
|
||||
*
|
||||
* Tracing example:
|
||||
* ```js
|
||||
* function trace(message) {
|
||||
* var stackInfo = TraceKit.computeStackTrace.ofCaller();
|
||||
* var data = message + "\n";
|
||||
@ -306,6 +359,9 @@ TraceKit.report = (function reportModuleWrapper() {
|
||||
* else
|
||||
* alert(data);
|
||||
* }
|
||||
* ```
|
||||
* @memberof TraceKit
|
||||
* @namespace
|
||||
*/
|
||||
TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
var debug = false,
|
||||
@ -316,20 +372,21 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* to look up anonymous function names.
|
||||
* @param {string} url URL of source code.
|
||||
* @return {string} Source contents.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function loadSource(url) {
|
||||
if (!TraceKit.remoteFetching) { //Only attempt request if remoteFetching is on.
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
function getXHR() {
|
||||
var getXHR = function() {
|
||||
try {
|
||||
return new window.XMLHttpRequest();
|
||||
} catch (e) {
|
||||
// explicitly bubble up the exception if not found
|
||||
return new window.ActiveXObject('Microsoft.XMLHTTP');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var request = getXHR();
|
||||
request.open('GET', url, false);
|
||||
@ -344,13 +401,29 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* Retrieves source code from the source code cache.
|
||||
* @param {string} url URL of source code.
|
||||
* @return {Array.<string>} Source contents.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function getSource(url) {
|
||||
if (typeof url !== 'string') {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!_has(sourceCache, url)) {
|
||||
// URL needs to be able to fetched within the acceptable domain. Otherwise,
|
||||
// cross-domain errors will be triggered.
|
||||
/*
|
||||
Regex matches:
|
||||
0 - Full Url
|
||||
1 - Protocol
|
||||
2 - Domain
|
||||
3 - Port (Useful for internal applications)
|
||||
4 - Path
|
||||
*/
|
||||
var source = '';
|
||||
if (url.indexOf(document.domain) !== -1) {
|
||||
var domain = '';
|
||||
try { domain = window.document.domain; } catch (e) { }
|
||||
var match = /(.*)\:\/\/([^:\/]+)([:\d]*)\/{0,1}([\s\S]*)/.exec(url);
|
||||
if (match && match[2] === domain) {
|
||||
source = loadSource(url);
|
||||
}
|
||||
sourceCache[url] = source ? source.split('\n') : [];
|
||||
@ -366,6 +439,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* @param {string} url URL of source code.
|
||||
* @param {(string|number)} lineNo Line number in source code.
|
||||
* @return {string} The function name, if discoverable.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function guessFunctionName(url, lineNo) {
|
||||
var reFunctionArgNames = /function ([^(]*)\(([^)]*)\)/,
|
||||
@ -402,6 +476,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* @param {(string|number)} line Line number in source code to centre
|
||||
* around for context.
|
||||
* @return {?Array.<string>} Lines of source code.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function gatherContext(url, line) {
|
||||
var source = getSource(url);
|
||||
@ -436,6 +511,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* used inside a regular expression as a string literal.
|
||||
* @param {string} text The string.
|
||||
* @return {string} The escaped string literal.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function escapeRegExp(text) {
|
||||
return text.replace(/[\-\[\]{}()*+?.,\\\^$|#]/g, '\\$&');
|
||||
@ -447,6 +523,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* be matched the same as their literal friends.
|
||||
* @param {string} body The string.
|
||||
* @return {string} The escaped string.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function escapeCodeAsRegExpForMatchingInsideHTML(body) {
|
||||
return escapeRegExp(body).replace('<', '(?:<|<)').replace('>', '(?:>|>)').replace('&', '(?:&|&)').replace('"', '(?:"|")').replace(/\s+/g, '\\s+');
|
||||
@ -458,6 +535,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* @param {Array.<string>} urls A list of URLs to search.
|
||||
* @return {?Object.<string, (string|number)>} An object containing
|
||||
* the url, line, and column number of the defined function.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function findSourceInUrls(re, urls) {
|
||||
var source, m;
|
||||
@ -489,6 +567,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* @param {string} url The URL to search.
|
||||
* @param {(string|number)} line The line number to examine.
|
||||
* @return {?number} The column number.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function findSourceInLine(fragment, url, line) {
|
||||
var source = getSource(url),
|
||||
@ -510,10 +589,15 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* function definition.
|
||||
* @return {?Object.<string, (string|number)>} An object containing
|
||||
* the url, line, and column number of the defined function.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function findSourceByFunctionBody(func) {
|
||||
if (_isUndefined(window && window.document)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var urls = [window.location.href],
|
||||
scripts = document.getElementsByTagName('script'),
|
||||
scripts = window.document.getElementsByTagName('script'),
|
||||
body,
|
||||
code = '' + func,
|
||||
codeRE = /^function(?:\s+([\w$]+))?\s*\(([\w\s,]*)\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/,
|
||||
@ -587,6 +671,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
// ex.message = qq is not defined
|
||||
// ex.fileName = http://...
|
||||
// ex.lineNumber = 59
|
||||
// ex.columnNumber = 69
|
||||
// ex.stack = ...stack trace... (see the example below)
|
||||
// ex.name = ReferenceError
|
||||
//
|
||||
@ -611,15 +696,17 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* Computes stack trace information from the stack property.
|
||||
* Chrome and Gecko use this property.
|
||||
* @param {Error} ex
|
||||
* @return {?Object.<string, *>} Stack trace information.
|
||||
* @return {?TraceKit.StackTrace} Stack trace information.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function computeStackTraceFromStackProp(ex) {
|
||||
if (!ex.stack) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var chrome = /^\s*at (?:((?:\[object object\])?\S+(?: \[as \S+\])?) )?\(?((?:file|http|https):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
|
||||
gecko = /^\s*(\S*)(?:\((.*?)\))?@((?:file|http|https).*?):(\d+)(?::(\d+))?\s*$/i,
|
||||
var chrome = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|webpack|eval).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,
|
||||
gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|\[native).*?)(?::(\d+))?(?::(\d+))?\s*$/i,
|
||||
winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
|
||||
lines = ex.stack.split('\n'),
|
||||
stack = [],
|
||||
parts,
|
||||
@ -627,21 +714,31 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
reference = /^(.*) is undefined$/.exec(ex.message);
|
||||
|
||||
for (var i = 0, j = lines.length; i < j; ++i) {
|
||||
if ((parts = gecko.exec(lines[i]))) {
|
||||
if ((parts = chrome.exec(lines[i]))) {
|
||||
var isNative = parts[2] && parts[2].indexOf('native') !== -1;
|
||||
element = {
|
||||
'url': parts[3],
|
||||
'url': !isNative ? parts[2] : null,
|
||||
'func': parts[1] || UNKNOWN_FUNCTION,
|
||||
'args': parts[2] ? parts[2].split(',') : '',
|
||||
'line': +parts[4],
|
||||
'column': parts[5] ? +parts[5] : null
|
||||
'args': isNative ? [parts[2]] : [],
|
||||
'line': parts[3] ? +parts[3] : null,
|
||||
'column': parts[4] ? +parts[4] : null
|
||||
};
|
||||
} else if ((parts = chrome.exec(lines[i]))) {
|
||||
} else if ( parts = winjs.exec(lines[i]) ) {
|
||||
element = {
|
||||
'url': parts[2],
|
||||
'func': parts[1] || UNKNOWN_FUNCTION,
|
||||
'args': [],
|
||||
'line': +parts[3],
|
||||
'column': parts[4] ? +parts[4] : null
|
||||
};
|
||||
} else if ((parts = gecko.exec(lines[i]))) {
|
||||
element = {
|
||||
'url': parts[3],
|
||||
'func': parts[1] || UNKNOWN_FUNCTION,
|
||||
'args': parts[2] ? parts[2].split(',') : [],
|
||||
'line': parts[4] ? +parts[4] : null,
|
||||
'column': parts[5] ? +parts[5] : null
|
||||
};
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@ -657,51 +754,70 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
stack.push(element);
|
||||
}
|
||||
|
||||
if (stack[0] && stack[0].line && !stack[0].column && reference) {
|
||||
stack[0].column = findSourceInLine(reference[1], stack[0].url, stack[0].line);
|
||||
}
|
||||
|
||||
if (!stack.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (stack[0] && stack[0].line && !stack[0].column && reference) {
|
||||
stack[0].column = findSourceInLine(reference[1], stack[0].url, stack[0].line);
|
||||
} else if (!stack[0].column && !_isUndefined(ex.columnNumber)) {
|
||||
// FireFox uses this awesome columnNumber property for its top frame
|
||||
// Also note, Firefox's column number is 0-based and everything else expects 1-based,
|
||||
// so adding 1
|
||||
stack[0].column = ex.columnNumber + 1;
|
||||
}
|
||||
|
||||
return {
|
||||
'mode': 'stack',
|
||||
'name': ex.name,
|
||||
'message': ex.message,
|
||||
'url': document.location.href,
|
||||
'stack': stack,
|
||||
'useragent': navigator.userAgent
|
||||
'stack': stack
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes stack trace information from the stacktrace property.
|
||||
* Opera 10 uses this property.
|
||||
* Opera 10+ uses this property.
|
||||
* @param {Error} ex
|
||||
* @return {?Object.<string, *>} Stack trace information.
|
||||
* @return {?TraceKit.StackTrace} Stack trace information.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function computeStackTraceFromStacktraceProp(ex) {
|
||||
// Access and store the stacktrace property before doing ANYTHING
|
||||
// else to it because Opera is not very good at providing it
|
||||
// reliably in other circumstances.
|
||||
var stacktrace = ex.stacktrace;
|
||||
if (!stacktrace) {
|
||||
return;
|
||||
}
|
||||
|
||||
var testRE = / line (\d+), column (\d+) in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\) in (.*):\s*$/i,
|
||||
var opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i,
|
||||
opera11Regex = / line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\))? in (.*):\s*$/i,
|
||||
lines = stacktrace.split('\n'),
|
||||
stack = [],
|
||||
parts;
|
||||
|
||||
for (var i = 0, j = lines.length; i < j; i += 2) {
|
||||
if ((parts = testRE.exec(lines[i]))) {
|
||||
var element = {
|
||||
for (var line = 0; line < lines.length; line += 2) {
|
||||
var element = null;
|
||||
if ((parts = opera10Regex.exec(lines[line]))) {
|
||||
element = {
|
||||
'url': parts[2],
|
||||
'line': +parts[1],
|
||||
'column': null,
|
||||
'func': parts[3],
|
||||
'args':[]
|
||||
};
|
||||
} else if ((parts = opera11Regex.exec(lines[line]))) {
|
||||
element = {
|
||||
'url': parts[6],
|
||||
'line': +parts[1],
|
||||
'column': +parts[2],
|
||||
'func': parts[3] || parts[4],
|
||||
'args': parts[5] ? parts[5].split(',') : [],
|
||||
'url': parts[6]
|
||||
'args': parts[5] ? parts[5].split(',') : []
|
||||
};
|
||||
}
|
||||
|
||||
if (element) {
|
||||
if (!element.func && element.line) {
|
||||
element.func = guessFunctionName(element.url, element.line);
|
||||
}
|
||||
@ -712,7 +828,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
}
|
||||
|
||||
if (!element.context) {
|
||||
element.context = [lines[i + 1]];
|
||||
element.context = [lines[line + 1]];
|
||||
}
|
||||
|
||||
stack.push(element);
|
||||
@ -727,9 +843,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
'mode': 'stacktrace',
|
||||
'name': ex.name,
|
||||
'message': ex.message,
|
||||
'url': document.location.href,
|
||||
'stack': stack,
|
||||
'useragent': navigator.userAgent
|
||||
'stack': stack
|
||||
};
|
||||
}
|
||||
|
||||
@ -740,9 +854,11 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* Opera 9 and earlier use this method if the option to show stack
|
||||
* traces is turned on in opera:config.
|
||||
* @param {Error} ex
|
||||
* @return {?Object.<string, *>} Stack information.
|
||||
* @return {?TraceKit.StackTrace} Stack information.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function computeStackTraceFromOperaMultiLineMessage(ex) {
|
||||
// TODO: Clean this function up
|
||||
// Opera includes a stack trace into the exception message. An example is:
|
||||
//
|
||||
// Statement on line 3: Undefined variable: undefinedFunc
|
||||
@ -762,40 +878,42 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
return null;
|
||||
}
|
||||
|
||||
var lineRE1 = /^\s*Line (\d+) of linked script ((?:file|http|https)\S+)(?:: in function (\S+))?\s*$/i,
|
||||
lineRE2 = /^\s*Line (\d+) of inline#(\d+) script in ((?:file|http|https)\S+)(?:: in function (\S+))?\s*$/i,
|
||||
var lineRE1 = /^\s*Line (\d+) of linked script ((?:file|https?|blob)\S+)(?:: in function (\S+))?\s*$/i,
|
||||
lineRE2 = /^\s*Line (\d+) of inline#(\d+) script in ((?:file|https?|blob)\S+)(?:: in function (\S+))?\s*$/i,
|
||||
lineRE3 = /^\s*Line (\d+) of function script\s*$/i,
|
||||
stack = [],
|
||||
scripts = document.getElementsByTagName('script'),
|
||||
scripts = (window && window.document && window.document.getElementsByTagName('script')),
|
||||
inlineScriptBlocks = [],
|
||||
parts,
|
||||
i,
|
||||
len,
|
||||
source;
|
||||
parts;
|
||||
|
||||
for (i in scripts) {
|
||||
if (_has(scripts, i) && !scripts[i].src) {
|
||||
inlineScriptBlocks.push(scripts[i]);
|
||||
for (var s in scripts) {
|
||||
if (_has(scripts, s) && !scripts[s].src) {
|
||||
inlineScriptBlocks.push(scripts[s]);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 2, len = lines.length; i < len; i += 2) {
|
||||
for (var line = 2; line < lines.length; line += 2) {
|
||||
var item = null;
|
||||
if ((parts = lineRE1.exec(lines[i]))) {
|
||||
if ((parts = lineRE1.exec(lines[line]))) {
|
||||
item = {
|
||||
'url': parts[2],
|
||||
'func': parts[3],
|
||||
'line': +parts[1]
|
||||
'args': [],
|
||||
'line': +parts[1],
|
||||
'column': null
|
||||
};
|
||||
} else if ((parts = lineRE2.exec(lines[i]))) {
|
||||
} else if ((parts = lineRE2.exec(lines[line]))) {
|
||||
item = {
|
||||
'url': parts[3],
|
||||
'func': parts[4]
|
||||
'func': parts[4],
|
||||
'args': [],
|
||||
'line': +parts[1],
|
||||
'column': null // TODO: Check to see if inline#1 (+parts[2]) points to the script number or column number.
|
||||
};
|
||||
var relativeLine = (+parts[1]); // relative to the start of the <SCRIPT> block
|
||||
var script = inlineScriptBlocks[parts[2] - 1];
|
||||
if (script) {
|
||||
source = getSource(item.url);
|
||||
var source = getSource(item.url);
|
||||
if (source) {
|
||||
source = source.join('\n');
|
||||
var pos = source.indexOf(script.innerText);
|
||||
@ -804,15 +922,16 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((parts = lineRE3.exec(lines[i]))) {
|
||||
var url = window.location.href.replace(/#.*$/, ''),
|
||||
line = parts[1];
|
||||
var re = new RegExp(escapeCodeAsRegExpForMatchingInsideHTML(lines[i + 1]));
|
||||
source = findSourceInUrls(re, [url]);
|
||||
} else if ((parts = lineRE3.exec(lines[line]))) {
|
||||
var url = window.location.href.replace(/#.*$/, '');
|
||||
var re = new RegExp(escapeCodeAsRegExpForMatchingInsideHTML(lines[line + 1]));
|
||||
var src = findSourceInUrls(re, [url]);
|
||||
item = {
|
||||
'url': url,
|
||||
'line': source ? source.line : line,
|
||||
'func': ''
|
||||
'func': '',
|
||||
'args': [],
|
||||
'line': src ? src.line : parts[1],
|
||||
'column': null
|
||||
};
|
||||
}
|
||||
|
||||
@ -822,11 +941,11 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
}
|
||||
var context = gatherContext(item.url, item.line);
|
||||
var midline = (context ? context[Math.floor(context.length / 2)] : null);
|
||||
if (context && midline.replace(/^\s*/, '') === lines[i + 1].replace(/^\s*/, '')) {
|
||||
if (context && midline.replace(/^\s*/, '') === lines[line + 1].replace(/^\s*/, '')) {
|
||||
item.context = context;
|
||||
} else {
|
||||
// if (context) alert("Context mismatch. Correct midline:\n" + lines[i+1] + "\n\nMidline:\n" + midline + "\n\nContext:\n" + context.join("\n") + "\n\nURL:\n" + item.url);
|
||||
item.context = [lines[i + 1]];
|
||||
item.context = [lines[line + 1]];
|
||||
}
|
||||
stack.push(item);
|
||||
}
|
||||
@ -839,16 +958,14 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
'mode': 'multiline',
|
||||
'name': ex.name,
|
||||
'message': lines[0],
|
||||
'url': document.location.href,
|
||||
'stack': stack,
|
||||
'useragent': navigator.userAgent
|
||||
'stack': stack
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds information about the first frame to incomplete stack traces.
|
||||
* Safari and IE require this to get complete data on the first frame.
|
||||
* @param {Object.<string, *>} stackInfo Stack trace information from
|
||||
* @param {TraceKit.StackTrace} stackInfo Stack trace information from
|
||||
* one of the compute* methods.
|
||||
* @param {string} url The URL of the script that caused an error.
|
||||
* @param {(number|string)} lineNo The line number of the script that
|
||||
@ -857,6 +974,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* hopefully contains the name of the object that caused the error.
|
||||
* @return {boolean} Whether or not the stack information was
|
||||
* augmented.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function augmentStackTraceWithInitialElement(stackInfo, url, lineNo, message) {
|
||||
var initial = {
|
||||
@ -909,7 +1027,8 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* Safari and IE. The top frame is restored by
|
||||
* {@link augmentStackTraceWithInitialElement}.
|
||||
* @param {Error} ex
|
||||
* @return {?Object.<string, *>} Stack trace information.
|
||||
* @return {TraceKit.StackTrace=} Stack trace information.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function computeStackTraceByWalkingCallerChain(ex, depth) {
|
||||
var functionName = /function\s+([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)?\s*\(/i,
|
||||
@ -929,6 +1048,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
item = {
|
||||
'url': null,
|
||||
'func': UNKNOWN_FUNCTION,
|
||||
'args': [],
|
||||
'line': null,
|
||||
'column': null
|
||||
};
|
||||
@ -939,6 +1059,12 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
item.func = parts[1];
|
||||
}
|
||||
|
||||
if (typeof item.func === 'undefined') {
|
||||
try {
|
||||
item.func = parts.input.substring(0, parts.input.indexOf('{'));
|
||||
} catch (e) { }
|
||||
}
|
||||
|
||||
if ((source = findSourceByFunctionBody(curr))) {
|
||||
item.url = source.url;
|
||||
item.line = source.line;
|
||||
@ -972,9 +1098,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
'mode': 'callers',
|
||||
'name': ex.name,
|
||||
'message': ex.message,
|
||||
'url': document.location.href,
|
||||
'stack': stack,
|
||||
'useragent': navigator.userAgent
|
||||
'stack': stack
|
||||
};
|
||||
augmentStackTraceWithInitialElement(result, ex.sourceURL || ex.fileName, ex.line || ex.lineNumber, ex.message || ex.description);
|
||||
return result;
|
||||
@ -984,6 +1108,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
* Computes a stack trace for an exception.
|
||||
* @param {Error} ex
|
||||
* @param {(string|number)=} depth
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function computeStackTrace(ex, depth) {
|
||||
var stack = null;
|
||||
@ -1044,7 +1169,8 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
/**
|
||||
* Logs a stacktrace starting from the previous call and working down.
|
||||
* @param {(number|string)=} depth How many frames deep to trace.
|
||||
* @return {Object.<string, *>} Stack trace information.
|
||||
* @return {TraceKit.StackTrace} Stack trace information.
|
||||
* @memberof TraceKit.computeStackTrace
|
||||
*/
|
||||
function computeStackTraceOfCaller(depth) {
|
||||
depth = (depth == null ? 0 : +depth) + 1; // "+ 1" because "ofCaller" should drop one frame
|
||||
@ -1053,14 +1179,13 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
} catch (ex) {
|
||||
return computeStackTrace(ex, depth + 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;
|
||||
computeStackTrace.guessFunctionName = guessFunctionName;
|
||||
computeStackTrace.gatherContext = gatherContext;
|
||||
computeStackTrace.ofCaller = computeStackTraceOfCaller;
|
||||
computeStackTrace.getSource = getSource;
|
||||
|
||||
return computeStackTrace;
|
||||
}());
|
||||
@ -1068,8 +1193,9 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
/**
|
||||
* Extends support for global error handling for asynchronous browser
|
||||
* functions. Adopted from Closure Library's errorhandler.js
|
||||
* @memberof TraceKit
|
||||
*/
|
||||
(function extendToAsynchronousCallbacks() {
|
||||
TraceKit.extendToAsynchronousCallbacks = function () {
|
||||
var _helper = function _helper(fnName) {
|
||||
var originalFn = window[fnName];
|
||||
window[fnName] = function traceKitAsyncExtension() {
|
||||
@ -1092,23 +1218,27 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
||||
|
||||
_helper('setTimeout');
|
||||
_helper('setInterval');
|
||||
}());
|
||||
};
|
||||
|
||||
//Default options:
|
||||
if (!TraceKit.remoteFetching) {
|
||||
TraceKit.remoteFetching = true;
|
||||
TraceKit.remoteFetching = true;
|
||||
}
|
||||
if (!TraceKit.collectWindowErrors) {
|
||||
TraceKit.collectWindowErrors = true;
|
||||
TraceKit.collectWindowErrors = true;
|
||||
}
|
||||
if (!TraceKit.linesOfContext || TraceKit.linesOfContext < 1) {
|
||||
// 5 lines before, the offending line, 5 lines after
|
||||
TraceKit.linesOfContext = 11;
|
||||
// 5 lines before, the offending line, 5 lines after
|
||||
TraceKit.linesOfContext = 11;
|
||||
}
|
||||
|
||||
// UMD export
|
||||
if (typeof module !== 'undefined' && module.exports && window.module !== module) {
|
||||
module.exports = TraceKit;
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define('TraceKit', [], TraceKit);
|
||||
} else {
|
||||
window.TraceKit = TraceKit;
|
||||
}
|
||||
|
||||
|
||||
// Export to global object
|
||||
window.TraceKit = TraceKit;
|
||||
|
||||
}(window));
|
||||
}(typeof window !== 'undefined' ? window : global));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user