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