2a7a28f2705e39155779e277f2bbdc0e6ee20a3d
[aai/esr-gui.git] /
1 import {
2   isArray,
3   isMaybeThenable
4 } from './utils';
5
6 import {
7   noop,
8   reject,
9   fulfill,
10   subscribe,
11   FULFILLED,
12   REJECTED,
13   PENDING,
14   getThen,
15   handleMaybeThenable
16 } from './-internal';
17
18 import then from './then';
19 import Promise from './promise';
20 import originalResolve from './promise/resolve';
21 import originalThen from './then';
22 import { makePromise, PROMISE_ID } from './-internal';
23
24 export default Enumerator;
25 function Enumerator(Constructor, input) {
26   this._instanceConstructor = Constructor;
27   this.promise = new Constructor(noop);
28
29   if (!this.promise[PROMISE_ID]) {
30     makePromise(this.promise);
31   }
32
33   if (isArray(input)) {
34     this._input     = input;
35     this.length     = input.length;
36     this._remaining = input.length;
37
38     this._result = new Array(this.length);
39
40     if (this.length === 0) {
41       fulfill(this.promise, this._result);
42     } else {
43       this.length = this.length || 0;
44       this._enumerate();
45       if (this._remaining === 0) {
46         fulfill(this.promise, this._result);
47       }
48     }
49   } else {
50     reject(this.promise, validationError());
51   }
52 }
53
54 function validationError() {
55   return new Error('Array Methods must be provided an Array');
56 };
57
58 Enumerator.prototype._enumerate = function() {
59   var length  = this.length;
60   var input   = this._input;
61
62   for (var i = 0; this._state === PENDING && i < length; i++) {
63     this._eachEntry(input[i], i);
64   }
65 };
66
67 Enumerator.prototype._eachEntry = function(entry, i) {
68   var c = this._instanceConstructor;
69   var resolve = c.resolve;
70
71   if (resolve === originalResolve) {
72     var then = getThen(entry);
73
74     if (then === originalThen &&
75         entry._state !== PENDING) {
76       this._settledAt(entry._state, i, entry._result);
77     } else if (typeof then !== 'function') {
78       this._remaining--;
79       this._result[i] = entry;
80     } else if (c === Promise) {
81       var promise = new c(noop);
82       handleMaybeThenable(promise, entry, then);
83       this._willSettleAt(promise, i);
84     } else {
85       this._willSettleAt(new c(function(resolve) { resolve(entry); }), i);
86     }
87   } else {
88     this._willSettleAt(resolve(entry), i);
89   }
90 };
91
92 Enumerator.prototype._settledAt = function(state, i, value) {
93   var promise = this.promise;
94
95   if (promise._state === PENDING) {
96     this._remaining--;
97
98     if (state === REJECTED) {
99       reject(promise, value);
100     } else {
101       this._result[i] = value;
102     }
103   }
104
105   if (this._remaining === 0) {
106     fulfill(promise, this._result);
107   }
108 };
109
110 Enumerator.prototype._willSettleAt = function(promise, i) {
111   var enumerator = this;
112
113   subscribe(promise, undefined, function(value) {
114     enumerator._settledAt(FULFILLED, i, value);
115   }, function(reason) {
116     enumerator._settledAt(REJECTED, i, reason);
117   });
118 };