| 1 | import util from 'node:util'; |
| 2 | |
| 3 | export default class Utils { |
| 4 | // STATE |
| 5 | public static isUndefined(value: unknown): boolean { |
| 6 | return typeof value === 'undefined'; |
| 7 | } |
| 8 | |
| 9 | public static ifUndefined<T>(value: T | undefined, isValue: T): T { |
| 10 | if (Utils.isUndefined(value) === true) return isValue; |
| 11 | return value as T; |
| 12 | } |
| 13 | |
| 14 | public static isIterable<T>(obj: T): boolean { |
| 15 | if (obj === null || obj === undefined) { |
| 16 | return false; |
| 17 | } |
| 18 | return typeof (obj as any)[Symbol.iterator] === 'function'; |
| 19 | } |
| 20 | |
| 21 | // public static ifNotIterableDo<T>(obj: T, cb: () => void): void { |
| 22 | // if (this.isIterable(obj) === false) cb(); |
| 23 | // } |
| 24 | |
| 25 | public static isPromisePending(promise: Promise<unknown>): boolean { |
| 26 | return util.inspect(promise).includes('pending'); |
| 27 | } |
| 28 | |
| 29 | public static async promiseWithTimeout<T>( |
| 30 | promise: Promise<T>, |
| 31 | timeoutMs: number, |
| 32 | timeoutError: Error, |
| 33 | timeoutCallback: () => void = () => { |
| 34 | /* This is intentional */ |
| 35 | } |
| 36 | ): Promise<T> { |
| 37 | // Create a timeout promise that rejects in timeout milliseconds |
| 38 | const timeoutPromise = new Promise<never>((_, reject) => { |
| 39 | setTimeout(() => { |
| 40 | if (Utils.isPromisePending(promise)) { |
| 41 | timeoutCallback(); |
| 42 | // FIXME: The original promise shall be canceled |
| 43 | } |
| 44 | reject(timeoutError); |
| 45 | }, timeoutMs); |
| 46 | }); |
| 47 | |
| 48 | // Returns a race between timeout promise and the passed promise |
| 49 | return Promise.race<T>([promise, timeoutPromise]); |
| 50 | } |
| 51 | |
| 52 | // FUNCTIONAL |
| 53 | // public static compose<T>(...fns: ((arg: T) => T)[]): (x: T) => T { |
| 54 | // return (x: T) => fns.reduceRight((y, fn) => fn(y), x); |
| 55 | // } |
| 56 | } |