import { Observable } from '../Observable'; import { MediatorObservable } from '../mediator/MediatorObservable'; import { OnNext } from '../types'; import {Reflect} from '../../utils/reflect'; export class ColdMediatorObservable extends MediatorObservable { constructor(obj: T, private readonly handler = new PropertyAccessTrackingProxy()) { super(new Proxy(obj, handler)); } override set value(_: T) { throw new Error('Cannot set value of ColdMediatorObservable, use setValue(value, key) instead'); } override get value(): T { return super.value; } setValue(key: keyof T, value: any) { if (this.shouldUpdateTrackedProperty(key, value)) { this.handler.suspendTracking(); super.value = { ...this.value, [key]: value }; this.handler.resumeTracking(); } } private shouldUpdateTrackedProperty(key: keyof T, value: any) { return this.handler.hasAccessedProperty(key) && !Object.is(this.value[key], value); } override addSource(source: Observable, onNext: OnNext) { source.subscribe(onNext); return this; } } class PropertyAccessTrackingProxy implements ProxyHandler { private readonly accessedProperties = new Set(); private trackingSuspended = false; get(target: T, p: string | symbol, receiver: any) { if (!this.trackingSuspended) { this.accessedProperties.add(p as keyof T); } return Reflect.get(target, p, receiver); } hasAccessedProperty(key: keyof T) { return this.accessedProperties.has(key); } public suspendTracking() { this.trackingSuspended = true; } public resumeTracking() { this.trackingSuspended = false; } }