@szydlovski/deep-object
Version:
utility functions for deeply nested objects
39 lines (35 loc) • 1.39 kB
text/typescript
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;
}