synstate 3.4.0 → 4.1.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 +13 -8
- 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.map +1 -1
- package/dist/core/combine/merge.mjs +26 -14
- package/dist/core/combine/merge.mjs.map +1 -1
- package/dist/core/combine/zip.d.mts.map +1 -1
- package/dist/core/combine/zip.mjs +43 -25
- package/dist/core/combine/zip.mjs.map +1 -1
- package/dist/core/create/counter.d.mts.map +1 -1
- package/dist/core/create/counter.mjs +65 -44
- package/dist/core/create/counter.mjs.map +1 -1
- package/dist/core/create/empty.d.mts +32 -0
- package/dist/core/create/empty.d.mts.map +1 -0
- package/dist/core/create/empty.mjs +39 -0
- package/dist/core/create/empty.mjs.map +1 -0
- 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 +37 -24
- package/dist/core/create/from-subscribable.mjs.map +1 -1
- package/dist/core/create/index.d.mts +1 -0
- package/dist/core/create/index.d.mts.map +1 -1
- package/dist/core/create/index.mjs +1 -0
- package/dist/core/create/index.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.map +1 -1
- package/dist/core/create/source.mjs +27 -17
- 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 -0
- package/dist/core/operators/merge-map.d.mts.map +1 -1
- package/dist/core/operators/merge-map.mjs +52 -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 +40 -26
- 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 -0
- package/dist/core/operators/switch-map.d.mts.map +1 -1
- package/dist/core/operators/switch-map.mjs +56 -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 +36 -29
- 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 +43 -39
- 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 +1 -0
- package/dist/core/types/observable-family.d.mts.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-reducer.d.mts +7 -7
- package/dist/utils/create-reducer.mjs +2 -2
- package/dist/utils/create-reducer.mjs.map +1 -1
- package/dist/utils/create-state.d.mts +2 -2
- package/package.json +17 -17
- 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/{base → class}/write-during-propagation.test.mts +3 -3
- package/src/core/combine/combine.mts +67 -55
- package/src/core/combine/merge.mts +33 -23
- package/src/core/combine/zip.mts +95 -81
- package/src/core/create/counter.mts +95 -65
- package/src/core/create/empty.mts +42 -0
- package/src/core/create/empty.test.mts +65 -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 +62 -45
- package/src/core/create/from-subscribable.test.mts +8 -3
- package/src/core/create/index.mts +1 -0
- package/src/core/create/just.mts +4 -5
- package/src/core/create/source.mts +29 -20
- 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 -43
- 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 +55 -41
- package/src/core/operators/skip-while.mts +49 -31
- package/src/core/operators/switch-map.mts +74 -35
- package/src/core/operators/take-until-skip-until-teardown.test.mts +18 -12
- package/src/core/operators/take-until.mts +45 -41
- 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 +42 -44
- package/src/core/operators/with-buffered-from.test.mts +4 -3
- 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 +2 -0
- 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-reducer.mts +9 -9
- package/src/utils/create-reducer.test.mts +31 -14
- package/src/utils/create-state.mts +2 -2
- package/src/utils/create-state.test.mts +12 -14
- package/dist/core/base/create-child-observable.d.mts +0 -72
- package/dist/core/base/create-child-observable.d.mts.map +0 -1
- package/dist/core/base/create-child-observable.mjs +0 -285
- package/dist/core/base/create-child-observable.mjs.map +0 -1
- package/dist/core/base/create-observable-base.d.mts +0 -149
- package/dist/core/base/create-observable-base.d.mts.map +0 -1
- package/dist/core/base/create-observable-base.mjs +0 -273
- package/dist/core/base/create-observable-base.mjs.map +0 -1
- package/dist/core/base/create-root-observable.d.mts +0 -46
- package/dist/core/base/create-root-observable.d.mts.map +0 -1
- package/dist/core/base/create-root-observable.mjs +0 -80
- 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 -485
- package/src/core/base/create-observable-base.mts +0 -568
- package/src/core/base/create-root-observable.mts +0 -147
- 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,8 +1,16 @@
|
|
|
1
|
+
// Sumi bans classes, `this`, method syntax and writes to `this` outside a
|
|
2
|
+
// `mut_` binding; an observable is a class (`ObservableBaseClass` says why),
|
|
3
|
+
// so those rules are waived here (D-63).
|
|
4
|
+
// @sumi-expect-error-file classes/no-class
|
|
5
|
+
// @sumi-expect-error-file banned-syntax/no-this
|
|
6
|
+
// @sumi-expect-error-file functions/prefer-arrow-function
|
|
7
|
+
// @sumi-expect-error-file mutation/no-mutation-without-mut-prefix
|
|
1
8
|
import { Optional, pipe } from 'ts-data-forge';
|
|
2
|
-
import {
|
|
9
|
+
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
3
10
|
import type {
|
|
4
11
|
DropInitialValueOperator,
|
|
5
12
|
Observable,
|
|
13
|
+
UpdateToken,
|
|
6
14
|
WithCurrentValueFromOperatorObservable,
|
|
7
15
|
} from '../types/index.mjs';
|
|
8
16
|
import { maxDepth } from '../utils/index.mjs';
|
|
@@ -68,7 +76,7 @@ export const withCurrentValueFrom =
|
|
|
68
76
|
observable: Observable<B>,
|
|
69
77
|
): DropInitialValueOperator<A, readonly [A, B]> =>
|
|
70
78
|
(parentObservable) =>
|
|
71
|
-
|
|
79
|
+
new WithCurrentValueFromObservableClass(parentObservable, observable);
|
|
72
80
|
|
|
73
81
|
/**
|
|
74
82
|
* Alias for `withCurrentValueFrom`.
|
|
@@ -76,12 +84,14 @@ export const withCurrentValueFrom =
|
|
|
76
84
|
*/
|
|
77
85
|
export const withLatestFrom = withCurrentValueFrom;
|
|
78
86
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
class WithCurrentValueFromObservableClass<A, B>
|
|
88
|
+
extends SyncChildObservableClass<readonly [A, B], readonly [A]>
|
|
89
|
+
implements WithCurrentValueFromOperatorObservable<A, B>
|
|
90
|
+
{
|
|
91
|
+
readonly #observable: Observable<B>;
|
|
92
|
+
|
|
93
|
+
constructor(parentObservable: Observable<A>, observable: Observable<B>) {
|
|
94
|
+
super({
|
|
85
95
|
parents: [parentObservable],
|
|
86
96
|
depth: 1 + maxDepth([parentObservable, observable]),
|
|
87
97
|
initialValue: pipe({
|
|
@@ -92,24 +102,28 @@ const createWithCurrentValueFromObservable = <A, B>(
|
|
|
92
102
|
? Optional.none
|
|
93
103
|
: Optional.some([par.value, me.value] as const),
|
|
94
104
|
).value,
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
this.#observable = observable;
|
|
108
|
+
|
|
109
|
+
this.attach();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
override tryUpdate(updateToken: UpdateToken): void {
|
|
113
|
+
const par = this.parents[0];
|
|
114
|
+
|
|
115
|
+
const ps = par.getSnapshot();
|
|
99
116
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
) {
|
|
104
|
-
return; // skip update
|
|
105
|
-
}
|
|
117
|
+
if (par.updateToken !== updateToken || Optional.isNone(ps)) {
|
|
118
|
+
return; // skip update
|
|
119
|
+
}
|
|
106
120
|
|
|
107
|
-
|
|
121
|
+
const curr = this.#observable.getSnapshot();
|
|
108
122
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
123
|
+
if (Optional.isNone(curr)) {
|
|
124
|
+
return; // skip update
|
|
125
|
+
}
|
|
112
126
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
127
|
+
this.setNext([ps.value, curr.value], updateToken);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
// Sumi bans classes, `this`, method syntax and writes to `this` outside a
|
|
2
|
+
// `mut_` binding; an observable is a class (`ObservableBaseClass` says why),
|
|
3
|
+
// so those rules are waived here (D-63).
|
|
4
|
+
// @sumi-expect-error-file classes/no-class
|
|
5
|
+
// @sumi-expect-error-file banned-syntax/no-this
|
|
6
|
+
// @sumi-expect-error-file functions/prefer-arrow-function
|
|
1
7
|
import { expectType, Optional } from 'ts-data-forge';
|
|
2
|
-
import {
|
|
8
|
+
import { InitializedSyncChildObservableClass } from '../class/index.mjs';
|
|
3
9
|
import { source } from '../create/index.mjs';
|
|
4
10
|
import type {
|
|
5
11
|
InitializedObservable,
|
|
6
12
|
Observable,
|
|
13
|
+
UpdateToken,
|
|
7
14
|
WithInitialValueOperator,
|
|
8
15
|
WithInitialValueOperatorObservable,
|
|
9
16
|
} from '../types/index.mjs';
|
|
@@ -56,31 +63,33 @@ import type {
|
|
|
56
63
|
export const withInitialValue =
|
|
57
64
|
<A, I = A>(initialValue: I): WithInitialValueOperator<A, A | I> =>
|
|
58
65
|
(parentObservable) =>
|
|
59
|
-
|
|
66
|
+
new WithInitialValueObservableClass(parentObservable, initialValue);
|
|
60
67
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
{
|
|
68
|
+
class WithInitialValueObservableClass<A, I>
|
|
69
|
+
extends InitializedSyncChildObservableClass<A | I, readonly [A]>
|
|
70
|
+
implements WithInitialValueOperatorObservable<A, I>
|
|
71
|
+
{
|
|
72
|
+
constructor(parentObservable: Observable<A>, initialValue: I) {
|
|
73
|
+
super({
|
|
67
74
|
parents: [parentObservable],
|
|
68
75
|
initialValue: Optional.some(initialValue),
|
|
69
|
-
}
|
|
70
|
-
({ setNext }) =>
|
|
71
|
-
(updateToken) => {
|
|
72
|
-
const sn = parentObservable.getSnapshot();
|
|
76
|
+
});
|
|
73
77
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
this.attach();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
override tryUpdate(updateToken: UpdateToken): void {
|
|
82
|
+
const par = this.parents[0];
|
|
83
|
+
|
|
84
|
+
const sn = par.getSnapshot();
|
|
80
85
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
if (par.updateToken !== updateToken || Optional.isNone(sn)) {
|
|
87
|
+
return; // skip update
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.setNext(sn.value, updateToken);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
84
93
|
|
|
85
94
|
if (import.meta.vitest !== undefined) {
|
|
86
95
|
test('type test', () => {
|
|
@@ -5,7 +5,6 @@ export * from './map-result-ok.mjs';
|
|
|
5
5
|
export * from './map-to.mjs';
|
|
6
6
|
export * from './pluck.mjs';
|
|
7
7
|
export * from './skip.mjs';
|
|
8
|
-
export * from './take.mjs';
|
|
9
8
|
export * from './unwrap-optional.mjs';
|
|
10
9
|
export * from './unwrap-result-err.mjs';
|
|
11
10
|
export * from './unwrap-result-ok.mjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './scope.mjs';
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
// Sumi bans classes, `this`, method syntax and writes to `this` outside a
|
|
2
|
+
// `mut_` binding. A scope is a class for the reason the observables are (see
|
|
3
|
+
// `ScopeClass` below), so those four rules are waived here (D-63).
|
|
4
|
+
// @sumi-expect-error-file classes/no-class
|
|
5
|
+
// @sumi-expect-error-file banned-syntax/no-this
|
|
6
|
+
// @sumi-expect-error-file functions/prefer-arrow-function
|
|
7
|
+
// @sumi-expect-error-file mutation/no-mutation-without-mut-prefix
|
|
8
|
+
import type { Scope } from '../types/index.mjs';
|
|
9
|
+
import {
|
|
10
|
+
getCurrentScopeInternals,
|
|
11
|
+
runWithScope,
|
|
12
|
+
type ScopeInternals,
|
|
13
|
+
type ScopeMember,
|
|
14
|
+
} from '../utils/index.mjs';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a {@link Scope}. Observables created synchronously inside
|
|
18
|
+
* `scope.run(body)` belong to it, and `scope.dispose()` disposes them without
|
|
19
|
+
* completing the shared observables they were derived from.
|
|
20
|
+
*
|
|
21
|
+
* With `parent`, the new scope is disposed together with it; without one it
|
|
22
|
+
* stands alone and lives until its own `dispose()`. A parent that is already
|
|
23
|
+
* disposed gives a scope that is born disposed, with a warning.
|
|
24
|
+
*
|
|
25
|
+
* Intended for authors of libraries built on synstate rather than for
|
|
26
|
+
* application code; state defined at module level belongs to no scope and
|
|
27
|
+
* lives as long as the page.
|
|
28
|
+
*
|
|
29
|
+
* `run` and `dispose` read the scope they are called on, so call them on it
|
|
30
|
+
* (`scope.dispose()`) rather than taking them off it.
|
|
31
|
+
*
|
|
32
|
+
* @param parent - The scope whose disposal also disposes the new one
|
|
33
|
+
* @returns The new scope
|
|
34
|
+
*/
|
|
35
|
+
export const createScope = (parent?: Scope): Scope =>
|
|
36
|
+
new ScopeClass(parent instanceof ScopeClass ? parent : undefined);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Returns the scope whose `run` is executing, or `undefined` outside every
|
|
40
|
+
* `run` and inside {@link untracked}.
|
|
41
|
+
*
|
|
42
|
+
* To put work that runs later (after an `await`, in a callback) into the
|
|
43
|
+
* current scope, take it here while still synchronous and wrap the later work
|
|
44
|
+
* in its `run`.
|
|
45
|
+
*
|
|
46
|
+
* @returns The current scope, if any
|
|
47
|
+
*/
|
|
48
|
+
export const getCurrentScope = (): Scope | undefined =>
|
|
49
|
+
getCurrentScopeInternals();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Registers `cleanup` to be called when the current scope is disposed. Cleanups
|
|
53
|
+
* run after the child scopes are disposed and before the owned observables
|
|
54
|
+
* are, newest first.
|
|
55
|
+
*
|
|
56
|
+
* Outside every scope it warns and registers nothing.
|
|
57
|
+
*
|
|
58
|
+
* @param cleanup - The function to call
|
|
59
|
+
*/
|
|
60
|
+
export const onScopeDispose = (cleanup: () => void): void => {
|
|
61
|
+
const current = getCurrentScopeInternals();
|
|
62
|
+
|
|
63
|
+
if (current === undefined) {
|
|
64
|
+
console.warn(
|
|
65
|
+
'synstate: onScopeDispose() was called outside any scope; the cleanup will never run.',
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
current.addCleanup(cleanup);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Calls `body` with no current scope and returns what it returns, so that the
|
|
76
|
+
* observables it creates belong to no scope and outlive the surrounding one.
|
|
77
|
+
*
|
|
78
|
+
* @param body - The function to call
|
|
79
|
+
* @returns What `body` returns
|
|
80
|
+
*/
|
|
81
|
+
export const untracked = <R,>(body: () => R): R =>
|
|
82
|
+
runWithScope(undefined, body);
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* A scope is created for every row and branch of a UI, so creating one has to
|
|
86
|
+
* be cheap. It used to be a set of closures with a `Set` of children, a `Set`
|
|
87
|
+
* of owned observables and a record in a `WeakMap`; it is now one object whose
|
|
88
|
+
* methods live on the prototype and whose lists are arrays made when the
|
|
89
|
+
* first entry arrives.
|
|
90
|
+
*
|
|
91
|
+
* Whatever leaves a list on its own (a child scope disposed by itself, an
|
|
92
|
+
* observable that completed) is not looked up and spliced out: it only counts
|
|
93
|
+
* itself gone, and once at least half of a list is gone the list is rebuilt
|
|
94
|
+
* from what is left. Disposal walks the lists newest first, as before.
|
|
95
|
+
*
|
|
96
|
+
* The class itself is not exported; `createScope` is the way to make one.
|
|
97
|
+
*/
|
|
98
|
+
class ScopeClass implements ScopeInternals {
|
|
99
|
+
readonly #parent: ScopeClass | undefined;
|
|
100
|
+
// Pushed to in place: a scope gains children, cleanups and nodes one at a
|
|
101
|
+
// time, and copying the list for each would make a big scope quadratic.
|
|
102
|
+
// @sumi-expect-error readonly/require-readonly-type
|
|
103
|
+
#mut_children: ScopeClass[] | undefined;
|
|
104
|
+
#mut_goneChildren: number;
|
|
105
|
+
// @sumi-expect-error readonly/require-readonly-type
|
|
106
|
+
#mut_cleanups: (() => void)[] | undefined;
|
|
107
|
+
// @sumi-expect-error readonly/require-readonly-type
|
|
108
|
+
#mut_nodes: ScopeMember[] | undefined;
|
|
109
|
+
#mut_goneNodes: number;
|
|
110
|
+
#mut_isDisposed: boolean;
|
|
111
|
+
|
|
112
|
+
constructor(parent: ScopeClass | undefined) {
|
|
113
|
+
this.#parent = parent;
|
|
114
|
+
|
|
115
|
+
this.#mut_children = undefined;
|
|
116
|
+
|
|
117
|
+
this.#mut_goneChildren = 0;
|
|
118
|
+
|
|
119
|
+
this.#mut_cleanups = undefined;
|
|
120
|
+
|
|
121
|
+
this.#mut_nodes = undefined;
|
|
122
|
+
|
|
123
|
+
this.#mut_goneNodes = 0;
|
|
124
|
+
|
|
125
|
+
this.#mut_isDisposed = false;
|
|
126
|
+
|
|
127
|
+
if (parent !== undefined) {
|
|
128
|
+
if (parent.#mut_isDisposed) {
|
|
129
|
+
console.warn(
|
|
130
|
+
'synstate: createScope() was given a disposed parent; the new scope is born disposed.',
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
this.#mut_isDisposed = true;
|
|
134
|
+
} else if (parent.#mut_children === undefined) {
|
|
135
|
+
parent.#mut_children = [this];
|
|
136
|
+
} else {
|
|
137
|
+
parent.#mut_children.push(this);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Called by a child scope that was disposed on its own. */
|
|
143
|
+
#childGone(): void {
|
|
144
|
+
const children = this.#mut_children;
|
|
145
|
+
|
|
146
|
+
if (children === undefined) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
this.#mut_goneChildren += 1;
|
|
151
|
+
|
|
152
|
+
if (!isMostlyGone(this.#mut_goneChildren, children.length)) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.#mut_children = children.filter((c) => !c.#mut_isDisposed);
|
|
157
|
+
|
|
158
|
+
this.#mut_goneChildren = 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
run<R>(body: () => R): R {
|
|
162
|
+
if (this.#mut_isDisposed) {
|
|
163
|
+
console.warn(
|
|
164
|
+
'synstate: run() was called on a disposed scope; what it creates belongs to no scope.',
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
return runWithScope(undefined, body);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return runWithScope(this, body);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
dispose(): void {
|
|
174
|
+
if (this.#mut_isDisposed) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Set first: the children, cleanups and nodes below call back into this
|
|
179
|
+
// scope (`childGone`, `release`), which has nothing to do once it is
|
|
180
|
+
// disposing everything anyway.
|
|
181
|
+
this.#mut_isDisposed = true;
|
|
182
|
+
|
|
183
|
+
const children = this.#mut_children;
|
|
184
|
+
|
|
185
|
+
if (children !== undefined) {
|
|
186
|
+
this.#mut_children = undefined;
|
|
187
|
+
|
|
188
|
+
for (let mut_i = children.length - 1; mut_i >= 0; mut_i -= 1) {
|
|
189
|
+
children[mut_i]?.dispose();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const cleanups = this.#mut_cleanups;
|
|
194
|
+
|
|
195
|
+
if (cleanups !== undefined) {
|
|
196
|
+
this.#mut_cleanups = undefined;
|
|
197
|
+
|
|
198
|
+
for (let mut_i = cleanups.length - 1; mut_i >= 0; mut_i -= 1) {
|
|
199
|
+
cleanups[mut_i]?.();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const nodes = this.#mut_nodes;
|
|
204
|
+
|
|
205
|
+
if (nodes !== undefined) {
|
|
206
|
+
this.#mut_nodes = undefined;
|
|
207
|
+
|
|
208
|
+
for (let mut_i = nodes.length - 1; mut_i >= 0; mut_i -= 1) {
|
|
209
|
+
nodes[mut_i]?.dispose();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (this.#parent !== undefined) {
|
|
214
|
+
this.#parent.#childGone();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
adopt(node: ScopeMember): void {
|
|
219
|
+
if (this.#mut_nodes === undefined) {
|
|
220
|
+
this.#mut_nodes = [node];
|
|
221
|
+
} else {
|
|
222
|
+
this.#mut_nodes.push(node);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
release(): void {
|
|
227
|
+
const nodes = this.#mut_nodes;
|
|
228
|
+
|
|
229
|
+
if (nodes === undefined) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
this.#mut_goneNodes += 1;
|
|
234
|
+
|
|
235
|
+
if (!isMostlyGone(this.#mut_goneNodes, nodes.length)) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
this.#mut_nodes = nodes.filter((n) => !n.isCompleted);
|
|
240
|
+
|
|
241
|
+
this.#mut_goneNodes = 0;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
addCleanup(cleanup: () => void): void {
|
|
245
|
+
if (this.#mut_cleanups === undefined) {
|
|
246
|
+
this.#mut_cleanups = [cleanup];
|
|
247
|
+
} else {
|
|
248
|
+
this.#mut_cleanups.push(cleanup);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Whether a list is worth rebuilding: at least half of it is gone, and enough
|
|
255
|
+
* of it that the rebuild is paid for by the entries it drops.
|
|
256
|
+
*/
|
|
257
|
+
const isMostlyGone = (gone: number, length: number): boolean =>
|
|
258
|
+
gone >= minGoneToCompact && gone * 2 >= length;
|
|
259
|
+
|
|
260
|
+
const minGoneToCompact = 16;
|