orbit-studio / src /modules /util /equality.ts
moncefem's picture
Deploy Orbit Studio propagator
9f21d0a
Raw
History Blame Contribute Delete
1.5 kB
// One answer to "did this actually change?".
//
// Several places need it for the same reason: a write is not free. Assigning an
// equal value to a store ref still fires the url sync and lands a history
// entry, and handing the manager an equal scene still tears components down and
// rebuilds them. Decoded values arrive as fresh arrays and objects every time,
// so identity alone never says no.
interface Comparable {
[key: string]: unknown;
}
/**
* Structural comparison, short-circuiting on identity. Deliberately not
* JSON-based: `enabledSatellites` can hold thousands of names with Starlink
* enabled, and serialising that on every toggle to avoid a write is the wrong
* trade. This walks and stops at the first difference, allocating nothing for
* the common case of two lists of strings.
*/
export function sameValue(a: unknown, b: unknown): boolean {
if (a === b) {
return true;
}
// Checked before the object branch: an array and a plain object are both
// typeof "object", and an empty one of each has zero keys.
if (Array.isArray(a) || Array.isArray(b)) {
return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((entry, index) => sameValue(entry, b[index]));
}
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
return false;
}
const keys = Object.keys(a);
return keys.length === Object.keys(b).length && keys.every((key) => sameValue((a as Comparable)[key], (b as Comparable)[key]));
}