synstate 0.1.1 → 1.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.
Files changed (309) hide show
  1. package/README.md +317 -298
  2. package/dist/core/class/child-observable-class.d.mts.map +1 -1
  3. package/dist/core/class/child-observable-class.mjs +43 -10
  4. package/dist/core/class/child-observable-class.mjs.map +1 -1
  5. package/dist/core/class/observable-base-class.d.mts +4 -4
  6. package/dist/core/class/observable-base-class.d.mts.map +1 -1
  7. package/dist/core/class/observable-base-class.mjs +8 -8
  8. package/dist/core/class/observable-base-class.mjs.map +1 -1
  9. package/dist/core/class/root-observable-class.d.mts +1 -1
  10. package/dist/core/class/root-observable-class.d.mts.map +1 -1
  11. package/dist/core/class/root-observable-class.mjs +9 -9
  12. package/dist/core/class/root-observable-class.mjs.map +1 -1
  13. package/dist/core/combine/combine.d.mts +7 -7
  14. package/dist/core/combine/combine.mjs +13 -14
  15. package/dist/core/combine/combine.mjs.map +1 -1
  16. package/dist/core/combine/merge.d.mts +6 -6
  17. package/dist/core/combine/merge.mjs +9 -9
  18. package/dist/core/combine/merge.mjs.map +1 -1
  19. package/dist/core/combine/zip.d.mts +20 -19
  20. package/dist/core/combine/zip.d.mts.map +1 -1
  21. package/dist/core/combine/zip.mjs +22 -21
  22. package/dist/core/combine/zip.mjs.map +1 -1
  23. package/dist/core/create/{interval.d.mts → counter.d.mts} +14 -12
  24. package/dist/core/create/counter.d.mts.map +1 -0
  25. package/dist/core/create/{interval.mjs → counter.mjs} +21 -23
  26. package/dist/core/create/counter.mjs.map +1 -0
  27. package/dist/core/create/from-abortable-promise.d.mts +29 -0
  28. package/dist/core/create/from-abortable-promise.d.mts.map +1 -0
  29. package/dist/core/create/from-abortable-promise.mjs +70 -0
  30. package/dist/core/create/from-abortable-promise.mjs.map +1 -0
  31. package/dist/core/create/from-promise.d.mts +9 -6
  32. package/dist/core/create/from-promise.d.mts.map +1 -1
  33. package/dist/core/create/from-promise.mjs +8 -5
  34. package/dist/core/create/from-promise.mjs.map +1 -1
  35. package/dist/core/create/from-subscribable.d.mts +4 -4
  36. package/dist/core/create/from-subscribable.mjs +4 -4
  37. package/dist/core/create/index.d.mts +3 -3
  38. package/dist/core/create/index.d.mts.map +1 -1
  39. package/dist/core/create/index.mjs +4 -4
  40. package/dist/core/create/just.d.mts +32 -0
  41. package/dist/core/create/just.d.mts.map +1 -0
  42. package/dist/core/create/just.mjs +44 -0
  43. package/dist/core/create/just.mjs.map +1 -0
  44. package/dist/core/create/source.d.mts +7 -12
  45. package/dist/core/create/source.d.mts.map +1 -1
  46. package/dist/core/create/source.mjs +1 -6
  47. package/dist/core/create/source.mjs.map +1 -1
  48. package/dist/core/create/timer.d.mts +6 -4
  49. package/dist/core/create/timer.d.mts.map +1 -1
  50. package/dist/core/create/timer.mjs +6 -7
  51. package/dist/core/create/timer.mjs.map +1 -1
  52. package/dist/core/index.d.mts +1 -1
  53. package/dist/core/index.d.mts.map +1 -1
  54. package/dist/core/index.mjs +21 -14
  55. package/dist/core/index.mjs.map +1 -1
  56. package/dist/core/operators/audit.d.mts +97 -0
  57. package/dist/core/operators/audit.d.mts.map +1 -0
  58. package/dist/core/operators/audit.mjs +144 -0
  59. package/dist/core/operators/audit.mjs.map +1 -0
  60. package/dist/core/operators/debounce.d.mts +88 -0
  61. package/dist/core/operators/debounce.d.mts.map +1 -0
  62. package/dist/core/operators/debounce.mjs +130 -0
  63. package/dist/core/operators/debounce.mjs.map +1 -0
  64. package/dist/core/operators/filter.d.mts +5 -5
  65. package/dist/core/operators/filter.mjs +3 -3
  66. package/dist/core/operators/filter.mjs.map +1 -1
  67. package/dist/core/operators/index.d.mts +4 -4
  68. package/dist/core/operators/index.d.mts.map +1 -1
  69. package/dist/core/operators/index.mjs +6 -6
  70. package/dist/core/operators/map.d.mts +41 -0
  71. package/dist/core/operators/map.d.mts.map +1 -0
  72. package/dist/core/operators/map.mjs +71 -0
  73. package/dist/core/operators/map.mjs.map +1 -0
  74. package/dist/core/operators/merge-map.d.mts +57 -30
  75. package/dist/core/operators/merge-map.d.mts.map +1 -1
  76. package/dist/core/operators/merge-map.mjs +59 -32
  77. package/dist/core/operators/merge-map.mjs.map +1 -1
  78. package/dist/core/operators/pairwise.d.mts +6 -6
  79. package/dist/core/operators/pairwise.mjs +9 -9
  80. package/dist/core/operators/pairwise.mjs.map +1 -1
  81. package/dist/core/operators/scan.d.mts +6 -6
  82. package/dist/core/operators/scan.mjs +9 -9
  83. package/dist/core/operators/scan.mjs.map +1 -1
  84. package/dist/core/operators/skip-if-no-change.d.mts +21 -9
  85. package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
  86. package/dist/core/operators/skip-if-no-change.mjs +25 -13
  87. package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
  88. package/dist/core/operators/skip-until.d.mts +5 -5
  89. package/dist/core/operators/skip-until.mjs +8 -8
  90. package/dist/core/operators/skip-until.mjs.map +1 -1
  91. package/dist/core/operators/skip-while.d.mts +18 -9
  92. package/dist/core/operators/skip-while.d.mts.map +1 -1
  93. package/dist/core/operators/skip-while.mjs +28 -16
  94. package/dist/core/operators/skip-while.mjs.map +1 -1
  95. package/dist/core/operators/switch-map.d.mts +57 -26
  96. package/dist/core/operators/switch-map.d.mts.map +1 -1
  97. package/dist/core/operators/switch-map.mjs +59 -28
  98. package/dist/core/operators/switch-map.mjs.map +1 -1
  99. package/dist/core/operators/take-until.d.mts +5 -5
  100. package/dist/core/operators/take-until.mjs +8 -8
  101. package/dist/core/operators/take-until.mjs.map +1 -1
  102. package/dist/core/operators/take-while.d.mts +15 -8
  103. package/dist/core/operators/take-while.d.mts.map +1 -1
  104. package/dist/core/operators/take-while.mjs +19 -13
  105. package/dist/core/operators/take-while.mjs.map +1 -1
  106. package/dist/core/operators/throttle.d.mts +81 -0
  107. package/dist/core/operators/throttle.d.mts.map +1 -0
  108. package/dist/core/operators/throttle.mjs +126 -0
  109. package/dist/core/operators/throttle.mjs.map +1 -0
  110. package/dist/core/operators/with-buffered-from.d.mts +13 -9
  111. package/dist/core/operators/with-buffered-from.d.mts.map +1 -1
  112. package/dist/core/operators/with-buffered-from.mjs +17 -13
  113. package/dist/core/operators/with-buffered-from.mjs.map +1 -1
  114. package/dist/core/operators/with-current-value-from.d.mts +14 -9
  115. package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
  116. package/dist/core/operators/with-current-value-from.mjs +18 -13
  117. package/dist/core/operators/with-current-value-from.mjs.map +1 -1
  118. package/dist/core/operators/with-initial-value.d.mts +5 -5
  119. package/dist/core/operators/with-initial-value.mjs +8 -8
  120. package/dist/core/operators/with-initial-value.mjs.map +1 -1
  121. package/dist/core/predefined/index.d.mts +2 -0
  122. package/dist/core/predefined/index.d.mts.map +1 -0
  123. package/dist/core/predefined/index.mjs +12 -0
  124. package/dist/core/predefined/index.mjs.map +1 -0
  125. package/dist/core/predefined/operators/attach-index.d.mts +57 -0
  126. package/dist/core/predefined/operators/attach-index.d.mts.map +1 -0
  127. package/dist/core/predefined/operators/attach-index.mjs +62 -0
  128. package/dist/core/predefined/operators/attach-index.mjs.map +1 -0
  129. package/dist/core/predefined/operators/index.d.mts +12 -0
  130. package/dist/core/predefined/operators/index.d.mts.map +1 -0
  131. package/dist/core/predefined/operators/index.mjs +12 -0
  132. package/dist/core/predefined/operators/index.mjs.map +1 -0
  133. package/dist/core/predefined/operators/map-optional.d.mts +51 -0
  134. package/dist/core/predefined/operators/map-optional.d.mts.map +1 -0
  135. package/dist/core/predefined/operators/map-optional.mjs +55 -0
  136. package/dist/core/predefined/operators/map-optional.mjs.map +1 -0
  137. package/dist/core/predefined/operators/map-result-err.d.mts +51 -0
  138. package/dist/core/predefined/operators/map-result-err.d.mts.map +1 -0
  139. package/dist/core/predefined/operators/map-result-err.mjs +55 -0
  140. package/dist/core/predefined/operators/map-result-err.mjs.map +1 -0
  141. package/dist/core/predefined/operators/map-result-ok.d.mts +51 -0
  142. package/dist/core/predefined/operators/map-result-ok.d.mts.map +1 -0
  143. package/dist/core/predefined/operators/map-result-ok.mjs +55 -0
  144. package/dist/core/predefined/operators/map-result-ok.mjs.map +1 -0
  145. package/dist/core/predefined/operators/map-to.d.mts +43 -0
  146. package/dist/core/predefined/operators/map-to.d.mts.map +1 -0
  147. package/dist/core/predefined/operators/map-to.mjs +48 -0
  148. package/dist/core/predefined/operators/map-to.mjs.map +1 -0
  149. package/dist/core/predefined/operators/pluck.d.mts +47 -0
  150. package/dist/core/predefined/operators/pluck.d.mts.map +1 -0
  151. package/dist/core/predefined/operators/pluck.mjs +52 -0
  152. package/dist/core/predefined/operators/pluck.mjs.map +1 -0
  153. package/dist/core/predefined/operators/skip.d.mts +50 -0
  154. package/dist/core/predefined/operators/skip.d.mts.map +1 -0
  155. package/dist/core/predefined/operators/skip.mjs +56 -0
  156. package/dist/core/predefined/operators/skip.mjs.map +1 -0
  157. package/dist/core/predefined/operators/take.d.mts +44 -0
  158. package/dist/core/predefined/operators/take.d.mts.map +1 -0
  159. package/dist/core/predefined/operators/take.mjs +49 -0
  160. package/dist/core/predefined/operators/take.mjs.map +1 -0
  161. package/dist/core/predefined/operators/unwrap-optional.d.mts +44 -0
  162. package/dist/core/predefined/operators/unwrap-optional.d.mts.map +1 -0
  163. package/dist/core/predefined/operators/unwrap-optional.mjs +50 -0
  164. package/dist/core/predefined/operators/unwrap-optional.mjs.map +1 -0
  165. package/dist/core/predefined/operators/unwrap-result-err.d.mts +44 -0
  166. package/dist/core/predefined/operators/unwrap-result-err.d.mts.map +1 -0
  167. package/dist/core/predefined/operators/unwrap-result-err.mjs +48 -0
  168. package/dist/core/predefined/operators/unwrap-result-err.mjs.map +1 -0
  169. package/dist/core/predefined/operators/unwrap-result-ok.d.mts +44 -0
  170. package/dist/core/predefined/operators/unwrap-result-ok.d.mts.map +1 -0
  171. package/dist/core/predefined/operators/unwrap-result-ok.mjs +50 -0
  172. package/dist/core/predefined/operators/unwrap-result-ok.mjs.map +1 -0
  173. package/dist/core/types/id.d.mts +1 -1
  174. package/dist/core/types/id.d.mts.map +1 -1
  175. package/dist/core/types/index.d.mts +1 -0
  176. package/dist/core/types/index.d.mts.map +1 -1
  177. package/dist/core/types/observable-family.d.mts +8 -14
  178. package/dist/core/types/observable-family.d.mts.map +1 -1
  179. package/dist/core/types/observable.d.mts +3 -3
  180. package/dist/core/types/observable.d.mts.map +1 -1
  181. package/dist/core/types/timer.d.mts +2 -0
  182. package/dist/core/types/timer.d.mts.map +1 -0
  183. package/dist/core/types/timer.mjs +2 -0
  184. package/dist/core/types/timer.mjs.map +1 -0
  185. package/dist/core/utils/id-maker.d.mts +2 -2
  186. package/dist/core/utils/id-maker.d.mts.map +1 -1
  187. package/dist/core/utils/id-maker.mjs +3 -3
  188. package/dist/core/utils/id-maker.mjs.map +1 -1
  189. package/dist/core/utils/index.mjs +1 -1
  190. package/dist/entry-point.mjs +24 -15
  191. package/dist/entry-point.mjs.map +1 -1
  192. package/dist/globals.d.mts +0 -3
  193. package/dist/index.mjs +24 -15
  194. package/dist/index.mjs.map +1 -1
  195. package/dist/utils/collect-to-array.d.mts +3 -0
  196. package/dist/utils/collect-to-array.d.mts.map +1 -0
  197. package/dist/utils/collect-to-array.mjs +11 -0
  198. package/dist/utils/collect-to-array.mjs.map +1 -0
  199. package/dist/utils/create-boolean-state.d.mts +40 -0
  200. package/dist/utils/create-boolean-state.d.mts.map +1 -0
  201. package/dist/utils/create-boolean-state.mjs +53 -0
  202. package/dist/utils/create-boolean-state.mjs.map +1 -0
  203. package/dist/utils/create-event-emitter.d.mts +4 -4
  204. package/dist/utils/create-event-emitter.mjs +4 -4
  205. package/dist/utils/create-reducer.d.mts +10 -7
  206. package/dist/utils/create-reducer.d.mts.map +1 -1
  207. package/dist/utils/create-reducer.mjs +7 -7
  208. package/dist/utils/create-reducer.mjs.map +1 -1
  209. package/dist/utils/create-state.d.mts +8 -48
  210. package/dist/utils/create-state.d.mts.map +1 -1
  211. package/dist/utils/create-state.mjs +10 -60
  212. package/dist/utils/create-state.mjs.map +1 -1
  213. package/dist/utils/index.d.mts +2 -0
  214. package/dist/utils/index.d.mts.map +1 -1
  215. package/dist/utils/index.mjs +3 -1
  216. package/dist/utils/index.mjs.map +1 -1
  217. package/package.json +17 -11
  218. package/src/core/class/child-observable-class.mts +65 -9
  219. package/src/core/class/circular-dependency-comparison.test.mts +142 -0
  220. package/src/core/class/circular-dependency.test.mts +251 -0
  221. package/src/core/class/observable-base-class.mts +9 -9
  222. package/src/core/class/root-observable-class.mts +14 -10
  223. package/src/core/combine/combine.mts +15 -15
  224. package/src/core/combine/merge.mts +13 -14
  225. package/src/core/combine/zip.mts +26 -25
  226. package/src/core/create/{interval.mts → counter.mts} +32 -30
  227. package/src/core/create/from-abortable-promise.mts +83 -0
  228. package/src/core/create/from-promise.mts +10 -7
  229. package/src/core/create/from-subscribable.mts +4 -4
  230. package/src/core/create/index.mts +3 -3
  231. package/src/core/create/just.mts +43 -0
  232. package/src/core/create/source.mts +10 -14
  233. package/src/core/create/timer.mts +12 -11
  234. package/src/core/index.mts +1 -1
  235. package/src/core/operators/audit.mts +172 -0
  236. package/src/core/operators/debounce.mts +154 -0
  237. package/src/core/operators/filter.mts +9 -9
  238. package/src/core/operators/index.mts +4 -4
  239. package/src/core/operators/map.mts +124 -0
  240. package/src/core/operators/merge-map.mts +60 -33
  241. package/src/core/operators/pairwise.mts +10 -10
  242. package/src/core/operators/scan.mts +10 -10
  243. package/src/core/operators/skip-if-no-change.mts +26 -14
  244. package/src/core/operators/skip-until.mts +9 -9
  245. package/src/core/operators/skip-while.mts +30 -28
  246. package/src/core/operators/switch-map.mts +60 -29
  247. package/src/core/operators/take-until.mts +9 -9
  248. package/src/core/operators/take-while.mts +21 -19
  249. package/src/core/operators/{throttle-time.mts → throttle.mts} +58 -38
  250. package/src/core/operators/with-buffered-from.mts +18 -14
  251. package/src/core/operators/with-current-value-from.mts +19 -14
  252. package/src/core/operators/with-initial-value.mts +9 -9
  253. package/src/core/predefined/index.mts +1 -0
  254. package/src/core/predefined/operators/attach-index.mts +62 -0
  255. package/src/core/predefined/operators/index.mts +11 -0
  256. package/src/core/predefined/operators/map-optional.mts +55 -0
  257. package/src/core/predefined/operators/map-result-err.mts +55 -0
  258. package/src/core/predefined/operators/map-result-ok.mts +55 -0
  259. package/src/core/predefined/operators/map-to.mts +45 -0
  260. package/src/core/predefined/operators/pluck.mts +51 -0
  261. package/src/core/predefined/operators/skip.mts +57 -0
  262. package/src/core/predefined/operators/take.mts +47 -0
  263. package/src/core/predefined/operators/unwrap-optional.mts +49 -0
  264. package/src/core/predefined/operators/unwrap-result-err.mts +48 -0
  265. package/src/core/predefined/operators/unwrap-result-ok.mts +49 -0
  266. package/src/core/types/id.mts +1 -1
  267. package/src/core/types/index.mts +1 -0
  268. package/src/core/types/observable-family.mts +8 -24
  269. package/src/core/types/observable.mts +3 -3
  270. package/src/core/types/timer.mts +2 -0
  271. package/src/core/utils/id-maker.mts +4 -4
  272. package/src/globals.d.mts +0 -3
  273. package/src/utils/collect-to-array.mts +17 -0
  274. package/src/utils/create-boolean-state.mts +68 -0
  275. package/src/utils/create-event-emitter.mts +4 -4
  276. package/src/utils/create-reducer.mts +11 -8
  277. package/src/utils/create-state.mts +10 -75
  278. package/src/utils/index.mts +2 -0
  279. package/dist/core/create/from-array.d.mts +0 -39
  280. package/dist/core/create/from-array.d.mts.map +0 -1
  281. package/dist/core/create/from-array.mjs +0 -65
  282. package/dist/core/create/from-array.mjs.map +0 -1
  283. package/dist/core/create/interval.d.mts.map +0 -1
  284. package/dist/core/create/interval.mjs.map +0 -1
  285. package/dist/core/create/of.d.mts +0 -39
  286. package/dist/core/create/of.d.mts.map +0 -1
  287. package/dist/core/create/of.mjs +0 -63
  288. package/dist/core/create/of.mjs.map +0 -1
  289. package/dist/core/operators/audit-time.d.mts +0 -62
  290. package/dist/core/operators/audit-time.d.mts.map +0 -1
  291. package/dist/core/operators/audit-time.mjs +0 -109
  292. package/dist/core/operators/audit-time.mjs.map +0 -1
  293. package/dist/core/operators/debounce-time.d.mts +0 -51
  294. package/dist/core/operators/debounce-time.d.mts.map +0 -1
  295. package/dist/core/operators/debounce-time.mjs +0 -93
  296. package/dist/core/operators/debounce-time.mjs.map +0 -1
  297. package/dist/core/operators/map-with-index.d.mts +0 -54
  298. package/dist/core/operators/map-with-index.d.mts.map +0 -1
  299. package/dist/core/operators/map-with-index.mjs +0 -88
  300. package/dist/core/operators/map-with-index.mjs.map +0 -1
  301. package/dist/core/operators/throttle-time.d.mts +0 -62
  302. package/dist/core/operators/throttle-time.d.mts.map +0 -1
  303. package/dist/core/operators/throttle-time.mjs +0 -107
  304. package/dist/core/operators/throttle-time.mjs.map +0 -1
  305. package/src/core/create/from-array.mts +0 -76
  306. package/src/core/create/of.mts +0 -73
  307. package/src/core/operators/audit-time.mts +0 -136
  308. package/src/core/operators/debounce-time.mts +0 -116
  309. package/src/core/operators/map-with-index.mts +0 -183
@@ -0,0 +1,51 @@
1
+ import { map } from '../../operators/index.mjs';
2
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
3
+
4
+ /**
5
+ * Extracts a property value from each emitted object by key.
6
+ * Equivalent to `map(value => value[key])`.
7
+ *
8
+ * @template A - The type of the emitted object
9
+ * @template K - The key to extract
10
+ * @param key - The property key to pluck
11
+ * @returns An operator that emits the property value
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * // Timeline:
16
+ * //
17
+ * // user$ { name: "Alice", age: 25 } { name: "Bob", age: 30 }
18
+ * // name$ "Alice" "Bob"
19
+ * //
20
+ * // Explanation:
21
+ * // - getKey extracts a property value from each emitted object
22
+ * // - Equivalent to map(value => value[key])
23
+ *
24
+ * const user$ = source<Readonly<{ name: string; age: number }>>();
25
+ *
26
+ * const name$ = user$.pipe(getKey('name'));
27
+ *
28
+ * const valueHistory: string[] = [];
29
+ *
30
+ * name$.subscribe((n) => {
31
+ * valueHistory.push(n);
32
+ * });
33
+ *
34
+ * user$.next({ name: 'Alice', age: 25 });
35
+ *
36
+ * assert.deepStrictEqual(valueHistory, ['Alice']);
37
+ *
38
+ * user$.next({ name: 'Bob', age: 30 });
39
+ *
40
+ * assert.deepStrictEqual(valueHistory, ['Alice', 'Bob']);
41
+ * ```
42
+ */
43
+ export const pluck = <A, K extends keyof A>(
44
+ key: K,
45
+ ): KeepInitialValueOperator<A, A[K]> => map((a) => a[key]);
46
+
47
+ /**
48
+ * Alias for `pluck`.
49
+ * @see pluck
50
+ */
51
+ export const getKey = pluck;
@@ -0,0 +1,57 @@
1
+ import { PositiveSafeInt } from 'ts-data-forge';
2
+ import { skipWhile } from '../../operators/index.mjs';
3
+ import { type DropInitialValueOperator } from '../../types/index.mjs';
4
+
5
+ /**
6
+ * Skips the first `n` emissions from the source observable.
7
+ * After `n` values are skipped, all subsequent values pass through.
8
+ *
9
+ * @template A - The type of values from the source
10
+ * @param n - The number of values to skip
11
+ * @returns An operator that skips the first n emissions
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * // Timeline:
16
+ * //
17
+ * // num$ 1 2 3 4 5
18
+ * // skipped$ 3 4 5
19
+ * // |skip 2|
20
+ * //
21
+ * // Explanation:
22
+ * // - skip ignores the first n emissions from the source
23
+ * // - After n values are skipped, all subsequent values pass through
24
+ *
25
+ * const num$ = source<number>();
26
+ *
27
+ * const skipped$ = num$.pipe(skip(2));
28
+ *
29
+ * const valueHistory: number[] = [];
30
+ *
31
+ * skipped$.subscribe((x) => {
32
+ * valueHistory.push(x);
33
+ * });
34
+ *
35
+ * num$.next(1); // skipped
36
+ *
37
+ * num$.next(2); // skipped
38
+ *
39
+ * assert.deepStrictEqual(valueHistory, []);
40
+ *
41
+ * num$.next(3); // logs: 3
42
+ *
43
+ * assert.deepStrictEqual(valueHistory, [3]);
44
+ *
45
+ * num$.next(4); // logs: 4
46
+ *
47
+ * num$.next(5); // logs: 5
48
+ *
49
+ * assert.deepStrictEqual(valueHistory, [3, 4, 5]);
50
+ * ```
51
+ */
52
+ export const skip = <A,>(
53
+ n: PositiveSafeIntWithSmallInt,
54
+ ): DropInitialValueOperator<A, A> =>
55
+ !PositiveSafeInt.is(n) ? idFn : skipWhile((_, index) => index + 1 <= n);
56
+
57
+ const idFn = <T,>(value: T): T => value;
@@ -0,0 +1,47 @@
1
+ import { takeWhile } from '../../operators/index.mjs';
2
+ import { type DropInitialValueOperator } from '../../types/index.mjs';
3
+
4
+ /**
5
+ * Takes only the first `n` emissions from the source observable, then completes.
6
+ *
7
+ * @template A - The type of values from the source
8
+ * @param n - The number of values to take
9
+ * @returns An operator that takes the first n emissions
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // Timeline:
14
+ * //
15
+ * // num$ 1 2 3 4 (ignored)
16
+ * // taken$ 1 2 3 | (completes)
17
+ * //
18
+ * // Explanation:
19
+ * // - take emits only the first n values, then completes
20
+ * // - Subsequent emissions from the source are ignored
21
+ *
22
+ * const num$ = source<number>();
23
+ *
24
+ * const taken$ = num$.pipe(take(3));
25
+ *
26
+ * const valueHistory: number[] = [];
27
+ *
28
+ * taken$.subscribe((x) => {
29
+ * valueHistory.push(x);
30
+ * });
31
+ *
32
+ * num$.next(1);
33
+ *
34
+ * num$.next(2);
35
+ *
36
+ * num$.next(3);
37
+ *
38
+ * assert.deepStrictEqual(valueHistory, [1, 2, 3]);
39
+ *
40
+ * num$.next(4); // ignored (already completed)
41
+ *
42
+ * assert.deepStrictEqual(valueHistory, [1, 2, 3]);
43
+ * ```
44
+ */
45
+ export const take = <A,>(
46
+ n: PositiveSafeIntWithSmallInt,
47
+ ): DropInitialValueOperator<A, A> => takeWhile((_, index) => index + 1 <= n);
@@ -0,0 +1,49 @@
1
+ import { Optional } from 'ts-data-forge';
2
+ import { map } from '../../operators/index.mjs';
3
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
4
+
5
+ /**
6
+ * Unwraps `Optional` values, converting `Some(value)` to `value` and `None` to `undefined`.
7
+ *
8
+ * @template O - The Optional type from the source
9
+ * @returns An operator that unwraps Optional emissions
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // Timeline:
14
+ * //
15
+ * // opt$ Some(42) None Some(7)
16
+ * // unwrapped$ 42 undefined 7
17
+ * //
18
+ * // Explanation:
19
+ * // - unwrapOptional converts Some(value) to value, and None to undefined
20
+ * // - Useful for extracting raw values from Optional streams
21
+ *
22
+ * const opt$ = source<Optional<number>>();
23
+ *
24
+ * const unwrapped$ = opt$.pipe(unwrapOptional());
25
+ *
26
+ * const valueHistory: (number | undefined)[] = [];
27
+ *
28
+ * unwrapped$.subscribe((v) => {
29
+ * valueHistory.push(v);
30
+ * });
31
+ *
32
+ * opt$.next(Optional.some(42));
33
+ *
34
+ * assert.deepStrictEqual(valueHistory, [42]);
35
+ *
36
+ * opt$.next(Optional.none);
37
+ *
38
+ * assert.deepStrictEqual(valueHistory, [42, undefined]);
39
+ *
40
+ * opt$.next(Optional.some(7));
41
+ *
42
+ * assert.deepStrictEqual(valueHistory, [42, undefined, 7]);
43
+ * ```
44
+ */
45
+ export const unwrapOptional = <
46
+ O extends UnknownOptional,
47
+ >(): KeepInitialValueOperator<O, Optional.Unwrap<O> | undefined> =>
48
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
49
+ map(Optional.unwrap as Fn<O, Optional.Unwrap<O> | undefined>);
@@ -0,0 +1,48 @@
1
+ import { Result } from 'ts-data-forge';
2
+ import { map } from '../../operators/index.mjs';
3
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
4
+
5
+ /**
6
+ * Unwraps the error value from a `Result`, converting `Err(error)` to `error` and `Ok` to `undefined`.
7
+ *
8
+ * @template R - The Result type from the source
9
+ * @returns An operator that unwraps the Err side of Result emissions
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // Timeline:
14
+ * //
15
+ * // result$ Ok(1) Err("fail") Ok(2)
16
+ * // unwrapped$ undefined "fail" undefined
17
+ * //
18
+ * // Explanation:
19
+ * // - unwrapResultErr converts Err(error) to error, and Ok to undefined
20
+ * // - Useful for extracting error values from Result streams
21
+ *
22
+ * const result$ = source<Result<number, string>>();
23
+ *
24
+ * const unwrapped$ = result$.pipe(unwrapResultErr());
25
+ *
26
+ * const valueHistory: (string | undefined)[] = [];
27
+ *
28
+ * unwrapped$.subscribe((v) => {
29
+ * valueHistory.push(v);
30
+ * });
31
+ *
32
+ * result$.next(Result.ok(1));
33
+ *
34
+ * assert.deepStrictEqual(valueHistory, [undefined]);
35
+ *
36
+ * result$.next(Result.err('fail'));
37
+ *
38
+ * assert.deepStrictEqual(valueHistory, [undefined, 'fail']);
39
+ *
40
+ * result$.next(Result.ok(2));
41
+ *
42
+ * assert.deepStrictEqual(valueHistory, [undefined, 'fail', undefined]);
43
+ * ```
44
+ */
45
+ export const unwrapResultErr = <
46
+ R extends UnknownResult,
47
+ >(): KeepInitialValueOperator<R, Result.UnwrapErr<R> | undefined> =>
48
+ map(Result.unwrapErr as Fn<R, Result.UnwrapErr<R> | undefined>);
@@ -0,0 +1,49 @@
1
+ import { Result } from 'ts-data-forge';
2
+ import { map } from '../../operators/index.mjs';
3
+ import { type KeepInitialValueOperator } from '../../types/index.mjs';
4
+
5
+ /**
6
+ * Unwraps the success value from a `Result`, converting `Ok(value)` to `value` and `Err` to `undefined`.
7
+ *
8
+ * @template R - The Result type from the source
9
+ * @returns An operator that unwraps the Ok side of Result emissions
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // Timeline:
14
+ * //
15
+ * // result$ Ok(42) Err("e") Ok(7)
16
+ * // unwrapped$ 42 undefined 7
17
+ * //
18
+ * // Explanation:
19
+ * // - unwrapResultOk converts Ok(value) to value, and Err to undefined
20
+ * // - Useful for extracting success values from Result streams
21
+ *
22
+ * const result$ = source<Result<number, string>>();
23
+ *
24
+ * const unwrapped$ = result$.pipe(unwrapResultOk());
25
+ *
26
+ * const valueHistory: (number | undefined)[] = [];
27
+ *
28
+ * unwrapped$.subscribe((v) => {
29
+ * valueHistory.push(v);
30
+ * });
31
+ *
32
+ * result$.next(Result.ok(42));
33
+ *
34
+ * assert.deepStrictEqual(valueHistory, [42]);
35
+ *
36
+ * result$.next(Result.err('e'));
37
+ *
38
+ * assert.deepStrictEqual(valueHistory, [42, undefined]);
39
+ *
40
+ * result$.next(Result.ok(7));
41
+ *
42
+ * assert.deepStrictEqual(valueHistory, [42, undefined, 7]);
43
+ * ```
44
+ */
45
+ export const unwrapResultOk = <
46
+ R extends UnknownResult,
47
+ >(): KeepInitialValueOperator<R, Result.UnwrapOk<R> | undefined> =>
48
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
49
+ map(Result.unwrapOk as Fn<R, Result.UnwrapOk<R> | undefined>);
@@ -2,4 +2,4 @@ export type ObservableId = Brand<symbol, 'observable-id'>;
2
2
 
3
3
  export type SubscriberId = Brand<symbol, 'subscriber-id'>;
4
4
 
5
- export type UpdaterSymbol = Brand<symbol, 'updater-symbol'>;
5
+ export type UpdateToken = Brand<symbol, 'update-token'>;
@@ -2,4 +2,5 @@ export * from './id.mjs';
2
2
  export * from './observable-family.mjs';
3
3
  export * from './observable-kind.mjs';
4
4
  export * from './observable.mjs';
5
+ export * from './timer.mjs';
5
6
  export * from './types.mjs';
@@ -23,16 +23,6 @@ export type SourceObservable<A> = Readonly<{
23
23
  }> &
24
24
  RootObservable<A>;
25
25
 
26
- export type OfObservable<A> = Readonly<{
27
- emit: () => OfObservable<A>;
28
- }> &
29
- RootObservable<A>;
30
-
31
- export type FromArrayObservable<A> = Readonly<{
32
- emit: () => FromArrayObservable<A>;
33
- }> &
34
- RootObservable<A>;
35
-
36
26
  export type FromPromiseObservable<A, E = unknown> = RootObservable<
37
27
  Result<A, E>
38
28
  >;
@@ -41,13 +31,13 @@ export type FromSubscribableObservable<A, E = unknown> = RootObservable<
41
31
  Result<A, E>
42
32
  >;
43
33
 
44
- export type IntervalObservable = Readonly<{
45
- start: () => IntervalObservable;
34
+ export type CounterObservable = Readonly<{
35
+ start: () => void;
46
36
  }> &
47
37
  RootObservable<SafeUint>;
48
38
 
49
39
  export type TimerObservable = Readonly<{
50
- start: () => TimerObservable;
40
+ start: () => void;
51
41
  }> &
52
42
  RootObservable<0>;
53
43
 
@@ -77,7 +67,7 @@ namespace SynStateInternals {
77
67
  ? true
78
68
  : false;
79
69
 
80
- /** Evaluates True | false as true instead of boolean */
70
+ /** Evaluates true | false as true instead of boolean */
81
71
  type LogicalValue<B extends boolean> = readonly [B] extends readonly [true]
82
72
  ? true
83
73
  : readonly [B] extends readonly [false]
@@ -184,10 +174,7 @@ export type MergeObservableRefined<
184
174
  OS extends NonEmptyArray<Observable<unknown>>,
185
175
  > = SynStateInternals.MergeObservableRefinedImpl<OS>;
186
176
 
187
- export type MapWithIndexOperatorObservable<A, B> = SyncChildObservable<
188
- B,
189
- readonly [A]
190
- >;
177
+ export type MapOperatorObservable<A, B> = SyncChildObservable<B, readonly [A]>;
191
178
 
192
179
  export type PairwiseOperatorObservable<A> = SyncChildObservable<
193
180
  readonly [A, A],
@@ -231,19 +218,16 @@ export type SkipIfNoChangeOperatorObservable<A> = SyncChildObservable<
231
218
  readonly [A]
232
219
  >;
233
220
 
234
- export type ThrottleTimeOperatorObservable<A> = SyncChildObservable<
221
+ export type ThrottleOperatorObservable<A> = SyncChildObservable<
235
222
  A,
236
223
  readonly [A]
237
224
  >;
238
225
 
239
226
  // AsyncChildObservable
240
227
 
241
- export type AuditTimeOperatorObservable<A> = AsyncChildObservable<
242
- A,
243
- readonly [A]
244
- >;
228
+ export type AuditOperatorObservable<A> = AsyncChildObservable<A, readonly [A]>;
245
229
 
246
- export type DebounceTimeOperatorObservable<A> = AsyncChildObservable<
230
+ export type DebounceOperatorObservable<A> = AsyncChildObservable<
247
231
  A,
248
232
  readonly [A]
249
233
  >;
@@ -1,5 +1,5 @@
1
1
  import { expectType, type Optional } from 'ts-data-forge';
2
- import { type ObservableId, type UpdaterSymbol } from './id.mjs';
2
+ import { type ObservableId, type UpdateToken } from './id.mjs';
3
3
  import { type ObservableKind } from './observable-kind.mjs';
4
4
  import { type NonEmptyUnknownList, type Subscription } from './types.mjs';
5
5
 
@@ -28,12 +28,12 @@ type CreateObservableType<A, Kind extends ObservableKind> = Readonly<{
28
28
  // state
29
29
  getSnapshot: () => Optional<A>;
30
30
  isCompleted: boolean;
31
- updaterSymbol: UpdaterSymbol;
31
+ updateToken: UpdateToken;
32
32
  hasSubscriber: boolean;
33
33
  hasChild: boolean;
34
34
  hasActiveChild: () => boolean;
35
35
 
36
- tryUpdate: (updaterSymbol: UpdaterSymbol) => void;
36
+ tryUpdate: (updateToken: UpdateToken) => void;
37
37
  tryComplete: () => void;
38
38
  complete: () => void;
39
39
  subscribe: (onNext: (v: A) => void, onComplete?: () => void) => Subscription;
@@ -0,0 +1,2 @@
1
+ // Timer types for Node.js/Browser compatibility
2
+ export type TimerId = ReturnType<typeof setTimeout>;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  type ObservableId,
3
3
  type SubscriberId,
4
- type UpdaterSymbol,
4
+ type UpdateToken,
5
5
  } from '../types/index.mjs';
6
6
 
7
7
  function* idMaker<T extends symbol>(): Generator<T, T, T> {
@@ -19,7 +19,7 @@ const observableIdMaker = idMaker<ObservableId>();
19
19
 
20
20
  const subscriberIdMaker = idMaker<SubscriberId>();
21
21
 
22
- const updaterSymbolMaker = idMaker<UpdaterSymbol>();
22
+ const updateTokenMaker = idMaker<UpdateToken>();
23
23
 
24
24
  export const issueObservableId = (): ObservableId =>
25
25
  observableIdMaker.next().value;
@@ -27,5 +27,5 @@ export const issueObservableId = (): ObservableId =>
27
27
  export const issueSubscriberId = (): SubscriberId =>
28
28
  subscriberIdMaker.next().value;
29
29
 
30
- export const issueUpdaterSymbol = (): UpdaterSymbol =>
31
- updaterSymbolMaker.next().value;
30
+ export const issueUpdateToken = (): UpdateToken =>
31
+ updateTokenMaker.next().value;
package/src/globals.d.mts CHANGED
@@ -1,4 +1 @@
1
1
  /// <reference types="ts-type-forge" />
2
-
3
- // Timer types for Node.js/Browser compatibility
4
- type TimerId = ReturnType<typeof setTimeout>;
@@ -0,0 +1,17 @@
1
+ import { type Observable } from '../core/index.mjs';
2
+
3
+ export const collectToArray = <A,>(
4
+ observable: Observable<A>,
5
+ ): Promise<readonly A[]> =>
6
+ new Promise<readonly A[]>((resolve) => {
7
+ const mut_buffer: A[] = [];
8
+
9
+ observable.subscribe(
10
+ (value) => {
11
+ mut_buffer.push(value);
12
+ },
13
+ () => {
14
+ resolve(mut_buffer);
15
+ },
16
+ );
17
+ });
@@ -0,0 +1,68 @@
1
+ import { type InitializedObservable } from '../core/index.mjs';
2
+ import { createState } from './create-state.mjs';
3
+
4
+ /**
5
+ * Creates a reactive boolean state with convenient methods for boolean operations.
6
+ * Extends `createState` with boolean-specific helpers like `toggle`, `setTrue`, and `setFalse`.
7
+ *
8
+ * @param initialState - The initial boolean value
9
+ * @returns A 2-element tuple: `[state, { setTrue, setFalse, toggle, setState, updateState, resetState, getSnapshot, initialState }]`
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import type * as React from 'react';
14
+ * import { createBooleanState } from 'synstate';
15
+ * import { useObservableValue } from 'synstate-react-hooks';
16
+ *
17
+ * // Menu drawer open/close state.
18
+ * // setTrue and setFalse can be passed directly as callbacks
19
+ * // — no need to create wrapper functions like `() => setState(true)`.
20
+ * const [menuOpen$, { setTrue: openMenu, setFalse: closeMenu }] =
21
+ * createBooleanState(false);
22
+ *
23
+ * const SampleComponent = (): React.JSX.Element => (
24
+ * <MenuDrawer
25
+ * open={useObservableValue(menuOpen$)}
26
+ * onClose={closeMenu}
27
+ * onOpen={openMenu}
28
+ * />
29
+ * );
30
+ * ```
31
+ */
32
+
33
+ export const createBooleanState = (
34
+ initialState: boolean,
35
+ ): readonly [
36
+ state: InitializedObservable<boolean>,
37
+ Readonly<{
38
+ setTrue: () => void;
39
+ setFalse: () => void;
40
+ setState: (next: boolean) => boolean;
41
+ toggle: () => boolean;
42
+ updateState: (updateFn: (prev: boolean) => boolean) => boolean;
43
+ resetState: () => boolean;
44
+ getSnapshot: () => boolean;
45
+ initialState: boolean;
46
+ }>,
47
+ ] => {
48
+ const [state, setState, { updateState, resetState, getSnapshot }] =
49
+ createState(initialState);
50
+
51
+ return [
52
+ state,
53
+ {
54
+ setTrue: () => {
55
+ setState(true);
56
+ },
57
+ setFalse: () => {
58
+ setState(false);
59
+ },
60
+ toggle: () => updateState((s) => !s),
61
+ setState,
62
+ updateState,
63
+ resetState,
64
+ getSnapshot,
65
+ initialState,
66
+ },
67
+ ] as const;
68
+ };
@@ -51,19 +51,19 @@ export const createEventEmitter = (): readonly [
51
51
  * ```ts
52
52
  * const [message$, emitMessage] = createValueEmitter<string>();
53
53
  *
54
- * const mut_history: string[] = [];
54
+ * const messageHistory: string[] = [];
55
55
  *
56
56
  * message$.subscribe((msg) => {
57
- * mut_history.push(msg);
57
+ * messageHistory.push(msg);
58
58
  * });
59
59
  *
60
60
  * emitMessage('Hello'); // logs: Hello
61
61
  *
62
- * assert.deepStrictEqual(mut_history, ['Hello']);
62
+ * assert.deepStrictEqual(messageHistory, ['Hello']);
63
63
  *
64
64
  * emitMessage('World');
65
65
  *
66
- * assert.deepStrictEqual(mut_history, ['Hello', 'World']);
66
+ * assert.deepStrictEqual(messageHistory, ['Hello', 'World']);
67
67
  * ```
68
68
  */
69
69
  export const createValueEmitter = <A,>(): readonly [
@@ -8,7 +8,7 @@ import { source, type InitializedObservable } from '../core/index.mjs';
8
8
  * @template A - The type of actions
9
9
  * @param reducer - A pure function that takes current state and action, returns new state
10
10
  * @param initialState - The initial value of the state
11
- * @returns An object containing the state observable, dispatch function, and snapshot getter
11
+ * @returns A 3-element tuple: `[state, dispatch, { getSnapshot, initialState }]`
12
12
  *
13
13
  * @example
14
14
  * ```ts
@@ -24,23 +24,23 @@ import { source, type InitializedObservable } from '../core/index.mjs';
24
24
  * 0,
25
25
  * );
26
26
  *
27
- * const mut_history: number[] = [];
27
+ * const stateHistory: number[] = [];
28
28
  *
29
29
  * state.subscribe((value: number) => {
30
- * mut_history.push(value);
30
+ * stateHistory.push(value);
31
31
  * });
32
32
  *
33
- * assert.deepStrictEqual(mut_history, [0]);
33
+ * assert.deepStrictEqual(stateHistory, [0]);
34
34
  *
35
35
  * dispatch({ type: 'increment' }); // logs: 1
36
36
  *
37
- * assert.deepStrictEqual(mut_history, [0, 1]);
37
+ * assert.deepStrictEqual(stateHistory, [0, 1]);
38
38
  *
39
39
  * dispatch({ type: 'increment' });
40
40
  *
41
41
  * dispatch({ type: 'decrement' });
42
42
  *
43
- * assert.deepStrictEqual(mut_history, [0, 1, 2, 1]);
43
+ * assert.deepStrictEqual(stateHistory, [0, 1, 2, 1]);
44
44
  * ```
45
45
  */
46
46
  export const createReducer = <S, A>(
@@ -49,7 +49,10 @@ export const createReducer = <S, A>(
49
49
  ): readonly [
50
50
  state: InitializedObservable<S>,
51
51
  dispatch: (action: A) => S,
52
- getSnapshot: () => S,
52
+ Readonly<{
53
+ getSnapshot: () => S;
54
+ initialState: S;
55
+ }>,
53
56
  ] => {
54
57
  const state = source<S>(initialState);
55
58
 
@@ -63,5 +66,5 @@ export const createReducer = <S, A>(
63
66
 
64
67
  const getSnapshot = (): S => state.getSnapshot().value;
65
68
 
66
- return [state, dispatch, getSnapshot] as const;
69
+ return [state, dispatch, { getSnapshot, initialState }] as const;
67
70
  };