UNPKG

@constantiner/fun-ctional

Version:

The library brings most of the familiar functional techniques (like functional composition) to asynchronous world with shining Promises

1,099 lines (974 loc) 37.1 kB
/** * @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" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : ((global = global || self), factory((global.funCtional = {}))); })(this, function(exports) { "use strict"; var customPromiseHandlingSupportSupport = Symbol.for("Custom Promise Handling Support"); var addCustomPromiseHandlingSupport = function addCustomPromiseHandlingSupport(fn, customVersion) { return (fn[customPromiseHandlingSupportSupport] = customVersion), fn; }; var supportsCustomPromiseHandling = function supportsCustomPromiseHandling(fn) { return fn[customPromiseHandlingSupportSupport]; }; /** * Composable version of catch method for promises. * * It gets a value (a promise or not), resolves it and if resulting promise was rejected calls catch function. * * It allows to handle errors within acompose or apipe asynchronous composition chains to restore broken state etc. * * A sample with acompose: * * <pre><code>const resultOrFallback = await acompose(acatch(handleAndRecoverFn), canFailFn)(someInput);</code></pre> * * Standalone usage: * * <pre><code>const resultOrFallback = await acatch(handleAndRecoverFn)(requestDataAndReturnPromise());</code></pre> * * It is the same as the following: * * <pre><code>requestDataAndReturnPromise().catch(handleAndRecoverFn).then(resultOrFallback => console.log(resultOrFallback));</code></pre> * * @param {function} catchFn Is function to handle Promise's rejection. * @returns {any => Promise} A function which expects any value as input (Promise or not) and returns a Promise. */ var acatch = function(catchFn) { var handler = function handler(value) { return Promise.resolve(value).catch(catchFn); }; return addCustomPromiseHandlingSupport(handler, function(promise) { return promise.catch(catchFn); }); }; 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"); } /** * Checks if parameter is an iterable. * * @param {any} obj is target to check. * @returns {boolean} Result of checking. */ var isIterable = function isIterable(obj) { return Array.isArray(obj) || ((obj || obj === "") && typeof obj[Symbol.iterator] === "function"); }; /** * Returns an array of values from arguments of some function. * Arguments can be passed as arguments list ar as single iterable parameter. * * @param {array} args are input array (just arguments of some other function). * If if consists of one element and this element is an iterable returns array from it. * @returns {Promise} Resulting array of arguments. */ var extractResolvedArguments = function extractResolvedArguments(args) { return args ? (args.length === 1 && isIterable(args[0]) ? _toConsumableArray(args[0]) : args) : []; }; /** * Asynchronous compose function (acompose stays for async-compose). * * The main purpose is to replace a Promise handling code like this: * <pre><code>somePromise.then(normalize).then(upperCase).then(insertGreetings);</code></pre> * * with point-free style of functional compose syntax like the following: * <pre><code>acompose(insertGreetings, upperCase, normalize)(somePromise);</code></pre> * * It is lazy and allows of reusing of promise handling chains. * * You can run acompose with Promise instance (for true asynchronous execution) * or with any other object to use as usual functional composition. * It produces a Promise and can be used in async/await context: * * <pre><code>const message = await acompose(insertGreetings, upperCase, normalize)(somePromise);</code></pre> * * It also allows to handle errors like for traditional Promise but only in the tail position of the chain: * * <pre><code>acompose(insertGreetings, upperCase, normalize)(somePromise).catch(e => console.error(e));</code></pre> * * @param {...function|Iterable.<*>} fns Are functions to compose chains of promises. * @returns {(promise : Promise|any) => Promise} A function which expects any value as input (resolving to Promise) and returns a Promise. */ var acompose = function() { for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) { fns[_key] = arguments[_key]; } return ( /*#__PURE__*/ (function() { var _ref = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee(promise) { return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch ((_context.prev = _context.next)) { case 0: return _context.abrupt( "return", extractResolvedArguments(fns).reduceRight(function(promise, fn) { var promiseHandler = supportsCustomPromiseHandling(fn); if (promiseHandler) { return promiseHandler(promise); } return promise.then(fn); }, Promise.resolve(promise)) ); case 1: case "end": return _context.stop(); } } }, _callee); }) ); return function(_x) { return _ref.apply(this, arguments); }; })() ); }; /* 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 filterMergeMap = function filterMergeMap(filterFn) { return ( /*#__PURE__*/ (function() { var _ref = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee(element, index, array) { var filterResult; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch ((_context.prev = _context.next)) { case 0: _context.next = 2; return filterFn(element, index, array); case 2: filterResult = !!_context.sent; return _context.abrupt("return", { filterResult: filterResult, element: element }); case 4: case "end": return _context.stop(); } } }, _callee); }) ); return function(_x, _x2, _x3) { return _ref.apply(this, arguments); }; })() ); }; var filterResultsReducer = function filterResultsReducer(filteredArray, _ref2) { var filterResult = _ref2.filterResult, element = _ref2.element; if (filterResult) { filteredArray.push(element); } return filteredArray; }; var getFilteredInParallel = /*#__PURE__*/ (function() { var _ref3 = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee2(filterFn, array) { var filterMergeMapFn, filterValues; return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch ((_context2.prev = _context2.next)) { case 0: filterMergeMapFn = filterMergeMap(filterFn); _context2.next = 3; return Promise.all(array.map(filterMergeMapFn)); case 3: filterValues = _context2.sent; return _context2.abrupt("return", filterValues.reduce(filterResultsReducer, [])); case 5: case "end": return _context2.stop(); } } }, _callee2); }) ); return function getFilteredInParallel(_x4, _x5) { return _ref3.apply(this, arguments); }; })(); var getFilteredInSequence = /*#__PURE__*/ (function() { var _ref4 = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee3(filterFn, array) { var result, i, filterResult; return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch ((_context3.prev = _context3.next)) { case 0: result = []; i = 0; case 2: if (!(i < array.length)) { _context3.next = 10; break; } _context3.next = 5; return filterFn(array[i], i, array); case 5: filterResult = !!_context3.sent; if (filterResult) { result.push(array[i]); } case 7: i++; _context3.next = 2; break; case 10: return _context3.abrupt("return", result); case 11: case "end": return _context3.stop(); } } }, _callee3); }) ); return function getFilteredInSequence(_x6, _x7) { return _ref4.apply(this, arguments); }; })(); var afilterGeneric = function() { var sequence = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; return function(filterFn) { return ( /*#__PURE__*/ (function() { var _ref5 = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee4(iterable) { var sourceArray, array; return regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch ((_context4.prev = _context4.next)) { case 0: _context4.next = 2; return extractArrayFromArgument(iterable); case 2: sourceArray = _context4.sent; _context4.next = 5; return Promise.all(sourceArray); case 5: array = _context4.sent; if (!sequence) { _context4.next = 12; break; } _context4.next = 9; return getFilteredInSequence(filterFn, array); case 9: _context4.t0 = _context4.sent; _context4.next = 15; break; case 12: _context4.next = 14; return getFilteredInParallel(filterFn, array); case 14: _context4.t0 = _context4.sent; case 15: return _context4.abrupt("return", _context4.t0); case 16: case "end": return _context4.stop(); } } }, _callee4); }) ); return function(_x8) { return _ref5.apply(this, arguments); }; })() ); }; }; /** * An asynchronous version of filter over an iterable (afilter stays for async-filter). * * It gets an iterable of values (or promises) as input (or promise to resolve to iterable), * resolves them, iterates over them with filter function * (which returns boolean where true means current value will be included in resulting array) * and returns a promise which resolves to an array of values (filtered input iterable). * * It allows asynchronous filtering point-free way and can be used with asynchronous compose functions. * * It uses Promise.all() under the hood. * So if filtering function is asynchronous (returns a promise) all promises are being generated at once * and then resolved with Promise.all(). * So if any of promises will produce error (promise rejection) all the other promises will be invoked anyway. * The advantage of this method of invoking promises it will finish earlier than sequential filter (because of Promise.all()) * but it may perform some fetches or even state modifications even in case of fail on some previous filtering steps. * * <pre><code>const [ first, third ] = await afilter(fetchPermissions)([somePromise1, someValue2, somePromise3]);</code></pre> * * It first resolves a promises passed and then pass resolutions value to the filtering function. * * Input iterable's values are not restricted to promises but can be any value to pass as input to functions. * * It also allows to handle errors like for traditional Promise: * * <pre><code>afilter(fetchPermissions)(somePromise1, someValue2, somePromise3).catch(e => console.error(e));</code></pre> * * @param {function} filterFn Is filtering function which can produce a promise (but not restricted to this). * Function can return a promise (asynchronous filtering) or may just perform some synchronous filtering. * So you can use it in synchronous code taking in mind it returns promise so can't be resolved immediately. * It has three parameters (currentValue, currentIndex, array) which are already resolved (not promises). * @returns {(iterable : Promise|Iterable.<*>) => Promise} A function which expects any values as input (resolving to Promise) * and returns a Promise. */ var afilter = afilterGeneric(); /** * An asynchronous version of filter over an iterable (afilterSeq stays for async-filter). * * It gets an iterable of values (or promises) as input (or promise to resolve to iterable), * resolves them, iterates over them with filter function * (which returns boolean where true means current value will be included in resulting array) * and returns a promise which resolves to an array of values (filtered input iterable). * * It allows asynchronous filtering point-free way and can be used with asynchronous compose functions. * * The difference from regular afilter is if filter function is asynchronous (returns a promise) * every new invocation of filter function performs sequentially after resolving previous promise. * So if any of promises produces error (promise rejection) afilterSeq will not produce new promises and they won't be invoked. * * <pre><code>const [ first, third ] = await afilterSeq(fetchPermissions)([somePromise1, someValue2, somePromise3]);</code></pre> * * It first resolves a promises passed and then pass resolutions value to the filtering function. * * Input iterable's values are not restricted to promises but can be any value to pass as input to functions. * * It also allows to handle errors like for traditional Promise: * * <pre><code>afilterSeq(fetchPermissions)(somePromise1, someValue2, somePromise3).catch(e => console.error(e));</code></pre> * * @param {function} filterFn Is filtering function which can produce a promise (but not restricted to this). * Function can return a promise (asynchronous filtering) or may just perform some synchronous filtering. * So you can use it in synchronous code taking in mind it returns promise so can't be resolved immediately. * It has three parameters (currentValue, currentIndex, array) which are already resolved (not promises). * @returns {(iterable : Promise|Iterable.<*>) => Promise} A function which expects any values as input (resolving to Promise) * and returns a Promise. */ var afilterSeq = afilterGeneric(true); var getMappedInParallel = function getMappedInParallel(mapFn, array) { return Promise.all(array.map(mapFn)); }; var getMappedInSequence = /*#__PURE__*/ (function() { var _ref = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee(mapFn, array) { var result, i, mapResult; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch ((_context.prev = _context.next)) { case 0: result = []; i = 0; case 2: if (!(i < array.length)) { _context.next = 10; break; } _context.next = 5; return mapFn(array[i], i, array); case 5: mapResult = _context.sent; result.push(mapResult); case 7: i++; _context.next = 2; break; case 10: return _context.abrupt("return", result); case 11: case "end": return _context.stop(); } } }, _callee); }) ); return function getMappedInSequence(_x, _x2) { return _ref.apply(this, arguments); }; })(); var amapGeneric = function() { var sequence = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; return function(mapFn) { return ( /*#__PURE__*/ (function() { var _ref2 = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee2(iterable) { var sourceArray, array; return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch ((_context2.prev = _context2.next)) { case 0: _context2.next = 2; return extractArrayFromArgument(iterable); case 2: sourceArray = _context2.sent; _context2.next = 5; return Promise.all(sourceArray); case 5: array = _context2.sent; return _context2.abrupt( "return", sequence ? getMappedInSequence(mapFn, array) : getMappedInParallel(mapFn, array) ); case 7: case "end": return _context2.stop(); } } }, _callee2); }) ); return function(_x3) { return _ref2.apply(this, arguments); }; })() ); }; }; /** * An asynchronous version of map over an iterable (amap stays for async-map). * * It gets an iterable of values (or promises) as input (or promise to resolve to iterable), * resolves them, maps over map function and returns a promise which resolves to an array of values. * * It allows asynchronous mapping point-free way and can be used with asynchronous compose functions. * * It uses Promise.all() under the hood. * So if mapping function is asynchronous (returns a promise) all promises are being generated at once * and then resolved with Promise.all(). * So if any of promises will produce error (promise rejection) all the other promises will be invoked. * The advantage of this method of invoking promises it will finish earlier than sequential map (because of Promise.all()) * but it may perform some fetches or even state modifications even in case of fail on some previous mapping steps. * * <pre><code>const [ first, second, third ] = await amap(getDataFromServer)([somePromise1, someValue2, somePromise3]);</code></pre> * * It first resolves a promises passed and then pass resolutions value to the mapping function. * * Input iterable's values are not restricted to promises but can be any value to pass as input to functions. * * It also allows to handle errors like for traditional Promise: * * <pre><code>amap(getDataFromServer)(somePromise1, someValue2, somePromise3).catch(e => console.error(e));</code></pre> * * @param {function} mapFn Is mapping function which can produce a promise (but not restricted to this). * Function can return a promise (asynchronous mapping) or may just perform some synchronous mapping. * So you can use it in synchronous code taking in mind it returns promise so can't be resolved immediately. * It has three parameters (currentValue, currentIndex, array) which are resolved (not promises). * @returns {(iterable : Promise|Iterable.<*>) => Promise} A function which expects any values as input (resolving to Promise) * and returns a Promise. */ var amap = amapGeneric(); /** * An asynchronous version of map over an iterable (amap stays for async-map). * * It gets an iterable of values (or promises) as input (or promise to resolve to iterable), * resolves them, maps over map function and returns a promise which resolves to an array of values. * * It allows asynchronous mapping point-free way and can be used with asynchronous compose functions. * * The difference from regular amap is if map function is asynchronous (returns a promise) * every new invocation of map function performs sequentially after resolving previous promise. * So if any of promises produces error (promise rejection) amapSeq will not produce new promises and they won't be invoked. * * <pre><code>const [ first, second, third ] = await amap(getDataFromServer)([somePromise1, someValue2, somePromise3]);</code></pre> * * It first resolves a promises passed and then pass resolutions value to the mapping function. * * Input iterable's values are not restricted to promises but can be any value to pass as input to functions. * * It also allows to handle errors like for traditional Promise: * * <pre><code>amap(getDataFromServer)(somePromise1, someValue2, somePromise3).catch(e => console.error(e));</code></pre> * * @param {function} mapFn Is mapping function which can produce a promise (but not restricted to this). * Function can return a promise (asynchronous mapping) or may just perform some synchronous mapping. * So you can use it in synchronous code taking in mind it returns promise so can't be resolved immediately. * It has three parameters (currentValue, currentIndex, array) which are resolved (not promises). * @returns {(iterable : Promise|Iterable.<*>) => Promise} A function which expects any values as input (resolving to Promise) * and returns a Promise. */ var amapSeq = amapGeneric(true); /** * Asynchronous pipe function (apipe stays for async-pipe). * * The main purpose is to replace a Promise handling code like this: * <pre><code>somePromise.then(normalize).then(upperCase).then(insertGreetings);</code></pre> * * with point-free style of functional pipe syntax like the following: * <pre><code>apipe(normalize, upperCase, insertGreetings)(somePromise);</code></pre> * * It is lazy and allows of reusing of promise handling chains. * * You can run apipe with Promise instance (for true asynchronous execution) * or with any other object to use as in usual functional composition. * It produces a Promise and can be used in async/await context: * * <pre><code>const message = await apipe(normalize, upperCase, insertGreetings)(somePromise);</code></pre> * * It also allows to handle errors like for traditional Promise but only in the tail position of the chain: * * <pre><code>apipe(normalize, upperCase, insertGreetings)(somePromise).catch(e => console.error(e));</code></pre> * * @param {...function|Iterable.<*>} fns Are functions to pipe chains of promises. * @returns {(promise : Promise|any) => Promise} A function which expects any value as input (resolving to Promise) and returns a Promise. */ var apipe = function() { for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) { fns[_key] = arguments[_key]; } return ( /*#__PURE__*/ (function() { var _ref = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee(promise) { return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch ((_context.prev = _context.next)) { case 0: return _context.abrupt( "return", extractResolvedArguments(fns).reduce(function(promise, fn) { var promiseHandler = supportsCustomPromiseHandling(fn); if (promiseHandler) { return promiseHandler(promise); } return promise.then(fn); }, Promise.resolve(promise)) ); case 1: case "end": return _context.stop(); } } }, _callee); }) ); return function(_x) { return _ref.apply(this, arguments); }; })() ); }; /** * A kind of composable version of Promise.all(). * * It gets some value or promise as input, pass it to the functions list * and produces the array of results after resolving all the functions which can return promises as well. * * It allows to use Promise.all() point-free way. * * <pre><code>const [ first, second ] = await applyFns(squareRoot, getDataFromServer)(somePromise);</code></pre> * * It first resolves a promise passed and then pass resolution value to all the functions. * * Input value is not restricted to promise but can be any value to pass as input to functions. * * It also allows to handle errors like for traditional Promise: * * <pre><code>applyFns(squareRoot, getDataFromServer)(somePromise).catch(e => console.error(e));</code></pre> * * @param {...function|Iterable.<*>} fns Are functions to handle input value in parallel. * Functions can return promises or may just perform some mapping. * So you can use it in synchronous code taking in mind it returns promise so can't be resolved immediately. * @returns {(value : Promise|any) => Promise} A function which expects any value as input (resolving to Promise) and returns a Promise. */ var applyFns = function() { for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) { fns[_key] = arguments[_key]; } return ( /*#__PURE__*/ (function() { var _ref = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee(value) { var resolvedValue; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch ((_context.prev = _context.next)) { case 0: _context.next = 2; return Promise.resolve(value); case 2: resolvedValue = _context.sent; return _context.abrupt( "return", Promise.all( extractResolvedArguments(fns).map(function(fn) { return fn(resolvedValue); }) ) ); case 4: case "end": return _context.stop(); } } }, _callee); }) ); return function(_x) { return _ref.apply(this, arguments); }; })() ); }; /** * Composable version of promise.then(mapFn).catch(catchFn). * * It gets a value (a promise or not), resolves it and handles as promise.then(mapFn).catch(catchFn) returning resulting promise. * * It allows to handle errors within acompose or apipe asynchronous composition chains to restore broken state etc. * * A sample with acompose: * * <pre><code>const resultOrFallback = await acompose(applySafe(canFailFn, handleAndRecoverFn), canFailTooFn)(someInput);</code></pre> * * Standalone usage: * * <pre><code>const resultOrFallback = await applySafe(canFailFn, handleAndRecoverFn)(requestDataAndReturnPromise());</code></pre> * * Or even: * * <pre><code>const resultOrFallback = await applySafe(acompose(handlerFn2, handlerFn1), handleAndRecoverFn)(requestDataAndReturnPromise());</code></pre> * * It is the same as the following: * * <pre><code>requestDataAndReturnPromise().then(canFailFn).catch(handleAndRecoverFn).then(resultOrFallback => console.log(resultOrFallback));</code></pre> * * @param {function} mapFn Is function to handle Promise's resolution (then). * @param {function} catchFn Is function to handle Promise's rejection (catch). * @returns {any => Promise} A function which expects any value as input (Promise or not) and returns a Promise. */ var applySafe = function(mapFn, catchFn) { var handler = function handler(value) { return Promise.resolve(value) .then(mapFn) .catch(catchFn); }; return addCustomPromiseHandlingSupport(handler, function(promise) { return promise.then(mapFn).catch(catchFn); }); }; 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); }; })() ); }; /** * Asynchronous composable version of reduceRight 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 areduceRight(sum, 0)(fetchInvoiceIds(userId));</code></pre> * * Or the same with acompose: * * <pre><code>const paymentTotal = await acompose(areduceRight(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 areduceRight = 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.reduceRight; _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); }; })() ); }; exports.acatch = acatch; exports.acompose = acompose; exports.afilter = afilter; exports.afilterSeq = afilterSeq; exports.amap = amap; exports.amapSeq = amapSeq; exports.apipe = apipe; exports.applyFns = applyFns; exports.applySafe = applySafe; exports.areduce = areduce; exports.areduceRight = areduceRight; Object.defineProperty(exports, "__esModule", { value: true }); }); //# sourceMappingURL=fun-ctional.js.map