import { curry, id } from '@typed/lambda' import { fromJust, isNothing } from '@typed/maybe' import { append } from '../append/append' import { findIndex } from '../findIndex' import { remove } from '../remove' /** * Append a value to a list if it does not exist or remove if it does exist. * Useful for toggling things on/off. * * @param item :: a * @param items :: [a] * @returns :: [a] */ export const appendOrRemove = curry((item: A, items: ReadonlyArray): A[] => __appendOrRemove(item, items, id), ) as { (item: A, items: ReadonlyArray): A[] (item: A): (items: ReadonlyArray) => A[] } /** * Append a value to a list if it does not exist or remove if it does exist. * Allows providing a custom comparison function. * * @param item :: a * @param items :: [a] * @param comparison :: (a -> b) * @returns :: [a] */ export const appendOrRemoveBy = curry(__appendOrRemove) as { (item: A, items: ReadonlyArray, comparison: (value: A) => B): A[] (item: A, items: ReadonlyArray): (comparison: (value: A) => B) => A[] (item: A): { (items: ReadonlyArray, comparison: (value: A) => B): A[] (items: ReadonlyArray): (comparison: (value: A) => B) => A[] } } function __appendOrRemove( item: A, items: ReadonlyArray, comparison: (value: A) => B, ): A[] { const b = comparison(item) const index = findIndex((a) => comparison(a) === b, items) if (isNothing(index)) { return append(item, items) } return remove(fromJust(index), 1, items) }