import isEqual from 'lodash/isEqual'; import isObject from 'lodash/isObject'; import transform from 'lodash/transform'; import { isNotEmpty } from './empty.util'; /** * Returns passed object without specified property */ export function deleteProperty(object: object, key: string): object { const { [key]: deletedKey, ...otherKeys } = object as { [key: string]: any }; return otherKeys; } /** * Returns true if the passed object is empty or has only empty property. * hasOnlyEmptyProperties({}); // true * hasOnlyEmptyProperties({a: null}); // true * hasOnlyEmptyProperties({a: []}); // true * hasOnlyEmptyProperties({a: [], b: {}); // true * hasOnlyEmptyProperties({a: 'a', b: 'b'}); // false * hasOnlyEmptyProperties({a: [], b: 'b'}); // false */ export function hasOnlyEmptyProperties(obj: object): boolean { const objectType = typeof obj; if (objectType === 'object') { if (Object.keys(obj).length === 0) { return true; } else { let result = true; for (const key in obj) { if (isNotEmpty(obj[key])) { result = false; break; } } return result; } } } /** * Returns diff from the base object. * difference({}, {}); // {} * difference({a: 'a', b: 'b'}, {a: 'a'}); // {b: 'b'} * difference({a: 'a', b: {}}, {a: 'a'}); // {} * difference({a: 'a'}, {a: 'a', b: 'b'}); // {} */ export function difference(object: object, base: object) { const changes = (o, b) => { return transform(o, (result, value, key) => { if (!isEqual(value, b[key]) && isNotEmpty(value)) { const resultValue = ((isObject(value) && isObject(b[key])) ? changes(value, b[key]) : value) as object; if (!hasOnlyEmptyProperties(resultValue)) { result[key] = resultValue; } } }); }; return changes(object, base); }