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
|
@@ -2,93 +2,33 @@ import { pipe, Optional, asSafeUint, SafeUint } from 'ts-data-forge';
|
|
|
2
2
|
import { SyncChildObservableClass } from '../class/child-observable-class.mjs';
|
|
3
3
|
import '../utils/id-maker.mjs';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Emits values from the source observable while the predicate returns true.
|
|
7
|
-
* Completes immediately when the predicate returns false.
|
|
8
|
-
*
|
|
9
|
-
* @template A - The type of values from the source
|
|
10
|
-
* @param predicate - Function to test each value
|
|
11
|
-
* @returns An operator that takes values while the predicate is true
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```ts
|
|
15
|
-
* // Timeline:
|
|
16
|
-
* //
|
|
17
|
-
* // num$ 1 2 3 4 5 6 1 2 (ignored)
|
|
18
|
-
* // taken$ 1 2 3 4 | (completes)
|
|
19
|
-
* //
|
|
20
|
-
* // Explanation:
|
|
21
|
-
* // - takeWhile emits values while the predicate returns true
|
|
22
|
-
* // - Completes immediately when the predicate returns false
|
|
23
|
-
* // - No further values are emitted after completion
|
|
24
|
-
*
|
|
25
|
-
* const num$ = source<number>();
|
|
26
|
-
*
|
|
27
|
-
* const taken$ = num$.pipe(takeWhile((x) => x < 5));
|
|
28
|
-
*
|
|
29
|
-
* const valueHistory: number[] = [];
|
|
30
|
-
*
|
|
31
|
-
* taken$.subscribe((x) => {
|
|
32
|
-
* valueHistory.push(x);
|
|
33
|
-
* });
|
|
34
|
-
*
|
|
35
|
-
* num$.next(1); // logs: 1
|
|
36
|
-
*
|
|
37
|
-
* assert.deepStrictEqual(valueHistory, [1]);
|
|
38
|
-
*
|
|
39
|
-
* num$.next(2); // logs: 2
|
|
40
|
-
*
|
|
41
|
-
* num$.next(3); // logs: 3
|
|
42
|
-
*
|
|
43
|
-
* num$.next(4); // logs: 4
|
|
44
|
-
*
|
|
45
|
-
* assert.deepStrictEqual(valueHistory, [1, 2, 3, 4]);
|
|
46
|
-
*
|
|
47
|
-
* num$.next(5); // nothing logged (completes)
|
|
48
|
-
*
|
|
49
|
-
* assert.deepStrictEqual(valueHistory, [1, 2, 3, 4]);
|
|
50
|
-
*
|
|
51
|
-
* num$.next(6); // nothing logged (already completed)
|
|
52
|
-
*
|
|
53
|
-
* assert.deepStrictEqual(valueHistory, [1, 2, 3, 4]);
|
|
54
|
-
*
|
|
55
|
-
* num$.next(1); // logs: 1
|
|
56
|
-
*
|
|
57
|
-
* assert.deepStrictEqual(valueHistory, [1, 2, 3, 4]);
|
|
58
|
-
* ```
|
|
59
|
-
*/
|
|
60
5
|
const takeWhile = (predicate) => (parentObservable) => new TakeWhileObservableClass(parentObservable, predicate);
|
|
61
|
-
/* implementation */
|
|
62
6
|
class TakeWhileObservableClass extends SyncChildObservableClass {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
7
|
+
#predicate;
|
|
8
|
+
#mut_index;
|
|
9
|
+
constructor(parentObservable, predicate) {
|
|
10
|
+
super({
|
|
11
|
+
parents: [parentObservable],
|
|
12
|
+
initialValue: pipe(parentObservable.getSnapshot()).map(
|
|
13
|
+
(par) => Optional.isNone(par) ? Optional.none : predicate(par.value, -1) ? par : Optional.none
|
|
14
|
+
).value
|
|
15
|
+
});
|
|
16
|
+
this.#mut_index = -1;
|
|
17
|
+
this.#predicate = predicate;
|
|
18
|
+
}
|
|
19
|
+
tryUpdate(updateToken) {
|
|
20
|
+
const par = this.parents[0];
|
|
21
|
+
const sn = par.getSnapshot();
|
|
22
|
+
if (par.updateToken !== updateToken || Optional.isNone(sn)) {
|
|
23
|
+
return;
|
|
76
24
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
this.#mut_index =
|
|
84
|
-
this.#mut_index === -1 ? asSafeUint(0) : SafeUint.add(1, this.#mut_index);
|
|
85
|
-
if (this.#predicate(sn.value, this.#mut_index)) {
|
|
86
|
-
this.setNext(sn.value, updateToken);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
this.complete();
|
|
90
|
-
}
|
|
25
|
+
this.#mut_index = this.#mut_index === -1 ? asSafeUint(0) : SafeUint.add(1, this.#mut_index);
|
|
26
|
+
if (this.#predicate(sn.value, this.#mut_index)) {
|
|
27
|
+
this.setNext(sn.value, updateToken);
|
|
28
|
+
} else {
|
|
29
|
+
this.complete();
|
|
91
30
|
}
|
|
31
|
+
}
|
|
92
32
|
}
|
|
93
33
|
|
|
94
34
|
export { takeWhile };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"take-while.mjs","sources":["../../../src/core/operators/take-while.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"take-while.mjs","sources":["../../../src/core/operators/take-while.mts"],"sourcesContent":["import {\n Optional,\n SafeUint,\n asSafeUint,\n expectType,\n pipe,\n} from 'ts-data-forge';\nimport { SyncChildObservableClass } from '../class/index.mjs';\nimport { source } from '../create/index.mjs';\nimport {\n type DropInitialValueOperator,\n type InitializedObservable,\n type Observable,\n type TakeWhileOperatorObservable,\n type UpdateToken,\n} from '../types/index.mjs';\nimport { withInitialValue } from './with-initial-value.mjs';\n\n/**\n * Emits values from the source observable while the predicate returns true.\n * Completes immediately when the predicate returns false.\n *\n * @template A - The type of values from the source\n * @param predicate - Function to test each value\n * @returns An operator that takes values while the predicate is true\n *\n * @example\n * ```ts\n * // Timeline:\n * //\n * // num$ 1 2 3 4 5 6 1 2 (ignored)\n * // taken$ 1 2 3 4 | (completes)\n * //\n * // Explanation:\n * // - takeWhile emits values while the predicate returns true\n * // - Completes immediately when the predicate returns false\n * // - No further values are emitted after completion\n *\n * const num$ = source<number>();\n *\n * const taken$ = num$.pipe(takeWhile((x) => x < 5));\n *\n * const valueHistory: number[] = [];\n *\n * taken$.subscribe((x) => {\n * valueHistory.push(x);\n * });\n *\n * num$.next(1); // logs: 1\n *\n * assert.deepStrictEqual(valueHistory, [1]);\n *\n * num$.next(2); // logs: 2\n *\n * num$.next(3); // logs: 3\n *\n * num$.next(4); // logs: 4\n *\n * assert.deepStrictEqual(valueHistory, [1, 2, 3, 4]);\n *\n * num$.next(5); // nothing logged (completes)\n *\n * assert.deepStrictEqual(valueHistory, [1, 2, 3, 4]);\n *\n * num$.next(6); // nothing logged (already completed)\n *\n * assert.deepStrictEqual(valueHistory, [1, 2, 3, 4]);\n *\n * num$.next(1); // logs: 1\n *\n * assert.deepStrictEqual(valueHistory, [1, 2, 3, 4]);\n * ```\n */\nexport const takeWhile =\n <A,>(\n predicate: (value: A, index: SafeUint | -1) => boolean,\n ): DropInitialValueOperator<A, A> =>\n (parentObservable) =>\n new TakeWhileObservableClass(parentObservable, predicate);\n\n/* implementation */\n\nclass TakeWhileObservableClass<A>\n extends SyncChildObservableClass<A, readonly [A]>\n implements TakeWhileOperatorObservable<A>\n{\n readonly #predicate: (value: A, index: SafeUint | -1) => boolean;\n #mut_index: SafeUint | -1;\n\n constructor(\n parentObservable: Observable<A>,\n predicate: (value: A, index: SafeUint | -1) => boolean,\n ) {\n super({\n parents: [parentObservable],\n initialValue: pipe(parentObservable.getSnapshot()).map((par) =>\n Optional.isNone(par)\n ? Optional.none\n : predicate(par.value, -1)\n ? par\n : Optional.none,\n ).value,\n });\n\n this.#mut_index = -1;\n\n this.#predicate = predicate;\n }\n\n override tryUpdate(updateToken: UpdateToken): void {\n const par = this.parents[0];\n\n const sn = par.getSnapshot();\n\n if (par.updateToken !== updateToken || Optional.isNone(sn)) {\n return; // skip update\n }\n\n this.#mut_index =\n this.#mut_index === -1 ? asSafeUint(0) : SafeUint.add(1, this.#mut_index);\n\n if (this.#predicate(sn.value, this.#mut_index)) {\n this.setNext(sn.value, updateToken);\n } else {\n this.complete();\n }\n }\n}\n\nif (import.meta.vitest !== undefined) {\n test('type test', () => {\n expect(1).toBe(1); // dummy\n });\n\n {\n const s: Observable<number> = source<number>();\n\n const _d1 = s.pipe(takeWhile((_, index) => index + 1 <= 3));\n\n expectType<typeof _d1, Observable<number>>('=');\n }\n\n {\n const s = source<number>();\n\n const m: InitializedObservable<number> = s.pipe(withInitialValue(0));\n\n const _d = m.pipe(takeWhile((_, index) => index + 1 <= 3));\n\n expectType<typeof _d, Observable<number>>('=');\n }\n}\n"],"names":[],"mappings":";;;;AAyEO,MAAM,SAAA,GACX,CACE,SAAA,KAEF,CAAC,qBACC,IAAI,wBAAA,CAAyB,kBAAkB,SAAS;AAI5D,MAAM,iCACI,wBAAA,CAEV;AAAA,EACW,UAAA;AAAA,EACT,UAAA;AAAA,EAEA,WAAA,CACE,kBACA,SAAA,EACA;AACA,IAAA,KAAA,CAAM;AAAA,MACJ,OAAA,EAAS,CAAC,gBAAgB,CAAA;AAAA,MAC1B,YAAA,EAAc,IAAA,CAAK,gBAAA,CAAiB,WAAA,EAAa,CAAA,CAAE,GAAA;AAAA,QAAI,CAAC,GAAA,KACtD,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,GACf,QAAA,CAAS,IAAA,GACT,SAAA,CAAU,GAAA,CAAI,KAAA,EAAO,EAAE,CAAA,GACrB,MACA,QAAA,CAAS;AAAA,OACjB,CAAE;AAAA,KACH,CAAA;AAED,IAAA,IAAA,CAAK,UAAA,GAAa,EAAA;AAElB,IAAA,IAAA,CAAK,UAAA,GAAa,SAAA;AAAA,EAAA;AACpB,EAES,UAAU,WAAA,EAAgC;AACjD,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAA;AAE1B,IAAA,MAAM,EAAA,GAAK,IAAI,WAAA,EAAY;AAE3B,IAAA,IAAI,IAAI,WAAA,KAAgB,WAAA,IAAe,QAAA,CAAS,MAAA,CAAO,EAAE,CAAA,EAAG;AAC1D,MAAA;AAAA,IAAA;AAGF,IAAA,IAAA,CAAK,UAAA,GACH,IAAA,CAAK,UAAA,KAAe,EAAA,GAAK,UAAA,CAAW,CAAC,CAAA,GAAI,QAAA,CAAS,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,UAAU,CAAA;AAE1E,IAAA,IAAI,KAAK,UAAA,CAAW,EAAA,CAAG,KAAA,EAAO,IAAA,CAAK,UAAU,CAAA,EAAG;AAC9C,MAAA,IAAA,CAAK,OAAA,CAAQ,EAAA,CAAG,KAAA,EAAO,WAAW,CAAA;AAAA,IAAA,CACpC,MAAO;AACL,MAAA,IAAA,CAAK,QAAA,EAAS;AAAA,IAAA;AAChB,EAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throttle.d.mts","sourceRoot":"","sources":["../../../src/core/operators/throttle.mts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,wBAAwB,EAK9B,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6EG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"throttle.d.mts","sourceRoot":"","sources":["../../../src/core/operators/throttle.mts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,wBAAwB,EAK9B,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6EG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,gBACV,MAAM,KACnB,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAMQ,CAAC"}
|
|
@@ -2,124 +2,47 @@ import { Optional } from 'ts-data-forge';
|
|
|
2
2
|
import { SyncChildObservableClass } from '../class/child-observable-class.mjs';
|
|
3
3
|
import '../utils/id-maker.mjs';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```ts
|
|
15
|
-
* // Timeline (250ms throttle):
|
|
16
|
-
* //
|
|
17
|
-
* // Time(x50ms) 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
|
|
18
|
-
* //
|
|
19
|
-
* // input$ 0 2 3 9 10 11 12 13 14
|
|
20
|
-
* // |- 250ms -> |- 250ms -> |- 250ms -> |- 250ms ->
|
|
21
|
-
* // throttled$ 0 3 9 12 (emitted at start of window)
|
|
22
|
-
* //
|
|
23
|
-
* // Explanation:
|
|
24
|
-
* // - throttle emits the FIRST value received, then ignores subsequent values
|
|
25
|
-
* // for the specified duration (250ms)
|
|
26
|
-
* // - Unlike audit (which emits the LAST value), throttle emits the FIRST
|
|
27
|
-
* // - Useful for rate-limiting scroll/resize events
|
|
28
|
-
*
|
|
29
|
-
* const input$ = source<number>();
|
|
30
|
-
*
|
|
31
|
-
* const throttled$ = input$.pipe(throttle(250));
|
|
32
|
-
*
|
|
33
|
-
* const valueHistory: number[] = [];
|
|
34
|
-
*
|
|
35
|
-
* throttled$.subscribe((value) => {
|
|
36
|
-
* valueHistory.push(value);
|
|
37
|
-
* });
|
|
38
|
-
*
|
|
39
|
-
* const sleep = (ms: number): Promise<void> =>
|
|
40
|
-
* new Promise((resolve) => {
|
|
41
|
-
* setTimeout(resolve, ms);
|
|
42
|
-
* });
|
|
43
|
-
*
|
|
44
|
-
* input$.next(0);
|
|
45
|
-
*
|
|
46
|
-
* assert.deepStrictEqual(valueHistory, [0]);
|
|
47
|
-
*
|
|
48
|
-
* await sleep(200);
|
|
49
|
-
*
|
|
50
|
-
* input$.next(2);
|
|
51
|
-
*
|
|
52
|
-
* assert.deepStrictEqual(valueHistory, [0]);
|
|
53
|
-
*
|
|
54
|
-
* await sleep(100);
|
|
55
|
-
*
|
|
56
|
-
* input$.next(3);
|
|
57
|
-
*
|
|
58
|
-
* assert.deepStrictEqual(valueHistory, [0, 3]);
|
|
59
|
-
*
|
|
60
|
-
* await sleep(300);
|
|
61
|
-
*
|
|
62
|
-
* input$.next(9);
|
|
63
|
-
*
|
|
64
|
-
* assert.deepStrictEqual(valueHistory, [0, 3, 9]);
|
|
65
|
-
*
|
|
66
|
-
* await sleep(100);
|
|
67
|
-
*
|
|
68
|
-
* input$.next(10);
|
|
69
|
-
*
|
|
70
|
-
* await sleep(100);
|
|
71
|
-
*
|
|
72
|
-
* input$.next(11);
|
|
73
|
-
*
|
|
74
|
-
* assert.deepStrictEqual(valueHistory, [0, 3, 9]);
|
|
75
|
-
*
|
|
76
|
-
* await sleep(100);
|
|
77
|
-
*
|
|
78
|
-
* input$.next(12);
|
|
79
|
-
*
|
|
80
|
-
* assert.deepStrictEqual(valueHistory, [0, 3, 9, 12]);
|
|
81
|
-
* ```
|
|
82
|
-
*/
|
|
83
|
-
const throttle = (milliSeconds) =>
|
|
84
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
85
|
-
((parentObservable) => new ThrottleObservableClass(parentObservable, milliSeconds));
|
|
5
|
+
const throttle = (milliSeconds) => (
|
|
6
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
7
|
+
((parentObservable) => new ThrottleObservableClass(
|
|
8
|
+
parentObservable,
|
|
9
|
+
milliSeconds
|
|
10
|
+
))
|
|
11
|
+
);
|
|
86
12
|
class ThrottleObservableClass extends SyncChildObservableClass {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
13
|
+
#milliSeconds;
|
|
14
|
+
#mut_timerId;
|
|
15
|
+
#mut_isSkipping;
|
|
16
|
+
constructor(parentObservable, milliSeconds) {
|
|
17
|
+
super({
|
|
18
|
+
parents: [parentObservable],
|
|
19
|
+
initialValue: parentObservable.getSnapshot()
|
|
20
|
+
});
|
|
21
|
+
this.#mut_timerId = void 0;
|
|
22
|
+
this.#mut_isSkipping = false;
|
|
23
|
+
this.#milliSeconds = milliSeconds;
|
|
24
|
+
}
|
|
25
|
+
#resetTimer() {
|
|
26
|
+
if (this.#mut_timerId !== void 0) {
|
|
27
|
+
clearTimeout(this.#mut_timerId);
|
|
98
28
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return; // skip update
|
|
106
|
-
}
|
|
107
|
-
this.setNext(sn.value, updateToken);
|
|
108
|
-
this.#mut_isSkipping = true;
|
|
109
|
-
// set timer
|
|
110
|
-
this.#mut_timerId = setTimeout(() => {
|
|
111
|
-
this.#mut_isSkipping = false;
|
|
112
|
-
}, this.#milliSeconds);
|
|
113
|
-
}
|
|
114
|
-
#resetTimer() {
|
|
115
|
-
if (this.#mut_timerId !== undefined) {
|
|
116
|
-
clearTimeout(this.#mut_timerId);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
complete() {
|
|
120
|
-
this.#resetTimer();
|
|
121
|
-
super.complete();
|
|
29
|
+
}
|
|
30
|
+
tryUpdate(updateToken) {
|
|
31
|
+
const par = this.parents[0];
|
|
32
|
+
const sn = par.getSnapshot();
|
|
33
|
+
if (par.updateToken !== updateToken || Optional.isNone(sn) || this.#mut_isSkipping) {
|
|
34
|
+
return;
|
|
122
35
|
}
|
|
36
|
+
this.setNext(sn.value, updateToken);
|
|
37
|
+
this.#mut_isSkipping = true;
|
|
38
|
+
this.#mut_timerId = setTimeout(() => {
|
|
39
|
+
this.#mut_isSkipping = false;
|
|
40
|
+
}, this.#milliSeconds);
|
|
41
|
+
}
|
|
42
|
+
complete() {
|
|
43
|
+
this.#resetTimer();
|
|
44
|
+
super.complete();
|
|
45
|
+
}
|
|
123
46
|
}
|
|
124
47
|
|
|
125
48
|
export { throttle };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throttle.mjs","sources":["../../../src/core/operators/throttle.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"throttle.mjs","sources":["../../../src/core/operators/throttle.mts"],"sourcesContent":["import { Optional } from 'ts-data-forge';\nimport { SyncChildObservableClass } from '../class/index.mjs';\nimport {\n type KeepInitialValueOperator,\n type Observable,\n type ThrottleOperatorObservable,\n type TimerId,\n type UpdateToken,\n} from '../types/index.mjs';\n\n/**\n * Emits the first value, then ignores subsequent values for a specified duration.\n * After the duration, the next emission is allowed through.\n *\n * @template A - The type of values from the source\n * @param milliSeconds - The throttle duration in milliseconds\n * @returns An operator that throttles emissions\n *\n * @example\n * ```ts\n * // Timeline (250ms throttle):\n * //\n * // Time(x50ms) 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0\n * //\n * // input$ 0 2 3 9 10 11 12 13 14\n * // |- 250ms -> |- 250ms -> |- 250ms -> |- 250ms ->\n * // throttled$ 0 3 9 12 (emitted at start of window)\n * //\n * // Explanation:\n * // - throttle emits the FIRST value received, then ignores subsequent values\n * // for the specified duration (250ms)\n * // - Unlike audit (which emits the LAST value), throttle emits the FIRST\n * // - Useful for rate-limiting scroll/resize events\n *\n * const input$ = source<number>();\n *\n * const throttled$ = input$.pipe(throttle(250));\n *\n * const valueHistory: number[] = [];\n *\n * throttled$.subscribe((value) => {\n * valueHistory.push(value);\n * });\n *\n * const sleep = (ms: number): Promise<void> =>\n * new Promise((resolve) => {\n * setTimeout(resolve, ms);\n * });\n *\n * input$.next(0);\n *\n * assert.deepStrictEqual(valueHistory, [0]);\n *\n * await sleep(200);\n *\n * input$.next(2);\n *\n * assert.deepStrictEqual(valueHistory, [0]);\n *\n * await sleep(100);\n *\n * input$.next(3);\n *\n * assert.deepStrictEqual(valueHistory, [0, 3]);\n *\n * await sleep(300);\n *\n * input$.next(9);\n *\n * assert.deepStrictEqual(valueHistory, [0, 3, 9]);\n *\n * await sleep(100);\n *\n * input$.next(10);\n *\n * await sleep(100);\n *\n * input$.next(11);\n *\n * assert.deepStrictEqual(valueHistory, [0, 3, 9]);\n *\n * await sleep(100);\n *\n * input$.next(12);\n *\n * assert.deepStrictEqual(valueHistory, [0, 3, 9, 12]);\n * ```\n */\nexport const throttle = <A,>(\n milliSeconds: number,\n): KeepInitialValueOperator<A, A> =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n ((parentObservable) =>\n new ThrottleObservableClass(\n parentObservable,\n milliSeconds,\n )) as KeepInitialValueOperator<A, A>;\n\nclass ThrottleObservableClass<A>\n extends SyncChildObservableClass<A, readonly [A]>\n implements ThrottleOperatorObservable<A>\n{\n readonly #milliSeconds: number;\n #mut_timerId: TimerId | undefined;\n #mut_isSkipping: boolean;\n\n constructor(parentObservable: Observable<A>, milliSeconds: number) {\n super({\n parents: [parentObservable],\n initialValue: parentObservable.getSnapshot(),\n });\n\n this.#mut_timerId = undefined;\n\n this.#mut_isSkipping = false;\n\n this.#milliSeconds = milliSeconds;\n }\n\n #resetTimer(): void {\n if (this.#mut_timerId !== undefined) {\n clearTimeout(this.#mut_timerId);\n }\n }\n\n override tryUpdate(updateToken: UpdateToken): void {\n const par = this.parents[0];\n\n const sn = par.getSnapshot();\n\n if (\n par.updateToken !== updateToken ||\n Optional.isNone(sn) ||\n this.#mut_isSkipping\n ) {\n return; // skip update\n }\n\n this.setNext(sn.value, updateToken);\n\n this.#mut_isSkipping = true;\n\n // set timer\n this.#mut_timerId = setTimeout(() => {\n this.#mut_isSkipping = false;\n }, this.#milliSeconds);\n }\n\n override complete(): void {\n this.#resetTimer();\n\n super.complete();\n }\n}\n"],"names":[],"mappings":";;;;AAwFO,MAAM,WAAW,CACtB,YAAA;AAAA;AAAA,GAGC,CAAC,qBACA,IAAI,uBAAA;AAAA,IACF,gBAAA;AAAA,IACA;AAAA,GACF;AAAA;AAEJ,MAAM,gCACI,wBAAA,CAEV;AAAA,EACW,aAAA;AAAA,EACT,YAAA;AAAA,EACA,eAAA;AAAA,EAEA,WAAA,CAAY,kBAAiC,YAAA,EAAsB;AACjE,IAAA,KAAA,CAAM;AAAA,MACJ,OAAA,EAAS,CAAC,gBAAgB,CAAA;AAAA,MAC1B,YAAA,EAAc,iBAAiB,WAAA;AAAY,KAC5C,CAAA;AAED,IAAA,IAAA,CAAK,YAAA,GAAe,MAAA;AAEpB,IAAA,IAAA,CAAK,eAAA,GAAkB,KAAA;AAEvB,IAAA,IAAA,CAAK,aAAA,GAAgB,YAAA;AAAA,EACvB;AAAA,EAEA,WAAA,GAAoB;AAClB,IAAA,IAAI,IAAA,CAAK,iBAAiB,MAAA,EAAW;AACnC,MAAA,YAAA,CAAa,KAAK,YAAY,CAAA;AAAA,IAChC;AAAA,EACF;AAAA,EAES,UAAU,WAAA,EAAgC;AACjD,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAA;AAE1B,IAAA,MAAM,EAAA,GAAK,IAAI,WAAA,EAAY;AAE3B,IAAA,IACE,GAAA,CAAI,gBAAgB,WAAA,IACpB,QAAA,CAAS,OAAO,EAAE,CAAA,IAClB,KAAK,eAAA,EACL;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,OAAA,CAAQ,EAAA,CAAG,KAAA,EAAO,WAAW,CAAA;AAElC,IAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AAGvB,IAAA,IAAA,CAAK,YAAA,GAAe,WAAW,MAAM;AACnC,MAAA,IAAA,CAAK,eAAA,GAAkB,KAAA;AAAA,IACzB,CAAA,EAAG,KAAK,aAAa,CAAA;AAAA,EACvB;AAAA,EAES,QAAA,GAAiB;AACxB,IAAA,IAAA,CAAK,WAAA,EAAY;AAEjB,IAAA,KAAA,CAAM,QAAA,EAAS;AAAA,EACjB;AACF;;;;"}
|
|
@@ -57,5 +57,5 @@ export declare const withBufferedFrom: <A, B>(observable: Observable<B>) => Keep
|
|
|
57
57
|
* Alias for `withBufferedFrom`.
|
|
58
58
|
* @see withBufferedFrom
|
|
59
59
|
*/
|
|
60
|
-
export declare const withBuffered:
|
|
60
|
+
export declare const withBuffered: typeof withBufferedFrom;
|
|
61
61
|
//# sourceMappingURL=with-buffered-from.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"with-buffered-from.d.mts","sourceRoot":"","sources":["../../../src/core/operators/with-buffered-from.mts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,UAAU,EAGhB,MAAM,oBAAoB,CAAC;AAG5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"with-buffered-from.d.mts","sourceRoot":"","sources":["../../../src/core/operators/with-buffered-from.mts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,UAAU,EAGhB,MAAM,oBAAoB,CAAC;AAG5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,EAAE,CAAC,cACvB,UAAU,CAAC,CAAC,CAAC,KACxB,wBAAwB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,CAMQ,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,YAAY,yBAAmB,CAAC"}
|
|
@@ -3,99 +3,46 @@ import { SyncChildObservableClass } from '../class/child-observable-class.mjs';
|
|
|
3
3
|
import '../utils/id-maker.mjs';
|
|
4
4
|
import { maxDepth } from '../utils/max-depth.mjs';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* @returns An operator that emits tuples of [parentValue, bufferedValues]
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```ts
|
|
17
|
-
* // Timeline:
|
|
18
|
-
* //
|
|
19
|
-
* // data$ d1 d2 d3 d4 d5 d6 d7 d8
|
|
20
|
-
* // trigger$ T1 T2 T3
|
|
21
|
-
* // result$ [T1,[d1,d2,d3]] [T2,[d4,d5,d6]] [T3,[d7,d8]]
|
|
22
|
-
* //
|
|
23
|
-
* // Explanation:
|
|
24
|
-
* // - withBufferedFrom collects values from the source observable
|
|
25
|
-
* // - When the trigger emits, it emits a tuple of [triggerValue, bufferedValues]
|
|
26
|
-
* // - Buffer is cleared after each emission
|
|
27
|
-
* // - Useful for batching data collection triggered by events
|
|
28
|
-
*
|
|
29
|
-
* const data$ = source<string>();
|
|
30
|
-
*
|
|
31
|
-
* const trigger$ = source<number>();
|
|
32
|
-
*
|
|
33
|
-
* const result$ = trigger$.pipe(withBufferedFrom(data$));
|
|
34
|
-
*
|
|
35
|
-
* const valueHistory: (readonly [number, readonly string[]])[] = [];
|
|
36
|
-
*
|
|
37
|
-
* result$.subscribe(([triggerValue, bufferedData]) => {
|
|
38
|
-
* valueHistory.push([triggerValue, bufferedData]);
|
|
39
|
-
* });
|
|
40
|
-
*
|
|
41
|
-
* data$.next('A');
|
|
42
|
-
*
|
|
43
|
-
* data$.next('B');
|
|
44
|
-
*
|
|
45
|
-
* trigger$.next(1);
|
|
46
|
-
*
|
|
47
|
-
* assert.deepStrictEqual(valueHistory, [[1, ['A', 'B']]]);
|
|
48
|
-
*
|
|
49
|
-
* data$.next('C');
|
|
50
|
-
*
|
|
51
|
-
* trigger$.next(2);
|
|
52
|
-
*
|
|
53
|
-
* assert.deepStrictEqual(valueHistory, [
|
|
54
|
-
* [1, ['A', 'B']],
|
|
55
|
-
* [2, ['C']],
|
|
56
|
-
* ]);
|
|
57
|
-
* ```
|
|
58
|
-
*/
|
|
59
|
-
const withBufferedFrom = (observable) =>
|
|
60
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
61
|
-
((parentObservable) => new WithBufferedFromObservableClass(parentObservable, observable));
|
|
62
|
-
/**
|
|
63
|
-
* Alias for `withBufferedFrom`.
|
|
64
|
-
* @see withBufferedFrom
|
|
65
|
-
*/
|
|
6
|
+
const withBufferedFrom = (observable) => (
|
|
7
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
8
|
+
((parentObservable) => new WithBufferedFromObservableClass(
|
|
9
|
+
parentObservable,
|
|
10
|
+
observable
|
|
11
|
+
))
|
|
12
|
+
);
|
|
66
13
|
const withBuffered = withBufferedFrom;
|
|
67
14
|
class WithBufferedFromObservableClass extends SyncChildObservableClass {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
#clearBuffer() {
|
|
97
|
-
this.#mut_bufferedValues = [];
|
|
15
|
+
#mut_bufferedValues = [];
|
|
16
|
+
constructor(parentObservable, observable) {
|
|
17
|
+
super({
|
|
18
|
+
parents: [parentObservable],
|
|
19
|
+
depth: 1 + maxDepth([parentObservable, observable]),
|
|
20
|
+
initialValue: pipe({
|
|
21
|
+
par: parentObservable.getSnapshot(),
|
|
22
|
+
me: observable.getSnapshot()
|
|
23
|
+
}).map(
|
|
24
|
+
({ par, me }) => Optional.isNone(par) ? Optional.none : Optional.some([
|
|
25
|
+
par.value,
|
|
26
|
+
Optional.isNone(me) ? [] : [me.value]
|
|
27
|
+
])
|
|
28
|
+
).value
|
|
29
|
+
});
|
|
30
|
+
observable.subscribe((value) => {
|
|
31
|
+
this.#mut_bufferedValues = Arr.toPushed(this.#mut_bufferedValues, value);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
#clearBuffer() {
|
|
35
|
+
this.#mut_bufferedValues = [];
|
|
36
|
+
}
|
|
37
|
+
tryUpdate(updateToken) {
|
|
38
|
+
const par = this.parents[0];
|
|
39
|
+
const sn = par.getSnapshot();
|
|
40
|
+
if (par.updateToken !== updateToken || Optional.isNone(sn)) {
|
|
41
|
+
return;
|
|
98
42
|
}
|
|
43
|
+
this.setNext([sn.value, this.#mut_bufferedValues], updateToken);
|
|
44
|
+
this.#clearBuffer();
|
|
45
|
+
}
|
|
99
46
|
}
|
|
100
47
|
|
|
101
48
|
export { withBuffered, withBufferedFrom };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"with-buffered-from.mjs","sources":["../../../src/core/operators/with-buffered-from.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"with-buffered-from.mjs","sources":["../../../src/core/operators/with-buffered-from.mts"],"sourcesContent":["import { Arr, Optional, pipe } from 'ts-data-forge';\nimport { SyncChildObservableClass } from '../class/index.mjs';\nimport {\n type KeepInitialValueOperator,\n type Observable,\n type UpdateToken,\n type WithBufferedFromOperatorObservable,\n} from '../types/index.mjs';\nimport { maxDepth } from '../utils/index.mjs';\n\n/**\n * Buffers values from the source observable and emits them along with the parent value\n * when the parent emits. The buffer is cleared after each emission.\n *\n * @template A - The type of values from the parent observable\n * @template B - The type of values from the source observable\n * @param observable - The observable whose values will be buffered\n * @returns An operator that emits tuples of [parentValue, bufferedValues]\n *\n * @example\n * ```ts\n * // Timeline:\n * //\n * // data$ d1 d2 d3 d4 d5 d6 d7 d8\n * // trigger$ T1 T2 T3\n * // result$ [T1,[d1,d2,d3]] [T2,[d4,d5,d6]] [T3,[d7,d8]]\n * //\n * // Explanation:\n * // - withBufferedFrom collects values from the source observable\n * // - When the trigger emits, it emits a tuple of [triggerValue, bufferedValues]\n * // - Buffer is cleared after each emission\n * // - Useful for batching data collection triggered by events\n *\n * const data$ = source<string>();\n *\n * const trigger$ = source<number>();\n *\n * const result$ = trigger$.pipe(withBufferedFrom(data$));\n *\n * const valueHistory: (readonly [number, readonly string[]])[] = [];\n *\n * result$.subscribe(([triggerValue, bufferedData]) => {\n * valueHistory.push([triggerValue, bufferedData]);\n * });\n *\n * data$.next('A');\n *\n * data$.next('B');\n *\n * trigger$.next(1);\n *\n * assert.deepStrictEqual(valueHistory, [[1, ['A', 'B']]]);\n *\n * data$.next('C');\n *\n * trigger$.next(2);\n *\n * assert.deepStrictEqual(valueHistory, [\n * [1, ['A', 'B']],\n * [2, ['C']],\n * ]);\n * ```\n */\nexport const withBufferedFrom = <A, B>(\n observable: Observable<B>,\n): KeepInitialValueOperator<A, readonly [A, readonly B[]]> =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n ((parentObservable) =>\n new WithBufferedFromObservableClass(\n parentObservable,\n observable,\n )) as KeepInitialValueOperator<A, readonly [A, readonly B[]]>;\n\n/**\n * Alias for `withBufferedFrom`.\n * @see withBufferedFrom\n */\nexport const withBuffered = withBufferedFrom;\n\nclass WithBufferedFromObservableClass<A, B>\n extends SyncChildObservableClass<readonly [A, readonly B[]], readonly [A]>\n implements WithBufferedFromOperatorObservable<A, B>\n{\n #mut_bufferedValues: readonly B[] = [];\n\n constructor(parentObservable: Observable<A>, observable: Observable<B>) {\n super({\n parents: [parentObservable],\n depth: 1 + maxDepth([parentObservable, observable]),\n initialValue: pipe({\n par: parentObservable.getSnapshot(),\n me: observable.getSnapshot(),\n }).map(({ par, me }) =>\n Optional.isNone(par)\n ? Optional.none\n : Optional.some([\n par.value,\n Optional.isNone(me) ? [] : [me.value],\n ] as const),\n ).value,\n });\n\n observable.subscribe((value) => {\n this.#mut_bufferedValues = Arr.toPushed(this.#mut_bufferedValues, value);\n });\n }\n\n #clearBuffer(): void {\n this.#mut_bufferedValues = [];\n }\n\n override tryUpdate(updateToken: UpdateToken): void {\n const par = this.parents[0];\n\n const sn = par.getSnapshot();\n\n if (par.updateToken !== updateToken || Optional.isNone(sn)) {\n return; // skip update\n }\n\n this.setNext([sn.value, this.#mut_bufferedValues], updateToken);\n\n this.#clearBuffer();\n }\n}\n"],"names":[],"mappings":";;;;;AA+DO,MAAM,mBAAmB,CAC9B,UAAA;AAAA;AAAA,GAGC,CAAC,qBACA,IAAI,+BAAA;AAAA,IACF,gBAAA;AAAA,IACA;AAAA,GACF;AAAA;AAMG,MAAM,YAAA,GAAe;AAE5B,MAAM,wCACI,wBAAA,CAEV;AAAA,EACE,sBAAoC,EAAC;AAAA,EAErC,WAAA,CAAY,kBAAiC,UAAA,EAA2B;AACtE,IAAA,KAAA,CAAM;AAAA,MACJ,OAAA,EAAS,CAAC,gBAAgB,CAAA;AAAA,MAC1B,OAAO,CAAA,GAAI,QAAA,CAAS,CAAC,gBAAA,EAAkB,UAAU,CAAC,CAAA;AAAA,MAClD,cAAc,IAAA,CAAK;AAAA,QACjB,GAAA,EAAK,iBAAiB,WAAA,EAAY;AAAA,QAClC,EAAA,EAAI,WAAW,WAAA;AAAY,OAC5B,CAAA,CAAE,GAAA;AAAA,QAAI,CAAC,EAAE,GAAA,EAAK,EAAA,EAAG,KAChB,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,GACf,QAAA,CAAS,IAAA,GACT,QAAA,CAAS,IAAA,CAAK;AAAA,UACZ,GAAA,CAAI,KAAA;AAAA,UACJ,QAAA,CAAS,OAAO,EAAE,CAAA,GAAI,EAAC,GAAI,CAAC,GAAG,KAAK;AAAA,SAC5B;AAAA,OAChB,CAAE;AAAA,KACH,CAAA;AAED,IAAA,UAAA,CAAW,SAAA,CAAU,CAAC,KAAA,KAAU;AAC9B,MAAA,IAAA,CAAK,mBAAA,GAAsB,GAAA,CAAI,QAAA,CAAS,IAAA,CAAK,qBAAqB,KAAK,CAAA;AAAA,IACzE,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,YAAA,GAAqB;AACnB,IAAA,IAAA,CAAK,sBAAsB,EAAC;AAAA,EAC9B;AAAA,EAES,UAAU,WAAA,EAAgC;AACjD,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAA;AAE1B,IAAA,MAAM,EAAA,GAAK,IAAI,WAAA,EAAY;AAE3B,IAAA,IAAI,IAAI,WAAA,KAAgB,WAAA,IAAe,QAAA,CAAS,MAAA,CAAO,EAAE,CAAA,EAAG;AAC1D,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,QAAQ,CAAC,EAAA,CAAG,OAAO,IAAA,CAAK,mBAAmB,GAAG,WAAW,CAAA;AAE9D,IAAA,IAAA,CAAK,YAAA,EAAa;AAAA,EACpB;AACF;;;;"}
|
|
@@ -60,5 +60,5 @@ export declare const withCurrentValueFrom: <A, B>(observable: Observable<B>) =>
|
|
|
60
60
|
* Alias for `withCurrentValueFrom`.
|
|
61
61
|
* @see withCurrentValueFrom
|
|
62
62
|
*/
|
|
63
|
-
export declare const withLatestFrom:
|
|
63
|
+
export declare const withLatestFrom: typeof withCurrentValueFrom;
|
|
64
64
|
//# sourceMappingURL=with-current-value-from.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"with-current-value-from.d.mts","sourceRoot":"","sources":["../../../src/core/operators/with-current-value-from.mts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,UAAU,EAGhB,MAAM,oBAAoB,CAAC;AAG5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,eAAO,MAAM,oBAAoB,GAC9B,CAAC,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"with-current-value-from.d.mts","sourceRoot":"","sources":["../../../src/core/operators/with-current-value-from.mts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,UAAU,EAGhB,MAAM,oBAAoB,CAAC;AAG5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,eAAO,MAAM,oBAAoB,GAC9B,CAAC,EAAE,CAAC,cACS,UAAU,CAAC,CAAC,CAAC,KACxB,wBAAwB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAEyB,CAAC;AAE1E;;;GAGG;AACH,eAAO,MAAM,cAAc,6BAAuB,CAAC"}
|
|
@@ -3,94 +3,33 @@ import { SyncChildObservableClass } from '../class/child-observable-class.mjs';
|
|
|
3
3
|
import '../utils/id-maker.mjs';
|
|
4
4
|
import { maxDepth } from '../utils/max-depth.mjs';
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Samples the current value from another observable each time the source emits.
|
|
8
|
-
* Emits a tuple of [sourceValue, sampledValue].
|
|
9
|
-
*
|
|
10
|
-
* @template A - The type of values from the source observable
|
|
11
|
-
* @template B - The type of values from the sampled observable
|
|
12
|
-
* @param observable - The observable to sample from
|
|
13
|
-
* @returns An operator that emits tuples of source and sampled values
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```ts
|
|
17
|
-
* // Timeline:
|
|
18
|
-
* //
|
|
19
|
-
* // name$ "Alice" "Bob" "Charlie"
|
|
20
|
-
* // age$ 25 30
|
|
21
|
-
* // result$ (skip) ["Bob",25] ["Charlie",30]
|
|
22
|
-
* //
|
|
23
|
-
* // Explanation:
|
|
24
|
-
* // - withCurrentValueFrom samples the current value from another observable
|
|
25
|
-
* // - Emits a tuple [sourceValue, sampledValue] each time the SOURCE emits
|
|
26
|
-
* // - Does NOT emit when the sampled observable (age$) emits
|
|
27
|
-
* // - Does not emit until both observables have emitted at least once
|
|
28
|
-
* // - "Alice" is skipped because age$ hasn't emitted yet
|
|
29
|
-
*
|
|
30
|
-
* const name$ = source<string>();
|
|
31
|
-
*
|
|
32
|
-
* const age$ = source<number>();
|
|
33
|
-
*
|
|
34
|
-
* const result$ = name$.pipe(withCurrentValueFrom(age$));
|
|
35
|
-
*
|
|
36
|
-
* const valueHistory: (readonly [string, number])[] = [];
|
|
37
|
-
*
|
|
38
|
-
* result$.subscribe(([name_, currentAge]) => {
|
|
39
|
-
* valueHistory.push([name_, currentAge]);
|
|
40
|
-
* });
|
|
41
|
-
*
|
|
42
|
-
* name$.next('Alice'); // nothing logged (age$ hasn't emitted)
|
|
43
|
-
*
|
|
44
|
-
* assert.deepStrictEqual(valueHistory, []);
|
|
45
|
-
*
|
|
46
|
-
* age$.next(25);
|
|
47
|
-
*
|
|
48
|
-
* name$.next('Bob'); // logs: Bob is 25 years old
|
|
49
|
-
*
|
|
50
|
-
* assert.deepStrictEqual(valueHistory, [['Bob', 25]]);
|
|
51
|
-
*
|
|
52
|
-
* age$.next(30);
|
|
53
|
-
*
|
|
54
|
-
* name$.next('Charlie'); // logs: Charlie is 30 years old
|
|
55
|
-
*
|
|
56
|
-
* assert.deepStrictEqual(valueHistory, [
|
|
57
|
-
* ['Bob', 25],
|
|
58
|
-
* ['Charlie', 30],
|
|
59
|
-
* ]);
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
6
|
const withCurrentValueFrom = (observable) => (parentObservable) => new WithCurrentValueFromObservableClass(parentObservable, observable);
|
|
63
|
-
/**
|
|
64
|
-
* Alias for `withCurrentValueFrom`.
|
|
65
|
-
* @see withCurrentValueFrom
|
|
66
|
-
*/
|
|
67
7
|
const withLatestFrom = withCurrentValueFrom;
|
|
68
8
|
class WithCurrentValueFromObservableClass extends SyncChildObservableClass {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
const curr = this.#observable.getSnapshot();
|
|
90
|
-
if (Optional.isNone(curr))
|
|
91
|
-
return; // skip update
|
|
92
|
-
this.setNext([ps.value, curr.value], updateToken);
|
|
9
|
+
#observable;
|
|
10
|
+
constructor(parentObservable, observable) {
|
|
11
|
+
super({
|
|
12
|
+
parents: [parentObservable],
|
|
13
|
+
depth: 1 + maxDepth([parentObservable, observable]),
|
|
14
|
+
initialValue: pipe({
|
|
15
|
+
par: parentObservable.getSnapshot(),
|
|
16
|
+
me: observable.getSnapshot()
|
|
17
|
+
}).map(
|
|
18
|
+
({ me, par }) => Optional.isNone(par) || Optional.isNone(me) ? Optional.none : Optional.some([par.value, me.value])
|
|
19
|
+
).value
|
|
20
|
+
});
|
|
21
|
+
this.#observable = observable;
|
|
22
|
+
}
|
|
23
|
+
tryUpdate(updateToken) {
|
|
24
|
+
const par = this.parents[0];
|
|
25
|
+
const ps = par.getSnapshot();
|
|
26
|
+
if (par.updateToken !== updateToken || Optional.isNone(ps)) {
|
|
27
|
+
return;
|
|
93
28
|
}
|
|
29
|
+
const curr = this.#observable.getSnapshot();
|
|
30
|
+
if (Optional.isNone(curr)) return;
|
|
31
|
+
this.setNext([ps.value, curr.value], updateToken);
|
|
32
|
+
}
|
|
94
33
|
}
|
|
95
34
|
|
|
96
35
|
export { withCurrentValueFrom, withLatestFrom };
|