/* Copyright 2026 Marimo. All rights reserved. */ export const Objects = { EMPTY: Object.freeze({}) as Record, mapValues( obj: Record, mapper: (value: T, key: K) => U, ): Record { if (!obj) { return obj as Record; } return Objects.fromEntries( Objects.entries(obj).map(([key, value]) => [key, mapper(value, key)]), ); }, /** * Type-safe Object.fromEntries */ fromEntries(obj: [K, V][]): Record { return Object.fromEntries(obj) as Record; }, /** * Type-safe Object.entries */ entries(obj: Record): [K, V][] { return Object.entries(obj) as [K, V][]; }, /** * Type-safe Object.keys */ keys(obj: Record): K[] { return Object.keys(obj) as K[]; }, size(obj: Record): number { return Object.keys(obj).length; }, /** * Type-safe keyBy */ keyBy( items: T[], toKey: (item: T) => K | undefined, ): Record { const result: Record = {} as Record; for (const item of items) { const key = toKey(item); if (key === undefined) { continue; } result[key] = item; } return result; }, /** * Collect */ collect( items: T[], key: (item: NoInfer) => K, mapper: (item: NoInfer) => V, ): Record { return Objects.mapValues(Objects.keyBy(items, key), mapper); }, /** * Type-safe groupBy */ groupBy( items: T[], toKey: (item: T) => K | undefined, toValue: (item: T) => V, ): Record { const result: Record = {} as Record; for (const item of items) { const key = toKey(item); if (key === undefined) { continue; } const value = toValue(item); if (key in result) { result[key].push(value); } else { result[key] = [value]; } } return result; }, filter( obj: Record, predicate: (value: V, key: K) => boolean, ): Record { const result: Record = {} as Record; for (const [key, value] of Objects.entries(obj)) { if (predicate(value, key)) { result[key] = obj[key]; } } return result; }, omit( obj: V, keys: K[] | Set, ): Partial { const set = new Set(keys); return Objects.filter(obj, (_, key) => !set.has(key)); }, // oxlint-disable-next-line typescript/no-explicit-any pick, K extends string>( obj: V, keys: readonly K[], ): Pick { const result = {} as Record; for (const key of keys) { if (Object.hasOwn(obj, key)) { result[key] = obj[key]; } } return result as Pick; }, };