debuggability.js 29 KB

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