geninq
Version:
A JavaScript version of the Linq library for Generators
95 lines (83 loc) • 2.54 kB
text/typescript
import { IsString } from "@paulpopat/safe-type";
import { Build, Promised } from "./utils";
declare global {
interface Generator<T = unknown, TReturn = any, TNext = unknown> {
single(): T;
single(allow_empty: "or-default"): T | undefined;
single(predicate: (item: T) => boolean): T;
single(
predicate: (item: T) => boolean,
allow_empty: "or-default"
): T | undefined;
single<TRes extends T>(predicate: (item: T) => item is TRes): TRes;
single<TRes extends T>(
predicate: (item: T) => item is TRes,
allow_empty: "or-default"
): TRes | undefined;
}
interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> {
single(): Promise<T>;
single(allow_empty: true): Promise<T | undefined>;
single(predicate: (item: T) => Promised<boolean>): Promise<T>;
single(
predicate: (item: T) => Promised<boolean>,
allow_empty: true
): Promise<T | undefined>;
single<TRes extends T>(predicate: (item: T) => item is TRes): Promise<TRes>;
single<TRes extends T>(
predicate: (item: T) => item is TRes,
allow_empty: "or-default"
): Promise<TRes | undefined>;
}
}
Build(
"single",
function (predicate, allow_empty) {
if (IsString(predicate)) {
allow_empty = predicate as "or-default";
predicate = (i): i is unknown => true;
} else if (!predicate) {
predicate = (i): i is unknown => true;
}
const matches = [];
for (const item of this) {
if (predicate(item)) {
matches.push(item);
if (matches.length > 1) {
throw new Error("Too many matches in sequence");
}
}
}
if (matches.length === 1) {
return matches[0];
}
if (allow_empty) {
return undefined;
}
throw new Error("No matching elements in sequence.");
},
async function (predicate, allow_empty) {
if (IsString(predicate)) {
allow_empty = predicate as "or-default";
predicate = (i): i is unknown => true;
} else if (!predicate) {
predicate = (i): i is unknown => true;
}
const matches = [];
for await (const item of this) {
if (await Promise.resolve(predicate(item))) {
matches.push(item);
if (matches.length > 1) {
throw new Error("Too many matches in sequence");
}
}
}
if (matches.length === 1) {
return matches[0];
}
if (allow_empty) {
return undefined;
}
throw new Error("No matching elements in sequence.");
}
);