import { sort } from 'fp-ts/lib/Array' import { Foldable, Foldable1, Foldable2, Foldable3 } from 'fp-ts/lib/Foldable' import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from 'fp-ts/lib/HKT' import { Magma } from 'fp-ts/lib/Magma' import * as O from 'fp-ts/lib/Option' import { Ord } from 'fp-ts/lib/Ord' import { pipe } from 'fp-ts/lib/pipeable' import { hasOwnProperty, isEmpty } from 'fp-ts/lib/Record' import { isObject } from '../typeGuards' import { forEach } from './Array' export * from 'fp-ts/lib/Record' /** * Retrieves the keys of an object while retaining keyof type information * * `T` suffix is "type" to differentiate this from the base Record keys function */ export const keysT = , K extends keyof A>( x: A, ): Array => Object.keys(x) as Array export const values = , V extends A[keyof A]>( x: A, ): Array => Object.values(x) as Array export const entries = < A extends Record, K extends keyof A, V extends A[K] >( x: A, ): Array<[K, V]> => Object.entries(x) as Array<[K, V]> /** * Retrieves the value of a given property key from an object (curried) */ export const prop = , K extends keyof A>( k: K, ) => (obj: A): A[K] => obj[k] /** * Omits the key-value pairs from an object associated with the provided keys */ export const omit = , K extends keyof A>( rec: A, ks: Array, ): { [P in Exclude]: A[P] } => { const { ...result } = rec pipe( ks, forEach(k => delete result[k]), ) return result } /** * A pipeable version of `omit`. * Omits the key-value pairs from an object associated with the provided keys */ export const omitI: , K extends keyof A>( ...ks: ReadonlyArray ) => (rec: A) => { [P in Exclude]: A[P] } = (...ks) => rec => { const { ...result } = rec ks.forEach(k => delete result[k]) return result } /** * Picks the key-value pairs from an object associated with the provided keys */ export const pick = , K extends keyof A>( rec: A, ks: Array, ): { [P in K]: A[P] } => { const result = {} as { [P in K]: A[P] } pipe( ks, forEach(k => { result[k] = rec[k] }), ) return result } export const sortRecords = < S extends Record, K extends keyof S & string, A extends S[K] >( ord: Ord, ) => (data: Array) => sort(ord)(data) /** * Type guard for `Record` from `object` */ export const isRecord = ( x: unknown, ): x is Record => isObject(x) /** * Check if a record is *not* empty */ export const isNotEmpty = ( r: Record, ) => !isEmpty(r) export function fromFoldableFilterMap( M: Magma, F: Foldable3, ): ( ta: Kind3, f: (a: A) => O.Option<[K, B]>, ) => Record export function fromFoldableFilterMap( M: Magma, F: Foldable2, ): ( ta: Kind2, f: (a: A) => O.Option<[K, B]>, ) => Record export function fromFoldableFilterMap( M: Magma, F: Foldable1, ): ( ta: Kind, f: (a: A) => O.Option<[K, B]>, ) => Record export function fromFoldableFilterMap( M: Magma, F: Foldable, ): ( ta: HKT, f: (a: A) => O.Option<[K, B]>, ) => Record export function fromFoldableFilterMap( M: Magma, F: Foldable, ): (ta: HKT, f: (a: A) => O.Option<[string, B]>) => Record { return (ta: HKT, f: (a: A) => O.Option<[string, B]>) => F.reduce>(ta, {}, (r, a) => pipe( f(a), O.map(([k, b]) => { r[k] = hasOwnProperty(k, r) ? M.concat(r[k], b) : b return r }), O.getOrElse(() => r), ), ) }