UNPKG

callyflower

Version:

A collection of lightweight higher order functions to add customizable event handling to a function execution flow.

307 lines (293 loc) 14.3 kB
'use strict'; /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; /** * Check if a value is a function * @param func - The value to check * @returns {func is (...args: any) => any} - True if the value is a function */ var isCallable = function (func) { return typeof func === "function"; }; /** * Check if a function is synchronous * @param func - The function to check * @returns {boolean} - True if the function is synchronous */ var isSynchronous = function (func) { return isCallable(func) && func.constructor.name === "Function"; }; /** * throw an error if the value is not a function * @param func - The function to check * @throws {Error} - If the value is not a function */ var throwIfNotCallable = function (func) { if (!isCallable(func)) { throw new Error("Expected a function, but got ".concat(func)); } }; /** * Merge options with am optional transformer function * @template H - The type of the transformer function * @param options {any} - The options to merge * @param transformer {H} - The transformer function * @returns {any} - The merged options, either synchronously or asynchronously. if the transformer function returns a promise, the result will be a promise */ function baseMerge(options, transformer) { if (!transformer) return options; var maybePromise = transformer(options); return Promise.resolve(maybePromise).then(function (res) { return (__assign(__assign({}, options), (res || {}))); }); } /** * Merge options with am optional transformer function synchronously * @template H - The type of the transformer function * @param options {any} - The options to merge * @param transformer {H} - The transformer function * @returns {any} - The merged options */ var syncMerge = function (options, transformer) { var result = transformer ? transformer(options) : null; return __assign(__assign({}, options), (result || {})); }; /** * Merge options with am optional transformer function asynchronously * @template H - The type of the transformer function * @param options {any} - The options to merge * @param transformer {H} - The transformer function * @returns {Promise<any>} - The merged options */ var asyncMerge = function (options, transformer) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, baseMerge(options, transformer)]; }); }); }; /** * Wraps a function with an `onCall` event handler, allowing modification of the function's arguments. * The returned function calls the original function and applies the `onCall` event beforehand. * It can be used to modify the arguments before the function is called, or to short-circuit the function call. * This is useful for validation, logging, memoization or other pre-processing tasks. * * @template F - The type of the function to wrap. * @param {F} callee - The original function to wrap. * @param {OnCallHandler<F>} onCall - The handler invoked before the function call to modify the arguments. * @returns {F} A new function that wraps the original function with the `onCall` event handler. */ var withOnCall = function (callee, onCall) { throwIfNotCallable(callee); return !onCall ? callee : isSynchronous(callee) ? function () { var _a; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var modifiedCall = syncMerge({ callee: callee, args: args, event: "onCall" }, onCall); return (_a = modifiedCall.result) !== null && _a !== void 0 ? _a : modifiedCall.callee.apply(modifiedCall, modifiedCall.args); } : function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return __awaiter(void 0, void 0, void 0, function () { var modifiedCall; var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, asyncMerge({ callee: callee, args: args, event: "onCall" }, onCall)]; case 1: modifiedCall = _b.sent(); return [2 /*return*/, (_a = modifiedCall.result) !== null && _a !== void 0 ? _a : modifiedCall.callee.apply(modifiedCall, modifiedCall.args)]; } }); }); }; }; /** * Wraps a function with an `onResult` event handler, allowing modification of the function's result. * The returned function calls the original function and applies the `onResult` event afterward. * * @template F - The type of the function to wrap. * @param {F} callee - The original function to wrap. * @param {OnResultHandler<F>} onCall - The handler invoked before the function call to modify the arguments. * @returns {F} A new function that wraps the original function with the `onResult` event handler. */ var withOnResult = function (callee, onResult) { throwIfNotCallable(callee); return !onResult ? callee : isSynchronous(callee) ? function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var result = callee.apply(void 0, args); var modifiedResult = (result ? syncMerge({ callee: callee, args: args, result: result, event: "onResult" }, onResult) : { result: result }).result; return modifiedResult; } : function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return __awaiter(void 0, void 0, void 0, function () { var result, modifiedResult, _a; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, callee.apply(void 0, args)]; case 1: result = _b.sent(); if (!result) return [3 /*break*/, 3]; return [4 /*yield*/, asyncMerge({ callee: callee, args: args, result: result, event: "onResult" }, onResult)]; case 2: _a = _b.sent(); return [3 /*break*/, 4]; case 3: _a = { result: result }; _b.label = 4; case 4: modifiedResult = (_a).result; return [2 /*return*/, modifiedResult]; } }); }); }; }; /** @internal */ var _handleCatch = function (callee, args, onCatch) { return __awaiter(void 0, void 0, void 0, function () { var isSync, _a, caught_1, merged, _b; return __generator(this, function (_c) { switch (_c.label) { case 0: isSync = isSynchronous(callee); _c.label = 1; case 1: _c.trys.push([1, 5, , 9]); if (!isSync) return [3 /*break*/, 2]; _a = callee.apply(void 0, args); return [3 /*break*/, 4]; case 2: return [4 /*yield*/, callee.apply(void 0, args)]; case 3: _a = _c.sent(); _c.label = 4; case 4: return [2 /*return*/, _a]; case 5: caught_1 = _c.sent(); if (!isSync) return [3 /*break*/, 6]; _b = syncMerge({ callee: callee, args: args, caught: caught_1, event: "onCatch" }, onCatch); return [3 /*break*/, 8]; case 6: return [4 /*yield*/, asyncMerge({ callee: callee, args: args, caught: caught_1, event: "onCatch" }, onCatch)]; case 7: _b = _c.sent(); _c.label = 8; case 8: merged = _b; if (merged.result) { return [2 /*return*/, merged.result]; } else { throw merged.caught; } case 9: return [2 /*return*/]; } }); }); }; /** * Wraps a function with an `onCatch` event handler, allowing modification of the function's caught error. * The returned function calls the original function and applies the `onCatch` event if an error is caught. * It can be used to modify the error before it is rethrown, or to suppress the error and return a value. * * @template F - The type of the function to wrap. * @param {F} callee - The original function to wrap. * @param {OnCatchHandler<F>} onCatch - The handler invoked when an error is caught to modify the error or return a value. * @returns {F} A new function that wraps the original function with the `onCatch` event handler. */ var withOnCatch = function (callee, onCatch) { throwIfNotCallable(callee); return !onCatch ? callee : isSynchronous(callee) ? function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return _handleCatch(callee, args, onCatch); } : function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, _handleCatch(callee, args, onCatch)]; }); }); }; }; exports.withOnCall = withOnCall; exports.withOnCatch = withOnCatch; exports.withOnResult = withOnResult; //# sourceMappingURL=callyflower.cjs.js.map