function observeLeafProperties()

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