@nbottarini/observable 0.4.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,11 +18,13 @@ $ yarn add @nbottarini/observable
18
18
 
19
19
  ## Usage
20
20
 
21
+ ### Observables
22
+
21
23
  **View1.ts:**
22
24
  ```typescript
23
25
  export class View1 {
24
- public readonly buttonClicked = new Observable<ClickEvent>()
25
- public readonly textChanged = new Observable<TextChangedEvent>()
26
+ public readonly buttonClicked = observable<ClickEvent>()
27
+ public readonly textChanged = observable<TextChangedEvent>()
26
28
 
27
29
  // Do something internally to handle UI events
28
30
 
@@ -48,11 +50,36 @@ export class View2 {
48
50
  }
49
51
  ```
50
52
 
51
- **Observable properties:**
53
+ ### Composite observables
54
+
55
+ ```typescript
56
+ const buttonClicked = observable<ClickEvent>()
57
+ const textChanged = observable<TextChangedEvent>()
58
+ const allEvents = compositeObservable(buttonClicked, textChanged)
59
+
60
+ allEvents.subscribe({}, (event) => {
61
+ // Notifies click and text changed events
62
+ })
63
+ ```
64
+
65
+ ### Observable properties:
52
66
 
53
67
  ```typescript
54
- const nameProperty = new ObservableProperty('John')
55
- nameProperty.changed.subscribe(this, this.onNameChanged)
68
+ const nameProperty$ = property('John')
69
+ nameProperty$.value // 'John'
70
+
71
+ nameProperty$.changed.subscribe(this, this.onNameChanged)
72
+ nameProperty$.value = 'new name' // Notifies changes to subscribers
73
+ ```
74
+
75
+ ### Computed properties:
76
+ ```typescript
77
+ const property1 = property(1)
78
+ const property2$ = property(2)
79
+ const computedProperty$ = computed((value1, value2) => value1 + value2, $property1, $property2)
80
+ computedProperty$.value // returns 3
81
+
82
+ computedProperty$.changed.subscribe(this, this.onComputedChanged)
83
+ property1$.value = 3 // Notifies new computed value 5 to computedProperty$ subscribers
56
84
 
57
- nameProperty.value = 'new name'
58
85
  ```
package/dist/cjs/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";class Observable{observers=new Set;handlers=new Map;subscribe(observer,handler){this.observers.add(observer),this.handlers.set(observer,handler.bind(observer))}unsubscribe(observer){this.observers.delete(observer),this.handlers.delete(observer)}unsubscribeAll(){this.observers.clear(),this.handlers.clear()}async notify(value){let promises=[];for(const handler of this.handlers.values())promises.push(handler(value));await Promise.all(promises)}}exports.Observable=Observable,exports.ObservableProperty=class{_value;changed=new Observable;constructor(initialValue){this._value=initialValue}get value(){return this._value}set value(newValue){this._value!==newValue&&(this._value=newValue,this.changed.notify(this._value))}};
1
+ "use strict";class DefaultObservable{observers=new Set;handlers=new Map;subscribe(observer,handler){this.observers.add(observer),this.handlers.set(observer,handler.bind(observer))}hasObserver(observer){return this.observers.has(observer)}unsubscribe(observer){this.observers.delete(observer),this.handlers.delete(observer)}unsubscribeAll(){this.observers.clear(),this.handlers.clear()}async notify(value){let promises=[];for(const handler of this.handlers.values())promises.push(handler(value));await Promise.all(promises)}}function observable(){return new DefaultObservable}class CompositeObservable{sources;observers=new Set;handlers=new Map;onSourceEventRef=this.onSourceEvent.bind(this);constructor(sources){this.sources=sources}hasObserver(observer){return this.observers.has(observer)}async notify(value){throw new Error("CompositeObservable cannot be notified directly")}subscribe(observer,handler){const isFirstObserver=0===this.observers.size;this.observers.add(observer),this.handlers.set(observer,handler.bind(observer)),isFirstObserver&&this.attachToSources()}unsubscribe(observer){const hadObservers=this.observers.size>0;this.observers.delete(observer),this.handlers.delete(observer),hadObservers&&0===this.observers.size&&this.detachFromSources()}unsubscribeAll(){const hadObservers=this.observers.size>0;this.observers.clear(),this.handlers.clear(),hadObservers&&this.detachFromSources()}attachToSources(){for(const source of this.sources)source.subscribe(this,this.onSourceEventRef)}detachFromSources(){for(const source of this.sources)source.unsubscribe(this)}async onSourceEvent(value){let promises=[];for(const handler of this.handlers.values())promises.push(handler(value));await Promise.all(promises)}}function compositeObservable(...sources){return new CompositeObservable(sources)}class MutableProperty{_value;changed=observable();constructor(initialValue){this._value=initialValue}subscribe(observer,handler){this.changed.subscribe(observer,handler)}hasObserver(observer){return this.changed.hasObserver(observer)}unsubscribe(observer){this.changed.unsubscribe(observer)}unsubscribeAll(){this.changed.unsubscribeAll()}async notify(value){return this.changed.notify(value)}get value(){return this._value}set value(newValue){this._value!==newValue&&(this._value=newValue,this.changed.notify(this._value))}}class ComputedProperty{computeFunc;internalChanged=observable();changed={subscribe:(o,h)=>this.subscribe(o,h),hasObserver:o=>this.hasObserver(o),unsubscribe:o=>this.unsubscribe(o),unsubscribeAll:()=>this.unsubscribeAll(),notify:v=>this.notify(v)};depsChanged;deps;onDepsChangedRef=this.onDepsChanged.bind(this);observerCount=0;hasValue=!1;cachedValue;constructor(computeFunc,...deps){this.computeFunc=computeFunc,this.deps=deps;const sources=deps.map((it=>it.changed));this.depsChanged=compositeObservable(...sources)}subscribe(observer,handler){const observerAlreadySubscribed=this.hasObserver(observer),isFirstObserver=0===this.observerCount;this.internalChanged.subscribe(observer,handler),observerAlreadySubscribed||this.observerCount++,isFirstObserver&&this.depsChanged.subscribe(this,this.onDepsChangedRef)}hasObserver(observer){return this.internalChanged.hasObserver(observer)}unsubscribe(observer){this.internalChanged.hasObserver(observer)&&(this.internalChanged.unsubscribe(observer),this.observerCount--,0===this.observerCount&&this.depsChanged.unsubscribe(this))}unsubscribeAll(){const hadObservers=this.observerCount>0;this.internalChanged.unsubscribeAll(),this.observerCount=0,hadObservers&&this.depsChanged.unsubscribe(this)}async notify(value){throw new Error("ComputedProperty cannot be notified directly")}get value(){return 0===this.observerCount?this.compute():(this.hasValue||(this.cachedValue=this.compute(),this.hasValue=!0),this.cachedValue)}compute(){const values=this.deps.map((d=>d.value));return this.computeFunc(...values)}onDepsChanged(){const newValue=this.compute();this.hasValue&&Object.is(this.cachedValue,newValue)||(this.cachedValue=newValue,this.hasValue=!0,this.internalChanged.notify(this.cachedValue))}}exports.CompositeObservable=CompositeObservable,exports.ComputedProperty=ComputedProperty,exports.DefaultObservable=DefaultObservable,exports.MutableProperty=MutableProperty,exports.compositeObservable=compositeObservable,exports.computed=function(computeFunc,...deps){return new ComputedProperty(computeFunc,...deps)},exports.observable=observable,exports.property=function(initialValue){return new MutableProperty(initialValue)};
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/Observable.ts","../../src/ObservableProperty.ts"],"sourcesContent":["export type ObserverFunc<T> = (subject: T) => any\n\nexport class Observable<T = void> {\n private observers: Set<object> = new Set()\n private handlers: Map<object, ObserverFunc<T>> = new Map()\n\n subscribe(observer: object, handler: ObserverFunc<T>) {\n this.observers.add(observer)\n this.handlers.set(observer, handler.bind(observer))\n }\n\n unsubscribe(observer: object) {\n this.observers.delete(observer)\n this.handlers.delete(observer)\n }\n\n unsubscribeAll() {\n this.observers.clear()\n this.handlers.clear()\n }\n\n async notify(value?: T) {\n let promises = []\n for (const handler of this.handlers.values()) {\n promises.push(handler(value))\n }\n await Promise.all(promises)\n }\n}\n","import { Observable } from './Observable'\n\nexport class ObservableProperty<T = any> {\n private _value: T\n readonly changed: Observable<T> = new Observable()\n\n constructor(initialValue: T) {\n this._value = initialValue\n }\n\n get value(): T {\n return this._value\n }\n\n set value(newValue: T) {\n if (this._value === newValue) return\n this._value = newValue\n this.changed.notify(this._value)\n }\n}\n"],"names":["Observable","observers","Set","handlers","Map","subscribe","observer","handler","this","add","set","bind","unsubscribe","delete","unsubscribeAll","clear","notify","value","promises","values","push","Promise","all","_value","changed","constructor","initialValue","newValue"],"mappings":"mBAEaA,WACDC,UAAyB,IAAIC,IAC7BC,SAAyC,IAAIC,IAErD,SAAAC,CAAUC,SAAkBC,SACxBC,KAAKP,UAAUQ,IAAIH,UACnBE,KAAKL,SAASO,IAAIJ,SAAUC,QAAQI,KAAKL,UAC5C,CAED,WAAAM,CAAYN,UACRE,KAAKP,UAAUY,OAAOP,UACtBE,KAAKL,SAASU,OAAOP,SACxB,CAED,cAAAQ,GACIN,KAAKP,UAAUc,QACfP,KAAKL,SAASY,OACjB,CAED,YAAMC,CAAOC,OACT,IAAIC,SAAW,GACf,IAAK,MAAMX,WAAWC,KAAKL,SAASgB,SAChCD,SAASE,KAAKb,QAAQU,cAEpBI,QAAQC,IAAIJ,SACrB,iECxBOK,OACCC,QAAyB,IAAIxB,WAEtC,WAAAyB,CAAYC,cACRlB,KAAKe,OAASG,YACjB,CAED,SAAIT,GACA,OAAOT,KAAKe,MACf,CAED,SAAIN,CAAMU,UACFnB,KAAKe,SAAWI,WACpBnB,KAAKe,OAASI,SACdnB,KAAKgB,QAAQR,OAAOR,KAAKe,QAC5B"}
1
+ {"version":3,"file":"index.js","sources":["../../src/DefaultObservable.ts","../../src/CompositeObservable.ts","../../src/MutableProperty.ts","../../src/ComputedProperty.ts"],"sourcesContent":["import { Observable, ObserverFunc } from './Observable'\n\nexport class DefaultObservable<T = void> implements Observable<T> {\n private observers: Set<object> = new Set()\n private handlers: Map<object, ObserverFunc<T>> = new Map()\n\n subscribe(observer: object, handler: ObserverFunc<T>) {\n this.observers.add(observer)\n this.handlers.set(observer, handler.bind(observer))\n }\n\n hasObserver(observer: object) {\n return this.observers.has(observer)\n }\n\n unsubscribe(observer: object) {\n this.observers.delete(observer)\n this.handlers.delete(observer)\n }\n\n unsubscribeAll() {\n this.observers.clear()\n this.handlers.clear()\n }\n\n async notify(value?: T) {\n let promises = []\n for (const handler of this.handlers.values()) {\n promises.push(handler(value))\n }\n await Promise.all(promises)\n }\n}\n\nexport function observable<T = void>(): Observable<T> {\n return new DefaultObservable<T>()\n}\n","import { Observable, ObserverFunc } from './Observable'\n\ntype EventOf<O> = O extends Observable<infer T> ? T : never\n\nexport class CompositeObservable<Sources extends readonly Observable<any>[]> implements Observable<EventOf<Sources[number]>> {\n private observers = new Set<object>()\n private handlers: Map<object, ObserverFunc<EventOf<Sources[number]>>> = new Map()\n private onSourceEventRef = this.onSourceEvent.bind(this)\n\n constructor(private readonly sources: Sources) {\n }\n\n hasObserver(observer: object): boolean {\n return this.observers.has(observer)\n }\n\n async notify(value?: EventOf<Sources[number]>) {\n throw new Error('CompositeObservable cannot be notified directly')\n }\n\n subscribe(observer: object, handler: ObserverFunc<EventOf<Sources[number]>>): void {\n const isFirstObserver = this.observers.size === 0\n this.observers.add(observer)\n this.handlers.set(observer, handler.bind(observer))\n\n if (isFirstObserver) this.attachToSources()\n }\n\n unsubscribe(observer: object): void {\n const hadObservers = this.observers.size > 0\n this.observers.delete(observer)\n this.handlers.delete(observer)\n\n if (hadObservers && this.observers.size === 0) this.detachFromSources()\n }\n\n unsubscribeAll(): void {\n const hadObservers = this.observers.size > 0\n this.observers.clear()\n this.handlers.clear()\n if (hadObservers ) this.detachFromSources()\n }\n\n private attachToSources() {\n for (const source of this.sources) {\n source.subscribe(this, this.onSourceEventRef)\n }\n }\n\n private detachFromSources() {\n for (const source of this.sources) {\n source.unsubscribe(this)\n }\n }\n\n private async onSourceEvent(value?: EventOf<Sources[number]>) {\n let promises = []\n for (const handler of this.handlers.values()) {\n promises.push(handler(value))\n }\n await Promise.all(promises)\n }\n}\n\nexport function compositeObservable<Sources extends readonly Observable<any>[]>(...sources: Sources) {\n return new CompositeObservable(sources)\n}\n","import { observable } from './DefaultObservable'\nimport { ObserverFunc } from './Observable'\nimport { ObservableProperty } from './ObservableProperty'\n\nexport class MutableProperty<T> implements ObservableProperty<T> {\n private _value: T\n readonly changed = observable<T>()\n\n constructor(initialValue: T) {\n this._value = initialValue\n }\n\n subscribe(observer: object, handler: ObserverFunc<T>) {\n this.changed.subscribe(observer, handler)\n }\n hasObserver(observer: object): boolean {\n return this.changed.hasObserver(observer)\n }\n unsubscribe(observer: object) {\n this.changed.unsubscribe(observer)\n }\n unsubscribeAll() {\n this.changed.unsubscribeAll()\n }\n\n async notify(value?: T): Promise<void> {\n return this.changed.notify(value)\n }\n\n get value(): T {\n return this._value\n }\n\n set value(newValue: T) {\n if (this._value === newValue) return\n this._value = newValue\n this.changed.notify(this._value)\n }\n}\n\nexport function property<T>(initialValue: T): MutableProperty<T> {\n return new MutableProperty<T>(initialValue)\n}\n","import { ObservableProperty } from './ObservableProperty'\nimport { Observable, ObserverFunc } from './Observable'\nimport { compositeObservable } from './CompositeObservable'\nimport { observable } from './DefaultObservable'\n\ntype ValueOf<P> = P extends ObservableProperty<infer T> ? T : never\n\nexport class ComputedProperty<Deps extends readonly ObservableProperty<any>[], T> implements ObservableProperty<T> {\n private readonly internalChanged = observable<T>()\n readonly changed: Observable<T> = {\n subscribe: (o, h) => this.subscribe(o, h),\n hasObserver: (o) => this.hasObserver(o),\n unsubscribe: (o) => this.unsubscribe(o),\n unsubscribeAll: () => this.unsubscribeAll(),\n notify: (v) => this.notify(v),\n }\n private readonly depsChanged: Observable<any>\n private readonly deps: Deps\n private readonly onDepsChangedRef = this.onDepsChanged.bind(this)\n private observerCount = 0\n private hasValue = false\n private cachedValue!: T\n\n constructor(private readonly computeFunc: (...values: { [K in keyof Deps]: ValueOf<Deps[K]> }) => T, ...deps: Deps) {\n this.deps = deps\n const sources = deps.map(it => it.changed)\n this.depsChanged = compositeObservable(...sources)\n }\n\n subscribe(observer: object, handler: ObserverFunc<any>) {\n const observerAlreadySubscribed = this.hasObserver(observer)\n const isFirstObserver = this.observerCount === 0\n this.internalChanged.subscribe(observer, handler)\n if (!observerAlreadySubscribed) {\n this.observerCount++\n }\n if (isFirstObserver) this.depsChanged.subscribe(this, this.onDepsChangedRef)\n }\n\n hasObserver(observer: object): boolean {\n return this.internalChanged.hasObserver(observer)\n }\n\n unsubscribe(observer: object) {\n if (!this.internalChanged.hasObserver(observer)) return\n\n this.internalChanged.unsubscribe(observer)\n this.observerCount--\n\n if (this.observerCount === 0) this.depsChanged.unsubscribe(this)\n }\n\n unsubscribeAll() {\n const hadObservers = this.observerCount > 0\n this.internalChanged.unsubscribeAll()\n this.observerCount = 0\n if (hadObservers) this.depsChanged.unsubscribe(this)\n }\n\n async notify(value?: any): Promise<void> {\n throw new Error('ComputedProperty cannot be notified directly')\n }\n\n get value(): T {\n // When there are no observers we must recompute on each call because we aren't watching dep changes\n if (this.observerCount === 0) return this.compute()\n\n if (!this.hasValue) {\n this.cachedValue = this.compute()\n this.hasValue = true\n }\n return this.cachedValue\n }\n\n private compute(): T {\n const values = this.deps.map(d => d.value) as { [K in keyof Deps]: ValueOf<Deps[K]> }\n return this.computeFunc(...values)\n }\n\n private onDepsChanged() {\n const newValue = this.compute()\n\n if (!this.hasValue || !Object.is(this.cachedValue, newValue)) {\n this.cachedValue = newValue\n this.hasValue = true\n this.internalChanged.notify(this.cachedValue)\n }\n }\n}\n\nexport function computed<\n Deps extends readonly ObservableProperty<any>[],\n T,\n>(computeFunc: (...values: { [K in keyof Deps]: ValueOf<Deps[K]> }) => T, ...deps: Deps) {\n return new ComputedProperty(computeFunc, ...deps)\n}\n"],"names":["DefaultObservable","observers","Set","handlers","Map","subscribe","observer","handler","this","add","set","bind","hasObserver","has","unsubscribe","delete","unsubscribeAll","clear","notify","value","promises","values","push","Promise","all","observable","CompositeObservable","sources","onSourceEventRef","onSourceEvent","constructor","Error","isFirstObserver","size","attachToSources","hadObservers","detachFromSources","source","compositeObservable","MutableProperty","_value","changed","initialValue","newValue","ComputedProperty","computeFunc","internalChanged","o","h","v","depsChanged","deps","onDepsChangedRef","onDepsChanged","observerCount","hasValue","cachedValue","map","it","observerAlreadySubscribed","compute","d","Object","is"],"mappings":"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"}
package/dist/esm/index.js CHANGED
@@ -1,2 +1,2 @@
1
- class Observable{observers=new Set;handlers=new Map;subscribe(observer,handler){this.observers.add(observer),this.handlers.set(observer,handler.bind(observer))}unsubscribe(observer){this.observers.delete(observer),this.handlers.delete(observer)}unsubscribeAll(){this.observers.clear(),this.handlers.clear()}async notify(value){let promises=[];for(const handler of this.handlers.values())promises.push(handler(value));await Promise.all(promises)}}class ObservableProperty{_value;changed=new Observable;constructor(initialValue){this._value=initialValue}get value(){return this._value}set value(newValue){this._value!==newValue&&(this._value=newValue,this.changed.notify(this._value))}}export{Observable,ObservableProperty};
1
+ class DefaultObservable{observers=new Set;handlers=new Map;subscribe(observer,handler){this.observers.add(observer),this.handlers.set(observer,handler.bind(observer))}hasObserver(observer){return this.observers.has(observer)}unsubscribe(observer){this.observers.delete(observer),this.handlers.delete(observer)}unsubscribeAll(){this.observers.clear(),this.handlers.clear()}async notify(value){let promises=[];for(const handler of this.handlers.values())promises.push(handler(value));await Promise.all(promises)}}function observable(){return new DefaultObservable}class CompositeObservable{sources;observers=new Set;handlers=new Map;onSourceEventRef=this.onSourceEvent.bind(this);constructor(sources){this.sources=sources}hasObserver(observer){return this.observers.has(observer)}async notify(value){throw new Error("CompositeObservable cannot be notified directly")}subscribe(observer,handler){const isFirstObserver=0===this.observers.size;this.observers.add(observer),this.handlers.set(observer,handler.bind(observer)),isFirstObserver&&this.attachToSources()}unsubscribe(observer){const hadObservers=this.observers.size>0;this.observers.delete(observer),this.handlers.delete(observer),hadObservers&&0===this.observers.size&&this.detachFromSources()}unsubscribeAll(){const hadObservers=this.observers.size>0;this.observers.clear(),this.handlers.clear(),hadObservers&&this.detachFromSources()}attachToSources(){for(const source of this.sources)source.subscribe(this,this.onSourceEventRef)}detachFromSources(){for(const source of this.sources)source.unsubscribe(this)}async onSourceEvent(value){let promises=[];for(const handler of this.handlers.values())promises.push(handler(value));await Promise.all(promises)}}function compositeObservable(...sources){return new CompositeObservable(sources)}class MutableProperty{_value;changed=observable();constructor(initialValue){this._value=initialValue}subscribe(observer,handler){this.changed.subscribe(observer,handler)}hasObserver(observer){return this.changed.hasObserver(observer)}unsubscribe(observer){this.changed.unsubscribe(observer)}unsubscribeAll(){this.changed.unsubscribeAll()}async notify(value){return this.changed.notify(value)}get value(){return this._value}set value(newValue){this._value!==newValue&&(this._value=newValue,this.changed.notify(this._value))}}function property(initialValue){return new MutableProperty(initialValue)}class ComputedProperty{computeFunc;internalChanged=observable();changed={subscribe:(o,h)=>this.subscribe(o,h),hasObserver:o=>this.hasObserver(o),unsubscribe:o=>this.unsubscribe(o),unsubscribeAll:()=>this.unsubscribeAll(),notify:v=>this.notify(v)};depsChanged;deps;onDepsChangedRef=this.onDepsChanged.bind(this);observerCount=0;hasValue=!1;cachedValue;constructor(computeFunc,...deps){this.computeFunc=computeFunc,this.deps=deps;const sources=deps.map((it=>it.changed));this.depsChanged=compositeObservable(...sources)}subscribe(observer,handler){const observerAlreadySubscribed=this.hasObserver(observer),isFirstObserver=0===this.observerCount;this.internalChanged.subscribe(observer,handler),observerAlreadySubscribed||this.observerCount++,isFirstObserver&&this.depsChanged.subscribe(this,this.onDepsChangedRef)}hasObserver(observer){return this.internalChanged.hasObserver(observer)}unsubscribe(observer){this.internalChanged.hasObserver(observer)&&(this.internalChanged.unsubscribe(observer),this.observerCount--,0===this.observerCount&&this.depsChanged.unsubscribe(this))}unsubscribeAll(){const hadObservers=this.observerCount>0;this.internalChanged.unsubscribeAll(),this.observerCount=0,hadObservers&&this.depsChanged.unsubscribe(this)}async notify(value){throw new Error("ComputedProperty cannot be notified directly")}get value(){return 0===this.observerCount?this.compute():(this.hasValue||(this.cachedValue=this.compute(),this.hasValue=!0),this.cachedValue)}compute(){const values=this.deps.map((d=>d.value));return this.computeFunc(...values)}onDepsChanged(){const newValue=this.compute();this.hasValue&&Object.is(this.cachedValue,newValue)||(this.cachedValue=newValue,this.hasValue=!0,this.internalChanged.notify(this.cachedValue))}}function computed(computeFunc,...deps){return new ComputedProperty(computeFunc,...deps)}export{CompositeObservable,ComputedProperty,DefaultObservable,MutableProperty,compositeObservable,computed,observable,property};
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/Observable.ts","../../src/ObservableProperty.ts"],"sourcesContent":["export type ObserverFunc<T> = (subject: T) => any\n\nexport class Observable<T = void> {\n private observers: Set<object> = new Set()\n private handlers: Map<object, ObserverFunc<T>> = new Map()\n\n subscribe(observer: object, handler: ObserverFunc<T>) {\n this.observers.add(observer)\n this.handlers.set(observer, handler.bind(observer))\n }\n\n unsubscribe(observer: object) {\n this.observers.delete(observer)\n this.handlers.delete(observer)\n }\n\n unsubscribeAll() {\n this.observers.clear()\n this.handlers.clear()\n }\n\n async notify(value?: T) {\n let promises = []\n for (const handler of this.handlers.values()) {\n promises.push(handler(value))\n }\n await Promise.all(promises)\n }\n}\n","import { Observable } from './Observable'\n\nexport class ObservableProperty<T = any> {\n private _value: T\n readonly changed: Observable<T> = new Observable()\n\n constructor(initialValue: T) {\n this._value = initialValue\n }\n\n get value(): T {\n return this._value\n }\n\n set value(newValue: T) {\n if (this._value === newValue) return\n this._value = newValue\n this.changed.notify(this._value)\n }\n}\n"],"names":["Observable","observers","Set","handlers","Map","subscribe","observer","handler","this","add","set","bind","unsubscribe","delete","unsubscribeAll","clear","notify","value","promises","values","push","Promise","all","ObservableProperty","_value","changed","constructor","initialValue","newValue"],"mappings":"MAEaA,WACDC,UAAyB,IAAIC,IAC7BC,SAAyC,IAAIC,IAErD,SAAAC,CAAUC,SAAkBC,SACxBC,KAAKP,UAAUQ,IAAIH,UACnBE,KAAKL,SAASO,IAAIJ,SAAUC,QAAQI,KAAKL,UAC5C,CAED,WAAAM,CAAYN,UACRE,KAAKP,UAAUY,OAAOP,UACtBE,KAAKL,SAASU,OAAOP,SACxB,CAED,cAAAQ,GACIN,KAAKP,UAAUc,QACfP,KAAKL,SAASY,OACjB,CAED,YAAMC,CAAOC,OACT,IAAIC,SAAW,GACf,IAAK,MAAMX,WAAWC,KAAKL,SAASgB,SAChCD,SAASE,KAAKb,QAAQU,cAEpBI,QAAQC,IAAIJ,SACrB,QCzBQK,mBACDC,OACCC,QAAyB,IAAIzB,WAEtC,WAAA0B,CAAYC,cACRnB,KAAKgB,OAASG,YACjB,CAED,SAAIV,GACA,OAAOT,KAAKgB,MACf,CAED,SAAIP,CAAMW,UACFpB,KAAKgB,SAAWI,WACpBpB,KAAKgB,OAASI,SACdpB,KAAKiB,QAAQT,OAAOR,KAAKgB,QAC5B"}
1
+ {"version":3,"file":"index.js","sources":["../../src/DefaultObservable.ts","../../src/CompositeObservable.ts","../../src/MutableProperty.ts","../../src/ComputedProperty.ts"],"sourcesContent":["import { Observable, ObserverFunc } from './Observable'\n\nexport class DefaultObservable<T = void> implements Observable<T> {\n private observers: Set<object> = new Set()\n private handlers: Map<object, ObserverFunc<T>> = new Map()\n\n subscribe(observer: object, handler: ObserverFunc<T>) {\n this.observers.add(observer)\n this.handlers.set(observer, handler.bind(observer))\n }\n\n hasObserver(observer: object) {\n return this.observers.has(observer)\n }\n\n unsubscribe(observer: object) {\n this.observers.delete(observer)\n this.handlers.delete(observer)\n }\n\n unsubscribeAll() {\n this.observers.clear()\n this.handlers.clear()\n }\n\n async notify(value?: T) {\n let promises = []\n for (const handler of this.handlers.values()) {\n promises.push(handler(value))\n }\n await Promise.all(promises)\n }\n}\n\nexport function observable<T = void>(): Observable<T> {\n return new DefaultObservable<T>()\n}\n","import { Observable, ObserverFunc } from './Observable'\n\ntype EventOf<O> = O extends Observable<infer T> ? T : never\n\nexport class CompositeObservable<Sources extends readonly Observable<any>[]> implements Observable<EventOf<Sources[number]>> {\n private observers = new Set<object>()\n private handlers: Map<object, ObserverFunc<EventOf<Sources[number]>>> = new Map()\n private onSourceEventRef = this.onSourceEvent.bind(this)\n\n constructor(private readonly sources: Sources) {\n }\n\n hasObserver(observer: object): boolean {\n return this.observers.has(observer)\n }\n\n async notify(value?: EventOf<Sources[number]>) {\n throw new Error('CompositeObservable cannot be notified directly')\n }\n\n subscribe(observer: object, handler: ObserverFunc<EventOf<Sources[number]>>): void {\n const isFirstObserver = this.observers.size === 0\n this.observers.add(observer)\n this.handlers.set(observer, handler.bind(observer))\n\n if (isFirstObserver) this.attachToSources()\n }\n\n unsubscribe(observer: object): void {\n const hadObservers = this.observers.size > 0\n this.observers.delete(observer)\n this.handlers.delete(observer)\n\n if (hadObservers && this.observers.size === 0) this.detachFromSources()\n }\n\n unsubscribeAll(): void {\n const hadObservers = this.observers.size > 0\n this.observers.clear()\n this.handlers.clear()\n if (hadObservers ) this.detachFromSources()\n }\n\n private attachToSources() {\n for (const source of this.sources) {\n source.subscribe(this, this.onSourceEventRef)\n }\n }\n\n private detachFromSources() {\n for (const source of this.sources) {\n source.unsubscribe(this)\n }\n }\n\n private async onSourceEvent(value?: EventOf<Sources[number]>) {\n let promises = []\n for (const handler of this.handlers.values()) {\n promises.push(handler(value))\n }\n await Promise.all(promises)\n }\n}\n\nexport function compositeObservable<Sources extends readonly Observable<any>[]>(...sources: Sources) {\n return new CompositeObservable(sources)\n}\n","import { observable } from './DefaultObservable'\nimport { ObserverFunc } from './Observable'\nimport { ObservableProperty } from './ObservableProperty'\n\nexport class MutableProperty<T> implements ObservableProperty<T> {\n private _value: T\n readonly changed = observable<T>()\n\n constructor(initialValue: T) {\n this._value = initialValue\n }\n\n subscribe(observer: object, handler: ObserverFunc<T>) {\n this.changed.subscribe(observer, handler)\n }\n hasObserver(observer: object): boolean {\n return this.changed.hasObserver(observer)\n }\n unsubscribe(observer: object) {\n this.changed.unsubscribe(observer)\n }\n unsubscribeAll() {\n this.changed.unsubscribeAll()\n }\n\n async notify(value?: T): Promise<void> {\n return this.changed.notify(value)\n }\n\n get value(): T {\n return this._value\n }\n\n set value(newValue: T) {\n if (this._value === newValue) return\n this._value = newValue\n this.changed.notify(this._value)\n }\n}\n\nexport function property<T>(initialValue: T): MutableProperty<T> {\n return new MutableProperty<T>(initialValue)\n}\n","import { ObservableProperty } from './ObservableProperty'\nimport { Observable, ObserverFunc } from './Observable'\nimport { compositeObservable } from './CompositeObservable'\nimport { observable } from './DefaultObservable'\n\ntype ValueOf<P> = P extends ObservableProperty<infer T> ? T : never\n\nexport class ComputedProperty<Deps extends readonly ObservableProperty<any>[], T> implements ObservableProperty<T> {\n private readonly internalChanged = observable<T>()\n readonly changed: Observable<T> = {\n subscribe: (o, h) => this.subscribe(o, h),\n hasObserver: (o) => this.hasObserver(o),\n unsubscribe: (o) => this.unsubscribe(o),\n unsubscribeAll: () => this.unsubscribeAll(),\n notify: (v) => this.notify(v),\n }\n private readonly depsChanged: Observable<any>\n private readonly deps: Deps\n private readonly onDepsChangedRef = this.onDepsChanged.bind(this)\n private observerCount = 0\n private hasValue = false\n private cachedValue!: T\n\n constructor(private readonly computeFunc: (...values: { [K in keyof Deps]: ValueOf<Deps[K]> }) => T, ...deps: Deps) {\n this.deps = deps\n const sources = deps.map(it => it.changed)\n this.depsChanged = compositeObservable(...sources)\n }\n\n subscribe(observer: object, handler: ObserverFunc<any>) {\n const observerAlreadySubscribed = this.hasObserver(observer)\n const isFirstObserver = this.observerCount === 0\n this.internalChanged.subscribe(observer, handler)\n if (!observerAlreadySubscribed) {\n this.observerCount++\n }\n if (isFirstObserver) this.depsChanged.subscribe(this, this.onDepsChangedRef)\n }\n\n hasObserver(observer: object): boolean {\n return this.internalChanged.hasObserver(observer)\n }\n\n unsubscribe(observer: object) {\n if (!this.internalChanged.hasObserver(observer)) return\n\n this.internalChanged.unsubscribe(observer)\n this.observerCount--\n\n if (this.observerCount === 0) this.depsChanged.unsubscribe(this)\n }\n\n unsubscribeAll() {\n const hadObservers = this.observerCount > 0\n this.internalChanged.unsubscribeAll()\n this.observerCount = 0\n if (hadObservers) this.depsChanged.unsubscribe(this)\n }\n\n async notify(value?: any): Promise<void> {\n throw new Error('ComputedProperty cannot be notified directly')\n }\n\n get value(): T {\n // When there are no observers we must recompute on each call because we aren't watching dep changes\n if (this.observerCount === 0) return this.compute()\n\n if (!this.hasValue) {\n this.cachedValue = this.compute()\n this.hasValue = true\n }\n return this.cachedValue\n }\n\n private compute(): T {\n const values = this.deps.map(d => d.value) as { [K in keyof Deps]: ValueOf<Deps[K]> }\n return this.computeFunc(...values)\n }\n\n private onDepsChanged() {\n const newValue = this.compute()\n\n if (!this.hasValue || !Object.is(this.cachedValue, newValue)) {\n this.cachedValue = newValue\n this.hasValue = true\n this.internalChanged.notify(this.cachedValue)\n }\n }\n}\n\nexport function computed<\n Deps extends readonly ObservableProperty<any>[],\n T,\n>(computeFunc: (...values: { [K in keyof Deps]: ValueOf<Deps[K]> }) => T, ...deps: Deps) {\n return new ComputedProperty(computeFunc, ...deps)\n}\n"],"names":["DefaultObservable","observers","Set","handlers","Map","subscribe","observer","handler","this","add","set","bind","hasObserver","has","unsubscribe","delete","unsubscribeAll","clear","notify","value","promises","values","push","Promise","all","observable","CompositeObservable","sources","onSourceEventRef","onSourceEvent","constructor","Error","isFirstObserver","size","attachToSources","hadObservers","detachFromSources","source","compositeObservable","MutableProperty","_value","changed","initialValue","newValue","property","ComputedProperty","computeFunc","internalChanged","o","h","v","depsChanged","deps","onDepsChangedRef","onDepsChanged","observerCount","hasValue","cachedValue","map","it","observerAlreadySubscribed","compute","d","Object","is","computed"],"mappings":"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"}
@@ -1,19 +1,85 @@
1
1
  type ObserverFunc<T> = (subject: T) => any;
2
- declare class Observable<T = void> {
2
+ interface Observable<T> {
3
+ subscribe(observer: object, handler: ObserverFunc<T>): void;
4
+ hasObserver(observer: object): boolean;
5
+ unsubscribe(observer: object): void;
6
+ unsubscribeAll(): void;
7
+ notify(value?: T): Promise<void>;
8
+ }
9
+
10
+ interface ObservableProperty<T = any> extends Observable<T> {
11
+ readonly changed: Observable<T>;
12
+ readonly value: T;
13
+ }
14
+
15
+ declare class DefaultObservable<T = void> implements Observable<T> {
3
16
  private observers;
4
17
  private handlers;
5
18
  subscribe(observer: object, handler: ObserverFunc<T>): void;
19
+ hasObserver(observer: object): boolean;
6
20
  unsubscribe(observer: object): void;
7
21
  unsubscribeAll(): void;
8
22
  notify(value?: T): Promise<void>;
9
23
  }
24
+ declare function observable<T = void>(): Observable<T>;
10
25
 
11
- declare class ObservableProperty<T = any> {
26
+ type EventOf<O> = O extends Observable<infer T> ? T : never;
27
+ declare class CompositeObservable<Sources extends readonly Observable<any>[]> implements Observable<EventOf<Sources[number]>> {
28
+ private readonly sources;
29
+ private observers;
30
+ private handlers;
31
+ private onSourceEventRef;
32
+ constructor(sources: Sources);
33
+ hasObserver(observer: object): boolean;
34
+ notify(value?: EventOf<Sources[number]>): Promise<void>;
35
+ subscribe(observer: object, handler: ObserverFunc<EventOf<Sources[number]>>): void;
36
+ unsubscribe(observer: object): void;
37
+ unsubscribeAll(): void;
38
+ private attachToSources;
39
+ private detachFromSources;
40
+ private onSourceEvent;
41
+ }
42
+ declare function compositeObservable<Sources extends readonly Observable<any>[]>(...sources: Sources): CompositeObservable<Sources>;
43
+
44
+ declare class MutableProperty<T> implements ObservableProperty<T> {
12
45
  private _value;
13
46
  readonly changed: Observable<T>;
14
47
  constructor(initialValue: T);
48
+ subscribe(observer: object, handler: ObserverFunc<T>): void;
49
+ hasObserver(observer: object): boolean;
50
+ unsubscribe(observer: object): void;
51
+ unsubscribeAll(): void;
52
+ notify(value?: T): Promise<void>;
15
53
  get value(): T;
16
54
  set value(newValue: T);
17
55
  }
56
+ declare function property<T>(initialValue: T): MutableProperty<T>;
57
+
58
+ type ValueOf<P> = P extends ObservableProperty<infer T> ? T : never;
59
+ declare class ComputedProperty<Deps extends readonly ObservableProperty<any>[], T> implements ObservableProperty<T> {
60
+ private readonly computeFunc;
61
+ private readonly internalChanged;
62
+ readonly changed: Observable<T>;
63
+ private readonly depsChanged;
64
+ private readonly deps;
65
+ private readonly onDepsChangedRef;
66
+ private observerCount;
67
+ private hasValue;
68
+ private cachedValue;
69
+ constructor(computeFunc: (...values: {
70
+ [K in keyof Deps]: ValueOf<Deps[K]>;
71
+ }) => T, ...deps: Deps);
72
+ subscribe(observer: object, handler: ObserverFunc<any>): void;
73
+ hasObserver(observer: object): boolean;
74
+ unsubscribe(observer: object): void;
75
+ unsubscribeAll(): void;
76
+ notify(value?: any): Promise<void>;
77
+ get value(): T;
78
+ private compute;
79
+ private onDepsChanged;
80
+ }
81
+ declare function computed<Deps extends readonly ObservableProperty<any>[], T>(computeFunc: (...values: {
82
+ [K in keyof Deps]: ValueOf<Deps[K]>;
83
+ }) => T, ...deps: Deps): ComputedProperty<[...Deps], T>;
18
84
 
19
- export { Observable, ObservableProperty };
85
+ export { CompositeObservable, ComputedProperty, DefaultObservable, MutableProperty, Observable, ObservableProperty, ObserverFunc, compositeObservable, computed, observable, property };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nbottarini/observable",
3
- "version": "0.4.1",
3
+ "version": "0.7.0",
4
4
  "description": "Tiny Observable pattern implementation for creating observable properties",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",