UNPKG

@constantiner/fun-ctional

Version:

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

201 lines (175 loc) 6.56 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" ? (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"); } var customPromiseHandlingSupportSupport = Symbol.for("Custom Promise Handling Support"); var supportsCustomPromiseHandling = function supportsCustomPromiseHandling(fn) { return fn[customPromiseHandlingSupportSupport]; }; /** * 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 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); }; })() ); }; return apipe; }); //# sourceMappingURL=apipe.js.map