synstate 1.0.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -10
- 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 +16 -16
- 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
|
@@ -3,21 +3,18 @@ import '../utils/id-maker.mjs';
|
|
|
3
3
|
import { RootObservableClass } from '../class/root-observable-class.mjs';
|
|
4
4
|
|
|
5
5
|
function source(...args) {
|
|
6
|
-
|
|
6
|
+
return new SourceObservableClass(...args);
|
|
7
7
|
}
|
|
8
8
|
class SourceObservableClass extends RootObservableClass {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return;
|
|
19
|
-
this.startUpdate(nextValue);
|
|
20
|
-
}
|
|
9
|
+
constructor(...args) {
|
|
10
|
+
super({
|
|
11
|
+
initialValue: Arr.isNonEmpty(args) ? Optional.some(args[0]) : Optional.none
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
next(nextValue) {
|
|
15
|
+
if (this.isCompleted) return;
|
|
16
|
+
this.startUpdate(nextValue);
|
|
17
|
+
}
|
|
21
18
|
}
|
|
22
19
|
|
|
23
20
|
export { source };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.mjs","sources":["../../../src/core/create/source.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"source.mjs","sources":["../../../src/core/create/source.mts"],"sourcesContent":["import { Arr, Optional } from 'ts-data-forge';\nimport { RootObservableClass } from '../class/index.mjs';\nimport {\n type InitializedSourceObservable,\n type SourceObservable,\n} from '../types/index.mjs';\n\n/**\n * Creates a new Observable source that can manually emit values.\n * This is the primary way to create root observables that start reactive chains.\n *\n * @template A - The type of values emitted by the source\n * @returns A SourceObservable that can emit values via `.next()` method\n *\n * @example\n * ```ts\n * // Timeline:\n * //\n * // count$ 1 2 3 ...\n * //\n * // Explanation:\n * // - source creates a new observable that you can manually emit values to\n * // - Use .next() to emit values\n * // - Foundation for building custom observables\n *\n * const count$ = source<number>();\n *\n * const valueHistory: number[] = [];\n *\n * count$.subscribe((value) => {\n * valueHistory.push(value);\n * });\n *\n * count$.next(1); // logs: 1\n *\n * assert.deepStrictEqual(valueHistory, [1]);\n *\n * count$.next(2); // logs: 2\n *\n * assert.deepStrictEqual(valueHistory, [1, 2]);\n *\n * count$.next(3); // logs: 3\n *\n * assert.deepStrictEqual(valueHistory, [1, 2, 3]);\n * ```\n */\nexport function source<const A>(\n initialValue: A,\n): InitializedSourceObservable<A>;\n\nexport function source<const A>(): SourceObservable<A>;\n\nexport function source<const A>(...args: readonly A[]): SourceObservable<A> {\n return new SourceObservableClass<A>(...args);\n}\n\nclass SourceObservableClass<A>\n extends RootObservableClass<A>\n implements SourceObservable<A>\n{\n constructor(...args: readonly A[]) {\n super({\n initialValue: Arr.isNonEmpty(args)\n ? Optional.some(args[0])\n : Optional.none,\n });\n }\n\n next(nextValue: A): void {\n if (this.isCompleted) return;\n\n this.startUpdate(nextValue);\n }\n}\n"],"names":[],"mappings":";;;;AAoDO,SAAS,UAAmB,IAAA,EAAyC;AAC1E,EAAA,OAAO,IAAI,qBAAA,CAAyB,GAAG,IAAI,CAAA;AAC7C;AAEA,MAAM,8BACI,mBAAA,CAEV;AAAA,EACE,eAAe,IAAA,EAAoB;AACjC,IAAA,KAAA,CAAM;AAAA,MACJ,YAAA,EAAc,GAAA,CAAI,UAAA,CAAW,IAAI,CAAA,GAC7B,QAAA,CAAS,IAAA,CAAK,IAAA,CAAK,CAAC,CAAC,CAAA,GACrB,QAAA,CAAS;AAAA,KACd,CAAA;AAAA,EACH;AAAA,EAEA,KAAK,SAAA,EAAoB;AACvB,IAAA,IAAI,KAAK,WAAA,EAAa;AAEtB,IAAA,IAAA,CAAK,YAAY,SAAS,CAAA;AAAA,EAC5B;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timer.d.mts","sourceRoot":"","sources":["../../../src/core/create/timer.mts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"timer.d.mts","sourceRoot":"","sources":["../../../src/core/create/timer.mts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,KAAK,iBACF,MAAM,YACV,QAAQ,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC,KACD,eACsE,CAAC"}
|
|
@@ -2,80 +2,44 @@ import { Optional } from 'ts-data-forge';
|
|
|
2
2
|
import '../utils/id-maker.mjs';
|
|
3
3
|
import { RootObservableClass } from '../class/root-observable-class.mjs';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Creates an observable that emits 0 after a specified delay and then completes.
|
|
7
|
-
*
|
|
8
|
-
* @param milliSeconds - The delay in milliseconds before emission
|
|
9
|
-
* @param startManually - If true, waits for manual start (default: false)
|
|
10
|
-
* @returns An observable that emits after delay
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* // Timeline:
|
|
15
|
-
* //
|
|
16
|
-
* // Time(ms) 0 ... 1000
|
|
17
|
-
* // delayed$ X (emits and completes)
|
|
18
|
-
* //
|
|
19
|
-
* // Explanation:
|
|
20
|
-
* // - timer emits once after the specified delay, then completes
|
|
21
|
-
* // - Useful for delayed actions or timeouts
|
|
22
|
-
*
|
|
23
|
-
* const delayed$ = timer(100);
|
|
24
|
-
*
|
|
25
|
-
* const valueHistory: number[] = [];
|
|
26
|
-
*
|
|
27
|
-
* await new Promise<void>((resolve) => {
|
|
28
|
-
* delayed$.subscribe(
|
|
29
|
-
* () => {
|
|
30
|
-
* valueHistory.push(1);
|
|
31
|
-
* },
|
|
32
|
-
* () => {
|
|
33
|
-
* resolve();
|
|
34
|
-
* },
|
|
35
|
-
* );
|
|
36
|
-
* });
|
|
37
|
-
*
|
|
38
|
-
* assert.deepStrictEqual(valueHistory, [1]);
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
5
|
const timer = (milliSeconds, options) => new TimerObservableClass(milliSeconds, options?.startManually ?? false);
|
|
42
6
|
class TimerObservableClass extends RootObservableClass {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
7
|
+
#milliSeconds;
|
|
8
|
+
#mut_timerId;
|
|
9
|
+
#mut_isStarted;
|
|
10
|
+
constructor(milliSeconds, startManually) {
|
|
11
|
+
super({ initialValue: Optional.none });
|
|
12
|
+
this.#milliSeconds = milliSeconds;
|
|
13
|
+
this.#mut_timerId = void 0;
|
|
14
|
+
this.#mut_isStarted = false;
|
|
15
|
+
if (!startManually) {
|
|
16
|
+
this.start();
|
|
54
17
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
this.#mut_isStarted = true;
|
|
61
|
-
if (this.isCompleted) {
|
|
62
|
-
console.warn('cannot restart stopped TimerObservable');
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
this.#mut_timerId = setTimeout(() => {
|
|
66
|
-
this.startUpdate(0);
|
|
67
|
-
this.complete();
|
|
68
|
-
}, this.#milliSeconds);
|
|
18
|
+
}
|
|
19
|
+
#resetTimer() {
|
|
20
|
+
if (this.#mut_timerId !== void 0) {
|
|
21
|
+
clearTimeout(this.#mut_timerId);
|
|
69
22
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
23
|
+
}
|
|
24
|
+
start() {
|
|
25
|
+
if (this.#mut_isStarted) {
|
|
26
|
+
console.warn("cannot start twice");
|
|
27
|
+
return;
|
|
74
28
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
29
|
+
this.#mut_isStarted = true;
|
|
30
|
+
if (this.isCompleted) {
|
|
31
|
+
console.warn("cannot restart stopped TimerObservable");
|
|
32
|
+
return;
|
|
78
33
|
}
|
|
34
|
+
this.#mut_timerId = setTimeout(() => {
|
|
35
|
+
this.startUpdate(0);
|
|
36
|
+
this.complete();
|
|
37
|
+
}, this.#milliSeconds);
|
|
38
|
+
}
|
|
39
|
+
complete() {
|
|
40
|
+
this.#resetTimer();
|
|
41
|
+
super.complete();
|
|
42
|
+
}
|
|
79
43
|
}
|
|
80
44
|
|
|
81
45
|
export { timer };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timer.mjs","sources":["../../../src/core/create/timer.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"timer.mjs","sources":["../../../src/core/create/timer.mts"],"sourcesContent":["import { Optional } from 'ts-data-forge';\nimport { RootObservableClass } from '../class/index.mjs';\nimport { type TimerId, type TimerObservable } from '../types/index.mjs';\n\n/**\n * Creates an observable that emits 0 after a specified delay and then completes.\n *\n * @param milliSeconds - The delay in milliseconds before emission\n * @param startManually - If true, waits for manual start (default: false)\n * @returns An observable that emits after delay\n *\n * @example\n * ```ts\n * // Timeline:\n * //\n * // Time(ms) 0 ... 1000\n * // delayed$ X (emits and completes)\n * //\n * // Explanation:\n * // - timer emits once after the specified delay, then completes\n * // - Useful for delayed actions or timeouts\n *\n * const delayed$ = timer(100);\n *\n * const valueHistory: number[] = [];\n *\n * await new Promise<void>((resolve) => {\n * delayed$.subscribe(\n * () => {\n * valueHistory.push(1);\n * },\n * () => {\n * resolve();\n * },\n * );\n * });\n *\n * assert.deepStrictEqual(valueHistory, [1]);\n * ```\n */\nexport const timer = (\n milliSeconds: number,\n options?: Readonly<{\n startManually?: boolean;\n }>,\n): TimerObservable =>\n new TimerObservableClass(milliSeconds, options?.startManually ?? false);\n\nclass TimerObservableClass\n extends RootObservableClass<0>\n implements TimerObservable\n{\n readonly #milliSeconds: number;\n #mut_timerId: TimerId | undefined;\n #mut_isStarted: boolean;\n\n constructor(milliSeconds: number, startManually: boolean) {\n super({ initialValue: Optional.none });\n\n this.#milliSeconds = milliSeconds;\n\n this.#mut_timerId = undefined;\n\n this.#mut_isStarted = false;\n\n if (!startManually) {\n this.start();\n }\n }\n\n #resetTimer(): void {\n if (this.#mut_timerId !== undefined) {\n clearTimeout(this.#mut_timerId);\n }\n }\n\n start(): void {\n if (this.#mut_isStarted) {\n console.warn('cannot start twice');\n\n return;\n }\n\n this.#mut_isStarted = true;\n\n if (this.isCompleted) {\n console.warn('cannot restart stopped TimerObservable');\n\n return;\n }\n\n this.#mut_timerId = setTimeout(() => {\n this.startUpdate(0);\n\n this.complete();\n }, this.#milliSeconds);\n }\n\n override complete(): void {\n this.#resetTimer();\n\n super.complete();\n }\n}\n"],"names":[],"mappings":";;;;AAwCO,MAAM,KAAA,GAAQ,CACnB,YAAA,EACA,OAAA,KAIA,IAAI,oBAAA,CAAqB,YAAA,EAAc,OAAA,EAAS,aAAA,IAAiB,KAAK;AAExE,MAAM,6BACI,mBAAA,CAEV;AAAA,EACW,aAAA;AAAA,EACT,YAAA;AAAA,EACA,cAAA;AAAA,EAEA,WAAA,CAAY,cAAsB,aAAA,EAAwB;AACxD,IAAA,KAAA,CAAM,EAAE,YAAA,EAAc,QAAA,CAAS,IAAA,EAAM,CAAA;AAErC,IAAA,IAAA,CAAK,aAAA,GAAgB,YAAA;AAErB,IAAA,IAAA,CAAK,YAAA,GAAe,MAAA;AAEpB,IAAA,IAAA,CAAK,cAAA,GAAiB,KAAA;AAEtB,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA,IAAA,CAAK,KAAA,EAAM;AAAA,IACb;AAAA,EACF;AAAA,EAEA,WAAA,GAAoB;AAClB,IAAA,IAAI,IAAA,CAAK,iBAAiB,MAAA,EAAW;AACnC,MAAA,YAAA,CAAa,KAAK,YAAY,CAAA;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAI,KAAK,cAAA,EAAgB;AACvB,MAAA,OAAA,CAAQ,KAAK,oBAAoB,CAAA;AAEjC,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AAEtB,IAAA,IAAI,KAAK,WAAA,EAAa;AACpB,MAAA,OAAA,CAAQ,KAAK,wCAAwC,CAAA;AAErD,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,YAAA,GAAe,WAAW,MAAM;AACnC,MAAA,IAAA,CAAK,YAAY,CAAC,CAAA;AAElB,MAAA,IAAA,CAAK,QAAA,EAAS;AAAA,IAChB,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;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.mts","sourceRoot":"","sources":["../../../src/core/operators/audit.mts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,wBAAwB,EAI9B,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6FG;AACH,eAAO,MAAM,KAAK,GAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"audit.d.mts","sourceRoot":"","sources":["../../../src/core/operators/audit.mts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,wBAAwB,EAI9B,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6FG;AACH,eAAO,MAAM,KAAK,GAAI,CAAC,gBACP,MAAM,KACnB,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAMQ,CAAC"}
|
|
@@ -2,142 +2,48 @@ import { Optional } from 'ts-data-forge';
|
|
|
2
2
|
import { AsyncChildObservableClass } from '../class/child-observable-class.mjs';
|
|
3
3
|
import '../utils/id-maker.mjs';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* @returns An operator that audits emissions from the observable
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* // Timeline (250ms audit):
|
|
17
|
-
* //
|
|
18
|
-
* // 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
|
|
19
|
-
* //
|
|
20
|
-
* // input$ 0 2 3 9 10 11 12 13 14
|
|
21
|
-
* // |- 250ms -> |- 250ms -> |- 250ms -> |- 250ms ->
|
|
22
|
-
* // audited$ 2 3 11 14 (emitted at end of window)
|
|
23
|
-
* //
|
|
24
|
-
* // Explanation:
|
|
25
|
-
* // - audit emits the LAST value received during each time window
|
|
26
|
-
* // - Unlike throttle (which emits the FIRST value), audit emits the LAST
|
|
27
|
-
* // - Useful when you want the most recent value after a burst of events
|
|
28
|
-
*
|
|
29
|
-
* const input$ = source<number>();
|
|
30
|
-
*
|
|
31
|
-
* const audited$ = input$.pipe(audit(250));
|
|
32
|
-
*
|
|
33
|
-
* const valueHistory: number[] = [];
|
|
34
|
-
*
|
|
35
|
-
* audited$.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
|
-
* await sleep(200);
|
|
47
|
-
*
|
|
48
|
-
* input$.next(2);
|
|
49
|
-
*
|
|
50
|
-
* assert.deepStrictEqual(valueHistory, []);
|
|
51
|
-
*
|
|
52
|
-
* await sleep(100);
|
|
53
|
-
*
|
|
54
|
-
* assert.deepStrictEqual(valueHistory, [2]);
|
|
55
|
-
*
|
|
56
|
-
* input$.next(3);
|
|
57
|
-
*
|
|
58
|
-
* await sleep(300);
|
|
59
|
-
*
|
|
60
|
-
* assert.deepStrictEqual(valueHistory, [2, 3]);
|
|
61
|
-
*
|
|
62
|
-
* await sleep(300);
|
|
63
|
-
*
|
|
64
|
-
* input$.next(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, [2, 3]);
|
|
75
|
-
*
|
|
76
|
-
* await sleep(100);
|
|
77
|
-
*
|
|
78
|
-
* assert.deepStrictEqual(valueHistory, [2, 3, 11]);
|
|
79
|
-
*
|
|
80
|
-
* input$.next(12);
|
|
81
|
-
*
|
|
82
|
-
* await sleep(100);
|
|
83
|
-
*
|
|
84
|
-
* input$.next(13);
|
|
85
|
-
*
|
|
86
|
-
* assert.deepStrictEqual(valueHistory, [2, 3, 11]);
|
|
87
|
-
*
|
|
88
|
-
* await sleep(100);
|
|
89
|
-
*
|
|
90
|
-
* input$.next(14);
|
|
91
|
-
*
|
|
92
|
-
* assert.deepStrictEqual(valueHistory, [2, 3, 11]);
|
|
93
|
-
*
|
|
94
|
-
* await sleep(100);
|
|
95
|
-
*
|
|
96
|
-
* assert.deepStrictEqual(valueHistory, [2, 3, 11, 14]);
|
|
97
|
-
* ```
|
|
98
|
-
*/
|
|
99
|
-
const audit = (milliSeconds) =>
|
|
100
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
101
|
-
((parentObservable) => new AuditObservableClass(parentObservable, milliSeconds));
|
|
5
|
+
const audit = (milliSeconds) => (
|
|
6
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
7
|
+
((parentObservable) => new AuditObservableClass(
|
|
8
|
+
parentObservable,
|
|
9
|
+
milliSeconds
|
|
10
|
+
))
|
|
11
|
+
);
|
|
102
12
|
class AuditObservableClass extends AsyncChildObservableClass {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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_isSkipping = false;
|
|
22
|
+
this.#mut_timerId = void 0;
|
|
23
|
+
this.#milliSeconds = milliSeconds;
|
|
24
|
+
}
|
|
25
|
+
#resetTimer() {
|
|
26
|
+
if (this.#mut_timerId !== void 0) {
|
|
27
|
+
clearTimeout(this.#mut_timerId);
|
|
114
28
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return; // skip update
|
|
121
|
-
}
|
|
122
|
-
// set timer
|
|
123
|
-
this.#mut_isSkipping = true;
|
|
124
|
-
this.#mut_timerId = setTimeout(() => {
|
|
125
|
-
const sn = par.getSnapshot();
|
|
126
|
-
if (Optional.isNone(sn))
|
|
127
|
-
return;
|
|
128
|
-
this.startUpdate(sn.value);
|
|
129
|
-
this.#mut_isSkipping = false;
|
|
130
|
-
}, this.#milliSeconds);
|
|
131
|
-
}
|
|
132
|
-
#resetTimer() {
|
|
133
|
-
if (this.#mut_timerId !== undefined) {
|
|
134
|
-
clearTimeout(this.#mut_timerId);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
complete() {
|
|
138
|
-
this.#resetTimer();
|
|
139
|
-
super.complete();
|
|
29
|
+
}
|
|
30
|
+
tryUpdate(updateToken) {
|
|
31
|
+
const par = this.parents[0];
|
|
32
|
+
if (par.updateToken !== updateToken || Optional.isNone(par.getSnapshot()) || this.#mut_isSkipping) {
|
|
33
|
+
return;
|
|
140
34
|
}
|
|
35
|
+
this.#mut_isSkipping = true;
|
|
36
|
+
this.#mut_timerId = setTimeout(() => {
|
|
37
|
+
const sn = par.getSnapshot();
|
|
38
|
+
if (Optional.isNone(sn)) return;
|
|
39
|
+
this.startUpdate(sn.value);
|
|
40
|
+
this.#mut_isSkipping = false;
|
|
41
|
+
}, this.#milliSeconds);
|
|
42
|
+
}
|
|
43
|
+
complete() {
|
|
44
|
+
this.#resetTimer();
|
|
45
|
+
super.complete();
|
|
46
|
+
}
|
|
141
47
|
}
|
|
142
48
|
|
|
143
49
|
export { audit };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.mjs","sources":["../../../src/core/operators/audit.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"audit.mjs","sources":["../../../src/core/operators/audit.mts"],"sourcesContent":["import { Optional } from 'ts-data-forge';\nimport { AsyncChildObservableClass } from '../class/index.mjs';\nimport {\n type AuditOperatorObservable,\n type KeepInitialValueOperator,\n type Observable,\n type TimerId,\n type UpdateToken,\n} from '../types/index.mjs';\n\n/**\n * Ignores source values for duration milliseconds, then emits the most recent value from the source Observable, then repeats this process.\n *\n * Unlike `throttle` which emits the first value, `audit` emits the last value.\n *\n * @template A - The type of values from the source\n * @param milliSeconds - The audit time window in milliseconds\n * @returns An operator that audits emissions from the observable\n *\n * @example\n * ```ts\n * // Timeline (250ms audit):\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 * // audited$ 2 3 11 14 (emitted at end of window)\n * //\n * // Explanation:\n * // - audit emits the LAST value received during each time window\n * // - Unlike throttle (which emits the FIRST value), audit emits the LAST\n * // - Useful when you want the most recent value after a burst of events\n *\n * const input$ = source<number>();\n *\n * const audited$ = input$.pipe(audit(250));\n *\n * const valueHistory: number[] = [];\n *\n * audited$.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 * await sleep(200);\n *\n * input$.next(2);\n *\n * assert.deepStrictEqual(valueHistory, []);\n *\n * await sleep(100);\n *\n * assert.deepStrictEqual(valueHistory, [2]);\n *\n * input$.next(3);\n *\n * await sleep(300);\n *\n * assert.deepStrictEqual(valueHistory, [2, 3]);\n *\n * await sleep(300);\n *\n * input$.next(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, [2, 3]);\n *\n * await sleep(100);\n *\n * assert.deepStrictEqual(valueHistory, [2, 3, 11]);\n *\n * input$.next(12);\n *\n * await sleep(100);\n *\n * input$.next(13);\n *\n * assert.deepStrictEqual(valueHistory, [2, 3, 11]);\n *\n * await sleep(100);\n *\n * input$.next(14);\n *\n * assert.deepStrictEqual(valueHistory, [2, 3, 11]);\n *\n * await sleep(100);\n *\n * assert.deepStrictEqual(valueHistory, [2, 3, 11, 14]);\n * ```\n */\nexport const audit = <A,>(\n milliSeconds: number,\n): KeepInitialValueOperator<A, A> =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n ((parentObservable) =>\n new AuditObservableClass(\n parentObservable,\n milliSeconds,\n )) as KeepInitialValueOperator<A, A>;\n\nclass AuditObservableClass<A>\n extends AsyncChildObservableClass<A, readonly [A]>\n implements AuditOperatorObservable<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_isSkipping = false;\n\n this.#mut_timerId = undefined;\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 if (\n par.updateToken !== updateToken ||\n Optional.isNone(par.getSnapshot()) ||\n this.#mut_isSkipping\n ) {\n return; // skip update\n }\n\n // set timer\n this.#mut_isSkipping = true;\n\n this.#mut_timerId = setTimeout(() => {\n const sn = par.getSnapshot();\n\n if (Optional.isNone(sn)) return;\n\n this.startUpdate(sn.value);\n\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":";;;;AAwGO,MAAM,QAAQ,CACnB,YAAA;AAAA;AAAA,GAGC,CAAC,qBACA,IAAI,oBAAA;AAAA,IACF,gBAAA;AAAA,IACA;AAAA,GACF;AAAA;AAEJ,MAAM,6BACI,yBAAA,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,eAAA,GAAkB,KAAA;AAEvB,IAAA,IAAA,CAAK,YAAA,GAAe,MAAA;AAEpB,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,IACE,GAAA,CAAI,WAAA,KAAgB,WAAA,IACpB,QAAA,CAAS,MAAA,CAAO,IAAI,WAAA,EAAa,CAAA,IACjC,IAAA,CAAK,eAAA,EACL;AACA,MAAA;AAAA,IACF;AAGA,IAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AAEvB,IAAA,IAAA,CAAK,YAAA,GAAe,WAAW,MAAM;AACnC,MAAA,MAAM,EAAA,GAAK,IAAI,WAAA,EAAY;AAE3B,MAAA,IAAI,QAAA,CAAS,MAAA,CAAO,EAAE,CAAA,EAAG;AAEzB,MAAA,IAAA,CAAK,WAAA,CAAY,GAAG,KAAK,CAAA;AAEzB,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;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debounce.d.mts","sourceRoot":"","sources":["../../../src/core/operators/debounce.mts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,wBAAwB,EAI9B,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"debounce.d.mts","sourceRoot":"","sources":["../../../src/core/operators/debounce.mts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,wBAAwB,EAI9B,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,gBACV,MAAM,KACnB,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAMQ,CAAC"}
|
|
@@ -2,128 +2,45 @@ import { Optional } from 'ts-data-forge';
|
|
|
2
2
|
import { AsyncChildObservableClass } 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 debounce):
|
|
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 ->
|
|
21
|
-
* // debounced$ 3 14 (emitted after 250ms silence)
|
|
22
|
-
* //
|
|
23
|
-
* // Explanation:
|
|
24
|
-
* // - debounce emits the latest value AFTER a quiet period with no new emissions
|
|
25
|
-
* // - Unlike audit (which uses a fixed window), debounce resets the timer on every emission
|
|
26
|
-
* // - Useful for search-as-you-type and form validation
|
|
27
|
-
*
|
|
28
|
-
* const input$ = source<number>();
|
|
29
|
-
*
|
|
30
|
-
* const debounced$ = input$.pipe(debounce(250));
|
|
31
|
-
*
|
|
32
|
-
* const valueHistory: number[] = [];
|
|
33
|
-
*
|
|
34
|
-
* debounced$.subscribe((value) => {
|
|
35
|
-
* valueHistory.push(value);
|
|
36
|
-
* });
|
|
37
|
-
*
|
|
38
|
-
* const sleep = (ms: number): Promise<void> =>
|
|
39
|
-
* new Promise((resolve) => {
|
|
40
|
-
* setTimeout(resolve, ms);
|
|
41
|
-
* });
|
|
42
|
-
*
|
|
43
|
-
* input$.next(0);
|
|
44
|
-
*
|
|
45
|
-
* await sleep(200);
|
|
46
|
-
*
|
|
47
|
-
* input$.next(2);
|
|
48
|
-
*
|
|
49
|
-
* await sleep(100);
|
|
50
|
-
*
|
|
51
|
-
* input$.next(3);
|
|
52
|
-
*
|
|
53
|
-
* assert.deepStrictEqual(valueHistory, []);
|
|
54
|
-
*
|
|
55
|
-
* await sleep(300);
|
|
56
|
-
*
|
|
57
|
-
* assert.deepStrictEqual(valueHistory, [3]);
|
|
58
|
-
*
|
|
59
|
-
* await sleep(300);
|
|
60
|
-
*
|
|
61
|
-
* input$.next(9);
|
|
62
|
-
*
|
|
63
|
-
* await sleep(100);
|
|
64
|
-
*
|
|
65
|
-
* input$.next(10);
|
|
66
|
-
*
|
|
67
|
-
* await sleep(100);
|
|
68
|
-
*
|
|
69
|
-
* input$.next(11);
|
|
70
|
-
*
|
|
71
|
-
* await sleep(100);
|
|
72
|
-
*
|
|
73
|
-
* input$.next(12);
|
|
74
|
-
*
|
|
75
|
-
* await sleep(100);
|
|
76
|
-
*
|
|
77
|
-
* input$.next(13);
|
|
78
|
-
*
|
|
79
|
-
* await sleep(100);
|
|
80
|
-
*
|
|
81
|
-
* input$.next(14);
|
|
82
|
-
*
|
|
83
|
-
* assert.deepStrictEqual(valueHistory, [3]);
|
|
84
|
-
*
|
|
85
|
-
* await sleep(300);
|
|
86
|
-
*
|
|
87
|
-
* assert.deepStrictEqual(valueHistory, [3, 14]);
|
|
88
|
-
* ```
|
|
89
|
-
*/
|
|
90
|
-
const debounce = (milliSeconds) =>
|
|
91
|
-
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
92
|
-
((parentObservable) => new DebounceObservableClass(parentObservable, milliSeconds));
|
|
5
|
+
const debounce = (milliSeconds) => (
|
|
6
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
7
|
+
((parentObservable) => new DebounceObservableClass(
|
|
8
|
+
parentObservable,
|
|
9
|
+
milliSeconds
|
|
10
|
+
))
|
|
11
|
+
);
|
|
93
12
|
class DebounceObservableClass extends AsyncChildObservableClass {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
13
|
+
#milliSeconds;
|
|
14
|
+
#mut_timerId;
|
|
15
|
+
constructor(parentObservable, milliSeconds) {
|
|
16
|
+
super({
|
|
17
|
+
parents: [parentObservable],
|
|
18
|
+
initialValue: parentObservable.getSnapshot()
|
|
19
|
+
});
|
|
20
|
+
this.#mut_timerId = void 0;
|
|
21
|
+
this.#milliSeconds = milliSeconds;
|
|
22
|
+
}
|
|
23
|
+
#resetTimer() {
|
|
24
|
+
if (this.#mut_timerId !== void 0) {
|
|
25
|
+
clearTimeout(this.#mut_timerId);
|
|
103
26
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.#resetTimer();
|
|
111
|
-
// set timer
|
|
112
|
-
this.#mut_timerId = setTimeout(() => {
|
|
113
|
-
if (Optional.isNone(sn))
|
|
114
|
-
return;
|
|
115
|
-
this.startUpdate(sn.value);
|
|
116
|
-
}, this.#milliSeconds);
|
|
117
|
-
}
|
|
118
|
-
#resetTimer() {
|
|
119
|
-
if (this.#mut_timerId !== undefined) {
|
|
120
|
-
clearTimeout(this.#mut_timerId);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
complete() {
|
|
124
|
-
this.#resetTimer();
|
|
125
|
-
super.complete();
|
|
27
|
+
}
|
|
28
|
+
tryUpdate(updateToken) {
|
|
29
|
+
const par = this.parents[0];
|
|
30
|
+
const sn = par.getSnapshot();
|
|
31
|
+
if (par.updateToken !== updateToken || Optional.isNone(sn)) {
|
|
32
|
+
return;
|
|
126
33
|
}
|
|
34
|
+
this.#resetTimer();
|
|
35
|
+
this.#mut_timerId = setTimeout(() => {
|
|
36
|
+
if (Optional.isNone(sn)) return;
|
|
37
|
+
this.startUpdate(sn.value);
|
|
38
|
+
}, this.#milliSeconds);
|
|
39
|
+
}
|
|
40
|
+
complete() {
|
|
41
|
+
this.#resetTimer();
|
|
42
|
+
super.complete();
|
|
43
|
+
}
|
|
127
44
|
}
|
|
128
45
|
|
|
129
46
|
export { debounce };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debounce.mjs","sources":["../../../src/core/operators/debounce.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"debounce.mjs","sources":["../../../src/core/operators/debounce.mts"],"sourcesContent":["import { Optional } from 'ts-data-forge';\nimport { AsyncChildObservableClass } from '../class/index.mjs';\nimport {\n type DebounceOperatorObservable,\n type KeepInitialValueOperator,\n type Observable,\n type TimerId,\n type UpdateToken,\n} from '../types/index.mjs';\n\n/**\n * Delays emissions from the source observable until a specified time has passed without another emission.\n * Useful for handling user input events like typing or scrolling.\n *\n * @template A - The type of values from the source\n * @param milliSeconds - The debounce duration in milliseconds\n * @returns An operator that debounces the observable\n *\n * @example\n * ```ts\n * // Timeline (250ms debounce):\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 ->\n * // debounced$ 3 14 (emitted after 250ms silence)\n * //\n * // Explanation:\n * // - debounce emits the latest value AFTER a quiet period with no new emissions\n * // - Unlike audit (which uses a fixed window), debounce resets the timer on every emission\n * // - Useful for search-as-you-type and form validation\n *\n * const input$ = source<number>();\n *\n * const debounced$ = input$.pipe(debounce(250));\n *\n * const valueHistory: number[] = [];\n *\n * debounced$.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 * await sleep(200);\n *\n * input$.next(2);\n *\n * await sleep(100);\n *\n * input$.next(3);\n *\n * assert.deepStrictEqual(valueHistory, []);\n *\n * await sleep(300);\n *\n * assert.deepStrictEqual(valueHistory, [3]);\n *\n * await sleep(300);\n *\n * input$.next(9);\n *\n * await sleep(100);\n *\n * input$.next(10);\n *\n * await sleep(100);\n *\n * input$.next(11);\n *\n * await sleep(100);\n *\n * input$.next(12);\n *\n * await sleep(100);\n *\n * input$.next(13);\n *\n * await sleep(100);\n *\n * input$.next(14);\n *\n * assert.deepStrictEqual(valueHistory, [3]);\n *\n * await sleep(300);\n *\n * assert.deepStrictEqual(valueHistory, [3, 14]);\n * ```\n */\nexport const debounce = <A,>(\n milliSeconds: number,\n): KeepInitialValueOperator<A, A> =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n ((parentObservable) =>\n new DebounceObservableClass(\n parentObservable,\n milliSeconds,\n )) as KeepInitialValueOperator<A, A>;\n\nclass DebounceObservableClass<A>\n extends AsyncChildObservableClass<A, readonly [A]>\n implements DebounceOperatorObservable<A>\n{\n readonly #milliSeconds: number;\n #mut_timerId: TimerId | undefined;\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.#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 (par.updateToken !== updateToken || Optional.isNone(sn)) {\n return; // skip update\n }\n\n this.#resetTimer();\n\n // set timer\n this.#mut_timerId = setTimeout(() => {\n if (Optional.isNone(sn)) return;\n\n this.startUpdate(sn.value);\n }, this.#milliSeconds);\n }\n\n override complete(): void {\n this.#resetTimer();\n\n super.complete();\n }\n}\n"],"names":[],"mappings":";;;;AA+FO,MAAM,WAAW,CACtB,YAAA;AAAA;AAAA,GAGC,CAAC,qBACA,IAAI,uBAAA;AAAA,IACF,gBAAA;AAAA,IACA;AAAA,GACF;AAAA;AAEJ,MAAM,gCACI,yBAAA,CAEV;AAAA,EACW,aAAA;AAAA,EACT,YAAA;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,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,IAAI,IAAI,WAAA,KAAgB,WAAA,IAAe,QAAA,CAAS,MAAA,CAAO,EAAE,CAAA,EAAG;AAC1D,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,WAAA,EAAY;AAGjB,IAAA,IAAA,CAAK,YAAA,GAAe,WAAW,MAAM;AACnC,MAAA,IAAI,QAAA,CAAS,MAAA,CAAO,EAAE,CAAA,EAAG;AAEzB,MAAA,IAAA,CAAK,WAAA,CAAY,GAAG,KAAK,CAAA;AAAA,IAC3B,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;;;;"}
|
|
@@ -3,35 +3,32 @@ import { SyncChildObservableClass } from '../class/child-observable-class.mjs';
|
|
|
3
3
|
import '../utils/id-maker.mjs';
|
|
4
4
|
|
|
5
5
|
function filter(predicate) {
|
|
6
|
-
|
|
6
|
+
return (parentObservable) => new FilterObservableClass(parentObservable, predicate);
|
|
7
7
|
}
|
|
8
8
|
class FilterObservableClass extends SyncChildObservableClass {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
#predicate;
|
|
10
|
+
#mut_index;
|
|
11
|
+
constructor(parentObservable, predicate) {
|
|
12
|
+
super({
|
|
13
|
+
parents: [parentObservable],
|
|
14
|
+
initialValue: pipe(parentObservable.getSnapshot()).map(
|
|
15
|
+
(sn) => Optional.isNone(sn) ? Optional.none : predicate(sn.value, -1) ? sn : Optional.none
|
|
16
|
+
).value
|
|
17
|
+
});
|
|
18
|
+
this.#mut_index = -1;
|
|
19
|
+
this.#predicate = predicate;
|
|
20
|
+
}
|
|
21
|
+
tryUpdate(updateToken) {
|
|
22
|
+
const par = this.parents[0];
|
|
23
|
+
const sn = par.getSnapshot();
|
|
24
|
+
if (par.updateToken !== updateToken || Optional.isNone(sn)) {
|
|
25
|
+
return;
|
|
22
26
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (par.updateToken !== updateToken || Optional.isNone(sn)) {
|
|
27
|
-
return; // skip update
|
|
28
|
-
}
|
|
29
|
-
this.#mut_index =
|
|
30
|
-
this.#mut_index === -1 ? asSafeUint(0) : SafeUint.add(1, this.#mut_index);
|
|
31
|
-
if (this.#predicate(sn.value, this.#mut_index)) {
|
|
32
|
-
this.setNext(sn.value, updateToken);
|
|
33
|
-
}
|
|
27
|
+
this.#mut_index = this.#mut_index === -1 ? asSafeUint(0) : SafeUint.add(1, this.#mut_index);
|
|
28
|
+
if (this.#predicate(sn.value, this.#mut_index)) {
|
|
29
|
+
this.setNext(sn.value, updateToken);
|
|
34
30
|
}
|
|
31
|
+
}
|
|
35
32
|
}
|
|
36
33
|
|
|
37
34
|
export { filter };
|