/*! Raven.js 3.22.2 (1b6187b) | github.com/getsentry/raven-js */ /* * Includes TraceKit * https://github.com/getsentry/TraceKit * * Copyright 2018 Matt Robenolt and other contributors * Released under the BSD license * https://github.com/getsentry/raven-js/blob/master/LICENSE * */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.Raven = global.Raven || {}, global.Raven.Plugins = global.Raven.Plugins || {}, global.Raven.Plugins.Angular = factory()); }(this, (function () { 'use strict'; function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function (obj) { return typeof obj; }; } else { _typeof = function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } var _sPO = Object.setPrototypeOf || function _sPO(o, p) { o.__proto__ = p; return o; }; var _construct = typeof Reflect === "object" && Reflect.construct || function _construct(Parent, args, Class) { var Constructor, a = [null]; a.push.apply(a, args); Constructor = Parent.bind.apply(Parent, a); return _sPO(new Constructor(), Class.prototype); }; var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; var _window = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {}; function isObject(what) { return _typeof(what) === 'object' && what !== null; } // Yanked from https://git.io/vS8DV re-used under CC0 // with some tiny modifications function isError(value) { switch ({}.toString.call(value)) { case '[object Error]': return true; case '[object Exception]': return true; case '[object DOMException]': return true; default: return value instanceof Error; } } function isErrorEvent(value) { return supportsErrorEvent() && {}.toString.call(value) === '[object ErrorEvent]'; } function isUndefined(what) { return what === void 0; } function isFunction(what) { return typeof what === 'function'; } function isPlainObject(what) { return Object.prototype.toString.call(what) === '[object Object]'; } function isString(what) { return Object.prototype.toString.call(what) === '[object String]'; } function isArray(what) { return Object.prototype.toString.call(what) === '[object Array]'; } function isEmptyObject(what) { if (!isPlainObject(what)) return false; for (var _ in what) { if (what.hasOwnProperty(_)) { return false; } } return true; } function supportsErrorEvent() { try { new ErrorEvent(''); // eslint-disable-line no-new return true; } catch (e) { return false; } } function supportsFetch() { if (!('fetch' in _window)) return false; try { new Headers(); // eslint-disable-line no-new new Request(''); // eslint-disable-line no-new new Response(); // eslint-disable-line no-new return true; } catch (e) { return false; } } function wrappedCallback$1(callback) { function dataCallback(data, original) { var normalizedData = callback(data) || data; if (original) { return original(normalizedData) || normalizedData; } return normalizedData; } return dataCallback; } function each(obj, callback) { var i, j; if (isUndefined(obj.length)) { for (i in obj) { if (hasKey(obj, i)) { callback.call(null, i, obj[i]); } } } else { j = obj.length; if (j) { for (i = 0; i < j; i++) { callback.call(null, i, obj[i]); } } } } function objectMerge(obj1, obj2) { if (!obj2) { return obj1; } each(obj2, function (key, value) { obj1[key] = value; }); return obj1; } /** * This function is only used for react-native. * react-native freezes object that have already been sent over the * js bridge. We need this function in order to check if the object is frozen. * So it's ok that objectFrozen returns false if Object.isFrozen is not * supported because it's not relevant for other "platforms". See related issue: * https://github.com/getsentry/react-native-sentry/issues/57 */ function objectFrozen(obj) { if (!Object.isFrozen) { return false; } return Object.isFrozen(obj); } function truncate(str, max) { return !max || str.length <= max ? str : str.substr(0, max) + "\u2026"; } /** * hasKey, a better form of hasOwnProperty * Example: hasKey(MainHostObject, property) === true/false * * @param {Object} host object to check property * @param {string} key to check */ function hasKey(object, key) { return Object.prototype.hasOwnProperty.call(object, key); } function joinRegExp(patterns) { // Combine an array of regular expressions and strings into one large regexp // Be mad. var sources = [], i = 0, len = patterns.length, pattern; for (; i < len; i++) { pattern = patterns[i]; if (isString(pattern)) { // If it's a string, we need to escape it // Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions sources.push(pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1')); } else if (pattern && pattern.source) { // If it's a regexp already, we want to extract the source sources.push(pattern.source); } // Intentionally skip other cases } return new RegExp(sources.join('|'), 'i'); } function urlencode(o) { var pairs = []; each(o, function (key, value) { pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); }); return pairs.join('&'); } // borrowed from https://tools.ietf.org/html/rfc3986#appendix-B // intentionally using regex and not href parsing trick because React Native and other // environments where DOM might not be available function parseUrl(url) { if (typeof url !== 'string') return {}; var match = url.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/); // coerce to undefined values to empty string so we don't get 'undefined' var query = match[6] || ''; var fragment = match[8] || ''; return { protocol: match[2], host: match[4], path: match[5], relative: match[5] + query + fragment // everything minus origin }; } function uuid4() { var crypto = _window.crypto || _window.msCrypto; if (!isUndefined(crypto) && crypto.getRandomValues) { // Use window.crypto API if available // eslint-disable-next-line no-undef var arr = new Uint16Array(8); crypto.getRandomValues(arr); // set 4 in byte 7 arr[3] = arr[3] & 0xfff | 0x4000; // set 2 most significant bits of byte 9 to '10' arr[4] = arr[4] & 0x3fff | 0x8000; var pad = function pad(num) { var v = num.toString(16); while (v.length < 4) { v = '0' + v; } return v; }; return pad(arr[0]) + pad(arr[1]) + pad(arr[2]) + pad(arr[3]) + pad(arr[4]) + pad(arr[5]) + pad(arr[6]) + pad(arr[7]); } else { // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523 return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c === 'x' ? r : r & 0x3 | 0x8; return v.toString(16); }); } } /** * Given a child DOM element, returns a query-selector statement describing that * and its ancestors * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz] * @param elem * @returns {string} */ function htmlTreeAsString(elem) { /* eslint no-extra-parens:0*/ var MAX_TRAVERSE_HEIGHT = 5, MAX_OUTPUT_LEN = 80, out = [], height = 0, len = 0, separator = ' > ', sepLength = separator.length, nextStr; while (elem && height++ < MAX_TRAVERSE_HEIGHT) { nextStr = htmlElementAsString(elem); // bail out if // - nextStr is the 'html' element // - the length of the string that would be created exceeds MAX_OUTPUT_LEN // (ignore this limit if we are on the first iteration) if (nextStr === 'html' || height > 1 && len + out.length * sepLength + nextStr.length >= MAX_OUTPUT_LEN) { break; } out.push(nextStr); len += nextStr.length; elem = elem.parentNode; } return out.reverse().join(separator); } /** * Returns a simple, query-selector representation of a DOM element * e.g. [HTMLElement] => input#foo.btn[name=baz] * @param HTMLElement * @returns {string} */ function htmlElementAsString(elem) { var out = [], className, classes, key, attr, i; if (!elem || !elem.tagName) { return ''; } out.push(elem.tagName.toLowerCase()); if (elem.id) { out.push('#' + elem.id); } className = elem.className; if (className && isString(className)) { classes = className.split(/\s+/); for (i = 0; i < classes.length; i++) { out.push('.' + classes[i]); } } var attrWhitelist = ['type', 'name', 'title', 'alt']; for (i = 0; i < attrWhitelist.length; i++) { key = attrWhitelist[i]; attr = elem.getAttribute(key); if (attr) { out.push('[' + key + '="' + attr + '"]'); } } return out.join(''); } /** * Returns true if either a OR b is truthy, but not both */ function isOnlyOneTruthy(a, b) { return !!(!!a ^ !!b); } /** * Returns true if both parameters are undefined */ function isBothUndefined(a, b) { return isUndefined(a) && isUndefined(b); } /** * Returns true if the two input exception interfaces have the same content */ function isSameException(ex1, ex2) { if (isOnlyOneTruthy(ex1, ex2)) return false; ex1 = ex1.values[0]; ex2 = ex2.values[0]; if (ex1.type !== ex2.type || ex1.value !== ex2.value) return false; // in case both stacktraces are undefined, we can't decide so default to false if (isBothUndefined(ex1.stacktrace, ex2.stacktrace)) return false; return isSameStacktrace(ex1.stacktrace, ex2.stacktrace); } /** * Returns true if the two input stack trace interfaces have the same content */ function isSameStacktrace(stack1, stack2) { if (isOnlyOneTruthy(stack1, stack2)) return false; var frames1 = stack1.frames; var frames2 = stack2.frames; // Exit early if frame count differs if (frames1.length !== frames2.length) return false; // Iterate through every frame; bail out if anything differs var a, b; for (var i = 0; i < frames1.length; i++) { a = frames1[i]; b = frames2[i]; if (a.filename !== b.filename || a.lineno !== b.lineno || a.colno !== b.colno || a['function'] !== b['function']) return false; } return true; } /** * Polyfill a method * @param obj object e.g. `document` * @param name method name present on object e.g. `addEventListener` * @param replacement replacement function * @param track {optional} record instrumentation to an array */ function fill(obj, name, replacement, track) { var orig = obj[name]; obj[name] = replacement(orig); obj[name].__raven__ = true; obj[name].__orig__ = orig; if (track) { track.push([obj, name, orig]); } } /** * Join values in array * @param input array of values to be joined together * @param delimiter string to be placed in-between values * @returns {string} */ function safeJoin(input, delimiter) { if (!isArray(input)) return ''; var output = []; for (var i = 0; i < input.length; i++) { try { output.push(String(input[i])); } catch (e) { output.push('[value cannot be serialized]'); } } return output.join(delimiter); } var utils = { isObject: isObject, isError: isError, isErrorEvent: isErrorEvent, isUndefined: isUndefined, isFunction: isFunction, isPlainObject: isPlainObject, isString: isString, isArray: isArray, isEmptyObject: isEmptyObject, supportsErrorEvent: supportsErrorEvent, supportsFetch: supportsFetch, wrappedCallback: wrappedCallback$1, each: each, objectMerge: objectMerge, truncate: truncate, objectFrozen: objectFrozen, hasKey: hasKey, joinRegExp: joinRegExp, urlencode: urlencode, uuid4: uuid4, htmlTreeAsString: htmlTreeAsString, htmlElementAsString: htmlElementAsString, isSameException: isSameException, isSameStacktrace: isSameStacktrace, parseUrl: parseUrl, fill: fill, safeJoin: safeJoin }; /** * Angular.js plugin * * Provides an $exceptionHandler for Angular.js */ var wrappedCallback = utils.wrappedCallback; // See https://github.com/angular/angular.js/blob/v1.4.7/src/minErr.js var angularPattern = /^\[((?:[$a-zA-Z0-9]+:)?(?:[$a-zA-Z0-9]+))\] (.*?)\n?(\S+)$/; var moduleName = 'ngRaven'; function angularPlugin(Raven, angular) { angular = angular || window.angular; if (!angular) return; function RavenProvider() { this.$get = ['$window', function ($window) { return Raven; }]; } function ExceptionHandlerProvider($provide) { $provide.decorator('$exceptionHandler', ['Raven', '$delegate', exceptionHandler]); } function exceptionHandler(R, $delegate) { return function (ex, cause) { R.captureException(ex, { extra: { cause: cause } }); $delegate(ex, cause); }; } angular.module(moduleName, []).provider('Raven', RavenProvider).config(['$provide', ExceptionHandlerProvider]); Raven.setDataCallback(wrappedCallback(function (data) { return angularPlugin._normalizeData(data); })); } angularPlugin._normalizeData = function (data) { // We only care about mutating an exception var exception = data.exception; if (exception) { exception = exception.values[0]; var matches = angularPattern.exec(exception.value); if (matches) { // This type now becomes something like: $rootScope:inprog exception.type = matches[1]; exception.value = matches[2]; data.message = exception.type + ': ' + exception.value; // auto set a new tag specifically for the angular error url data.extra.angularDocs = matches[3].substr(0, 250); } } return data; }; angularPlugin.moduleName = moduleName; var angular = angularPlugin; return angular; })));