aveazul
Version:
Bluebird drop-in replacement built on native Promise
648 lines • 23.1 kB
JavaScript
;
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