Version 1
[yaffs-website] / node_modules / bluebird / js / release / generators.js
1 "use strict";
2 module.exports = function(Promise,
3                           apiRejection,
4                           INTERNAL,
5                           tryConvertToPromise,
6                           Proxyable,
7                           debug) {
8 var errors = require("./errors");
9 var TypeError = errors.TypeError;
10 var util = require("./util");
11 var errorObj = util.errorObj;
12 var tryCatch = util.tryCatch;
13 var yieldHandlers = [];
14
15 function promiseFromYieldHandler(value, yieldHandlers, traceParent) {
16     for (var i = 0; i < yieldHandlers.length; ++i) {
17         traceParent._pushContext();
18         var result = tryCatch(yieldHandlers[i])(value);
19         traceParent._popContext();
20         if (result === errorObj) {
21             traceParent._pushContext();
22             var ret = Promise.reject(errorObj.e);
23             traceParent._popContext();
24             return ret;
25         }
26         var maybePromise = tryConvertToPromise(result, traceParent);
27         if (maybePromise instanceof Promise) return maybePromise;
28     }
29     return null;
30 }
31
32 function PromiseSpawn(generatorFunction, receiver, yieldHandler, stack) {
33     var promise = this._promise = new Promise(INTERNAL);
34     promise._captureStackTrace();
35     promise._setOnCancel(this);
36     this._stack = stack;
37     this._generatorFunction = generatorFunction;
38     this._receiver = receiver;
39     this._generator = undefined;
40     this._yieldHandlers = typeof yieldHandler === "function"
41         ? [yieldHandler].concat(yieldHandlers)
42         : yieldHandlers;
43     this._yieldedPromise = null;
44 }
45 util.inherits(PromiseSpawn, Proxyable);
46
47 PromiseSpawn.prototype._isResolved = function() {
48     return this._promise === null;
49 };
50
51 PromiseSpawn.prototype._cleanup = function() {
52     this._promise = this._generator = null;
53 };
54
55 PromiseSpawn.prototype._promiseCancelled = function() {
56     if (this._isResolved()) return;
57     var implementsReturn = typeof this._generator["return"] !== "undefined";
58
59     var result;
60     if (!implementsReturn) {
61         var reason = new Promise.CancellationError(
62             "generator .return() sentinel");
63         Promise.coroutine.returnSentinel = reason;
64         this._promise._attachExtraTrace(reason);
65         this._promise._pushContext();
66         result = tryCatch(this._generator["throw"]).call(this._generator,
67                                                          reason);
68         this._promise._popContext();
69         if (result === errorObj && result.e === reason) {
70             result = null;
71         }
72     } else {
73         this._promise._pushContext();
74         result = tryCatch(this._generator["return"]).call(this._generator,
75                                                           undefined);
76         this._promise._popContext();
77     }
78     var promise = this._promise;
79     this._cleanup();
80     if (result === errorObj) {
81         promise._rejectCallback(result.e, false);
82     } else {
83         promise.cancel();
84     }
85 };
86
87 PromiseSpawn.prototype._promiseFulfilled = function(value) {
88     this._yieldedPromise = null;
89     this._promise._pushContext();
90     var result = tryCatch(this._generator.next).call(this._generator, value);
91     this._promise._popContext();
92     this._continue(result);
93 };
94
95 PromiseSpawn.prototype._promiseRejected = function(reason) {
96     this._yieldedPromise = null;
97     this._promise._attachExtraTrace(reason);
98     this._promise._pushContext();
99     var result = tryCatch(this._generator["throw"])
100         .call(this._generator, reason);
101     this._promise._popContext();
102     this._continue(result);
103 };
104
105 PromiseSpawn.prototype._resultCancelled = function() {
106     if (this._yieldedPromise instanceof Promise) {
107         var promise = this._yieldedPromise;
108         this._yieldedPromise = null;
109         promise.cancel();
110     }
111 };
112
113 PromiseSpawn.prototype.promise = function () {
114     return this._promise;
115 };
116
117 PromiseSpawn.prototype._run = function () {
118     this._generator = this._generatorFunction.call(this._receiver);
119     this._receiver =
120         this._generatorFunction = undefined;
121     this._promiseFulfilled(undefined);
122 };
123
124 PromiseSpawn.prototype._continue = function (result) {
125     var promise = this._promise;
126     if (result === errorObj) {
127         this._cleanup();
128         return promise._rejectCallback(result.e, false);
129     }
130
131     var value = result.value;
132     if (result.done === true) {
133         this._cleanup();
134         return promise._resolveCallback(value);
135     } else {
136         var maybePromise = tryConvertToPromise(value, this._promise);
137         if (!(maybePromise instanceof Promise)) {
138             maybePromise =
139                 promiseFromYieldHandler(maybePromise,
140                                         this._yieldHandlers,
141                                         this._promise);
142             if (maybePromise === null) {
143                 this._promiseRejected(
144                     new TypeError(
145                         "A value %s was yielded that could not be treated as a promise\u000a\u000a    See http://goo.gl/MqrFmX\u000a\u000a".replace("%s", value) +
146                         "From coroutine:\u000a" +
147                         this._stack.split("\n").slice(1, -7).join("\n")
148                     )
149                 );
150                 return;
151             }
152         }
153         maybePromise = maybePromise._target();
154         var bitField = maybePromise._bitField;
155         ;
156         if (((bitField & 50397184) === 0)) {
157             this._yieldedPromise = maybePromise;
158             maybePromise._proxy(this, null);
159         } else if (((bitField & 33554432) !== 0)) {
160             this._promiseFulfilled(maybePromise._value());
161         } else if (((bitField & 16777216) !== 0)) {
162             this._promiseRejected(maybePromise._reason());
163         } else {
164             this._promiseCancelled();
165         }
166     }
167 };
168
169 Promise.coroutine = function (generatorFunction, options) {
170     if (typeof generatorFunction !== "function") {
171         throw new TypeError("generatorFunction must be a function\u000a\u000a    See http://goo.gl/MqrFmX\u000a");
172     }
173     var yieldHandler = Object(options).yieldHandler;
174     var PromiseSpawn$ = PromiseSpawn;
175     var stack = new Error().stack;
176     return function () {
177         var generator = generatorFunction.apply(this, arguments);
178         var spawn = new PromiseSpawn$(undefined, undefined, yieldHandler,
179                                       stack);
180         var ret = spawn.promise();
181         spawn._generator = generator;
182         spawn._promiseFulfilled(undefined);
183         return ret;
184     };
185 };
186
187 Promise.coroutine.addYieldHandler = function(fn) {
188     if (typeof fn !== "function") {
189         throw new TypeError("expecting a function but got " + util.classString(fn));
190     }
191     yieldHandlers.push(fn);
192 };
193
194 Promise.spawn = function (generatorFunction) {
195     debug.deprecated("Promise.spawn()", "Promise.coroutine()");
196     if (typeof generatorFunction !== "function") {
197         return apiRejection("generatorFunction must be a function\u000a\u000a    See http://goo.gl/MqrFmX\u000a");
198     }
199     var spawn = new PromiseSpawn(generatorFunction, this);
200     var ret = spawn.promise();
201     spawn._run(Promise.spawn);
202     return ret;
203 };
204 };