UNPKG

@dillonkearns/elm-graphql

Version:

<img src="https://cdn.jsdelivr.net/gh/martimatix/logo-graphqelm/logo.svg" alt="dillonearns/elm-graphql logo" width="40%" align="right">

88 lines (67 loc) 2.49 kB
// @flow import {curry} from "flow-static-land/lib/Fun"; import {isLastIndex} from "@jumpn/utils-array"; import get from "./get"; import hasKey from "./hasKey"; import remove from "./remove"; import shallowCopy from "./shallowCopy"; import type {Composite, Path} from "./types"; const createReduceContext = composite => { const origin = shallowCopy(composite); return {origin, previous: undefined, current: origin}; }; const createSupporting = key => (typeof key === "number" ? [] : {}); const copyOrCreate = (key, nextKey, current) => hasKey(key, current) ? shallowCopy(get(key, current)) : createSupporting(nextKey); const getNext = (path, updater, index, current) => isLastIndex(path, index) ? updater(get(path[index], current)) : copyOrCreate(path[index], path[index + 1], current); const set = (key, value, composite) => { // eslint-disable-next-line no-param-reassign composite[(key: any)] = value; return get(key, composite); }; const updateSet = (path, index, value, context) => ({ ...context, current: set(path[index], value, context.current) }); const updateRemove = (path, index, context) => { const removed = remove(path[index], context.current); return index === 0 ? {...context, current: removed, origin: removed} : { ...context, previous: set(path[index - 1], removed, (context.previous: any)) }; }; const removeAction = Symbol("composite.updateIn.removeAction"); const update = (path, index, value, context) => value === removeAction ? updateRemove(path, index, context) : updateSet(path, index, value, context); const getReducer = (path, updater) => (context, key, index) => update(path, index, getNext(path, updater, index, context.current), context); /** * Returns a new composite with the result of having updated the property value * at the given path with the result of the call to updater function. * * Entry removal is supported by returning `updateIn.remove` symbol on updater * function. */ const updateIn = ( path: Path, updater: (prev: any) => any, composite: Composite ): Composite => path.length === 0 ? composite : path.reduce(getReducer(path, updater), createReduceContext(composite)) .origin; // we are doing this way and not returning an Object.assign construction, as // that is not well typed (returns any) const updateInCurried = curry(updateIn); updateInCurried.remove = removeAction; export default updateInCurried;