@constantiner/fun-ctional
Version:
The library brings most of the familiar functional techniques (like functional composition) to asynchronous world with shining Promises
264 lines (231 loc) • 7.88 kB
JavaScript
/**
* @constantiner/fun-ctional
* The library brings most of the familiar functional techniques (like functional composition) to asynchronous world with shining Promises
*
* @author Konstantin Kovalev <constantiner@gmail.com>
* @version v0.6.6
* @link https://github.com/Constantiner/fun-ctional#readme
* @date 30 May 2019
*
* MIT License
*
* Copyright (c) 2018-2019 Konstantin Kovalev
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined"
? (module.exports = factory())
: typeof define === "function" && define.amd
? define(factory)
: ((global = global || self), (global.funCtional = factory()));
})(this, function() {
"use strict";
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this,
args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]")
return Array.from(iter);
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
}
/* eslint-disable unicorn/prefer-spread */
/**
* Returns a promise which resolved to array of values from a passed iterable.
* An iterable can be a promise to resolve to iterable and then to array.
*
* @param {Promise|Iterable.<*>} arrayLike Is iterable or promise to resolve to.
* @returns {Promise} A promise to resolve to resulting array.
*/
var extractArrayFromArgument =
/*#__PURE__*/
(function() {
var _ref = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee(arrayLike) {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch ((_context.prev = _context.next)) {
case 0:
_context.t0 = Array;
_context.next = 3;
return Promise.resolve(arrayLike);
case 3:
_context.t1 = _context.sent;
return _context.abrupt("return", _context.t0.from.call(_context.t0, _context.t1));
case 5:
case "end":
return _context.stop();
}
}
}, _callee);
})
);
return function extractArrayFromArgument(_x) {
return _ref.apply(this, arguments);
};
})();
var resolveArrayFromInput =
/*#__PURE__*/
(function() {
var _ref = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee(iterable) {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch ((_context.prev = _context.next)) {
case 0:
_context.t0 = Promise;
_context.next = 3;
return extractArrayFromArgument(iterable);
case 3:
_context.t1 = _context.sent;
return _context.abrupt("return", _context.t0.all.call(_context.t0, _context.t1));
case 5:
case "end":
return _context.stop();
}
}
}, _callee);
})
);
return function resolveArrayFromInput(_x) {
return _ref.apply(this, arguments);
};
})();
var reducer = function reducer(reduceFn) {
return function(acc, current, index, array) {
return Promise.resolve(acc).then(function(acc) {
return reduceFn(acc, current, index, array);
});
};
};
var getReducerArguments = function getReducerArguments(args) {
var effectiveReduceFn = reducer(args[0]);
var effectiveArguments = _toConsumableArray(args);
effectiveArguments[0] = effectiveReduceFn;
return effectiveArguments;
};
/**
* Asynchronous composable version of reduce method for iterables ("a" stays for "asynchronous").
*
* It gets a list of values (or list of promises, or promise to resolve to list) and performs standard reduce on them.
*
* Reduce function may be asynchronous to return a promise (to fetch some data etc).
*
* Initial value of reducer also could be a promise.
*
* A sample usage is:
*
* <pre><code>const sum = async (currentSum, invoiceId) => {
* const { total:invoiceTotal } = await fetchInvoiceById(invoiceId);
* return currentSum + invoiceTotal;
* };
* const paymentTotal = await areduce(sum, 0)(fetchInvoiceIds(userId));</code></pre>
*
* Or the same with acompose:
*
* <pre><code>const paymentTotal = await acompose(areduce(sum, 0), fetchInvoiceIds)(userId);</code></pre>
*
* @param {function} callback Function to execute on each element in the array, taking four arguments
* (accumulator, currentValue, currentIndex, array).
* @param {any} initialValue (optional) Value to use as the first argument to the first call of the callback.
* @returns {(iterable : Promise|Iterable.<*>) => Promise} A function which expects an iterable
* (or promise resolved to iterable) and returns a Promise.
*/
var areduce = function() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return (
/*#__PURE__*/
(function() {
var _ref = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee(iterable) {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch ((_context.prev = _context.next)) {
case 0:
_context.t0 = Array.prototype.reduce;
_context.next = 3;
return resolveArrayFromInput(iterable);
case 3:
_context.t1 = _context.sent;
_context.t2 = getReducerArguments(args);
return _context.abrupt(
"return",
_context.t0.apply.call(_context.t0, _context.t1, _context.t2)
);
case 6:
case "end":
return _context.stop();
}
}
}, _callee);
})
);
return function(_x) {
return _ref.apply(this, arguments);
};
})()
);
};
return areduce;
});
//# sourceMappingURL=areduce.js.map