aboutsummaryrefslogtreecommitdiff
path: root/node_modules/when/lib/decorators/array.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/when/lib/decorators/array.js')
-rw-r--r--node_modules/when/lib/decorators/array.js285
1 files changed, 285 insertions, 0 deletions
diff --git a/node_modules/when/lib/decorators/array.js b/node_modules/when/lib/decorators/array.js
new file mode 100644
index 00000000..de0d373f
--- /dev/null
+++ b/node_modules/when/lib/decorators/array.js
@@ -0,0 +1,285 @@
+/** @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 state = require('../state');
+ var applier = require('../apply');
+
+ return function array(Promise) {
+
+ var applyFold = applier(Promise);
+ var toPromise = Promise.resolve;
+ var all = Promise.all;
+
+ var ar = Array.prototype.reduce;
+ var arr = Array.prototype.reduceRight;
+ var slice = Array.prototype.slice;
+
+ // Additional array combinators
+
+ Promise.any = any;
+ Promise.some = some;
+ Promise.settle = settle;
+
+ Promise.map = map;
+ Promise.filter = filter;
+ Promise.reduce = reduce;
+ Promise.reduceRight = reduceRight;
+
+ /**
+ * When this promise fulfills with an array, do
+ * onFulfilled.apply(void 0, array)
+ * @param {function} onFulfilled function to apply
+ * @returns {Promise} promise for the result of applying onFulfilled
+ */
+ Promise.prototype.spread = function(onFulfilled) {
+ return this.then(all).then(function(array) {
+ return onFulfilled.apply(this, array);
+ });
+ };
+
+ return Promise;
+
+ /**
+ * One-winner competitive race.
+ * Return a promise that will fulfill when one of the promises
+ * in the input array fulfills, or will reject when all promises
+ * have rejected.
+ * @param {array} promises
+ * @returns {Promise} promise for the first fulfilled value
+ */
+ function any(promises) {
+ var p = Promise._defer();
+ var resolver = p._handler;
+ var l = promises.length>>>0;
+
+ var pending = l;
+ var errors = [];
+
+ for (var h, x, i = 0; i < l; ++i) {
+ x = promises[i];
+ if(x === void 0 && !(i in promises)) {
+ --pending;
+ continue;
+ }
+
+ h = Promise._handler(x);
+ if(h.state() > 0) {
+ resolver.become(h);
+ Promise._visitRemaining(promises, i, h);
+ break;
+ } else {
+ h.visit(resolver, handleFulfill, handleReject);
+ }
+ }
+
+ if(pending === 0) {
+ resolver.reject(new RangeError('any(): array must not be empty'));
+ }
+
+ return p;
+
+ function handleFulfill(x) {
+ /*jshint validthis:true*/
+ errors = null;
+ this.resolve(x); // this === resolver
+ }
+
+ function handleReject(e) {
+ /*jshint validthis:true*/
+ if(this.resolved) { // this === resolver
+ return;
+ }
+
+ errors.push(e);
+ if(--pending === 0) {
+ this.reject(errors);
+ }
+ }
+ }
+
+ /**
+ * N-winner competitive race
+ * Return a promise that will fulfill when n input promises have
+ * fulfilled, or will reject when it becomes impossible for n
+ * input promises to fulfill (ie when promises.length - n + 1
+ * have rejected)
+ * @param {array} promises
+ * @param {number} n
+ * @returns {Promise} promise for the earliest n fulfillment values
+ *
+ * @deprecated
+ */
+ function some(promises, n) {
+ /*jshint maxcomplexity:7*/
+ var p = Promise._defer();
+ var resolver = p._handler;
+
+ var results = [];
+ var errors = [];
+
+ var l = promises.length>>>0;
+ var nFulfill = 0;
+ var nReject;
+ var x, i; // reused in both for() loops
+
+ // First pass: count actual array items
+ for(i=0; i<l; ++i) {
+ x = promises[i];
+ if(x === void 0 && !(i in promises)) {
+ continue;
+ }
+ ++nFulfill;
+ }
+
+ // Compute actual goals
+ n = Math.max(n, 0);
+ nReject = (nFulfill - n + 1);
+ nFulfill = Math.min(n, nFulfill);
+
+ if(n > nFulfill) {
+ resolver.reject(new RangeError('some(): array must contain at least '
+ + n + ' item(s), but had ' + nFulfill));
+ } else if(nFulfill === 0) {
+ resolver.resolve(results);
+ }
+
+ // Second pass: observe each array item, make progress toward goals
+ for(i=0; i<l; ++i) {
+ x = promises[i];
+ if(x === void 0 && !(i in promises)) {
+ continue;
+ }
+
+ Promise._handler(x).visit(resolver, fulfill, reject, resolver.notify);
+ }
+
+ return p;
+
+ function fulfill(x) {
+ /*jshint validthis:true*/
+ if(this.resolved) { // this === resolver
+ return;
+ }
+
+ results.push(x);
+ if(--nFulfill === 0) {
+ errors = null;
+ this.resolve(results);
+ }
+ }
+
+ function reject(e) {
+ /*jshint validthis:true*/
+ if(this.resolved) { // this === resolver
+ return;
+ }
+
+ errors.push(e);
+ if(--nReject === 0) {
+ results = null;
+ this.reject(errors);
+ }
+ }
+ }
+
+ /**
+ * Apply f to the value of each promise in a list of promises
+ * and return a new list containing the results.
+ * @param {array} promises
+ * @param {function(x:*, index:Number):*} f mapping function
+ * @returns {Promise}
+ */
+ function map(promises, f) {
+ return Promise._traverse(f, promises);
+ }
+
+ /**
+ * Filter the provided array of promises using the provided predicate. Input may
+ * contain promises and values
+ * @param {Array} promises array of promises and values
+ * @param {function(x:*, index:Number):boolean} predicate filtering predicate.
+ * Must return truthy (or promise for truthy) for items to retain.
+ * @returns {Promise} promise that will fulfill with an array containing all items
+ * for which predicate returned truthy.
+ */
+ function filter(promises, predicate) {
+ var a = slice.call(promises);
+ return Promise._traverse(predicate, a).then(function(keep) {
+ return filterSync(a, keep);
+ });
+ }
+
+ function filterSync(promises, keep) {
+ // Safe because we know all promises have fulfilled if we've made it this far
+ var l = keep.length;
+ var filtered = new Array(l);
+ for(var i=0, j=0; i<l; ++i) {
+ if(keep[i]) {
+ filtered[j++] = Promise._handler(promises[i]).value;
+ }
+ }
+ filtered.length = j;
+ return filtered;
+
+ }
+
+ /**
+ * Return a promise that will always fulfill with an array containing
+ * the outcome states of all input promises. The returned promise
+ * will never reject.
+ * @param {Array} promises
+ * @returns {Promise} promise for array of settled state descriptors
+ */
+ function settle(promises) {
+ return all(promises.map(settleOne));
+ }
+
+ function settleOne(p) {
+ var h = Promise._handler(p);
+ return h.state() === 0 ? toPromise(p).then(state.fulfilled, state.rejected)
+ : state.inspect(h);
+ }
+
+ /**
+ * Traditional reduce function, similar to `Array.prototype.reduce()`, but
+ * input may contain promises and/or values, and reduceFunc
+ * may return either a value or a promise, *and* initialValue may
+ * be a promise for the starting value.
+ * @param {Array|Promise} promises array or promise for an array of anything,
+ * may contain a mix of promises and values.
+ * @param {function(accumulated:*, x:*, index:Number):*} f reduce function
+ * @returns {Promise} that will resolve to the final reduced value
+ */
+ function reduce(promises, f /*, initialValue */) {
+ return arguments.length > 2 ? ar.call(promises, liftCombine(f), arguments[2])
+ : ar.call(promises, liftCombine(f));
+ }
+
+ /**
+ * Traditional reduce function, similar to `Array.prototype.reduceRight()`, but
+ * input may contain promises and/or values, and reduceFunc
+ * may return either a value or a promise, *and* initialValue may
+ * be a promise for the starting value.
+ * @param {Array|Promise} promises array or promise for an array of anything,
+ * may contain a mix of promises and values.
+ * @param {function(accumulated:*, x:*, index:Number):*} f reduce function
+ * @returns {Promise} that will resolve to the final reduced value
+ */
+ function reduceRight(promises, f /*, initialValue */) {
+ return arguments.length > 2 ? arr.call(promises, liftCombine(f), arguments[2])
+ : arr.call(promises, liftCombine(f));
+ }
+
+ function liftCombine(f) {
+ return function(z, x, i) {
+ return applyFold(f, void 0, [z,x,i]);
+ };
+ }
+ };
+
+});
+}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));