sussy-util
Version:
Util package made by me
300 lines (299 loc) • 12.6 kB
JavaScript
;
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _PromiseUtil_resFirst, _PromiseUtil_resReplace, _PromiseUtil_resLast, _PromiseUtil_MAPPINGS;
Object.defineProperty(exports, "__esModule", { value: true });
const IsSomething_1 = __importDefault(require("./IsSomething"));
class PromiseUtil {
constructor() {
/**
* Resolves or rejects a promise based on the provided result and error.
*
* @template R - Type of the promise result.
* @template E - Type of the error.
* @param {Function} resolve - The resolve function of a promise.
* @param {Function} reject - The reject function of a promise.
* @param {R} result - The result value of the promise.
* @param {E | null} error - The error value of the promise (or null if there is no error).
* @private
*/
_PromiseUtil_resFirst.set(this, (resolve, reject, result, error) => {
if (error) {
return reject(error);
}
resolve(result);
});
/**
* Resolves or rejects a promise based on the provided result, which can be a result value or an error.
*
* @template R - Type of the promise result.
* @template E - Type of the error.
* @param {Function} resolve - The resolve function of a promise.
* @param {Function} reject - The reject function of a promise.
* @param {R | E} result - The result value of the promise (or an error).
* @private
*/
_PromiseUtil_resReplace.set(this, (resolve, reject, result) => {
if (result instanceof Error) {
return reject(result);
}
resolve(result);
});
/**
* Resolves or rejects a promise based on the provided error and result.
*
* @template R - Type of the promise result.
* @template E - Type of the error.
* @param {Function} resolve - The resolve function of a promise.
* @param {Function} reject - The reject function of a promise.
* @param {E | null} error - The error value of the promise (or null if there is no error).
* @param {R} result - The result value of the promise.
* @private
*/
_PromiseUtil_resLast.set(this, (resolve, reject, error, result) => {
if (error) {
return reject(error);
}
resolve(result);
});
/**
* Mapping of callback positions and error handling functions.
* @private
*/
_PromiseUtil_MAPPINGS.set(this, {
'front-first': {
args: (args, callback) => [callback, ...args],
function1: __classPrivateFieldGet(this, _PromiseUtil_resLast, "f"),
},
'front-replace': {
args: (args, callback) => [callback, ...args],
function1: __classPrivateFieldGet(this, _PromiseUtil_resReplace, "f"),
},
'front-last': {
args: (args, callback) => [callback, ...args],
function1: __classPrivateFieldGet(this, _PromiseUtil_resFirst, "f"),
},
'back-first': {
args: (args, callback) => [...args, callback],
function1: __classPrivateFieldGet(this, _PromiseUtil_resLast, "f"),
},
'back-replace': {
args: (args, callback) => [...args, callback],
function1: __classPrivateFieldGet(this, _PromiseUtil_resReplace, "f"),
},
'back-last': {
args: (args, callback) => [...args, callback],
function1: __classPrivateFieldGet(this, _PromiseUtil_resFirst, "f"),
},
});
}
/**
* Execute an array of promises sequentially and collect results and errors.
*
* @template T - Type of the promise results.
* @param {PromiseOr<T>[]} promises - Array of promises to execute.
* @returns {Promise<[Array<T | null>, Error[]]>} - A promise that resolves to an array of results and errors.
*/
async executeSequentially(promises) {
const errors = [];
const results = await promises.reduce(async (chain, promise) => {
const results = await chain;
const [result, error] = await this.handler(promise);
results.push(result);
if (error) {
errors.push(error);
}
return results;
}, Promise.resolve([]));
return [results, errors];
}
/**
* Handle a promise, including error handling.
*
* @template R - Type of the promise result.
* @template E - Type of the error.
* @param {PromiseOr<R> | AsyncFunction<R>} promise - The promise to handle.
* @returns {Promise<[R | null, E | null]>} - A promise that resolves to a tuple of result and error.
*/
async handler(promise) {
try {
if (IsSomething_1.default.isFunction(promise))
promise = promise();
const data = await promise;
return [data, null];
}
catch (e) {
return [null, e];
}
}
/**
* Retry executing a function with a specified number of retries.
*
* @template T - Type of the function result.
* @param {() => PromiseOr<T>} func - The function to retry.
* @param {number} [maxRetries=3] - The maximum number of retries.
* @returns {Promise} A promise that resolves to the result and an array of errors.
*/
async retry(func, maxRetries = 3) {
const errors = [];
let result = null;
for (let i = 0; i <= maxRetries; i++) {
try {
result = await func();
break;
}
catch (error) {
errors.push(error);
}
}
return [result, errors];
}
/**
* Delay execution for a specified number of milliseconds.
*
* @param {number} milliseconds - The delay duration in milliseconds.
* @returns {Promise<void>} A promise that resolves after the delay.
*/
async delay(milliseconds) {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}
/**
* Filter an array of values using an asynchronous filter function.
*
* @template T - Type of the values.
* @param {T[]} values - The array of values to filter.
* @param {(value: T) => PromiseOr<boolean>} asyncFilterFunc - The asynchronous filter function.
* @returns {Promise<T[]>} A promise that resolves to the filtered array.
*/
async filter(values, asyncFilterFunc) {
const results = await Promise.all(values.map(async (value) => ({
value,
shouldKeep: await asyncFilterFunc(value),
})));
return results.filter((result) => result.shouldKeep).map((result) => result.value);
}
/**
* Timeout a promise after a specified duration.
*
* @template T - Type of the promise result.
* @param {PromiseOr<T>} promise - The promise to add a timeout to.
* @param {number} milliseconds - The timeout duration in milliseconds.
* @returns {Promise<T>} A promise that resolves with the result or rejects with a timeout error.
*/
async timeout(promise, milliseconds) {
return Promise.race([
promise,
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout exceeded')), milliseconds)),
]);
}
/**
* Execute promises in batches and collect results.
*
* @template T - Type of input values.
* @template R - Type of promise results.
* @param {T[]} values - Array of input values.
* @param {number} batchSize - Size of each batch.
* @param {(value: T) => PromiseOr<R>} asyncFunc - Asynchronous function to apply to each value.
* @returns {Promise<R[]>} - A promise that resolves to an array of results.
*/
async batchPromises(values, batchSize, asyncFunc) {
const results = [];
for (let i = 0; i < values.length; i += batchSize) {
const batch = values.slice(i, i + batchSize);
const batchResults = await Promise.all(batch.map(asyncFunc));
results.push(...batchResults);
}
return results;
}
/**
* Promisify a function, allowing customization of callback and error positions.
*
* @template T - Type of arguments to the function.
* @template R - Type of the promise result.
* @param {Function} func - The function to promisify.
* @param {options} [options={ callBackPosition: "back", errorPosition: "last" }] - Options for customization.
* @returns {Function} A promisified function.
*/
promisify(func, { callBackPosition = 'back', errorPosition = 'last' } = {
callBackPosition: 'back',
errorPosition: 'last',
}) {
return (...args) => new Promise((resolve, reject) => {
const key = `${callBackPosition}-${errorPosition}`;
const current = __classPrivateFieldGet(this, _PromiseUtil_MAPPINGS, "f")[key];
if (!current)
throw new Error('ERR: Invalid callBackPosition or errorPosition');
// @ts-expect-error - Dynamic function call
func(...current.args(args, current.function1.bind(this, resolve, reject)));
});
}
/**
* Map an array of values to an array of promises and await their results.
* @param values Array of values to map to promises.
* @param asyncMapFunc Function to map values to promises.
* @returns Array of results.
*/
async mapPromises(values, asyncMapFunc) {
return await Promise.all(values.map(asyncMapFunc));
}
/**
* Concurrently map an array of values to promises with a specified concurrency limit.
* @param values Array of values to map to promises.
* @param asyncMapFunc Function to map values to promises.
* @param concurrency Maximum number of promises to run concurrently.
* @returns Array of results.
*/
async concurrentMap(values, asyncMapFunc, concurrency) {
const results = [];
let index = 0;
async function processNext() {
while (index < values.length) {
const value = values[index++];
const result = await asyncMapFunc(value);
results.push(result);
}
}
const concurrencyPromises = [];
for (let i = 0; i < concurrency; i++) {
concurrencyPromises.push(processNext());
}
await Promise.all(concurrencyPromises);
return results;
}
/**
* Execute an array of promises concurrently with a specified concurrency limit.
*
* @template T - Type of the promise results.
* @param {PromiseOr<T>[]} promises - Array of promises to execute.
* @param {number} concurrency - Maximum number of promises to run concurrently.
* @returns {Promise<[Array<T | null>, Error[]]>} - A promise that resolves to an array of results and errors.
*/
async executeConcurrently(promises, concurrency) {
const errors = [];
const results = await this.concurrentMap(promises, async (promise) => {
const [result, error] = await this.handler(promise);
if (error) {
errors.push(error);
}
return result;
}, concurrency);
return [results, errors];
}
static getInstance() {
return this.instance;
}
}
_PromiseUtil_resFirst = new WeakMap(), _PromiseUtil_resReplace = new WeakMap(), _PromiseUtil_resLast = new WeakMap(), _PromiseUtil_MAPPINGS = new WeakMap();
/**
* Singleton instance of the PromiseUtil class.
* @private
* @static
*/
PromiseUtil.instance = new PromiseUtil();
exports.default = PromiseUtil.getInstance();