1"use strict"; 2module.exports = function(Promise, Context) { 3var getDomain = Promise._getDomain; 4var async = Promise._async; 5var Warning = require("./errors").Warning; 6var util = require("./util"); 7var es5 = require("./es5"); 8var canAttachTrace = util.canAttachTrace; 9var unhandledRejectionHandled; 10var possiblyUnhandledRejection; 11var bluebirdFramePattern = 12 /[\\\/]bluebird[\\\/]js[\\\/](release|debug|instrumented)/; 13var nodeFramePattern = /\((?:timers\.js):\d+:\d+\)/; 14var parseLinePattern = /[\/<\(](.+?):(\d+):(\d+)\)?\s*$/; 15var stackFramePattern = null; 16var formatStack = null; 17var indentStackFrames = false; 18var printWarning; 19var debugging = !!(util.env("BLUEBIRD_DEBUG") != 0 && 20 (false || 21 util.env("BLUEBIRD_DEBUG") || 22 util.env("NODE_ENV") === "development")); 23 24var warnings = !!(util.env("BLUEBIRD_WARNINGS") != 0 && 25 (debugging || util.env("BLUEBIRD_WARNINGS"))); 26 27var longStackTraces = !!(util.env("BLUEBIRD_LONG_STACK_TRACES") != 0 && 28 (debugging || util.env("BLUEBIRD_LONG_STACK_TRACES"))); 29 30var wForgottenReturn = util.env("BLUEBIRD_W_FORGOTTEN_RETURN") != 0 && 31 (warnings || !!util.env("BLUEBIRD_W_FORGOTTEN_RETURN")); 32 33Promise.prototype.suppressUnhandledRejections = function() { 34 var target = this._target(); 35 target._bitField = ((target._bitField & (~1048576)) | 36 524288); 37}; 38 39Promise.prototype._ensurePossibleRejectionHandled = function () { 40 if ((this._bitField & 524288) !== 0) return; 41 this._setRejectionIsUnhandled(); 42 var self = this; 43 setTimeout(function() { 44 self._notifyUnhandledRejection(); 45 }, 1); 46}; 47 48Promise.prototype._notifyUnhandledRejectionIsHandled = function () { 49 fireRejectionEvent("rejectionHandled", 50 unhandledRejectionHandled, undefined, this); 51}; 52 53Promise.prototype._setReturnedNonUndefined = function() { 54 this._bitField = this._bitField | 268435456; 55}; 56 57Promise.prototype._returnedNonUndefined = function() { 58 return (this._bitField & 268435456) !== 0; 59}; 60 61Promise.prototype._notifyUnhandledRejection = function () { 62 if (this._isRejectionUnhandled()) { 63 var reason = this._settledValue(); 64 this._setUnhandledRejectionIsNotified(); 65 fireRejectionEvent("unhandledRejection", 66 possiblyUnhandledRejection, reason, this); 67 } 68}; 69 70Promise.prototype._setUnhandledRejectionIsNotified = function () { 71 this._bitField = this._bitField | 262144; 72}; 73 74Promise.prototype._unsetUnhandledRejectionIsNotified = function () { 75 this._bitField = this._bitField & (~262144); 76}; 77 78Promise.prototype._isUnhandledRejectionNotified = function () { 79 return (this._bitField & 262144) > 0; 80}; 81 82Promise.prototype._setRejectionIsUnhandled = function () { 83 this._bitField = this._bitField | 1048576; 84}; 85 86Promise.prototype._unsetRejectionIsUnhandled = function () { 87 this._bitField = this._bitField & (~1048576); 88 if (this._isUnhandledRejectionNotified()) { 89 this._unsetUnhandledRejectionIsNotified(); 90 this._notifyUnhandledRejectionIsHandled(); 91 } 92}; 93 94Promise.prototype._isRejectionUnhandled = function () { 95 return (this._bitField & 1048576) > 0; 96}; 97 98Promise.prototype._warn = function(message, shouldUseOwnTrace, promise) { 99 return warn(message, shouldUseOwnTrace, promise || this); 100}; 101 102Promise.onPossiblyUnhandledRejection = function (fn) { 103 var domain = getDomain(); 104 possiblyUnhandledRejection = 105 typeof fn === "function" ? (domain === null ? 106 fn : util.domainBind(domain, fn)) 107 : undefined; 108}; 109 110Promise.onUnhandledRejectionHandled = function (fn) { 111 var domain = getDomain(); 112 unhandledRejectionHandled = 113 typeof fn === "function" ? (domain === null ? 114 fn : util.domainBind(domain, fn)) 115 : undefined; 116}; 117 118var disableLongStackTraces = function() {}; 119Promise.longStackTraces = function () { 120 if (async.haveItemsQueued() && !config.longStackTraces) { 121 throw new Error("cannot enable long stack traces after promises have been created\u000a\u000a See http://goo.gl/MqrFmX\u000a"); 122 } 123 if (!config.longStackTraces && longStackTracesIsSupported()) { 124 var Promise_captureStackTrace = Promise.prototype._captureStackTrace; 125 var Promise_attachExtraTrace = Promise.prototype._attachExtraTrace; 126 var Promise_dereferenceTrace = Promise.prototype._dereferenceTrace; 127 config.longStackTraces = true; 128 disableLongStackTraces = function() { 129 if (async.haveItemsQueued() && !config.longStackTraces) { 130 throw new Error("cannot enable long stack traces after promises have been created\u000a\u000a See http://goo.gl/MqrFmX\u000a"); 131 } 132 Promise.prototype._captureStackTrace = Promise_captureStackTrace; 133 Promise.prototype._attachExtraTrace = Promise_attachExtraTrace; 134 Promise.prototype._dereferenceTrace = Promise_dereferenceTrace; 135 Context.deactivateLongStackTraces(); 136 async.enableTrampoline(); 137 config.longStackTraces = false; 138 }; 139 Promise.prototype._captureStackTrace = longStackTracesCaptureStackTrace; 140 Promise.prototype._attachExtraTrace = longStackTracesAttachExtraTrace; 141 Promise.prototype._dereferenceTrace = longStackTracesDereferenceTrace; 142 Context.activateLongStackTraces(); 143 async.disableTrampolineIfNecessary(); 144 } 145}; 146 147Promise.hasLongStackTraces = function () { 148 return config.longStackTraces && longStackTracesIsSupported(); 149}; 150 151var fireDomEvent = (function() { 152 try { 153 if (typeof CustomEvent === "function") { 154 var event = new CustomEvent("CustomEvent"); 155 util.global.dispatchEvent(event); 156 return function(name, event) { 157 var eventData = { 158 detail: event, 159 cancelable: true 160 }; 161 es5.defineProperty( 162 eventData, "promise", {value: event.promise}); 163 es5.defineProperty(eventData, "reason", {value: event.reason}); 164 var domEvent = new CustomEvent(name.toLowerCase(), eventData); 165 return !util.global.dispatchEvent(domEvent); 166 }; 167 } else if (typeof Event === "function") { 168 var event = new Event("CustomEvent"); 169 util.global.dispatchEvent(event); 170 return function(name, event) { 171 var domEvent = new Event(name.toLowerCase(), { 172 cancelable: true 173 }); 174 domEvent.detail = event; 175 es5.defineProperty(domEvent, "promise", {value: event.promise}); 176 es5.defineProperty(domEvent, "reason", {value: event.reason}); 177 return !util.global.dispatchEvent(domEvent); 178 }; 179 } else { 180 var event = document.createEvent("CustomEvent"); 181 event.initCustomEvent("testingtheevent", false, true, {}); 182 util.global.dispatchEvent(event); 183 return function(name, event) { 184 var domEvent = document.createEvent("CustomEvent"); 185 domEvent.initCustomEvent(name.toLowerCase(), false, true, 186 event); 187 return !util.global.dispatchEvent(domEvent); 188 }; 189 } 190 } catch (e) {} 191 return function() { 192 return false; 193 }; 194})(); 195 196var fireGlobalEvent = (function() { 197 if (util.isNode) { 198 return function() { 199 return process.emit.apply(process, arguments); 200 }; 201 } else { 202 if (!util.global) { 203 return function() { 204 return false; 205 }; 206 } 207 return function(name) { 208 var methodName = "on" + name.toLowerCase(); 209 var method = util.global[methodName]; 210 if (!method) return false; 211 method.apply(util.global, [].slice.call(arguments, 1)); 212 return true; 213 }; 214 } 215})(); 216 217function generatePromiseLifecycleEventObject(name, promise) { 218 return {promise: promise}; 219} 220 221var eventToObjectGenerator = { 222 promiseCreated: generatePromiseLifecycleEventObject, 223 promiseFulfilled: generatePromiseLifecycleEventObject, 224 promiseRejected: generatePromiseLifecycleEventObject, 225 promiseResolved: generatePromiseLifecycleEventObject, 226 promiseCancelled: generatePromiseLifecycleEventObject, 227 promiseChained: function(name, promise, child) { 228 return {promise: promise, child: child}; 229 }, 230 warning: function(name, warning) { 231 return {warning: warning}; 232 }, 233 unhandledRejection: function (name, reason, promise) { 234 return {reason: reason, promise: promise}; 235 }, 236 rejectionHandled: generatePromiseLifecycleEventObject 237}; 238 239var activeFireEvent = function (name) { 240 var globalEventFired = false; 241 try { 242 globalEventFired = fireGlobalEvent.apply(null, arguments); 243 } catch (e) { 244 async.throwLater(e); 245 globalEventFired = true; 246 } 247 248 var domEventFired = false; 249 try { 250 domEventFired = fireDomEvent(name, 251 eventToObjectGenerator[name].apply(null, arguments)); 252 } catch (e) { 253 async.throwLater(e); 254 domEventFired = true; 255 } 256 257 return domEventFired || globalEventFired; 258}; 259 260Promise.config = function(opts) { 261 opts = Object(opts); 262 if ("longStackTraces" in opts) { 263 if (opts.longStackTraces) { 264 Promise.longStackTraces(); 265 } else if (!opts.longStackTraces && Promise.hasLongStackTraces()) { 266 disableLongStackTraces(); 267 } 268 } 269 if ("warnings" in opts) { 270 var warningsOption = opts.warnings; 271 config.warnings = !!warningsOption; 272 wForgottenReturn = config.warnings; 273 274 if (util.isObject(warningsOption)) { 275 if ("wForgottenReturn" in warningsOption) { 276 wForgottenReturn = !!warningsOption.wForgottenReturn; 277 } 278 } 279 } 280 if ("cancellation" in opts && opts.cancellation && !config.cancellation) { 281 if (async.haveItemsQueued()) { 282 throw new Error( 283 "cannot enable cancellation after promises are in use"); 284 } 285 Promise.prototype._clearCancellationData = 286 cancellationClearCancellationData; 287 Promise.prototype._propagateFrom = cancellationPropagateFrom; 288 Promise.prototype._onCancel = cancellationOnCancel; 289 Promise.prototype._setOnCancel = cancellationSetOnCancel; 290 Promise.prototype._attachCancellationCallback = 291 cancellationAttachCancellationCallback; 292 Promise.prototype._execute = cancellationExecute; 293 propagateFromFunction = cancellationPropagateFrom; 294 config.cancellation = true; 295 } 296 if ("monitoring" in opts) { 297 if (opts.monitoring && !config.monitoring) { 298 config.monitoring = true; 299 Promise.prototype._fireEvent = activeFireEvent; 300 } else if (!opts.monitoring && config.monitoring) { 301 config.monitoring = false; 302 Promise.prototype._fireEvent = defaultFireEvent; 303 } 304 } 305 return Promise; 306}; 307 308function defaultFireEvent() { return false; } 309 310Promise.prototype._fireEvent = defaultFireEvent; 311Promise.prototype._execute = function(executor, resolve, reject) { 312 try { 313 executor(resolve, reject); 314 } catch (e) { 315 return e; 316 } 317}; 318Promise.prototype._onCancel = function () {}; 319Promise.prototype._setOnCancel = function (handler) { ; }; 320Promise.prototype._attachCancellationCallback = function(onCancel) { 321 ; 322}; 323Promise.prototype._captureStackTrace = function () {}; 324Promise.prototype._attachExtraTrace = function () {}; 325Promise.prototype._dereferenceTrace = function () {}; 326Promise.prototype._clearCancellationData = function() {}; 327Promise.prototype._propagateFrom = function (parent, flags) { 328 ; 329 ; 330}; 331 332function cancellationExecute(executor, resolve, reject) { 333 var promise = this; 334 try { 335 executor(resolve, reject, function(onCancel) { 336 if (typeof onCancel !== "function") { 337 throw new TypeError("onCancel must be a function, got: " + 338 util.toString(onCancel)); 339 } 340 promise._attachCancellationCallback(onCancel); 341 }); 342 } catch (e) { 343 return e; 344 } 345} 346 347function cancellationAttachCancellationCallback(onCancel) { 348 if (!this._isCancellable()) return this; 349 350 var previousOnCancel = this._onCancel(); 351 if (previousOnCancel !== undefined) { 352 if (util.isArray(previousOnCancel)) { 353 previousOnCancel.push(onCancel); 354 } else { 355 this._setOnCancel([previousOnCancel, onCancel]); 356 } 357 } else { 358 this._setOnCancel(onCancel); 359 } 360} 361 362function cancellationOnCancel() { 363 return this._onCancelField; 364} 365 366function cancellationSetOnCancel(onCancel) { 367 this._onCancelField = onCancel; 368} 369 370function cancellationClearCancellationData() { 371 this._cancellationParent = undefined; 372 this._onCancelField = undefined; 373} 374 375function cancellationPropagateFrom(parent, flags) { 376 if ((flags & 1) !== 0) { 377 this._cancellationParent = parent; 378 var branchesRemainingToCancel = parent._branchesRemainingToCancel; 379 if (branchesRemainingToCancel === undefined) { 380 branchesRemainingToCancel = 0; 381 } 382 parent._branchesRemainingToCancel = branchesRemainingToCancel + 1; 383 } 384 if ((flags & 2) !== 0 && parent._isBound()) { 385 this._setBoundTo(parent._boundTo); 386 } 387} 388 389function bindingPropagateFrom(parent, flags) { 390 if ((flags & 2) !== 0 && parent._isBound()) { 391 this._setBoundTo(parent._boundTo); 392 } 393} 394var propagateFromFunction = bindingPropagateFrom; 395 396function boundValueFunction() { 397 var ret = this._boundTo; 398 if (ret !== undefined) { 399 if (ret instanceof Promise) { 400 if (ret.isFulfilled()) { 401 return ret.value(); 402 } else { 403 return undefined; 404 } 405 } 406 } 407 return ret; 408} 409 410function longStackTracesCaptureStackTrace() { 411 this._trace = new CapturedTrace(this._peekContext()); 412} 413 414function longStackTracesAttachExtraTrace(error, ignoreSelf) { 415 if (canAttachTrace(error)) { 416 var trace = this._trace; 417 if (trace !== undefined) { 418 if (ignoreSelf) trace = trace._parent; 419 } 420 if (trace !== undefined) { 421 trace.attachExtraTrace(error); 422 } else if (!error.__stackCleaned__) { 423 var parsed = parseStackAndMessage(error); 424 util.notEnumerableProp(error, "stack", 425 parsed.message + "\n" + parsed.stack.join("\n")); 426 util.notEnumerableProp(error, "__stackCleaned__", true); 427 } 428 } 429} 430 431function longStackTracesDereferenceTrace() { 432 this._trace = undefined; 433} 434 435function checkForgottenReturns(returnValue, promiseCreated, name, promise, 436 parent) { 437 if (returnValue === undefined && promiseCreated !== null && 438 wForgottenReturn) { 439 if (parent !== undefined && parent._returnedNonUndefined()) return; 440 if ((promise._bitField & 65535) === 0) return; 441 442 if (name) name = name + " "; 443 var handlerLine = ""; 444 var creatorLine = ""; 445 if (promiseCreated._trace) { 446 var traceLines = promiseCreated._trace.stack.split("\n"); 447 var stack = cleanStack(traceLines); 448 for (var i = stack.length - 1; i >= 0; --i) { 449 var line = stack[i]; 450 if (!nodeFramePattern.test(line)) { 451 var lineMatches = line.match(parseLinePattern); 452 if (lineMatches) { 453 handlerLine = "at " + lineMatches[1] + 454 ":" + lineMatches[2] + ":" + lineMatches[3] + " "; 455 } 456 break; 457 } 458 } 459 460 if (stack.length > 0) { 461 var firstUserLine = stack[0]; 462 for (var i = 0; i < traceLines.length; ++i) { 463 464 if (traceLines[i] === firstUserLine) { 465 if (i > 0) { 466 creatorLine = "\n" + traceLines[i - 1]; 467 } 468 break; 469 } 470 } 471 472 } 473 } 474 var msg = "a promise was created in a " + name + 475 "handler " + handlerLine + "but was not returned from it, " + 476 "see http://goo.gl/rRqMUw" + 477 creatorLine; 478 promise._warn(msg, true, promiseCreated); 479 } 480} 481 482function deprecated(name, replacement) { 483 var message = name + 484 " is deprecated and will be removed in a future version."; 485 if (replacement) message += " Use " + replacement + " instead."; 486 return warn(message); 487} 488 489function warn(message, shouldUseOwnTrace, promise) { 490 if (!config.warnings) return; 491 var warning = new Warning(message); 492 var ctx; 493 if (shouldUseOwnTrace) { 494 promise._attachExtraTrace(warning); 495 } else if (config.longStackTraces && (ctx = Promise._peekContext())) { 496 ctx.attachExtraTrace(warning); 497 } else { 498 var parsed = parseStackAndMessage(warning); 499 warning.stack = parsed.message + "\n" + parsed.stack.join("\n"); 500 } 501 502 if (!activeFireEvent("warning", warning)) { 503 formatAndLogError(warning, "", true); 504 } 505} 506 507function reconstructStack(message, stacks) { 508 for (var i = 0; i < stacks.length - 1; ++i) { 509 stacks[i].push("From previous event:"); 510 stacks[i] = stacks[i].join("\n"); 511 } 512 if (i < stacks.length) { 513 stacks[i] = stacks[i].join("\n"); 514 } 515 return message + "\n" + stacks.join("\n"); 516} 517 518function removeDuplicateOrEmptyJumps(stacks) { 519 for (var i = 0; i < stacks.length; ++i) { 520 if (stacks[i].length === 0 || 521 ((i + 1 < stacks.length) && stacks[i][0] === stacks[i+1][0])) { 522 stacks.splice(i, 1); 523 i--; 524 } 525 } 526} 527 528function removeCommonRoots(stacks) { 529 var current = stacks[0]; 530 for (var i = 1; i < stacks.length; ++i) { 531 var prev = stacks[i]; 532 var currentLastIndex = current.length - 1; 533 var currentLastLine = current[currentLastIndex]; 534 var commonRootMeetPoint = -1; 535 536 for (var j = prev.length - 1; j >= 0; --j) { 537 if (prev[j] === currentLastLine) { 538 commonRootMeetPoint = j; 539 break; 540 } 541 } 542 543 for (var j = commonRootMeetPoint; j >= 0; --j) { 544 var line = prev[j]; 545 if (current[currentLastIndex] === line) { 546 current.pop(); 547 currentLastIndex--; 548 } else { 549 break; 550 } 551 } 552 current = prev; 553 } 554} 555 556function cleanStack(stack) { 557 var ret = []; 558 for (var i = 0; i < stack.length; ++i) { 559 var line = stack[i]; 560 var isTraceLine = " (No stack trace)" === line || 561 stackFramePattern.test(line); 562 var isInternalFrame = isTraceLine && shouldIgnore(line); 563 if (isTraceLine && !isInternalFrame) { 564 if (indentStackFrames && line.charAt(0) !== " ") { 565 line = " " + line; 566 } 567 ret.push(line); 568 } 569 } 570 return ret; 571} 572 573function stackFramesAsArray(error) { 574 var stack = error.stack.replace(/\s+$/g, "").split("\n"); 575 for (var i = 0; i < stack.length; ++i) { 576 var line = stack[i]; 577 if (" (No stack trace)" === line || stackFramePattern.test(line)) { 578 break; 579 } 580 } 581 if (i > 0 && error.name != "SyntaxError") { 582 stack = stack.slice(i); 583 } 584 return stack; 585} 586 587function parseStackAndMessage(error) { 588 var stack = error.stack; 589 var message = error.toString(); 590 stack = typeof stack === "string" && stack.length > 0 591 ? stackFramesAsArray(error) : [" (No stack trace)"]; 592 return { 593 message: message, 594 stack: error.name == "SyntaxError" ? stack : cleanStack(stack) 595 }; 596} 597 598function formatAndLogError(error, title, isSoft) { 599 if (typeof console !== "undefined") { 600 var message; 601 if (util.isObject(error)) { 602 var stack = error.stack; 603 message = title + formatStack(stack, error); 604 } else { 605 message = title + String(error); 606 } 607 if (typeof printWarning === "function") { 608 printWarning(message, isSoft); 609 } else if (typeof console.log === "function" || 610 typeof console.log === "object") { 611 console.log(message); 612 } 613 } 614} 615 616function fireRejectionEvent(name, localHandler, reason, promise) { 617 var localEventFired = false; 618 try { 619 if (typeof localHandler === "function") { 620 localEventFired = true; 621 if (name === "rejectionHandled") { 622 localHandler(promise); 623 } else { 624 localHandler(reason, promise); 625 } 626 } 627 } catch (e) { 628 async.throwLater(e); 629 } 630 631 if (name === "unhandledRejection") { 632 if (!activeFireEvent(name, reason, promise) && !localEventFired) { 633 formatAndLogError(reason, "Unhandled rejection "); 634 } 635 } else { 636 activeFireEvent(name, promise); 637 } 638} 639 640function formatNonError(obj) { 641 var str; 642 if (typeof obj === "function") { 643 str = "[function " + 644 (obj.name || "anonymous") + 645 "]"; 646 } else { 647 str = obj && typeof obj.toString === "function" 648 ? obj.toString() : util.toString(obj); 649 var ruselessToString = /\[object [a-zA-Z0-9$_]+\]/; 650 if (ruselessToString.test(str)) { 651 try { 652 var newStr = JSON.stringify(obj); 653 str = newStr; 654 } 655 catch(e) { 656 657 } 658 } 659 if (str.length === 0) { 660 str = "(empty array)"; 661 } 662 } 663 return ("(<" + snip(str) + ">, no stack trace)"); 664} 665 666function snip(str) { 667 var maxChars = 41; 668 if (str.length < maxChars) { 669 return str; 670 } 671 return str.substr(0, maxChars - 3) + "..."; 672} 673 674function longStackTracesIsSupported() { 675 return typeof captureStackTrace === "function"; 676} 677 678var shouldIgnore = function() { return false; }; 679var parseLineInfoRegex = /[\/<\(]([^:\/]+):(\d+):(?:\d+)\)?\s*$/; 680function parseLineInfo(line) { 681 var matches = line.match(parseLineInfoRegex); 682 if (matches) { 683 return { 684 fileName: matches[1], 685 line: parseInt(matches[2], 10) 686 }; 687 } 688} 689 690function setBounds(firstLineError, lastLineError) { 691 if (!longStackTracesIsSupported()) return; 692 var firstStackLines = (firstLineError.stack || "").split("\n"); 693 var lastStackLines = (lastLineError.stack || "").split("\n"); 694 var firstIndex = -1; 695 var lastIndex = -1; 696 var firstFileName; 697 var lastFileName; 698 for (var i = 0; i < firstStackLines.length; ++i) { 699 var result = parseLineInfo(firstStackLines[i]); 700 if (result) { 701 firstFileName = result.fileName; 702 firstIndex = result.line; 703 break; 704 } 705 } 706 for (var i = 0; i < lastStackLines.length; ++i) { 707 var result = parseLineInfo(lastStackLines[i]); 708 if (result) { 709 lastFileName = result.fileName; 710 lastIndex = result.line; 711 break; 712 } 713 } 714 if (firstIndex < 0 || lastIndex < 0 || !firstFileName || !lastFileName || 715 firstFileName !== lastFileName || firstIndex >= lastIndex) { 716 return; 717 } 718 719 shouldIgnore = function(line) { 720 if (bluebirdFramePattern.test(line)) return true; 721 var info = parseLineInfo(line); 722 if (info) { 723 if (info.fileName === firstFileName && 724 (firstIndex <= info.line && info.line <= lastIndex)) { 725 return true; 726 } 727 } 728 return false; 729 }; 730} 731 732function CapturedTrace(parent) { 733 this._parent = parent; 734 this._promisesCreated = 0; 735 var length = this._length = 1 + (parent === undefined ? 0 : parent._length); 736 captureStackTrace(this, CapturedTrace); 737 if (length > 32) this.uncycle(); 738} 739util.inherits(CapturedTrace, Error); 740Context.CapturedTrace = CapturedTrace; 741 742CapturedTrace.prototype.uncycle = function() { 743 var length = this._length; 744 if (length < 2) return; 745 var nodes = []; 746 var stackToIndex = {}; 747 748 for (var i = 0, node = this; node !== undefined; ++i) { 749 nodes.push(node); 750 node = node._parent; 751 } 752 length = this._length = i; 753 for (var i = length - 1; i >= 0; --i) { 754 var stack = nodes[i].stack; 755 if (stackToIndex[stack] === undefined) { 756 stackToIndex[stack] = i; 757 } 758 } 759 for (var i = 0; i < length; ++i) { 760 var currentStack = nodes[i].stack; 761 var index = stackToIndex[currentStack]; 762 if (index !== undefined && index !== i) { 763 if (index > 0) { 764 nodes[index - 1]._parent = undefined; 765 nodes[index - 1]._length = 1; 766 } 767 nodes[i]._parent = undefined; 768 nodes[i]._length = 1; 769 var cycleEdgeNode = i > 0 ? nodes[i - 1] : this; 770 771 if (index < length - 1) { 772 cycleEdgeNode._parent = nodes[index + 1]; 773 cycleEdgeNode._parent.uncycle(); 774 cycleEdgeNode._length = 775 cycleEdgeNode._parent._length + 1; 776 } else { 777 cycleEdgeNode._parent = undefined; 778 cycleEdgeNode._length = 1; 779 } 780 var currentChildLength = cycleEdgeNode._length + 1; 781 for (var j = i - 2; j >= 0; --j) { 782 nodes[j]._length = currentChildLength; 783 currentChildLength++; 784 } 785 return; 786 } 787 } 788}; 789 790CapturedTrace.prototype.attachExtraTrace = function(error) { 791 if (error.__stackCleaned__) return; 792 this.uncycle(); 793 var parsed = parseStackAndMessage(error); 794 var message = parsed.message; 795 var stacks = [parsed.stack]; 796 797 var trace = this; 798 while (trace !== undefined) { 799 stacks.push(cleanStack(trace.stack.split("\n"))); 800 trace = trace._parent; 801 } 802 removeCommonRoots(stacks); 803 removeDuplicateOrEmptyJumps(stacks); 804 util.notEnumerableProp(error, "stack", reconstructStack(message, stacks)); 805 util.notEnumerableProp(error, "__stackCleaned__", true); 806}; 807 808var captureStackTrace = (function stackDetection() { 809 var v8stackFramePattern = /^\s*at\s*/; 810 var v8stackFormatter = function(stack, error) { 811 if (typeof stack === "string") return stack; 812 813 if (error.name !== undefined && 814 error.message !== undefined) { 815 return error.toString(); 816 } 817 return formatNonError(error); 818 }; 819 820 if (typeof Error.stackTraceLimit === "number" && 821 typeof Error.captureStackTrace === "function") { 822 Error.stackTraceLimit += 6; 823 stackFramePattern = v8stackFramePattern; 824 formatStack = v8stackFormatter; 825 var captureStackTrace = Error.captureStackTrace; 826 827 shouldIgnore = function(line) { 828 return bluebirdFramePattern.test(line); 829 }; 830 return function(receiver, ignoreUntil) { 831 Error.stackTraceLimit += 6; 832 captureStackTrace(receiver, ignoreUntil); 833 Error.stackTraceLimit -= 6; 834 }; 835 } 836 var err = new Error(); 837 838 if (typeof err.stack === "string" && 839 err.stack.split("\n")[0].indexOf("stackDetection@") >= 0) { 840 stackFramePattern = /@/; 841 formatStack = v8stackFormatter; 842 indentStackFrames = true; 843 return function captureStackTrace(o) { 844 o.stack = new Error().stack; 845 }; 846 } 847 848 var hasStackAfterThrow; 849 try { throw new Error(); } 850 catch(e) { 851 hasStackAfterThrow = ("stack" in e); 852 } 853 if (!("stack" in err) && hasStackAfterThrow && 854 typeof Error.stackTraceLimit === "number") { 855 stackFramePattern = v8stackFramePattern; 856 formatStack = v8stackFormatter; 857 return function captureStackTrace(o) { 858 Error.stackTraceLimit += 6; 859 try { throw new Error(); } 860 catch(e) { o.stack = e.stack; } 861 Error.stackTraceLimit -= 6; 862 }; 863 } 864 865 formatStack = function(stack, error) { 866 if (typeof stack === "string") return stack; 867 868 if ((typeof error === "object" || 869 typeof error === "function") && 870 error.name !== undefined && 871 error.message !== undefined) { 872 return error.toString(); 873 } 874 return formatNonError(error); 875 }; 876 877 return null; 878 879})([]); 880 881if (typeof console !== "undefined" && typeof console.warn !== "undefined") { 882 printWarning = function (message) { 883 console.warn(message); 884 }; 885 if (util.isNode && process.stderr.isTTY) { 886 printWarning = function(message, isSoft) { 887 var color = isSoft ? "\u001b[33m" : "\u001b[31m"; 888 console.warn(color + message + "\u001b[0m\n"); 889 }; 890 } else if (!util.isNode && typeof (new Error().stack) === "string") { 891 printWarning = function(message, isSoft) { 892 console.warn("%c" + message, 893 isSoft ? "color: darkorange" : "color: red"); 894 }; 895 } 896} 897 898var config = { 899 warnings: warnings, 900 longStackTraces: false, 901 cancellation: false, 902 monitoring: false 903}; 904 905if (longStackTraces) Promise.longStackTraces(); 906 907return { 908 longStackTraces: function() { 909 return config.longStackTraces; 910 }, 911 warnings: function() { 912 return config.warnings; 913 }, 914 cancellation: function() { 915 return config.cancellation; 916 }, 917 monitoring: function() { 918 return config.monitoring; 919 }, 920 propagateFromFunction: function() { 921 return propagateFromFunction; 922 }, 923 boundValueFunction: function() { 924 return boundValueFunction; 925 }, 926 checkForgottenReturns: checkForgottenReturns, 927 setBounds: setBounds, 928 warn: warn, 929 deprecated: deprecated, 930 CapturedTrace: CapturedTrace, 931 fireDomEvent: fireDomEvent, 932 fireGlobalEvent: fireGlobalEvent 933}; 934}; 935