in packages/sdk/src/internal/util/observe.ts [6:51]
function observeLeafProperties(
target: any, path: string[], notifyChanged: (...path: string[]) => void, triggerNotificationsNow: boolean) {
const names = Object.getOwnPropertyNames(target)
.filter(n => !target.$DoNotObserve || !target.$DoNotObserve.includes(n));
for (const name of names) {
// Fields starting with a dollar sign are not observed.
if (name.startsWith('$')) {
continue;
}
// TODO: Figure out array patching.
if (Array.isArray(target[name])) {
continue;
}
// Get the public name of this field by removing leading underscores.
const publicName = name.replace(/^_+/u, '');
// If the property is a simple type, then hook it.
const type = typeof target[name];
if (type === 'number' || type === 'string' || type === 'boolean') {
// Create a non-enumerable backing property to hold the field value.
const __name = `__observed_${name}`;
Object.defineProperty(target, __name, {
configurable: true,
enumerable: false,
value: target[name],
writable: true
});
// Override the getter and setter to call notifyChanged when the value changes.
Object.defineProperty(target, name, {
configurable: true,
enumerable: true,
get: () => target[__name],
set: (value) => {
if (target[__name] !== value) {
target[__name] = value;
notifyChanged(...path, publicName);
}
},
});
if (triggerNotificationsNow) {
notifyChanged(...path, publicName);
}
} else if (type === 'object') {
observeLeafProperties(target[name], [...path, publicName], notifyChanged, triggerNotificationsNow);
}
}
}