debuggability.js 29 KB

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