mirror of
https://github.com/LukeHagar/arbiter.git
synced 2025-12-09 04:19:20 +00:00
57 lines
2.0 KiB
JavaScript
57 lines
2.0 KiB
JavaScript
const richTypes = { Date: true, RegExp: true, String: true, Number: true };
|
|
export default function diff(obj, newObj, options = { cyclesFix: true }, _stack = []) {
|
|
let diffs = [];
|
|
const isObjArray = Array.isArray(obj);
|
|
for (const key in obj) {
|
|
const objKey = obj[key];
|
|
const path = isObjArray ? +key : key;
|
|
if (!(key in newObj)) {
|
|
diffs.push({
|
|
type: "REMOVE",
|
|
path: [path],
|
|
oldValue: obj[key],
|
|
});
|
|
continue;
|
|
}
|
|
const newObjKey = newObj[key];
|
|
const areCompatibleObjects = typeof objKey === "object" &&
|
|
typeof newObjKey === "object" &&
|
|
Array.isArray(objKey) === Array.isArray(newObjKey);
|
|
if (objKey &&
|
|
newObjKey &&
|
|
areCompatibleObjects &&
|
|
!richTypes[Object.getPrototypeOf(objKey)?.constructor?.name] &&
|
|
(!options.cyclesFix || !_stack.includes(objKey))) {
|
|
diffs.push.apply(diffs, diff(objKey, newObjKey, options, options.cyclesFix ? _stack.concat([objKey]) : []).map((difference) => {
|
|
difference.path.unshift(path);
|
|
return difference;
|
|
}));
|
|
}
|
|
else if (objKey !== newObjKey &&
|
|
// treat NaN values as equivalent
|
|
!(Number.isNaN(objKey) && Number.isNaN(newObjKey)) &&
|
|
!(areCompatibleObjects &&
|
|
(isNaN(objKey)
|
|
? objKey + "" === newObjKey + ""
|
|
: +objKey === +newObjKey))) {
|
|
diffs.push({
|
|
path: [path],
|
|
type: "CHANGE",
|
|
value: newObjKey,
|
|
oldValue: objKey,
|
|
});
|
|
}
|
|
}
|
|
const isNewObjArray = Array.isArray(newObj);
|
|
for (const key in newObj) {
|
|
if (!(key in obj)) {
|
|
diffs.push({
|
|
type: "CREATE",
|
|
path: [isNewObjArray ? +key : key],
|
|
value: newObj[key],
|
|
});
|
|
}
|
|
}
|
|
return diffs;
|
|
}
|