| "use strict"; |
| module.exports = function(Promise, Context, |
| enableAsyncHooks, disableAsyncHooks) { |
| var async = Promise._async; |
| var Warning = require("./errors").Warning; |
| var util = require("./util"); |
| var es5 = require("./es5"); |
| var canAttachTrace = util.canAttachTrace; |
| var unhandledRejectionHandled; |
| var possiblyUnhandledRejection; |
| var bluebirdFramePattern = |
| /[\\\/]bluebird[\\\/]js[\\\/](release|debug|instrumented)/; |
| var nodeFramePattern = /\((?:timers\.js):\d+:\d+\)/; |
| var parseLinePattern = /[\/<\(](.+?):(\d+):(\d+)\)?\s*$/; |
| var stackFramePattern = null; |
| var formatStack = null; |
| var indentStackFrames = false; |
| var printWarning; |
| var debugging = !!(util.env("BLUEBIRD_DEBUG") != 0 && |
| (false || |
| util.env("BLUEBIRD_DEBUG") || |
| util.env("NODE_ENV") === "development")); |
| |
| var warnings = !!(util.env("BLUEBIRD_WARNINGS") != 0 && |
| (debugging || util.env("BLUEBIRD_WARNINGS"))); |
| |
| var longStackTraces = !!(util.env("BLUEBIRD_LONG_STACK_TRACES") != 0 && |
| (debugging || util.env("BLUEBIRD_LONG_STACK_TRACES"))); |
| |
| var wForgottenReturn = util.env("BLUEBIRD_W_FORGOTTEN_RETURN") != 0 && |
| (warnings || !!util.env("BLUEBIRD_W_FORGOTTEN_RETURN")); |
| |
| var deferUnhandledRejectionCheck; |
| (function() { |
| var promises = []; |
| |
| function unhandledRejectionCheck() { |
| for (var i = 0; i < promises.length; ++i) { |
| promises[i]._notifyUnhandledRejection(); |
| } |
| unhandledRejectionClear(); |
| } |
| |
| function unhandledRejectionClear() { |
| promises.length = 0; |
| } |
| |
| if (typeof document === "object" && document.createElement) { |
| deferUnhandledRejectionCheck = (function() { |
| var iframeSetTimeout; |
| |
| function checkIframe() { |
| if (document.body) { |
| var iframe = document.createElement("iframe"); |
| document.body.appendChild(iframe); |
| if (iframe.contentWindow && |
| iframe.contentWindow.setTimeout) { |
| iframeSetTimeout = iframe.contentWindow.setTimeout; |
| } |
| document.body.removeChild(iframe); |
| } |
| } |
| checkIframe(); |
| return function(promise) { |
| promises.push(promise); |
| if (iframeSetTimeout) { |
| iframeSetTimeout(unhandledRejectionCheck, 1); |
| } else { |
| checkIframe(); |
| } |
| }; |
| })(); |
| } else { |
| deferUnhandledRejectionCheck = function(promise) { |
| promises.push(promise); |
| setTimeout(unhandledRejectionCheck, 1); |
| }; |
| } |
| |
| es5.defineProperty(Promise, "_unhandledRejectionCheck", { |
| value: unhandledRejectionCheck |
| }); |
| es5.defineProperty(Promise, "_unhandledRejectionClear", { |
| value: unhandledRejectionClear |
| }); |
| })(); |
| |
| Promise.prototype.suppressUnhandledRejections = function() { |
| var target = this._target(); |
| target._bitField = ((target._bitField & (~1048576)) | |
| 524288); |
| }; |
| |
| Promise.prototype._ensurePossibleRejectionHandled = function () { |
| if ((this._bitField & 524288) !== 0) return; |
| this._setRejectionIsUnhandled(); |
| deferUnhandledRejectionCheck(this); |
| }; |
| |
| Promise.prototype._notifyUnhandledRejectionIsHandled = function () { |
| fireRejectionEvent("rejectionHandled", |
| unhandledRejectionHandled, undefined, this); |
| }; |
| |
| Promise.prototype._setReturnedNonUndefined = function() { |
| this._bitField = this._bitField | 268435456; |
| }; |
| |
| Promise.prototype._returnedNonUndefined = function() { |
| return (this._bitField & 268435456) !== 0; |
| }; |
| |
| Promise.prototype._notifyUnhandledRejection = function () { |
| if (this._isRejectionUnhandled()) { |
| var reason = this._settledValue(); |
| this._setUnhandledRejectionIsNotified(); |
| fireRejectionEvent("unhandledRejection", |
| possiblyUnhandledRejection, reason, this); |
| } |
| }; |
| |
| Promise.prototype._setUnhandledRejectionIsNotified = function () { |
| this._bitField = this._bitField | 262144; |
| }; |
| |
| Promise.prototype._unsetUnhandledRejectionIsNotified = function () { |
| this._bitField = this._bitField & (~262144); |
| }; |
| |
| Promise.prototype._isUnhandledRejectionNotified = function () { |
| return (this._bitField & 262144) > 0; |
| }; |
| |
| Promise.prototype._setRejectionIsUnhandled = function () { |
| this._bitField = this._bitField | 1048576; |
| }; |
| |
| Promise.prototype._unsetRejectionIsUnhandled = function () { |
| this._bitField = this._bitField & (~1048576); |
| if (this._isUnhandledRejectionNotified()) { |
| this._unsetUnhandledRejectionIsNotified(); |
| this._notifyUnhandledRejectionIsHandled(); |
| } |
| }; |
| |
| Promise.prototype._isRejectionUnhandled = function () { |
| return (this._bitField & 1048576) > 0; |
| }; |
| |
| Promise.prototype._warn = function(message, shouldUseOwnTrace, promise) { |
| return warn(message, shouldUseOwnTrace, promise || this); |
| }; |
| |
| Promise.onPossiblyUnhandledRejection = function (fn) { |
| var context = Promise._getContext(); |
| possiblyUnhandledRejection = util.contextBind(context, fn); |
| }; |
| |
| Promise.onUnhandledRejectionHandled = function (fn) { |
| var context = Promise._getContext(); |
| unhandledRejectionHandled = util.contextBind(context, fn); |
| }; |
| |
| var disableLongStackTraces = function() {}; |
| Promise.longStackTraces = function () { |
| if (async.haveItemsQueued() && !config.longStackTraces) { |
| throw new Error("cannot enable long stack traces after promises have been created\u000a\u000a See http://goo.gl/MqrFmX\u000a"); |
| } |
| if (!config.longStackTraces && longStackTracesIsSupported()) { |
| var Promise_captureStackTrace = Promise.prototype._captureStackTrace; |
| var Promise_attachExtraTrace = Promise.prototype._attachExtraTrace; |
| var Promise_dereferenceTrace = Promise.prototype._dereferenceTrace; |
| config.longStackTraces = true; |
| disableLongStackTraces = function() { |
| if (async.haveItemsQueued() && !config.longStackTraces) { |
| throw new Error("cannot enable long stack traces after promises have been created\u000a\u000a See http://goo.gl/MqrFmX\u000a"); |
| } |
| Promise.prototype._captureStackTrace = Promise_captureStackTrace; |
| Promise.prototype._attachExtraTrace = Promise_attachExtraTrace; |
| Promise.prototype._dereferenceTrace = Promise_dereferenceTrace; |
| Context.deactivateLongStackTraces(); |
| config.longStackTraces = false; |
| }; |
| Promise.prototype._captureStackTrace = longStackTracesCaptureStackTrace; |
| Promise.prototype._attachExtraTrace = longStackTracesAttachExtraTrace; |
| Promise.prototype._dereferenceTrace = longStackTracesDereferenceTrace; |
| Context.activateLongStackTraces(); |
| } |
| }; |
| |
| Promise.hasLongStackTraces = function () { |
| return config.longStackTraces && longStackTracesIsSupported(); |
| }; |
| |
| |
| var legacyHandlers = { |
| unhandledrejection: { |
| before: function() { |
| var ret = util.global.onunhandledrejection; |
| util.global.onunhandledrejection = null; |
| return ret; |
| }, |
| after: function(fn) { |
| util.global.onunhandledrejection = fn; |
| } |
| }, |
| rejectionhandled: { |
| before: function() { |
| var ret = util.global.onrejectionhandled; |
| util.global.onrejectionhandled = null; |
| return ret; |
| }, |
| after: function(fn) { |
| util.global.onrejectionhandled = fn; |
| } |
| } |
| }; |
| |
| var fireDomEvent = (function() { |
| var dispatch = function(legacy, e) { |
| if (legacy) { |
| var fn; |
| try { |
| fn = legacy.before(); |
| return !util.global.dispatchEvent(e); |
| } finally { |
| legacy.after(fn); |
| } |
| } else { |
| return !util.global.dispatchEvent(e); |
| } |
| }; |
| try { |
| if (typeof CustomEvent === "function") { |
| var event = new CustomEvent("CustomEvent"); |
| util.global.dispatchEvent(event); |
| return function(name, event) { |
| name = name.toLowerCase(); |
| var eventData = { |
| detail: event, |
| cancelable: true |
| }; |
| var domEvent = new CustomEvent(name, eventData); |
| es5.defineProperty( |
| domEvent, "promise", {value: event.promise}); |
| es5.defineProperty( |
| domEvent, "reason", {value: event.reason}); |
| |
| return dispatch(legacyHandlers[name], domEvent); |
| }; |
| } else if (typeof Event === "function") { |
| var event = new Event("CustomEvent"); |
| util.global.dispatchEvent(event); |
| return function(name, event) { |
| name = name.toLowerCase(); |
| var domEvent = new Event(name, { |
| cancelable: true |
| }); |
| domEvent.detail = event; |
| es5.defineProperty(domEvent, "promise", {value: event.promise}); |
| es5.defineProperty(domEvent, "reason", {value: event.reason}); |
| return dispatch(legacyHandlers[name], domEvent); |
| }; |
| } else { |
| var event = document.createEvent("CustomEvent"); |
| event.initCustomEvent("testingtheevent", false, true, {}); |
| util.global.dispatchEvent(event); |
| return function(name, event) { |
| name = name.toLowerCase(); |
| var domEvent = document.createEvent("CustomEvent"); |
| domEvent.initCustomEvent(name, false, true, |
| event); |
| return dispatch(legacyHandlers[name], domEvent); |
| }; |
| } |
| } catch (e) {} |
| return function() { |
| return false; |
| }; |
| })(); |
| |
| var fireGlobalEvent = (function() { |
| if (util.isNode) { |
| return function() { |
| return process.emit.apply(process, arguments); |
| }; |
| } else { |
| if (!util.global) { |
| return function() { |
| return false; |
| }; |
| } |
| return function(name) { |
| var methodName = "on" + name.toLowerCase(); |
| var method = util.global[methodName]; |
| if (!method) return false; |
| method.apply(util.global, [].slice.call(arguments, 1)); |
| return true; |
| }; |
| } |
| })(); |
| |
| function generatePromiseLifecycleEventObject(name, promise) { |
| return {promise: promise}; |
| } |
| |
| var eventToObjectGenerator = { |
| promiseCreated: generatePromiseLifecycleEventObject, |
| promiseFulfilled: generatePromiseLifecycleEventObject, |
| promiseRejected: generatePromiseLifecycleEventObject, |
| promiseResolved: generatePromiseLifecycleEventObject, |
| promiseCancelled: generatePromiseLifecycleEventObject, |
| promiseChained: function(name, promise, child) { |
| return {promise: promise, child: child}; |
| }, |
| warning: function(name, warning) { |
| return {warning: warning}; |
| }, |
| unhandledRejection: function (name, reason, promise) { |
| return {reason: reason, promise: promise}; |
| }, |
| rejectionHandled: generatePromiseLifecycleEventObject |
| }; |
| |
| var activeFireEvent = function (name) { |
| var globalEventFired = false; |
| try { |
| globalEventFired = fireGlobalEvent.apply(null, arguments); |
| } catch (e) { |
| async.throwLater(e); |
| globalEventFired = true; |
| } |
| |
| var domEventFired = false; |
| try { |
| domEventFired = fireDomEvent(name, |
| eventToObjectGenerator[name].apply(null, arguments)); |
| } catch (e) { |
| async.throwLater(e); |
| domEventFired = true; |
| } |
| |
| return domEventFired || globalEventFired; |
| }; |
| |
| Promise.config = function(opts) { |
| opts = Object(opts); |
| if ("longStackTraces" in opts) { |
| if (opts.longStackTraces) { |
| Promise.longStackTraces(); |
| } else if (!opts.longStackTraces && Promise.hasLongStackTraces()) { |
| disableLongStackTraces(); |
| } |
| } |
| if ("warnings" in opts) { |
| var warningsOption = opts.warnings; |
| config.warnings = !!warningsOption; |
| wForgottenReturn = config.warnings; |
| |
| if (util.isObject(warningsOption)) { |
| if ("wForgottenReturn" in warningsOption) { |
| wForgottenReturn = !!warningsOption.wForgottenReturn; |
| } |
| } |
| } |
| if ("cancellation" in opts && opts.cancellation && !config.cancellation) { |
| if (async.haveItemsQueued()) { |
| throw new Error( |
| "cannot enable cancellation after promises are in use"); |
| } |
| Promise.prototype._clearCancellationData = |
| cancellationClearCancellationData; |
| Promise.prototype._propagateFrom = cancellationPropagateFrom; |
| Promise.prototype._onCancel = cancellationOnCancel; |
| Promise.prototype._setOnCancel = cancellationSetOnCancel; |
| Promise.prototype._attachCancellationCallback = |
| cancellationAttachCancellationCallback; |
| Promise.prototype._execute = cancellationExecute; |
| propagateFromFunction = cancellationPropagateFrom; |
| config.cancellation = true; |
| } |
| if ("monitoring" in opts) { |
| if (opts.monitoring && !config.monitoring) { |
| config.monitoring = true; |
| Promise.prototype._fireEvent = activeFireEvent; |
| } else if (!opts.monitoring && config.monitoring) { |
| config.monitoring = false; |
| Promise.prototype._fireEvent = defaultFireEvent; |
| } |
| } |
| if ("asyncHooks" in opts && util.nodeSupportsAsyncResource) { |
| var prev = config.asyncHooks; |
| var cur = !!opts.asyncHooks; |
| if (prev !== cur) { |
| config.asyncHooks = cur; |
| if (cur) { |
| enableAsyncHooks(); |
| } else { |
| disableAsyncHooks(); |
| } |
| } |
| } |
| return Promise; |
| }; |
| |
| function defaultFireEvent() { return false; } |
| |
| Promise.prototype._fireEvent = defaultFireEvent; |
| Promise.prototype._execute = function(executor, resolve, reject) { |
| try { |
| executor(resolve, reject); |
| } catch (e) { |
| return e; |
| } |
| }; |
| Promise.prototype._onCancel = function () {}; |
| Promise.prototype._setOnCancel = function (handler) { ; }; |
| Promise.prototype._attachCancellationCallback = function(onCancel) { |
| ; |
| }; |
| Promise.prototype._captureStackTrace = function () {}; |
| Promise.prototype._attachExtraTrace = function () {}; |
| Promise.prototype._dereferenceTrace = function () {}; |
| Promise.prototype._clearCancellationData = function() {}; |
| Promise.prototype._propagateFrom = function (parent, flags) { |
| ; |
| ; |
| }; |
| |
| function cancellationExecute(executor, resolve, reject) { |
| var promise = this; |
| try { |
| executor(resolve, reject, function(onCancel) { |
| if (typeof onCancel !== "function") { |
| throw new TypeError("onCancel must be a function, got: " + |
| util.toString(onCancel)); |
| } |
| promise._attachCancellationCallback(onCancel); |
| }); |
| } catch (e) { |
| return e; |
| } |
| } |
| |
| function cancellationAttachCancellationCallback(onCancel) { |
| if (!this._isCancellable()) return this; |
| |
| var previousOnCancel = this._onCancel(); |
| if (previousOnCancel !== undefined) { |
| if (util.isArray(previousOnCancel)) { |
| previousOnCancel.push(onCancel); |
| } else { |
| this._setOnCancel([previousOnCancel, onCancel]); |
| } |
| } else { |
| this._setOnCancel(onCancel); |
| } |
| } |
| |
| function cancellationOnCancel() { |
| return this._onCancelField; |
| } |
| |
| function cancellationSetOnCancel(onCancel) { |
| this._onCancelField = onCancel; |
| } |
| |
| function cancellationClearCancellationData() { |
| this._cancellationParent = undefined; |
| this._onCancelField = undefined; |
| } |
| |
| function cancellationPropagateFrom(parent, flags) { |
| if ((flags & 1) !== 0) { |
| this._cancellationParent = parent; |
| var branchesRemainingToCancel = parent._branchesRemainingToCancel; |
| if (branchesRemainingToCancel === undefined) { |
| branchesRemainingToCancel = 0; |
| } |
| parent._branchesRemainingToCancel = branchesRemainingToCancel + 1; |
| } |
| if ((flags & 2) !== 0 && parent._isBound()) { |
| this._setBoundTo(parent._boundTo); |
| } |
| } |
| |
| function bindingPropagateFrom(parent, flags) { |
| if ((flags & 2) !== 0 && parent._isBound()) { |
| this._setBoundTo(parent._boundTo); |
| } |
| } |
| var propagateFromFunction = bindingPropagateFrom; |
| |
| function boundValueFunction() { |
| var ret = this._boundTo; |
| if (ret !== undefined) { |
| if (ret instanceof Promise) { |
| if (ret.isFulfilled()) { |
| return ret.value(); |
| } else { |
| return undefined; |
| } |
| } |
| } |
| return ret; |
| } |
| |
| function longStackTracesCaptureStackTrace() { |
| this._trace = new CapturedTrace(this._peekContext()); |
| } |
| |
| function longStackTracesAttachExtraTrace(error, ignoreSelf) { |
| if (canAttachTrace(error)) { |
| var trace = this._trace; |
| if (trace !== undefined) { |
| if (ignoreSelf) trace = trace._parent; |
| } |
| if (trace !== undefined) { |
| trace.attachExtraTrace(error); |
| } else if (!error.__stackCleaned__) { |
| var parsed = parseStackAndMessage(error); |
| util.notEnumerableProp(error, "stack", |
| parsed.message + "\n" + parsed.stack.join("\n")); |
| util.notEnumerableProp(error, "__stackCleaned__", true); |
| } |
| } |
| } |
| |
| function longStackTracesDereferenceTrace() { |
| this._trace = undefined; |
| } |
| |
| function checkForgottenReturns(returnValue, promiseCreated, name, promise, |
| parent) { |
| if (returnValue === undefined && promiseCreated !== null && |
| wForgottenReturn) { |
| if (parent !== undefined && parent._returnedNonUndefined()) return; |
| if ((promise._bitField & 65535) === 0) return; |
| |
| if (name) name = name + " "; |
| var handlerLine = ""; |
| var creatorLine = ""; |
| if (promiseCreated._trace) { |
| var traceLines = promiseCreated._trace.stack.split("\n"); |
| var stack = cleanStack(traceLines); |
| for (var i = stack.length - 1; i >= 0; --i) { |
| var line = stack[i]; |
| if (!nodeFramePattern.test(line)) { |
| var lineMatches = line.match(parseLinePattern); |
| if (lineMatches) { |
| handlerLine = "at " + lineMatches[1] + |
| ":" + lineMatches[2] + ":" + lineMatches[3] + " "; |
| } |
| break; |
| } |
| } |
| |
| if (stack.length > 0) { |
| var firstUserLine = stack[0]; |
| for (var i = 0; i < traceLines.length; ++i) { |
| |
| if (traceLines[i] === firstUserLine) { |
| if (i > 0) { |
| creatorLine = "\n" + traceLines[i - 1]; |
| } |
| break; |
| } |
| } |
| |
| } |
| } |
| var msg = "a promise was created in a " + name + |
| "handler " + handlerLine + "but was not returned from it, " + |
| "see http://goo.gl/rRqMUw" + |
| creatorLine; |
| promise._warn(msg, true, promiseCreated); |
| } |
| } |
| |
| function deprecated(name, replacement) { |
| var message = name + |
| " is deprecated and will be removed in a future version."; |
| if (replacement) message += " Use " + replacement + " instead."; |
| return warn(message); |
| } |
| |
| function warn(message, shouldUseOwnTrace, promise) { |
| if (!config.warnings) return; |
| var warning = new Warning(message); |
| var ctx; |
| if (shouldUseOwnTrace) { |
| promise._attachExtraTrace(warning); |
| } else if (config.longStackTraces && (ctx = Promise._peekContext())) { |
| ctx.attachExtraTrace(warning); |
| } else { |
| var parsed = parseStackAndMessage(warning); |
| warning.stack = parsed.message + "\n" + parsed.stack.join("\n"); |
| } |
| |
| if (!activeFireEvent("warning", warning)) { |
| formatAndLogError(warning, "", true); |
| } |
| } |
| |
| function reconstructStack(message, stacks) { |
| for (var i = 0; i < stacks.length - 1; ++i) { |
| stacks[i].push("From previous event:"); |
| stacks[i] = stacks[i].join("\n"); |
| } |
| if (i < stacks.length) { |
| stacks[i] = stacks[i].join("\n"); |
| } |
| return message + "\n" + stacks.join("\n"); |
| } |
| |
| function removeDuplicateOrEmptyJumps(stacks) { |
| for (var i = 0; i < stacks.length; ++i) { |
| if (stacks[i].length === 0 || |
| ((i + 1 < stacks.length) && stacks[i][0] === stacks[i+1][0])) { |
| stacks.splice(i, 1); |
| i--; |
| } |
| } |
| } |
| |
| function removeCommonRoots(stacks) { |
| var current = stacks[0]; |
| for (var i = 1; i < stacks.length; ++i) { |
| var prev = stacks[i]; |
| var currentLastIndex = current.length - 1; |
| var currentLastLine = current[currentLastIndex]; |
| var commonRootMeetPoint = -1; |
| |
| for (var j = prev.length - 1; j >= 0; --j) { |
| if (prev[j] === currentLastLine) { |
| commonRootMeetPoint = j; |
| break; |
| } |
| } |
| |
| for (var j = commonRootMeetPoint; j >= 0; --j) { |
| var line = prev[j]; |
| if (current[currentLastIndex] === line) { |
| current.pop(); |
| currentLastIndex--; |
| } else { |
| break; |
| } |
| } |
| current = prev; |
| } |
| } |
| |
| function cleanStack(stack) { |
| var ret = []; |
| for (var i = 0; i < stack.length; ++i) { |
| var line = stack[i]; |
| var isTraceLine = " (No stack trace)" === line || |
| stackFramePattern.test(line); |
| var isInternalFrame = isTraceLine && shouldIgnore(line); |
| if (isTraceLine && !isInternalFrame) { |
| if (indentStackFrames && line.charAt(0) !== " ") { |
| line = " " + line; |
| } |
| ret.push(line); |
| } |
| } |
| return ret; |
| } |
| |
| function stackFramesAsArray(error) { |
| var stack = error.stack.replace(/\s+$/g, "").split("\n"); |
| for (var i = 0; i < stack.length; ++i) { |
| var line = stack[i]; |
| if (" (No stack trace)" === line || stackFramePattern.test(line)) { |
| break; |
| } |
| } |
| if (i > 0 && error.name != "SyntaxError") { |
| stack = stack.slice(i); |
| } |
| return stack; |
| } |
| |
| function parseStackAndMessage(error) { |
| var stack = error.stack; |
| var message = error.toString(); |
| stack = typeof stack === "string" && stack.length > 0 |
| ? stackFramesAsArray(error) : [" (No stack trace)"]; |
| return { |
| message: message, |
| stack: error.name == "SyntaxError" ? stack : cleanStack(stack) |
| }; |
| } |
| |
| function formatAndLogError(error, title, isSoft) { |
| if (typeof console !== "undefined") { |
| var message; |
| if (util.isObject(error)) { |
| var stack = error.stack; |
| message = title + formatStack(stack, error); |
| } else { |
| message = title + String(error); |
| } |
| if (typeof printWarning === "function") { |
| printWarning(message, isSoft); |
| } else if (typeof console.log === "function" || |
| typeof console.log === "object") { |
| console.log(message); |
| } |
| } |
| } |
| |
| function fireRejectionEvent(name, localHandler, reason, promise) { |
| var localEventFired = false; |
| try { |
| if (typeof localHandler === "function") { |
| localEventFired = true; |
| if (name === "rejectionHandled") { |
| localHandler(promise); |
| } else { |
| localHandler(reason, promise); |
| } |
| } |
| } catch (e) { |
| async.throwLater(e); |
| } |
| |
| if (name === "unhandledRejection") { |
| if (!activeFireEvent(name, reason, promise) && !localEventFired) { |
| formatAndLogError(reason, "Unhandled rejection "); |
| } |
| } else { |
| activeFireEvent(name, promise); |
| } |
| } |
| |
| function formatNonError(obj) { |
| var str; |
| if (typeof obj === "function") { |
| str = "[function " + |
| (obj.name || "anonymous") + |
| "]"; |
| } else { |
| str = obj && typeof obj.toString === "function" |
| ? obj.toString() : util.toString(obj); |
| var ruselessToString = /\[object [a-zA-Z0-9$_]+\]/; |
| if (ruselessToString.test(str)) { |
| try { |
| var newStr = JSON.stringify(obj); |
| str = newStr; |
| } |
| catch(e) { |
| |
| } |
| } |
| if (str.length === 0) { |
| str = "(empty array)"; |
| } |
| } |
| return ("(<" + snip(str) + ">, no stack trace)"); |
| } |
| |
| function snip(str) { |
| var maxChars = 41; |
| if (str.length < maxChars) { |
| return str; |
| } |
| return str.substr(0, maxChars - 3) + "..."; |
| } |
| |
| function longStackTracesIsSupported() { |
| return typeof captureStackTrace === "function"; |
| } |
| |
| var shouldIgnore = function() { return false; }; |
| var parseLineInfoRegex = /[\/<\(]([^:\/]+):(\d+):(?:\d+)\)?\s*$/; |
| function parseLineInfo(line) { |
| var matches = line.match(parseLineInfoRegex); |
| if (matches) { |
| return { |
| fileName: matches[1], |
| line: parseInt(matches[2], 10) |
| }; |
| } |
| } |
| |
| function setBounds(firstLineError, lastLineError) { |
| if (!longStackTracesIsSupported()) return; |
| var firstStackLines = (firstLineError.stack || "").split("\n"); |
| var lastStackLines = (lastLineError.stack || "").split("\n"); |
| var firstIndex = -1; |
| var lastIndex = -1; |
| var firstFileName; |
| var lastFileName; |
| for (var i = 0; i < firstStackLines.length; ++i) { |
| var result = parseLineInfo(firstStackLines[i]); |
| if (result) { |
| firstFileName = result.fileName; |
| firstIndex = result.line; |
| break; |
| } |
| } |
| for (var i = 0; i < lastStackLines.length; ++i) { |
| var result = parseLineInfo(lastStackLines[i]); |
| if (result) { |
| lastFileName = result.fileName; |
| lastIndex = result.line; |
| break; |
| } |
| } |
| if (firstIndex < 0 || lastIndex < 0 || !firstFileName || !lastFileName || |
| firstFileName !== lastFileName || firstIndex >= lastIndex) { |
| return; |
| } |
| |
| shouldIgnore = function(line) { |
| if (bluebirdFramePattern.test(line)) return true; |
| var info = parseLineInfo(line); |
| if (info) { |
| if (info.fileName === firstFileName && |
| (firstIndex <= info.line && info.line <= lastIndex)) { |
| return true; |
| } |
| } |
| return false; |
| }; |
| } |
| |
| function CapturedTrace(parent) { |
| this._parent = parent; |
| this._promisesCreated = 0; |
| var length = this._length = 1 + (parent === undefined ? 0 : parent._length); |
| captureStackTrace(this, CapturedTrace); |
| if (length > 32) this.uncycle(); |
| } |
| util.inherits(CapturedTrace, Error); |
| Context.CapturedTrace = CapturedTrace; |
| |
| CapturedTrace.prototype.uncycle = function() { |
| var length = this._length; |
| if (length < 2) return; |
| var nodes = []; |
| var stackToIndex = {}; |
| |
| for (var i = 0, node = this; node !== undefined; ++i) { |
| nodes.push(node); |
| node = node._parent; |
| } |
| length = this._length = i; |
| for (var i = length - 1; i >= 0; --i) { |
| var stack = nodes[i].stack; |
| if (stackToIndex[stack] === undefined) { |
| stackToIndex[stack] = i; |
| } |
| } |
| for (var i = 0; i < length; ++i) { |
| var currentStack = nodes[i].stack; |
| var index = stackToIndex[currentStack]; |
| if (index !== undefined && index !== i) { |
| if (index > 0) { |
| nodes[index - 1]._parent = undefined; |
| nodes[index - 1]._length = 1; |
| } |
| nodes[i]._parent = undefined; |
| nodes[i]._length = 1; |
| var cycleEdgeNode = i > 0 ? nodes[i - 1] : this; |
| |
| if (index < length - 1) { |
| cycleEdgeNode._parent = nodes[index + 1]; |
| cycleEdgeNode._parent.uncycle(); |
| cycleEdgeNode._length = |
| cycleEdgeNode._parent._length + 1; |
| } else { |
| cycleEdgeNode._parent = undefined; |
| cycleEdgeNode._length = 1; |
| } |
| var currentChildLength = cycleEdgeNode._length + 1; |
| for (var j = i - 2; j >= 0; --j) { |
| nodes[j]._length = currentChildLength; |
| currentChildLength++; |
| } |
| return; |
| } |
| } |
| }; |
| |
| CapturedTrace.prototype.attachExtraTrace = function(error) { |
| if (error.__stackCleaned__) return; |
| this.uncycle(); |
| var parsed = parseStackAndMessage(error); |
| var message = parsed.message; |
| var stacks = [parsed.stack]; |
| |
| var trace = this; |
| while (trace !== undefined) { |
| stacks.push(cleanStack(trace.stack.split("\n"))); |
| trace = trace._parent; |
| } |
| removeCommonRoots(stacks); |
| removeDuplicateOrEmptyJumps(stacks); |
| util.notEnumerableProp(error, "stack", reconstructStack(message, stacks)); |
| util.notEnumerableProp(error, "__stackCleaned__", true); |
| }; |
| |
| var captureStackTrace = (function stackDetection() { |
| var v8stackFramePattern = /^\s*at\s*/; |
| var v8stackFormatter = function(stack, error) { |
| if (typeof stack === "string") return stack; |
| |
| if (error.name !== undefined && |
| error.message !== undefined) { |
| return error.toString(); |
| } |
| return formatNonError(error); |
| }; |
| |
| if (typeof Error.stackTraceLimit === "number" && |
| typeof Error.captureStackTrace === "function") { |
| Error.stackTraceLimit += 6; |
| stackFramePattern = v8stackFramePattern; |
| formatStack = v8stackFormatter; |
| var captureStackTrace = Error.captureStackTrace; |
| |
| shouldIgnore = function(line) { |
| return bluebirdFramePattern.test(line); |
| }; |
| return function(receiver, ignoreUntil) { |
| Error.stackTraceLimit += 6; |
| captureStackTrace(receiver, ignoreUntil); |
| Error.stackTraceLimit -= 6; |
| }; |
| } |
| var err = new Error(); |
| |
| if (typeof err.stack === "string" && |
| err.stack.split("\n")[0].indexOf("stackDetection@") >= 0) { |
| stackFramePattern = /@/; |
| formatStack = v8stackFormatter; |
| indentStackFrames = true; |
| return function captureStackTrace(o) { |
| o.stack = new Error().stack; |
| }; |
| } |
| |
| var hasStackAfterThrow; |
| try { throw new Error(); } |
| catch(e) { |
| hasStackAfterThrow = ("stack" in e); |
| } |
| if (!("stack" in err) && hasStackAfterThrow && |
| typeof Error.stackTraceLimit === "number") { |
| stackFramePattern = v8stackFramePattern; |
| formatStack = v8stackFormatter; |
| return function captureStackTrace(o) { |
| Error.stackTraceLimit += 6; |
| try { throw new Error(); } |
| catch(e) { o.stack = e.stack; } |
| Error.stackTraceLimit -= 6; |
| }; |
| } |
| |
| formatStack = function(stack, error) { |
| if (typeof stack === "string") return stack; |
| |
| if ((typeof error === "object" || |
| typeof error === "function") && |
| error.name !== undefined && |
| error.message !== undefined) { |
| return error.toString(); |
| } |
| return formatNonError(error); |
| }; |
| |
| return null; |
| |
| })([]); |
| |
| if (typeof console !== "undefined" && typeof console.warn !== "undefined") { |
| printWarning = function (message) { |
| console.warn(message); |
| }; |
| if (util.isNode && process.stderr.isTTY) { |
| printWarning = function(message, isSoft) { |
| var color = isSoft ? "\u001b[33m" : "\u001b[31m"; |
| console.warn(color + message + "\u001b[0m\n"); |
| }; |
| } else if (!util.isNode && typeof (new Error().stack) === "string") { |
| printWarning = function(message, isSoft) { |
| console.warn("%c" + message, |
| isSoft ? "color: darkorange" : "color: red"); |
| }; |
| } |
| } |
| |
| var config = { |
| warnings: warnings, |
| longStackTraces: false, |
| cancellation: false, |
| monitoring: false, |
| asyncHooks: false |
| }; |
| |
| if (longStackTraces) Promise.longStackTraces(); |
| |
| return { |
| asyncHooks: function() { |
| return config.asyncHooks; |
| }, |
| longStackTraces: function() { |
| return config.longStackTraces; |
| }, |
| warnings: function() { |
| return config.warnings; |
| }, |
| cancellation: function() { |
| return config.cancellation; |
| }, |
| monitoring: function() { |
| return config.monitoring; |
| }, |
| propagateFromFunction: function() { |
| return propagateFromFunction; |
| }, |
| boundValueFunction: function() { |
| return boundValueFunction; |
| }, |
| checkForgottenReturns: checkForgottenReturns, |
| setBounds: setBounds, |
| warn: warn, |
| deprecated: deprecated, |
| CapturedTrace: CapturedTrace, |
| fireDomEvent: fireDomEvent, |
| fireGlobalEvent: fireGlobalEvent |
| }; |
| }; |