4c0568d21f9eafcb41a45178b99fff7bafb06365
[aai/esr-gui.git] /
1 "use strict";
2 module.exports = function(Promise,
3                           apiRejection,
4                           INTERNAL,
5                           tryConvertToPromise) {
6 var errors = require("./errors.js");
7 var TypeError = errors.TypeError;
8 var util = require("./util.js");
9 var errorObj = util.errorObj;
10 var tryCatch = util.tryCatch;
11 var yieldHandlers = [];
12
13 function promiseFromYieldHandler(value, yieldHandlers, traceParent) {
14     for (var i = 0; i < yieldHandlers.length; ++i) {
15         traceParent._pushContext();
16         var result = tryCatch(yieldHandlers[i])(value);
17         traceParent._popContext();
18         if (result === errorObj) {
19             traceParent._pushContext();
20             var ret = Promise.reject(errorObj.e);
21             traceParent._popContext();
22             return ret;
23         }
24         var maybePromise = tryConvertToPromise(result, traceParent);
25         if (maybePromise instanceof Promise) return maybePromise;
26     }
27     return null;
28 }
29
30 function PromiseSpawn(generatorFunction, receiver, yieldHandler, stack) {
31     var promise = this._promise = new Promise(INTERNAL);
32     promise._captureStackTrace();
33     this._stack = stack;
34     this._generatorFunction = generatorFunction;
35     this._receiver = receiver;
36     this._generator = undefined;
37     this._yieldHandlers = typeof yieldHandler === "function"
38         ? [yieldHandler].concat(yieldHandlers)
39         : yieldHandlers;
40 }
41
42 PromiseSpawn.prototype.promise = function () {
43     return this._promise;
44 };
45
46 PromiseSpawn.prototype._run = function () {
47     this._generator = this._generatorFunction.call(this._receiver);
48     this._receiver =
49         this._generatorFunction = undefined;
50     this._next(undefined);
51 };
52
53 PromiseSpawn.prototype._continue = function (result) {
54     if (result === errorObj) {
55         return this._promise._rejectCallback(result.e, false, true);
56     }
57
58     var value = result.value;
59     if (result.done === true) {
60         this._promise._resolveCallback(value);
61     } else {
62         var maybePromise = tryConvertToPromise(value, this._promise);
63         if (!(maybePromise instanceof Promise)) {
64             maybePromise =
65                 promiseFromYieldHandler(maybePromise,
66                                         this._yieldHandlers,
67                                         this._promise);
68             if (maybePromise === null) {
69                 this._throw(
70                     new TypeError(
71                         "A value %s was yielded that could not be treated as a promise\u000a\u000a    See http://goo.gl/4Y4pDk\u000a\u000a".replace("%s", value) +
72                         "From coroutine:\u000a" +
73                         this._stack.split("\n").slice(1, -7).join("\n")
74                     )
75                 );
76                 return;
77             }
78         }
79         maybePromise._then(
80             this._next,
81             this._throw,
82             undefined,
83             this,
84             null
85        );
86     }
87 };
88
89 PromiseSpawn.prototype._throw = function (reason) {
90     this._promise._attachExtraTrace(reason);
91     this._promise._pushContext();
92     var result = tryCatch(this._generator["throw"])
93         .call(this._generator, reason);
94     this._promise._popContext();
95     this._continue(result);
96 };
97
98 PromiseSpawn.prototype._next = function (value) {
99     this._promise._pushContext();
100     var result = tryCatch(this._generator.next).call(this._generator, value);
101     this._promise._popContext();
102     this._continue(result);
103 };
104
105 Promise.coroutine = function (generatorFunction, options) {
106     if (typeof generatorFunction !== "function") {
107         throw new TypeError("generatorFunction must be a function\u000a\u000a    See http://goo.gl/6Vqhm0\u000a");
108     }
109     var yieldHandler = Object(options).yieldHandler;
110     var PromiseSpawn$ = PromiseSpawn;
111     var stack = new Error().stack;
112     return function () {
113         var generator = generatorFunction.apply(this, arguments);
114         var spawn = new PromiseSpawn$(undefined, undefined, yieldHandler,
115                                       stack);
116         spawn._generator = generator;
117         spawn._next(undefined);
118         return spawn.promise();
119     };
120 };
121
122 Promise.coroutine.addYieldHandler = function(fn) {
123     if (typeof fn !== "function") throw new TypeError("fn must be a function\u000a\u000a    See http://goo.gl/916lJJ\u000a");
124     yieldHandlers.push(fn);
125 };
126
127 Promise.spawn = function (generatorFunction) {
128     if (typeof generatorFunction !== "function") {
129         return apiRejection("generatorFunction must be a function\u000a\u000a    See http://goo.gl/6Vqhm0\u000a");
130     }
131     var spawn = new PromiseSpawn(generatorFunction, this);
132     var ret = spawn.promise();
133     spawn._run(Promise.spawn);
134     return ret;
135 };
136 };