@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
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");
}
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