Files
arbiter/node_modules/microdiff/dist/index.js
2025-03-19 22:47:50 -05:00

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;
}