synstate 0.1.0 → 0.1.2

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 (235) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +272 -532
  3. package/assets/synstate-icon.png +0 -0
  4. package/dist/core/combine/combine.d.mts +33 -3
  5. package/dist/core/combine/combine.d.mts.map +1 -1
  6. package/dist/core/combine/combine.mjs +34 -4
  7. package/dist/core/combine/combine.mjs.map +1 -1
  8. package/dist/core/combine/merge.d.mts +30 -4
  9. package/dist/core/combine/merge.d.mts.map +1 -1
  10. package/dist/core/combine/merge.mjs +30 -4
  11. package/dist/core/combine/merge.mjs.map +1 -1
  12. package/dist/core/combine/zip.d.mts +28 -3
  13. package/dist/core/combine/zip.d.mts.map +1 -1
  14. package/dist/core/combine/zip.mjs +28 -3
  15. package/dist/core/combine/zip.mjs.map +1 -1
  16. package/dist/core/create/from-array.d.mts +21 -3
  17. package/dist/core/create/from-array.d.mts.map +1 -1
  18. package/dist/core/create/from-array.mjs +21 -3
  19. package/dist/core/create/from-array.mjs.map +1 -1
  20. package/dist/core/create/from-promise.d.mts +29 -7
  21. package/dist/core/create/from-promise.d.mts.map +1 -1
  22. package/dist/core/create/from-promise.mjs +29 -7
  23. package/dist/core/create/from-promise.mjs.map +1 -1
  24. package/dist/core/create/from-subscribable.d.mts +58 -0
  25. package/dist/core/create/from-subscribable.d.mts.map +1 -1
  26. package/dist/core/create/from-subscribable.mjs +58 -0
  27. package/dist/core/create/from-subscribable.mjs.map +1 -1
  28. package/dist/core/create/interval.d.mts +29 -4
  29. package/dist/core/create/interval.d.mts.map +1 -1
  30. package/dist/core/create/interval.mjs +29 -4
  31. package/dist/core/create/interval.mjs.map +1 -1
  32. package/dist/core/create/of.d.mts +22 -3
  33. package/dist/core/create/of.d.mts.map +1 -1
  34. package/dist/core/create/of.mjs +22 -3
  35. package/dist/core/create/of.mjs.map +1 -1
  36. package/dist/core/create/source.d.mts +21 -2
  37. package/dist/core/create/source.d.mts.map +1 -1
  38. package/dist/core/create/source.mjs +2 -2
  39. package/dist/core/create/source.mjs.map +1 -1
  40. package/dist/core/create/timer.d.mts +23 -4
  41. package/dist/core/create/timer.d.mts.map +1 -1
  42. package/dist/core/create/timer.mjs +23 -4
  43. package/dist/core/create/timer.mjs.map +1 -1
  44. package/dist/core/index.d.mts +1 -0
  45. package/dist/core/index.d.mts.map +1 -1
  46. package/dist/core/index.mjs +15 -3
  47. package/dist/core/index.mjs.map +1 -1
  48. package/dist/core/operators/audit-time.d.mts +59 -0
  49. package/dist/core/operators/audit-time.d.mts.map +1 -1
  50. package/dist/core/operators/audit-time.mjs +59 -0
  51. package/dist/core/operators/audit-time.mjs.map +1 -1
  52. package/dist/core/operators/debounce-time.d.mts +22 -2
  53. package/dist/core/operators/debounce-time.d.mts.map +1 -1
  54. package/dist/core/operators/debounce-time.mjs +22 -2
  55. package/dist/core/operators/debounce-time.mjs.map +1 -1
  56. package/dist/core/operators/filter.d.mts +26 -1
  57. package/dist/core/operators/filter.d.mts.map +1 -1
  58. package/dist/core/operators/filter.mjs.map +1 -1
  59. package/dist/core/operators/index.mjs +3 -3
  60. package/dist/core/operators/map-with-index.d.mts +19 -17
  61. package/dist/core/operators/map-with-index.d.mts.map +1 -1
  62. package/dist/core/operators/map-with-index.mjs +21 -23
  63. package/dist/core/operators/map-with-index.mjs.map +1 -1
  64. package/dist/core/operators/merge-map.d.mts +48 -6
  65. package/dist/core/operators/merge-map.d.mts.map +1 -1
  66. package/dist/core/operators/merge-map.mjs +48 -6
  67. package/dist/core/operators/merge-map.mjs.map +1 -1
  68. package/dist/core/operators/pairwise.d.mts +30 -1
  69. package/dist/core/operators/pairwise.d.mts.map +1 -1
  70. package/dist/core/operators/pairwise.mjs +30 -1
  71. package/dist/core/operators/pairwise.mjs.map +1 -1
  72. package/dist/core/operators/scan.d.mts +23 -1
  73. package/dist/core/operators/scan.d.mts.map +1 -1
  74. package/dist/core/operators/scan.mjs +23 -1
  75. package/dist/core/operators/scan.mjs.map +1 -1
  76. package/dist/core/operators/skip-if-no-change.d.mts +26 -2
  77. package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
  78. package/dist/core/operators/skip-if-no-change.mjs +27 -3
  79. package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
  80. package/dist/core/operators/skip-until.d.mts +50 -0
  81. package/dist/core/operators/skip-until.d.mts.map +1 -1
  82. package/dist/core/operators/skip-until.mjs +50 -0
  83. package/dist/core/operators/skip-until.mjs.map +1 -1
  84. package/dist/core/operators/skip-while.d.mts +48 -1
  85. package/dist/core/operators/skip-while.d.mts.map +1 -1
  86. package/dist/core/operators/skip-while.mjs +50 -5
  87. package/dist/core/operators/skip-while.mjs.map +1 -1
  88. package/dist/core/operators/switch-map.d.mts +39 -5
  89. package/dist/core/operators/switch-map.d.mts.map +1 -1
  90. package/dist/core/operators/switch-map.mjs +39 -5
  91. package/dist/core/operators/switch-map.mjs.map +1 -1
  92. package/dist/core/operators/take-until.d.mts +20 -1
  93. package/dist/core/operators/take-until.d.mts.map +1 -1
  94. package/dist/core/operators/take-until.mjs +20 -1
  95. package/dist/core/operators/take-until.mjs.map +1 -1
  96. package/dist/core/operators/take-while.d.mts +47 -1
  97. package/dist/core/operators/take-while.d.mts.map +1 -1
  98. package/dist/core/operators/take-while.mjs +48 -3
  99. package/dist/core/operators/take-while.mjs.map +1 -1
  100. package/dist/core/operators/throttle-time.d.mts +44 -5
  101. package/dist/core/operators/throttle-time.d.mts.map +1 -1
  102. package/dist/core/operators/throttle-time.mjs +44 -5
  103. package/dist/core/operators/throttle-time.mjs.map +1 -1
  104. package/dist/core/operators/with-buffered-from.d.mts +57 -0
  105. package/dist/core/operators/with-buffered-from.d.mts.map +1 -1
  106. package/dist/core/operators/with-buffered-from.mjs +58 -1
  107. package/dist/core/operators/with-buffered-from.mjs.map +1 -1
  108. package/dist/core/operators/with-current-value-from.d.mts +59 -0
  109. package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
  110. package/dist/core/operators/with-current-value-from.mjs +60 -1
  111. package/dist/core/operators/with-current-value-from.mjs.map +1 -1
  112. package/dist/core/operators/with-initial-value.d.mts +24 -2
  113. package/dist/core/operators/with-initial-value.d.mts.map +1 -1
  114. package/dist/core/operators/with-initial-value.mjs +24 -2
  115. package/dist/core/operators/with-initial-value.mjs.map +1 -1
  116. package/dist/core/predefined/index.d.mts +2 -0
  117. package/dist/core/predefined/index.d.mts.map +1 -0
  118. package/dist/core/predefined/index.mjs +13 -0
  119. package/dist/core/predefined/index.mjs.map +1 -0
  120. package/dist/core/predefined/operators/attach-index.d.mts +8 -0
  121. package/dist/core/predefined/operators/attach-index.d.mts.map +1 -0
  122. package/dist/core/predefined/operators/attach-index.mjs +13 -0
  123. package/dist/core/predefined/operators/attach-index.mjs.map +1 -0
  124. package/dist/core/predefined/operators/index.d.mts +13 -0
  125. package/dist/core/predefined/operators/index.d.mts.map +1 -0
  126. package/dist/core/predefined/operators/index.mjs +13 -0
  127. package/dist/core/predefined/operators/index.mjs.map +1 -0
  128. package/dist/core/predefined/operators/map-optional.d.mts +4 -0
  129. package/dist/core/predefined/operators/map-optional.d.mts.map +1 -0
  130. package/dist/core/predefined/operators/map-optional.mjs +7 -0
  131. package/dist/core/predefined/operators/map-optional.mjs.map +1 -0
  132. package/dist/core/predefined/operators/map-result-err.d.mts +4 -0
  133. package/dist/core/predefined/operators/map-result-err.d.mts.map +1 -0
  134. package/dist/core/predefined/operators/map-result-err.mjs +7 -0
  135. package/dist/core/predefined/operators/map-result-err.mjs.map +1 -0
  136. package/dist/core/predefined/operators/map-result-ok.d.mts +4 -0
  137. package/dist/core/predefined/operators/map-result-ok.d.mts.map +1 -0
  138. package/dist/core/predefined/operators/map-result-ok.mjs +7 -0
  139. package/dist/core/predefined/operators/map-result-ok.mjs.map +1 -0
  140. package/dist/core/predefined/operators/map-to.d.mts +3 -0
  141. package/dist/core/predefined/operators/map-to.d.mts.map +1 -0
  142. package/dist/core/predefined/operators/map-to.mjs +6 -0
  143. package/dist/core/predefined/operators/map-to.mjs.map +1 -0
  144. package/dist/core/predefined/operators/map.d.mts +3 -0
  145. package/dist/core/predefined/operators/map.d.mts.map +1 -0
  146. package/dist/core/predefined/operators/map.mjs +8 -0
  147. package/dist/core/predefined/operators/map.mjs.map +1 -0
  148. package/dist/core/predefined/operators/pluck.d.mts +8 -0
  149. package/dist/core/predefined/operators/pluck.d.mts.map +1 -0
  150. package/dist/core/predefined/operators/pluck.mjs +11 -0
  151. package/dist/core/predefined/operators/pluck.mjs.map +1 -0
  152. package/dist/core/predefined/operators/skip.d.mts +3 -0
  153. package/dist/core/predefined/operators/skip.d.mts.map +1 -0
  154. package/dist/core/predefined/operators/skip.mjs +9 -0
  155. package/dist/core/predefined/operators/skip.mjs.map +1 -0
  156. package/dist/core/predefined/operators/take.d.mts +3 -0
  157. package/dist/core/predefined/operators/take.d.mts.map +1 -0
  158. package/dist/core/predefined/operators/take.mjs +8 -0
  159. package/dist/core/predefined/operators/take.mjs.map +1 -0
  160. package/dist/core/predefined/operators/unwrap-optional.d.mts +4 -0
  161. package/dist/core/predefined/operators/unwrap-optional.d.mts.map +1 -0
  162. package/dist/core/predefined/operators/unwrap-optional.mjs +9 -0
  163. package/dist/core/predefined/operators/unwrap-optional.mjs.map +1 -0
  164. package/dist/core/predefined/operators/unwrap-result-err.d.mts +4 -0
  165. package/dist/core/predefined/operators/unwrap-result-err.d.mts.map +1 -0
  166. package/dist/core/predefined/operators/unwrap-result-err.mjs +7 -0
  167. package/dist/core/predefined/operators/unwrap-result-err.mjs.map +1 -0
  168. package/dist/core/predefined/operators/unwrap-result-ok.d.mts +4 -0
  169. package/dist/core/predefined/operators/unwrap-result-ok.d.mts.map +1 -0
  170. package/dist/core/predefined/operators/unwrap-result-ok.mjs +9 -0
  171. package/dist/core/predefined/operators/unwrap-result-ok.mjs.map +1 -0
  172. package/dist/core/types/observable-family.d.mts +7 -7
  173. package/dist/entry-point.mjs +15 -3
  174. package/dist/entry-point.mjs.map +1 -1
  175. package/dist/index.mjs +15 -3
  176. package/dist/index.mjs.map +1 -1
  177. package/dist/utils/create-event-emitter.d.mts +20 -2
  178. package/dist/utils/create-event-emitter.d.mts.map +1 -1
  179. package/dist/utils/create-event-emitter.mjs +20 -2
  180. package/dist/utils/create-event-emitter.mjs.map +1 -1
  181. package/dist/utils/create-reducer.d.mts +13 -1
  182. package/dist/utils/create-reducer.d.mts.map +1 -1
  183. package/dist/utils/create-reducer.mjs +13 -1
  184. package/dist/utils/create-reducer.mjs.map +1 -1
  185. package/dist/utils/create-state.d.mts +24 -4
  186. package/dist/utils/create-state.d.mts.map +1 -1
  187. package/dist/utils/create-state.mjs +24 -4
  188. package/dist/utils/create-state.mjs.map +1 -1
  189. package/package.json +13 -12
  190. package/src/core/combine/combine.mts +34 -4
  191. package/src/core/combine/merge.mts +30 -4
  192. package/src/core/combine/zip.mts +28 -3
  193. package/src/core/create/from-array.mts +21 -3
  194. package/src/core/create/from-promise.mts +29 -7
  195. package/src/core/create/from-subscribable.mts +58 -0
  196. package/src/core/create/interval.mts +29 -4
  197. package/src/core/create/of.mts +22 -3
  198. package/src/core/create/source.mts +22 -3
  199. package/src/core/create/timer.mts +23 -4
  200. package/src/core/index.mts +1 -0
  201. package/src/core/operators/audit-time.mts +59 -0
  202. package/src/core/operators/debounce-time.mts +22 -2
  203. package/src/core/operators/filter.mts +26 -1
  204. package/src/core/operators/map-with-index.mts +22 -66
  205. package/src/core/operators/merge-map.mts +48 -6
  206. package/src/core/operators/pairwise.mts +30 -1
  207. package/src/core/operators/scan.mts +23 -1
  208. package/src/core/operators/skip-if-no-change.mts +27 -3
  209. package/src/core/operators/skip-until.mts +50 -0
  210. package/src/core/operators/skip-while.mts +49 -16
  211. package/src/core/operators/switch-map.mts +39 -5
  212. package/src/core/operators/take-until.mts +20 -1
  213. package/src/core/operators/take-while.mts +49 -8
  214. package/src/core/operators/throttle-time.mts +44 -5
  215. package/src/core/operators/with-buffered-from.mts +58 -1
  216. package/src/core/operators/with-current-value-from.mts +60 -1
  217. package/src/core/operators/with-initial-value.mts +24 -2
  218. package/src/core/predefined/index.mts +1 -0
  219. package/src/core/predefined/operators/attach-index.mts +13 -0
  220. package/src/core/predefined/operators/index.mts +12 -0
  221. package/src/core/predefined/operators/map-optional.mts +8 -0
  222. package/src/core/predefined/operators/map-result-err.mts +8 -0
  223. package/src/core/predefined/operators/map-result-ok.mts +8 -0
  224. package/src/core/predefined/operators/map-to.mts +5 -0
  225. package/src/core/predefined/operators/map.mts +5 -0
  226. package/src/core/predefined/operators/pluck.mts +12 -0
  227. package/src/core/predefined/operators/skip.mts +10 -0
  228. package/src/core/predefined/operators/take.mts +6 -0
  229. package/src/core/predefined/operators/unwrap-optional.mts +9 -0
  230. package/src/core/predefined/operators/unwrap-result-err.mts +8 -0
  231. package/src/core/predefined/operators/unwrap-result-ok.mts +9 -0
  232. package/src/core/types/observable-family.mts +7 -7
  233. package/src/utils/create-event-emitter.mts +20 -2
  234. package/src/utils/create-reducer.mts +13 -1
  235. package/src/utils/create-state.mts +24 -4
@@ -17,23 +17,42 @@ import {
17
17
  *
18
18
  * @example
19
19
  * ```ts
20
+ * // Timeline:
21
+ * //
22
+ * // num$ 1 2 stop 3 (ignored)
23
+ * // stopNotifier X
24
+ * // limited$ 1 2 |------- (completed)
25
+ * //
26
+ * // Explanation:
27
+ * // - takeUntil completes the observable when the notifier emits
28
+ * // - After stop() is called, no further values are emitted
29
+ * // - Useful for cleanup and cancellation patterns
30
+ *
20
31
  * const num$ = source<number>();
21
32
  *
22
33
  * const [stopNotifier, stop_] = createEventEmitter();
23
34
  *
24
35
  * const limited$ = num$.pipe(takeUntil(stopNotifier));
25
36
  *
37
+ * const mut_history: number[] = [];
38
+ *
26
39
  * limited$.subscribe((x) => {
27
- * console.log(x);
40
+ * mut_history.push(x);
28
41
  * });
29
42
  *
30
43
  * num$.next(1); // logs: 1
31
44
  *
45
+ * assert.deepStrictEqual(mut_history, [1]);
46
+ *
32
47
  * num$.next(2); // logs: 2
33
48
  *
49
+ * assert.deepStrictEqual(mut_history, [1, 2]);
50
+ *
34
51
  * stop_();
35
52
  *
36
53
  * num$.next(3); // nothing logged (completed)
54
+ *
55
+ * assert.deepStrictEqual(mut_history, [1, 2]);
37
56
  * ```
38
57
  */
39
58
  export const takeUntil = <A,>(
@@ -16,6 +16,53 @@ import {
16
16
  } from '../types/index.mjs';
17
17
  import { withInitialValue } from './with-initial-value.mjs';
18
18
 
19
+ /**
20
+ * Emits values from the source observable while the predicate returns true.
21
+ * Completes immediately when the predicate returns false.
22
+ *
23
+ * @template A - The type of values from the source
24
+ * @param predicate - Function to test each value
25
+ * @returns An operator that takes values while the predicate is true
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * // Timeline:
30
+ * //
31
+ * // num$ 1 2 3 4 5 6 (ignored)
32
+ * // taken$ 1 2 3 4 | (completes)
33
+ * //
34
+ * // Explanation:
35
+ * // - takeWhile emits values while the predicate returns true
36
+ * // - Completes immediately when the predicate returns false
37
+ * // - No further values are emitted after completion
38
+ *
39
+ * const num$ = source<number>();
40
+ *
41
+ * const taken$ = num$.pipe(takeWhile((x) => x < 5));
42
+ *
43
+ * const mut_history: number[] = [];
44
+ *
45
+ * taken$.subscribe((x) => {
46
+ * mut_history.push(x);
47
+ * });
48
+ *
49
+ * num$.next(1); // logs: 1
50
+ *
51
+ * assert.deepStrictEqual(mut_history, [1]);
52
+ *
53
+ * num$.next(2); // logs: 2
54
+ *
55
+ * assert.deepStrictEqual(mut_history, [1, 2]);
56
+ *
57
+ * num$.next(5); // nothing logged (completes)
58
+ *
59
+ * assert.deepStrictEqual(mut_history, [1, 2]);
60
+ *
61
+ * num$.next(6); // nothing logged (already completed)
62
+ *
63
+ * assert.deepStrictEqual(mut_history, [1, 2]);
64
+ * ```
65
+ */
19
66
  export const takeWhile =
20
67
  <A,>(
21
68
  predicate: (value: A, index: SafeUint | -1) => boolean,
@@ -23,12 +70,6 @@ export const takeWhile =
23
70
  (parentObservable) =>
24
71
  new TakeWhileObservableClass(parentObservable, predicate);
25
72
 
26
- /* Specialized operators */
27
-
28
- export const take = <A,>(
29
- n: PositiveSafeIntWithSmallInt,
30
- ): DropInitialValueOperator<A, A> => takeWhile((_, index) => index + 1 <= n);
31
-
32
73
  /* implementation */
33
74
 
34
75
  class TakeWhileObservableClass<A>
@@ -86,7 +127,7 @@ if (import.meta.vitest !== undefined) {
86
127
  {
87
128
  const s: Observable<number> = source<number>();
88
129
 
89
- const _d1 = s.pipe(take(3));
130
+ const _d1 = s.pipe(takeWhile((_, index) => index + 1 <= 3));
90
131
 
91
132
  expectType<typeof _d1, Observable<number>>('=');
92
133
  }
@@ -96,7 +137,7 @@ if (import.meta.vitest !== undefined) {
96
137
 
97
138
  const m: InitializedObservable<number> = s.pipe(withInitialValue(0));
98
139
 
99
- const _d = m.pipe(take(3));
140
+ const _d = m.pipe(takeWhile((_, index) => index + 1 <= 3));
100
141
 
101
142
  expectType<typeof _d, Observable<number>>('=');
102
143
  }
@@ -17,14 +17,53 @@ import {
17
17
  *
18
18
  * @example
19
19
  * ```ts
20
- * const scroll$ = source<Event>();
20
+ * // Timeline (1000ms throttle):
21
+ * //
22
+ * // Time(ms) 0 100 200 300 ... 1000 1100 1200 ... 2000 2100
23
+ * // scroll$ e1 e2 e3 e4 e5 e6 e7 e8 e9
24
+ * // throttled$ e1 e5 e8
25
+ * // |-------1000ms------> |------1000ms------> |------1000ms------>
26
+ * //
27
+ * // Explanation:
28
+ * // - throttleTime emits the first value immediately, then ignores subsequent values
29
+ * // for the specified duration (1000ms)
30
+ * // - At 0ms: e1 is emitted immediately
31
+ * // - At 100-300ms: e2, e3, e4 are ignored (within 1000ms window)
32
+ * // - At 1000ms: e5 is emitted (1000ms has passed since e1)
33
+ * // - At 1100-1200ms: e6, e7 are ignored
34
+ * // - At 2000ms: e8 is emitted (1000ms has passed since e5)
21
35
  *
22
- * const throttled$ = scroll$.pipe(throttleTime(1000));
36
+ * const scroll$ = source<number>();
23
37
  *
24
- * throttled$.subscribe((event_) => {
25
- * console.log(event_);
38
+ * const throttled$ = scroll$.pipe(throttleTime(200));
39
+ *
40
+ * const mut_history: number[] = [];
41
+ *
42
+ * throttled$.subscribe((value) => {
43
+ * mut_history.push(value);
26
44
  * });
27
- * // Emits at most once per second
45
+ *
46
+ * scroll$.next(1);
47
+ *
48
+ * assert.deepStrictEqual(mut_history, [1]);
49
+ *
50
+ * await new Promise((resolve) => {
51
+ * setTimeout(resolve, 50);
52
+ * });
53
+ *
54
+ * scroll$.next(2);
55
+ *
56
+ * scroll$.next(3);
57
+ *
58
+ * assert.deepStrictEqual(mut_history, [1]);
59
+ *
60
+ * await new Promise((resolve) => {
61
+ * setTimeout(resolve, 200);
62
+ * });
63
+ *
64
+ * scroll$.next(4);
65
+ *
66
+ * assert.deepStrictEqual(mut_history, [1, 4]);
28
67
  * ```
29
68
  */
30
69
  export const throttleTime = <A,>(
@@ -8,6 +8,59 @@ import {
8
8
  } from '../types/index.mjs';
9
9
  import { maxDepth } from '../utils/index.mjs';
10
10
 
11
+ /**
12
+ * Buffers values from the source observable and emits them along with the parent value
13
+ * when the parent emits. The buffer is cleared after each emission.
14
+ *
15
+ * @template A - The type of values from the parent observable
16
+ * @template B - The type of values from the source observable
17
+ * @param observable - The observable whose values will be buffered
18
+ * @returns An operator that emits tuples of [parentValue, bufferedValues]
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * // Timeline:
23
+ * //
24
+ * // data$ d1 d2 d3 d4 d5 d6 d7 d8
25
+ * // trigger$ T1 T2 T3
26
+ * // result$ [T1,[d1,d2,d3]] [T2,[d4,d5,d6]] [T3,[d7,d8]]
27
+ * //
28
+ * // Explanation:
29
+ * // - withBufferedFrom collects values from the source observable
30
+ * // - When the trigger emits, it emits a tuple of [triggerValue, bufferedValues]
31
+ * // - Buffer is cleared after each emission
32
+ * // - Useful for batching data collection triggered by events
33
+ *
34
+ * const data$ = source<string>();
35
+ *
36
+ * const trigger$ = source<number>();
37
+ *
38
+ * const result$ = trigger$.pipe(withBufferedFrom(data$));
39
+ *
40
+ * const mut_history: (readonly [number, readonly string[]])[] = [];
41
+ *
42
+ * result$.subscribe(([triggerValue, bufferedData]) => {
43
+ * mut_history.push([triggerValue, bufferedData]);
44
+ * });
45
+ *
46
+ * data$.next('a');
47
+ *
48
+ * data$.next('b');
49
+ *
50
+ * trigger$.next(1);
51
+ *
52
+ * assert.deepStrictEqual(mut_history, [[1, ['a', 'b']]]);
53
+ *
54
+ * data$.next('c');
55
+ *
56
+ * trigger$.next(2);
57
+ *
58
+ * assert.deepStrictEqual(mut_history, [
59
+ * [1, ['a', 'b']],
60
+ * [2, ['c']],
61
+ * ]);
62
+ * ```
63
+ */
11
64
  export const withBufferedFrom = <A, B>(
12
65
  observable: Observable<B>,
13
66
  ): KeepInitialValueOperator<A, readonly [A, readonly B[]]> =>
@@ -18,7 +71,11 @@ export const withBufferedFrom = <A, B>(
18
71
  observable,
19
72
  )) as KeepInitialValueOperator<A, readonly [A, readonly B[]]>;
20
73
 
21
- export const withBuffered = withBufferedFrom; // alias
74
+ /**
75
+ * Alias for `withBufferedFrom`.
76
+ * @see withBufferedFrom
77
+ */
78
+ export const withBuffered = withBufferedFrom;
22
79
 
23
80
  class WithBufferedFromObservableClass<A, B>
24
81
  extends SyncChildObservableClass<readonly [A, readonly B[]], readonly [A]>
@@ -8,6 +8,61 @@ import {
8
8
  } from '../types/index.mjs';
9
9
  import { maxDepth } from '../utils/index.mjs';
10
10
 
11
+ /**
12
+ * Samples the current value from another observable each time the source emits.
13
+ * Emits a tuple of [sourceValue, sampledValue].
14
+ *
15
+ * @template A - The type of values from the source observable
16
+ * @template B - The type of values from the sampled observable
17
+ * @param observable - The observable to sample from
18
+ * @returns An operator that emits tuples of source and sampled values
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * // Timeline:
23
+ * //
24
+ * // name$ "Alice" "Bob" "Charlie"
25
+ * // age$ 25 30 35 40
26
+ * // result$ ["Alice",25] ["Bob",30] ["Bob",35] ["Charlie",40]
27
+ * //
28
+ * // Explanation:
29
+ * // - withCurrentValueFrom samples the current value from another observable
30
+ * // - Emits a tuple [sourceValue, sampledValue] each time the source emits
31
+ * // - Does not emit until both observables have emitted at least once
32
+ * // - Similar to combine, but only emits when the source (not the sampled) emits
33
+ *
34
+ * const name$ = source<string>();
35
+ *
36
+ * const age$ = source<number>();
37
+ *
38
+ * const result$ = name$.pipe(withCurrentValueFrom(age$));
39
+ *
40
+ * const mut_history: (readonly [string, number])[] = [];
41
+ *
42
+ * result$.subscribe(([name_, currentAge]) => {
43
+ * mut_history.push([name_, currentAge]);
44
+ * });
45
+ *
46
+ * name$.next('Alice'); // nothing logged (age$ hasn't emitted)
47
+ *
48
+ * assert.deepStrictEqual(mut_history, []);
49
+ *
50
+ * age$.next(25);
51
+ *
52
+ * name$.next('Bob'); // logs: Bob is 25 years old
53
+ *
54
+ * assert.deepStrictEqual(mut_history, [['Bob', 25]]);
55
+ *
56
+ * age$.next(30);
57
+ *
58
+ * name$.next('Charlie'); // logs: Charlie is 30 years old
59
+ *
60
+ * assert.deepStrictEqual(mut_history, [
61
+ * ['Bob', 25],
62
+ * ['Charlie', 30],
63
+ * ]);
64
+ * ```
65
+ */
11
66
  export const withCurrentValueFrom =
12
67
  <A, B>(
13
68
  observable: Observable<B>,
@@ -15,7 +70,11 @@ export const withCurrentValueFrom =
15
70
  (parentObservable) =>
16
71
  new WithCurrentValueFromObservableClass(parentObservable, observable);
17
72
 
18
- export const withLatestFrom = withCurrentValueFrom; // alias
73
+ /**
74
+ * Alias for `withCurrentValueFrom`.
75
+ * @see withCurrentValueFrom
76
+ */
77
+ export const withLatestFrom = withCurrentValueFrom;
19
78
 
20
79
  class WithCurrentValueFromObservableClass<A, B>
21
80
  extends SyncChildObservableClass<readonly [A, B], readonly [A]>
@@ -21,15 +21,37 @@ import {
21
21
  *
22
22
  * @example
23
23
  * ```ts
24
+ * // Timeline:
25
+ * //
26
+ * // num$ 1 2 3
27
+ * // withInitial$ 0 1 2 3
28
+ * // ^
29
+ * // initial value
30
+ * //
31
+ * // Explanation:
32
+ * // - withInitialValue provides an initial value before the source emits
33
+ * // - Converts an uninitialized observable to an initialized one
34
+ * // - Useful when you need a default value immediately
35
+ *
24
36
  * const num$ = source<number>();
25
37
  *
26
38
  * const initialized$ = num$.pipe(withInitialValue(0));
27
39
  *
40
+ * const mut_history: number[] = [];
41
+ *
28
42
  * initialized$.subscribe((x) => {
29
- * console.log(x);
30
- * }); // immediately logs: 0
43
+ * mut_history.push(x);
44
+ * });
45
+ *
46
+ * assert.deepStrictEqual(mut_history, [0]);
31
47
  *
32
48
  * num$.next(1); // logs: 1
49
+ *
50
+ * assert.deepStrictEqual(mut_history, [0, 1]);
51
+ *
52
+ * num$.next(2); // logs: 2
53
+ *
54
+ * assert.deepStrictEqual(mut_history, [0, 1, 2]);
33
55
  * ```
34
56
  */
35
57
  export const withInitialValue =
@@ -0,0 +1 @@
1
+ export * from './operators/index.mjs';
@@ -0,0 +1,13 @@
1
+ import { mapWithIndex } from '../../operators/index.mjs';
2
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
3
+
4
+ export const withIndex = <A,>(): KeepInitialValueOperator<
5
+ A,
6
+ readonly [SafeUint | -1, A]
7
+ > => mapWithIndex((a, i) => [i, a] as const);
8
+
9
+ /**
10
+ * Alias for `withIndex`.
11
+ * @see withIndex
12
+ */
13
+ export const attachIndex = withIndex;
@@ -0,0 +1,12 @@
1
+ export * from './attach-index.mjs';
2
+ export * from './map-optional.mjs';
3
+ export * from './map-result-err.mjs';
4
+ export * from './map-result-ok.mjs';
5
+ export * from './map-to.mjs';
6
+ export * from './map.mjs';
7
+ export * from './pluck.mjs';
8
+ export * from './skip.mjs';
9
+ export * from './take.mjs';
10
+ export * from './unwrap-optional.mjs';
11
+ export * from './unwrap-result-err.mjs';
12
+ export * from './unwrap-result-ok.mjs';
@@ -0,0 +1,8 @@
1
+ import { Optional } from 'ts-data-forge';
2
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
3
+ import { map } from './map.mjs';
4
+
5
+ export const mapOptional = <O extends UnknownOptional, B>(
6
+ mapFn: (x: Optional.Unwrap<O>) => B,
7
+ ): KeepInitialValueOperator<O, Optional<B>> =>
8
+ map((a) => Optional.map(a, mapFn));
@@ -0,0 +1,8 @@
1
+ import { Result } from 'ts-data-forge';
2
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
3
+ import { map } from './map.mjs';
4
+
5
+ export const mapResultErr = <R extends UnknownResult, E2>(
6
+ mapFn: (x: Result.UnwrapErr<R>) => E2,
7
+ ): KeepInitialValueOperator<R, Result<Result.UnwrapOk<R>, E2>> =>
8
+ map((a) => Result.mapErr(a, mapFn));
@@ -0,0 +1,8 @@
1
+ import { Result } from 'ts-data-forge';
2
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
3
+ import { map } from './map.mjs';
4
+
5
+ export const mapResultOk = <R extends UnknownResult, S2>(
6
+ mapFn: (x: Result.UnwrapOk<R>) => S2,
7
+ ): KeepInitialValueOperator<R, Result<S2, Result.UnwrapErr<R>>> =>
8
+ map((a) => Result.map(a, mapFn));
@@ -0,0 +1,5 @@
1
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
2
+ import { map } from './map.mjs';
3
+
4
+ export const mapTo = <A, B>(value: B): KeepInitialValueOperator<A, B> =>
5
+ map(() => value);
@@ -0,0 +1,5 @@
1
+ import { mapWithIndex } from '../../operators/index.mjs';
2
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
3
+
4
+ export const map = <A, B>(mapFn: (x: A) => B): KeepInitialValueOperator<A, B> =>
5
+ mapWithIndex(mapFn);
@@ -0,0 +1,12 @@
1
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
2
+ import { map } from './map.mjs';
3
+
4
+ export const pluck = <A, K extends keyof A>(
5
+ key: K,
6
+ ): KeepInitialValueOperator<A, A[K]> => map((a) => a[key]);
7
+
8
+ /**
9
+ * Alias for `pluck`.
10
+ * @see pluck
11
+ */
12
+ export const getKey = pluck;
@@ -0,0 +1,10 @@
1
+ import { PositiveSafeInt } from 'ts-data-forge';
2
+ import { skipWhile } from '../../operators/index.mjs';
3
+ import { type DropInitialValueOperator } from '../../types/index.mjs';
4
+
5
+ export const skip = <A,>(
6
+ n: PositiveSafeIntWithSmallInt,
7
+ ): DropInitialValueOperator<A, A> =>
8
+ !PositiveSafeInt.is(n) ? idFn : skipWhile((_, index) => index + 1 <= n);
9
+
10
+ const idFn = <T,>(value: T): T => value;
@@ -0,0 +1,6 @@
1
+ import { takeWhile } from '../../operators/index.mjs';
2
+ import { type DropInitialValueOperator } from '../../types/index.mjs';
3
+
4
+ export const take = <A,>(
5
+ n: PositiveSafeIntWithSmallInt,
6
+ ): DropInitialValueOperator<A, A> => takeWhile((_, index) => index + 1 <= n);
@@ -0,0 +1,9 @@
1
+ import { Optional } from 'ts-data-forge';
2
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
3
+ import { map } from './map.mjs';
4
+
5
+ export const unwrapOptional = <
6
+ O extends UnknownOptional,
7
+ >(): KeepInitialValueOperator<O, Optional.Unwrap<O> | undefined> =>
8
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
9
+ map(Optional.unwrap as Fn<O, Optional.Unwrap<O> | undefined>);
@@ -0,0 +1,8 @@
1
+ import { Result } from 'ts-data-forge';
2
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
3
+ import { map } from './map.mjs';
4
+
5
+ export const unwrapResultErr = <
6
+ R extends UnknownResult,
7
+ >(): KeepInitialValueOperator<R, Result.UnwrapErr<R> | undefined> =>
8
+ map(Result.unwrapErr as Fn<R, Result.UnwrapErr<R> | undefined>);
@@ -0,0 +1,9 @@
1
+ import { Result } from 'ts-data-forge';
2
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
3
+ import { map } from './map.mjs';
4
+
5
+ export const unwrapResultOk = <
6
+ R extends UnknownResult,
7
+ >(): KeepInitialValueOperator<R, Result.UnwrapOk<R> | undefined> =>
8
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
9
+ map(Result.unwrapOk as Fn<R, Result.UnwrapOk<R> | undefined>);
@@ -65,7 +65,7 @@ export type ScanOperatorObservable<A, B> = InitializedSyncChildObservable<
65
65
 
66
66
  // SyncChildObservable
67
67
 
68
- namespace SyncFlowInternals {
68
+ namespace SynStateInternals {
69
69
  type Cast<A> = A extends NonEmptyUnknownList ? A : never;
70
70
 
71
71
  type EveryInitialized<OS extends NonEmptyArray<Observable<unknown>>> =
@@ -164,25 +164,25 @@ namespace SyncFlowInternals {
164
164
  }
165
165
 
166
166
  export type CombineObservable<A extends NonEmptyUnknownList> =
167
- SyncFlowInternals.CombineObservableImpl<A>;
167
+ SynStateInternals.CombineObservableImpl<A>;
168
168
 
169
169
  export type CombineObservableRefined<
170
170
  OS extends NonEmptyArray<Observable<unknown>>,
171
- > = SyncFlowInternals.CombineObservableRefinedImpl<OS>;
171
+ > = SynStateInternals.CombineObservableRefinedImpl<OS>;
172
172
 
173
173
  export type ZipObservable<A extends NonEmptyUnknownList> =
174
- SyncFlowInternals.ZipObservableImpl<A>;
174
+ SynStateInternals.ZipObservableImpl<A>;
175
175
 
176
176
  export type ZipObservableRefined<
177
177
  OS extends NonEmptyArray<Observable<unknown>>,
178
- > = SyncFlowInternals.ZipObservableRefinedImpl<OS>;
178
+ > = SynStateInternals.ZipObservableRefinedImpl<OS>;
179
179
 
180
180
  export type MergeObservable<A extends NonEmptyUnknownList> =
181
- SyncFlowInternals.MergeObservableImpl<A>;
181
+ SynStateInternals.MergeObservableImpl<A>;
182
182
 
183
183
  export type MergeObservableRefined<
184
184
  OS extends NonEmptyArray<Observable<unknown>>,
185
- > = SyncFlowInternals.MergeObservableRefinedImpl<OS>;
185
+ > = SynStateInternals.MergeObservableRefinedImpl<OS>;
186
186
 
187
187
  export type MapWithIndexOperatorObservable<A, B> = SyncChildObservable<
188
188
  B,
@@ -10,11 +10,21 @@ import { source, type Observable } from '../core/index.mjs';
10
10
  * ```ts
11
11
  * const [click$, emitClick] = createEventEmitter();
12
12
  *
13
+ * const mut_clickCount = { value: 0 };
14
+ *
13
15
  * click$.subscribe(() => {
14
- * console.log('Clicked!');
16
+ * mut_clickCount.value += 1;
15
17
  * });
16
18
  *
17
19
  * emitClick(); // logs: Clicked!
20
+ *
21
+ * assert.deepStrictEqual(mut_clickCount.value, 1);
22
+ *
23
+ * emitClick();
24
+ *
25
+ * emitClick();
26
+ *
27
+ * assert.deepStrictEqual(mut_clickCount.value, 3);
18
28
  * ```
19
29
  */
20
30
  export const createEventEmitter = (): readonly [
@@ -41,11 +51,19 @@ export const createEventEmitter = (): readonly [
41
51
  * ```ts
42
52
  * const [message$, emitMessage] = createValueEmitter<string>();
43
53
  *
54
+ * const mut_history: string[] = [];
55
+ *
44
56
  * message$.subscribe((msg) => {
45
- * console.log(msg);
57
+ * mut_history.push(msg);
46
58
  * });
47
59
  *
48
60
  * emitMessage('Hello'); // logs: Hello
61
+ *
62
+ * assert.deepStrictEqual(mut_history, ['Hello']);
63
+ *
64
+ * emitMessage('World');
65
+ *
66
+ * assert.deepStrictEqual(mut_history, ['Hello', 'World']);
49
67
  * ```
50
68
  */
51
69
  export const createValueEmitter = <A,>(): readonly [
@@ -24,11 +24,23 @@ import { source, type InitializedObservable } from '../core/index.mjs';
24
24
  * 0,
25
25
  * );
26
26
  *
27
+ * const mut_history: number[] = [];
28
+ *
27
29
  * state.subscribe((value: number) => {
28
- * console.log(value);
30
+ * mut_history.push(value);
29
31
  * });
30
32
  *
33
+ * assert.deepStrictEqual(mut_history, [0]);
34
+ *
31
35
  * dispatch({ type: 'increment' }); // logs: 1
36
+ *
37
+ * assert.deepStrictEqual(mut_history, [0, 1]);
38
+ *
39
+ * dispatch({ type: 'increment' });
40
+ *
41
+ * dispatch({ type: 'decrement' });
42
+ *
43
+ * assert.deepStrictEqual(mut_history, [0, 1, 2, 1]);
32
44
  * ```
33
45
  */
34
46
  export const createReducer = <S, A>(