UNPKG

@naturalcycles/js-lib

Version:

Standard library for universal (browser + Node.js) javascript

93 lines (79 loc) 2.33 kB
import { _stringMapValues } from '../types.js' import type { Comparator, Mapper, SortDirection, SortOptions, StringMap } from '../types.js' class Comparators { /** * Good for numbers. */ numericAsc(this: void, a: number, b: number): number { return a - b } numericDesc(this: void, a: number, b: number): number { return b - a } localeAsc(this: void, a: string, b: string): number { return a.localeCompare(b) } localeDesc(this: void, a: string, b: string): number { return -a.localeCompare(b) } by<T, COMPARE_TYPE extends string | number>( this: void, mapper: Mapper<T, COMPARE_TYPE>, opt: ComparatorByOptions = {}, ): Comparator<T> { const mod = opt.dir === 'desc' ? -1 : 1 return (objA: T, objB: T): number => { // This implementation may call mapper more than once per item, // but the benchmarks show no significant difference in performance. const a = mapper(objA) const b = mapper(objB) if (a > b) return mod if (a < b) return -mod return 0 } } updatedAsc(this: void, a: { updated: number }, b: { updated: number }): number { return a.updated - b.updated } updatedDesc(this: void, a: { updated: number }, b: { updated: number }): number { return b.updated - a.updated } createdAsc(this: void, a: { created: number }, b: { created: number }): number { return a.created - b.created } createdDesc(this: void, a: { created: number }, b: { created: number }): number { return b.created - a.created } } export const comparators = new Comparators() interface ComparatorByOptions { /** * Defaults to 'asc'. */ dir?: SortDirection } /** * _sortBy([{age: 20}, {age: 10}], 'age') * // => [{age: 10}, {age: 20}] * * Same: * _sortBy([{age: 20}, {age: 10}], o => o.age) */ export function _sortBy<T, COMPARE_TYPE extends string | number>( items: T[], mapper: Mapper<T, COMPARE_TYPE>, opt: SortOptions = {}, ): T[] { const cmp = comparators.by(mapper, opt) return opt.mutate ? items.sort(cmp) : items.toSorted(cmp) } /** * Like _stringMapValues, but values are sorted. */ export function _stringMapValuesSorted<T>( map: StringMap<T>, mapper: Mapper<T, any>, dir: SortDirection = 'asc', ): T[] { return _sortBy(_stringMapValues(map), mapper, { dir }) }