rxdeep
Version:
RxJS deep state management
68 lines • 2.51 kB
JavaScript
import { Observable, Subject } from 'rxjs';
import { filter, map, tap, multicast, refCount } from 'rxjs/operators';
import { isLeaf } from './types/changes';
import { postTrace } from './util/post-trace';
export class State extends Observable {
constructor(initial, downstream = new Subject(), upstream) {
super((observer) => {
observer.next(this.value);
return this.downstream.pipe(map(change => change.value)).subscribe(observer);
});
this._value = initial;
this._changesub = new Subject();
this.downstream = downstream.pipe(postTrace(), tap(change => {
if (change.value !== this._value) {
this._value = change.value;
}
}), multicast(() => this._changesub), refCount());
this.upstream = upstream || downstream;
}
next(t) { this.upstream.next({ value: t, trace: { from: this.value, to: t } }); }
error(err) { this.upstream.error(err); }
complete() { this.upstream.complete(); this._changesub.complete(); }
get value() { return this._value; }
set value(t) { this.next(t); }
sub(key) {
const _sub = new State(this.value ? this.value[key] : undefined, this.subDownstream(key, () => _sub.value), this.subUpstream(key));
return _sub;
}
subDownstream(key, current) {
return this.downstream.pipe(map(change => ({
value: change.value ? change.value[key] : undefined,
trace: change.trace,
})), filter(change => {
if (isLeaf(change.trace)) {
return current() !== change.value;
}
else {
return key in change.trace.subs;
}
}), map(change => ({
value: change.value,
trace: isLeaf(change.trace) ? undefined : change.trace.subs[key]
})));
}
subUpstream(key) {
return {
next: change => {
if (this.value) {
this.value[key] = change.value;
}
this.upstream.next({
value: this.value,
trace: {
subs: {
[key]: change.trace
}
}
});
},
error: err => this.upstream.error(err),
complete: () => { },
};
}
}
export function state(initial) {
return new State(initial);
}
//# sourceMappingURL=state.js.map