UNPKG

@szydlovski/deep-object

Version:

utility functions for deeply nested objects

39 lines (35 loc) 1.39 kB
export type StringIndexed = Record<string, any>; export type OpCb<T = any, V = any> = (value: V, key: string, path: string[], target: T, isObject: boolean) => any; export type OpArgs<T, V> = [T, OpCb<T, V>, boolean, string[]?]; export function _deepObjectOperation<T = StringIndexed, V = any>(...args: OpArgs<T, V>): void { const [target, callback, depthFirst, pathSoFar = []] = args; const entries = Object.entries(target); const trvD = () => entries.forEach(([key, value]) => _isObject(value) && _deepObjectOperation(value, callback, depthFirst, [...pathSoFar, key])); const trvB = () => entries.forEach(([key, value]) => callback(value, key, [...pathSoFar, key], target, _isObject(value))); if (depthFirst) { trvD(); trvB(); } else { trvB(); trvD(); } } export function _isObject(value: any): boolean { return ( value !== null && typeof value === 'object' && value.constructor === Object ); } export function _deepObjectTraverse<F extends boolean = true>(target: StringIndexed, [...path]: string[], create: F | true = true): StringIndexed { let step: string | undefined; while (step = path.shift()) { if (!_isObject(target[step])) { if (create) { target[step] = {}; } else { throw new TypeError('Cannot traverse object, provided path does not exist') } } target = target[step]; } return target; }