export type MaybeArray = T | T[]; export type MaybePromise = T | Promise | PromiseLike; export interface Prioritizeable { readonly priority: number; readonly value: T; } export namespace Prioritizeable { export type GetPriority = (value: T) => MaybePromise; export type GetPrioritySync = (value: T) => number; export async function toPrioritizeable(rawValue: MaybePromise, getPriority: GetPriority): Promise>; export async function toPrioritizeable(rawValue: MaybePromise[], getPriority: GetPriority): Promise[]>; export async function toPrioritizeable(rawValue: MaybeArray>, getPriority: GetPriority): Promise>> { if (rawValue instanceof Array) { return Promise.all( rawValue.map(v => toPrioritizeable(v, getPriority)) ); } const value = await rawValue; const priority = await getPriority(value); return { priority, value }; } export function toPrioritizeableSync(rawValue: T[], getPriority: GetPrioritySync = value => (value).priority): Prioritizeable[] { return rawValue.map(v => ({ value: v, priority: getPriority(v) })); } export function prioritizeAllSync(values: T[], getPriority?: GetPrioritySync): Prioritizeable[] { const prioritizeable = toPrioritizeableSync(values, getPriority); return prioritizeable.filter(isValid).sort(compare); } export async function prioritizeAll(values: MaybePromise[], getPriority: GetPriority): Promise[]> { const prioritizeable = await toPrioritizeable(values, getPriority); return prioritizeable.filter(isValid).sort(compare); } export function isValid(p: Prioritizeable): boolean { return p.priority > 0; } export function compare(p: Prioritizeable, p2: Prioritizeable): number { return p2.priority - p.priority; } }