UNPKG

geninq

Version:

A JavaScript version of the Linq library for Generators

148 lines (141 loc) 3.99 kB
import { Build, Promised } from "./utils"; import "./select"; import "./array"; import { Assert, IsFunction, IsNumber, IsString, IsTuple, IsUnion, PatternMatch, } from "@paulpopat/safe-type"; declare global { interface Generator<T = unknown, TReturn = any, TNext = unknown> { order_by( this: Generator<number, TReturn, TNext>, descending?: "descending" ): Generator<T, TReturn, TNext>; order_by( this: Generator<string, TReturn, TNext>, descending?: "descending" ): Generator<T, TReturn, TNext>; order_by( key_selector: (item: T) => number, descending?: "descending" ): Generator<T, TReturn, TNext>; order_by( key_selector: (item: T) => string, descending?: "descending" ): Generator<T, TReturn, TNext>; order_by<TKey>( key_selector: (item: T) => TKey, comparitor: (a: TKey, b: TKey) => boolean, descending?: "descending" ): Generator<T, TReturn, TNext>; } interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> { order_by( this: AsyncGenerator<number, TReturn, TNext>, descending?: "descending" ): AsyncGenerator<T, TReturn, TNext>; order_by( this: AsyncGenerator<string, TReturn, TNext>, descending?: "descending" ): AsyncGenerator<T, TReturn, TNext>; order_by( key_selector: (item: T) => Promised<number>, descending?: "descending" ): AsyncGenerator<T, TReturn, TNext>; order_by( key_selector: (item: T) => Promised<string>, descending?: "descending" ): AsyncGenerator<T, TReturn, TNext>; order_by<TKey>( key_selector: (item: T) => Promised<TKey>, comparitor: (a: TKey, b: TKey) => boolean, descending?: "descending" ): AsyncGenerator<T, TReturn, TNext>; } } function BuildArguments(args: IArguments): { key_selector: <T>(i: T) => T; comparitor: (a: unknown, b: unknown) => boolean; descending: boolean; } { const default_key_selector = <T>(i: T) => i; const default_comparitor = (a: unknown, b: unknown) => { Assert(IsUnion(IsString, IsNumber), a); Assert(IsUnion(IsString, IsNumber), b); return a > b; }; if (args.length === 0) { return { key_selector: default_key_selector, comparitor: default_comparitor, descending: false, }; } return PatternMatch( IsTuple(IsString), IsTuple(IsFunction, IsString), IsTuple(IsFunction, IsFunction, IsString), IsTuple(IsFunction), IsTuple(IsFunction, IsFunction) )( ([descending]) => ({ key_selector: default_key_selector, comparitor: default_comparitor, descending: descending != null, }), ([key_selector, descending]) => ({ key_selector, comparitor: default_comparitor, descending: descending != null, }), ([key_selector, comparitor, descending]) => ({ key_selector, comparitor, descending: descending != null, }), ([key_selector]) => ({ key_selector, comparitor: default_comparitor, descending: false, }), ([key_selector, comparitor]) => ({ key_selector, comparitor, descending: false, }) )([...args] as any) as any; } Build( "order_by", function* () { const m = BuildArguments(arguments); let new_subject = this.select((i) => [m.key_selector(i), i] as const) .array() .sort(([a], [b]) => (m.comparitor(a, b) ? 1 : -1)); if (m.descending) { new_subject = new_subject.reverse(); } for (const item of new_subject) { yield item[1]; } }, async function* () { const m = BuildArguments(arguments); let new_subject = ( await this.select( async (i) => [await m.key_selector(i), i] as const ).array() ).sort(([a], [b]) => (m.comparitor(a, b) ? 1 : -1)); if (m.descending) { new_subject = new_subject.reverse(); } for (const item of new_subject) { yield item[1]; } } );