UNPKG

flatten-anything

Version:

Flatten objects and replace nested props with 'prop.subprop'. A simple and small integration

90 lines (89 loc) 3.41 kB
import { omit } from 'filter-anything'; import { isArray, isNumber, isPlainObject } from 'is-what'; function retrievePaths(object, path, result, untilDepth) { if (!isPlainObject(object) || !Object.keys(object).length || `${object['methodName']}`?.includes('FieldValue')) { if (!path) return object; result[path] = object; return result; } if (isNumber(untilDepth)) untilDepth--; return Object.keys(object).reduce((carry, key) => { const pathUntilNow = path ? path + '.' : ''; const newPath = pathUntilNow + key; // last iteration or not const extra = untilDepth === -1 ? { [newPath]: object[key] } : retrievePaths(object[key], newPath, result, untilDepth); return Object.assign(carry, extra); }, {}); } /** * Flattens an object from `{a: {b: {c: 'd'}}}` to `{'a.b.c': 'd'}` * * @export * @param object the object to flatten * @param [number] how deep you want to flatten. 1 for flattening only the first nested prop, and keeping deeper objects as is. * @returns the flattened object */ export function flattenObject(object, untilDepth) { const result = {}; return retrievePaths(object, null, result, untilDepth); } /** * Flattens an array from `[1, ['a', ['z']], 2]` to `[1, 'a', 'z', 2]` * * @export * @param array the array to flatten * @returns the flattened array */ export function flattenArray(array) { return array.reduce((carry, item) => { return isArray(item) ? [...carry, ...flattenArray(item)] : [...carry, item]; }, []); } /** * Flattens certain props of an object. * * @export * @param object the object to flatten Eg. `{a: {subA: 1}, b: {subB: 1}}` * @param [props=[]] the prop names you want to flatten. Eg. `['a']` will return `{'a.subA': 1, b: {subB: 1}}` * @returns the flattened object */ export function flattenObjectProps(object, props = []) { const flatObject = props.reduce((carry, propPath) => { const firstPropKey = propPath.split('.')[0] ?? ''; const target = { [`${firstPropKey}`]: object[firstPropKey] }; // calculate a certain depth to flatten or `null` to flatten everything const untilDepth = propPath.split('.').length - 1 || undefined; const flatPart = flattenObject(target, untilDepth); const flatPartFiltered = Object.entries(flatPart).reduce((carry, [key, value]) => { if (!key.startsWith(propPath)) return carry; carry[key] = value; return carry; }, {}); return { ...carry, ...flatPartFiltered }; }, {}); const omittedProps = props; const objectWithoutFlatProps = omit(object, omittedProps); return { ...objectWithoutFlatProps, ...flatObject }; } /** * Flattens an object or array. * Object example: `{a: {b: {c: 'd'}}}` to `{'a.b.c': 'd'}` * Array example: `[1, ['a', ['z']], 2]` to `[1, 'a', 'z', 2]` * * @export * @param objectOrArray the payload to flatten * @param [number] how deep you want to flatten. (currently only works with objects) 1 for flattening only the first nested prop, and keeping deeper objects as is. * @returns the flattened result */ export function flatten(objectOrArray, untilDepth) { return isArray(objectOrArray) ? flattenArray(objectOrArray) : flattenObject(objectOrArray, untilDepth); }