UNPKG

aveazul

Version:

Bluebird drop-in replacement built on native Promise

648 lines 23.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.AveAzul = void 0; /* eslint-disable @typescript-eslint/no-explicit-any */ const xaa = __importStar(require("xaa")); const promisify_ts_1 = require("./promisify.cjs"); const promisify_all_ts_1 = require("./promisify-all.cjs"); const disposer_ts_1 = require("./disposer.cjs"); const using_ts_1 = require("./using.cjs"); const util_ts_1 = require("./util.cjs"); const error_1 = require("@jchip/error"); const operational_error_ts_1 = require("./operational-error.cjs"); /** * @fileoverview * AveAzul ("Blue Bird" in Spanish) - Extended Promise class that provides Bluebird like utility methods * This implementation is inspired by and provides similar APIs to the Bluebird Promise library, * but built on top of native Promises. The name is a Spanish play on words referencing Bluebird. * @extends Promise */ class AveAzul extends Promise { constructor(executor) { super(executor); } /** * Note: Per ECMAScript specification, when extending Promise, both .then() and static methods * (resolve, reject, all, etc) must return instances of the derived class (AveAzul), so there's * no need to explicitly wrap returns in new AveAzul(). This behavior is standard across all * spec-compliant JS engines (V8, SpiderMonkey, JavaScriptCore, etc). */ /** * Bluebird-style tap() method that lets you perform side effects in a chain * Similar to Bluebird's Promise.prototype.tap() * @param fn - Function to execute with the resolved value * @returns Promise that resolves with the original value */ tap(fn) { return this.then(async (value) => { await fn(value); return value; }); } /** * Bluebird-style filter() method for array operations * Similar to Bluebird's Promise.prototype.filter() * @param fn - Filter function to apply to each element * @returns Promise that resolves with the filtered array */ filter(fn) { return this.then((value) => xaa.filter(value, fn)); } /** * Bluebird-style map() method for array operations * Similar to Bluebird's Promise.prototype.map() * @param fn - Map function to apply to each element * @returns Promise that resolves with the mapped array */ map(fn, options = { concurrency: 50 }) { return this.then((value) => xaa.map(value, fn, options)); } /** * Bluebird-style mapSeries() method for array operations * Similar to Bluebird's Promise.prototype.mapSeries() * @param fn - Map function to apply to each element * @returns Promise that resolves with the mapped array */ mapSeries(fn) { return this.map(fn, { concurrency: 1 }); } /** * Bluebird-style return() method to inject a value into the chain * Similar to Bluebird's Promise.prototype.return() * @param value - Value to return * @returns Promise that resolves with the new value */ return(value) { return this.then(() => value); } /** * Bluebird-style any() method for waiting for any promises to resolve * @returns Promise that resolves with the first resolved promise */ any() { return this.then((args) => { return AveAzul.any((0, util_ts_1.toArray)(args)); }); } /** * Bluebird-style each() method for array iteration * Similar to Bluebird's Promise.prototype.each() * @param fn - Function to execute for each element * @returns Promise that resolves when iteration is complete */ each(fn) { return this.then(async (value) => { const arr = value; const result = []; for (let i = 0; i < arr.length; i++) { let x = arr[i]; if ((0, util_ts_1.isPromise)(x)) { x = await x; } await fn(x, i, arr.length); result.push(x); } return result; }); } /** * Bluebird-style delay() method * @param ms - Milliseconds to delay * @returns Promise that resolves after the delay */ delay(ms) { return xaa.delay(ms); } /** * Bluebird-style timeout() method * @param ms - Milliseconds before timeout * @param message - Optional error message * @returns Promise that rejects if timeout occurs */ timeout(ms, message = "operation timed out") { return xaa .timeout(ms, message, { Promise: AveAzul, TimeoutError: operational_error_ts_1.OperationalError, }) .run(this); } /** * Bluebird-style props() for object properties * @returns Promise that resolves with an object of resolved values */ props() { return this.then((value) => { const obj = value; const keys = Object.keys(obj); const values = keys.map((k) => obj[k]); return AveAzul.all(values).then((results) => { const resolved = {}; keys.forEach((k, i) => { resolved[k] = results[i]; }); return resolved; }); }); } /** * Bluebird-style tapCatch() for side effects on rejection * @param fn - Function to execute on rejection * @returns Promise that maintains the rejection */ tapCatch(fn) { return this.catch((err) => { fn(err); throw err; }); } /** * Bluebird-style reduce() method for array reduction * Similar to Bluebird's Promise.prototype.reduce() * @param fn - Reducer function to apply to each element * @param initialValue - Optional initial value * @returns Promise that resolves with the final reduced value */ reduce(fn, initialValue) { const hasInitial = arguments.length > 1; return this.then(async (array) => { const arr = array; const len = arr.length; let value; let idx; if (hasInitial) { idx = 0; value = initialValue; } else { idx = 1; value = arr[0]; } value = (0, util_ts_1.isPromise)(value) ? await value : value; for (; idx < len; idx++) { let x = arr[idx]; if ((0, util_ts_1.isPromise)(x)) { x = await x; } value = await fn(value, x, idx, len); } return value; }); } /** * Bluebird-style throw() that returns a rejected promise with the given reason * @param reason - Value to reject the promise with * @returns Promise that rejects with the given reason */ throw(reason) { return AveAzul.reject(reason); } /** * Bluebird-style catchThrow() that catches an error and throws a new one * @param reason - Value to reject the promise with * @returns Promise that rejects with the new reason */ catchThrow(reason) { return this.catch(() => { throw reason; }); } /** * Bluebird-style catchReturn() that catches an error and returns a value instead * @param value - Value to return * @returns Promise that resolves with the given value */ catchReturn(value) { return this.catch(() => value); } /** * Bluebird-style get() for retrieving a property value * @param key - Key to retrieve * @returns Promise that resolves with the property value */ get(key) { return this.then((value) => value[key]); } /** * Bluebird-style disposer() for resource cleanup * @param fn - Cleanup function * @returns Disposer object */ disposer(fn) { if (typeof fn !== "function") { throw new TypeError("Expected a function"); } return new disposer_ts_1.Disposer(fn, this); } /** * Bluebird-style spread() method for handling array arguments * Similar to Bluebird's Promise.prototype.spread() * @param fn - Function to apply to the array arguments * @returns Promise that resolves with the function's return value */ spread(fn) { if (typeof fn !== "function") { return AveAzul.reject(new TypeError("expecting a function but got " + fn)); } return this.then(async (args) => { if (Array.isArray(args)) { for (let i = 0; i < args.length; i++) { if ((0, util_ts_1.isPromise)(args[i])) { args[i] = await args[i]; } } return fn(...args); } else { return fn(args); } }); } some(count) { return this.then((args) => { const arr = (0, util_ts_1.toArray)(args); return new AveAzul((resolve, reject) => { // If too many promises are rejected so that the promise can never become fulfilled, // it will be immediately rejected with an AggregateError of the rejection reasons // in the order they were thrown in. const errors = []; // The fulfillment value is an array with count values // in the order they were fulfilled. const results = []; const len = arr.length; let settled = false; const addDone = (result) => { if (settled) return; results.push(result); if (results.length >= count) { settled = true; // Resolve with exactly count results to match Bluebird's behavior resolve(results.slice(0, count)); } }; const addError = (err) => { if (settled) return; errors.push(err); if (len - errors.length < count) { settled = true; reject(new error_1.AggregateError(errors, `aggregate error`)); } }; for (let i = 0; i < len; i++) { const x = arr[i]; if ((0, util_ts_1.isPromise)(x)) { x.then(addDone, addError); } else { addDone(x); } } }); }); } /** * Bluebird-style all() method for array operations * Similar to Promise.all() but operates on the resolved value of this promise * @returns Promise that resolves when all items in the array resolve */ all() { return this.then((value) => { return AveAzul.all((0, util_ts_1.toArray)(value)); }); } /** * Bluebird-style asCallback() method * Attaches a callback to the promise and returns the promise. * The callback is invoked when the promise is resolved or rejected. * * @param cb - Node.js-style callback function (err, value) * @param options - Additional options * @returns The same promise instance */ asCallback(cb, options = {}) { if (typeof cb !== "function") { return this; } const spread = options && options.spread === true; this.then((value) => { try { if (spread && Array.isArray(value)) { cb(null, ...value); } else { cb(null, value); } } catch (err) { AveAzul.___throwUncaughtError(err); } }, (reason) => { try { cb(reason); } catch (err) { AveAzul.___throwUncaughtError(err); } }); return this; } nodeify(cb, options) { return this.asCallback(cb, options); } /** * Bluebird-style call() method for calling a method on the resolved value * @param methodName - Name of the method to call * @param args - Arguments to pass to the method * @returns Promise that resolves with the method's return value */ call(methodName, ...args) { return this.then(function (obj) { const method = obj[methodName]; if (typeof method === "function") { return method.call(obj, ...args); } throw new TypeError(`${String(methodName)} is not a function`); }); } /** * Catches only operational errors and passes them to the handler. * Programmer errors (non-operational) are rethrown. * @param handler - Function to handle operational errors * @returns Promise with the error handled or rethrown */ error(handler) { return this.catch((err) => { if ((0, operational_error_ts_1.isOperationalError)(err)) { return handler(err); } throw err; }); } /** * Static helper methods */ /** * Bluebird-style delay() that resolves after specified milliseconds * @param ms - Milliseconds to delay * @param value - Optional value to resolve with * @returns Promise that resolves after the delay */ static delay(ms, value) { if (value === undefined) { return AveAzul.resolve(xaa.delay(ms)); } return AveAzul.resolve(xaa.delay(ms, value)); } /** * Bluebird-style map() for array operations * @param value - Array to map over * @param fn - Map function to apply to each element * @returns Promise that resolves with the mapped array */ static map(value, fn, options = { concurrency: 50 }) { return AveAzul.resolve(value).map(fn, options); } /** * Bluebird-style mapSeries() for array operations * @param value - Array to map over * @param fn - Map function to apply to each element * @returns Promise that resolves with the mapped array */ static mapSeries(value, fn) { return AveAzul.map(value, fn, { concurrency: 1 }); } /** * Bluebird-style try() for wrapping sync/async functions * @param fn - Function to execute * @returns Promise that resolves with the function's return value */ static try(fn) { return AveAzul.resolve(xaa.wrap(fn)); } /** * Bluebird-style props() for object properties * @param obj - Object with promise values * @returns Promise that resolves with an object of resolved values */ static props(obj) { const keys = Object.keys(obj); const values = keys.map((k) => obj[k]); return AveAzul.all(values).then((results) => { const resolved = {}; keys.forEach((k, i) => { resolved[k] = results[i]; }); return resolved; }); } /** * Bluebird-style defer() for creating a deferred promise * @returns Deferred object with promise, resolve, and reject methods */ static defer() { return xaa.makeDefer(AveAzul); } /** * Bluebird-style each() for array iteration * @param items - Array to iterate over * @param fn - Iterator function to call for each item * @returns Promise that resolves when iteration is complete */ static each(items, fn) { return AveAzul.resolve(items).each(fn); } /** * Bluebird-style reduce() for array reduction * @param array - Array to reduce * @param fn - Reducer function (value, item, index, length) * @param initialValue - Optional initial value * @returns Promise that resolves with the final reduced value */ static reduce(array, fn, initialValue) { if (arguments.length > 2) { return AveAzul.resolve(array).reduce(fn, initialValue); } return AveAzul.resolve(array).reduce(fn); } /** * Bluebird-style promisify() for converting callback-based functions to promises * @param fn - Function to promisify * @param options - Options object * @returns Promisified function */ static promisify(fn, options) { return (0, promisify_ts_1.promisify)(fn, { ...options, Promise: AveAzul, }); } /** * Bluebird-style promisifyAll() for converting callback-based functions to promises * @param target - Object to promisify * @param options - Options object * @returns Object with promisified methods */ static promisifyAll(target, options) { return (0, promisify_all_ts_1.promisifyAll)(target, { ...options, Promise: AveAzul, }); } /** * Bluebird-style method() for creating a method that returns a promise * @param fn - Function to create a method for * @returns Method function that returns a promise */ static method(fn) { return function (...args) { return new AveAzul((resolve, reject) => { try { const result = fn.call(this, ...args); resolve(result); } catch (error) { reject(error); } }); }; } /** * Bluebird-style using() for resource management. There is only a static version of this method. * After the handler finish and returns, regardless of whether it resolves or rejects, the resources will be disposed. * * @param resources - Resource disposers, either an array of disposers or a variadic argument list * @param args - Handler function that will receive the resources as arguments * @returns Promise that resolves with handler result */ static using(resources, ...args) { if (args.length === 0) { throw new TypeError("resrouces and handler function required"); } if (Array.isArray(resources)) { if (args.length > 1) { throw new TypeError("only two arguments are allowed when passing an array of resources"); } return (0, using_ts_1.using)(resources, args[0], AveAzul, true); } const handler = args.pop(); return (0, using_ts_1.using)([resources, ...args], handler, AveAzul, false); } /** * Bluebird-style join() for joining promises * * @param args - Promises to join * @returns Promise that resolves with the handler's return value */ static join(...args) { if (args.length > 1 && typeof args[args.length - 1] === "function") { const handler = args.pop(); return AveAzul.all(args).then((results) => handler(...results)); } else { return AveAzul.all(args); } } /** * Bluebird-style fromCallback() for converting callback-based functions to promises * @param fn - Function to convert * @param options - Options object * @returns Promise that resolves with the function's return value */ static fromCallback(fn, options) { return new AveAzul((resolve, reject) => { try { fn((err, ...args) => { if (err) { reject(err); } else { if (options && options.multiArgs) { resolve(args); } else { resolve(args[0]); } } }); } catch (err) { reject(err); } }); } /** * Bluebird-style some() for waiting for some promises to resolve * @param promises - Array or iterable of promises * @param count - Number of promises that need to resolve * @returns Promise that resolves when count promises have resolved */ static some(promises, count) { return AveAzul.resolve(promises).some(count); } /** * Bluebird-style any() for waiting for any promise to resolve * @param args - Array or iterable of promises * @returns Promise that resolves with the first resolved value */ /* v8 ignore next 4 */ static any(args) { // Will be overwritten by addStaticAny throw new Error("any not initialized"); } } exports.AveAzul = AveAzul; AveAzul.fromNode = AveAzul.fromCallback; /** * When fatal error and AveAzul needs to crash the process, * this method is used to throw the error. * * @param error - The error to throw. */ AveAzul.___throwUncaughtError = util_ts_1.triggerUncaughtException; AveAzul.OperationalError = operational_error_ts_1.OperationalError; AveAzul.isOperationalError = operational_error_ts_1.isOperationalError; AveAzul.isProgrammerError = operational_error_ts_1.isProgrammerError; AveAzul.Disposer = disposer_ts_1.Disposer; // Setup the any method const any_ts_1 = require("./any.cjs"); (0, any_ts_1.addStaticAny)(AveAzul); // Setup the not implemented methods const not_implemented_ts_1 = require("./not-implemented.cjs"); (0, not_implemented_ts_1.setupNotImplemented)(AveAzul); exports.default = AveAzul; //# sourceMappingURL=aveazul.cjs.map