/* SPDX-FileCopyrightText: © 2025 Hornwitser 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(iterable: Iterable) { 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(it: Iterable, predicate: (value: T) => value is S): Generator; export function filter(it: Iterable, predicate: (value: T) => unknown): Generator; export function* filter(it: Iterable, predicate: (value: unknown) => unknown): Generator { for (const value of it) { if (predicate(value)) { yield value; } } } /** 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(iterable: Iterable) { 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( 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(...sets: Set[]) { 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( a: Map, b: Map, 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; }