import md5 from 'md5' import { forEach } from 'lodash' export type AddChange = { type: 'add' key: string value: any } export type ModifyChange = { type: 'modify' key: string value: any oldValue: any } export type RemovedChange = { type: 'remove' key: string oldValue: any } export type Change = AddChange | ModifyChange | RemovedChange export const computeHash = (value: any) => { if (value === null) { return 'null' } if (value === undefined) { return 'undefined' } let str = value try { if (typeof str === 'object') { str = JSON.stringify(value) } else { str = typeof value + '::' + value.toString() } } catch (error) { str = error.message + '::' + error.stack } return md5(str) } export const diffObjectShallow = ( objectA: object, objectB: object, computeHashFn = computeHash, ) => { const changes: Change[] = [] const docsMapACopy = { ...objectA } forEach(objectB, (valueB, key) => { const valueA = docsMapACopy[key] if (valueA) { delete docsMapACopy[key] const hashA = computeHashFn(valueA) const hashB = computeHashFn(valueB) if (hashA === hashB) { return } return changes.push({ type: 'modify', key, oldValue: valueA, value: valueB, }) } changes.push({ type: 'add', key, value: valueB, }) }) forEach(docsMapACopy, (value, key) => { changes.push({ type: 'remove', key, oldValue: value, }) }) return changes }