/* eslint-disable import/prefer-default-export */ import { Dict } from '@mike-north/types'; import * as ts from 'typescript'; function isUem(dict: ts.UnderscoreEscapedMap | Dict): dict is ts.UnderscoreEscapedMap { return typeof dict.clear === 'function'; } /** * Invoke a callback for each key-value pair in a dictionary * @param dict dictionary to iterate over * @param callback mapping function to apply to each key-value pair * @public */ export function forEachDict( dict: ts.UnderscoreEscapedMap | Dict, cb: (t: T, key: ts.__String | string) => void, ): void { if (isUem(dict)) { dict.forEach(cb); } else { Object.keys(dict).forEach((key) => { const item = dict[key] as T; cb(item, key); }); } } /** * Map over a dictionary * @param dict dictionary to iterate over * @param callback mapping function to apply to each key-value pair * @public */ export function mapDict( dict: ts.UnderscoreEscapedMap | Dict, callback: (t: T, key: ts.__String | string) => S | undefined, ): Dict { return reduceDict( dict, (d, item, key) => { const transformed = callback(item, key); if (typeof transformed !== 'undefined') { // eslint-disable-next-line no-param-reassign d[key.toString()] = transformed; } return d; }, {} as Dict, ); } /** * Filter a dictionary * @param dict dictionary to iterate over * @param callback mapping function to apply to each key-value pair * @public */ export function filterDict( dict: ts.UnderscoreEscapedMap | Dict, filterFn: (t: T, key: ts.__String | string) => boolean, ): Dict { return reduceDict( dict, (d, item, key) => { if (filterFn(item, key)) { // eslint-disable-next-line no-param-reassign d[typeof key === 'string' ? key : key.toString()] = item; } return d; }, {} as Dict, ); } /** * Reduce a dictionary * @param dict dictionary to iterate over * @param callback mapping function to apply to each key-value pair * @public */ export function reduceDict( dict: ts.UnderscoreEscapedMap | Dict, callback: (reduced: R, t: T, key: ts.__String | string) => R, initial: R, ): R { let reducedVal: R = initial; forEachDict(dict, (val, key) => { reducedVal = callback(reducedVal, val, key); }); return reducedVal; }