synstate 0.1.2 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/README.md +200 -147
  2. package/assets/old/synstate-icon-square.png +0 -0
  3. package/assets/synstate-logo.png +0 -0
  4. package/dist/core/class/child-observable-class.d.mts +2 -0
  5. package/dist/core/class/child-observable-class.d.mts.map +1 -1
  6. package/dist/core/class/child-observable-class.mjs +44 -13
  7. package/dist/core/class/child-observable-class.mjs.map +1 -1
  8. package/dist/core/class/observable-base-class.d.mts +4 -4
  9. package/dist/core/class/observable-base-class.d.mts.map +1 -1
  10. package/dist/core/class/observable-base-class.mjs +8 -8
  11. package/dist/core/class/observable-base-class.mjs.map +1 -1
  12. package/dist/core/class/root-observable-class.d.mts +3 -1
  13. package/dist/core/class/root-observable-class.d.mts.map +1 -1
  14. package/dist/core/class/root-observable-class.mjs +9 -9
  15. package/dist/core/class/root-observable-class.mjs.map +1 -1
  16. package/dist/core/combine/combine.d.mts +7 -6
  17. package/dist/core/combine/combine.d.mts.map +1 -1
  18. package/dist/core/combine/combine.mjs +11 -12
  19. package/dist/core/combine/combine.mjs.map +1 -1
  20. package/dist/core/combine/merge.d.mts +7 -6
  21. package/dist/core/combine/merge.d.mts.map +1 -1
  22. package/dist/core/combine/merge.mjs +9 -9
  23. package/dist/core/combine/merge.mjs.map +1 -1
  24. package/dist/core/combine/zip.d.mts +21 -19
  25. package/dist/core/combine/zip.d.mts.map +1 -1
  26. package/dist/core/combine/zip.mjs +22 -21
  27. package/dist/core/combine/zip.mjs.map +1 -1
  28. package/dist/core/create/{interval.d.mts → counter.d.mts} +14 -12
  29. package/dist/core/create/counter.d.mts.map +1 -0
  30. package/dist/core/create/{interval.mjs → counter.mjs} +21 -23
  31. package/dist/core/create/counter.mjs.map +1 -0
  32. package/dist/core/create/from-abortable-promise.d.mts +29 -0
  33. package/dist/core/create/from-abortable-promise.d.mts.map +1 -0
  34. package/dist/core/create/from-abortable-promise.mjs +70 -0
  35. package/dist/core/create/from-abortable-promise.mjs.map +1 -0
  36. package/dist/core/create/from-promise.d.mts +9 -6
  37. package/dist/core/create/from-promise.d.mts.map +1 -1
  38. package/dist/core/create/from-promise.mjs +8 -5
  39. package/dist/core/create/from-promise.mjs.map +1 -1
  40. package/dist/core/create/from-subscribable.d.mts +4 -4
  41. package/dist/core/create/from-subscribable.mjs +4 -4
  42. package/dist/core/create/index.d.mts +3 -3
  43. package/dist/core/create/index.d.mts.map +1 -1
  44. package/dist/core/create/index.mjs +4 -4
  45. package/dist/core/create/just.d.mts +32 -0
  46. package/dist/core/create/just.d.mts.map +1 -0
  47. package/dist/core/create/just.mjs +44 -0
  48. package/dist/core/create/just.mjs.map +1 -0
  49. package/dist/core/create/source.d.mts +7 -12
  50. package/dist/core/create/source.d.mts.map +1 -1
  51. package/dist/core/create/source.mjs +1 -6
  52. package/dist/core/create/source.mjs.map +1 -1
  53. package/dist/core/create/timer.d.mts +6 -4
  54. package/dist/core/create/timer.d.mts.map +1 -1
  55. package/dist/core/create/timer.mjs +6 -7
  56. package/dist/core/create/timer.mjs.map +1 -1
  57. package/dist/core/index.d.mts +0 -1
  58. package/dist/core/index.d.mts.map +1 -1
  59. package/dist/core/index.mjs +8 -13
  60. package/dist/core/index.mjs.map +1 -1
  61. package/dist/core/operators/audit.d.mts +97 -0
  62. package/dist/core/operators/audit.d.mts.map +1 -0
  63. package/dist/core/operators/audit.mjs +144 -0
  64. package/dist/core/operators/audit.mjs.map +1 -0
  65. package/dist/core/operators/debounce.d.mts +88 -0
  66. package/dist/core/operators/debounce.d.mts.map +1 -0
  67. package/dist/core/operators/debounce.mjs +130 -0
  68. package/dist/core/operators/debounce.mjs.map +1 -0
  69. package/dist/core/operators/filter.d.mts +6 -5
  70. package/dist/core/operators/filter.d.mts.map +1 -1
  71. package/dist/core/operators/filter.mjs +3 -3
  72. package/dist/core/operators/filter.mjs.map +1 -1
  73. package/dist/core/operators/index.d.mts +4 -4
  74. package/dist/core/operators/index.d.mts.map +1 -1
  75. package/dist/core/operators/index.mjs +4 -4
  76. package/dist/core/operators/{map-with-index.d.mts → map.d.mts} +12 -11
  77. package/dist/core/operators/map.d.mts.map +1 -0
  78. package/dist/core/operators/{map-with-index.mjs → map.mjs} +17 -17
  79. package/dist/core/operators/map.mjs.map +1 -0
  80. package/dist/core/operators/merge-map.d.mts +56 -29
  81. package/dist/core/operators/merge-map.d.mts.map +1 -1
  82. package/dist/core/operators/merge-map.mjs +58 -31
  83. package/dist/core/operators/merge-map.mjs.map +1 -1
  84. package/dist/core/operators/pairwise.d.mts +6 -6
  85. package/dist/core/operators/pairwise.mjs +9 -9
  86. package/dist/core/operators/pairwise.mjs.map +1 -1
  87. package/dist/core/operators/scan.d.mts +6 -6
  88. package/dist/core/operators/scan.mjs +9 -9
  89. package/dist/core/operators/scan.mjs.map +1 -1
  90. package/dist/core/operators/skip-if-no-change.d.mts +20 -8
  91. package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
  92. package/dist/core/operators/skip-if-no-change.mjs +23 -11
  93. package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
  94. package/dist/core/operators/skip-until.d.mts +5 -5
  95. package/dist/core/operators/skip-until.mjs +8 -8
  96. package/dist/core/operators/skip-until.mjs.map +1 -1
  97. package/dist/core/operators/skip-while.d.mts +19 -8
  98. package/dist/core/operators/skip-while.d.mts.map +1 -1
  99. package/dist/core/operators/skip-while.mjs +26 -11
  100. package/dist/core/operators/skip-while.mjs.map +1 -1
  101. package/dist/core/operators/switch-map.d.mts +57 -26
  102. package/dist/core/operators/switch-map.d.mts.map +1 -1
  103. package/dist/core/operators/switch-map.mjs +59 -28
  104. package/dist/core/operators/switch-map.mjs.map +1 -1
  105. package/dist/core/operators/take-until.d.mts +5 -5
  106. package/dist/core/operators/take-until.mjs +8 -8
  107. package/dist/core/operators/take-until.mjs.map +1 -1
  108. package/dist/core/operators/take-while.d.mts +16 -7
  109. package/dist/core/operators/take-while.d.mts.map +1 -1
  110. package/dist/core/operators/take-while.mjs +18 -10
  111. package/dist/core/operators/take-while.mjs.map +1 -1
  112. package/dist/core/operators/throttle.d.mts +81 -0
  113. package/dist/core/operators/throttle.d.mts.map +1 -0
  114. package/dist/core/operators/throttle.mjs +126 -0
  115. package/dist/core/operators/throttle.mjs.map +1 -0
  116. package/dist/core/operators/with-buffered-from.d.mts +9 -9
  117. package/dist/core/operators/with-buffered-from.mjs +12 -12
  118. package/dist/core/operators/with-buffered-from.mjs.map +1 -1
  119. package/dist/core/operators/with-current-value-from.d.mts +10 -9
  120. package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
  121. package/dist/core/operators/with-current-value-from.mjs +13 -12
  122. package/dist/core/operators/with-current-value-from.mjs.map +1 -1
  123. package/dist/core/operators/with-initial-value.d.mts +5 -5
  124. package/dist/core/operators/with-initial-value.mjs +8 -8
  125. package/dist/core/operators/with-initial-value.mjs.map +1 -1
  126. package/dist/core/predefined/index.mjs +0 -1
  127. package/dist/core/predefined/index.mjs.map +1 -1
  128. package/dist/core/predefined/operators/attach-index.d.mts +50 -0
  129. package/dist/core/predefined/operators/attach-index.d.mts.map +1 -1
  130. package/dist/core/predefined/operators/attach-index.mjs +51 -2
  131. package/dist/core/predefined/operators/attach-index.mjs.map +1 -1
  132. package/dist/core/predefined/operators/index.d.mts +0 -1
  133. package/dist/core/predefined/operators/index.d.mts.map +1 -1
  134. package/dist/core/predefined/operators/index.mjs +0 -1
  135. package/dist/core/predefined/operators/index.mjs.map +1 -1
  136. package/dist/core/predefined/operators/map-optional.d.mts +48 -1
  137. package/dist/core/predefined/operators/map-optional.d.mts.map +1 -1
  138. package/dist/core/predefined/operators/map-optional.mjs +49 -1
  139. package/dist/core/predefined/operators/map-optional.mjs.map +1 -1
  140. package/dist/core/predefined/operators/map-result-err.d.mts +48 -1
  141. package/dist/core/predefined/operators/map-result-err.d.mts.map +1 -1
  142. package/dist/core/predefined/operators/map-result-err.mjs +49 -1
  143. package/dist/core/predefined/operators/map-result-err.mjs.map +1 -1
  144. package/dist/core/predefined/operators/map-result-ok.d.mts +48 -1
  145. package/dist/core/predefined/operators/map-result-ok.d.mts.map +1 -1
  146. package/dist/core/predefined/operators/map-result-ok.mjs +49 -1
  147. package/dist/core/predefined/operators/map-result-ok.mjs.map +1 -1
  148. package/dist/core/predefined/operators/map-to.d.mts +40 -0
  149. package/dist/core/predefined/operators/map-to.d.mts.map +1 -1
  150. package/dist/core/predefined/operators/map-to.mjs +43 -1
  151. package/dist/core/predefined/operators/map-to.mjs.map +1 -1
  152. package/dist/core/predefined/operators/pluck.d.mts +39 -0
  153. package/dist/core/predefined/operators/pluck.d.mts.map +1 -1
  154. package/dist/core/predefined/operators/pluck.mjs +42 -1
  155. package/dist/core/predefined/operators/pluck.mjs.map +1 -1
  156. package/dist/core/predefined/operators/skip.d.mts +48 -0
  157. package/dist/core/predefined/operators/skip.d.mts.map +1 -1
  158. package/dist/core/predefined/operators/skip.mjs +47 -0
  159. package/dist/core/predefined/operators/skip.mjs.map +1 -1
  160. package/dist/core/predefined/operators/take.d.mts +42 -0
  161. package/dist/core/predefined/operators/take.d.mts.map +1 -1
  162. package/dist/core/predefined/operators/take.mjs +41 -0
  163. package/dist/core/predefined/operators/take.mjs.map +1 -1
  164. package/dist/core/predefined/operators/unwrap-optional.d.mts +41 -1
  165. package/dist/core/predefined/operators/unwrap-optional.d.mts.map +1 -1
  166. package/dist/core/predefined/operators/unwrap-optional.mjs +42 -1
  167. package/dist/core/predefined/operators/unwrap-optional.mjs.map +1 -1
  168. package/dist/core/predefined/operators/unwrap-result-err.d.mts +41 -1
  169. package/dist/core/predefined/operators/unwrap-result-err.d.mts.map +1 -1
  170. package/dist/core/predefined/operators/unwrap-result-err.mjs +42 -1
  171. package/dist/core/predefined/operators/unwrap-result-err.mjs.map +1 -1
  172. package/dist/core/predefined/operators/unwrap-result-ok.d.mts +41 -1
  173. package/dist/core/predefined/operators/unwrap-result-ok.d.mts.map +1 -1
  174. package/dist/core/predefined/operators/unwrap-result-ok.mjs +42 -1
  175. package/dist/core/predefined/operators/unwrap-result-ok.mjs.map +1 -1
  176. package/dist/core/types/id.d.mts +2 -1
  177. package/dist/core/types/id.d.mts.map +1 -1
  178. package/dist/core/types/index.d.mts +1 -0
  179. package/dist/core/types/index.d.mts.map +1 -1
  180. package/dist/core/types/observable-family.d.mts +10 -14
  181. package/dist/core/types/observable-family.d.mts.map +1 -1
  182. package/dist/core/types/observable-kind.d.mts +1 -0
  183. package/dist/core/types/observable-kind.d.mts.map +1 -1
  184. package/dist/core/types/observable.d.mts +5 -3
  185. package/dist/core/types/observable.d.mts.map +1 -1
  186. package/dist/core/types/observable.mjs.map +1 -1
  187. package/dist/core/types/timer.d.mts +2 -0
  188. package/dist/core/types/timer.d.mts.map +1 -0
  189. package/dist/core/types/timer.mjs +2 -0
  190. package/dist/core/types/timer.mjs.map +1 -0
  191. package/dist/core/utils/id-maker.d.mts +2 -2
  192. package/dist/core/utils/id-maker.d.mts.map +1 -1
  193. package/dist/core/utils/id-maker.mjs +3 -3
  194. package/dist/core/utils/id-maker.mjs.map +1 -1
  195. package/dist/core/utils/index.mjs +1 -1
  196. package/dist/core/utils/utils.d.mts +2 -0
  197. package/dist/core/utils/utils.d.mts.map +1 -1
  198. package/dist/core/utils/utils.mjs.map +1 -1
  199. package/dist/entry-point.mjs +11 -14
  200. package/dist/entry-point.mjs.map +1 -1
  201. package/dist/index.mjs +11 -14
  202. package/dist/index.mjs.map +1 -1
  203. package/dist/types.d.mts +1 -2
  204. package/dist/utils/collect-to-array.d.mts +3 -0
  205. package/dist/utils/collect-to-array.d.mts.map +1 -0
  206. package/dist/utils/collect-to-array.mjs +11 -0
  207. package/dist/utils/collect-to-array.mjs.map +1 -0
  208. package/dist/utils/create-boolean-state.d.mts +40 -0
  209. package/dist/utils/create-boolean-state.d.mts.map +1 -0
  210. package/dist/utils/create-boolean-state.mjs +53 -0
  211. package/dist/utils/create-boolean-state.mjs.map +1 -0
  212. package/dist/utils/create-event-emitter.d.mts +4 -4
  213. package/dist/utils/create-event-emitter.mjs +4 -4
  214. package/dist/utils/create-reducer.d.mts +11 -7
  215. package/dist/utils/create-reducer.d.mts.map +1 -1
  216. package/dist/utils/create-reducer.mjs +7 -7
  217. package/dist/utils/create-reducer.mjs.map +1 -1
  218. package/dist/utils/create-state.d.mts +8 -48
  219. package/dist/utils/create-state.d.mts.map +1 -1
  220. package/dist/utils/create-state.mjs +10 -60
  221. package/dist/utils/create-state.mjs.map +1 -1
  222. package/dist/utils/index.d.mts +2 -0
  223. package/dist/utils/index.d.mts.map +1 -1
  224. package/dist/utils/index.mjs +3 -1
  225. package/dist/utils/index.mjs.map +1 -1
  226. package/package.json +21 -14
  227. package/src/core/class/child-observable-class.mts +68 -14
  228. package/src/core/class/circular-dependency-comparison.test.mts +142 -0
  229. package/src/core/class/circular-dependency.test.mts +251 -0
  230. package/src/core/class/observable-base-class.mts +10 -9
  231. package/src/core/class/root-observable-class.mts +15 -10
  232. package/src/core/combine/combine.mts +14 -13
  233. package/src/core/combine/merge.mts +14 -14
  234. package/src/core/combine/zip.mts +27 -25
  235. package/src/core/create/{interval.mts → counter.mts} +32 -30
  236. package/src/core/create/from-abortable-promise.mts +83 -0
  237. package/src/core/create/from-promise.mts +10 -7
  238. package/src/core/create/from-subscribable.mts +4 -4
  239. package/src/core/create/index.mts +3 -3
  240. package/src/core/create/just.mts +43 -0
  241. package/src/core/create/source.mts +10 -14
  242. package/src/core/create/timer.mts +12 -11
  243. package/src/core/index.mts +0 -1
  244. package/src/core/operators/audit.mts +172 -0
  245. package/src/core/operators/debounce.mts +154 -0
  246. package/src/core/operators/filter.mts +9 -9
  247. package/src/core/operators/index.mts +4 -4
  248. package/src/core/operators/{map-with-index.mts → map.mts} +20 -20
  249. package/src/core/operators/merge-map.mts +59 -32
  250. package/src/core/operators/pairwise.mts +10 -10
  251. package/src/core/operators/scan.mts +10 -10
  252. package/src/core/operators/skip-if-no-change.mts +24 -12
  253. package/src/core/operators/skip-until.mts +9 -9
  254. package/src/core/operators/skip-while.mts +29 -12
  255. package/src/core/operators/switch-map.mts +60 -29
  256. package/src/core/operators/take-until.mts +9 -9
  257. package/src/core/operators/take-while.mts +19 -11
  258. package/src/core/operators/{throttle-time.mts → throttle.mts} +58 -38
  259. package/src/core/operators/with-buffered-from.mts +13 -13
  260. package/src/core/operators/with-current-value-from.mts +14 -13
  261. package/src/core/operators/with-initial-value.mts +9 -9
  262. package/src/core/predefined/operators/attach-index.mts +52 -2
  263. package/src/core/predefined/operators/index.mts +0 -1
  264. package/src/core/predefined/operators/map-optional.mts +49 -2
  265. package/src/core/predefined/operators/map-result-err.mts +49 -2
  266. package/src/core/predefined/operators/map-result-ok.mts +49 -2
  267. package/src/core/predefined/operators/map-to.mts +41 -1
  268. package/src/core/predefined/operators/pluck.mts +40 -1
  269. package/src/core/predefined/operators/skip.mts +48 -0
  270. package/src/core/predefined/operators/take.mts +42 -0
  271. package/src/core/predefined/operators/unwrap-optional.mts +43 -2
  272. package/src/core/predefined/operators/unwrap-result-err.mts +43 -2
  273. package/src/core/predefined/operators/unwrap-result-ok.mts +43 -2
  274. package/src/core/types/id.mts +3 -1
  275. package/src/core/types/index.mts +1 -0
  276. package/src/core/types/observable-family.mts +13 -24
  277. package/src/core/types/observable-kind.mts +2 -0
  278. package/src/core/types/observable.mts +5 -4
  279. package/src/core/types/timer.mts +2 -0
  280. package/src/core/utils/id-maker.mts +4 -4
  281. package/src/core/utils/utils.mts +1 -0
  282. package/src/utils/collect-to-array.mts +17 -0
  283. package/src/utils/create-boolean-state.mts +68 -0
  284. package/src/utils/create-event-emitter.mts +4 -4
  285. package/src/utils/create-reducer.mts +12 -8
  286. package/src/utils/create-state.mts +10 -75
  287. package/src/utils/index.mts +2 -0
  288. package/dist/core/create/from-array.d.mts +0 -39
  289. package/dist/core/create/from-array.d.mts.map +0 -1
  290. package/dist/core/create/from-array.mjs +0 -65
  291. package/dist/core/create/from-array.mjs.map +0 -1
  292. package/dist/core/create/interval.d.mts.map +0 -1
  293. package/dist/core/create/interval.mjs.map +0 -1
  294. package/dist/core/create/of.d.mts +0 -39
  295. package/dist/core/create/of.d.mts.map +0 -1
  296. package/dist/core/create/of.mjs +0 -63
  297. package/dist/core/create/of.mjs.map +0 -1
  298. package/dist/core/operators/audit-time.d.mts +0 -62
  299. package/dist/core/operators/audit-time.d.mts.map +0 -1
  300. package/dist/core/operators/audit-time.mjs +0 -109
  301. package/dist/core/operators/audit-time.mjs.map +0 -1
  302. package/dist/core/operators/debounce-time.d.mts +0 -51
  303. package/dist/core/operators/debounce-time.d.mts.map +0 -1
  304. package/dist/core/operators/debounce-time.mjs +0 -93
  305. package/dist/core/operators/debounce-time.mjs.map +0 -1
  306. package/dist/core/operators/map-with-index.d.mts.map +0 -1
  307. package/dist/core/operators/map-with-index.mjs.map +0 -1
  308. package/dist/core/operators/throttle-time.d.mts +0 -62
  309. package/dist/core/operators/throttle-time.d.mts.map +0 -1
  310. package/dist/core/operators/throttle-time.mjs +0 -107
  311. package/dist/core/operators/throttle-time.mjs.map +0 -1
  312. package/dist/core/predefined/operators/map.d.mts +0 -3
  313. package/dist/core/predefined/operators/map.d.mts.map +0 -1
  314. package/dist/core/predefined/operators/map.mjs +0 -8
  315. package/dist/core/predefined/operators/map.mjs.map +0 -1
  316. package/dist/globals.d.mts +0 -4
  317. package/src/core/create/from-array.mts +0 -76
  318. package/src/core/create/of.mts +0 -73
  319. package/src/core/operators/audit-time.mts +0 -136
  320. package/src/core/operators/debounce-time.mts +0 -116
  321. package/src/core/predefined/operators/map.mts +0 -5
  322. package/src/globals.d.mts +0 -4
  323. /package/assets/{synstate-icon.png → old/synstate-icon.png} +0 -0
@@ -1,6 +1,7 @@
1
1
  import { Arr, Optional, expectType } from 'ts-data-forge';
2
+ import { type NonEmptyArray } from 'ts-type-forge';
2
3
  import { SyncChildObservableClass } from '../class/index.mjs';
3
- import { fromArray, source } from '../create/index.mjs';
4
+ import { source } from '../create/index.mjs';
4
5
  import { withInitialValue } from '../operators/index.mjs';
5
6
  import {
6
7
  type CombineObservable,
@@ -10,7 +11,7 @@ import {
10
11
  type NonEmptyUnknownList,
11
12
  type Observable,
12
13
  type SyncChildObservable,
13
- type UpdaterSymbol,
14
+ type UpdateToken,
14
15
  type Wrap,
15
16
  } from '../types/index.mjs';
16
17
 
@@ -41,30 +42,30 @@ import {
41
42
  *
42
43
  * const user$ = combine([name$, age$]);
43
44
  *
44
- * const mut_history: (readonly [string, number])[] = [];
45
+ * const userHistory: (readonly [string, number])[] = [];
45
46
  *
46
47
  * user$.subscribe(([name_, age]) => {
47
- * mut_history.push([name_, age]);
48
+ * userHistory.push([name_, age]);
48
49
  * });
49
50
  *
50
51
  * name$.next('Alice'); // nothing logged (age$ hasn't emitted yet)
51
52
  *
52
- * assert.deepStrictEqual(mut_history, []);
53
+ * assert.deepStrictEqual(userHistory, []);
53
54
  *
54
55
  * age$.next(25); // logs: { name: 'Alice', age: 25 }
55
56
  *
56
- * assert.deepStrictEqual(mut_history, [['Alice', 25]]);
57
+ * assert.deepStrictEqual(userHistory, [['Alice', 25]]);
57
58
  *
58
59
  * name$.next('Bob'); // logs: { name: 'Bob', age: 25 }
59
60
  *
60
- * assert.deepStrictEqual(mut_history, [
61
+ * assert.deepStrictEqual(userHistory, [
61
62
  * ['Alice', 25],
62
63
  * ['Bob', 25],
63
64
  * ]);
64
65
  *
65
66
  * age$.next(30); // logs: { name: 'Bob', age: 30 }
66
67
  *
67
- * assert.deepStrictEqual(mut_history, [
68
+ * assert.deepStrictEqual(userHistory, [
68
69
  * ['Alice', 25],
69
70
  * ['Bob', 25],
70
71
  * ['Bob', 30],
@@ -103,8 +104,8 @@ class CombineObservableClass<const A extends NonEmptyUnknownList>
103
104
  });
104
105
  }
105
106
 
106
- override tryUpdate(updaterSymbol: UpdaterSymbol): void {
107
- if (this.parents.every((o) => o.updaterSymbol !== updaterSymbol)) return; // all parents are skipped
107
+ override tryUpdate(updateToken: UpdateToken): void {
108
+ if (this.parents.every((o) => o.updateToken !== updateToken)) return; // all parents are skipped
108
109
 
109
110
  const parentValues = this.parents.map((a) => a.getSnapshot());
110
111
 
@@ -113,7 +114,7 @@ class CombineObservableClass<const A extends NonEmptyUnknownList>
113
114
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
114
115
  Arr.map(parentValues, (a) => a.value) as A;
115
116
 
116
- this.setNext(nextValue, updaterSymbol);
117
+ this.setNext(nextValue, updateToken);
117
118
  }
118
119
  }
119
120
  }
@@ -154,9 +155,9 @@ class CombineObservableClass<const A extends NonEmptyUnknownList>
154
155
  expectType<typeof _d, InitializedObservable<readonly [1, 2]>>('<=');
155
156
  }
156
157
 
157
- const r1 = fromArray([1, 2, 3]);
158
+ const r1 = source(1);
158
159
 
159
- const r2 = fromArray(['a', 'b', 'c']);
160
+ const r2 = source('a');
160
161
 
161
162
  const _c = combine([r1, r2]);
162
163
 
@@ -1,13 +1,14 @@
1
1
  import { Optional, expectType } from 'ts-data-forge';
2
+ import { type ArrayElement, type NonEmptyArray } from 'ts-type-forge';
2
3
  import { SyncChildObservableClass } from '../class/index.mjs';
3
- import { fromArray } from '../create/index.mjs';
4
+ import { source } from '../create/index.mjs';
4
5
  import {
5
6
  type MergeObservable,
6
7
  type MergeObservableRefined,
7
8
  type NonEmptyUnknownList,
8
9
  type Observable,
9
10
  type SyncChildObservable,
10
- type UpdaterSymbol,
11
+ type UpdateToken,
11
12
  type Wrap,
12
13
  } from '../types/index.mjs';
13
14
 
@@ -23,7 +24,7 @@ import {
23
24
  * ```ts
24
25
  * // Timeline:
25
26
  * //
26
- * // clicks$ c1 c2 c3
27
+ * // clicks$ c1 c2 c3
27
28
  * // keys$ k1 k2 k3
28
29
  * // events$ c1 k1 c2 k2 c3 k3
29
30
  * //
@@ -38,25 +39,25 @@ import {
38
39
  *
39
40
  * const events$ = merge([clicks$, keys$]);
40
41
  *
41
- * const mut_history: string[] = [];
42
+ * const valueHistory: string[] = [];
42
43
  *
43
44
  * events$.subscribe((event_) => {
44
- * mut_history.push(event_);
45
+ * valueHistory.push(event_);
45
46
  * });
46
47
  *
47
48
  * clicks$.next('c1');
48
49
  *
49
- * assert.deepStrictEqual(mut_history, ['c1']);
50
+ * assert.deepStrictEqual(valueHistory, ['c1']);
50
51
  *
51
52
  * keys$.next('k1');
52
53
  *
53
- * assert.deepStrictEqual(mut_history, ['c1', 'k1']);
54
+ * assert.deepStrictEqual(valueHistory, ['c1', 'k1']);
54
55
  *
55
56
  * clicks$.next('c2');
56
57
  *
57
58
  * keys$.next('k2');
58
59
  *
59
- * assert.deepStrictEqual(mut_history, ['c1', 'k1', 'c2', 'k2']);
60
+ * assert.deepStrictEqual(valueHistory, ['c1', 'k1', 'c2', 'k2']);
60
61
  * ```
61
62
  *
62
63
  * @note To improve code readability, consider using `createState` instead of `merge`,
@@ -79,10 +80,9 @@ class MergeObservableClass<const P extends NonEmptyUnknownList>
79
80
  });
80
81
  }
81
82
 
82
- override tryUpdate(updaterSymbol: UpdaterSymbol): void {
83
+ override tryUpdate(updateToken: UpdateToken): void {
83
84
  const parentToUse = this.parents.find(
84
- (o) =>
85
- o.updaterSymbol === updaterSymbol && Optional.isSome(o.getSnapshot()),
85
+ (o) => o.updateToken === updateToken && Optional.isSome(o.getSnapshot()),
86
86
  );
87
87
 
88
88
  if (parentToUse === undefined) return;
@@ -91,7 +91,7 @@ class MergeObservableClass<const P extends NonEmptyUnknownList>
91
91
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
92
92
  Optional.unwrap(parentToUse.getSnapshot()) as ArrayElement<P>;
93
93
 
94
- this.setNext(nextValue, updaterSymbol);
94
+ this.setNext(nextValue, updateToken);
95
95
  }
96
96
  }
97
97
 
@@ -100,9 +100,9 @@ if (import.meta.vitest !== undefined) {
100
100
  expect(1).toBe(1); // dummy
101
101
  });
102
102
 
103
- const r1 = fromArray([1, 2, 3]);
103
+ const r1 = source(1);
104
104
 
105
- const r2 = fromArray(['a', 'b', 'c']);
105
+ const r2 = source('a');
106
106
 
107
107
  const _m = merge([r1, r2] as const);
108
108
 
@@ -1,6 +1,7 @@
1
1
  import { Arr, Optional, createQueue, expectType } from 'ts-data-forge';
2
+ import { type NonEmptyArray } from 'ts-type-forge';
2
3
  import { SyncChildObservableClass } from '../class/index.mjs';
3
- import { fromArray, source } from '../create/index.mjs';
4
+ import { source } from '../create/index.mjs';
4
5
  import { withInitialValue } from '../operators/index.mjs';
5
6
  import {
6
7
  type InitializedObservable,
@@ -9,7 +10,7 @@ import {
9
10
  type Observable,
10
11
  type SyncChildObservable,
11
12
  type TupleToQueueTuple,
12
- type UpdaterSymbol,
13
+ type UpdateToken,
13
14
  type Wrap,
14
15
  type ZipObservable,
15
16
  type ZipObservableRefined,
@@ -28,38 +29,39 @@ import {
28
29
  * ```ts
29
30
  * // Timeline:
30
31
  * //
31
- * // letters$ 'a' 'b' 'c'
32
+ * // letters$ 'A' 'B' 'C'
32
33
  * // numbers$ 1 2 3
33
- * // zipped$ ['a',1] ['b',2] ['c',3]
34
+ * // zipped$ ['A',1] ['B',2] ['C',3]
34
35
  * //
35
36
  * // Explanation:
36
37
  * // - zip pairs values by their index from multiple sources
37
38
  * // - Waits for all sources to emit at the same index
38
39
  * // - Completes when any source completes
39
40
  *
40
- * const letters$ = fromArray(['a', 'b', 'c']);
41
+ * const [letters$, setLetter] = createState<string>('A');
41
42
  *
42
- * const numbers$ = fromArray([1, 2, 3]);
43
+ * const [numbers$, setNumber] = createState<number>(1);
43
44
  *
44
45
  * const zipped$ = zip([letters$, numbers$]);
45
46
  *
46
- * const mut_history: (readonly [string, number])[] = [];
47
+ * const valueHistory: (readonly [string, number])[] = [];
47
48
  *
48
- * await new Promise<void>((resolve) => {
49
- * zipped$.subscribe(
50
- * ([letter, num]) => {
51
- * mut_history.push([letter, num]);
52
- * },
53
- * () => {
54
- * resolve();
55
- * },
56
- * );
49
+ * zipped$.subscribe(([letter, num]) => {
50
+ * valueHistory.push([letter, num]);
57
51
  * });
58
52
  *
59
- * assert.deepStrictEqual(mut_history, [
60
- * ['a', 1],
61
- * ['b', 2],
62
- * ['c', 3],
53
+ * for (const letter of ['B', 'C']) {
54
+ * setLetter(letter);
55
+ * }
56
+ *
57
+ * for (const num of [2, 3]) {
58
+ * setNumber(num);
59
+ * }
60
+ *
61
+ * assert.deepStrictEqual(valueHistory, [
62
+ * ['A', 1],
63
+ * ['B', 2],
64
+ * ['C', 3],
63
65
  * ]);
64
66
  * ```
65
67
  */
@@ -93,13 +95,13 @@ class ZipObservableClass<const A extends NonEmptyUnknownList>
93
95
  ) satisfies TupleToQueueTuple<A>;
94
96
  }
95
97
 
96
- override tryUpdate(updaterSymbol: UpdaterSymbol): void {
98
+ override tryUpdate(updateToken: UpdateToken): void {
97
99
  const queues = this.#queues;
98
100
 
99
101
  for (const [index, par] of this.parents.entries()) {
100
102
  const sn = par.getSnapshot();
101
103
 
102
- if (par.updaterSymbol === updaterSymbol && Optional.isSome(sn)) {
104
+ if (par.updateToken === updateToken && Optional.isSome(sn)) {
103
105
  queues[index]?.enqueue(sn.value);
104
106
  }
105
107
  }
@@ -109,7 +111,7 @@ class ZipObservableClass<const A extends NonEmptyUnknownList>
109
111
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
110
112
  Arr.map(queues, (q) => Optional.unwrap(q.dequeue())) as A;
111
113
 
112
- this.setNext(nextValue, updaterSymbol);
114
+ this.setNext(nextValue, updateToken);
113
115
  }
114
116
  }
115
117
  }
@@ -154,9 +156,9 @@ if (import.meta.vitest !== undefined) {
154
156
  expectType<typeof _d, InitializedObservable<readonly [1, 2]>>('<=');
155
157
  }
156
158
 
157
- const r1 = fromArray([1, 2, 3]);
159
+ const r1 = source(1);
158
160
 
159
- const r2 = fromArray(['a', 'b', 'c']);
161
+ const r2 = source('a');
160
162
 
161
163
  const _z = zip([r1, r2] as const);
162
164
 
@@ -1,12 +1,12 @@
1
1
  import { asSafeUint, Optional, SafeUint } from 'ts-data-forge';
2
2
  import { RootObservableClass } from '../class/index.mjs';
3
- import { type IntervalObservable } from '../types/index.mjs';
3
+ import { type CounterObservable, type TimerId } from '../types/index.mjs';
4
4
 
5
5
  /**
6
6
  * Creates an observable that emits incremental numbers at a specified interval.
7
7
  * Starts with 0 immediately after subscription, then emits 1, 2, 3, ... every interval.
8
8
  *
9
- * @param milliSeconds - The interval duration in milliseconds
9
+ * @param intervalMilliSeconds - The interval duration in milliseconds
10
10
  * @param startManually - If true, waits for manual start (default: false)
11
11
  * @returns An observable that emits sequential numbers
12
12
  *
@@ -18,16 +18,16 @@ import { type IntervalObservable } from '../types/index.mjs';
18
18
  * // tick$ 0 1 2 3 4 5 ...
19
19
  * //
20
20
  * // Explanation:
21
- * // - interval emits incrementing numbers at specified intervals
21
+ * // - counter emits incrementing numbers at specified intervals
22
22
  * // - Starts at 0 and continues indefinitely
23
23
  * // - Useful for periodic tasks or animations
24
24
  *
25
- * const tick$ = interval(100);
25
+ * const tick$ = counter(100);
26
26
  *
27
- * const mut_history: number[] = [];
27
+ * const valueHistory: number[] = [];
28
28
  *
29
29
  * const subscription = tick$.subscribe((count) => {
30
- * mut_history.push(count);
30
+ * valueHistory.push(count);
31
31
  * });
32
32
  *
33
33
  * await new Promise((resolve) => {
@@ -36,35 +36,40 @@ import { type IntervalObservable } from '../types/index.mjs';
36
36
  *
37
37
  * subscription.unsubscribe();
38
38
  *
39
- * assert.isTrue(Arr.isArrayAtLeastLength(mut_history, 3));
39
+ * assert.isTrue(Arr.isArrayAtLeastLength(valueHistory, 3));
40
40
  *
41
- * assert.deepStrictEqual(mut_history[0], 0);
41
+ * assert.deepStrictEqual(valueHistory[0], 0);
42
42
  *
43
- * assert.deepStrictEqual(mut_history[1], 1);
43
+ * assert.deepStrictEqual(valueHistory[1], 1);
44
44
  *
45
- * assert.deepStrictEqual(mut_history[2], 2);
45
+ * assert.deepStrictEqual(valueHistory[2], 2);
46
46
  * ```
47
47
  */
48
- export const interval = (
49
- milliSeconds: number,
50
- startManually?: boolean,
51
- ): IntervalObservable =>
52
- new IntervalObservableClass(milliSeconds, startManually);
53
-
54
- class IntervalObservableClass
48
+ export const counter = (
49
+ intervalMilliSeconds: number,
50
+ options?: Readonly<{
51
+ startManually?: boolean;
52
+ }>,
53
+ ): CounterObservable =>
54
+ new CounterObservableClass(
55
+ intervalMilliSeconds,
56
+ options?.startManually ?? false,
57
+ );
58
+
59
+ class CounterObservableClass
55
60
  extends RootObservableClass<SafeUint>
56
- implements IntervalObservable
61
+ implements CounterObservable
57
62
  {
58
- readonly #milliSeconds: number;
63
+ readonly #intervalMilliSeconds: number;
59
64
  #mut_counter: SafeUint;
60
65
  #mut_timerId0: TimerId | undefined;
61
66
  #mut_timerId: TimerId | undefined;
62
67
  #mut_isStarted: boolean;
63
68
 
64
- constructor(milliSeconds: number, startManually?: boolean) {
69
+ constructor(intervalMilliSeconds: number, startManually: boolean) {
65
70
  super({ initialValue: Optional.none });
66
71
 
67
- this.#milliSeconds = milliSeconds;
72
+ this.#intervalMilliSeconds = intervalMilliSeconds;
68
73
 
69
74
  this.#mut_counter = asSafeUint(0);
70
75
 
@@ -74,27 +79,26 @@ class IntervalObservableClass
74
79
 
75
80
  this.#mut_isStarted = false;
76
81
 
77
- if (startManually !== true) {
82
+ if (!startManually) {
78
83
  this.start();
79
84
  }
80
85
  }
81
86
 
82
- start(): this {
87
+ start(): void {
83
88
  if (this.#mut_isStarted) {
84
89
  console.warn('cannot start twice');
85
90
 
86
- return this;
91
+ return;
87
92
  }
88
93
 
89
94
  this.#mut_isStarted = true;
90
95
 
91
96
  if (this.isCompleted) {
92
- console.warn('cannot restart stopped IntervalObservable');
97
+ console.warn('cannot restart stopped CounterObservable');
93
98
 
94
- return this;
99
+ return;
95
100
  }
96
101
 
97
- // emit zero
98
102
  this.#mut_timerId0 = setTimeout(() => {
99
103
  this.startUpdate(this.#mut_counter);
100
104
  }, 0);
@@ -103,9 +107,7 @@ class IntervalObservableClass
103
107
  this.#mut_counter = SafeUint.add(1, this.#mut_counter);
104
108
 
105
109
  this.startUpdate(this.#mut_counter);
106
- }, this.#milliSeconds);
107
-
108
- return this;
110
+ }, this.#intervalMilliSeconds);
109
111
  }
110
112
 
111
113
  #resetTimer(): void {
@@ -0,0 +1,83 @@
1
+ import { Optional, Result } from 'ts-data-forge';
2
+ import { RootObservableClass } from '../class/index.mjs';
3
+ import { type FromPromiseObservable } from '../types/index.mjs';
4
+
5
+ /**
6
+ * Creates an observable from a Promise factory that receives an `AbortSignal`.
7
+ * When the observable is completed (e.g., by `switchMap` switching to a new
8
+ * inner observable), the `AbortController` is automatically aborted, cancelling
9
+ * the in-flight request.
10
+ *
11
+ * Emits `Result.ok(value)` when the promise resolves, or `Result.err(error)`
12
+ * when it rejects. Rejections caused by abort (`AbortError`) are silently
13
+ * ignored and do not emit.
14
+ *
15
+ * @template A - The type of the resolved value
16
+ * @template E - The type of the error (excluding AbortError)
17
+ * @param factory - A function that receives an `AbortSignal` and returns a Promise
18
+ * @returns An observable that emits the promise result
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const results$ = query.pipe(
23
+ * switchMap((q) =>
24
+ * fromAbortablePromise((signal) =>
25
+ * fetch(`/api/search?q=${q}`, { signal }).then((r) => r.json()),
26
+ * ),
27
+ * ),
28
+ * );
29
+ * ```
30
+ */
31
+ export const fromAbortablePromise = <A, E = unknown>(
32
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
33
+ factory: (signal: AbortSignal) => Promise<A>,
34
+ ): FromPromiseObservable<A, E> =>
35
+ new FromAbortablePromiseObservableClass(factory);
36
+
37
+ class FromAbortablePromiseObservableClass<A, E = unknown>
38
+ extends RootObservableClass<Result<A, E>>
39
+ implements FromPromiseObservable<A, E>
40
+ {
41
+ readonly #abortController: AbortController;
42
+
43
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
44
+ constructor(factory: (signal: AbortSignal) => Promise<A>) {
45
+ super({ initialValue: Optional.none });
46
+
47
+ this.#abortController = new AbortController();
48
+
49
+ const promise = factory(this.#abortController.signal);
50
+
51
+ promise
52
+ .then((value) => {
53
+ if (this.isCompleted) return;
54
+
55
+ this.startUpdate(Result.ok(value));
56
+ })
57
+ .catch((error: unknown) => {
58
+ if (this.isCompleted) return;
59
+
60
+ // Silently ignore AbortError — it means the observable was
61
+ // intentionally completed (e.g., by switchMap).
62
+ if (error instanceof DOMException && error.name === 'AbortError') {
63
+ return;
64
+ }
65
+
66
+ this.startUpdate(
67
+ Result.err(
68
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
69
+ error as E,
70
+ ),
71
+ );
72
+ })
73
+ .finally(() => {
74
+ this.complete();
75
+ });
76
+ }
77
+
78
+ override complete(): void {
79
+ this.#abortController.abort();
80
+
81
+ super.complete();
82
+ }
83
+ }
@@ -16,7 +16,7 @@ import { type FromPromiseObservable } from '../types/index.mjs';
16
16
  * // Timeline:
17
17
  * //
18
18
  * // promise [pending...] -> resolved/rejected
19
- * // data$ Ok(value) or Err(error)
19
+ * // data$ Ok(value) or Err(error)
20
20
  * //
21
21
  * // Explanation:
22
22
  * // - fromPromise converts a Promise into an observable
@@ -24,17 +24,20 @@ import { type FromPromiseObservable } from '../types/index.mjs';
24
24
  * // - Completes after emitting the result
25
25
  * // - Useful for integrating async operations into reactive flows
26
26
  *
27
- * const fetchData = async (): Promise<{ value: number }> => ({ value: 42 });
27
+ * const fetchData = async (): Promise<Readonly<{ value: number }>> =>
28
+ * ({
29
+ * value: 42,
30
+ * }) as const;
28
31
  *
29
32
  * const data$ = fromPromise(fetchData());
30
33
  *
31
- * const mut_history: { value: number }[] = [];
34
+ * const valueHistory: Readonly<{ value: number }>[] = [];
32
35
  *
33
36
  * await new Promise<void>((resolve) => {
34
37
  * data$.subscribe(
35
38
  * (result) => {
36
39
  * if (Result.isOk(result)) {
37
- * mut_history.push(result.value);
40
+ * valueHistory.push(result.value);
38
41
  * }
39
42
  * },
40
43
  * () => {
@@ -43,18 +46,18 @@ import { type FromPromiseObservable } from '../types/index.mjs';
43
46
  * );
44
47
  * });
45
48
  *
46
- * assert.deepStrictEqual(mut_history, [{ value: 42 }]);
49
+ * assert.deepStrictEqual(valueHistory, [{ value: 42 }]);
47
50
  * ```
48
51
  */
49
52
  export const fromPromise = <A, E = unknown>(
50
- promise: Readonly<Promise<A>>,
53
+ promise: Promise<A>,
51
54
  ): FromPromiseObservable<A, E> => new FromPromiseObservableClass(promise);
52
55
 
53
56
  class FromPromiseObservableClass<A, E = unknown>
54
57
  extends RootObservableClass<Result<A, E>>
55
58
  implements FromPromiseObservable<A, E>
56
59
  {
57
- constructor(promise: Readonly<Promise<A>>) {
60
+ constructor(promise: Promise<A>) {
58
61
  super({ initialValue: Optional.none });
59
62
 
60
63
  promise
@@ -41,17 +41,17 @@ import {
41
41
  *
42
42
  * return { unsubscribe: () => {} };
43
43
  * },
44
- * };
44
+ * } as const;
45
45
  *
46
46
  * const observable$ = fromSubscribable<number>(customSubscribable);
47
47
  *
48
- * const mut_history: number[] = [];
48
+ * const valueHistory: number[] = [];
49
49
  *
50
50
  * await new Promise<void>((resolve) => {
51
51
  * observable$.subscribe(
52
52
  * (result) => {
53
53
  * if (Result.isOk(result)) {
54
- * mut_history.push(result.value);
54
+ * valueHistory.push(result.value);
55
55
  * }
56
56
  * },
57
57
  * () => {
@@ -60,7 +60,7 @@ import {
60
60
  * );
61
61
  * });
62
62
  *
63
- * assert.deepStrictEqual(mut_history, [1, 2, 3]);
63
+ * assert.deepStrictEqual(valueHistory, [1, 2, 3]);
64
64
  * ```
65
65
  */
66
66
  export const fromSubscribable = <A, E = unknown>(
@@ -1,7 +1,7 @@
1
- export * from './from-array.mjs';
1
+ export * from './counter.mjs';
2
+ export * from './from-abortable-promise.mjs';
2
3
  export * from './from-promise.mjs';
3
4
  export * from './from-subscribable.mjs';
4
- export * from './interval.mjs';
5
- export * from './of.mjs';
5
+ export * from './just.mjs';
6
6
  export * from './source.mjs';
7
7
  export * from './timer.mjs';
@@ -0,0 +1,43 @@
1
+ import { Optional } from 'ts-data-forge';
2
+ import { RootObservableClass } from '../class/index.mjs';
3
+ import { type InitializedRootObservable } from '../types/index.mjs';
4
+
5
+ /**
6
+ * Creates an Observable that holds a single static value and immediately
7
+ * completes. Useful inside `switchMap` to emit a fallback value when no
8
+ * asynchronous work is needed.
9
+ *
10
+ * @template A - The type of the value
11
+ * @param value - The value to emit
12
+ * @returns An initialized Observable that holds the value and is already completed
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const greeting$ = just('hello');
17
+ *
18
+ * const valueHistory: string[] = [];
19
+ *
20
+ * greeting$.subscribe(
21
+ * (value) => {
22
+ * valueHistory.push(value);
23
+ * },
24
+ * () => {
25
+ * // onComplete — called immediately since just() completes right away
26
+ * },
27
+ * );
28
+ *
29
+ * assert.deepStrictEqual(valueHistory, ['hello']);
30
+ *
31
+ * assert.strictEqual(greeting$.isCompleted, true);
32
+ * ```
33
+ */
34
+ export const just = <const A,>(value: A): InitializedRootObservable<A> => {
35
+ const obs = new RootObservableClass<A>({
36
+ initialValue: Optional.some(value),
37
+ });
38
+
39
+ obs.complete();
40
+
41
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
42
+ return obs as InitializedRootObservable<A>;
43
+ };