synstate 3.3.0 → 4.0.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 +14 -9
- package/dist/core/authoring.d.mts +7 -0
- package/dist/core/authoring.d.mts.map +1 -0
- package/dist/core/authoring.mjs +7 -0
- package/dist/core/authoring.mjs.map +1 -0
- package/dist/core/class/child-observable-class.d.mts +93 -0
- package/dist/core/class/child-observable-class.d.mts.map +1 -0
- package/dist/core/class/child-observable-class.mjs +248 -0
- package/dist/core/class/child-observable-class.mjs.map +1 -0
- package/dist/core/class/create-child-observable.d.mts +159 -0
- package/dist/core/class/create-child-observable.d.mts.map +1 -0
- package/dist/core/class/create-child-observable.mjs +183 -0
- package/dist/core/class/create-child-observable.mjs.map +1 -0
- package/dist/core/class/create-root-observable.d.mts +37 -0
- package/dist/core/class/create-root-observable.d.mts.map +1 -0
- package/dist/core/class/create-root-observable.mjs +52 -0
- package/dist/core/class/create-root-observable.mjs.map +1 -0
- package/dist/core/class/index.d.mts +9 -0
- package/dist/core/class/index.d.mts.map +1 -0
- package/dist/core/class/index.mjs +9 -0
- package/dist/core/class/index.mjs.map +1 -0
- package/dist/core/class/manager-observable-class.d.mts +26 -0
- package/dist/core/class/manager-observable-class.d.mts.map +1 -0
- package/dist/core/class/manager-observable-class.mjs +116 -0
- package/dist/core/class/manager-observable-class.mjs.map +1 -0
- package/dist/core/class/observable-base-class.d.mts +97 -0
- package/dist/core/class/observable-base-class.d.mts.map +1 -0
- package/dist/core/class/observable-base-class.mjs +219 -0
- package/dist/core/class/observable-base-class.mjs.map +1 -0
- package/dist/core/class/observable-node.d.mts +40 -0
- package/dist/core/class/observable-node.d.mts.map +1 -0
- package/dist/core/class/observable-node.mjs +10 -0
- package/dist/core/class/observable-node.mjs.map +1 -0
- package/dist/core/class/propagation-state.d.mts +24 -0
- package/dist/core/class/propagation-state.d.mts.map +1 -0
- package/dist/core/class/propagation-state.mjs +66 -0
- package/dist/core/class/propagation-state.mjs.map +1 -0
- package/dist/core/class/root-observable-class.d.mts +23 -0
- package/dist/core/class/root-observable-class.d.mts.map +1 -0
- package/dist/core/class/root-observable-class.mjs +58 -0
- package/dist/core/class/root-observable-class.mjs.map +1 -0
- package/dist/core/combine/combine.d.mts.map +1 -1
- package/dist/core/combine/combine.mjs +25 -14
- package/dist/core/combine/combine.mjs.map +1 -1
- package/dist/core/combine/merge.d.mts +0 -3
- package/dist/core/combine/merge.d.mts.map +1 -1
- package/dist/core/combine/merge.mjs +24 -15
- package/dist/core/combine/merge.mjs.map +1 -1
- package/dist/core/combine/zip.d.mts +4 -2
- package/dist/core/combine/zip.d.mts.map +1 -1
- package/dist/core/combine/zip.mjs +54 -18
- package/dist/core/combine/zip.mjs.map +1 -1
- package/dist/core/create/counter.d.mts +9 -3
- package/dist/core/create/counter.d.mts.map +1 -1
- package/dist/core/create/counter.mjs +69 -35
- package/dist/core/create/counter.mjs.map +1 -1
- package/dist/core/create/from-abortable-promise.d.mts.map +1 -1
- package/dist/core/create/from-abortable-promise.mjs +26 -18
- package/dist/core/create/from-abortable-promise.mjs.map +1 -1
- package/dist/core/create/from-promise.d.mts.map +1 -1
- package/dist/core/create/from-promise.mjs +30 -21
- package/dist/core/create/from-promise.mjs.map +1 -1
- package/dist/core/create/from-subscribable.d.mts.map +1 -1
- package/dist/core/create/from-subscribable.mjs +48 -12
- package/dist/core/create/from-subscribable.mjs.map +1 -1
- package/dist/core/create/just.d.mts.map +1 -1
- package/dist/core/create/just.mjs +4 -2
- package/dist/core/create/just.mjs.map +1 -1
- package/dist/core/create/source.d.mts +7 -0
- package/dist/core/create/source.d.mts.map +1 -1
- package/dist/core/create/source.mjs +27 -13
- package/dist/core/create/source.mjs.map +1 -1
- package/dist/core/create/timer.d.mts.map +1 -1
- package/dist/core/create/timer.mjs +40 -25
- package/dist/core/create/timer.mjs.map +1 -1
- package/dist/core/index.d.mts +2 -0
- package/dist/core/index.d.mts.map +1 -1
- package/dist/core/index.mjs +2 -0
- package/dist/core/index.mjs.map +1 -1
- package/dist/core/operators/audit.d.mts +3 -0
- package/dist/core/operators/audit.d.mts.map +1 -1
- package/dist/core/operators/audit.mjs +56 -28
- package/dist/core/operators/audit.mjs.map +1 -1
- package/dist/core/operators/debounce.d.mts +3 -0
- package/dist/core/operators/debounce.d.mts.map +1 -1
- package/dist/core/operators/debounce.mjs +57 -26
- package/dist/core/operators/debounce.mjs.map +1 -1
- package/dist/core/operators/filter.d.mts.map +1 -1
- package/dist/core/operators/filter.mjs +35 -21
- package/dist/core/operators/filter.mjs.map +1 -1
- package/dist/core/operators/index.d.mts +1 -0
- package/dist/core/operators/index.d.mts.map +1 -1
- package/dist/core/operators/index.mjs +1 -0
- package/dist/core/operators/index.mjs.map +1 -1
- package/dist/core/operators/map.d.mts.map +1 -1
- package/dist/core/operators/map.mjs +31 -17
- package/dist/core/operators/map.mjs.map +1 -1
- package/dist/core/operators/merge-map.d.mts +5 -3
- package/dist/core/operators/merge-map.d.mts.map +1 -1
- package/dist/core/operators/merge-map.mjs +49 -26
- package/dist/core/operators/merge-map.mjs.map +1 -1
- package/dist/core/operators/pairwise.d.mts.map +1 -1
- package/dist/core/operators/pairwise.mjs +31 -20
- package/dist/core/operators/pairwise.mjs.map +1 -1
- package/dist/core/operators/scan.d.mts.map +1 -1
- package/dist/core/operators/scan.mjs +27 -14
- package/dist/core/operators/scan.mjs.map +1 -1
- package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
- package/dist/core/operators/skip-if-no-change.mjs +33 -19
- package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
- package/dist/core/operators/skip-until.d.mts.map +1 -1
- package/dist/core/operators/skip-until.mjs +43 -20
- package/dist/core/operators/skip-until.mjs.map +1 -1
- package/dist/core/operators/skip-while.d.mts.map +1 -1
- package/dist/core/operators/skip-while.mjs +35 -20
- package/dist/core/operators/skip-while.mjs.map +1 -1
- package/dist/core/operators/switch-map.d.mts +5 -3
- package/dist/core/operators/switch-map.d.mts.map +1 -1
- package/dist/core/operators/switch-map.mjs +53 -25
- package/dist/core/operators/switch-map.mjs.map +1 -1
- package/dist/core/operators/take-until.d.mts.map +1 -1
- package/dist/core/operators/take-until.mjs +38 -19
- package/dist/core/operators/take-until.mjs.map +1 -1
- package/dist/core/operators/take-while.d.mts.map +1 -1
- package/dist/core/operators/take-while.mjs +36 -22
- package/dist/core/operators/take-while.mjs.map +1 -1
- package/dist/core/{predefined/operators → operators}/take.d.mts +7 -3
- package/dist/core/operators/take.d.mts.map +1 -0
- package/dist/core/operators/take.mjs +102 -0
- package/dist/core/operators/take.mjs.map +1 -0
- package/dist/core/operators/throttle.d.mts.map +1 -1
- package/dist/core/operators/throttle.mjs +41 -26
- package/dist/core/operators/throttle.mjs.map +1 -1
- package/dist/core/operators/with-buffered-from.d.mts.map +1 -1
- package/dist/core/operators/with-buffered-from.mjs +44 -31
- package/dist/core/operators/with-buffered-from.mjs.map +1 -1
- package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
- package/dist/core/operators/with-current-value-from.mjs +36 -21
- package/dist/core/operators/with-current-value-from.mjs.map +1 -1
- package/dist/core/operators/with-initial-value.d.mts.map +1 -1
- package/dist/core/operators/with-initial-value.mjs +24 -12
- package/dist/core/operators/with-initial-value.mjs.map +1 -1
- package/dist/core/predefined/operators/index.d.mts +0 -1
- package/dist/core/predefined/operators/index.d.mts.map +1 -1
- package/dist/core/predefined/operators/index.mjs +0 -1
- package/dist/core/predefined/operators/index.mjs.map +1 -1
- package/dist/core/scope/index.d.mts +2 -0
- package/dist/core/scope/index.d.mts.map +1 -0
- package/dist/core/scope/index.mjs +2 -0
- package/dist/core/scope/index.mjs.map +1 -0
- package/dist/core/scope/scope.d.mts +51 -0
- package/dist/core/scope/scope.d.mts.map +1 -0
- package/dist/core/scope/scope.mjs +194 -0
- package/dist/core/scope/scope.mjs.map +1 -0
- package/dist/core/types/id.d.mts +0 -2
- package/dist/core/types/id.d.mts.map +1 -1
- package/dist/core/types/index.d.mts +1 -0
- package/dist/core/types/index.d.mts.map +1 -1
- package/dist/core/types/index.mjs +1 -0
- package/dist/core/types/index.mjs.map +1 -1
- package/dist/core/types/observable-family.d.mts +6 -1
- package/dist/core/types/observable-family.d.mts.map +1 -1
- package/dist/core/types/observable-family.mjs.map +1 -1
- package/dist/core/types/observable.d.mts +40 -28
- package/dist/core/types/observable.d.mts.map +1 -1
- package/dist/core/types/observable.mjs +24 -0
- package/dist/core/types/observable.mjs.map +1 -1
- package/dist/core/types/scope.d.mts +27 -0
- package/dist/core/types/scope.d.mts.map +1 -0
- package/dist/core/types/scope.mjs +2 -0
- package/dist/core/types/scope.mjs.map +1 -0
- package/dist/core/utils/current-scope.d.mts +30 -0
- package/dist/core/utils/current-scope.d.mts.map +1 -0
- package/dist/core/utils/current-scope.mjs +26 -0
- package/dist/core/utils/current-scope.mjs.map +1 -0
- package/dist/core/utils/id-maker.d.mts +14 -3
- package/dist/core/utils/id-maker.d.mts.map +1 -1
- package/dist/core/utils/id-maker.mjs +18 -14
- package/dist/core/utils/id-maker.mjs.map +1 -1
- package/dist/core/utils/index.d.mts +2 -1
- package/dist/core/utils/index.d.mts.map +1 -1
- package/dist/core/utils/index.mjs +2 -1
- package/dist/core/utils/index.mjs.map +1 -1
- package/dist/core/utils/max-depth.d.mts +1 -0
- package/dist/core/utils/max-depth.d.mts.map +1 -1
- package/dist/core/utils/max-depth.mjs +9 -7
- package/dist/core/utils/max-depth.mjs.map +1 -1
- package/dist/core/utils/observable-brand.d.mts +13 -0
- package/dist/core/utils/observable-brand.d.mts.map +1 -0
- package/dist/core/utils/observable-brand.mjs +13 -0
- package/dist/core/utils/observable-brand.mjs.map +1 -0
- package/dist/utils/create-boolean-state.d.mts +2 -2
- package/dist/utils/create-event-emitter.d.mts +2 -2
- package/dist/utils/create-reducer.d.mts +17 -8
- package/dist/utils/create-reducer.d.mts.map +1 -1
- package/dist/utils/create-reducer.mjs +14 -6
- package/dist/utils/create-reducer.mjs.map +1 -1
- package/dist/utils/create-state.d.mts +9 -2
- package/dist/utils/create-state.d.mts.map +1 -1
- package/dist/utils/create-state.mjs +7 -0
- package/dist/utils/create-state.mjs.map +1 -1
- package/package.json +16 -16
- package/src/core/authoring.mts +19 -0
- package/src/core/class/child-observable-class.mts +374 -0
- package/src/core/{base → class}/circular-dependency-comparison.test.mts +46 -38
- package/src/core/{base → class}/circular-dependency.test.mts +38 -2
- package/src/core/class/complete-propagation.test.mts +264 -0
- package/src/core/class/create-child-observable.mts +370 -0
- package/src/core/class/create-root-observable.mts +107 -0
- package/src/core/class/index.mts +8 -0
- package/src/core/class/manager-observable-class.mts +166 -0
- package/src/core/class/observable-base-class.mts +315 -0
- package/src/core/{base → class}/observable-base.test.mts +1 -1
- package/src/core/class/observable-node.mts +54 -0
- package/src/core/class/propagation-order.test.mts +92 -0
- package/src/core/class/propagation-state.mts +80 -0
- package/src/core/class/remove-completed.test.mts +369 -0
- package/src/core/class/root-observable-class.mts +85 -0
- package/src/core/class/write-during-propagation.test.mts +234 -0
- package/src/core/combine/combine.mts +67 -55
- package/src/core/combine/merge.mts +33 -26
- package/src/core/combine/zip.mts +103 -58
- package/src/core/create/counter.mts +105 -54
- package/src/core/create/counter.test.mts +82 -0
- package/src/core/create/from-abortable-promise.mts +54 -42
- package/src/core/create/from-promise.mts +38 -29
- package/src/core/create/from-subscribable.mts +68 -23
- package/src/core/create/from-subscribable.test.mts +134 -0
- package/src/core/create/just.mts +4 -5
- package/src/core/create/source.mts +37 -13
- package/src/core/create/source.test.mts +41 -0
- package/src/core/create/timer.mts +51 -32
- package/src/core/index.mts +2 -0
- package/src/core/operators/audit.mts +79 -45
- package/src/core/operators/debounce-audit-complete.test.mts +121 -0
- package/src/core/operators/debounce.mts +81 -40
- package/src/core/operators/filter.mts +48 -31
- package/src/core/operators/index.mts +1 -0
- package/src/core/operators/inner-ownership.test.mts +280 -0
- package/src/core/operators/map.mts +49 -32
- package/src/core/operators/merge-map.mts +81 -46
- package/src/core/operators/pairwise.mts +40 -30
- package/src/core/operators/scan.mts +41 -24
- package/src/core/operators/skip-if-no-change.mts +45 -31
- package/src/core/operators/skip-until.mts +59 -33
- package/src/core/operators/skip-while.mts +49 -31
- package/src/core/operators/switch-map.mts +74 -38
- package/src/core/operators/take-until-skip-until-teardown.test.mts +133 -0
- package/src/core/operators/take-until.mts +49 -31
- package/src/core/operators/take-while.mts +50 -33
- package/src/core/operators/take.mts +138 -0
- package/src/core/operators/throttle.mts +55 -38
- package/src/core/operators/with-buffered-from.mts +45 -35
- package/src/core/operators/with-buffered-from.test.mts +57 -0
- package/src/core/operators/with-current-value-from.mts +39 -25
- package/src/core/operators/with-initial-value.mts +30 -21
- package/src/core/predefined/operators/index.mts +0 -1
- package/src/core/scope/index.mts +1 -0
- package/src/core/scope/scope.mts +260 -0
- package/src/core/scope/scope.test.mts +462 -0
- package/src/core/types/id.mts +0 -4
- package/src/core/types/index.mts +1 -0
- package/src/core/types/observable-family.mts +7 -1
- package/src/core/types/observable.mts +77 -42
- package/src/core/types/scope.mts +27 -0
- package/src/core/utils/current-scope.mts +61 -0
- package/src/core/utils/id-maker.mts +20 -30
- package/src/core/utils/index.mts +2 -1
- package/src/core/utils/max-depth.mts +12 -9
- package/src/core/utils/observable-brand.mts +12 -0
- package/src/utils/create-boolean-state.mts +2 -2
- package/src/utils/create-boolean-state.test.mts +18 -4
- package/src/utils/create-event-emitter.mts +2 -2
- package/src/utils/create-reducer.mts +22 -16
- package/src/utils/create-reducer.test.mts +43 -14
- package/src/utils/create-state.mts +9 -2
- package/src/utils/create-state.test.mts +32 -14
- package/dist/core/base/create-child-observable.d.mts +0 -65
- package/dist/core/base/create-child-observable.d.mts.map +0 -1
- package/dist/core/base/create-child-observable.mjs +0 -267
- package/dist/core/base/create-child-observable.mjs.map +0 -1
- package/dist/core/base/create-observable-base.d.mts +0 -147
- package/dist/core/base/create-observable-base.d.mts.map +0 -1
- package/dist/core/base/create-observable-base.mjs +0 -255
- package/dist/core/base/create-observable-base.mjs.map +0 -1
- package/dist/core/base/create-root-observable.d.mts +0 -37
- package/dist/core/base/create-root-observable.d.mts.map +0 -1
- package/dist/core/base/create-root-observable.mjs +0 -57
- package/dist/core/base/create-root-observable.mjs.map +0 -1
- package/dist/core/base/index.d.mts +0 -3
- package/dist/core/base/index.d.mts.map +0 -1
- package/dist/core/base/index.mjs +0 -3
- package/dist/core/base/index.mjs.map +0 -1
- package/dist/core/predefined/operators/take.d.mts.map +0 -1
- package/dist/core/predefined/operators/take.mjs +0 -44
- package/dist/core/predefined/operators/take.mjs.map +0 -1
- package/dist/core/utils/utils.d.mts +0 -6
- package/dist/core/utils/utils.d.mts.map +0 -1
- package/dist/core/utils/utils.mjs +0 -37
- package/dist/core/utils/utils.mjs.map +0 -1
- package/src/core/base/create-child-observable.mts +0 -457
- package/src/core/base/create-observable-base.mts +0 -548
- package/src/core/base/create-root-observable.mts +0 -113
- package/src/core/base/index.mts +0 -2
- package/src/core/predefined/operators/take.mts +0 -48
- package/src/core/utils/utils.mts +0 -56
- package/src/core/utils/utils.test.mts +0 -88
|
@@ -1,457 +0,0 @@
|
|
|
1
|
-
import { Arr, type Optional, type Some } from 'ts-data-forge';
|
|
2
|
-
import { panic } from 'ts-std-forge';
|
|
3
|
-
import type { MutableSet } from 'ts-type-forge';
|
|
4
|
-
import {
|
|
5
|
-
isChildObservable,
|
|
6
|
-
isManagerObservable,
|
|
7
|
-
type AsyncChildObservable,
|
|
8
|
-
type ChildObservable,
|
|
9
|
-
type InitializedSyncChildObservable,
|
|
10
|
-
type NonEmptyUnknownList,
|
|
11
|
-
type Observable,
|
|
12
|
-
type ObservableId,
|
|
13
|
-
type SyncChildObservable,
|
|
14
|
-
type UpdateToken,
|
|
15
|
-
type Wrap,
|
|
16
|
-
} from '../types/index.mjs';
|
|
17
|
-
import { maxDepth } from '../utils/index.mjs';
|
|
18
|
-
import {
|
|
19
|
-
assembleObservable,
|
|
20
|
-
createManagerObservableParts,
|
|
21
|
-
createObservableBaseHandle,
|
|
22
|
-
} from './create-observable-base.mjs';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* The internal tools a sync-child leaf factory (`map`, `filter`, `zip`, …)
|
|
26
|
-
* receives — the replacement for the `protected` methods a subclass of
|
|
27
|
-
* `SyncChildObservableClass` used to inherit.
|
|
28
|
-
*/
|
|
29
|
-
export type SyncChildObservableTools<A> = Readonly<{
|
|
30
|
-
/** Emits `nextValue` under `updateToken` and notifies subscribers. */
|
|
31
|
-
setNext: (nextValue: A, updateToken: UpdateToken) => void;
|
|
32
|
-
|
|
33
|
-
getSnapshot: () => Optional<A>;
|
|
34
|
-
|
|
35
|
-
/** Completes this observable (leaf teardown included). */
|
|
36
|
-
complete: () => void;
|
|
37
|
-
}>;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* The internal tools an async-child leaf factory (`debounce`, `switchMap`, …)
|
|
41
|
-
* receives. Async children additionally start their own update propagation.
|
|
42
|
-
*/
|
|
43
|
-
export type AsyncChildObservableTools<A> = Readonly<{
|
|
44
|
-
/** Emits `nextValue` and propagates the update to all descendants. */
|
|
45
|
-
startUpdate: (nextValue: A) => void;
|
|
46
|
-
}> &
|
|
47
|
-
SyncChildObservableTools<A>;
|
|
48
|
-
|
|
49
|
-
type ChildObservableConfigBase<P extends NonEmptyUnknownList> = Readonly<{
|
|
50
|
-
parents: Wrap<P>;
|
|
51
|
-
|
|
52
|
-
depth?: number;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Leaf teardown (clear timers, unsubscribe inner observables, …), run at
|
|
56
|
-
* the beginning of `complete()` — the closure replacement for
|
|
57
|
-
* `override complete() { teardown(); super.complete(); }`.
|
|
58
|
-
*/
|
|
59
|
-
onComplete?: () => void;
|
|
60
|
-
}>;
|
|
61
|
-
|
|
62
|
-
export type ChildObservableConfig<
|
|
63
|
-
A,
|
|
64
|
-
P extends NonEmptyUnknownList,
|
|
65
|
-
> = ChildObservableConfigBase<P> &
|
|
66
|
-
Readonly<{
|
|
67
|
-
initialValue: Optional<A>;
|
|
68
|
-
}>;
|
|
69
|
-
|
|
70
|
-
export type InitializedChildObservableConfig<
|
|
71
|
-
A,
|
|
72
|
-
P extends NonEmptyUnknownList,
|
|
73
|
-
> = ChildObservableConfigBase<P> &
|
|
74
|
-
Readonly<{
|
|
75
|
-
initialValue: Some<A>;
|
|
76
|
-
}>;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Creates a sync-child observable — the classless replacement for extending
|
|
80
|
-
* `SyncChildObservableClass`.
|
|
81
|
-
*
|
|
82
|
-
* `createTryUpdate` receives the internal tools and returns the `tryUpdate`
|
|
83
|
-
* implementation (the former `override tryUpdate`). It runs during
|
|
84
|
-
* construction, before the observable is registered to its parents; leaf
|
|
85
|
-
* state can live either in the enclosing factory scope or inside the
|
|
86
|
-
* `createTryUpdate` closure.
|
|
87
|
-
*/
|
|
88
|
-
export const createSyncChildObservable = <A, P extends NonEmptyUnknownList>(
|
|
89
|
-
{
|
|
90
|
-
parents,
|
|
91
|
-
depth = 1 + maxDepth(parents),
|
|
92
|
-
initialValue,
|
|
93
|
-
onComplete,
|
|
94
|
-
}: ChildObservableConfig<A, P>,
|
|
95
|
-
createTryUpdate: (
|
|
96
|
-
tools: SyncChildObservableTools<A>,
|
|
97
|
-
) => (updateToken: UpdateToken) => void,
|
|
98
|
-
): SyncChildObservable<A, P> => {
|
|
99
|
-
const handle = createObservableBaseHandle<A>(initialValue);
|
|
100
|
-
|
|
101
|
-
/** Set once assembled; see {@link unregisterChild}. */
|
|
102
|
-
let mut_self: ChildObservable<A> | undefined = undefined;
|
|
103
|
-
|
|
104
|
-
const autoComplete =
|
|
105
|
-
onComplete !== undefined || parents.some((p) => p.autoComplete);
|
|
106
|
-
|
|
107
|
-
const dispose = (): void => {
|
|
108
|
-
// A completed node is reached again through every parent and child that
|
|
109
|
-
// completes after it; running again would repeat the teardown and the
|
|
110
|
-
// ancestor walk in `unregisterChild` for each of them.
|
|
111
|
-
if (handle.isCompleted()) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
onComplete?.();
|
|
116
|
-
|
|
117
|
-
handle.completeBase();
|
|
118
|
-
|
|
119
|
-
if (mut_self !== undefined) {
|
|
120
|
-
unregisterChild(mut_self, parents);
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const complete = (): void => {
|
|
125
|
-
if (handle.isCompleted()) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
dispose();
|
|
130
|
-
|
|
131
|
-
// propagate to parents
|
|
132
|
-
for (const par of parents) {
|
|
133
|
-
par.tryComplete();
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const tryComplete = (): void => {
|
|
138
|
-
if (handle.isCompleted()) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
tryCompleteChild({
|
|
143
|
-
hasSubscriber: handle.hasSubscriber(),
|
|
144
|
-
hasActiveChild: handle.hasActiveChild(),
|
|
145
|
-
autoComplete,
|
|
146
|
-
parents,
|
|
147
|
-
complete,
|
|
148
|
-
});
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const tryUpdate = createTryUpdate({
|
|
152
|
-
setNext: handle.setNext,
|
|
153
|
-
getSnapshot: handle.getSnapshot,
|
|
154
|
-
complete,
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
const observable: SyncChildObservable<A, P> = assembleObservable({
|
|
158
|
-
kind: 'sync child',
|
|
159
|
-
depth,
|
|
160
|
-
handle,
|
|
161
|
-
tryUpdate,
|
|
162
|
-
tryComplete,
|
|
163
|
-
complete,
|
|
164
|
-
dispose,
|
|
165
|
-
autoComplete,
|
|
166
|
-
extra: { parents },
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
registerChild(observable, parents);
|
|
170
|
-
|
|
171
|
-
mut_self = observable;
|
|
172
|
-
|
|
173
|
-
return observable;
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Creates a sync-child observable that always holds a value.
|
|
178
|
-
*
|
|
179
|
-
* Runtime-wise this is exactly `createSyncChildObservable`; only the types of
|
|
180
|
-
* `getSnapshot` and `pipe` are narrowed, which is what the
|
|
181
|
-
* `InitializedSyncChildObservableClass` overrides existed for.
|
|
182
|
-
*/
|
|
183
|
-
export const createInitializedSyncChildObservable = <
|
|
184
|
-
A,
|
|
185
|
-
P extends NonEmptyUnknownList,
|
|
186
|
-
>(
|
|
187
|
-
config: InitializedChildObservableConfig<A, P>,
|
|
188
|
-
createTryUpdate: (
|
|
189
|
-
tools: SyncChildObservableTools<A>,
|
|
190
|
-
) => (updateToken: UpdateToken) => void,
|
|
191
|
-
): InitializedSyncChildObservable<A, P> => {
|
|
192
|
-
const observable = createSyncChildObservable<A, P>(config, createTryUpdate);
|
|
193
|
-
|
|
194
|
-
return (
|
|
195
|
-
// `getSnapshot` always returns `Some` here: `initialValue` is a `Some` and
|
|
196
|
-
// `setNext` only ever stores a `Some`.
|
|
197
|
-
// @sumi-expect-error banned-syntax/no-unsafe-type-assertion
|
|
198
|
-
observable as InitializedSyncChildObservable<A, P>
|
|
199
|
-
);
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Creates an async-child observable — the classless replacement for extending
|
|
204
|
-
* `AsyncChildObservableClass`. See {@link createSyncChildObservable} for the
|
|
205
|
-
* `createTryUpdate` contract.
|
|
206
|
-
*/
|
|
207
|
-
export const createAsyncChildObservable = <A, P extends NonEmptyUnknownList>(
|
|
208
|
-
{
|
|
209
|
-
parents,
|
|
210
|
-
depth = 1 + maxDepth(parents),
|
|
211
|
-
initialValue,
|
|
212
|
-
onComplete,
|
|
213
|
-
}: ChildObservableConfig<A, P>,
|
|
214
|
-
createTryUpdate: (
|
|
215
|
-
tools: AsyncChildObservableTools<A>,
|
|
216
|
-
) => (updateToken: UpdateToken) => void,
|
|
217
|
-
): AsyncChildObservable<A, P> => {
|
|
218
|
-
const handle = createObservableBaseHandle<A>(initialValue);
|
|
219
|
-
|
|
220
|
-
const { addDescendant, deleteDescendant, startUpdate } =
|
|
221
|
-
createManagerObservableParts(handle);
|
|
222
|
-
|
|
223
|
-
/** Set once assembled; see {@link unregisterChild}. */
|
|
224
|
-
let mut_self: ChildObservable<A> | undefined = undefined;
|
|
225
|
-
|
|
226
|
-
const autoComplete =
|
|
227
|
-
onComplete !== undefined || parents.some((p) => p.autoComplete);
|
|
228
|
-
|
|
229
|
-
const dispose = (): void => {
|
|
230
|
-
// A completed node is reached again through every parent and child that
|
|
231
|
-
// completes after it; running again would repeat the teardown and the
|
|
232
|
-
// ancestor walk in `unregisterChild` for each of them.
|
|
233
|
-
if (handle.isCompleted()) {
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
onComplete?.();
|
|
238
|
-
|
|
239
|
-
handle.completeBase();
|
|
240
|
-
|
|
241
|
-
if (mut_self !== undefined) {
|
|
242
|
-
unregisterChild(mut_self, parents);
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
const complete = (): void => {
|
|
247
|
-
if (handle.isCompleted()) {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
dispose();
|
|
252
|
-
|
|
253
|
-
// propagate to parents
|
|
254
|
-
for (const par of parents) {
|
|
255
|
-
par.tryComplete();
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
const tryComplete = (): void => {
|
|
260
|
-
if (handle.isCompleted()) {
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
tryCompleteChild({
|
|
265
|
-
hasSubscriber: handle.hasSubscriber(),
|
|
266
|
-
hasActiveChild: handle.hasActiveChild(),
|
|
267
|
-
autoComplete,
|
|
268
|
-
parents,
|
|
269
|
-
complete,
|
|
270
|
-
});
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
const tryUpdate = createTryUpdate({
|
|
274
|
-
setNext: handle.setNext,
|
|
275
|
-
getSnapshot: handle.getSnapshot,
|
|
276
|
-
complete,
|
|
277
|
-
startUpdate,
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
const observable: AsyncChildObservable<A, P> = assembleObservable({
|
|
281
|
-
kind: 'async child',
|
|
282
|
-
depth,
|
|
283
|
-
handle,
|
|
284
|
-
tryUpdate,
|
|
285
|
-
tryComplete,
|
|
286
|
-
complete,
|
|
287
|
-
dispose,
|
|
288
|
-
autoComplete,
|
|
289
|
-
extra: { parents, addDescendant, deleteDescendant },
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
registerChild(observable, parents);
|
|
293
|
-
|
|
294
|
-
mut_self = observable;
|
|
295
|
-
|
|
296
|
-
return observable;
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
/* helpers */
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Detects circular dependencies by walking the full ancestor chain of the
|
|
303
|
-
* given parents and checking whether `child` already appears among them.
|
|
304
|
-
*
|
|
305
|
-
* @throws {Error} if a circular dependency is detected
|
|
306
|
-
*/
|
|
307
|
-
const hasCircularDependencyFrom = (
|
|
308
|
-
node: Observable<unknown>,
|
|
309
|
-
mut_visited: MutableSet<ObservableId>,
|
|
310
|
-
mut_inPath: MutableSet<ObservableId>,
|
|
311
|
-
): boolean => {
|
|
312
|
-
if (mut_inPath.has(node.id)) {
|
|
313
|
-
return true;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
if (mut_visited.has(node.id)) {
|
|
317
|
-
return false;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
mut_visited.add(node.id);
|
|
321
|
-
|
|
322
|
-
mut_inPath.add(node.id);
|
|
323
|
-
|
|
324
|
-
if (isChildObservable(node)) {
|
|
325
|
-
for (const parent of node.parents) {
|
|
326
|
-
if (hasCircularDependencyFrom(parent, mut_visited, mut_inPath)) {
|
|
327
|
-
return true;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
mut_inPath.delete(node.id);
|
|
333
|
-
|
|
334
|
-
return false;
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
const detectCircularDependency = (
|
|
338
|
-
child: ChildObservable<unknown>,
|
|
339
|
-
parents: readonly Observable<unknown>[],
|
|
340
|
-
): void => {
|
|
341
|
-
const mut_visited = new Set<ObservableId>();
|
|
342
|
-
|
|
343
|
-
const mut_inPath = new Set<ObservableId>([child.id]);
|
|
344
|
-
|
|
345
|
-
for (const parent of parents) {
|
|
346
|
-
if (hasCircularDependencyFrom(parent, mut_visited, mut_inPath)) {
|
|
347
|
-
// A programming error (invariant violation), not a recoverable
|
|
348
|
-
// failure. `panic` marks the error it throws, so the `Result` /
|
|
349
|
-
// `AsyncResult` boundaries rethrow it rather than turning an invariant
|
|
350
|
-
// violation into an `Err` a caller might handle (Sumi D-48 / D-53).
|
|
351
|
-
panic(
|
|
352
|
-
'Circular dependency detected in observable graph: a child observable cannot be its own ancestor.',
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Registers `child` to its parents and to all reachable manager observables.
|
|
360
|
-
* Runs after the child object is fully assembled, so parents only ever hold a
|
|
361
|
-
* reference to the final composed object (the class version registered `this`
|
|
362
|
-
* from inside the constructor instead).
|
|
363
|
-
*/
|
|
364
|
-
const registerChild = <A,>(
|
|
365
|
-
child: ChildObservable<A>,
|
|
366
|
-
parents: ChildObservable<A>['parents'],
|
|
367
|
-
): void => {
|
|
368
|
-
detectCircularDependency(child, parents);
|
|
369
|
-
|
|
370
|
-
for (const p of parents) {
|
|
371
|
-
p.addChild(child);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// register child to all reachable ManagerObservables
|
|
375
|
-
const mut_rest = Array.from(parents);
|
|
376
|
-
|
|
377
|
-
while (Arr.isNonEmpty(mut_rest)) {
|
|
378
|
-
const p = mut_rest.pop();
|
|
379
|
-
|
|
380
|
-
if (p === undefined) {
|
|
381
|
-
break;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (isManagerObservable(p)) {
|
|
385
|
-
p.addDescendant(child);
|
|
386
|
-
} else {
|
|
387
|
-
// trace back dependency graph
|
|
388
|
-
mut_rest.push(...p.parents);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* Undoes {@link registerChild} for a completed child: its parents forget it, and
|
|
395
|
-
* every manager it registered to stops propagating updates to it. Without this
|
|
396
|
-
* a completed node stayed reachable for as long as its root lived, and ran its
|
|
397
|
-
* `tryUpdate` on every update (#2134).
|
|
398
|
-
*
|
|
399
|
-
* A completion that happens while the child is still being constructed (from
|
|
400
|
-
* a leaf factory's `createTryUpdate`) precedes its registration, so there is
|
|
401
|
-
* nothing to undo; `mut_self` is still `undefined` then.
|
|
402
|
-
*/
|
|
403
|
-
const unregisterChild = <A,>(
|
|
404
|
-
child: ChildObservable<A>,
|
|
405
|
-
parents: ChildObservable<A>['parents'],
|
|
406
|
-
): void => {
|
|
407
|
-
for (const p of parents) {
|
|
408
|
-
p.deleteChild(child);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
const mut_rest = Array.from(parents);
|
|
412
|
-
|
|
413
|
-
while (Arr.isNonEmpty(mut_rest)) {
|
|
414
|
-
const p = mut_rest.pop();
|
|
415
|
-
|
|
416
|
-
if (p === undefined) {
|
|
417
|
-
break;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
if (isManagerObservable(p)) {
|
|
421
|
-
p.deleteDescendant(child);
|
|
422
|
-
} else {
|
|
423
|
-
mut_rest.push(...p.parents);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
const tryCompleteChild = <A,>({
|
|
429
|
-
hasSubscriber,
|
|
430
|
-
hasActiveChild,
|
|
431
|
-
autoComplete,
|
|
432
|
-
parents,
|
|
433
|
-
complete,
|
|
434
|
-
}: Readonly<{
|
|
435
|
-
hasSubscriber: boolean;
|
|
436
|
-
hasActiveChild: boolean;
|
|
437
|
-
autoComplete: boolean;
|
|
438
|
-
parents: ChildObservable<A>['parents'];
|
|
439
|
-
complete: () => void;
|
|
440
|
-
}>): void => {
|
|
441
|
-
// If there is no working parent node
|
|
442
|
-
if (parents.every((r) => r.isCompleted)) {
|
|
443
|
-
complete();
|
|
444
|
-
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// If there are no active child node, and completing releases something
|
|
449
|
-
if (autoComplete && !hasSubscriber && !hasActiveChild) {
|
|
450
|
-
complete();
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// propagate to parents
|
|
454
|
-
for (const par of parents) {
|
|
455
|
-
par.tryComplete();
|
|
456
|
-
}
|
|
457
|
-
};
|