import type { Comparator } from './types'; export function isDefined(value: T): value is NonNullable { return typeof value !== 'undefined' && value !== null; } export function spaceList(...values: ReadonlyArray>): string { return values .flatMap((value) => { if (!value) { return []; } if (typeof value === 'string') { return value; } return Object.entries(value).flatMap(([key, condition]) => (condition ? key : [])); }) .join(' '); } export function baseComparator(selector: (source: S) => T, matcher: Comparator>): Comparator { return (sourceA, sourceB) => { const a = selector(sourceA); const b = selector(sourceB); if (a === b || (!isDefined(a) && !isDefined(b))) { return 0; } if (isDefined(a) && isDefined(b)) { return matcher(a, b); } return isDefined(a) ? -1 : 1; }; } export function textComparator( selector: (source: T) => string | null | undefined, locales?: string | string[], collatorOptions?: Intl.CollatorOptions, ): Comparator { return baseComparator(selector, (a, b) => a.localeCompare(b, locales, collatorOptions)); } export function numberComparator(selector: (source: T) => number | null | undefined): Comparator { return baseComparator(selector, (a, b) => a - b); }