synstate 1.0.2 → 2.0.1
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 +16 -17
- package/dist/core/class/child-observable-class.d.mts.map +1 -1
- package/dist/core/class/child-observable-class.mjs +148 -140
- package/dist/core/class/child-observable-class.mjs.map +1 -1
- package/dist/core/class/observable-base-class.d.mts.map +1 -1
- package/dist/core/class/observable-base-class.mjs +111 -107
- package/dist/core/class/observable-base-class.mjs.map +1 -1
- package/dist/core/class/root-observable-class.d.mts.map +1 -1
- package/dist/core/class/root-observable-class.mjs +32 -24
- package/dist/core/class/root-observable-class.mjs.map +1 -1
- package/dist/core/combine/combine.d.mts +3 -3
- package/dist/core/combine/combine.d.mts.map +1 -1
- package/dist/core/combine/combine.mjs +31 -113
- package/dist/core/combine/combine.mjs.map +1 -1
- package/dist/core/combine/merge.d.mts +2 -2
- package/dist/core/combine/merge.d.mts.map +1 -1
- package/dist/core/combine/merge.mjs +21 -69
- package/dist/core/combine/merge.mjs.map +1 -1
- package/dist/core/combine/zip.d.mts +2 -2
- package/dist/core/combine/zip.d.mts.map +1 -1
- package/dist/core/combine/zip.mjs +34 -79
- package/dist/core/combine/zip.mjs.map +1 -1
- package/dist/core/create/counter.d.mts +1 -1
- package/dist/core/create/counter.d.mts.map +1 -1
- package/dist/core/create/counter.mjs +45 -84
- 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 +29 -61
- 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 +17 -66
- 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 +18 -69
- 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 +5 -35
- package/dist/core/create/just.mjs.map +1 -1
- package/dist/core/create/source.mjs +10 -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 +32 -68
- package/dist/core/create/timer.mjs.map +1 -1
- package/dist/core/operators/audit.d.mts.map +1 -1
- package/dist/core/operators/audit.mjs +39 -133
- package/dist/core/operators/audit.mjs.map +1 -1
- package/dist/core/operators/debounce.d.mts.map +1 -1
- package/dist/core/operators/debounce.mjs +36 -119
- package/dist/core/operators/debounce.mjs.map +1 -1
- package/dist/core/operators/filter.mjs +22 -25
- package/dist/core/operators/filter.mjs.map +1 -1
- package/dist/core/operators/map.d.mts.map +1 -1
- package/dist/core/operators/map.mjs +28 -61
- package/dist/core/operators/map.mjs.map +1 -1
- package/dist/core/operators/merge-map.d.mts +1 -1
- package/dist/core/operators/merge-map.d.mts.map +1 -1
- package/dist/core/operators/merge-map.mjs +34 -130
- package/dist/core/operators/merge-map.mjs.map +1 -1
- package/dist/core/operators/pairwise.d.mts +3 -2
- package/dist/core/operators/pairwise.d.mts.map +1 -1
- package/dist/core/operators/pairwise.mjs +19 -75
- 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 +16 -67
- package/dist/core/operators/scan.mjs.map +1 -1
- package/dist/core/operators/skip-if-no-change.d.mts +1 -1
- package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
- package/dist/core/operators/skip-if-no-change.mjs +28 -92
- 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 +23 -72
- 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 +26 -88
- package/dist/core/operators/skip-while.mjs.map +1 -1
- package/dist/core/operators/switch-map.d.mts.map +1 -1
- package/dist/core/operators/switch-map.mjs +31 -124
- 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 +28 -69
- 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 +23 -83
- package/dist/core/operators/take-while.mjs.map +1 -1
- package/dist/core/operators/throttle.d.mts.map +1 -1
- package/dist/core/operators/throttle.mjs +38 -115
- package/dist/core/operators/throttle.mjs.map +1 -1
- package/dist/core/operators/with-buffered-from.d.mts +1 -1
- package/dist/core/operators/with-buffered-from.d.mts.map +1 -1
- package/dist/core/operators/with-buffered-from.mjs +37 -90
- package/dist/core/operators/with-buffered-from.mjs.map +1 -1
- package/dist/core/operators/with-current-value-from.d.mts +1 -1
- package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
- package/dist/core/operators/with-current-value-from.mjs +23 -84
- 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 +13 -58
- package/dist/core/operators/with-initial-value.mjs.map +1 -1
- package/dist/core/predefined/operators/attach-index.d.mts +1 -1
- package/dist/core/predefined/operators/attach-index.d.mts.map +1 -1
- package/dist/core/predefined/operators/attach-index.mjs +0 -53
- package/dist/core/predefined/operators/attach-index.mjs.map +1 -1
- package/dist/core/predefined/operators/map-optional.d.mts.map +1 -1
- package/dist/core/predefined/operators/map-optional.mjs +1 -48
- package/dist/core/predefined/operators/map-optional.mjs.map +1 -1
- package/dist/core/predefined/operators/map-result-err.d.mts.map +1 -1
- package/dist/core/predefined/operators/map-result-err.mjs +1 -48
- package/dist/core/predefined/operators/map-result-err.mjs.map +1 -1
- package/dist/core/predefined/operators/map-result-ok.d.mts.map +1 -1
- package/dist/core/predefined/operators/map-result-ok.mjs +1 -48
- package/dist/core/predefined/operators/map-result-ok.mjs.map +1 -1
- package/dist/core/predefined/operators/map-to.d.mts.map +1 -1
- package/dist/core/predefined/operators/map-to.mjs +0 -40
- package/dist/core/predefined/operators/map-to.mjs.map +1 -1
- package/dist/core/predefined/operators/pluck.d.mts +1 -1
- package/dist/core/predefined/operators/pluck.d.mts.map +1 -1
- package/dist/core/predefined/operators/pluck.mjs +0 -43
- package/dist/core/predefined/operators/pluck.mjs.map +1 -1
- package/dist/core/predefined/operators/skip.d.mts.map +1 -1
- package/dist/core/predefined/operators/skip.mjs +0 -47
- package/dist/core/predefined/operators/skip.mjs.map +1 -1
- package/dist/core/predefined/operators/take.d.mts.map +1 -1
- package/dist/core/predefined/operators/take.mjs +0 -41
- package/dist/core/predefined/operators/take.mjs.map +1 -1
- package/dist/core/predefined/operators/unwrap-optional.mjs +4 -43
- package/dist/core/predefined/operators/unwrap-optional.mjs.map +1 -1
- package/dist/core/predefined/operators/unwrap-result-err.mjs +0 -40
- package/dist/core/predefined/operators/unwrap-result-err.mjs.map +1 -1
- package/dist/core/predefined/operators/unwrap-result-ok.mjs +4 -43
- package/dist/core/predefined/operators/unwrap-result-ok.mjs.map +1 -1
- package/dist/core/types/observable-family.d.mts +10 -10
- package/dist/core/types/observable-family.d.mts.map +1 -1
- package/dist/core/types/observable.d.mts.map +1 -1
- package/dist/core/types/observable.mjs +3 -5
- package/dist/core/types/observable.mjs.map +1 -1
- package/dist/core/types/types.d.mts +2 -1
- package/dist/core/types/types.d.mts.map +1 -1
- package/dist/core/utils/id-maker.mjs +5 -6
- package/dist/core/utils/id-maker.mjs.map +1 -1
- package/dist/core/utils/max-depth.d.mts.map +1 -1
- package/dist/core/utils/max-depth.mjs +1 -3
- package/dist/core/utils/max-depth.mjs.map +1 -1
- package/dist/core/utils/observable-utils.d.mts.map +1 -1
- package/dist/core/utils/observable-utils.mjs +3 -2
- package/dist/core/utils/observable-utils.mjs.map +1 -1
- package/dist/core/utils/utils.d.mts.map +1 -1
- package/dist/core/utils/utils.mjs +23 -30
- package/dist/core/utils/utils.mjs.map +1 -1
- package/dist/utils/collect-to-array.d.mts.map +1 -1
- package/dist/utils/collect-to-array.mjs +9 -6
- package/dist/utils/collect-to-array.mjs.map +1 -1
- package/dist/utils/create-boolean-state.d.mts +1 -1
- package/dist/utils/create-boolean-state.d.mts.map +1 -1
- package/dist/utils/create-boolean-state.mjs +18 -46
- package/dist/utils/create-boolean-state.mjs.map +1 -1
- package/dist/utils/create-event-emitter.mjs +10 -64
- package/dist/utils/create-event-emitter.mjs.map +1 -1
- package/dist/utils/create-reducer.d.mts +1 -1
- package/dist/utils/create-reducer.d.mts.map +1 -1
- package/dist/utils/create-reducer.mjs +8 -52
- package/dist/utils/create-reducer.mjs.map +1 -1
- package/dist/utils/create-state.d.mts +1 -1
- package/dist/utils/create-state.d.mts.map +1 -1
- package/dist/utils/create-state.mjs +23 -53
- package/dist/utils/create-state.mjs.map +1 -1
- package/package.json +42 -29
- package/src/core/class/child-observable-class.mts +1 -1
- package/src/core/class/observable-base-class.mts +16 -16
- package/src/core/combine/combine.mts +38 -16
- package/src/core/combine/merge.mts +3 -3
- package/src/core/combine/zip.mts +24 -13
- package/src/core/create/counter.mts +11 -9
- package/src/core/create/counter.test.mts +11 -0
- package/src/core/create/timer.mts +6 -6
- package/src/core/create/timer.test.mts +11 -0
- package/src/core/operators/audit-throttle-teardown.test.mts +21 -0
- package/src/core/operators/audit.mts +6 -6
- package/src/core/operators/debounce.mts +6 -6
- package/src/core/operators/pairwise.mts +10 -5
- package/src/core/operators/skip-while.mts +1 -5
- package/src/core/operators/skip-while.test.mts +20 -0
- package/src/core/operators/throttle.mts +6 -6
- package/src/core/operators/with-buffered-from.mts +4 -4
- package/src/core/predefined/operators/map-optional.mts +1 -2
- package/src/core/predefined/operators/map-result-err.mts +1 -1
- package/src/core/predefined/operators/map-result-ok.mts +1 -1
- package/src/core/types/observable-family.mts +12 -11
- package/src/core/types/observable.mts +5 -7
- package/src/core/types/types.mts +2 -1
- package/src/core/utils/max-depth.mts +5 -1
- package/src/core/utils/utils.mts +1 -1
- package/src/utils/create-boolean-state.mts +1 -1
- package/src/utils/create-reducer.mts +1 -1
- package/src/utils/create-state.mts +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Arr,
|
|
2
|
-
import { type
|
|
1
|
+
import { Arr, expectType, Optional } from 'ts-data-forge';
|
|
2
|
+
import { type NonEmptyTuple, type Tuple } from 'ts-type-forge';
|
|
3
3
|
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
4
4
|
import { source } from '../create/index.mjs';
|
|
5
5
|
import { withInitialValue } from '../operators/index.mjs';
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
* ]);
|
|
73
73
|
* ```
|
|
74
74
|
*/
|
|
75
|
-
export const combine = <const OS extends
|
|
75
|
+
export const combine = <const OS extends NonEmptyTuple<Observable<unknown>>>(
|
|
76
76
|
parents: OS,
|
|
77
77
|
): CombineObservableRefined<OS> =>
|
|
78
78
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
@@ -91,35 +91,57 @@ class CombineObservableClass<const A extends NonEmptyUnknownList>
|
|
|
91
91
|
implements CombineObservable<A>
|
|
92
92
|
{
|
|
93
93
|
constructor(parents: Wrap<A>) {
|
|
94
|
-
const parentsValues =
|
|
94
|
+
const parentsValues: Tuple.MapTo<Optional<A[number]>, A> = Arr.map(
|
|
95
|
+
parents,
|
|
96
|
+
(p) => p.getSnapshot(),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// The annotation on `initialValue` is what replaces the type assertion.
|
|
100
|
+
// `Arr.map` carries a single result element type, so it reports `A[number]`
|
|
101
|
+
// at every position, and `Tuple.MapTo<A[number], A>` — the uniform mapping
|
|
102
|
+
// — is *not* assignable back to `A`. The positional
|
|
103
|
+
// `Readonly<{ [K in keyof A]: A[K] }>` is, and TypeScript accepts the
|
|
104
|
+
// uniform result into it because the two mapped types share `keyof A`. So
|
|
105
|
+
// it is the annotation, not an assertion, that records the position-wise
|
|
106
|
+
// fact the checker cannot derive on its own.
|
|
107
|
+
const initialValue: Optional<Readonly<{ [K in keyof A]: A[K] }>> =
|
|
108
|
+
Arr.every(parentsValues, Optional.isSome)
|
|
109
|
+
? Optional.some(Arr.map(parentsValues, (c) => c.value))
|
|
110
|
+
: Optional.none;
|
|
95
111
|
|
|
96
112
|
super({
|
|
97
113
|
parents,
|
|
98
|
-
initialValue
|
|
99
|
-
? Optional.some(
|
|
100
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
101
|
-
Arr.map(parentsValues, (c) => c.value) as A,
|
|
102
|
-
)
|
|
103
|
-
: Optional.none,
|
|
114
|
+
initialValue,
|
|
104
115
|
});
|
|
105
116
|
}
|
|
106
117
|
|
|
107
118
|
override tryUpdate(updateToken: UpdateToken): void {
|
|
108
119
|
if (this.parents.every((o) => o.updateToken !== updateToken)) return; // all parents are skipped
|
|
109
120
|
|
|
110
|
-
|
|
121
|
+
// Same shape-preserving chain as the constructor: `Arr.map` (not the
|
|
122
|
+
// native one, which drops the tuple shape) into the uniform
|
|
123
|
+
// `Tuple.MapTo`, then a positional annotation to get back to `A`.
|
|
124
|
+
const parentValues: Tuple.MapTo<Optional<A[number]>, A> = Arr.map(
|
|
125
|
+
this.parents,
|
|
126
|
+
(a) => a.getSnapshot(),
|
|
127
|
+
);
|
|
111
128
|
|
|
112
|
-
if (
|
|
113
|
-
const nextValue =
|
|
114
|
-
|
|
115
|
-
|
|
129
|
+
if (Arr.every(parentValues, Optional.isSome)) {
|
|
130
|
+
const nextValue: Readonly<{ [K in keyof A]: A[K] }> = Arr.map(
|
|
131
|
+
parentValues,
|
|
132
|
+
(a) => a.value,
|
|
133
|
+
);
|
|
116
134
|
|
|
117
135
|
this.setNext(nextValue, updateToken);
|
|
118
136
|
}
|
|
119
137
|
}
|
|
120
138
|
}
|
|
121
139
|
|
|
122
|
-
{
|
|
140
|
+
if (import.meta.vitest !== undefined) {
|
|
141
|
+
test('type test', () => {
|
|
142
|
+
expect(1).toBe(1); // dummy
|
|
143
|
+
});
|
|
144
|
+
|
|
123
145
|
{
|
|
124
146
|
const s1: Observable<1> = source<1>();
|
|
125
147
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Optional, expectType } from 'ts-data-forge';
|
|
2
|
-
import { type ArrayElement, type
|
|
2
|
+
import { type ArrayElement, type NonEmptyTuple } from 'ts-type-forge';
|
|
3
3
|
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
4
4
|
import { source } from '../create/index.mjs';
|
|
5
5
|
import {
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
* @note To improve code readability, consider using `createState` instead of `merge`,
|
|
64
64
|
* subscribing to `parents` and calling `setState` within it.
|
|
65
65
|
*/
|
|
66
|
-
export const merge = <const OS extends
|
|
66
|
+
export const merge = <const OS extends NonEmptyTuple<Observable<unknown>>>(
|
|
67
67
|
parents: OS,
|
|
68
68
|
): MergeObservableRefined<OS> =>
|
|
69
69
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
@@ -104,7 +104,7 @@ if (import.meta.vitest !== undefined) {
|
|
|
104
104
|
|
|
105
105
|
const r2 = source('a');
|
|
106
106
|
|
|
107
|
-
const _m = merge([r1, r2]
|
|
107
|
+
const _m = merge([r1, r2]);
|
|
108
108
|
|
|
109
109
|
expectType<typeof _m, SyncChildObservable<number | string>>('<=');
|
|
110
110
|
}
|
package/src/core/combine/zip.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Arr, Optional, createQueue, expectType } from 'ts-data-forge';
|
|
2
|
-
import { type
|
|
2
|
+
import { type NonEmptyTuple, type Tuple } from 'ts-type-forge';
|
|
3
3
|
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
4
4
|
import { source } from '../create/index.mjs';
|
|
5
5
|
import { withInitialValue } from '../operators/index.mjs';
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
* ]);
|
|
66
66
|
* ```
|
|
67
67
|
*/
|
|
68
|
-
export const zip = <const OS extends
|
|
68
|
+
export const zip = <const OS extends NonEmptyTuple<Observable<unknown>>>(
|
|
69
69
|
parents: OS,
|
|
70
70
|
): ZipObservableRefined<OS> =>
|
|
71
71
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
@@ -78,21 +78,30 @@ class ZipObservableClass<const A extends NonEmptyUnknownList>
|
|
|
78
78
|
readonly #queues: TupleToQueueTuple<A>;
|
|
79
79
|
|
|
80
80
|
constructor(parents: Wrap<A>) {
|
|
81
|
-
const parentsValues =
|
|
81
|
+
const parentsValues: Tuple.MapTo<Optional<A[number]>, A> = Arr.map(
|
|
82
|
+
parents,
|
|
83
|
+
(p) => p.getSnapshot(),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// The annotation on `initialValue` is what replaces the type assertion.
|
|
87
|
+
// `Arr.map` carries a single result element type, so it reports `A[number]`
|
|
88
|
+
// at every position, and `Tuple.MapTo<A[number], A>` — the uniform mapping
|
|
89
|
+
// — is *not* assignable back to `A`. The positional
|
|
90
|
+
// `Readonly<{ [K in keyof A]: A[K] }>` is, and TypeScript accepts the
|
|
91
|
+
// uniform result into it because the two mapped types share `keyof A`. So
|
|
92
|
+
// it is the annotation, not an assertion, that records the position-wise
|
|
93
|
+
// fact the checker cannot derive on its own.
|
|
94
|
+
const initialValue: Optional<Readonly<{ [K in keyof A]: A[K] }>> =
|
|
95
|
+
Arr.every(parentsValues, Optional.isSome)
|
|
96
|
+
? Optional.some(Arr.map(parentsValues, (c) => c.value))
|
|
97
|
+
: Optional.none;
|
|
82
98
|
|
|
83
99
|
super({
|
|
84
100
|
parents,
|
|
85
|
-
initialValue
|
|
86
|
-
? Optional.some(
|
|
87
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
88
|
-
Arr.map(parentsValues, (c) => c.value) as A,
|
|
89
|
-
)
|
|
90
|
-
: Optional.none,
|
|
101
|
+
initialValue,
|
|
91
102
|
});
|
|
92
103
|
|
|
93
|
-
this.#queues = Arr.map(parents, () =>
|
|
94
|
-
createQueue(),
|
|
95
|
-
) satisfies TupleToQueueTuple<A>;
|
|
104
|
+
this.#queues = Arr.map(parents, () => createQueue());
|
|
96
105
|
}
|
|
97
106
|
|
|
98
107
|
override tryUpdate(updateToken: UpdateToken): void {
|
|
@@ -108,6 +117,8 @@ class ZipObservableClass<const A extends NonEmptyUnknownList>
|
|
|
108
117
|
|
|
109
118
|
if (queues.every((list) => !list.isEmpty)) {
|
|
110
119
|
const nextValue =
|
|
120
|
+
// `Arr.map` has a single result element type, so it reports
|
|
121
|
+
// `A[number] | undefined` per position rather than `A[P]`.
|
|
111
122
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
112
123
|
Arr.map(queues, (q) => Optional.unwrap(q.dequeue())) as A;
|
|
113
124
|
|
|
@@ -160,7 +171,7 @@ if (import.meta.vitest !== undefined) {
|
|
|
160
171
|
|
|
161
172
|
const r2 = source('a');
|
|
162
173
|
|
|
163
|
-
const _z = zip([r1, r2]
|
|
174
|
+
const _z = zip([r1, r2]);
|
|
164
175
|
|
|
165
176
|
const _zi = zip([
|
|
166
177
|
r1.pipe(withInitialValue(0)),
|
|
@@ -36,7 +36,7 @@ import { type CounterObservable, type TimerId } from '../types/index.mjs';
|
|
|
36
36
|
*
|
|
37
37
|
* subscription.unsubscribe();
|
|
38
38
|
*
|
|
39
|
-
* assert.isTrue(Arr.
|
|
39
|
+
* assert.isTrue(Arr.isMinLengthArray(3, valueHistory));
|
|
40
40
|
*
|
|
41
41
|
* assert.deepStrictEqual(valueHistory[0], 0);
|
|
42
42
|
*
|
|
@@ -84,6 +84,16 @@ class CounterObservableClass
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
#resetTimer(): void {
|
|
88
|
+
if (this.#mut_timerId0 === undefined || this.#mut_timerId === undefined) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
clearInterval(this.#mut_timerId0);
|
|
93
|
+
|
|
94
|
+
clearInterval(this.#mut_timerId);
|
|
95
|
+
}
|
|
96
|
+
|
|
87
97
|
start(): void {
|
|
88
98
|
if (this.#mut_isStarted) {
|
|
89
99
|
console.warn('cannot start twice');
|
|
@@ -110,14 +120,6 @@ class CounterObservableClass
|
|
|
110
120
|
}, this.#intervalMilliSeconds);
|
|
111
121
|
}
|
|
112
122
|
|
|
113
|
-
#resetTimer(): void {
|
|
114
|
-
if (this.#mut_timerId0 !== undefined && this.#mut_timerId !== undefined) {
|
|
115
|
-
clearInterval(this.#mut_timerId0);
|
|
116
|
-
|
|
117
|
-
clearInterval(this.#mut_timerId);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
123
|
override complete(): void {
|
|
122
124
|
this.#resetTimer();
|
|
123
125
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { counter } from './counter.mjs';
|
|
2
|
+
|
|
3
|
+
describe(counter, () => {
|
|
4
|
+
test('completing before start() tears down without touching the timers', () => {
|
|
5
|
+
const counter$ = counter(10, { startManually: true });
|
|
6
|
+
|
|
7
|
+
counter$.complete();
|
|
8
|
+
|
|
9
|
+
assert.isTrue(counter$.isCompleted);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -68,6 +68,12 @@ class TimerObservableClass
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
#resetTimer(): void {
|
|
72
|
+
if (this.#mut_timerId !== undefined) {
|
|
73
|
+
clearTimeout(this.#mut_timerId);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
71
77
|
start(): void {
|
|
72
78
|
if (this.#mut_isStarted) {
|
|
73
79
|
console.warn('cannot start twice');
|
|
@@ -90,12 +96,6 @@ class TimerObservableClass
|
|
|
90
96
|
}, this.#milliSeconds);
|
|
91
97
|
}
|
|
92
98
|
|
|
93
|
-
#resetTimer(): void {
|
|
94
|
-
if (this.#mut_timerId !== undefined) {
|
|
95
|
-
clearTimeout(this.#mut_timerId);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
99
|
override complete(): void {
|
|
100
100
|
this.#resetTimer();
|
|
101
101
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { timer } from './timer.mjs';
|
|
2
|
+
|
|
3
|
+
describe(timer, () => {
|
|
4
|
+
test('completing before start() tears down without touching the timer', () => {
|
|
5
|
+
const timer$ = timer(10, { startManually: true });
|
|
6
|
+
|
|
7
|
+
timer$.complete();
|
|
8
|
+
|
|
9
|
+
assert.isTrue(timer$.isCompleted);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { source } from '../create/index.mjs';
|
|
2
|
+
import { audit } from './audit.mjs';
|
|
3
|
+
import { throttle } from './throttle.mjs';
|
|
4
|
+
|
|
5
|
+
describe('completing before any emission', () => {
|
|
6
|
+
test('audit tears down without a pending timer', () => {
|
|
7
|
+
const audited$ = source<number>().pipe(audit(10));
|
|
8
|
+
|
|
9
|
+
audited$.complete();
|
|
10
|
+
|
|
11
|
+
assert.isTrue(audited$.isCompleted);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('throttle tears down without a pending timer', () => {
|
|
15
|
+
const throttled$ = source<number>().pipe(throttle(10));
|
|
16
|
+
|
|
17
|
+
throttled$.complete();
|
|
18
|
+
|
|
19
|
+
assert.isTrue(throttled$.isCompleted);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -133,6 +133,12 @@ class AuditObservableClass<A>
|
|
|
133
133
|
this.#milliSeconds = milliSeconds;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
#resetTimer(): void {
|
|
137
|
+
if (this.#mut_timerId !== undefined) {
|
|
138
|
+
clearTimeout(this.#mut_timerId);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
136
142
|
override tryUpdate(updateToken: UpdateToken): void {
|
|
137
143
|
const par = this.parents[0];
|
|
138
144
|
|
|
@@ -158,12 +164,6 @@ class AuditObservableClass<A>
|
|
|
158
164
|
}, this.#milliSeconds);
|
|
159
165
|
}
|
|
160
166
|
|
|
161
|
-
#resetTimer(): void {
|
|
162
|
-
if (this.#mut_timerId !== undefined) {
|
|
163
|
-
clearTimeout(this.#mut_timerId);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
167
|
override complete(): void {
|
|
168
168
|
this.#resetTimer();
|
|
169
169
|
|
|
@@ -121,6 +121,12 @@ class DebounceObservableClass<A>
|
|
|
121
121
|
this.#milliSeconds = milliSeconds;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
#resetTimer(): void {
|
|
125
|
+
if (this.#mut_timerId !== undefined) {
|
|
126
|
+
clearTimeout(this.#mut_timerId);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
124
130
|
override tryUpdate(updateToken: UpdateToken): void {
|
|
125
131
|
const par = this.parents[0];
|
|
126
132
|
|
|
@@ -140,12 +146,6 @@ class DebounceObservableClass<A>
|
|
|
140
146
|
}, this.#milliSeconds);
|
|
141
147
|
}
|
|
142
148
|
|
|
143
|
-
#resetTimer(): void {
|
|
144
|
-
if (this.#mut_timerId !== undefined) {
|
|
145
|
-
clearTimeout(this.#mut_timerId);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
149
|
override complete(): void {
|
|
150
150
|
this.#resetTimer();
|
|
151
151
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Optional } from 'ts-data-forge';
|
|
2
|
+
import { type FixedLengthTuple } from 'ts-type-forge';
|
|
2
3
|
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
3
4
|
import {
|
|
4
5
|
type DropInitialValueOperator,
|
|
@@ -30,7 +31,7 @@ import {
|
|
|
30
31
|
*
|
|
31
32
|
* const pairs$ = num$.pipe(pairwise());
|
|
32
33
|
*
|
|
33
|
-
* const valueHistory:
|
|
34
|
+
* const valueHistory: FixedLengthTuple<2, number>[] = [];
|
|
34
35
|
*
|
|
35
36
|
* pairs$.subscribe(([prev, curr]) => {
|
|
36
37
|
* valueHistory.push([prev, curr]);
|
|
@@ -60,14 +61,18 @@ import {
|
|
|
60
61
|
* ]);
|
|
61
62
|
* ```
|
|
62
63
|
*/
|
|
63
|
-
export const pairwise = <A,>(): DropInitialValueOperator<
|
|
64
|
-
|
|
64
|
+
export const pairwise = <A,>(): DropInitialValueOperator<
|
|
65
|
+
A,
|
|
66
|
+
FixedLengthTuple<2, A>
|
|
67
|
+
> => f;
|
|
65
68
|
|
|
66
|
-
const f = <A,>(
|
|
69
|
+
const f = <A,>(
|
|
70
|
+
parentObservable: Observable<A>,
|
|
71
|
+
): Observable<FixedLengthTuple<2, A>> =>
|
|
67
72
|
new PairwiseObservableClass(parentObservable);
|
|
68
73
|
|
|
69
74
|
class PairwiseObservableClass<A>
|
|
70
|
-
extends SyncChildObservableClass<
|
|
75
|
+
extends SyncChildObservableClass<FixedLengthTuple<2, A>, readonly [A]>
|
|
71
76
|
implements PairwiseOperatorObservable<A>
|
|
72
77
|
{
|
|
73
78
|
#mut_previousValue: Optional<A>;
|
|
@@ -89,11 +89,7 @@ class SkipWhileObservableClass<A>
|
|
|
89
89
|
super({
|
|
90
90
|
parents: [parentObservable],
|
|
91
91
|
initialValue: pipe(parentObservable.getSnapshot()).map((sn) =>
|
|
92
|
-
Optional.isNone(sn)
|
|
93
|
-
? Optional.none
|
|
94
|
-
: predicate(sn.value, -1)
|
|
95
|
-
? Optional.none
|
|
96
|
-
: sn,
|
|
92
|
+
Optional.isNone(sn) || predicate(sn.value, -1) ? Optional.none : sn,
|
|
97
93
|
).value,
|
|
98
94
|
});
|
|
99
95
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Optional } from 'ts-data-forge';
|
|
2
|
+
import { just } from '../create/index.mjs';
|
|
3
|
+
import { skipWhile } from './skip-while.mjs';
|
|
4
|
+
|
|
5
|
+
describe(skipWhile, () => {
|
|
6
|
+
// Widened so the predicate is not statically decidable.
|
|
7
|
+
const seed: number = 1;
|
|
8
|
+
|
|
9
|
+
test('keeps an initialized parent value the predicate does not skip', () => {
|
|
10
|
+
const kept$ = just(seed).pipe(skipWhile((x) => x > 10));
|
|
11
|
+
|
|
12
|
+
expect(Optional.unwrapOr(kept$.getSnapshot(), -1)).toBe(1);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('drops an initialized parent value the predicate skips', () => {
|
|
16
|
+
const dropped$ = just(seed).pipe(skipWhile((x) => x < 10));
|
|
17
|
+
|
|
18
|
+
assert.isTrue(Optional.isNone(dropped$.getSnapshot()));
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -117,6 +117,12 @@ class ThrottleObservableClass<A>
|
|
|
117
117
|
this.#milliSeconds = milliSeconds;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
#resetTimer(): void {
|
|
121
|
+
if (this.#mut_timerId !== undefined) {
|
|
122
|
+
clearTimeout(this.#mut_timerId);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
120
126
|
override tryUpdate(updateToken: UpdateToken): void {
|
|
121
127
|
const par = this.parents[0];
|
|
122
128
|
|
|
@@ -140,12 +146,6 @@ class ThrottleObservableClass<A>
|
|
|
140
146
|
}, this.#milliSeconds);
|
|
141
147
|
}
|
|
142
148
|
|
|
143
|
-
#resetTimer(): void {
|
|
144
|
-
if (this.#mut_timerId !== undefined) {
|
|
145
|
-
clearTimeout(this.#mut_timerId);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
149
|
override complete(): void {
|
|
150
150
|
this.#resetTimer();
|
|
151
151
|
|
|
@@ -105,6 +105,10 @@ class WithBufferedFromObservableClass<A, B>
|
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
#clearBuffer(): void {
|
|
109
|
+
this.#mut_bufferedValues = [];
|
|
110
|
+
}
|
|
111
|
+
|
|
108
112
|
override tryUpdate(updateToken: UpdateToken): void {
|
|
109
113
|
const par = this.parents[0];
|
|
110
114
|
|
|
@@ -118,8 +122,4 @@ class WithBufferedFromObservableClass<A, B>
|
|
|
118
122
|
|
|
119
123
|
this.#clearBuffer();
|
|
120
124
|
}
|
|
121
|
-
|
|
122
|
-
#clearBuffer(): void {
|
|
123
|
-
this.#mut_bufferedValues = [];
|
|
124
|
-
}
|
|
125
125
|
}
|
|
@@ -51,5 +51,4 @@ import { type KeepInitialValueOperator } from '../../types/index.mjs';
|
|
|
51
51
|
*/
|
|
52
52
|
export const mapOptional = <O extends UnknownOptional, B>(
|
|
53
53
|
mapFn: (x: Optional.Unwrap<O>) => B,
|
|
54
|
-
): KeepInitialValueOperator<O, Optional<B>> =>
|
|
55
|
-
map((a) => Optional.map(a, mapFn));
|
|
54
|
+
): KeepInitialValueOperator<O, Optional<B>> => map(Optional.map(mapFn));
|
|
@@ -52,4 +52,4 @@ import { type KeepInitialValueOperator } from '../../types/index.mjs';
|
|
|
52
52
|
export const mapResultErr = <R extends UnknownResult, E2>(
|
|
53
53
|
mapFn: (x: Result.UnwrapErr<R>) => E2,
|
|
54
54
|
): KeepInitialValueOperator<R, Result<Result.UnwrapOk<R>, E2>> =>
|
|
55
|
-
map(
|
|
55
|
+
map(Result.mapErr(mapFn));
|
|
@@ -52,4 +52,4 @@ import { type KeepInitialValueOperator } from '../../types/index.mjs';
|
|
|
52
52
|
export const mapResultOk = <R extends UnknownResult, S2>(
|
|
53
53
|
mapFn: (x: Result.UnwrapOk<R>) => S2,
|
|
54
54
|
): KeepInitialValueOperator<R, Result<S2, Result.UnwrapErr<R>>> =>
|
|
55
|
-
map(
|
|
55
|
+
map(Result.map(mapFn));
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { expectType, type Result } from 'ts-data-forge';
|
|
2
2
|
import {
|
|
3
3
|
type ArrayElement,
|
|
4
|
-
type
|
|
4
|
+
type FixedLengthTuple,
|
|
5
|
+
type NonEmptyTuple,
|
|
5
6
|
type SafeUint,
|
|
6
7
|
} from 'ts-type-forge';
|
|
7
8
|
import {
|
|
@@ -63,8 +64,8 @@ export type ScanOperatorObservable<A, B> = InitializedSyncChildObservable<
|
|
|
63
64
|
namespace SynStateInternals {
|
|
64
65
|
type Cast<A> = A extends NonEmptyUnknownList ? A : never;
|
|
65
66
|
|
|
66
|
-
type EveryInitialized<OS extends
|
|
67
|
-
OS extends
|
|
67
|
+
type EveryInitialized<OS extends NonEmptyTuple<Observable<unknown>>> =
|
|
68
|
+
OS extends NonEmptyTuple<InitializedObservable<unknown>> ? true : false;
|
|
68
69
|
|
|
69
70
|
type IsInitialized<O> = readonly [O] extends readonly [
|
|
70
71
|
InitializedObservable<unknown>,
|
|
@@ -83,7 +84,7 @@ namespace SynStateInternals {
|
|
|
83
84
|
// union distribution
|
|
84
85
|
LogicalValue<OS extends OS ? IsInitialized<OS> : never>;
|
|
85
86
|
|
|
86
|
-
type SomeInitialized<OS extends
|
|
87
|
+
type SomeInitialized<OS extends NonEmptyTuple<Observable<unknown>>> =
|
|
87
88
|
SomeInitializedImpl<OS[number]>;
|
|
88
89
|
|
|
89
90
|
expectType<EveryInitialized<readonly [Observable<1>]>, false>('=');
|
|
@@ -125,7 +126,7 @@ namespace SynStateInternals {
|
|
|
125
126
|
SyncChildObservable<A, A>;
|
|
126
127
|
|
|
127
128
|
export type CombineObservableRefinedImpl<
|
|
128
|
-
OS extends
|
|
129
|
+
OS extends NonEmptyTuple<Observable<unknown>>,
|
|
129
130
|
> =
|
|
130
131
|
EveryInitialized<OS> extends true
|
|
131
132
|
? InitializedCombineObservableImpl<Cast<Unwrap<OS>>>
|
|
@@ -138,7 +139,7 @@ namespace SynStateInternals {
|
|
|
138
139
|
SyncChildObservable<A, A>;
|
|
139
140
|
|
|
140
141
|
export type ZipObservableRefinedImpl<
|
|
141
|
-
OS extends
|
|
142
|
+
OS extends NonEmptyTuple<Observable<unknown>>,
|
|
142
143
|
> =
|
|
143
144
|
EveryInitialized<OS> extends true
|
|
144
145
|
? InitializedZipObservableImpl<Cast<Unwrap<OS>>>
|
|
@@ -151,7 +152,7 @@ namespace SynStateInternals {
|
|
|
151
152
|
SyncChildObservable<ArrayElement<P>, P>;
|
|
152
153
|
|
|
153
154
|
export type MergeObservableRefinedImpl<
|
|
154
|
-
OS extends
|
|
155
|
+
OS extends NonEmptyTuple<Observable<unknown>>,
|
|
155
156
|
> =
|
|
156
157
|
SomeInitialized<OS> extends true
|
|
157
158
|
? InitializedMergeObservableImpl<Cast<Unwrap<OS>>>
|
|
@@ -162,27 +163,27 @@ export type CombineObservable<A extends NonEmptyUnknownList> =
|
|
|
162
163
|
SynStateInternals.CombineObservableImpl<A>;
|
|
163
164
|
|
|
164
165
|
export type CombineObservableRefined<
|
|
165
|
-
OS extends
|
|
166
|
+
OS extends NonEmptyTuple<Observable<unknown>>,
|
|
166
167
|
> = SynStateInternals.CombineObservableRefinedImpl<OS>;
|
|
167
168
|
|
|
168
169
|
export type ZipObservable<A extends NonEmptyUnknownList> =
|
|
169
170
|
SynStateInternals.ZipObservableImpl<A>;
|
|
170
171
|
|
|
171
172
|
export type ZipObservableRefined<
|
|
172
|
-
OS extends
|
|
173
|
+
OS extends NonEmptyTuple<Observable<unknown>>,
|
|
173
174
|
> = SynStateInternals.ZipObservableRefinedImpl<OS>;
|
|
174
175
|
|
|
175
176
|
export type MergeObservable<A extends NonEmptyUnknownList> =
|
|
176
177
|
SynStateInternals.MergeObservableImpl<A>;
|
|
177
178
|
|
|
178
179
|
export type MergeObservableRefined<
|
|
179
|
-
OS extends
|
|
180
|
+
OS extends NonEmptyTuple<Observable<unknown>>,
|
|
180
181
|
> = SynStateInternals.MergeObservableRefinedImpl<OS>;
|
|
181
182
|
|
|
182
183
|
export type MapOperatorObservable<A, B> = SyncChildObservable<B, readonly [A]>;
|
|
183
184
|
|
|
184
185
|
export type PairwiseOperatorObservable<A> = SyncChildObservable<
|
|
185
|
-
|
|
186
|
+
FixedLengthTuple<2, A>,
|
|
186
187
|
readonly [A]
|
|
187
188
|
>;
|
|
188
189
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expectType, type Optional, type Some } from 'ts-data-forge';
|
|
2
|
-
import { type StrictOmit } from 'ts-type-forge';
|
|
2
|
+
import { type FixedLengthTuple, type StrictOmit } from 'ts-type-forge';
|
|
3
3
|
import { type ObservableId, type UpdateToken } from './id.mjs';
|
|
4
4
|
import { type ObservableKind } from './observable-kind.mjs';
|
|
5
5
|
import { type NonEmptyUnknownList, type Subscription } from './types.mjs';
|
|
@@ -128,9 +128,7 @@ export type InitializedRootObservable<A> =
|
|
|
128
128
|
ObservableTypeConverter.ToInitialized<A, RootObservable<A>>;
|
|
129
129
|
|
|
130
130
|
export type Observable<A> =
|
|
131
|
-
|
|
|
132
|
-
| RootObservable<A>
|
|
133
|
-
| SyncChildObservable<A>;
|
|
131
|
+
AsyncChildObservable<A> | RootObservable<A> | SyncChildObservable<A>;
|
|
134
132
|
|
|
135
133
|
export type InitializedObservable<A> =
|
|
136
134
|
| InitializedAsyncChildObservable<A>
|
|
@@ -209,11 +207,11 @@ expectType<
|
|
|
209
207
|
expectType<number, ObservableValue<Observable<string>>>('!<=');
|
|
210
208
|
|
|
211
209
|
expectType<
|
|
212
|
-
|
|
213
|
-
Wrap<
|
|
210
|
+
FixedLengthTuple<2, Observable<number>>,
|
|
211
|
+
Wrap<FixedLengthTuple<2, number>>
|
|
214
212
|
>('<=');
|
|
215
213
|
|
|
216
214
|
expectType<
|
|
217
215
|
readonly [Observable<number>, Observable<string>],
|
|
218
|
-
Wrap<
|
|
216
|
+
Wrap<FixedLengthTuple<2, number>>
|
|
219
217
|
>('!<=');
|
package/src/core/types/types.mts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { expectType, type Queue } from 'ts-data-forge';
|
|
2
|
+
import { type NonEmptyTuple } from 'ts-type-forge';
|
|
2
3
|
|
|
3
4
|
export type TupleToQueueTuple<T extends readonly unknown[]> = Readonly<{
|
|
4
5
|
[P in keyof T]: Queue<T[P]>;
|
|
5
6
|
}>;
|
|
6
7
|
|
|
7
|
-
export type NonEmptyUnknownList =
|
|
8
|
+
export type NonEmptyUnknownList = NonEmptyTuple<unknown>;
|
|
8
9
|
|
|
9
10
|
export type Subscriber<A> = Readonly<{
|
|
10
11
|
onNext: (v: A) => void;
|
|
@@ -3,5 +3,9 @@ import { type Observable } from '../types/index.mjs';
|
|
|
3
3
|
|
|
4
4
|
export const maxDepth = (parents: readonly Observable<unknown>[]): number =>
|
|
5
5
|
pipe(Arr.maxBy(parents, (p) => p.depth))
|
|
6
|
-
.
|
|
6
|
+
// Explicit return type + non-curried `Optional.unwrapOr` call: TypeScript
|
|
7
|
+
// 7 (native)'s inference for this chained generic call resolves to
|
|
8
|
+
// `unknown` without them, even though TypeScript <= 6.0's checker
|
|
9
|
+
// resolves this fine.
|
|
10
|
+
.mapOptional((o): number => o.depth)
|
|
7
11
|
.map(Optional.unwrapOr(0)).value;
|
package/src/core/utils/utils.mts
CHANGED