owltide/shared/utils/functions.ts

110 lines
2.7 KiB
TypeScript
Raw Normal View History

/*
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
SPDX-License-Identifier: AGPL-3.0-or-later
*/
/** Returns a tuple consisting of a running index starting from 0, and the item of the iterable */
export function* enumerate<T>(iterable: Iterable<T>) {
let index = 0;
for (const item of iterable) {
yield [index++, item] as [number, T];
}
}
/** Filters an iterable based on the passed predicate function */
export function filter<T, S extends T>(it: Iterable<T>, predicate: (value: T) => value is S): Generator<S, void, unknown>;
export function filter<T>(it: Iterable<T>, predicate: (value: T) => unknown): Generator<T, void, unknown>;
export function* filter(it: Iterable<unknown>, predicate: (value: unknown) => unknown): Generator<unknown, void, unknown> {
for (const value of it) {
if (predicate(value)) {
yield value;
}
}
}
2025-03-15 13:46:13 +01:00
/** Converts a name to an id */
export function toId(name: string) {
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
}
/** Returns adjacent pairs from iterable */
export function* pairs<T>(iterable: Iterable<T>) {
let first;
let second;
for (const [index, item] of enumerate(iterable)) {
[first, second] = [second, item];
if (index >= 1) {
yield [first, second] as [T, T];
}
}
}
/**
Returns true if the two arrays passed as input compare equal to each other.
@param a Input array
@param b Input array
@param equals Function to compare individual elements in the array.
@returns True if the arrays compare equal
*/
export function arrayEquals<T>(
a: T[],
b: T[],
equals: (a: T, b: T) => unknown = (a, b) => a === b,
) {
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (!equals(a[i], b[i])) {
return false;
}
}
return true;
}
/**
Returns true if all sets are equal
@param sets set to compare
@returns true if all sets are the same size and have the same elements
*/
export function setEquals<T>(...sets: Set<T>[]) {
if (sets.length < 2) {
throw TypeError("At least two sets must be passed to setEquals");
}
const ref = sets[0];
const rest = sets.slice(1);
if (rest.some(set => set.size !== ref.size)) {
return false;
}
for (const set of rest) {
for (const el of set) {
if (!ref.has(el)) {
return false;
}
}
}
return true;
}
/**
Returns true if the two maps passed as input compare equal to each other.
@param a Input map
@param b Input map
@param equals Function to compare individual values in the map.
@returns True if the maps compare equal
*/
export function mapEquals<K, V>(
a: Map<K, V>,
b: Map<K, V>,
equals: (a: V, b: V) => unknown = (a, b) => a === b,
) {
if (a.size !== b.size) {
return false;
}
for (const [key, value] of a) {
if (!b.has(key) || value !== b.get(key)) {
return false;
}
}
return true;
}