import { transform, isEqual, isObject, get } from 'lodash' type Dict = { [key: string]: boolean | Dict } export function diff(newObject: any = {}, oldObject: any = {}, ignore?: Dict) { const currentIgnoreList = ignore ? Object.entries(ignore).reduce( (accumulator, [key, value]) => typeof value === 'boolean' ? [...accumulator, key] : accumulator, [] as string[] ) : [] const transformResult = transform( newObject, (result: any, value: any, key: string) => { if (!currentIgnoreList.includes(key) && !isEqual(value, oldObject[key])) { const child = ignore && ignore[key] let childIgnoreList if (result instanceof Array) { childIgnoreList = ignore } else if (typeof child !== 'boolean') { childIgnoreList = child } else { childIgnoreList = undefined } const newValue = isObject(value) && isObject(oldObject[key]) ? diff(value, oldObject[key], childIgnoreList) : value if (newValue !== undefined && newValue !== null) result[key] = newValue } } ) return Object.keys(transformResult).length > 0 ? transformResult : undefined } export function deepDiff( newObject: any = {}, oldObject: any = {}, ignore?: Dict ) { return { added: diff(newObject, oldObject, ignore), removed: diff(oldObject, newObject, ignore) } } interface IcompareOptions { compareKeys: (keyof T)[] diffIgnore?: Dict keyNames?: { inA: string inB: string } } export function compare( objectsA: T[], objectsB: T[], compareOptions: IcompareOptions ) { const { keyNames, diffIgnore, compareKeys } = compareOptions const { inA, inB } = keyNames || { inA: 'inFile', inB: 'inDb' } let copyB = [...objectsB] let copyA: T[] = [] for (let objectA of objectsA) { const idxObjectB = copyB.findIndex(objectB => compareKeys.reduce((accumulator, value) => { console.log(get) return accumulator && get(objectA, value, 1) === get(objectB, value, 2) }, true as boolean) ) const objectB = copyB[idxObjectB] copyB = [...copyB.slice(0, idxObjectB), ...copyB.slice(idxObjectB + 1)] copyA = [ ...copyA, { ...objectA, changes: deepDiff(objectA, objectB, diffIgnore), [inA]: true, [inB]: !!objectB } ] } for (let objectB of copyB) { copyA = [ ...copyA, { ...objectB, changes: deepDiff(undefined, objectB, diffIgnore), [inA]: false, [inB]: true } ] } return copyA }