synstate 0.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 +878 -0
- package/dist/core/class/child-observable-class.d.mts +37 -0
- package/dist/core/class/child-observable-class.d.mts.map +1 -0
- package/dist/core/class/child-observable-class.mjs +134 -0
- package/dist/core/class/child-observable-class.mjs.map +1 -0
- package/dist/core/class/index.d.mts +4 -0
- package/dist/core/class/index.d.mts.map +1 -0
- package/dist/core/class/index.mjs +4 -0
- package/dist/core/class/index.mjs.map +1 -0
- package/dist/core/class/observable-base-class.d.mts +28 -0
- package/dist/core/class/observable-base-class.d.mts.map +1 -0
- package/dist/core/class/observable-base-class.mjs +116 -0
- package/dist/core/class/observable-base-class.mjs.map +1 -0
- package/dist/core/class/root-observable-class.d.mts +12 -0
- package/dist/core/class/root-observable-class.d.mts.map +1 -0
- package/dist/core/class/root-observable-class.mjs +35 -0
- package/dist/core/class/root-observable-class.mjs.map +1 -0
- package/dist/core/combine/combine.d.mts +35 -0
- package/dist/core/combine/combine.d.mts.map +1 -0
- package/dist/core/combine/combine.mjs +94 -0
- package/dist/core/combine/combine.mjs.map +1 -0
- package/dist/core/combine/index.d.mts +4 -0
- package/dist/core/combine/index.d.mts.map +1 -0
- package/dist/core/combine/index.mjs +4 -0
- package/dist/core/combine/index.mjs.map +1 -0
- package/dist/core/combine/merge.d.mts +28 -0
- package/dist/core/combine/merge.d.mts.map +1 -0
- package/dist/core/combine/merge.mjs +52 -0
- package/dist/core/combine/merge.mjs.map +1 -0
- package/dist/core/combine/zip.d.mts +26 -0
- package/dist/core/combine/zip.d.mts.map +1 -0
- package/dist/core/combine/zip.mjs +63 -0
- package/dist/core/combine/zip.mjs.map +1 -0
- package/dist/core/create/from-array.d.mts +21 -0
- package/dist/core/create/from-array.d.mts.map +1 -0
- package/dist/core/create/from-array.mjs +47 -0
- package/dist/core/create/from-array.mjs.map +1 -0
- package/dist/core/create/from-promise.d.mts +25 -0
- package/dist/core/create/from-promise.d.mts.map +1 -0
- package/dist/core/create/from-promise.mjs +51 -0
- package/dist/core/create/from-promise.mjs.map +1 -0
- package/dist/core/create/from-subscribable.d.mts +3 -0
- package/dist/core/create/from-subscribable.d.mts.map +1 -0
- package/dist/core/create/from-subscribable.mjs +22 -0
- package/dist/core/create/from-subscribable.mjs.map +1 -0
- package/dist/core/create/index.d.mts +8 -0
- package/dist/core/create/index.d.mts.map +1 -0
- package/dist/core/create/index.mjs +8 -0
- package/dist/core/create/index.mjs.map +1 -0
- package/dist/core/create/interval.d.mts +21 -0
- package/dist/core/create/interval.d.mts.map +1 -0
- package/dist/core/create/interval.mjs +74 -0
- package/dist/core/create/interval.mjs.map +1 -0
- package/dist/core/create/of.d.mts +20 -0
- package/dist/core/create/of.d.mts.map +1 -0
- package/dist/core/create/of.mjs +44 -0
- package/dist/core/create/of.mjs.map +1 -0
- package/dist/core/create/source.d.mts +29 -0
- package/dist/core/create/source.d.mts.map +1 -0
- package/dist/core/create/source.mjs +29 -0
- package/dist/core/create/source.mjs.map +1 -0
- package/dist/core/create/timer.d.mts +20 -0
- package/dist/core/create/timer.d.mts.map +1 -0
- package/dist/core/create/timer.mjs +64 -0
- package/dist/core/create/timer.mjs.map +1 -0
- package/dist/core/index.d.mts +7 -0
- package/dist/core/index.d.mts.map +1 -0
- package/dist/core/index.mjs +37 -0
- package/dist/core/index.mjs.map +1 -0
- package/dist/core/operators/audit-time.d.mts +3 -0
- package/dist/core/operators/audit-time.d.mts.map +1 -0
- package/dist/core/operators/audit-time.mjs +50 -0
- package/dist/core/operators/audit-time.mjs.map +1 -0
- package/dist/core/operators/debounce-time.d.mts +31 -0
- package/dist/core/operators/debounce-time.d.mts.map +1 -0
- package/dist/core/operators/debounce-time.mjs +73 -0
- package/dist/core/operators/debounce-time.mjs.map +1 -0
- package/dist/core/operators/filter.d.mts +28 -0
- package/dist/core/operators/filter.d.mts.map +1 -0
- package/dist/core/operators/filter.mjs +38 -0
- package/dist/core/operators/filter.mjs.map +1 -0
- package/dist/core/operators/index.d.mts +18 -0
- package/dist/core/operators/index.d.mts.map +1 -0
- package/dist/core/operators/index.mjs +18 -0
- package/dist/core/operators/index.mjs.map +1 -0
- package/dist/core/operators/map-with-index.d.mts +39 -0
- package/dist/core/operators/map-with-index.d.mts.map +1 -0
- package/dist/core/operators/map-with-index.mjs +73 -0
- package/dist/core/operators/map-with-index.mjs.map +1 -0
- package/dist/core/operators/merge-map.d.mts +34 -0
- package/dist/core/operators/merge-map.d.mts.map +1 -0
- package/dist/core/operators/merge-map.mjs +75 -0
- package/dist/core/operators/merge-map.mjs.map +1 -0
- package/dist/core/operators/pairwise.d.mts +27 -0
- package/dist/core/operators/pairwise.d.mts.map +1 -0
- package/dist/core/operators/pairwise.mjs +59 -0
- package/dist/core/operators/pairwise.mjs.map +1 -0
- package/dist/core/operators/scan.d.mts +30 -0
- package/dist/core/operators/scan.d.mts.map +1 -0
- package/dist/core/operators/scan.mjs +56 -0
- package/dist/core/operators/scan.mjs.map +1 -0
- package/dist/core/operators/skip-if-no-change.d.mts +33 -0
- package/dist/core/operators/skip-if-no-change.d.mts.map +1 -0
- package/dist/core/operators/skip-if-no-change.mjs +68 -0
- package/dist/core/operators/skip-if-no-change.mjs.map +1 -0
- package/dist/core/operators/skip-until.d.mts +3 -0
- package/dist/core/operators/skip-until.d.mts.map +1 -0
- package/dist/core/operators/skip-until.mjs +33 -0
- package/dist/core/operators/skip-until.mjs.map +1 -0
- package/dist/core/operators/skip-while.d.mts +4 -0
- package/dist/core/operators/skip-while.d.mts.map +1 -0
- package/dist/core/operators/skip-while.mjs +40 -0
- package/dist/core/operators/skip-while.mjs.map +1 -0
- package/dist/core/operators/switch-map.d.mts +31 -0
- package/dist/core/operators/switch-map.d.mts.map +1 -0
- package/dist/core/operators/switch-map.mjs +70 -0
- package/dist/core/operators/switch-map.mjs.map +1 -0
- package/dist/core/operators/take-until.d.mts +32 -0
- package/dist/core/operators/take-until.d.mts.map +1 -0
- package/dist/core/operators/take-until.mjs +60 -0
- package/dist/core/operators/take-until.mjs.map +1 -0
- package/dist/core/operators/take-while.d.mts +4 -0
- package/dist/core/operators/take-while.d.mts.map +1 -0
- package/dist/core/operators/take-while.mjs +42 -0
- package/dist/core/operators/take-while.mjs.map +1 -0
- package/dist/core/operators/throttle-time.d.mts +23 -0
- package/dist/core/operators/throttle-time.d.mts.map +1 -0
- package/dist/core/operators/throttle-time.mjs +68 -0
- package/dist/core/operators/throttle-time.mjs.map +1 -0
- package/dist/core/operators/with-buffered-from.d.mts +4 -0
- package/dist/core/operators/with-buffered-from.d.mts.map +1 -0
- package/dist/core/operators/with-buffered-from.mjs +45 -0
- package/dist/core/operators/with-buffered-from.mjs.map +1 -0
- package/dist/core/operators/with-current-value-from.d.mts +4 -0
- package/dist/core/operators/with-current-value-from.d.mts.map +1 -0
- package/dist/core/operators/with-current-value-from.mjs +37 -0
- package/dist/core/operators/with-current-value-from.mjs.map +1 -0
- package/dist/core/operators/with-initial-value.d.mts +26 -0
- package/dist/core/operators/with-initial-value.d.mts.map +1 -0
- package/dist/core/operators/with-initial-value.mjs +47 -0
- package/dist/core/operators/with-initial-value.mjs.map +1 -0
- package/dist/core/types/id.d.mts +4 -0
- package/dist/core/types/id.d.mts.map +1 -0
- package/dist/core/types/id.mjs +2 -0
- package/dist/core/types/id.mjs.map +1 -0
- package/dist/core/types/index.d.mts +6 -0
- package/dist/core/types/index.d.mts.map +1 -0
- package/dist/core/types/index.mjs +3 -0
- package/dist/core/types/index.mjs.map +1 -0
- package/dist/core/types/observable-family.d.mts +68 -0
- package/dist/core/types/observable-family.d.mts.map +1 -0
- package/dist/core/types/observable-family.mjs +2 -0
- package/dist/core/types/observable-family.mjs.map +1 -0
- package/dist/core/types/observable-kind.d.mts +4 -0
- package/dist/core/types/observable-kind.d.mts.map +1 -0
- package/dist/core/types/observable-kind.mjs +2 -0
- package/dist/core/types/observable-kind.mjs.map +1 -0
- package/dist/core/types/observable.d.mts +83 -0
- package/dist/core/types/observable.d.mts.map +1 -0
- package/dist/core/types/observable.mjs +10 -0
- package/dist/core/types/observable.mjs.map +1 -0
- package/dist/core/types/types.d.mts +16 -0
- package/dist/core/types/types.d.mts.map +1 -0
- package/dist/core/types/types.mjs +2 -0
- package/dist/core/types/types.mjs.map +1 -0
- package/dist/core/utils/id-maker.d.mts +5 -0
- package/dist/core/utils/id-maker.d.mts.map +1 -0
- package/dist/core/utils/id-maker.mjs +17 -0
- package/dist/core/utils/id-maker.mjs.map +1 -0
- package/dist/core/utils/index.d.mts +5 -0
- package/dist/core/utils/index.d.mts.map +1 -0
- package/dist/core/utils/index.mjs +5 -0
- package/dist/core/utils/index.mjs.map +1 -0
- package/dist/core/utils/max-depth.d.mts +3 -0
- package/dist/core/utils/max-depth.d.mts.map +1 -0
- package/dist/core/utils/max-depth.mjs +8 -0
- package/dist/core/utils/max-depth.mjs.map +1 -0
- package/dist/core/utils/observable-utils.d.mts +3 -0
- package/dist/core/utils/observable-utils.d.mts.map +1 -0
- package/dist/core/utils/observable-utils.mjs +7 -0
- package/dist/core/utils/observable-utils.mjs.map +1 -0
- package/dist/core/utils/utils.d.mts +4 -0
- package/dist/core/utils/utils.d.mts.map +1 -0
- package/dist/core/utils/utils.mjs +38 -0
- package/dist/core/utils/utils.mjs.map +1 -0
- package/dist/entry-point.d.mts +2 -0
- package/dist/entry-point.d.mts.map +1 -0
- package/dist/entry-point.mjs +40 -0
- package/dist/entry-point.mjs.map +1 -0
- package/dist/globals.d.mts +4 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +40 -0
- package/dist/index.mjs.map +1 -0
- package/dist/tsconfig.json +1 -0
- package/dist/types.d.mts +2 -0
- package/dist/utils/create-event-emitter.d.mts +39 -0
- package/dist/utils/create-event-emitter.d.mts.map +1 -0
- package/dist/utils/create-event-emitter.mjs +57 -0
- package/dist/utils/create-event-emitter.mjs.map +1 -0
- package/dist/utils/create-reducer.d.mts +34 -0
- package/dist/utils/create-reducer.d.mts.map +1 -0
- package/dist/utils/create-reducer.mjs +49 -0
- package/dist/utils/create-reducer.mjs.map +1 -0
- package/dist/utils/create-state.d.mts +61 -0
- package/dist/utils/create-state.d.mts.map +1 -0
- package/dist/utils/create-state.mjs +92 -0
- package/dist/utils/create-state.mjs.map +1 -0
- package/dist/utils/index.d.mts +4 -0
- package/dist/utils/index.d.mts.map +1 -0
- package/dist/utils/index.mjs +4 -0
- package/dist/utils/index.mjs.map +1 -0
- package/package.json +71 -0
- package/src/core/class/child-observable-class.mts +232 -0
- package/src/core/class/index.mts +3 -0
- package/src/core/class/observable-base-class.mts +186 -0
- package/src/core/class/observable.class.test.mts +89 -0
- package/src/core/class/root-observable-class.mts +68 -0
- package/src/core/combine/combine.mts +144 -0
- package/src/core/combine/index.mts +3 -0
- package/src/core/combine/merge.mts +84 -0
- package/src/core/combine/zip.mts +149 -0
- package/src/core/create/from-array.mts +58 -0
- package/src/core/create/from-promise.mts +58 -0
- package/src/core/create/from-subscribable.mts +37 -0
- package/src/core/create/index.mts +7 -0
- package/src/core/create/interval.mts +99 -0
- package/src/core/create/of.mts +54 -0
- package/src/core/create/source.mts +59 -0
- package/src/core/create/timer.mts +84 -0
- package/src/core/index.mts +6 -0
- package/src/core/operators/audit-time.mts +77 -0
- package/src/core/operators/debounce-time.mts +96 -0
- package/src/core/operators/filter.mts +125 -0
- package/src/core/operators/index.mts +17 -0
- package/src/core/operators/map-with-index.mts +168 -0
- package/src/core/operators/merge-map.mts +108 -0
- package/src/core/operators/pairwise.mts +77 -0
- package/src/core/operators/scan.mts +81 -0
- package/src/core/operators/skip-if-no-change.mts +91 -0
- package/src/core/operators/skip-until.mts +54 -0
- package/src/core/operators/skip-while.mts +77 -0
- package/src/core/operators/switch-map.mts +101 -0
- package/src/core/operators/take-until.mts +80 -0
- package/src/core/operators/take-while.mts +103 -0
- package/src/core/operators/throttle-time.mts +95 -0
- package/src/core/operators/with-buffered-from.mts +68 -0
- package/src/core/operators/with-current-value-from.mts +58 -0
- package/src/core/operators/with-initial-value.mts +76 -0
- package/src/core/types/id.mts +5 -0
- package/src/core/types/index.mts +5 -0
- package/src/core/types/observable-family.mts +259 -0
- package/src/core/types/observable-kind.mts +5 -0
- package/src/core/types/observable.mts +218 -0
- package/src/core/types/types.mts +40 -0
- package/src/core/utils/id-maker.mts +31 -0
- package/src/core/utils/index.mts +4 -0
- package/src/core/utils/max-depth.mts +7 -0
- package/src/core/utils/observable-utils.mts +10 -0
- package/src/core/utils/utils.mts +51 -0
- package/src/core/utils/utils.test.mts +88 -0
- package/src/entry-point.mts +1 -0
- package/src/globals.d.mts +4 -0
- package/src/index.mts +2 -0
- package/src/utils/create-event-emitter.mts +62 -0
- package/src/utils/create-reducer.mts +55 -0
- package/src/utils/create-state.mts +138 -0
- package/src/utils/index.mts +3 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Optional } from 'ts-data-forge';
|
|
2
|
+
import { AsyncChildObservableClass } from '../class/index.mjs';
|
|
3
|
+
import {
|
|
4
|
+
type DropInitialValueOperator,
|
|
5
|
+
type Observable,
|
|
6
|
+
type Subscription,
|
|
7
|
+
type SwitchMapOperatorObservable,
|
|
8
|
+
type UpdaterSymbol,
|
|
9
|
+
} from '../types/index.mjs';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Projects each source value to an observable, subscribes to it, and emits its values.
|
|
13
|
+
* When a new value arrives from the source, the previous inner observable is unsubscribed.
|
|
14
|
+
*
|
|
15
|
+
* @template A - The type of values from the source
|
|
16
|
+
* @template B - The type of values from the projected observable
|
|
17
|
+
* @param mapToObservable - A function that maps each source value to an observable
|
|
18
|
+
* @returns An operator that switches to new observables
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const searchQuery$ = source<string>();
|
|
23
|
+
*
|
|
24
|
+
* const results$ = searchQuery$.pipe(
|
|
25
|
+
* switchMap((query) => fromPromise(fetchResults(query))),
|
|
26
|
+
* );
|
|
27
|
+
*
|
|
28
|
+
* results$.subscribe((results) => {
|
|
29
|
+
* console.log(results);
|
|
30
|
+
* });
|
|
31
|
+
* // Only the latest search results are emitted, previous searches are cancelled
|
|
32
|
+
*
|
|
33
|
+
* const fetchResults = async (_query: string): Promise<readonly unknown[]> => [];
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @note To improve code readability, consider using `createState` instead of `switchMap`,
|
|
37
|
+
* subscribe to `parentObservable` and call `setState` within it.
|
|
38
|
+
*/
|
|
39
|
+
export const switchMap =
|
|
40
|
+
<A, B>(
|
|
41
|
+
mapToObservable: (curr: A) => Observable<B>,
|
|
42
|
+
): DropInitialValueOperator<A, B> =>
|
|
43
|
+
(parentObservable) =>
|
|
44
|
+
new SwitchMapObservableClass(parentObservable, mapToObservable);
|
|
45
|
+
|
|
46
|
+
class SwitchMapObservableClass<A, B>
|
|
47
|
+
extends AsyncChildObservableClass<B, readonly [A]>
|
|
48
|
+
implements SwitchMapOperatorObservable<A, B>
|
|
49
|
+
{
|
|
50
|
+
readonly #mapToObservable: (curr: A) => Observable<B>;
|
|
51
|
+
#mut_observable: Observable<B> | undefined;
|
|
52
|
+
#mut_subscription: Subscription | undefined;
|
|
53
|
+
|
|
54
|
+
constructor(
|
|
55
|
+
parentObservable: Observable<A>,
|
|
56
|
+
mapToObservable: (curr: A) => Observable<B>,
|
|
57
|
+
) {
|
|
58
|
+
super({
|
|
59
|
+
parents: [parentObservable],
|
|
60
|
+
initialValue: Optional.none,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
this.#mapToObservable = mapToObservable;
|
|
64
|
+
|
|
65
|
+
this.#mut_observable = undefined;
|
|
66
|
+
|
|
67
|
+
this.#mut_subscription = undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
override tryUpdate(updaterSymbol: UpdaterSymbol): void {
|
|
71
|
+
const par = this.parents[0];
|
|
72
|
+
|
|
73
|
+
const sn = par.getSnapshot();
|
|
74
|
+
|
|
75
|
+
if (par.updaterSymbol !== updaterSymbol || Optional.isNone(sn)) {
|
|
76
|
+
return; // skip update
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this.#mut_observable?.complete();
|
|
80
|
+
|
|
81
|
+
this.#mut_subscription?.unsubscribe();
|
|
82
|
+
|
|
83
|
+
const observable = this.#mapToObservable(sn.value);
|
|
84
|
+
|
|
85
|
+
this.#mut_observable = observable;
|
|
86
|
+
|
|
87
|
+
const subscription = observable.subscribe((curr) => {
|
|
88
|
+
this.startUpdate(curr);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
this.#mut_subscription = subscription;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
override complete(): void {
|
|
95
|
+
this.#mut_subscription?.unsubscribe();
|
|
96
|
+
|
|
97
|
+
this.#mut_observable?.complete();
|
|
98
|
+
|
|
99
|
+
super.complete();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Optional } from 'ts-data-forge';
|
|
2
|
+
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
3
|
+
import {
|
|
4
|
+
type KeepInitialValueOperator,
|
|
5
|
+
type Observable,
|
|
6
|
+
type TakeUntilOperatorObservable,
|
|
7
|
+
type UpdaterSymbol,
|
|
8
|
+
} from '../types/index.mjs';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Emits values from the source until the notifier observable emits.
|
|
12
|
+
* When the notifier emits, this observable completes.
|
|
13
|
+
*
|
|
14
|
+
* @template A - The type of values from the source
|
|
15
|
+
* @param notifier - An observable that signals when to complete
|
|
16
|
+
* @returns An operator that takes values until notifier emits
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const num$ = source<number>();
|
|
21
|
+
*
|
|
22
|
+
* const [stopNotifier, stop_] = createEventEmitter();
|
|
23
|
+
*
|
|
24
|
+
* const limited$ = num$.pipe(takeUntil(stopNotifier));
|
|
25
|
+
*
|
|
26
|
+
* limited$.subscribe((x) => {
|
|
27
|
+
* console.log(x);
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* num$.next(1); // logs: 1
|
|
31
|
+
*
|
|
32
|
+
* num$.next(2); // logs: 2
|
|
33
|
+
*
|
|
34
|
+
* stop_();
|
|
35
|
+
*
|
|
36
|
+
* num$.next(3); // nothing logged (completed)
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export const takeUntil = <A,>(
|
|
40
|
+
notifier: Observable<unknown>,
|
|
41
|
+
): KeepInitialValueOperator<A, A> =>
|
|
42
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
43
|
+
((parentObservable) =>
|
|
44
|
+
new TakeUntilObservableClass(
|
|
45
|
+
parentObservable,
|
|
46
|
+
notifier,
|
|
47
|
+
)) as KeepInitialValueOperator<A, A>;
|
|
48
|
+
|
|
49
|
+
class TakeUntilObservableClass<A>
|
|
50
|
+
extends SyncChildObservableClass<A, readonly [A]>
|
|
51
|
+
implements TakeUntilOperatorObservable<A>
|
|
52
|
+
{
|
|
53
|
+
constructor(parentObservable: Observable<A>, notifier: Observable<unknown>) {
|
|
54
|
+
super({
|
|
55
|
+
parents: [parentObservable],
|
|
56
|
+
initialValue: parentObservable.getSnapshot(),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
notifier.subscribe(
|
|
60
|
+
() => {
|
|
61
|
+
this.complete();
|
|
62
|
+
},
|
|
63
|
+
() => {
|
|
64
|
+
this.complete();
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
override tryUpdate(updaterSymbol: UpdaterSymbol): void {
|
|
70
|
+
const par = this.parents[0];
|
|
71
|
+
|
|
72
|
+
const sn = par.getSnapshot();
|
|
73
|
+
|
|
74
|
+
if (par.updaterSymbol !== updaterSymbol || Optional.isNone(sn)) {
|
|
75
|
+
return; // skip update
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.setNext(sn.value, updaterSymbol);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Optional,
|
|
3
|
+
SafeUint,
|
|
4
|
+
asSafeUint,
|
|
5
|
+
expectType,
|
|
6
|
+
pipe,
|
|
7
|
+
} from 'ts-data-forge';
|
|
8
|
+
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
9
|
+
import { source } from '../create/index.mjs';
|
|
10
|
+
import {
|
|
11
|
+
type DropInitialValueOperator,
|
|
12
|
+
type InitializedObservable,
|
|
13
|
+
type Observable,
|
|
14
|
+
type TakeWhileOperatorObservable,
|
|
15
|
+
type UpdaterSymbol,
|
|
16
|
+
} from '../types/index.mjs';
|
|
17
|
+
import { withInitialValue } from './with-initial-value.mjs';
|
|
18
|
+
|
|
19
|
+
export const takeWhile =
|
|
20
|
+
<A,>(
|
|
21
|
+
predicate: (value: A, index: SafeUint | -1) => boolean,
|
|
22
|
+
): DropInitialValueOperator<A, A> =>
|
|
23
|
+
(parentObservable) =>
|
|
24
|
+
new TakeWhileObservableClass(parentObservable, predicate);
|
|
25
|
+
|
|
26
|
+
/* Specialized operators */
|
|
27
|
+
|
|
28
|
+
export const take = <A,>(
|
|
29
|
+
n: PositiveSafeIntWithSmallInt,
|
|
30
|
+
): DropInitialValueOperator<A, A> => takeWhile((_, index) => index + 1 <= n);
|
|
31
|
+
|
|
32
|
+
/* implementation */
|
|
33
|
+
|
|
34
|
+
class TakeWhileObservableClass<A>
|
|
35
|
+
extends SyncChildObservableClass<A, readonly [A]>
|
|
36
|
+
implements TakeWhileOperatorObservable<A>
|
|
37
|
+
{
|
|
38
|
+
readonly #predicate: (value: A, index: SafeUint | -1) => boolean;
|
|
39
|
+
#mut_index: SafeUint | -1;
|
|
40
|
+
|
|
41
|
+
constructor(
|
|
42
|
+
parentObservable: Observable<A>,
|
|
43
|
+
predicate: (value: A, index: SafeUint | -1) => boolean,
|
|
44
|
+
) {
|
|
45
|
+
super({
|
|
46
|
+
parents: [parentObservable],
|
|
47
|
+
initialValue: pipe(parentObservable.getSnapshot()).map((par) =>
|
|
48
|
+
Optional.isNone(par)
|
|
49
|
+
? Optional.none
|
|
50
|
+
: predicate(par.value, -1)
|
|
51
|
+
? par
|
|
52
|
+
: Optional.none,
|
|
53
|
+
).value,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this.#mut_index = -1;
|
|
57
|
+
|
|
58
|
+
this.#predicate = predicate;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
override tryUpdate(updaterSymbol: UpdaterSymbol): void {
|
|
62
|
+
const par = this.parents[0];
|
|
63
|
+
|
|
64
|
+
const sn = par.getSnapshot();
|
|
65
|
+
|
|
66
|
+
if (par.updaterSymbol !== updaterSymbol || Optional.isNone(sn)) {
|
|
67
|
+
return; // skip update
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.#mut_index =
|
|
71
|
+
this.#mut_index === -1 ? asSafeUint(0) : SafeUint.add(1, this.#mut_index);
|
|
72
|
+
|
|
73
|
+
if (this.#predicate(sn.value, this.#mut_index)) {
|
|
74
|
+
this.setNext(sn.value, updaterSymbol);
|
|
75
|
+
} else {
|
|
76
|
+
this.complete();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (import.meta.vitest !== undefined) {
|
|
82
|
+
test('type test', () => {
|
|
83
|
+
expect(1).toBe(1); // dummy
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
{
|
|
87
|
+
const s: Observable<number> = source<number>();
|
|
88
|
+
|
|
89
|
+
const _d1 = s.pipe(take(3));
|
|
90
|
+
|
|
91
|
+
expectType<typeof _d1, Observable<number>>('=');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
{
|
|
95
|
+
const s = source<number>();
|
|
96
|
+
|
|
97
|
+
const m: InitializedObservable<number> = s.pipe(withInitialValue(0));
|
|
98
|
+
|
|
99
|
+
const _d = m.pipe(take(3));
|
|
100
|
+
|
|
101
|
+
expectType<typeof _d, Observable<number>>('=');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Optional } from 'ts-data-forge';
|
|
2
|
+
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
3
|
+
import {
|
|
4
|
+
type KeepInitialValueOperator,
|
|
5
|
+
type Observable,
|
|
6
|
+
type ThrottleTimeOperatorObservable,
|
|
7
|
+
type UpdaterSymbol,
|
|
8
|
+
} from '../types/index.mjs';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Emits the first value, then ignores subsequent values for a specified duration.
|
|
12
|
+
* After the duration, the next emission is allowed through.
|
|
13
|
+
*
|
|
14
|
+
* @template A - The type of values from the source
|
|
15
|
+
* @param milliSeconds - The throttle duration in milliseconds
|
|
16
|
+
* @returns An operator that throttles emissions
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const scroll$ = source<Event>();
|
|
21
|
+
*
|
|
22
|
+
* const throttled$ = scroll$.pipe(throttleTime(1000));
|
|
23
|
+
*
|
|
24
|
+
* throttled$.subscribe((event_) => {
|
|
25
|
+
* console.log(event_);
|
|
26
|
+
* });
|
|
27
|
+
* // Emits at most once per second
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export const throttleTime = <A,>(
|
|
31
|
+
milliSeconds: number,
|
|
32
|
+
): KeepInitialValueOperator<A, A> =>
|
|
33
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
34
|
+
((parentObservable) =>
|
|
35
|
+
new ThrottleTimeObservableClass(
|
|
36
|
+
parentObservable,
|
|
37
|
+
milliSeconds,
|
|
38
|
+
)) as KeepInitialValueOperator<A, A>;
|
|
39
|
+
|
|
40
|
+
class ThrottleTimeObservableClass<A>
|
|
41
|
+
extends SyncChildObservableClass<A, readonly [A]>
|
|
42
|
+
implements ThrottleTimeOperatorObservable<A>
|
|
43
|
+
{
|
|
44
|
+
readonly #milliSeconds: number;
|
|
45
|
+
#mut_timerId: TimerId | undefined;
|
|
46
|
+
#mut_isSkipping: boolean;
|
|
47
|
+
|
|
48
|
+
constructor(parentObservable: Observable<A>, milliSeconds: number) {
|
|
49
|
+
super({
|
|
50
|
+
parents: [parentObservable],
|
|
51
|
+
initialValue: parentObservable.getSnapshot(),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
this.#mut_timerId = undefined;
|
|
55
|
+
|
|
56
|
+
this.#mut_isSkipping = false;
|
|
57
|
+
|
|
58
|
+
this.#milliSeconds = milliSeconds;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
override tryUpdate(updaterSymbol: UpdaterSymbol): void {
|
|
62
|
+
const par = this.parents[0];
|
|
63
|
+
|
|
64
|
+
const sn = par.getSnapshot();
|
|
65
|
+
|
|
66
|
+
if (
|
|
67
|
+
par.updaterSymbol !== updaterSymbol ||
|
|
68
|
+
Optional.isNone(sn) ||
|
|
69
|
+
this.#mut_isSkipping
|
|
70
|
+
) {
|
|
71
|
+
return; // skip update
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this.setNext(sn.value, updaterSymbol);
|
|
75
|
+
|
|
76
|
+
this.#mut_isSkipping = true;
|
|
77
|
+
|
|
78
|
+
// set timer
|
|
79
|
+
this.#mut_timerId = setTimeout(() => {
|
|
80
|
+
this.#mut_isSkipping = false;
|
|
81
|
+
}, this.#milliSeconds);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#resetTimer(): void {
|
|
85
|
+
if (this.#mut_timerId !== undefined) {
|
|
86
|
+
clearTimeout(this.#mut_timerId);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
override complete(): void {
|
|
91
|
+
this.#resetTimer();
|
|
92
|
+
|
|
93
|
+
super.complete();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Arr, Optional, pipe } from 'ts-data-forge';
|
|
2
|
+
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
3
|
+
import {
|
|
4
|
+
type KeepInitialValueOperator,
|
|
5
|
+
type Observable,
|
|
6
|
+
type UpdaterSymbol,
|
|
7
|
+
type WithBufferedFromOperatorObservable,
|
|
8
|
+
} from '../types/index.mjs';
|
|
9
|
+
import { maxDepth } from '../utils/index.mjs';
|
|
10
|
+
|
|
11
|
+
export const withBufferedFrom = <A, B>(
|
|
12
|
+
observable: Observable<B>,
|
|
13
|
+
): KeepInitialValueOperator<A, readonly [A, readonly B[]]> =>
|
|
14
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
15
|
+
((parentObservable) =>
|
|
16
|
+
new WithBufferedFromObservableClass(
|
|
17
|
+
parentObservable,
|
|
18
|
+
observable,
|
|
19
|
+
)) as KeepInitialValueOperator<A, readonly [A, readonly B[]]>;
|
|
20
|
+
|
|
21
|
+
export const withBuffered = withBufferedFrom; // alias
|
|
22
|
+
|
|
23
|
+
class WithBufferedFromObservableClass<A, B>
|
|
24
|
+
extends SyncChildObservableClass<readonly [A, readonly B[]], readonly [A]>
|
|
25
|
+
implements WithBufferedFromOperatorObservable<A, B>
|
|
26
|
+
{
|
|
27
|
+
#mut_bufferedValues: readonly B[] = [];
|
|
28
|
+
|
|
29
|
+
constructor(parentObservable: Observable<A>, observable: Observable<B>) {
|
|
30
|
+
super({
|
|
31
|
+
parents: [parentObservable],
|
|
32
|
+
depth: 1 + maxDepth([parentObservable, observable]),
|
|
33
|
+
initialValue: pipe({
|
|
34
|
+
par: parentObservable.getSnapshot(),
|
|
35
|
+
me: observable.getSnapshot(),
|
|
36
|
+
}).map(({ par, me }) =>
|
|
37
|
+
Optional.isNone(par)
|
|
38
|
+
? Optional.none
|
|
39
|
+
: Optional.some([
|
|
40
|
+
par.value,
|
|
41
|
+
Optional.isNone(me) ? [] : [me.value],
|
|
42
|
+
] as const),
|
|
43
|
+
).value,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
observable.subscribe((value) => {
|
|
47
|
+
this.#mut_bufferedValues = Arr.toPushed(this.#mut_bufferedValues, value);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override tryUpdate(updaterSymbol: UpdaterSymbol): void {
|
|
52
|
+
const par = this.parents[0];
|
|
53
|
+
|
|
54
|
+
const sn = par.getSnapshot();
|
|
55
|
+
|
|
56
|
+
if (par.updaterSymbol !== updaterSymbol || Optional.isNone(sn)) {
|
|
57
|
+
return; // skip update
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.setNext([sn.value, this.#mut_bufferedValues], updaterSymbol);
|
|
61
|
+
|
|
62
|
+
this.#clearBuffer();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#clearBuffer(): void {
|
|
66
|
+
this.#mut_bufferedValues = [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Optional, pipe } from 'ts-data-forge';
|
|
2
|
+
import { SyncChildObservableClass } from '../class/index.mjs';
|
|
3
|
+
import {
|
|
4
|
+
type DropInitialValueOperator,
|
|
5
|
+
type Observable,
|
|
6
|
+
type UpdaterSymbol,
|
|
7
|
+
type WithCurrentValueFromOperatorObservable,
|
|
8
|
+
} from '../types/index.mjs';
|
|
9
|
+
import { maxDepth } from '../utils/index.mjs';
|
|
10
|
+
|
|
11
|
+
export const withCurrentValueFrom =
|
|
12
|
+
<A, B>(
|
|
13
|
+
observable: Observable<B>,
|
|
14
|
+
): DropInitialValueOperator<A, readonly [A, B]> =>
|
|
15
|
+
(parentObservable) =>
|
|
16
|
+
new WithCurrentValueFromObservableClass(parentObservable, observable);
|
|
17
|
+
|
|
18
|
+
export const withLatestFrom = withCurrentValueFrom; // alias
|
|
19
|
+
|
|
20
|
+
class WithCurrentValueFromObservableClass<A, B>
|
|
21
|
+
extends SyncChildObservableClass<readonly [A, B], readonly [A]>
|
|
22
|
+
implements WithCurrentValueFromOperatorObservable<A, B>
|
|
23
|
+
{
|
|
24
|
+
readonly #observable: Observable<B>;
|
|
25
|
+
|
|
26
|
+
constructor(parentObservable: Observable<A>, observable: Observable<B>) {
|
|
27
|
+
super({
|
|
28
|
+
parents: [parentObservable],
|
|
29
|
+
depth: 1 + maxDepth([parentObservable, observable]),
|
|
30
|
+
initialValue: pipe({
|
|
31
|
+
par: parentObservable.getSnapshot(),
|
|
32
|
+
me: observable.getSnapshot(),
|
|
33
|
+
}).map(({ me, par }) =>
|
|
34
|
+
Optional.isNone(par) || Optional.isNone(me)
|
|
35
|
+
? Optional.none
|
|
36
|
+
: Optional.some([par.value, me.value] as const),
|
|
37
|
+
).value,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
this.#observable = observable;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override tryUpdate(updaterSymbol: UpdaterSymbol): void {
|
|
44
|
+
const par = this.parents[0];
|
|
45
|
+
|
|
46
|
+
const ps = par.getSnapshot();
|
|
47
|
+
|
|
48
|
+
if (par.updaterSymbol !== updaterSymbol || Optional.isNone(ps)) {
|
|
49
|
+
return; // skip update
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const curr = this.#observable.getSnapshot();
|
|
53
|
+
|
|
54
|
+
if (Optional.isNone(curr)) return; // skip update
|
|
55
|
+
|
|
56
|
+
this.setNext([ps.value, curr.value], updaterSymbol);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { expectType, Optional } from 'ts-data-forge';
|
|
2
|
+
import { InitializedSyncChildObservableClass } from '../class/index.mjs';
|
|
3
|
+
import { source } from '../create/index.mjs';
|
|
4
|
+
import {
|
|
5
|
+
type InitializedObservable,
|
|
6
|
+
type Observable,
|
|
7
|
+
type UpdaterSymbol,
|
|
8
|
+
type WithInitialValueOperator,
|
|
9
|
+
type WithInitialValueOperatorObservable,
|
|
10
|
+
} from '../types/index.mjs';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Provides an initial value for an observable that doesn't have one.
|
|
14
|
+
* The resulting observable will immediately emit the initial value upon subscription,
|
|
15
|
+
* and then emit all subsequent values from the source.
|
|
16
|
+
*
|
|
17
|
+
* @template A - The type of values from the source
|
|
18
|
+
* @template I - The type of the initial value (defaults to A)
|
|
19
|
+
* @param initialValue - The initial value to emit
|
|
20
|
+
* @returns An operator that sets the initial value
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* const num$ = source<number>();
|
|
25
|
+
*
|
|
26
|
+
* const initialized$ = num$.pipe(withInitialValue(0));
|
|
27
|
+
*
|
|
28
|
+
* initialized$.subscribe((x) => {
|
|
29
|
+
* console.log(x);
|
|
30
|
+
* }); // immediately logs: 0
|
|
31
|
+
*
|
|
32
|
+
* num$.next(1); // logs: 1
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export const withInitialValue =
|
|
36
|
+
<A, I = A>(initialValue: I): WithInitialValueOperator<A, A | I> =>
|
|
37
|
+
(parentObservable) =>
|
|
38
|
+
new WithInitialValueObservableClass(parentObservable, initialValue);
|
|
39
|
+
|
|
40
|
+
class WithInitialValueObservableClass<A, I>
|
|
41
|
+
extends InitializedSyncChildObservableClass<A | I, readonly [A]>
|
|
42
|
+
implements WithInitialValueOperatorObservable<A, I>
|
|
43
|
+
{
|
|
44
|
+
constructor(parentObservable: Observable<A>, initialValue: I) {
|
|
45
|
+
super({
|
|
46
|
+
parents: [parentObservable],
|
|
47
|
+
initialValue: Optional.some(initialValue),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override tryUpdate(updaterSymbol: UpdaterSymbol): void {
|
|
52
|
+
const par = this.parents[0];
|
|
53
|
+
|
|
54
|
+
const sn = par.getSnapshot();
|
|
55
|
+
|
|
56
|
+
if (par.updaterSymbol !== updaterSymbol || Optional.isNone(sn)) {
|
|
57
|
+
return; // skip update
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.setNext(sn.value, updaterSymbol);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (import.meta.vitest !== undefined) {
|
|
65
|
+
test('type test', () => {
|
|
66
|
+
expect(1).toBe(1); // dummy
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
{
|
|
70
|
+
const s = source<number>();
|
|
71
|
+
|
|
72
|
+
const _d: InitializedObservable<number> = s.pipe(withInitialValue(0));
|
|
73
|
+
|
|
74
|
+
expectType<typeof _d, InitializedObservable<number>>('=');
|
|
75
|
+
}
|
|
76
|
+
}
|