diff options
Diffstat (limited to 'node_modules/when/monitor/PromiseMonitor.js')
-rw-r--r-- | node_modules/when/monitor/PromiseMonitor.js | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/node_modules/when/monitor/PromiseMonitor.js b/node_modules/when/monitor/PromiseMonitor.js new file mode 100644 index 000000000..2becc0e3c --- /dev/null +++ b/node_modules/when/monitor/PromiseMonitor.js @@ -0,0 +1,197 @@ +/** @license MIT License (c) copyright 2010-2014 original author or authors */ +/** @author Brian Cavalier */ +/** @author John Hann */ + +(function(define) { 'use strict'; +define(function(require) { + + var defaultStackJumpSeparator = 'from execution context:'; + var defaultStackFilter = /[\s\(\/\\](node|module|timers)\.js:|when([\/\\]{1,2}(lib|monitor|es6-shim)[\/\\]{1,2}|\.js)|(new\sPromise)\b|(\b(PromiseMonitor|ConsoleReporter|Scheduler|RunHandlerTask|ProgressTask|Promise|.*Handler)\.[\w_]\w\w+\b)|\b(tryCatch\w+|getHandler\w*)\b/i; + + var setTimer = require('../lib/env').setTimer; + var error = require('./error'); + + var executionContext = []; + + function PromiseMonitor(reporter) { + this.logDelay = 0; + this.stackFilter = defaultStackFilter; + this.stackJumpSeparator = defaultStackJumpSeparator; + this.filterDuplicateFrames = true; + + this._reporter = reporter; + if(typeof reporter.configurePromiseMonitor === 'function') { + reporter.configurePromiseMonitor(this); + } + + this._traces = []; + this._traceTask = 0; + + var self = this; + this._doLogTraces = function() { + self._logTraces(); + }; + } + + PromiseMonitor.prototype.monitor = function(Promise) { + var self = this; + Promise.createContext = function(p, context) { + p.context = self.createContext(p, context); + }; + + Promise.enterContext = function(p) { + executionContext.push(p.context); + }; + + Promise.exitContext = function() { + executionContext.pop(); + }; + + Promise.onPotentiallyUnhandledRejection = function(rejection, extraContext) { + return self.addTrace(rejection, extraContext); + }; + + Promise.onPotentiallyUnhandledRejectionHandled = function(rejection) { + return self.removeTrace(rejection); + }; + + Promise.onFatalRejection = function(rejection, extraContext) { + return self.fatal(rejection, extraContext); + }; + + return this; + }; + + PromiseMonitor.prototype.createContext = function(at, parentContext) { + var context = { + parent: parentContext || executionContext[executionContext.length - 1], + stack: void 0 + }; + error.captureStack(context, at.constructor); + return context; + }; + + PromiseMonitor.prototype.addTrace = function(handler, extraContext) { + var t, i; + + for(i = this._traces.length-1; i >= 0; --i) { + t = this._traces[i]; + if(t.handler === handler) { + break; + } + } + + if(i >= 0) { + t.extraContext = extraContext; + } else { + this._traces.push({ + handler: handler, + extraContext: extraContext + }); + } + + this.logTraces(); + }; + + PromiseMonitor.prototype.removeTrace = function(/*handler*/) { + this.logTraces(); + }; + + PromiseMonitor.prototype.fatal = function(handler, extraContext) { + var err = new Error(); + err.stack = this._createLongTrace(handler.value, handler.context, extraContext).join('\n'); + setTimer(function() { + throw err; + }, 0); + }; + + PromiseMonitor.prototype.logTraces = function() { + if(!this._traceTask) { + this._traceTask = setTimer(this._doLogTraces, this.logDelay); + } + }; + + PromiseMonitor.prototype._logTraces = function() { + this._traceTask = void 0; + this._traces = this._traces.filter(filterHandled); + this._reporter.log(this.formatTraces(this._traces)); + }; + + + PromiseMonitor.prototype.formatTraces = function(traces) { + return traces.map(function(t) { + return this._createLongTrace(t.handler.value, t.handler.context, t.extraContext); + }, this); + }; + + PromiseMonitor.prototype._createLongTrace = function(e, context, extraContext) { + var trace = error.parse(e) || [String(e) + ' (WARNING: non-Error used)']; + trace = filterFrames(this.stackFilter, trace, 0); + this._appendContext(trace, context); + this._appendContext(trace, extraContext); + return this.filterDuplicateFrames ? this._removeDuplicates(trace) : trace; + }; + + PromiseMonitor.prototype._removeDuplicates = function(trace) { + var seen = {}; + var sep = this.stackJumpSeparator; + var count = 0; + return trace.reduceRight(function(deduped, line, i) { + if(i === 0) { + deduped.unshift(line); + } else if(line === sep) { + if(count > 0) { + deduped.unshift(line); + count = 0; + } + } else if(!seen[line]) { + seen[line] = true; + deduped.unshift(line); + ++count; + } + return deduped; + }, []); + }; + + PromiseMonitor.prototype._appendContext = function(trace, context) { + trace.push.apply(trace, this._createTrace(context)); + }; + + PromiseMonitor.prototype._createTrace = function(traceChain) { + var trace = []; + var stack; + + while(traceChain) { + stack = error.parse(traceChain); + + if (stack) { + stack = filterFrames(this.stackFilter, stack); + appendStack(trace, stack, this.stackJumpSeparator); + } + + traceChain = traceChain.parent; + } + + return trace; + }; + + function appendStack(trace, stack, separator) { + if (stack.length > 1) { + stack[0] = separator; + trace.push.apply(trace, stack); + } + } + + function filterFrames(stackFilter, stack) { + return stack.filter(function(frame) { + return !stackFilter.test(frame); + }); + } + + function filterHandled(t) { + return !t.handler.handled; + } + + return PromiseMonitor; +}); +}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); |