synstate 3.4.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 +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/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/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 +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/{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/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/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 } from 'ts-data-forge';
|
|
2
|
-
import {
|
|
9
|
+
import { InitializedSyncChildObservableClass } from '../class/index.mjs';
|
|
3
10
|
import type {
|
|
4
11
|
Observable,
|
|
5
12
|
ScanOperatorObservable,
|
|
13
|
+
UpdateToken,
|
|
6
14
|
WithInitialValueOperator,
|
|
7
15
|
} from '../types/index.mjs';
|
|
8
16
|
|
|
@@ -61,32 +69,41 @@ export const scan =
|
|
|
61
69
|
initialValue: B,
|
|
62
70
|
): WithInitialValueOperator<A, B> =>
|
|
63
71
|
(parentObservable) =>
|
|
64
|
-
|
|
72
|
+
new ScanObservableClass(parentObservable, reducer, initialValue);
|
|
65
73
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
class ScanObservableClass<A, B>
|
|
75
|
+
extends InitializedSyncChildObservableClass<B, readonly [A]>
|
|
76
|
+
implements ScanOperatorObservable<A, B>
|
|
77
|
+
{
|
|
78
|
+
readonly #reducer: (acc: B, curr: A) => B;
|
|
79
|
+
|
|
80
|
+
constructor(
|
|
81
|
+
parentObservable: Observable<A>,
|
|
82
|
+
reducer: (acc: B, curr: A) => B,
|
|
83
|
+
initialValue: B,
|
|
84
|
+
) {
|
|
85
|
+
super({
|
|
73
86
|
parents: [parentObservable],
|
|
74
87
|
initialValue: Optional.some(initialValue),
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
this.#reducer = reducer;
|
|
91
|
+
|
|
92
|
+
this.attach();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
override tryUpdate(updateToken: UpdateToken): void {
|
|
96
|
+
const par = this.parents[0];
|
|
79
97
|
|
|
80
|
-
|
|
98
|
+
const psn = par.getSnapshot();
|
|
81
99
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
Optional.isNone(sn)
|
|
86
|
-
) {
|
|
87
|
-
return; // skip update
|
|
88
|
-
}
|
|
100
|
+
if (par.updateToken !== updateToken || Optional.isNone(psn)) {
|
|
101
|
+
return; // skip update
|
|
102
|
+
}
|
|
89
103
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
this.setNext(
|
|
105
|
+
this.#reducer(this.getSnapshot().value, psn.value),
|
|
106
|
+
updateToken,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -1,9 +1,17 @@
|
|
|
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 } from 'ts-data-forge';
|
|
2
|
-
import {
|
|
9
|
+
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
3
10
|
import type {
|
|
4
11
|
KeepInitialValueOperator,
|
|
5
12
|
Observable,
|
|
6
13
|
SkipIfNoChangeOperatorObservable,
|
|
14
|
+
UpdateToken,
|
|
7
15
|
} from '../types/index.mjs';
|
|
8
16
|
|
|
9
17
|
/**
|
|
@@ -72,7 +80,7 @@ export const skipIfNoChange = <A,>(
|
|
|
72
80
|
): KeepInitialValueOperator<A, A> =>
|
|
73
81
|
// @sumi-expect-error banned-syntax/no-unsafe-type-assertion
|
|
74
82
|
((parentObservable) =>
|
|
75
|
-
|
|
83
|
+
new SkipIfNoChangeObservableClass(
|
|
76
84
|
parentObservable,
|
|
77
85
|
eq,
|
|
78
86
|
)) as KeepInitialValueOperator<A, A>;
|
|
@@ -83,40 +91,46 @@ export const skipIfNoChange = <A,>(
|
|
|
83
91
|
*/
|
|
84
92
|
export const distinctUntilChanged = skipIfNoChange;
|
|
85
93
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
class SkipIfNoChangeObservableClass<A>
|
|
95
|
+
extends SyncChildObservableClass<A, readonly [A]>
|
|
96
|
+
implements SkipIfNoChangeOperatorObservable<A>
|
|
97
|
+
{
|
|
98
|
+
readonly #eq: (x: A, y: A) => boolean;
|
|
99
|
+
#mut_previousValue: Optional<A>;
|
|
100
|
+
|
|
101
|
+
constructor(parentObservable: Observable<A>, eq: (x: A, y: A) => boolean) {
|
|
102
|
+
super({
|
|
92
103
|
parents: [parentObservable],
|
|
93
104
|
initialValue: parentObservable.getSnapshot(),
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// parentObservable.snapshot has value
|
|
108
|
+
// if parentObservable is InitializedObservable
|
|
109
|
+
this.#mut_previousValue = parentObservable.getSnapshot();
|
|
110
|
+
|
|
111
|
+
this.#eq = eq;
|
|
112
|
+
|
|
113
|
+
this.attach();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
override tryUpdate(updateToken: UpdateToken): void {
|
|
117
|
+
const par = this.parents[0];
|
|
99
118
|
|
|
100
|
-
|
|
101
|
-
const sn = parentObservable.getSnapshot();
|
|
119
|
+
const sn = par.getSnapshot();
|
|
102
120
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
) {
|
|
107
|
-
return; // skip update
|
|
108
|
-
}
|
|
121
|
+
if (par.updateToken !== updateToken || Optional.isNone(sn)) {
|
|
122
|
+
return; // skip update
|
|
123
|
+
}
|
|
109
124
|
|
|
110
|
-
|
|
125
|
+
const prev = this.#mut_previousValue;
|
|
111
126
|
|
|
112
|
-
|
|
127
|
+
const cond = Optional.isNone(prev) || !this.#eq(prev.value, sn.value);
|
|
113
128
|
|
|
114
|
-
|
|
115
|
-
|
|
129
|
+
// NOTE: Must update before setNext, otherwise Optional.isNone(prev) remains true when tryUpdate is called consecutively
|
|
130
|
+
this.#mut_previousValue = sn;
|
|
116
131
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
);
|
|
132
|
+
if (cond) {
|
|
133
|
+
this.setNext(sn.value, updateToken);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -1,10 +1,18 @@
|
|
|
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 } from 'ts-data-forge';
|
|
2
|
-
import {
|
|
9
|
+
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
3
10
|
import type {
|
|
4
11
|
DropInitialValueOperator,
|
|
5
12
|
Observable,
|
|
6
13
|
SkipUntilOperatorObservable,
|
|
7
14
|
Subscription,
|
|
15
|
+
UpdateToken,
|
|
8
16
|
} from '../types/index.mjs';
|
|
9
17
|
|
|
10
18
|
/**
|
|
@@ -60,54 +68,60 @@ import type {
|
|
|
60
68
|
export const skipUntil =
|
|
61
69
|
<A,>(notifier: Observable<unknown>): DropInitialValueOperator<A, A> =>
|
|
62
70
|
(parentObservable) =>
|
|
63
|
-
|
|
71
|
+
new SkipUntilObservableClass(parentObservable, notifier);
|
|
64
72
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
let mut_isSkipping =
|
|
72
|
-
Optional.isNone(notifier.getSnapshot()) && !notifier.isCompleted;
|
|
73
|
+
class SkipUntilObservableClass<A>
|
|
74
|
+
extends SyncChildObservableClass<A, readonly [A]>
|
|
75
|
+
implements SkipUntilOperatorObservable<A>
|
|
76
|
+
{
|
|
77
|
+
#mut_isSkipping: boolean;
|
|
78
|
+
#mut_subscription: Subscription | undefined;
|
|
73
79
|
|
|
74
|
-
|
|
80
|
+
constructor(parentObservable: Observable<A>, notifier: Observable<unknown>) {
|
|
81
|
+
super({
|
|
82
|
+
parents: [parentObservable],
|
|
83
|
+
initialValue: Optional.none,
|
|
84
|
+
});
|
|
75
85
|
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
// A notifier that already holds a value, or has completed, would stop
|
|
87
|
+
// the skipping inside `subscribe`, before the subscription is stored.
|
|
88
|
+
this.#mut_isSkipping =
|
|
89
|
+
Optional.isNone(notifier.getSnapshot()) && !notifier.isCompleted;
|
|
78
90
|
|
|
79
|
-
mut_subscription
|
|
91
|
+
this.#mut_subscription = undefined;
|
|
80
92
|
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
if (this.#mut_isSkipping) {
|
|
94
|
+
const stopSkipping = (): void => {
|
|
95
|
+
this.#mut_isSkipping = false;
|
|
83
96
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
onComplete: () => {
|
|
89
|
-
mut_subscription?.unsubscribe();
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
({ setNext }) =>
|
|
93
|
-
(updateToken) => {
|
|
94
|
-
const sn = parentObservable.getSnapshot();
|
|
97
|
+
this.#mut_subscription?.unsubscribe();
|
|
98
|
+
|
|
99
|
+
this.#mut_subscription = undefined;
|
|
100
|
+
};
|
|
95
101
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
parentObservable.updateToken !== updateToken ||
|
|
99
|
-
Optional.isNone(sn)
|
|
100
|
-
) {
|
|
101
|
-
return; // skip update
|
|
102
|
-
}
|
|
102
|
+
this.#mut_subscription = notifier.subscribe(stopSkipping, stopSkipping);
|
|
103
|
+
}
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
this.attach();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
override tryUpdate(updateToken: UpdateToken): void {
|
|
109
|
+
const par = this.parents[0];
|
|
110
|
+
|
|
111
|
+
const sn = par.getSnapshot();
|
|
107
112
|
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
if (
|
|
114
|
+
this.#mut_isSkipping ||
|
|
115
|
+
par.updateToken !== updateToken ||
|
|
116
|
+
Optional.isNone(sn)
|
|
117
|
+
) {
|
|
118
|
+
return; // skip update
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.setNext(sn.value, updateToken);
|
|
110
122
|
}
|
|
111
123
|
|
|
112
|
-
|
|
113
|
-
|
|
124
|
+
protected override teardown(): void {
|
|
125
|
+
this.#mut_subscription?.unsubscribe();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -1,9 +1,17 @@
|
|
|
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, SafeUint, asSafeUint, pipe } from 'ts-data-forge';
|
|
2
|
-
import {
|
|
9
|
+
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
3
10
|
import type {
|
|
4
11
|
DropInitialValueOperator,
|
|
5
12
|
Observable,
|
|
6
13
|
SkipWhileOperatorObservable,
|
|
14
|
+
UpdateToken,
|
|
7
15
|
} from '../types/index.mjs';
|
|
8
16
|
|
|
9
17
|
/**
|
|
@@ -69,46 +77,56 @@ export const skipWhile =
|
|
|
69
77
|
predicate: (value: A, index: SafeUint | -1) => boolean,
|
|
70
78
|
): DropInitialValueOperator<A, A> =>
|
|
71
79
|
(parentObservable) =>
|
|
72
|
-
|
|
80
|
+
new SkipWhileObservableClass(parentObservable, predicate);
|
|
73
81
|
|
|
74
82
|
/* implementation */
|
|
75
83
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
class SkipWhileObservableClass<A>
|
|
85
|
+
extends SyncChildObservableClass<A, readonly [A]>
|
|
86
|
+
implements SkipWhileOperatorObservable<A>
|
|
87
|
+
{
|
|
88
|
+
readonly #predicate: (value: A, index: SafeUint | -1) => boolean;
|
|
89
|
+
#mut_index: SafeUint | -1;
|
|
90
|
+
#mut_isSkipping: boolean;
|
|
91
|
+
|
|
92
|
+
constructor(
|
|
93
|
+
parentObservable: Observable<A>,
|
|
94
|
+
predicate: (value: A, index: SafeUint | -1) => boolean,
|
|
95
|
+
) {
|
|
96
|
+
super({
|
|
82
97
|
parents: [parentObservable],
|
|
83
98
|
initialValue: pipe(parentObservable.getSnapshot()).map((sn) =>
|
|
84
99
|
Optional.isNone(sn) || predicate(sn.value, -1) ? Optional.none : sn,
|
|
85
100
|
).value,
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
this.#mut_index = -1;
|
|
104
|
+
|
|
105
|
+
this.#mut_isSkipping = true;
|
|
106
|
+
|
|
107
|
+
this.#predicate = predicate;
|
|
108
|
+
|
|
109
|
+
this.attach();
|
|
110
|
+
}
|
|
89
111
|
|
|
90
|
-
|
|
112
|
+
override tryUpdate(updateToken: UpdateToken): void {
|
|
113
|
+
const par = this.parents[0];
|
|
91
114
|
|
|
92
|
-
|
|
93
|
-
const sn = parentObservable.getSnapshot();
|
|
115
|
+
const sn = par.getSnapshot();
|
|
94
116
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
) {
|
|
99
|
-
return; // skip update
|
|
100
|
-
}
|
|
117
|
+
if (par.updateToken !== updateToken || Optional.isNone(sn)) {
|
|
118
|
+
return; // skip update
|
|
119
|
+
}
|
|
101
120
|
|
|
102
|
-
|
|
103
|
-
|
|
121
|
+
this.#mut_index =
|
|
122
|
+
this.#mut_index === -1 ? asSafeUint(0) : SafeUint.add(1, this.#mut_index);
|
|
104
123
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
124
|
+
if (!this.#predicate(sn.value, this.#mut_index)) {
|
|
125
|
+
this.#mut_isSkipping = false;
|
|
126
|
+
}
|
|
108
127
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
);
|
|
128
|
+
if (!this.#mut_isSkipping) {
|
|
129
|
+
this.setNext(sn.value, updateToken);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -1,16 +1,31 @@
|
|
|
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 } from 'ts-data-forge';
|
|
2
|
-
import {
|
|
9
|
+
import { AsyncChildObservableClass } from '../class/index.mjs';
|
|
10
|
+
import { createScope, getCurrentScope } from '../scope/index.mjs';
|
|
3
11
|
import type {
|
|
4
12
|
DropInitialValueOperator,
|
|
5
13
|
Observable,
|
|
14
|
+
Scope,
|
|
6
15
|
Subscription,
|
|
7
16
|
SwitchMapOperatorObservable,
|
|
17
|
+
UpdateToken,
|
|
8
18
|
} from '../types/index.mjs';
|
|
9
19
|
|
|
10
20
|
/**
|
|
11
21
|
* Projects each source value to an observable, subscribes to it, and emits its values.
|
|
12
22
|
* When a new value arrives from the source, the previous inner observable is unsubscribed.
|
|
13
23
|
*
|
|
24
|
+
* The projection runs in a scope of its own (see `createScope`): what it
|
|
25
|
+
* creates is disposed when the next value switches away from it and when
|
|
26
|
+
* `switchMap` completes. An observable it only returns — one created outside
|
|
27
|
+
* the projection and shared with others — is unsubscribed and left running.
|
|
28
|
+
*
|
|
14
29
|
* @template A - The type of values from the source
|
|
15
30
|
* @template B - The type of values from the projected observable
|
|
16
31
|
* @param mapToObservable - A function that maps each source value to an observable
|
|
@@ -102,50 +117,74 @@ export const switchMap =
|
|
|
102
117
|
mapToObservable: (curr: A) => Observable<B>,
|
|
103
118
|
): DropInitialValueOperator<A, B> =>
|
|
104
119
|
(parentObservable) =>
|
|
105
|
-
|
|
120
|
+
new SwitchMapObservableClass(parentObservable, mapToObservable);
|
|
121
|
+
|
|
122
|
+
class SwitchMapObservableClass<A, B>
|
|
123
|
+
extends AsyncChildObservableClass<B, readonly [A]>
|
|
124
|
+
implements SwitchMapOperatorObservable<A, B>
|
|
125
|
+
{
|
|
126
|
+
readonly #mapToObservable: (curr: A) => Observable<B>;
|
|
106
127
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
128
|
+
/**
|
|
129
|
+
* The scope the operator was created in, so that each inner scope is
|
|
130
|
+
* disposed with it; the projection itself runs during propagation, when the
|
|
131
|
+
* current scope is whatever happens to be running.
|
|
132
|
+
*/
|
|
133
|
+
readonly #ownerScope: Scope | undefined;
|
|
112
134
|
|
|
113
|
-
|
|
135
|
+
#mut_innerScope: Scope | undefined;
|
|
136
|
+
#mut_subscription: Subscription | undefined;
|
|
114
137
|
|
|
115
|
-
|
|
116
|
-
|
|
138
|
+
constructor(
|
|
139
|
+
parentObservable: Observable<A>,
|
|
140
|
+
mapToObservable: (curr: A) => Observable<B>,
|
|
141
|
+
) {
|
|
142
|
+
super({
|
|
117
143
|
parents: [parentObservable],
|
|
118
144
|
initialValue: Optional.none,
|
|
119
|
-
|
|
120
|
-
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
this.#mapToObservable = mapToObservable;
|
|
148
|
+
|
|
149
|
+
this.#ownerScope = getCurrentScope();
|
|
150
|
+
|
|
151
|
+
this.#mut_innerScope = undefined;
|
|
152
|
+
|
|
153
|
+
this.#mut_subscription = undefined;
|
|
154
|
+
|
|
155
|
+
this.attach();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Releases the inner observable, and only the one this operator made. */
|
|
159
|
+
#releaseInner(): void {
|
|
160
|
+
this.#mut_subscription?.unsubscribe();
|
|
161
|
+
|
|
162
|
+
this.#mut_innerScope?.dispose();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
override tryUpdate(updateToken: UpdateToken): void {
|
|
166
|
+
const par = this.parents[0];
|
|
121
167
|
|
|
122
|
-
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
({ startUpdate }) =>
|
|
126
|
-
(updateToken) => {
|
|
127
|
-
const sn = parentObservable.getSnapshot();
|
|
168
|
+
const sn = par.getSnapshot();
|
|
128
169
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
) {
|
|
133
|
-
return; // skip update
|
|
134
|
-
}
|
|
170
|
+
if (par.updateToken !== updateToken || Optional.isNone(sn)) {
|
|
171
|
+
return; // skip update
|
|
172
|
+
}
|
|
135
173
|
|
|
136
|
-
|
|
174
|
+
this.#releaseInner();
|
|
137
175
|
|
|
138
|
-
|
|
176
|
+
const innerScope = createScope(this.#ownerScope);
|
|
139
177
|
|
|
140
|
-
|
|
178
|
+
this.#mut_innerScope = innerScope;
|
|
141
179
|
|
|
142
|
-
|
|
180
|
+
const observable = innerScope.run(() => this.#mapToObservable(sn.value));
|
|
143
181
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
182
|
+
this.#mut_subscription = observable.subscribe((curr) => {
|
|
183
|
+
this.startUpdate(curr);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
147
186
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
187
|
+
protected override teardown(): void {
|
|
188
|
+
this.#releaseInner();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { toNode } from '../class/index.mjs';
|
|
1
2
|
import { source } from '../create/index.mjs';
|
|
2
|
-
import { take } from '../predefined/index.mjs';
|
|
3
3
|
import { skipUntil } from './skip-until.mjs';
|
|
4
4
|
import { takeUntil } from './take-until.mjs';
|
|
5
|
+
import { take } from './take.mjs';
|
|
5
6
|
|
|
6
7
|
describe('takeUntil releases the notifier', () => {
|
|
7
8
|
test('when the result is completed before the notifier emits', () => {
|
|
@@ -9,11 +10,11 @@ describe('takeUntil releases the notifier', () => {
|
|
|
9
10
|
|
|
10
11
|
const result$ = source<number>().pipe(takeUntil(notifier$));
|
|
11
12
|
|
|
12
|
-
assert.isTrue(notifier
|
|
13
|
+
assert.isTrue(toNode(notifier$).hasSubscriber);
|
|
13
14
|
|
|
14
15
|
result$.complete();
|
|
15
16
|
|
|
16
|
-
assert.isFalse(notifier
|
|
17
|
+
assert.isFalse(toNode(notifier$).hasSubscriber);
|
|
17
18
|
});
|
|
18
19
|
|
|
19
20
|
test('when the parent completes', () => {
|
|
@@ -25,15 +26,17 @@ describe('takeUntil releases the notifier', () => {
|
|
|
25
26
|
|
|
26
27
|
num$.complete();
|
|
27
28
|
|
|
28
|
-
assert.isFalse(notifier
|
|
29
|
+
assert.isFalse(toNode(notifier$).hasSubscriber);
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
test('when the downstream completes', () => {
|
|
32
|
+
test('not when the downstream completes', () => {
|
|
32
33
|
const notifier$ = source<undefined>();
|
|
33
34
|
|
|
34
35
|
const num$ = source<number>();
|
|
35
36
|
|
|
36
|
-
const
|
|
37
|
+
const result$ = num$.pipe(takeUntil(notifier$));
|
|
38
|
+
|
|
39
|
+
const taken$ = result$.pipe(take(1));
|
|
37
40
|
|
|
38
41
|
taken$.subscribe(() => {});
|
|
39
42
|
|
|
@@ -44,7 +47,10 @@ describe('takeUntil releases the notifier', () => {
|
|
|
44
47
|
|
|
45
48
|
assert.isTrue(taken$.isCompleted);
|
|
46
49
|
|
|
47
|
-
|
|
50
|
+
// Completion flows only downstream, so `takeUntil` is still running.
|
|
51
|
+
assert.isFalse(result$.isCompleted);
|
|
52
|
+
|
|
53
|
+
assert.isTrue(toNode(notifier$).hasSubscriber);
|
|
48
54
|
});
|
|
49
55
|
|
|
50
56
|
test('when the notifier emits', () => {
|
|
@@ -56,7 +62,7 @@ describe('takeUntil releases the notifier', () => {
|
|
|
56
62
|
|
|
57
63
|
assert.isTrue(result$.isCompleted);
|
|
58
64
|
|
|
59
|
-
assert.isFalse(notifier
|
|
65
|
+
assert.isFalse(toNode(notifier$).hasSubscriber);
|
|
60
66
|
});
|
|
61
67
|
|
|
62
68
|
test('when the notifier has already emitted', () => {
|
|
@@ -66,7 +72,7 @@ describe('takeUntil releases the notifier', () => {
|
|
|
66
72
|
|
|
67
73
|
assert.isTrue(result$.isCompleted);
|
|
68
74
|
|
|
69
|
-
assert.isFalse(notifier
|
|
75
|
+
assert.isFalse(toNode(notifier$).hasSubscriber);
|
|
70
76
|
});
|
|
71
77
|
});
|
|
72
78
|
|
|
@@ -88,7 +94,7 @@ describe('skipUntil releases the notifier', () => {
|
|
|
88
94
|
|
|
89
95
|
notifier$.next(undefined);
|
|
90
96
|
|
|
91
|
-
assert.isFalse(notifier
|
|
97
|
+
assert.isFalse(toNode(notifier$).hasSubscriber);
|
|
92
98
|
|
|
93
99
|
num$.next(2);
|
|
94
100
|
|
|
@@ -108,7 +114,7 @@ describe('skipUntil releases the notifier', () => {
|
|
|
108
114
|
mut_history.push(x);
|
|
109
115
|
});
|
|
110
116
|
|
|
111
|
-
assert.isFalse(notifier
|
|
117
|
+
assert.isFalse(toNode(notifier$).hasSubscriber);
|
|
112
118
|
|
|
113
119
|
num$.next(1);
|
|
114
120
|
|
|
@@ -122,6 +128,6 @@ describe('skipUntil releases the notifier', () => {
|
|
|
122
128
|
|
|
123
129
|
result$.complete();
|
|
124
130
|
|
|
125
|
-
assert.isFalse(notifier
|
|
131
|
+
assert.isFalse(toNode(notifier$).hasSubscriber);
|
|
126
132
|
});
|
|
127
133
|
});
|