synstate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/README.md +878 -0
  2. package/dist/core/class/child-observable-class.d.mts +37 -0
  3. package/dist/core/class/child-observable-class.d.mts.map +1 -0
  4. package/dist/core/class/child-observable-class.mjs +134 -0
  5. package/dist/core/class/child-observable-class.mjs.map +1 -0
  6. package/dist/core/class/index.d.mts +4 -0
  7. package/dist/core/class/index.d.mts.map +1 -0
  8. package/dist/core/class/index.mjs +4 -0
  9. package/dist/core/class/index.mjs.map +1 -0
  10. package/dist/core/class/observable-base-class.d.mts +28 -0
  11. package/dist/core/class/observable-base-class.d.mts.map +1 -0
  12. package/dist/core/class/observable-base-class.mjs +116 -0
  13. package/dist/core/class/observable-base-class.mjs.map +1 -0
  14. package/dist/core/class/root-observable-class.d.mts +12 -0
  15. package/dist/core/class/root-observable-class.d.mts.map +1 -0
  16. package/dist/core/class/root-observable-class.mjs +35 -0
  17. package/dist/core/class/root-observable-class.mjs.map +1 -0
  18. package/dist/core/combine/combine.d.mts +35 -0
  19. package/dist/core/combine/combine.d.mts.map +1 -0
  20. package/dist/core/combine/combine.mjs +94 -0
  21. package/dist/core/combine/combine.mjs.map +1 -0
  22. package/dist/core/combine/index.d.mts +4 -0
  23. package/dist/core/combine/index.d.mts.map +1 -0
  24. package/dist/core/combine/index.mjs +4 -0
  25. package/dist/core/combine/index.mjs.map +1 -0
  26. package/dist/core/combine/merge.d.mts +28 -0
  27. package/dist/core/combine/merge.d.mts.map +1 -0
  28. package/dist/core/combine/merge.mjs +52 -0
  29. package/dist/core/combine/merge.mjs.map +1 -0
  30. package/dist/core/combine/zip.d.mts +26 -0
  31. package/dist/core/combine/zip.d.mts.map +1 -0
  32. package/dist/core/combine/zip.mjs +63 -0
  33. package/dist/core/combine/zip.mjs.map +1 -0
  34. package/dist/core/create/from-array.d.mts +21 -0
  35. package/dist/core/create/from-array.d.mts.map +1 -0
  36. package/dist/core/create/from-array.mjs +47 -0
  37. package/dist/core/create/from-array.mjs.map +1 -0
  38. package/dist/core/create/from-promise.d.mts +25 -0
  39. package/dist/core/create/from-promise.d.mts.map +1 -0
  40. package/dist/core/create/from-promise.mjs +51 -0
  41. package/dist/core/create/from-promise.mjs.map +1 -0
  42. package/dist/core/create/from-subscribable.d.mts +3 -0
  43. package/dist/core/create/from-subscribable.d.mts.map +1 -0
  44. package/dist/core/create/from-subscribable.mjs +22 -0
  45. package/dist/core/create/from-subscribable.mjs.map +1 -0
  46. package/dist/core/create/index.d.mts +8 -0
  47. package/dist/core/create/index.d.mts.map +1 -0
  48. package/dist/core/create/index.mjs +8 -0
  49. package/dist/core/create/index.mjs.map +1 -0
  50. package/dist/core/create/interval.d.mts +21 -0
  51. package/dist/core/create/interval.d.mts.map +1 -0
  52. package/dist/core/create/interval.mjs +74 -0
  53. package/dist/core/create/interval.mjs.map +1 -0
  54. package/dist/core/create/of.d.mts +20 -0
  55. package/dist/core/create/of.d.mts.map +1 -0
  56. package/dist/core/create/of.mjs +44 -0
  57. package/dist/core/create/of.mjs.map +1 -0
  58. package/dist/core/create/source.d.mts +29 -0
  59. package/dist/core/create/source.d.mts.map +1 -0
  60. package/dist/core/create/source.mjs +29 -0
  61. package/dist/core/create/source.mjs.map +1 -0
  62. package/dist/core/create/timer.d.mts +20 -0
  63. package/dist/core/create/timer.d.mts.map +1 -0
  64. package/dist/core/create/timer.mjs +64 -0
  65. package/dist/core/create/timer.mjs.map +1 -0
  66. package/dist/core/index.d.mts +7 -0
  67. package/dist/core/index.d.mts.map +1 -0
  68. package/dist/core/index.mjs +37 -0
  69. package/dist/core/index.mjs.map +1 -0
  70. package/dist/core/operators/audit-time.d.mts +3 -0
  71. package/dist/core/operators/audit-time.d.mts.map +1 -0
  72. package/dist/core/operators/audit-time.mjs +50 -0
  73. package/dist/core/operators/audit-time.mjs.map +1 -0
  74. package/dist/core/operators/debounce-time.d.mts +31 -0
  75. package/dist/core/operators/debounce-time.d.mts.map +1 -0
  76. package/dist/core/operators/debounce-time.mjs +73 -0
  77. package/dist/core/operators/debounce-time.mjs.map +1 -0
  78. package/dist/core/operators/filter.d.mts +28 -0
  79. package/dist/core/operators/filter.d.mts.map +1 -0
  80. package/dist/core/operators/filter.mjs +38 -0
  81. package/dist/core/operators/filter.mjs.map +1 -0
  82. package/dist/core/operators/index.d.mts +18 -0
  83. package/dist/core/operators/index.d.mts.map +1 -0
  84. package/dist/core/operators/index.mjs +18 -0
  85. package/dist/core/operators/index.mjs.map +1 -0
  86. package/dist/core/operators/map-with-index.d.mts +39 -0
  87. package/dist/core/operators/map-with-index.d.mts.map +1 -0
  88. package/dist/core/operators/map-with-index.mjs +73 -0
  89. package/dist/core/operators/map-with-index.mjs.map +1 -0
  90. package/dist/core/operators/merge-map.d.mts +34 -0
  91. package/dist/core/operators/merge-map.d.mts.map +1 -0
  92. package/dist/core/operators/merge-map.mjs +75 -0
  93. package/dist/core/operators/merge-map.mjs.map +1 -0
  94. package/dist/core/operators/pairwise.d.mts +27 -0
  95. package/dist/core/operators/pairwise.d.mts.map +1 -0
  96. package/dist/core/operators/pairwise.mjs +59 -0
  97. package/dist/core/operators/pairwise.mjs.map +1 -0
  98. package/dist/core/operators/scan.d.mts +30 -0
  99. package/dist/core/operators/scan.d.mts.map +1 -0
  100. package/dist/core/operators/scan.mjs +56 -0
  101. package/dist/core/operators/scan.mjs.map +1 -0
  102. package/dist/core/operators/skip-if-no-change.d.mts +33 -0
  103. package/dist/core/operators/skip-if-no-change.d.mts.map +1 -0
  104. package/dist/core/operators/skip-if-no-change.mjs +68 -0
  105. package/dist/core/operators/skip-if-no-change.mjs.map +1 -0
  106. package/dist/core/operators/skip-until.d.mts +3 -0
  107. package/dist/core/operators/skip-until.d.mts.map +1 -0
  108. package/dist/core/operators/skip-until.mjs +33 -0
  109. package/dist/core/operators/skip-until.mjs.map +1 -0
  110. package/dist/core/operators/skip-while.d.mts +4 -0
  111. package/dist/core/operators/skip-while.d.mts.map +1 -0
  112. package/dist/core/operators/skip-while.mjs +40 -0
  113. package/dist/core/operators/skip-while.mjs.map +1 -0
  114. package/dist/core/operators/switch-map.d.mts +31 -0
  115. package/dist/core/operators/switch-map.d.mts.map +1 -0
  116. package/dist/core/operators/switch-map.mjs +70 -0
  117. package/dist/core/operators/switch-map.mjs.map +1 -0
  118. package/dist/core/operators/take-until.d.mts +32 -0
  119. package/dist/core/operators/take-until.d.mts.map +1 -0
  120. package/dist/core/operators/take-until.mjs +60 -0
  121. package/dist/core/operators/take-until.mjs.map +1 -0
  122. package/dist/core/operators/take-while.d.mts +4 -0
  123. package/dist/core/operators/take-while.d.mts.map +1 -0
  124. package/dist/core/operators/take-while.mjs +42 -0
  125. package/dist/core/operators/take-while.mjs.map +1 -0
  126. package/dist/core/operators/throttle-time.d.mts +23 -0
  127. package/dist/core/operators/throttle-time.d.mts.map +1 -0
  128. package/dist/core/operators/throttle-time.mjs +68 -0
  129. package/dist/core/operators/throttle-time.mjs.map +1 -0
  130. package/dist/core/operators/with-buffered-from.d.mts +4 -0
  131. package/dist/core/operators/with-buffered-from.d.mts.map +1 -0
  132. package/dist/core/operators/with-buffered-from.mjs +45 -0
  133. package/dist/core/operators/with-buffered-from.mjs.map +1 -0
  134. package/dist/core/operators/with-current-value-from.d.mts +4 -0
  135. package/dist/core/operators/with-current-value-from.d.mts.map +1 -0
  136. package/dist/core/operators/with-current-value-from.mjs +37 -0
  137. package/dist/core/operators/with-current-value-from.mjs.map +1 -0
  138. package/dist/core/operators/with-initial-value.d.mts +26 -0
  139. package/dist/core/operators/with-initial-value.d.mts.map +1 -0
  140. package/dist/core/operators/with-initial-value.mjs +47 -0
  141. package/dist/core/operators/with-initial-value.mjs.map +1 -0
  142. package/dist/core/types/id.d.mts +4 -0
  143. package/dist/core/types/id.d.mts.map +1 -0
  144. package/dist/core/types/id.mjs +2 -0
  145. package/dist/core/types/id.mjs.map +1 -0
  146. package/dist/core/types/index.d.mts +6 -0
  147. package/dist/core/types/index.d.mts.map +1 -0
  148. package/dist/core/types/index.mjs +3 -0
  149. package/dist/core/types/index.mjs.map +1 -0
  150. package/dist/core/types/observable-family.d.mts +68 -0
  151. package/dist/core/types/observable-family.d.mts.map +1 -0
  152. package/dist/core/types/observable-family.mjs +2 -0
  153. package/dist/core/types/observable-family.mjs.map +1 -0
  154. package/dist/core/types/observable-kind.d.mts +4 -0
  155. package/dist/core/types/observable-kind.d.mts.map +1 -0
  156. package/dist/core/types/observable-kind.mjs +2 -0
  157. package/dist/core/types/observable-kind.mjs.map +1 -0
  158. package/dist/core/types/observable.d.mts +83 -0
  159. package/dist/core/types/observable.d.mts.map +1 -0
  160. package/dist/core/types/observable.mjs +10 -0
  161. package/dist/core/types/observable.mjs.map +1 -0
  162. package/dist/core/types/types.d.mts +16 -0
  163. package/dist/core/types/types.d.mts.map +1 -0
  164. package/dist/core/types/types.mjs +2 -0
  165. package/dist/core/types/types.mjs.map +1 -0
  166. package/dist/core/utils/id-maker.d.mts +5 -0
  167. package/dist/core/utils/id-maker.d.mts.map +1 -0
  168. package/dist/core/utils/id-maker.mjs +17 -0
  169. package/dist/core/utils/id-maker.mjs.map +1 -0
  170. package/dist/core/utils/index.d.mts +5 -0
  171. package/dist/core/utils/index.d.mts.map +1 -0
  172. package/dist/core/utils/index.mjs +5 -0
  173. package/dist/core/utils/index.mjs.map +1 -0
  174. package/dist/core/utils/max-depth.d.mts +3 -0
  175. package/dist/core/utils/max-depth.d.mts.map +1 -0
  176. package/dist/core/utils/max-depth.mjs +8 -0
  177. package/dist/core/utils/max-depth.mjs.map +1 -0
  178. package/dist/core/utils/observable-utils.d.mts +3 -0
  179. package/dist/core/utils/observable-utils.d.mts.map +1 -0
  180. package/dist/core/utils/observable-utils.mjs +7 -0
  181. package/dist/core/utils/observable-utils.mjs.map +1 -0
  182. package/dist/core/utils/utils.d.mts +4 -0
  183. package/dist/core/utils/utils.d.mts.map +1 -0
  184. package/dist/core/utils/utils.mjs +38 -0
  185. package/dist/core/utils/utils.mjs.map +1 -0
  186. package/dist/entry-point.d.mts +2 -0
  187. package/dist/entry-point.d.mts.map +1 -0
  188. package/dist/entry-point.mjs +40 -0
  189. package/dist/entry-point.mjs.map +1 -0
  190. package/dist/globals.d.mts +4 -0
  191. package/dist/index.d.mts +3 -0
  192. package/dist/index.d.mts.map +1 -0
  193. package/dist/index.mjs +40 -0
  194. package/dist/index.mjs.map +1 -0
  195. package/dist/tsconfig.json +1 -0
  196. package/dist/types.d.mts +2 -0
  197. package/dist/utils/create-event-emitter.d.mts +39 -0
  198. package/dist/utils/create-event-emitter.d.mts.map +1 -0
  199. package/dist/utils/create-event-emitter.mjs +57 -0
  200. package/dist/utils/create-event-emitter.mjs.map +1 -0
  201. package/dist/utils/create-reducer.d.mts +34 -0
  202. package/dist/utils/create-reducer.d.mts.map +1 -0
  203. package/dist/utils/create-reducer.mjs +49 -0
  204. package/dist/utils/create-reducer.mjs.map +1 -0
  205. package/dist/utils/create-state.d.mts +61 -0
  206. package/dist/utils/create-state.d.mts.map +1 -0
  207. package/dist/utils/create-state.mjs +92 -0
  208. package/dist/utils/create-state.mjs.map +1 -0
  209. package/dist/utils/index.d.mts +4 -0
  210. package/dist/utils/index.d.mts.map +1 -0
  211. package/dist/utils/index.mjs +4 -0
  212. package/dist/utils/index.mjs.map +1 -0
  213. package/package.json +71 -0
  214. package/src/core/class/child-observable-class.mts +232 -0
  215. package/src/core/class/index.mts +3 -0
  216. package/src/core/class/observable-base-class.mts +186 -0
  217. package/src/core/class/observable.class.test.mts +89 -0
  218. package/src/core/class/root-observable-class.mts +68 -0
  219. package/src/core/combine/combine.mts +144 -0
  220. package/src/core/combine/index.mts +3 -0
  221. package/src/core/combine/merge.mts +84 -0
  222. package/src/core/combine/zip.mts +149 -0
  223. package/src/core/create/from-array.mts +58 -0
  224. package/src/core/create/from-promise.mts +58 -0
  225. package/src/core/create/from-subscribable.mts +37 -0
  226. package/src/core/create/index.mts +7 -0
  227. package/src/core/create/interval.mts +99 -0
  228. package/src/core/create/of.mts +54 -0
  229. package/src/core/create/source.mts +59 -0
  230. package/src/core/create/timer.mts +84 -0
  231. package/src/core/index.mts +6 -0
  232. package/src/core/operators/audit-time.mts +77 -0
  233. package/src/core/operators/debounce-time.mts +96 -0
  234. package/src/core/operators/filter.mts +125 -0
  235. package/src/core/operators/index.mts +17 -0
  236. package/src/core/operators/map-with-index.mts +168 -0
  237. package/src/core/operators/merge-map.mts +108 -0
  238. package/src/core/operators/pairwise.mts +77 -0
  239. package/src/core/operators/scan.mts +81 -0
  240. package/src/core/operators/skip-if-no-change.mts +91 -0
  241. package/src/core/operators/skip-until.mts +54 -0
  242. package/src/core/operators/skip-while.mts +77 -0
  243. package/src/core/operators/switch-map.mts +101 -0
  244. package/src/core/operators/take-until.mts +80 -0
  245. package/src/core/operators/take-while.mts +103 -0
  246. package/src/core/operators/throttle-time.mts +95 -0
  247. package/src/core/operators/with-buffered-from.mts +68 -0
  248. package/src/core/operators/with-current-value-from.mts +58 -0
  249. package/src/core/operators/with-initial-value.mts +76 -0
  250. package/src/core/types/id.mts +5 -0
  251. package/src/core/types/index.mts +5 -0
  252. package/src/core/types/observable-family.mts +259 -0
  253. package/src/core/types/observable-kind.mts +5 -0
  254. package/src/core/types/observable.mts +218 -0
  255. package/src/core/types/types.mts +40 -0
  256. package/src/core/utils/id-maker.mts +31 -0
  257. package/src/core/utils/index.mts +4 -0
  258. package/src/core/utils/max-depth.mts +7 -0
  259. package/src/core/utils/observable-utils.mts +10 -0
  260. package/src/core/utils/utils.mts +51 -0
  261. package/src/core/utils/utils.test.mts +88 -0
  262. package/src/entry-point.mts +1 -0
  263. package/src/globals.d.mts +4 -0
  264. package/src/index.mts +2 -0
  265. package/src/utils/create-event-emitter.mts +62 -0
  266. package/src/utils/create-reducer.mts +55 -0
  267. package/src/utils/create-state.mts +138 -0
  268. package/src/utils/index.mts +3 -0
@@ -0,0 +1,99 @@
1
+ import { asSafeUint, Optional, SafeUint } from 'ts-data-forge';
2
+ import { RootObservableClass } from '../class/index.mjs';
3
+ import { type IntervalObservable } from '../types/index.mjs';
4
+
5
+ /**
6
+ * Creates an observable that emits incremental numbers at a specified interval.
7
+ * Starts with 0 immediately after subscription, then emits 1, 2, 3, ... every interval.
8
+ *
9
+ * @param milliSeconds - The interval duration in milliseconds
10
+ * @param startManually - If true, waits for manual start (default: false)
11
+ * @returns An observable that emits sequential numbers
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const tick$ = interval(1000);
16
+ *
17
+ * tick$.subscribe((count) => {
18
+ * console.log(count);
19
+ * });
20
+ * // logs: 0, 1, 2, 3, ... every second
21
+ * ```
22
+ */
23
+ export const interval = (
24
+ milliSeconds: number,
25
+ startManually?: boolean,
26
+ ): IntervalObservable =>
27
+ new IntervalObservableClass(milliSeconds, startManually);
28
+
29
+ class IntervalObservableClass
30
+ extends RootObservableClass<SafeUint>
31
+ implements IntervalObservable
32
+ {
33
+ readonly #milliSeconds: number;
34
+ #mut_counter: SafeUint;
35
+ #mut_timerId0: TimerId | undefined;
36
+ #mut_timerId: TimerId | undefined;
37
+ #mut_isStarted: boolean;
38
+
39
+ constructor(milliSeconds: number, startManually?: boolean) {
40
+ super({ initialValue: Optional.none });
41
+
42
+ this.#milliSeconds = milliSeconds;
43
+
44
+ this.#mut_counter = asSafeUint(0);
45
+
46
+ this.#mut_timerId0 = undefined;
47
+
48
+ this.#mut_timerId = undefined;
49
+
50
+ this.#mut_isStarted = false;
51
+
52
+ if (startManually !== true) {
53
+ this.start();
54
+ }
55
+ }
56
+
57
+ start(): this {
58
+ if (this.#mut_isStarted) {
59
+ console.warn('cannot start twice');
60
+
61
+ return this;
62
+ }
63
+
64
+ this.#mut_isStarted = true;
65
+
66
+ if (this.isCompleted) {
67
+ console.warn('cannot restart stopped IntervalObservable');
68
+
69
+ return this;
70
+ }
71
+
72
+ // emit zero
73
+ this.#mut_timerId0 = setTimeout(() => {
74
+ this.startUpdate(this.#mut_counter);
75
+ }, 0);
76
+
77
+ this.#mut_timerId = setInterval(() => {
78
+ this.#mut_counter = SafeUint.add(1, this.#mut_counter);
79
+
80
+ this.startUpdate(this.#mut_counter);
81
+ }, this.#milliSeconds);
82
+
83
+ return this;
84
+ }
85
+
86
+ #resetTimer(): void {
87
+ if (this.#mut_timerId0 !== undefined && this.#mut_timerId !== undefined) {
88
+ clearInterval(this.#mut_timerId0);
89
+
90
+ clearInterval(this.#mut_timerId);
91
+ }
92
+ }
93
+
94
+ override complete(): void {
95
+ this.#resetTimer();
96
+
97
+ super.complete();
98
+ }
99
+ }
@@ -0,0 +1,54 @@
1
+ import { Optional } from 'ts-data-forge';
2
+ import { RootObservableClass } from '../class/index.mjs';
3
+ import { type OfObservable } from '../types/index.mjs';
4
+
5
+ /**
6
+ * Creates an observable that emits a single value and then completes.
7
+ *
8
+ * @template A - The type of the value
9
+ * @param value - The value to emit
10
+ * @param startManually - If true, waits for manual start (default: false)
11
+ * @returns An observable that emits the value
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const num$ = of(42);
16
+ *
17
+ * num$.subscribe((x) => {
18
+ * console.log(x);
19
+ * }); // logs: 42
20
+ * ```
21
+ */
22
+ export const of = <A,>(
23
+ value: A,
24
+ startManually: boolean = false,
25
+ ): OfObservable<A> => new OfObservableClass<A>(value, startManually);
26
+
27
+ class OfObservableClass<A>
28
+ extends RootObservableClass<A>
29
+ implements OfObservable<A>
30
+ {
31
+ readonly #value: A;
32
+
33
+ constructor(value: A, startManually: boolean = false) {
34
+ super({ initialValue: Optional.none });
35
+
36
+ this.#value = value;
37
+
38
+ if (!startManually) {
39
+ setTimeout(() => {
40
+ this.emit();
41
+ }, 0);
42
+ }
43
+ }
44
+
45
+ emit(): this {
46
+ if (this.isCompleted) return this;
47
+
48
+ this.startUpdate(this.#value);
49
+
50
+ this.complete();
51
+
52
+ return this;
53
+ }
54
+ }
@@ -0,0 +1,59 @@
1
+ import { Arr, Optional } from 'ts-data-forge';
2
+ import { RootObservableClass } from '../class/index.mjs';
3
+ import {
4
+ type InitializedSourceObservable,
5
+ type SourceObservable,
6
+ } from '../types/index.mjs';
7
+
8
+ /**
9
+ * Creates a new Observable source that can manually emit values.
10
+ * This is the primary way to create root observables that start reactive chains.
11
+ *
12
+ * @template A - The type of values emitted by the source
13
+ * @returns A SourceObservable that can emit values via `.next()` method
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const count$ = source<number>();
18
+ *
19
+ * count$.subscribe((value) => {
20
+ * console.log(value);
21
+ * });
22
+ *
23
+ * count$.next(1); // logs: 1
24
+ *
25
+ * count$.next(2); // logs: 2
26
+ * ```
27
+ */
28
+ export function source<A>(initialValue: A): InitializedSourceObservable<A>;
29
+
30
+ export function source<A>(): SourceObservable<A>;
31
+
32
+ export function source<A>(...args: readonly A[]): SourceObservable<A> {
33
+ return new SourceObservableClass<A>(...args);
34
+ }
35
+
36
+ /**
37
+ * Alias for `source()`. Creates a new Observable source.
38
+ * @see source
39
+ */
40
+ export const subject = source; // alias
41
+
42
+ class SourceObservableClass<A>
43
+ extends RootObservableClass<A>
44
+ implements SourceObservable<A>
45
+ {
46
+ constructor(...args: readonly A[]) {
47
+ super({
48
+ initialValue: Arr.isNonEmpty(args)
49
+ ? Optional.some(args[0])
50
+ : Optional.none,
51
+ });
52
+ }
53
+
54
+ next(nextValue: A): void {
55
+ if (this.isCompleted) return;
56
+
57
+ this.startUpdate(nextValue);
58
+ }
59
+ }
@@ -0,0 +1,84 @@
1
+ import { Optional } from 'ts-data-forge';
2
+ import { RootObservableClass } from '../class/index.mjs';
3
+ import { type TimerObservable } from '../types/index.mjs';
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
+ * const delayed$ = timer(1000);
15
+ *
16
+ * delayed$.subscribe(() => {
17
+ * console.log('1 second passed');
18
+ * });
19
+ * // After 1 second, logs: 1 second passed
20
+ * ```
21
+ */
22
+ export const timer = (
23
+ milliSeconds: number,
24
+ startManually: boolean = false,
25
+ ): TimerObservable => new TimerObservableClass(milliSeconds, startManually);
26
+
27
+ class TimerObservableClass
28
+ extends RootObservableClass<0>
29
+ implements TimerObservable
30
+ {
31
+ readonly #milliSeconds: number;
32
+ #mut_timerId: TimerId | undefined;
33
+ #mut_isStarted: boolean;
34
+
35
+ constructor(milliSeconds: number, startManually: boolean) {
36
+ super({ initialValue: Optional.none });
37
+
38
+ this.#milliSeconds = milliSeconds;
39
+
40
+ this.#mut_timerId = undefined;
41
+
42
+ this.#mut_isStarted = false;
43
+
44
+ if (!startManually) {
45
+ this.start();
46
+ }
47
+ }
48
+
49
+ start(): this {
50
+ if (this.#mut_isStarted) {
51
+ console.warn('cannot start twice');
52
+
53
+ return this;
54
+ }
55
+
56
+ this.#mut_isStarted = true;
57
+
58
+ if (this.isCompleted) {
59
+ console.warn('cannot restart stopped TimerObservable');
60
+
61
+ return this;
62
+ }
63
+
64
+ this.#mut_timerId = setTimeout(() => {
65
+ this.startUpdate(0);
66
+
67
+ this.complete();
68
+ }, this.#milliSeconds);
69
+
70
+ return this;
71
+ }
72
+
73
+ #resetTimer(): void {
74
+ if (this.#mut_timerId !== undefined) {
75
+ clearTimeout(this.#mut_timerId);
76
+ }
77
+ }
78
+
79
+ override complete(): void {
80
+ this.#resetTimer();
81
+
82
+ super.complete();
83
+ }
84
+ }
@@ -0,0 +1,6 @@
1
+ export * from './class/index.mjs';
2
+ export * from './combine/index.mjs';
3
+ export * from './create/index.mjs';
4
+ export * from './operators/index.mjs';
5
+ export * from './types/index.mjs';
6
+ export * from './utils/index.mjs';
@@ -0,0 +1,77 @@
1
+ import { Optional } from 'ts-data-forge';
2
+ import { AsyncChildObservableClass } from '../class/index.mjs';
3
+ import {
4
+ type AuditTimeOperatorObservable,
5
+ type KeepInitialValueOperator,
6
+ type Observable,
7
+ type UpdaterSymbol,
8
+ } from '../types/index.mjs';
9
+
10
+ export const auditTime = <A,>(
11
+ milliSeconds: number,
12
+ ): KeepInitialValueOperator<A, A> =>
13
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
14
+ ((parentObservable) =>
15
+ new AuditTimeObservableClass(
16
+ parentObservable,
17
+ milliSeconds,
18
+ )) as KeepInitialValueOperator<A, A>;
19
+
20
+ class AuditTimeObservableClass<A>
21
+ extends AsyncChildObservableClass<A, readonly [A]>
22
+ implements AuditTimeOperatorObservable<A>
23
+ {
24
+ readonly #milliSeconds: number;
25
+ #mut_timerId: TimerId | undefined;
26
+ #mut_isSkipping: boolean;
27
+
28
+ constructor(parentObservable: Observable<A>, milliSeconds: number) {
29
+ super({
30
+ parents: [parentObservable],
31
+ initialValue: parentObservable.getSnapshot(),
32
+ });
33
+
34
+ this.#mut_isSkipping = false;
35
+
36
+ this.#mut_timerId = undefined;
37
+
38
+ this.#milliSeconds = milliSeconds;
39
+ }
40
+
41
+ override tryUpdate(updaterSymbol: UpdaterSymbol): void {
42
+ const par = this.parents[0];
43
+
44
+ if (
45
+ par.updaterSymbol !== updaterSymbol ||
46
+ Optional.isNone(par.getSnapshot()) ||
47
+ this.#mut_isSkipping
48
+ ) {
49
+ return; // skip update
50
+ }
51
+
52
+ // set timer
53
+ this.#mut_isSkipping = true;
54
+
55
+ this.#mut_timerId = setTimeout(() => {
56
+ const sn = par.getSnapshot();
57
+
58
+ if (Optional.isNone(sn)) return;
59
+
60
+ this.startUpdate(sn.value);
61
+
62
+ this.#mut_isSkipping = false;
63
+ }, this.#milliSeconds);
64
+ }
65
+
66
+ #resetTimer(): void {
67
+ if (this.#mut_timerId !== undefined) {
68
+ clearTimeout(this.#mut_timerId);
69
+ }
70
+ }
71
+
72
+ override complete(): void {
73
+ this.#resetTimer();
74
+
75
+ super.complete();
76
+ }
77
+ }
@@ -0,0 +1,96 @@
1
+ import { Optional } from 'ts-data-forge';
2
+ import { AsyncChildObservableClass } from '../class/index.mjs';
3
+ import {
4
+ type DebounceTimeOperatorObservable,
5
+ type KeepInitialValueOperator,
6
+ type Observable,
7
+ type UpdaterSymbol,
8
+ } from '../types/index.mjs';
9
+
10
+ /**
11
+ * Delays emissions from the source observable until a specified time has passed without another emission.
12
+ * Useful for handling user input events like typing or scrolling.
13
+ *
14
+ * @template A - The type of values from the source
15
+ * @param milliSeconds - The debounce duration in milliseconds
16
+ * @returns An operator that debounces the observable
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const input$ = source<string>();
21
+ *
22
+ * const debounced$ = input$.pipe(debounceTime(300));
23
+ *
24
+ * debounced$.subscribe((value) => {
25
+ * console.log(value);
26
+ * });
27
+ *
28
+ * input$.next('h');
29
+ *
30
+ * input$.next('he');
31
+ *
32
+ * input$.next('hel');
33
+ *
34
+ * input$.next('hello');
35
+ * // After 300ms of silence, logs: hello
36
+ * ```
37
+ */
38
+ export const debounceTime = <A,>(
39
+ milliSeconds: number,
40
+ ): KeepInitialValueOperator<A, A> =>
41
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
42
+ ((parentObservable) =>
43
+ new DebounceTimeObservableClass(
44
+ parentObservable,
45
+ milliSeconds,
46
+ )) as KeepInitialValueOperator<A, A>;
47
+
48
+ class DebounceTimeObservableClass<A>
49
+ extends AsyncChildObservableClass<A, readonly [A]>
50
+ implements DebounceTimeOperatorObservable<A>
51
+ {
52
+ readonly #milliSeconds: number;
53
+ #mut_timerId: TimerId | undefined;
54
+
55
+ constructor(parentObservable: Observable<A>, milliSeconds: number) {
56
+ super({
57
+ parents: [parentObservable],
58
+ initialValue: parentObservable.getSnapshot(),
59
+ });
60
+
61
+ this.#mut_timerId = undefined;
62
+
63
+ this.#milliSeconds = milliSeconds;
64
+ }
65
+
66
+ override tryUpdate(updaterSymbol: UpdaterSymbol): void {
67
+ const par = this.parents[0];
68
+
69
+ const sn = par.getSnapshot();
70
+
71
+ if (par.updaterSymbol !== updaterSymbol || Optional.isNone(sn)) {
72
+ return; // skip update
73
+ }
74
+
75
+ this.#resetTimer();
76
+
77
+ // set timer
78
+ this.#mut_timerId = setTimeout(() => {
79
+ if (Optional.isNone(sn)) return;
80
+
81
+ this.startUpdate(sn.value);
82
+ }, this.#milliSeconds);
83
+ }
84
+
85
+ #resetTimer(): void {
86
+ if (this.#mut_timerId !== undefined) {
87
+ clearTimeout(this.#mut_timerId);
88
+ }
89
+ }
90
+
91
+ override complete(): void {
92
+ this.#resetTimer();
93
+
94
+ super.complete();
95
+ }
96
+ }
@@ -0,0 +1,125 @@
1
+ import {
2
+ asSafeUint,
3
+ expectType,
4
+ Optional,
5
+ pipe,
6
+ SafeUint,
7
+ } from 'ts-data-forge';
8
+ import { SyncChildObservableClass } from '../class/index.mjs';
9
+ import { source } from '../create/index.mjs';
10
+ import {
11
+ type DropInitialValueOperator,
12
+ type FilterOperatorObservable,
13
+ type InitializedObservable,
14
+ type Observable,
15
+ type UpdaterSymbol,
16
+ } from '../types/index.mjs';
17
+ import { withInitialValue } from './with-initial-value.mjs';
18
+
19
+ /**
20
+ * Filters values emitted by the source observable based on a predicate function.
21
+ * Only values that satisfy the predicate will be emitted by the resulting observable.
22
+ *
23
+ * @template A - The type of values from the source
24
+ * @template B - The narrowed type when using type guard
25
+ * @param predicate - A function that tests each value (receives value and index)
26
+ * @returns An operator that filters the observable
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const num$ = source<number>();
31
+ *
32
+ * const even$ = num$.pipe(filter((x) => x % 2 === 0));
33
+ *
34
+ * even$.subscribe((x) => {
35
+ * console.log(x);
36
+ * });
37
+ *
38
+ * num$.next(1); // nothing logged
39
+ *
40
+ * num$.next(2); // logs: 2
41
+ * ```
42
+ */
43
+ export function filter<A, B extends A>(
44
+ predicate: (value: A, index: SafeUint | -1) => value is B,
45
+ ): DropInitialValueOperator<A, B>;
46
+
47
+ export function filter<A>(
48
+ predicate: (value: A, index: SafeUint | -1) => boolean,
49
+ ): DropInitialValueOperator<A, A>;
50
+
51
+ export function filter<A>(
52
+ predicate: (value: A, index: SafeUint | -1) => boolean,
53
+ ): DropInitialValueOperator<A, A> {
54
+ return (parentObservable) =>
55
+ new FilterObservableClass(parentObservable, predicate);
56
+ }
57
+
58
+ class FilterObservableClass<A>
59
+ extends SyncChildObservableClass<A, readonly [A]>
60
+ implements FilterOperatorObservable<A>
61
+ {
62
+ readonly #predicate: (x: A, index: SafeUint | -1) => boolean;
63
+ #mut_index: SafeUint | -1;
64
+
65
+ constructor(
66
+ parentObservable: Observable<A>,
67
+ predicate: (x: A, index: SafeUint | -1) => boolean,
68
+ ) {
69
+ super({
70
+ parents: [parentObservable],
71
+ initialValue: pipe(parentObservable.getSnapshot()).map((sn) =>
72
+ Optional.isNone(sn)
73
+ ? Optional.none
74
+ : predicate(sn.value, -1)
75
+ ? sn
76
+ : Optional.none,
77
+ ).value,
78
+ });
79
+
80
+ this.#mut_index = -1;
81
+
82
+ this.#predicate = predicate;
83
+ }
84
+
85
+ override tryUpdate(updaterSymbol: UpdaterSymbol): void {
86
+ const par = this.parents[0];
87
+
88
+ const sn = par.getSnapshot();
89
+
90
+ if (par.updaterSymbol !== updaterSymbol || Optional.isNone(sn)) {
91
+ return; // skip update
92
+ }
93
+
94
+ this.#mut_index =
95
+ this.#mut_index === -1 ? asSafeUint(0) : SafeUint.add(1, this.#mut_index);
96
+
97
+ if (this.#predicate(sn.value, this.#mut_index)) {
98
+ this.setNext(sn.value, updaterSymbol);
99
+ }
100
+ }
101
+ }
102
+
103
+ if (import.meta.vitest !== undefined) {
104
+ test('type test', () => {
105
+ expect(1).toBe(1); // dummy
106
+ });
107
+
108
+ {
109
+ const s: Observable<number> = source<number>();
110
+
111
+ const _d1 = s.pipe(filter((x) => x % 2 === 0));
112
+
113
+ expectType<typeof _d1, Observable<number>>('=');
114
+ }
115
+
116
+ {
117
+ const s = source<number>();
118
+
119
+ const m: InitializedObservable<number> = s.pipe(withInitialValue(0));
120
+
121
+ const _d = m.pipe(filter((x) => x % 2 === 0));
122
+
123
+ expectType<typeof _d, Observable<number>>('=');
124
+ }
125
+ }
@@ -0,0 +1,17 @@
1
+ export * from './audit-time.mjs';
2
+ export * from './debounce-time.mjs';
3
+ export * from './filter.mjs';
4
+ export * from './map-with-index.mjs';
5
+ export * from './merge-map.mjs';
6
+ export * from './pairwise.mjs';
7
+ export * from './scan.mjs';
8
+ export * from './skip-if-no-change.mjs';
9
+ export * from './skip-until.mjs';
10
+ export * from './skip-while.mjs';
11
+ export * from './switch-map.mjs';
12
+ export * from './take-until.mjs';
13
+ export * from './take-while.mjs';
14
+ export * from './throttle-time.mjs';
15
+ export * from './with-buffered-from.mjs';
16
+ export * from './with-current-value-from.mjs';
17
+ export * from './with-initial-value.mjs';