diff --git a/src/functions/get-object-diff.ts b/src/functions/get-object-diff.ts index 4501bd5ff..b1f126915 100644 --- a/src/functions/get-object-diff.ts +++ b/src/functions/get-object-diff.ts @@ -1,51 +1,39 @@ -import { keys, hasOwn, toStringTag, intrinsicTypeNameSet, isArray } from "./utils"; +import { keys, hasOwn, toStringTag } from './utils'; -export const getValueOf = (val:any, type: string) => - type === "Array" ? ''+val.map(v => getValueOf(v, toStringTag(v))) : - type === "ArrayBuffer" ? ''+new Uint8Array(val) : - type === "Date" ? val.getTime() : - ArrayBuffer.isView(val) ? ''+new Uint8Array(val.buffer) : - val; +export function getObjectDiff(a: any, b: any, rv?: any, prfx?: string) { + // Compares objects a and b and produces a diff object. + rv = rv || {}; + prfx = prfx || ''; + keys(a).forEach((prop) => { + if (!hasOwn(b, prop)) { + // Property removed + rv[prfx + prop] = undefined; + } else { + var ap = a[prop], + bp = b[prop]; + if (typeof ap === 'object' && typeof bp === 'object' && ap && bp) { + const apTypeName = toStringTag(ap); + const bpTypeName = toStringTag(bp); - export function getObjectDiff(a, b, rv?, prfx?) { - // Compares objects a and b and produces a diff object. - rv = rv || {}; - prfx = prfx || ''; - keys(a).forEach(prop => { - if (!hasOwn(b, prop)) - rv[prfx+prop] = undefined; // Property removed - else { - var ap = a[prop], - bp = b[prop]; - if (typeof ap === 'object' && typeof bp === 'object' && ap && bp) - { - const apTypeName = toStringTag(ap); - const bpTypeName = toStringTag(bp); - - if (apTypeName === bpTypeName) { - if (intrinsicTypeNameSet[apTypeName] || isArray(ap)) { - // This is an intrinsic type. Don't go deep diffing it. - // Instead compare its value in best-effort: - // (Can compare real values of Date, ArrayBuffers and views) - if (getValueOf(ap, apTypeName) !== getValueOf(bp, bpTypeName)) { - rv[prfx + prop] = b[prop]; // Date / ArrayBuffer etc is of different value - } - } else { - // This is not an intrinsic object. Compare the it deeply: - getObjectDiff(ap, bp, rv, prfx + prop + "."); - } - } else { - rv[prfx + prop] = b[prop];// Property changed to other type - } - } else if (ap !== bp) - rv[prfx + prop] = b[prop];// Primitive value changed - } - }); - keys(b).forEach(prop => { - if (!hasOwn(a, prop)) { - rv[prfx+prop] = b[prop]; // Property added + if (apTypeName !== bpTypeName) { + rv[prfx + prop] = b[prop]; // Property changed to other type + } else if (apTypeName === 'Object') { + // Pojo objects (not Date, ArrayBuffer, Array etc). Go deep. + getObjectDiff(ap, bp, rv, prfx + prop + '.'); + } else if (ap !== bp) { + // Values differ. + // Could have checked if Date, arrays or binary types have same + // content here but I think that would be a suboptimation. + // Prefer simplicity. + rv[prfx + prop] = b[prop]; } - }); - return rv; + } else if (ap !== bp) rv[prfx + prop] = b[prop]; // Primitive value changed + } + }); + keys(b).forEach((prop) => { + if (!hasOwn(a, prop)) { + rv[prfx + prop] = b[prop]; // Property added + } + }); + return rv; } -