UNPKG

@difizen/mana-observable

Version:

87 lines (86 loc) 2.74 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ import { ObservableConfig } from "./config"; import { Notifiable } from "./notifiable"; import { Notifier } from "./notifier"; import { InstanceValue, ObservableProperties, Observability } from "./utils"; var propertyRelatedNotifier = Symbol('propertyRelatedNotifier'); // redefine observable properties export function defineProperty(target, property, defaultValue) { var notifier = Notifier.getOrCreate(target, property); /** * notify notifier when property changed */ var onChange = function onChange() { if (ObservableConfig.paused) { return; } Notifier.trigger(target, property); }; /** * set observable property value and register onChange listener * @param value * @param notifier */ var handleValue = function handleValue(value) { InstanceValue.set(target, property, value); if (notifier) { var last = Observability.getDisposable(propertyRelatedNotifier, notifier); if (last) { last.dispose(); } } if (Notifiable.is(value)) { var valueNotifier = Notifiable.getNotifier(value); if (notifier && valueNotifier) { var toDispose = valueNotifier.onChangeSync(onChange); Observability.setDisposable(propertyRelatedNotifier, toDispose, notifier); } } }; var initialValue = target[property] === undefined ? defaultValue : target[property]; handleValue(Notifiable.transform(initialValue)); // property getter var getter = function getter() { var value = Reflect.getMetadata(property, target); return value; }; // property setter var setter = function setter(value) { var notifiableValue = Notifiable.transform(value); var oldValue = InstanceValue.get(target, property); if (notifiableValue !== oldValue) { handleValue(notifiableValue); onChange(); } }; // define property if (Reflect.deleteProperty(target, property)) { Reflect.defineProperty(target, property, { configurable: true, enumerable: true, get: getter, set: setter }); } // mark observable property ObservableProperties.add(target, property); Observability.mark(target, property); } export function observable(target) { if (!Observability.canBeObservable(target)) { return target; } var origin = Observability.getOrigin(target); var properties = ObservableProperties.find(origin); if (!properties) { var notifiableValue = Notifiable.transform(origin); if (Notifiable.is(notifiableValue)) { Observability.mark(origin); } return notifiableValue; } properties.forEach(function (property) { return defineProperty(origin, property); }); return origin; }