@shopware-ag/dive
Version:
Shopware Spatial Framework
106 lines (87 loc) • 3.35 kB
text/typescript
/**
* Find the difference between two objects.
*/
export const getObjectDelta = <T extends object>(
a: T,
b: Partial<T>,
): Partial<T> => {
// if a and b have no entries we have no delta
if (Object.keys(a).length === 0 && Object.keys(b).length === 0) {
return {};
}
// if a or b is not an object we have a delta
if (typeof a !== 'object' || typeof b !== 'object') {
return b;
}
let delta = {};
Object.keys(b).forEach((key) => {
// if key is not in a we have a delta
if (!Object.keys(a).includes(key)) {
delta = { ...delta, [key]: b[key as keyof object] };
return;
}
// assumption: b[key] is an array
if (Array.isArray(b[key as keyof object])) {
// if a[key] is not an array we have a delta
if (!Array.isArray(a[key as keyof object])) {
delta = { ...delta, [key]: b[key as keyof object] };
return;
}
// create arrays (for TS types to be correct)
const aArray = a[key as keyof object] as [];
const bArray = b[key as keyof object] as [];
// if both arrays are empty we have no delta
if (aArray.length === 0 && bArray.length === 0) {
delta = { ...delta };
return;
}
// if array length is different we have a delta
if (aArray.length !== bArray.length) {
delta = { ...delta, [key]: b[key as keyof object] };
return;
}
// create array for deltas
const arrayDeltas: [] = [];
bArray.forEach((entry, index) => {
// getObjectDelta in array
const inArrayDelta = getObjectDelta(
aArray[index],
bArray[index],
);
// if inArrayDelta has more then 0 entries we have a delta
if (Object.keys(inArrayDelta).length) {
arrayDeltas.push(bArray[index]);
}
});
// if arrayDeltas has more than 0 entries we have a delta
if (Object.keys(arrayDeltas).length) {
delta = { ...delta, [key]: arrayDeltas };
return;
}
return;
}
// assumption: b[key] is an object
if (typeof b[key as keyof object] === 'object') {
// if a[key] is not an object we have a delta
if (typeof a[key as keyof object] !== 'object') {
delta = { ...delta, [key]: b[key as keyof object] };
return;
}
// recursive: find objectDelta in a and b
const objectDelta = getObjectDelta(
a[key as keyof object],
b[key as keyof object],
);
// if objectDelta has more than 0 entries we have a delta
if (Object.keys(objectDelta).length) {
delta = { ...delta, [key]: objectDelta };
return;
}
}
// if a[key] is not equal to b[key] we have a delta
if (a[key as keyof object] !== b[key as keyof object]) {
delta = { ...delta, [key]: b[key as keyof object] };
}
});
return delta;
};