export type MaybeIterable = T | Iterable; export type NonEmptyArray = [T, ...T[]]; export type AsyncYieldType = T extends AsyncGenerator ? U : never; export function surelyIterable(maybe: MaybeIterable): Iterable { return typeof maybe === "object" && maybe !== null && Symbol.iterator in maybe ? maybe : [maybe]; } export async function* createAsyncIterator( promises: Promise[], ): AsyncGenerator { for (const promise of promises) { yield promise; } } export function filterDuplicate( array: Iterable, key: (i: T) => K, ): T[] { const seen = new Map(); for (const i of array) { const id = key(i); if (!seen.has(id)) { seen.set(id, i); } } return Array.from(seen.values()); } export async function findMapAsync( iter: Iterable, predicate: (value: T) => Promise, ): Promise { const arr = Array.from(iter); async function tryNext(index: number): Promise { if (index >= arr.length) { return await Promise.resolve(undefined); } try { return await predicate(arr[index]); } catch { return tryNext(index + 1); } } return await tryNext(0); } export function createRanges(nums: Iterable): string[] { const ns = new Set(nums).values().toArray().sort(( a, b, ) => a - b); const result = []; let start = ns[0]; let end = ns[0]; for (let i = 1; i <= ns.length; i++) { if (ns[i] === end + 1) { end = ns[i]; } else { if (start === end) { result.push(`${start}`); } else { result.push(`${start}-${end}`); } start = ns[i]; end = ns[i]; } } return result; }