debuggability.js 26 KB

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