@ersbeth/picoflow 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/.vscode/settings.json +3 -3
  2. package/CHANGELOG.md +43 -0
  3. package/README.md +2 -18
  4. package/biome.json +45 -35
  5. package/dist/picoflow.js +857 -1528
  6. package/dist/types/api/base/flowDisposable.d.ts +41 -0
  7. package/dist/types/api/base/flowDisposable.d.ts.map +1 -0
  8. package/dist/types/api/base/flowObservable.d.ts +27 -0
  9. package/dist/types/api/base/flowObservable.d.ts.map +1 -0
  10. package/dist/types/api/base/flowSubscribable.d.ts +79 -0
  11. package/dist/types/api/base/flowSubscribable.d.ts.map +1 -0
  12. package/dist/types/api/base/flowTracker.d.ts +8 -0
  13. package/dist/types/api/base/flowTracker.d.ts.map +1 -0
  14. package/dist/types/api/base/index.d.ts +5 -0
  15. package/dist/types/api/base/index.d.ts.map +1 -0
  16. package/dist/types/api/index.d.ts +3 -0
  17. package/dist/types/api/index.d.ts.map +1 -0
  18. package/dist/types/api/nodes/async/flowConstantAsync.d.ts +31 -0
  19. package/dist/types/api/nodes/async/flowConstantAsync.d.ts.map +1 -0
  20. package/dist/types/api/nodes/async/flowDerivationAsync.d.ts +37 -0
  21. package/dist/types/api/nodes/async/flowDerivationAsync.d.ts.map +1 -0
  22. package/dist/types/api/nodes/async/flowStateAsync.d.ts +41 -0
  23. package/dist/types/api/nodes/async/flowStateAsync.d.ts.map +1 -0
  24. package/dist/types/api/nodes/async/flowWritableDerivationAsync.d.ts +30 -0
  25. package/dist/types/api/nodes/async/flowWritableDerivationAsync.d.ts.map +1 -0
  26. package/dist/types/{flow → api}/nodes/async/index.d.ts +1 -2
  27. package/dist/types/api/nodes/async/index.d.ts.map +1 -0
  28. package/dist/types/api/nodes/collections/flowArray.d.ts +134 -0
  29. package/dist/types/api/nodes/collections/flowArray.d.ts.map +1 -0
  30. package/dist/types/api/nodes/collections/flowMap.d.ts +98 -0
  31. package/dist/types/api/nodes/collections/flowMap.d.ts.map +1 -0
  32. package/dist/types/api/nodes/collections/index.d.ts.map +1 -0
  33. package/dist/types/api/nodes/flowEffect.d.ts +28 -0
  34. package/dist/types/api/nodes/flowEffect.d.ts.map +1 -0
  35. package/dist/types/api/nodes/flowSignal.d.ts +25 -0
  36. package/dist/types/api/nodes/flowSignal.d.ts.map +1 -0
  37. package/dist/types/api/nodes/flowValue.d.ts +35 -0
  38. package/dist/types/api/nodes/flowValue.d.ts.map +1 -0
  39. package/dist/types/api/nodes/index.d.ts +8 -0
  40. package/dist/types/api/nodes/index.d.ts.map +1 -0
  41. package/dist/types/api/nodes/sync/flowConstant.d.ts +29 -0
  42. package/dist/types/api/nodes/sync/flowConstant.d.ts.map +1 -0
  43. package/dist/types/api/nodes/sync/flowDerivation.d.ts +36 -0
  44. package/dist/types/api/nodes/sync/flowDerivation.d.ts.map +1 -0
  45. package/dist/types/api/nodes/sync/flowState.d.ts +39 -0
  46. package/dist/types/api/nodes/sync/flowState.d.ts.map +1 -0
  47. package/dist/types/api/nodes/sync/flowWritableDerivation.d.ts +28 -0
  48. package/dist/types/api/nodes/sync/flowWritableDerivation.d.ts.map +1 -0
  49. package/dist/types/{flow → api}/nodes/sync/index.d.ts +1 -2
  50. package/dist/types/api/nodes/sync/index.d.ts.map +1 -0
  51. package/dist/types/api/nodes/utils.d.ts +22 -0
  52. package/dist/types/api/nodes/utils.d.ts.map +1 -0
  53. package/dist/types/base/disposable.d.ts +11 -0
  54. package/dist/types/base/disposable.d.ts.map +1 -0
  55. package/dist/types/base/executionStack.d.ts +14 -0
  56. package/dist/types/base/executionStack.d.ts.map +1 -0
  57. package/dist/types/base/index.d.ts +6 -0
  58. package/dist/types/base/index.d.ts.map +1 -0
  59. package/dist/types/base/node.d.ts +27 -0
  60. package/dist/types/base/node.d.ts.map +1 -0
  61. package/dist/types/base/observable.d.ts +37 -0
  62. package/dist/types/base/observable.d.ts.map +1 -0
  63. package/dist/types/base/observer.d.ts +25 -0
  64. package/dist/types/base/observer.d.ts.map +1 -0
  65. package/dist/types/converters/index.d.ts +2 -0
  66. package/dist/types/converters/index.d.ts.map +1 -0
  67. package/dist/types/converters/solid.d.ts +46 -0
  68. package/dist/types/converters/solid.d.ts.map +1 -0
  69. package/dist/types/index.d.ts +2 -63
  70. package/dist/types/index.d.ts.map +1 -1
  71. package/dist/types/nodes/arrayNode.d.ts +2 -0
  72. package/dist/types/nodes/arrayNode.d.ts.map +1 -0
  73. package/dist/types/nodes/effectNode.d.ts +2 -0
  74. package/dist/types/nodes/effectNode.d.ts.map +1 -0
  75. package/dist/types/nodes/index.d.ts +9 -0
  76. package/dist/types/nodes/index.d.ts.map +1 -0
  77. package/dist/types/nodes/mapNode.d.ts +2 -0
  78. package/dist/types/nodes/mapNode.d.ts.map +1 -0
  79. package/dist/types/nodes/signalNode.d.ts +2 -0
  80. package/dist/types/nodes/signalNode.d.ts.map +1 -0
  81. package/dist/types/nodes/valueAsyncNode.d.ts +2 -0
  82. package/dist/types/nodes/valueAsyncNode.d.ts.map +1 -0
  83. package/dist/types/nodes/valueNode.d.ts +2 -0
  84. package/dist/types/nodes/valueNode.d.ts.map +1 -0
  85. package/dist/types/nodes/valueSyncNode.d.ts +2 -0
  86. package/dist/types/nodes/valueSyncNode.d.ts.map +1 -0
  87. package/dist/types/schedulers/asyncResolver.d.ts +2 -0
  88. package/dist/types/schedulers/asyncResolver.d.ts.map +1 -0
  89. package/dist/types/schedulers/asyncScheduler.d.ts +2 -0
  90. package/dist/types/schedulers/asyncScheduler.d.ts.map +1 -0
  91. package/dist/types/schedulers/index.d.ts +5 -0
  92. package/dist/types/schedulers/index.d.ts.map +1 -0
  93. package/dist/types/schedulers/pendingError.d.ts +2 -0
  94. package/dist/types/schedulers/pendingError.d.ts.map +1 -0
  95. package/dist/types/schedulers/scheduler.d.ts +2 -0
  96. package/dist/types/schedulers/scheduler.d.ts.map +1 -0
  97. package/dist/types/schedulers/syncResolver.d.ts +2 -0
  98. package/dist/types/schedulers/syncResolver.d.ts.map +1 -0
  99. package/dist/types/schedulers/syncScheduler.d.ts +2 -0
  100. package/dist/types/schedulers/syncScheduler.d.ts.map +1 -0
  101. package/docs/.vitepress/config.mts +128 -93
  102. package/docs/api/functions/array.md +14 -37
  103. package/docs/api/functions/constant.md +13 -25
  104. package/docs/api/functions/constantAsync.md +69 -0
  105. package/docs/api/functions/derivation.md +14 -33
  106. package/docs/api/functions/derivationAsync.md +34 -0
  107. package/docs/api/functions/from.md +62 -153
  108. package/docs/api/functions/isDisposable.md +8 -30
  109. package/docs/api/functions/map.md +15 -36
  110. package/docs/api/functions/signal.md +8 -23
  111. package/docs/api/functions/state.md +43 -23
  112. package/docs/api/functions/stateAsync.md +69 -0
  113. package/docs/api/functions/subscribe.md +40 -0
  114. package/docs/api/functions/writableDerivation.md +33 -0
  115. package/docs/api/functions/writableDerivationAsync.md +34 -0
  116. package/docs/api/index.md +45 -102
  117. package/docs/api/interfaces/FlowArray.md +439 -0
  118. package/docs/api/interfaces/FlowConstant.md +220 -0
  119. package/docs/api/interfaces/FlowConstantAsync.md +221 -0
  120. package/docs/api/interfaces/FlowDerivation.md +241 -0
  121. package/docs/api/interfaces/FlowDerivationAsync.md +242 -0
  122. package/docs/api/interfaces/FlowDisposable.md +32 -38
  123. package/docs/api/interfaces/FlowEffect.md +64 -0
  124. package/docs/api/interfaces/FlowMap.md +374 -0
  125. package/docs/api/interfaces/FlowObservable.md +155 -0
  126. package/docs/api/interfaces/FlowSignal.md +156 -0
  127. package/docs/api/interfaces/FlowState.md +269 -0
  128. package/docs/api/interfaces/FlowStateAsync.md +268 -0
  129. package/docs/api/interfaces/FlowSubscribable.md +55 -0
  130. package/docs/api/interfaces/FlowTracker.md +61 -0
  131. package/docs/api/interfaces/FlowValue.md +222 -0
  132. package/docs/api/interfaces/FlowWritableDerivation.md +292 -0
  133. package/docs/api/interfaces/FlowWritableDerivationAsync.md +293 -0
  134. package/docs/api/type-aliases/DerivationFunction.md +28 -0
  135. package/docs/api/type-aliases/DerivationFunctionAsync.md +28 -0
  136. package/docs/api/type-aliases/FlowArrayAction.md +19 -8
  137. package/docs/api/type-aliases/FlowDataTracker.md +33 -0
  138. package/docs/api/type-aliases/FlowMapAction.md +48 -0
  139. package/docs/api/type-aliases/FlowOnDataListener.md +33 -0
  140. package/docs/api/type-aliases/FlowOnErrorListener.md +27 -0
  141. package/docs/api/type-aliases/FlowOnPendingListener.md +21 -0
  142. package/docs/api/type-aliases/FlowReadonly.md +22 -0
  143. package/docs/api/type-aliases/InitFunction.md +21 -0
  144. package/docs/api/type-aliases/InitFunctionAsync.md +21 -0
  145. package/docs/api/type-aliases/NotPromise.md +6 -3
  146. package/docs/api/type-aliases/UpdateFunction.md +27 -0
  147. package/docs/api/type-aliases/UpdateFunctionAsync.md +27 -0
  148. package/docs/api/typedoc-sidebar.json +1 -81
  149. package/docs/examples/examples.md +0 -2
  150. package/docs/guide/advanced/architecture.md +1234 -0
  151. package/docs/guide/advanced/migration-v2.md +204 -0
  152. package/docs/guide/advanced/solidjs.md +2 -88
  153. package/docs/guide/introduction/concepts.md +4 -3
  154. package/docs/guide/introduction/conventions.md +2 -33
  155. package/docs/guide/introduction/getting-started.md +28 -23
  156. package/docs/guide/introduction/lifecycle.md +16 -19
  157. package/docs/guide/primitives/array.md +102 -216
  158. package/docs/guide/primitives/constant.md +39 -212
  159. package/docs/guide/primitives/derivations.md +55 -122
  160. package/docs/guide/primitives/effects.md +155 -241
  161. package/docs/guide/primitives/map.md +64 -186
  162. package/docs/guide/primitives/overview.md +45 -128
  163. package/docs/guide/primitives/signal.md +51 -88
  164. package/docs/guide/primitives/state.md +34 -130
  165. package/package.json +56 -60
  166. package/src/api/base/flowDisposable.ts +44 -0
  167. package/src/api/base/flowObservable.ts +28 -0
  168. package/src/api/base/flowSubscribable.ts +87 -0
  169. package/src/api/base/flowTracker.ts +7 -0
  170. package/src/api/base/index.ts +4 -0
  171. package/src/{flow → api}/index.ts +0 -1
  172. package/src/api/nodes/async/flowConstantAsync.ts +36 -0
  173. package/src/api/nodes/async/flowDerivationAsync.ts +42 -0
  174. package/src/api/nodes/async/flowStateAsync.ts +47 -0
  175. package/src/api/nodes/async/flowWritableDerivationAsync.ts +33 -0
  176. package/src/{flow → api}/nodes/async/index.ts +1 -2
  177. package/src/api/nodes/collections/flowArray.ts +155 -0
  178. package/src/api/nodes/collections/flowMap.ts +115 -0
  179. package/src/api/nodes/flowEffect.ts +42 -0
  180. package/src/api/nodes/flowSignal.ts +28 -0
  181. package/src/api/nodes/flowValue.ts +36 -0
  182. package/src/api/nodes/index.ts +7 -0
  183. package/src/api/nodes/sync/flowConstant.ts +33 -0
  184. package/src/api/nodes/sync/flowDerivation.ts +41 -0
  185. package/src/api/nodes/sync/flowState.ts +45 -0
  186. package/src/api/nodes/sync/flowWritableDerivation.ts +31 -0
  187. package/src/{flow → api}/nodes/sync/index.ts +1 -2
  188. package/src/api/nodes/utils.ts +22 -0
  189. package/src/base/disposable.ts +18 -0
  190. package/src/base/executionStack.ts +42 -0
  191. package/src/base/index.ts +5 -0
  192. package/src/base/node.ts +98 -0
  193. package/src/base/observable.ts +87 -0
  194. package/src/base/observer.ts +51 -0
  195. package/src/converters/index.ts +1 -0
  196. package/src/converters/solid.ts +109 -0
  197. package/src/index.ts +2 -64
  198. package/src/nodes/arrayNode.ts +172 -0
  199. package/src/nodes/effectNode.ts +59 -0
  200. package/src/nodes/index.ts +8 -0
  201. package/src/nodes/mapNode.ts +127 -0
  202. package/src/nodes/signalNode.ts +21 -0
  203. package/src/nodes/valueAsyncNode.ts +88 -0
  204. package/src/nodes/valueNode.ts +144 -0
  205. package/src/nodes/valueSyncNode.ts +128 -0
  206. package/src/schedulers/asyncResolver.ts +78 -0
  207. package/src/schedulers/asyncScheduler.ts +66 -0
  208. package/src/schedulers/index.ts +4 -0
  209. package/src/schedulers/pendingError.ts +13 -0
  210. package/src/schedulers/scheduler.ts +9 -0
  211. package/src/schedulers/syncResolver.ts +69 -0
  212. package/src/schedulers/syncScheduler.ts +55 -0
  213. package/test/base/pendingError.test.ts +67 -0
  214. package/test/converters/solid.derivation.browser.test.tsx +69 -0
  215. package/test/converters/solid.node.test.ts +654 -0
  216. package/test/converters/solid.state.browser.test.tsx +1592 -0
  217. package/test/reactivity/flowSignal.test.ts +226 -0
  218. package/test/reactivity/nodes/async/asyncScheduler/asyncResolver.test.ts +593 -0
  219. package/test/reactivity/nodes/async/asyncScheduler/asyncScheduler.test.ts +317 -0
  220. package/test/reactivity/nodes/async/flowConstantAsync.test.ts +652 -0
  221. package/test/reactivity/nodes/async/flowDerivation.test.ts +898 -0
  222. package/test/reactivity/nodes/async/flowDerivationAsync.test.ts +1716 -0
  223. package/test/reactivity/nodes/async/flowStateAsync.test.ts +708 -0
  224. package/test/reactivity/nodes/async/flowWritableDerivationAsync.test.ts +614 -0
  225. package/test/reactivity/nodes/collections/flowArray.asyncStates.test.ts +1289 -0
  226. package/test/reactivity/nodes/collections/flowArray.scalars.test.ts +961 -0
  227. package/test/reactivity/nodes/collections/flowArray.states.test.ts +1035 -0
  228. package/test/reactivity/nodes/collections/flowMap.asyncStates.test.ts +960 -0
  229. package/test/reactivity/nodes/collections/flowMap.scalars.test.ts +775 -0
  230. package/test/reactivity/nodes/collections/flowMap.states.test.ts +958 -0
  231. package/test/reactivity/nodes/sync/flowConstant.test.ts +377 -0
  232. package/test/reactivity/nodes/sync/flowDerivation.test.ts +896 -0
  233. package/test/reactivity/nodes/sync/flowState.test.ts +341 -0
  234. package/test/reactivity/nodes/sync/flowWritableDerivation.test.ts +603 -0
  235. package/test/vitest.d.ts +10 -0
  236. package/tsconfig.json +31 -20
  237. package/typedoc.json +35 -35
  238. package/vite.config.ts +25 -23
  239. package/vitest.browser.config.ts +21 -0
  240. package/vitest.config.ts +12 -12
  241. package/.cursor/plans/unifier-flowresource-avec-flowderivation-c9506e24.plan.md +0 -372
  242. package/.cursor/plans/update-js-e795d61b.plan.md +0 -567
  243. package/dist/types/flow/base/flowDisposable.d.ts +0 -67
  244. package/dist/types/flow/base/flowDisposable.d.ts.map +0 -1
  245. package/dist/types/flow/base/flowEffect.d.ts +0 -127
  246. package/dist/types/flow/base/flowEffect.d.ts.map +0 -1
  247. package/dist/types/flow/base/flowGraph.d.ts +0 -97
  248. package/dist/types/flow/base/flowGraph.d.ts.map +0 -1
  249. package/dist/types/flow/base/flowSignal.d.ts +0 -134
  250. package/dist/types/flow/base/flowSignal.d.ts.map +0 -1
  251. package/dist/types/flow/base/flowTracker.d.ts +0 -15
  252. package/dist/types/flow/base/flowTracker.d.ts.map +0 -1
  253. package/dist/types/flow/base/index.d.ts +0 -7
  254. package/dist/types/flow/base/index.d.ts.map +0 -1
  255. package/dist/types/flow/base/utils.d.ts +0 -20
  256. package/dist/types/flow/base/utils.d.ts.map +0 -1
  257. package/dist/types/flow/collections/flowArray.d.ts +0 -148
  258. package/dist/types/flow/collections/flowArray.d.ts.map +0 -1
  259. package/dist/types/flow/collections/flowMap.d.ts +0 -224
  260. package/dist/types/flow/collections/flowMap.d.ts.map +0 -1
  261. package/dist/types/flow/collections/index.d.ts.map +0 -1
  262. package/dist/types/flow/index.d.ts +0 -4
  263. package/dist/types/flow/index.d.ts.map +0 -1
  264. package/dist/types/flow/nodes/async/flowConstantAsync.d.ts +0 -137
  265. package/dist/types/flow/nodes/async/flowConstantAsync.d.ts.map +0 -1
  266. package/dist/types/flow/nodes/async/flowDerivationAsync.d.ts +0 -137
  267. package/dist/types/flow/nodes/async/flowDerivationAsync.d.ts.map +0 -1
  268. package/dist/types/flow/nodes/async/flowNodeAsync.d.ts +0 -343
  269. package/dist/types/flow/nodes/async/flowNodeAsync.d.ts.map +0 -1
  270. package/dist/types/flow/nodes/async/flowReadonlyAsync.d.ts +0 -81
  271. package/dist/types/flow/nodes/async/flowReadonlyAsync.d.ts.map +0 -1
  272. package/dist/types/flow/nodes/async/flowStateAsync.d.ts +0 -111
  273. package/dist/types/flow/nodes/async/flowStateAsync.d.ts.map +0 -1
  274. package/dist/types/flow/nodes/async/index.d.ts.map +0 -1
  275. package/dist/types/flow/nodes/index.d.ts +0 -3
  276. package/dist/types/flow/nodes/index.d.ts.map +0 -1
  277. package/dist/types/flow/nodes/sync/flowConstant.d.ts +0 -108
  278. package/dist/types/flow/nodes/sync/flowConstant.d.ts.map +0 -1
  279. package/dist/types/flow/nodes/sync/flowDerivation.d.ts +0 -100
  280. package/dist/types/flow/nodes/sync/flowDerivation.d.ts.map +0 -1
  281. package/dist/types/flow/nodes/sync/flowNode.d.ts +0 -314
  282. package/dist/types/flow/nodes/sync/flowNode.d.ts.map +0 -1
  283. package/dist/types/flow/nodes/sync/flowReadonly.d.ts +0 -57
  284. package/dist/types/flow/nodes/sync/flowReadonly.d.ts.map +0 -1
  285. package/dist/types/flow/nodes/sync/flowState.d.ts +0 -96
  286. package/dist/types/flow/nodes/sync/flowState.d.ts.map +0 -1
  287. package/dist/types/flow/nodes/sync/index.d.ts.map +0 -1
  288. package/dist/types/solid/converters.d.ts +0 -53
  289. package/dist/types/solid/converters.d.ts.map +0 -1
  290. package/dist/types/solid/index.d.ts +0 -3
  291. package/dist/types/solid/index.d.ts.map +0 -1
  292. package/dist/types/solid/primitives.d.ts +0 -181
  293. package/dist/types/solid/primitives.d.ts.map +0 -1
  294. package/docs/api/classes/FlowArray.md +0 -489
  295. package/docs/api/classes/FlowConstant.md +0 -350
  296. package/docs/api/classes/FlowDerivation.md +0 -334
  297. package/docs/api/classes/FlowEffect.md +0 -100
  298. package/docs/api/classes/FlowMap.md +0 -512
  299. package/docs/api/classes/FlowObservable.md +0 -306
  300. package/docs/api/classes/FlowResource.md +0 -380
  301. package/docs/api/classes/FlowResourceAsync.md +0 -362
  302. package/docs/api/classes/FlowSignal.md +0 -160
  303. package/docs/api/classes/FlowState.md +0 -368
  304. package/docs/api/classes/FlowStream.md +0 -367
  305. package/docs/api/classes/FlowStreamAsync.md +0 -364
  306. package/docs/api/classes/SolidDerivation.md +0 -75
  307. package/docs/api/classes/SolidResource.md +0 -91
  308. package/docs/api/classes/SolidState.md +0 -71
  309. package/docs/api/classes/TrackingContext.md +0 -33
  310. package/docs/api/functions/effect.md +0 -49
  311. package/docs/api/functions/resource.md +0 -52
  312. package/docs/api/functions/resourceAsync.md +0 -50
  313. package/docs/api/functions/stream.md +0 -53
  314. package/docs/api/functions/streamAsync.md +0 -50
  315. package/docs/api/interfaces/SolidObservable.md +0 -19
  316. package/docs/api/type-aliases/FlowStreamDisposer.md +0 -15
  317. package/docs/api/type-aliases/FlowStreamSetter.md +0 -27
  318. package/docs/api/type-aliases/FlowStreamUpdater.md +0 -32
  319. package/docs/api/type-aliases/SolidGetter.md +0 -17
  320. package/docs/guide/primitives/resources.md +0 -858
  321. package/docs/guide/primitives/streams.md +0 -931
  322. package/src/flow/base/flowDisposable.ts +0 -71
  323. package/src/flow/base/flowEffect.ts +0 -171
  324. package/src/flow/base/flowGraph.ts +0 -288
  325. package/src/flow/base/flowSignal.ts +0 -207
  326. package/src/flow/base/flowTracker.ts +0 -17
  327. package/src/flow/base/index.ts +0 -6
  328. package/src/flow/base/utils.ts +0 -19
  329. package/src/flow/collections/flowArray.ts +0 -409
  330. package/src/flow/collections/flowMap.ts +0 -398
  331. package/src/flow/nodes/async/flowConstantAsync.ts +0 -142
  332. package/src/flow/nodes/async/flowDerivationAsync.ts +0 -143
  333. package/src/flow/nodes/async/flowNodeAsync.ts +0 -474
  334. package/src/flow/nodes/async/flowReadonlyAsync.ts +0 -81
  335. package/src/flow/nodes/async/flowStateAsync.ts +0 -116
  336. package/src/flow/nodes/await/advanced/index.ts +0 -5
  337. package/src/flow/nodes/await/advanced/resource.ts +0 -134
  338. package/src/flow/nodes/await/advanced/resourceAsync.ts +0 -109
  339. package/src/flow/nodes/await/advanced/stream.ts +0 -188
  340. package/src/flow/nodes/await/advanced/streamAsync.ts +0 -176
  341. package/src/flow/nodes/await/flowConstantAwait.ts +0 -154
  342. package/src/flow/nodes/await/flowDerivationAwait.ts +0 -154
  343. package/src/flow/nodes/await/flowNodeAwait.ts +0 -508
  344. package/src/flow/nodes/await/flowReadonlyAwait.ts +0 -89
  345. package/src/flow/nodes/await/flowStateAwait.ts +0 -130
  346. package/src/flow/nodes/await/index.ts +0 -5
  347. package/src/flow/nodes/index.ts +0 -3
  348. package/src/flow/nodes/sync/flowConstant.ts +0 -111
  349. package/src/flow/nodes/sync/flowDerivation.ts +0 -105
  350. package/src/flow/nodes/sync/flowNode.ts +0 -439
  351. package/src/flow/nodes/sync/flowReadonly.ts +0 -57
  352. package/src/flow/nodes/sync/flowState.ts +0 -101
  353. package/src/solid/converters.ts +0 -139
  354. package/src/solid/index.ts +0 -2
  355. package/src/solid/primitives.ts +0 -215
  356. package/test/base/flowEffect.test.ts +0 -108
  357. package/test/base/flowGraph.test.ts +0 -485
  358. package/test/base/flowSignal.test.ts +0 -372
  359. package/test/collections/flowArray.asyncStates.test.ts +0 -1553
  360. package/test/collections/flowArray.scalars.test.ts +0 -1129
  361. package/test/collections/flowArray.states.test.ts +0 -1365
  362. package/test/collections/flowMap.asyncStates.test.ts +0 -1105
  363. package/test/collections/flowMap.scalars.test.ts +0 -877
  364. package/test/collections/flowMap.states.test.ts +0 -1097
  365. package/test/nodes/async/flowConstantAsync.test.ts +0 -860
  366. package/test/nodes/async/flowDerivationAsync.test.ts +0 -1517
  367. package/test/nodes/async/flowStateAsync.test.ts +0 -1387
  368. package/test/nodes/await/advanced/resource.test.ts +0 -129
  369. package/test/nodes/await/advanced/resourceAsync.test.ts +0 -108
  370. package/test/nodes/await/advanced/stream.test.ts +0 -198
  371. package/test/nodes/await/advanced/streamAsync.test.ts +0 -196
  372. package/test/nodes/await/flowConstantAwait.test.ts +0 -643
  373. package/test/nodes/await/flowDerivationAwait.test.ts +0 -1583
  374. package/test/nodes/await/flowStateAwait.test.ts +0 -999
  375. package/test/nodes/mixed/derivation.test.ts +0 -1527
  376. package/test/nodes/sync/flowConstant.test.ts +0 -620
  377. package/test/nodes/sync/flowDerivation.test.ts +0 -1373
  378. package/test/nodes/sync/flowState.test.ts +0 -945
  379. package/test/solid/converters.test.ts +0 -721
  380. package/test/solid/primitives.test.ts +0 -1031
  381. /package/dist/types/{flow → api/nodes}/collections/index.d.ts +0 -0
  382. /package/docs/guide/advanced/{upgrading.md → migration-v1.md} +0 -0
  383. /package/src/{flow → api/nodes}/collections/index.ts +0 -0
@@ -0,0 +1,1289 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { array, type FlowStateAsync, stateAsync, subscribe } from "~";
3
+
4
+ describe("FlowArray", () => {
5
+ describe("unit", () => {
6
+ describe("initialization", () => {
7
+ it("should initialize with provided FlowStateAsync values", async () => {
8
+ const $array = array([
9
+ stateAsync(Promise.resolve(1)),
10
+ stateAsync(Promise.resolve(2)),
11
+ stateAsync(Promise.resolve(3)),
12
+ ]);
13
+
14
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([1, 2, 3]);
15
+ });
16
+
17
+ it("should initialize with empty array when no value provided", async () => {
18
+ const $array = array<FlowStateAsync<number>>();
19
+
20
+ expect(await $array.pick()).toEqual([]);
21
+ });
22
+ });
23
+
24
+ describe("disposal", () => {
25
+ it("should have disposed property set to false initially and true after disposal", () => {
26
+ const $array = array([
27
+ stateAsync(Promise.resolve(1)),
28
+ stateAsync(Promise.resolve(2)),
29
+ stateAsync(Promise.resolve(3)),
30
+ ]);
31
+ expect($array.disposed).toBe(false);
32
+ $array.dispose();
33
+ expect($array.disposed).toBe(true);
34
+ });
35
+
36
+ it("should throw error when disposed twice", () => {
37
+ const $array = array([
38
+ stateAsync(Promise.resolve(1)),
39
+ stateAsync(Promise.resolve(2)),
40
+ stateAsync(Promise.resolve(3)),
41
+ ]);
42
+ $array.dispose();
43
+ expect(() => $array.dispose()).toThrow("[PicoFlow] Primitive is disposed");
44
+ });
45
+
46
+ it("should throw when pick is called after disposal", async () => {
47
+ const $array = array([
48
+ stateAsync(Promise.resolve(1)),
49
+ stateAsync(Promise.resolve(2)),
50
+ stateAsync(Promise.resolve(3)),
51
+ ]);
52
+ $array.dispose();
53
+ await expect($array.pick()).rejects.toThrow("[PicoFlow] Primitive is disposed");
54
+ });
55
+
56
+ it("should throw when set is called after disposal", () => {
57
+ const $array = array([
58
+ stateAsync(Promise.resolve(1)),
59
+ stateAsync(Promise.resolve(2)),
60
+ stateAsync(Promise.resolve(3)),
61
+ ]);
62
+ $array.dispose();
63
+ expect(() => $array.set([stateAsync(Promise.resolve(1))])).toThrow("[PicoFlow] Primitive is disposed");
64
+ });
65
+
66
+ it("should throw when update is called after disposal", () => {
67
+ const $array = array([
68
+ stateAsync(Promise.resolve(1)),
69
+ stateAsync(Promise.resolve(2)),
70
+ stateAsync(Promise.resolve(3)),
71
+ ]);
72
+ $array.dispose();
73
+ expect(() => $array.update(0, stateAsync(Promise.resolve(3)))).toThrow(
74
+ "[PicoFlow] Primitive is disposed",
75
+ );
76
+ });
77
+
78
+ it("should throw when push is called after disposal", () => {
79
+ const $array = array([
80
+ stateAsync(Promise.resolve(1)),
81
+ stateAsync(Promise.resolve(2)),
82
+ stateAsync(Promise.resolve(3)),
83
+ ]);
84
+ $array.dispose();
85
+ expect(() => $array.push(stateAsync(Promise.resolve(3)))).toThrow("[PicoFlow] Primitive is disposed");
86
+ });
87
+
88
+ it("should throw when pop is called after disposal", () => {
89
+ const $array = array([
90
+ stateAsync(Promise.resolve(1)),
91
+ stateAsync(Promise.resolve(2)),
92
+ stateAsync(Promise.resolve(3)),
93
+ ]);
94
+ $array.dispose();
95
+ expect(() => $array.pop()).toThrow("[PicoFlow] Primitive is disposed");
96
+ });
97
+
98
+ it("should throw when unshift is called after disposal", () => {
99
+ const $array = array([
100
+ stateAsync(Promise.resolve(1)),
101
+ stateAsync(Promise.resolve(2)),
102
+ stateAsync(Promise.resolve(3)),
103
+ ]);
104
+ $array.dispose();
105
+ expect(() => $array.unshift(stateAsync(Promise.resolve(3)))).toThrow(
106
+ "[PicoFlow] Primitive is disposed",
107
+ );
108
+ });
109
+
110
+ it("should throw when shift is called after disposal", () => {
111
+ const $array = array([
112
+ stateAsync(Promise.resolve(1)),
113
+ stateAsync(Promise.resolve(2)),
114
+ stateAsync(Promise.resolve(3)),
115
+ ]);
116
+ $array.dispose();
117
+ expect(() => $array.shift()).toThrow("[PicoFlow] Primitive is disposed");
118
+ });
119
+
120
+ it("should throw when splice is called after disposal", () => {
121
+ const $array = array<FlowStateAsync<number>>([
122
+ stateAsync(Promise.resolve(0)),
123
+ stateAsync(Promise.resolve(1)),
124
+ stateAsync(Promise.resolve(2)),
125
+ stateAsync(Promise.resolve(3)),
126
+ stateAsync(Promise.resolve(4)),
127
+ ]);
128
+ $array.dispose();
129
+ expect(() => $array.splice(1, 2)).toThrow("[PicoFlow] Primitive is disposed");
130
+ });
131
+
132
+ it("should throw when clear is called after disposal", () => {
133
+ const $array = array<FlowStateAsync<number>>([
134
+ stateAsync(Promise.resolve(0)),
135
+ stateAsync(Promise.resolve(1)),
136
+ stateAsync(Promise.resolve(2)),
137
+ stateAsync(Promise.resolve(3)),
138
+ stateAsync(Promise.resolve(4)),
139
+ ]);
140
+ $array.dispose();
141
+ expect(() => $array.clear()).toThrow("[PicoFlow] Primitive is disposed");
142
+ });
143
+ });
144
+
145
+ describe("length", () => {
146
+ it("should return correct length", () => {
147
+ const $array = array([
148
+ stateAsync(Promise.resolve(1)),
149
+ stateAsync(Promise.resolve(2)),
150
+ stateAsync(Promise.resolve(3)),
151
+ ]);
152
+ expect($array.length).toBe(3);
153
+ });
154
+
155
+ it("should return zero for empty array", () => {
156
+ const $array = array<FlowStateAsync<number>>([]);
157
+ expect($array.length).toBe(0);
158
+ });
159
+
160
+ it("should throw when length is accessed after disposal", () => {
161
+ const $array = array([
162
+ stateAsync(Promise.resolve(1)),
163
+ stateAsync(Promise.resolve(2)),
164
+ stateAsync(Promise.resolve(3)),
165
+ ]);
166
+ $array.dispose();
167
+ expect(() => $array.length).toThrow("[PicoFlow] Primitive is disposed");
168
+ });
169
+
170
+ it("should update length when array is modified", () => {
171
+ const $array = array<FlowStateAsync<number>>([]);
172
+ expect($array.length).toBe(0);
173
+
174
+ $array.push(stateAsync(Promise.resolve(1)));
175
+ expect($array.length).toBe(1);
176
+
177
+ $array.push(stateAsync(Promise.resolve(2)));
178
+ expect($array.length).toBe(2);
179
+
180
+ $array.pop();
181
+ expect($array.length).toBe(1);
182
+
183
+ $array.unshift(stateAsync(Promise.resolve(0)));
184
+ expect($array.length).toBe(2);
185
+
186
+ $array.shift();
187
+ expect($array.length).toBe(1);
188
+
189
+ $array.clear();
190
+ expect($array.length).toBe(0);
191
+ });
192
+ });
193
+
194
+ describe("set", () => {
195
+ it("should update array when set is called with FlowStateAsync", async () => {
196
+ const $array = array([
197
+ stateAsync(Promise.resolve(0)),
198
+ stateAsync(Promise.resolve(1)),
199
+ stateAsync(Promise.resolve(2)),
200
+ ]);
201
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 1, 2]);
202
+
203
+ $array.set([
204
+ stateAsync(Promise.resolve(1)),
205
+ stateAsync(Promise.resolve(2)),
206
+ stateAsync(Promise.resolve(3)),
207
+ ]);
208
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([1, 2, 3]);
209
+ });
210
+ });
211
+
212
+ describe("update", () => {
213
+ it("should update item at specific index", async () => {
214
+ const $array = array([
215
+ stateAsync(Promise.resolve(0)),
216
+ stateAsync(Promise.resolve(1)),
217
+ stateAsync(Promise.resolve(2)),
218
+ ]);
219
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 1, 2]);
220
+
221
+ $array.update(0, stateAsync(Promise.resolve(1)));
222
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([1, 1, 2]);
223
+
224
+ $array.update(1, stateAsync(Promise.resolve(2)));
225
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([1, 2, 2]);
226
+
227
+ $array.update(2, stateAsync(Promise.resolve(3)));
228
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([1, 2, 3]);
229
+ });
230
+
231
+ it("should throw when update is called with negative index", () => {
232
+ const $array = array([
233
+ stateAsync(Promise.resolve(1)),
234
+ stateAsync(Promise.resolve(2)),
235
+ stateAsync(Promise.resolve(3)),
236
+ ]);
237
+ expect(() => $array.update(-1, stateAsync(Promise.resolve(0)))).toThrow(
238
+ "[PicoFlow] Index out of bounds",
239
+ );
240
+ });
241
+
242
+ it("should throw when update is called with index >= length", () => {
243
+ const $array = array([
244
+ stateAsync(Promise.resolve(1)),
245
+ stateAsync(Promise.resolve(2)),
246
+ stateAsync(Promise.resolve(3)),
247
+ ]);
248
+ expect(() => $array.update(3, stateAsync(Promise.resolve(0)))).toThrow(
249
+ "[PicoFlow] Index out of bounds",
250
+ );
251
+ expect(() => $array.update(10, stateAsync(Promise.resolve(0)))).toThrow(
252
+ "[PicoFlow] Index out of bounds",
253
+ );
254
+ });
255
+
256
+ it("should handle boundary indices correctly", async () => {
257
+ const $array = array([
258
+ stateAsync(Promise.resolve(0)),
259
+ stateAsync(Promise.resolve(1)),
260
+ stateAsync(Promise.resolve(2)),
261
+ ]);
262
+ $array.update(0, stateAsync(Promise.resolve(10)));
263
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([10, 1, 2]);
264
+
265
+ $array.update(2, stateAsync(Promise.resolve(20)));
266
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([10, 1, 20]);
267
+ });
268
+ });
269
+
270
+ describe("push", () => {
271
+ it("should append FlowStateAsync to end of array", async () => {
272
+ const $array = array<FlowStateAsync<number>>([]);
273
+ expect(await $array.pick()).toEqual([]);
274
+
275
+ $array.push(stateAsync(Promise.resolve(0)));
276
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0]);
277
+
278
+ $array.push(stateAsync(Promise.resolve(1)));
279
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 1]);
280
+
281
+ $array.push(stateAsync(Promise.resolve(2)));
282
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 1, 2]);
283
+ });
284
+
285
+ it("should handle operations on empty array", () => {
286
+ const $array = array<FlowStateAsync<number>>([]);
287
+ expect($array.length).toBe(0);
288
+ $array.push(stateAsync(Promise.resolve(1)));
289
+ expect($array.length).toBe(1);
290
+ });
291
+ });
292
+
293
+ describe("pop", () => {
294
+ it("should remove last FlowStateAsync from array", async () => {
295
+ const $array = array([
296
+ stateAsync(Promise.resolve(0)),
297
+ stateAsync(Promise.resolve(1)),
298
+ stateAsync(Promise.resolve(2)),
299
+ ]);
300
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 1, 2]);
301
+
302
+ $array.pop();
303
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 1]);
304
+
305
+ $array.pop();
306
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0]);
307
+
308
+ $array.pop();
309
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([]);
310
+ });
311
+
312
+ it("should handle operations on empty array", () => {
313
+ const $array = array<FlowStateAsync<number>>([]);
314
+ expect($array.length).toBe(0);
315
+ $array.pop();
316
+ expect($array.length).toBe(0);
317
+ });
318
+ });
319
+
320
+ describe("unshift", () => {
321
+ it("should insert FlowStateAsync at beginning of array", async () => {
322
+ const $array = array<FlowStateAsync<number>>([]);
323
+ expect(await $array.pick()).toEqual([]);
324
+
325
+ $array.unshift(stateAsync(Promise.resolve(0)));
326
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0]);
327
+
328
+ $array.unshift(stateAsync(Promise.resolve(1)));
329
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([1, 0]);
330
+
331
+ $array.unshift(stateAsync(Promise.resolve(2)));
332
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([2, 1, 0]);
333
+ });
334
+ });
335
+
336
+ describe("shift", () => {
337
+ it("should remove first FlowStateAsync from array", async () => {
338
+ const $array = array([
339
+ stateAsync(Promise.resolve(0)),
340
+ stateAsync(Promise.resolve(1)),
341
+ stateAsync(Promise.resolve(2)),
342
+ ]);
343
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 1, 2]);
344
+
345
+ $array.shift();
346
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([1, 2]);
347
+
348
+ $array.shift();
349
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([2]);
350
+
351
+ $array.shift();
352
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([]);
353
+ });
354
+
355
+ it("should handle operations on empty array", () => {
356
+ const $array = array<FlowStateAsync<number>>([]);
357
+ expect($array.length).toBe(0);
358
+ $array.shift();
359
+ expect($array.length).toBe(0);
360
+ });
361
+ });
362
+
363
+ describe("splice", () => {
364
+ it("should remove FlowStateAsync from array", async () => {
365
+ const $array = array<FlowStateAsync<number>>([
366
+ stateAsync(Promise.resolve(0)),
367
+ stateAsync(Promise.resolve(1)),
368
+ stateAsync(Promise.resolve(2)),
369
+ stateAsync(Promise.resolve(3)),
370
+ stateAsync(Promise.resolve(4)),
371
+ ]);
372
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 1, 2, 3, 4]);
373
+
374
+ $array.splice(1, 2);
375
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 3, 4]);
376
+ });
377
+
378
+ it("should insert FlowStateAsync into array", async () => {
379
+ const $array = array<FlowStateAsync<number>>([
380
+ stateAsync(Promise.resolve(0)),
381
+ stateAsync(Promise.resolve(1)),
382
+ stateAsync(Promise.resolve(2)),
383
+ stateAsync(Promise.resolve(3)),
384
+ stateAsync(Promise.resolve(4)),
385
+ ]);
386
+ $array.splice(1, 0, stateAsync(Promise.resolve(10)), stateAsync(Promise.resolve(11)));
387
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([
388
+ 0, 10, 11, 1, 2, 3, 4,
389
+ ]);
390
+ });
391
+
392
+ it("should replace FlowStateAsync in array", async () => {
393
+ const $array = array<FlowStateAsync<number>>([
394
+ stateAsync(Promise.resolve(0)),
395
+ stateAsync(Promise.resolve(1)),
396
+ stateAsync(Promise.resolve(2)),
397
+ stateAsync(Promise.resolve(3)),
398
+ stateAsync(Promise.resolve(4)),
399
+ ]);
400
+ $array.splice(1, 2, stateAsync(Promise.resolve(10)), stateAsync(Promise.resolve(11)));
401
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([
402
+ 0, 10, 11, 3, 4,
403
+ ]);
404
+ });
405
+ });
406
+
407
+ describe("clear", () => {
408
+ it("should remove all FlowStateAsync from array", async () => {
409
+ const $array = array<FlowStateAsync<number>>([
410
+ stateAsync(Promise.resolve(0)),
411
+ stateAsync(Promise.resolve(1)),
412
+ stateAsync(Promise.resolve(2)),
413
+ stateAsync(Promise.resolve(3)),
414
+ stateAsync(Promise.resolve(4)),
415
+ ]);
416
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 1, 2, 3, 4]);
417
+
418
+ $array.clear();
419
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([]);
420
+ });
421
+ });
422
+
423
+ describe("$lastAction", () => {
424
+ describe("set action", () => {
425
+ it("should initialize $lastAction with set action on creation", async () => {
426
+ const $array = array([
427
+ stateAsync(Promise.resolve(1)),
428
+ stateAsync(Promise.resolve(2)),
429
+ stateAsync(Promise.resolve(3)),
430
+ ]);
431
+ const action = await $array.$lastAction.pick();
432
+ expect(action.type).toBe("set");
433
+ if (action.type === "set") {
434
+ expect(action.setItems).toHaveLength(3);
435
+ expect(action.setItems[0]).toBeInstanceOf(Object);
436
+ expect(action.setItems[1]).toBeInstanceOf(Object);
437
+ expect(action.setItems[2]).toBeInstanceOf(Object);
438
+ expect(action.clearedItems).toEqual([]);
439
+ }
440
+ });
441
+
442
+ it("should update $lastAction with set action when set is called", async () => {
443
+ const $array = array([
444
+ stateAsync(Promise.resolve(0)),
445
+ stateAsync(Promise.resolve(1)),
446
+ stateAsync(Promise.resolve(2)),
447
+ ]);
448
+ $array.set([
449
+ stateAsync(Promise.resolve(1)),
450
+ stateAsync(Promise.resolve(2)),
451
+ stateAsync(Promise.resolve(3)),
452
+ ]);
453
+ const action = await $array.$lastAction.pick();
454
+ expect(action.type).toBe("set");
455
+ if (action.type === "set") {
456
+ expect(action.setItems).toHaveLength(3);
457
+ expect(action.clearedItems).toHaveLength(3);
458
+ }
459
+ });
460
+
461
+ it("should have correct structure for set action (setItems and clearedItems)", async () => {
462
+ const $array = array([
463
+ stateAsync(Promise.resolve(1)),
464
+ stateAsync(Promise.resolve(2)),
465
+ stateAsync(Promise.resolve(3)),
466
+ ]);
467
+ const action = await $array.$lastAction.pick();
468
+ expect(action).toHaveProperty("type", "set");
469
+ if (action.type === "set") {
470
+ expect(action).toHaveProperty("setItems");
471
+ expect(action).toHaveProperty("clearedItems");
472
+ expect(Array.isArray(action.setItems)).toBe(true);
473
+ expect(Array.isArray(action.clearedItems)).toBe(true);
474
+ expect(action.setItems).toHaveLength(3);
475
+ expect(action.clearedItems).toEqual([]);
476
+ }
477
+ });
478
+ });
479
+
480
+ describe("update action", () => {
481
+ it("should update $lastAction with update action when update is called", async () => {
482
+ const $array = array([
483
+ stateAsync(Promise.resolve(0)),
484
+ stateAsync(Promise.resolve(1)),
485
+ stateAsync(Promise.resolve(2)),
486
+ ]);
487
+ const $newItem = stateAsync(Promise.resolve(10));
488
+ $array.update(1, $newItem);
489
+ const action = await $array.$lastAction.pick();
490
+ expect(action.type).toBe("update");
491
+ if (action.type === "update") {
492
+ expect(action.index).toBe(1);
493
+ expect(action.setItem).toBe($newItem);
494
+ expect(action.clearedItem).toBeInstanceOf(Object);
495
+ }
496
+ });
497
+
498
+ it("should have correct structure for update action (index, setItem, clearedItem)", async () => {
499
+ const $array = array([
500
+ stateAsync(Promise.resolve(1)),
501
+ stateAsync(Promise.resolve(2)),
502
+ stateAsync(Promise.resolve(3)),
503
+ ]);
504
+ const $newItem = stateAsync(Promise.resolve(10));
505
+ $array.update(0, $newItem);
506
+ const action = await $array.$lastAction.pick();
507
+ expect(action).toHaveProperty("type", "update");
508
+ if (action.type === "update") {
509
+ expect(action).toHaveProperty("index");
510
+ expect(action).toHaveProperty("setItem");
511
+ expect(action).toHaveProperty("clearedItem");
512
+ expect(action.index).toBe(0);
513
+ expect(action.setItem).toBe($newItem);
514
+ expect(action.clearedItem).toBeInstanceOf(Object);
515
+ }
516
+ });
517
+ });
518
+
519
+ describe("push action", () => {
520
+ it("should update $lastAction with push action when push is called", async () => {
521
+ const $array = array<FlowStateAsync<number>>([]);
522
+ const $newItem = stateAsync(Promise.resolve(42));
523
+ $array.push($newItem);
524
+ const action = await $array.$lastAction.pick();
525
+ expect(action.type).toBe("push");
526
+ if (action.type === "push") {
527
+ expect(action.addedItem).toBe($newItem);
528
+ }
529
+ });
530
+
531
+ it("should have correct structure for push action (addedItem)", async () => {
532
+ const $array = array<FlowStateAsync<number>>([]);
533
+ const $newItem = stateAsync(Promise.resolve(100));
534
+ $array.push($newItem);
535
+ const action = await $array.$lastAction.pick();
536
+ expect(action).toHaveProperty("type", "push");
537
+ if (action.type === "push") {
538
+ expect(action).toHaveProperty("addedItem");
539
+ expect(action.addedItem).toBe($newItem);
540
+ }
541
+ });
542
+ });
543
+
544
+ describe("pop action", () => {
545
+ it("should update $lastAction with pop action when pop is called", async () => {
546
+ const $array = array([
547
+ stateAsync(Promise.resolve(1)),
548
+ stateAsync(Promise.resolve(2)),
549
+ stateAsync(Promise.resolve(3)),
550
+ ]);
551
+ $array.pop();
552
+ const action = await $array.$lastAction.pick();
553
+ expect(action).toEqual({
554
+ type: "pop",
555
+ removedItem: expect.any(Object),
556
+ });
557
+ });
558
+
559
+ it("should have correct structure for pop action (removedItem)", async () => {
560
+ const $array = array([
561
+ stateAsync(Promise.resolve(1)),
562
+ stateAsync(Promise.resolve(2)),
563
+ stateAsync(Promise.resolve(3)),
564
+ ]);
565
+ $array.pop();
566
+ const action = await $array.$lastAction.pick();
567
+ expect(action).toHaveProperty("type", "pop");
568
+ if (action.type === "pop") {
569
+ expect(action).toHaveProperty("removedItem");
570
+ expect(action.removedItem).toBeInstanceOf(Object);
571
+ }
572
+ });
573
+
574
+ it("should have removedItem undefined when pop is called on empty array", async () => {
575
+ const $array = array<FlowStateAsync<number>>([]);
576
+ $array.pop();
577
+ const action = await $array.$lastAction.pick();
578
+ expect(action).toHaveProperty("type", "pop");
579
+ if (action.type === "pop") {
580
+ expect(action).toHaveProperty("removedItem");
581
+ expect(action.removedItem).toBeUndefined();
582
+ }
583
+ });
584
+ });
585
+
586
+ describe("unshift action", () => {
587
+ it("should update $lastAction with unshift action when unshift is called", async () => {
588
+ const $array = array<FlowStateAsync<number>>([]);
589
+ const $newItem = stateAsync(Promise.resolve(42));
590
+ $array.unshift($newItem);
591
+ const action = await $array.$lastAction.pick();
592
+ expect(action.type).toBe("unshift");
593
+ if (action.type === "unshift") {
594
+ expect(action.addedItem).toBe($newItem);
595
+ }
596
+ });
597
+
598
+ it("should have correct structure for unshift action (addedItem)", async () => {
599
+ const $array = array<FlowStateAsync<number>>([]);
600
+ const $newItem = stateAsync(Promise.resolve(200));
601
+ $array.unshift($newItem);
602
+ const action = await $array.$lastAction.pick();
603
+ expect(action).toHaveProperty("type", "unshift");
604
+ if (action.type === "unshift") {
605
+ expect(action).toHaveProperty("addedItem");
606
+ expect(action.addedItem).toBe($newItem);
607
+ }
608
+ });
609
+ });
610
+
611
+ describe("shift action", () => {
612
+ it("should update $lastAction with shift action when shift is called", async () => {
613
+ const $array = array([
614
+ stateAsync(Promise.resolve(1)),
615
+ stateAsync(Promise.resolve(2)),
616
+ stateAsync(Promise.resolve(3)),
617
+ ]);
618
+ $array.shift();
619
+ const action = await $array.$lastAction.pick();
620
+ expect(action).toEqual({
621
+ type: "shift",
622
+ removedItem: expect.any(Object),
623
+ });
624
+ });
625
+
626
+ it("should have correct structure for shift action (removedItem)", async () => {
627
+ const $array = array([
628
+ stateAsync(Promise.resolve(1)),
629
+ stateAsync(Promise.resolve(2)),
630
+ stateAsync(Promise.resolve(3)),
631
+ ]);
632
+ $array.shift();
633
+ const action = await $array.$lastAction.pick();
634
+ expect(action).toHaveProperty("type", "shift");
635
+ if (action.type === "shift") {
636
+ expect(action).toHaveProperty("removedItem");
637
+ expect(action.removedItem).toBeInstanceOf(Object);
638
+ }
639
+ });
640
+
641
+ it("should have removedItem undefined when shift is called on empty array", async () => {
642
+ const $array = array<FlowStateAsync<number>>([]);
643
+ $array.shift();
644
+ const action = await $array.$lastAction.pick();
645
+ expect(action).toHaveProperty("type", "shift");
646
+ if (action.type === "shift") {
647
+ expect(action).toHaveProperty("removedItem");
648
+ expect(action.removedItem).toBeUndefined();
649
+ }
650
+ });
651
+ });
652
+
653
+ describe("splice action", () => {
654
+ it("should update $lastAction with splice action when splice is called", async () => {
655
+ const $array = array<FlowStateAsync<number>>([
656
+ stateAsync(Promise.resolve(0)),
657
+ stateAsync(Promise.resolve(1)),
658
+ stateAsync(Promise.resolve(2)),
659
+ stateAsync(Promise.resolve(3)),
660
+ stateAsync(Promise.resolve(4)),
661
+ ]);
662
+ const $newItem1 = stateAsync(Promise.resolve(10));
663
+ const $newItem2 = stateAsync(Promise.resolve(11));
664
+ $array.splice(1, 2, $newItem1, $newItem2);
665
+ const action = await $array.$lastAction.pick();
666
+ expect(action.type).toBe("splice");
667
+ if (action.type === "splice") {
668
+ expect(action.start).toBe(1);
669
+ expect(action.deleteCount).toBe(2);
670
+ expect(action.addedItems).toHaveLength(2);
671
+ expect(action.addedItems[0]).toBe($newItem1);
672
+ expect(action.addedItems[1]).toBe($newItem2);
673
+ expect(action.removedItems).toHaveLength(2);
674
+ }
675
+ });
676
+
677
+ it("should have correct structure for splice action (start, deleteCount, addedItems, removedItems)", async () => {
678
+ const $array = array<FlowStateAsync<number>>([
679
+ stateAsync(Promise.resolve(0)),
680
+ stateAsync(Promise.resolve(1)),
681
+ stateAsync(Promise.resolve(2)),
682
+ ]);
683
+ const $newItem = stateAsync(Promise.resolve(100));
684
+ $array.splice(1, 1, $newItem);
685
+ const action = await $array.$lastAction.pick();
686
+ expect(action).toHaveProperty("type", "splice");
687
+ if (action.type === "splice") {
688
+ expect(action).toHaveProperty("start");
689
+ expect(action).toHaveProperty("deleteCount");
690
+ expect(action).toHaveProperty("addedItems");
691
+ expect(action).toHaveProperty("removedItems");
692
+ expect(action.start).toBe(1);
693
+ expect(action.deleteCount).toBe(1);
694
+ expect(Array.isArray(action.addedItems)).toBe(true);
695
+ expect(Array.isArray(action.removedItems)).toBe(true);
696
+ expect(action.addedItems).toHaveLength(1);
697
+ expect(action.addedItems[0]).toBe($newItem);
698
+ expect(action.removedItems).toHaveLength(1);
699
+ }
700
+ });
701
+ });
702
+
703
+ describe("clear action", () => {
704
+ it("should update $lastAction with clear action when clear is called", async () => {
705
+ const $array = array<FlowStateAsync<number>>([
706
+ stateAsync(Promise.resolve(0)),
707
+ stateAsync(Promise.resolve(1)),
708
+ stateAsync(Promise.resolve(2)),
709
+ stateAsync(Promise.resolve(3)),
710
+ stateAsync(Promise.resolve(4)),
711
+ ]);
712
+ $array.clear();
713
+ const action = await $array.$lastAction.pick();
714
+ expect(action).toEqual({
715
+ type: "clear",
716
+ clearedItems: expect.any(Array),
717
+ });
718
+ if (action.type === "clear") {
719
+ expect(action.clearedItems).toHaveLength(5);
720
+ }
721
+ });
722
+
723
+ it("should have correct structure for clear action (clearedItems)", async () => {
724
+ const $array = array<FlowStateAsync<number>>([
725
+ stateAsync(Promise.resolve(1)),
726
+ stateAsync(Promise.resolve(2)),
727
+ stateAsync(Promise.resolve(3)),
728
+ ]);
729
+ $array.clear();
730
+ const action = await $array.$lastAction.pick();
731
+ expect(action).toHaveProperty("type", "clear");
732
+ if (action.type === "clear") {
733
+ expect(action).toHaveProperty("clearedItems");
734
+ expect(Array.isArray(action.clearedItems)).toBe(true);
735
+ expect(action.clearedItems).toHaveLength(3);
736
+ }
737
+ });
738
+ });
739
+ });
740
+
741
+ describe("edge cases", () => {
742
+ it("should handle multiple rapid operations", async () => {
743
+ const $array = array<FlowStateAsync<number>>([]);
744
+ $array.push(stateAsync(Promise.resolve(1)));
745
+ $array.push(stateAsync(Promise.resolve(2)));
746
+ $array.push(stateAsync(Promise.resolve(3)));
747
+ $array.pop();
748
+ $array.shift();
749
+ $array.unshift(stateAsync(Promise.resolve(0)));
750
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([0, 2]);
751
+ });
752
+
753
+ it("should handle boundary indices correctly", async () => {
754
+ const $array = array([
755
+ stateAsync(Promise.resolve(0)),
756
+ stateAsync(Promise.resolve(1)),
757
+ stateAsync(Promise.resolve(2)),
758
+ ]);
759
+ $array.update(0, stateAsync(Promise.resolve(10)));
760
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([10, 1, 2]);
761
+
762
+ $array.update(2, stateAsync(Promise.resolve(20)));
763
+ expect(await Promise.all((await $array.pick()).map((state) => state.pick()))).toEqual([10, 1, 20]);
764
+ });
765
+ });
766
+ });
767
+
768
+ describe("integration", () => {
769
+ describe("with effects", () => {
770
+ describe("reactivity", () => {
771
+ it("should call effect when initialized", async () => {
772
+ const $array = array([
773
+ stateAsync(Promise.resolve(1)),
774
+ stateAsync(Promise.resolve(2)),
775
+ stateAsync(Promise.resolve(3)),
776
+ ]);
777
+ const onData = vi.fn();
778
+ subscribe((t) => $array.get(t).map((state) => state.get(t)), onData);
779
+
780
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
781
+ expect(onData).toHaveBeenLastCalledWith([1, 2, 3]);
782
+ });
783
+
784
+ it("should call effect when updated with set", async () => {
785
+ const $array = array<FlowStateAsync<number>>([
786
+ stateAsync(Promise.resolve(0)),
787
+ stateAsync(Promise.resolve(1)),
788
+ stateAsync(Promise.resolve(2)),
789
+ ]);
790
+ const onData = vi.fn();
791
+ subscribe((t) => $array.get(t).map((state) => state.get(t)), onData);
792
+
793
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
794
+ expect(onData).toHaveBeenLastCalledWith([0, 1, 2]);
795
+
796
+ $array.set([
797
+ stateAsync(Promise.resolve(1)),
798
+ stateAsync(Promise.resolve(2)),
799
+ stateAsync(Promise.resolve(3)),
800
+ ]);
801
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
802
+ expect(onData).toHaveBeenLastCalledWith([1, 2, 3]);
803
+ });
804
+
805
+ it("should call effect when updated with push/pop", async () => {
806
+ const $array = array<FlowStateAsync<number>>();
807
+ const onData = vi.fn();
808
+ subscribe((t) => $array.get(t).map((state) => state.get(t)), onData);
809
+
810
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
811
+ expect(onData).toHaveBeenLastCalledWith([]);
812
+
813
+ $array.push(stateAsync(Promise.resolve(0)));
814
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
815
+ expect(onData).toHaveBeenLastCalledWith([0]);
816
+
817
+ $array.push(stateAsync(Promise.resolve(1)));
818
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(3));
819
+ expect(onData).toHaveBeenLastCalledWith([0, 1]);
820
+
821
+ $array.push(stateAsync(Promise.resolve(2)));
822
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(4));
823
+ expect(onData).toHaveBeenLastCalledWith([0, 1, 2]);
824
+
825
+ $array.pop();
826
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(5));
827
+ expect(onData).toHaveBeenLastCalledWith([0, 1]);
828
+
829
+ $array.pop();
830
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(6));
831
+ expect(onData).toHaveBeenLastCalledWith([0]);
832
+
833
+ $array.pop();
834
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(7));
835
+ expect(onData).toHaveBeenLastCalledWith([]);
836
+ });
837
+
838
+ it("should call effect when updated with unshift/shift", async () => {
839
+ const $array = array<FlowStateAsync<number>>();
840
+ const onData = vi.fn();
841
+ subscribe((t) => $array.get(t).map((state) => state.get(t)), onData);
842
+
843
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
844
+ expect(onData).toHaveBeenLastCalledWith([]);
845
+
846
+ $array.unshift(stateAsync(Promise.resolve(0)));
847
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
848
+ expect(onData).toHaveBeenLastCalledWith([0]);
849
+
850
+ $array.unshift(stateAsync(Promise.resolve(1)));
851
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(3));
852
+ expect(onData).toHaveBeenLastCalledWith([1, 0]);
853
+
854
+ $array.unshift(stateAsync(Promise.resolve(2)));
855
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(4));
856
+ expect(onData).toHaveBeenLastCalledWith([2, 1, 0]);
857
+
858
+ $array.shift();
859
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(5));
860
+ expect(onData).toHaveBeenLastCalledWith([1, 0]);
861
+
862
+ $array.shift();
863
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(6));
864
+ expect(onData).toHaveBeenLastCalledWith([0]);
865
+
866
+ $array.shift();
867
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(7));
868
+ expect(onData).toHaveBeenLastCalledWith([]);
869
+ });
870
+
871
+ it("should call effect when updated with splice", async () => {
872
+ const $array = array<FlowStateAsync<number>>([
873
+ stateAsync(Promise.resolve(0)),
874
+ stateAsync(Promise.resolve(1)),
875
+ stateAsync(Promise.resolve(2)),
876
+ stateAsync(Promise.resolve(3)),
877
+ stateAsync(Promise.resolve(4)),
878
+ ]);
879
+ const onData = vi.fn();
880
+ subscribe((t) => $array.get(t).map((state) => state.get(t)), onData);
881
+
882
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
883
+ expect(onData).toHaveBeenLastCalledWith([0, 1, 2, 3, 4]);
884
+
885
+ $array.splice(1, 2);
886
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
887
+ expect(onData).toHaveBeenLastCalledWith([0, 3, 4]);
888
+
889
+ $array.splice(1, 0, stateAsync(Promise.resolve(1)), stateAsync(Promise.resolve(2)));
890
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(3));
891
+ expect(onData).toHaveBeenLastCalledWith([0, 1, 2, 3, 4]);
892
+ });
893
+
894
+ it("should call effect when updated with clear", async () => {
895
+ const $array = array<FlowStateAsync<number>>([
896
+ stateAsync(Promise.resolve(0)),
897
+ stateAsync(Promise.resolve(1)),
898
+ stateAsync(Promise.resolve(2)),
899
+ stateAsync(Promise.resolve(3)),
900
+ stateAsync(Promise.resolve(4)),
901
+ ]);
902
+ const onData = vi.fn();
903
+ subscribe((t) => $array.get(t).map((state) => state.get(t)), onData);
904
+
905
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
906
+ expect(onData).toHaveBeenLastCalledWith([0, 1, 2, 3, 4]);
907
+
908
+ $array.clear();
909
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
910
+ expect(onData).toHaveBeenLastCalledWith([]);
911
+ });
912
+ });
913
+
914
+ describe("item reactivity", () => {
915
+ it("should call effect when item is updated", async () => {
916
+ const $array = array<FlowStateAsync<number>>([
917
+ stateAsync(Promise.resolve(0)),
918
+ stateAsync(Promise.resolve(1)),
919
+ stateAsync(Promise.resolve(2)),
920
+ ]);
921
+ const onData = vi.fn();
922
+ const onData0 = vi.fn();
923
+ const onData1 = vi.fn();
924
+ const onData2 = vi.fn();
925
+
926
+ subscribe((t) => $array.get(t).map((state) => state.get(t)), onData);
927
+ subscribe((t) => $array.get(t)[0].get(t), onData0);
928
+ subscribe((t) => $array.get(t)[1].get(t), onData1);
929
+ subscribe((t) => $array.get(t)[2].get(t), onData2);
930
+
931
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
932
+ expect(onData).toHaveBeenLastCalledWith([0, 1, 2]);
933
+ await vi.waitFor(() => expect(onData0).toHaveBeenCalledTimes(1));
934
+ expect(onData0).toHaveBeenLastCalledWith(0);
935
+ await vi.waitFor(() => expect(onData1).toHaveBeenCalledTimes(1));
936
+ expect(onData1).toHaveBeenLastCalledWith(1);
937
+ await vi.waitFor(() => expect(onData2).toHaveBeenCalledTimes(1));
938
+ expect(onData2).toHaveBeenLastCalledWith(2);
939
+
940
+ (await $array.pick())[0].set(Promise.resolve(1));
941
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(3));
942
+ expect(onData).toHaveBeenLastCalledWith([1, 1, 2]);
943
+ await vi.waitFor(() => expect(onData0).toHaveBeenCalledTimes(3));
944
+ expect(onData0).toHaveBeenLastCalledWith(1);
945
+ await vi.waitFor(() => expect(onData1).toHaveBeenCalledTimes(1));
946
+ expect(onData1).toHaveBeenLastCalledWith(1);
947
+ await vi.waitFor(() => expect(onData2).toHaveBeenCalledTimes(1));
948
+ expect(onData2).toHaveBeenLastCalledWith(2);
949
+
950
+ (await $array.pick())[1].set(Promise.resolve(2));
951
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(5));
952
+ expect(onData).toHaveBeenLastCalledWith([1, 2, 2]);
953
+ await vi.waitFor(() => expect(onData0).toHaveBeenCalledTimes(3));
954
+ expect(onData0).toHaveBeenLastCalledWith(1);
955
+ await vi.waitFor(() => expect(onData1).toHaveBeenCalledTimes(3));
956
+ expect(onData1).toHaveBeenLastCalledWith(2);
957
+ await vi.waitFor(() => expect(onData2).toHaveBeenCalledTimes(1));
958
+ expect(onData2).toHaveBeenLastCalledWith(2);
959
+
960
+ (await $array.pick())[2].set(Promise.resolve(3));
961
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(7));
962
+ expect(onData).toHaveBeenLastCalledWith([1, 2, 3]);
963
+ await vi.waitFor(() => expect(onData0).toHaveBeenCalledTimes(3));
964
+ expect(onData0).toHaveBeenLastCalledWith(1);
965
+ await vi.waitFor(() => expect(onData1).toHaveBeenCalledTimes(3));
966
+ expect(onData1).toHaveBeenLastCalledWith(2);
967
+ await vi.waitFor(() => expect(onData2).toHaveBeenCalledTimes(3));
968
+ expect(onData2).toHaveBeenLastCalledWith(3);
969
+ });
970
+
971
+ it("should call effect when item is replaced", async () => {
972
+ const $array = array<FlowStateAsync<number>>([
973
+ stateAsync(Promise.resolve(0)),
974
+ stateAsync(Promise.resolve(1)),
975
+ stateAsync(Promise.resolve(2)),
976
+ ]);
977
+ const onData = vi.fn();
978
+ const onData0 = vi.fn();
979
+
980
+ subscribe((t) => $array.get(t).map((state) => state.get(t)), onData);
981
+ subscribe((t) => $array.get(t)[0].get(t), onData0);
982
+
983
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
984
+ expect(onData).toHaveBeenLastCalledWith([0, 1, 2]);
985
+ await vi.waitFor(() => expect(onData0).toHaveBeenCalledTimes(1));
986
+ expect(onData0).toHaveBeenLastCalledWith(0);
987
+
988
+ $array.update(0, stateAsync(Promise.resolve(3)));
989
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
990
+ expect(onData).toHaveBeenLastCalledWith([3, 1, 2]);
991
+ await vi.waitFor(() => expect(onData0).toHaveBeenCalledTimes(2));
992
+ expect(onData0).toHaveBeenLastCalledWith(3);
993
+
994
+ $array.shift();
995
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(3));
996
+ expect(onData).toHaveBeenLastCalledWith([1, 2]);
997
+ await vi.waitFor(() => expect(onData0).toHaveBeenCalledTimes(3));
998
+ expect(onData0).toHaveBeenLastCalledWith(1);
999
+
1000
+ $array.unshift(stateAsync(Promise.resolve(4)));
1001
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(4));
1002
+ expect(onData).toHaveBeenLastCalledWith([4, 1, 2]);
1003
+ await vi.waitFor(() => expect(onData0).toHaveBeenCalledTimes(4));
1004
+ expect(onData0).toHaveBeenLastCalledWith(4);
1005
+ });
1006
+ });
1007
+
1008
+ describe("lastAction reactivity", () => {
1009
+ describe("set action", () => {
1010
+ it("should call effect when $lastAction is updated with set action", async () => {
1011
+ const $array = array([
1012
+ stateAsync(Promise.resolve(0)),
1013
+ stateAsync(Promise.resolve(1)),
1014
+ stateAsync(Promise.resolve(2)),
1015
+ ]);
1016
+ const onData = vi.fn();
1017
+ subscribe((t) => $array.$lastAction.get(t), onData);
1018
+
1019
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
1020
+ expect(onData).toHaveBeenLastCalledWith(
1021
+ expect.objectContaining({
1022
+ type: "set",
1023
+ setItems: expect.any(Array),
1024
+ clearedItems: expect.any(Array),
1025
+ }),
1026
+ );
1027
+
1028
+ $array.set([
1029
+ stateAsync(Promise.resolve(1)),
1030
+ stateAsync(Promise.resolve(2)),
1031
+ stateAsync(Promise.resolve(3)),
1032
+ ]);
1033
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
1034
+ expect(onData).toHaveBeenLastCalledWith(
1035
+ expect.objectContaining({
1036
+ type: "set",
1037
+ setItems: expect.any(Array),
1038
+ clearedItems: expect.any(Array),
1039
+ }),
1040
+ );
1041
+ });
1042
+ });
1043
+
1044
+ describe("update action", () => {
1045
+ it("should call effect when $lastAction is updated with update action", async () => {
1046
+ const $array = array([
1047
+ stateAsync(Promise.resolve(0)),
1048
+ stateAsync(Promise.resolve(1)),
1049
+ stateAsync(Promise.resolve(2)),
1050
+ ]);
1051
+ const onData = vi.fn();
1052
+ subscribe((t) => $array.$lastAction.get(t), onData);
1053
+
1054
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
1055
+
1056
+ const $newItem = stateAsync(Promise.resolve(10));
1057
+ $array.update(1, $newItem);
1058
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
1059
+ expect(onData).toHaveBeenLastCalledWith(
1060
+ expect.objectContaining({
1061
+ type: "update",
1062
+ index: 1,
1063
+ setItem: $newItem,
1064
+ clearedItem: expect.any(Object),
1065
+ }),
1066
+ );
1067
+ });
1068
+ });
1069
+
1070
+ describe("push action", () => {
1071
+ it("should call effect when $lastAction is updated with push action", async () => {
1072
+ const $array = array<FlowStateAsync<number>>();
1073
+ const onData = vi.fn();
1074
+ subscribe((t) => $array.$lastAction.get(t), onData);
1075
+
1076
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
1077
+ expect(onData).toHaveBeenLastCalledWith(
1078
+ expect.objectContaining({
1079
+ type: "set",
1080
+ setItems: expect.any(Array),
1081
+ clearedItems: expect.any(Array),
1082
+ }),
1083
+ );
1084
+
1085
+ const $newItem = stateAsync(Promise.resolve(0));
1086
+ $array.push($newItem);
1087
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
1088
+ expect(onData).toHaveBeenLastCalledWith(
1089
+ expect.objectContaining({
1090
+ type: "push",
1091
+ addedItem: $newItem,
1092
+ }),
1093
+ );
1094
+
1095
+ const $newItem2 = stateAsync(Promise.resolve(1));
1096
+ $array.push($newItem2);
1097
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(3));
1098
+ expect(onData).toHaveBeenLastCalledWith(
1099
+ expect.objectContaining({
1100
+ type: "push",
1101
+ addedItem: $newItem2,
1102
+ }),
1103
+ );
1104
+ });
1105
+ });
1106
+
1107
+ describe("pop action", () => {
1108
+ it("should call effect when $lastAction is updated with pop action", async () => {
1109
+ const $array = array<FlowStateAsync<number>>([
1110
+ stateAsync(Promise.resolve(0)),
1111
+ stateAsync(Promise.resolve(1)),
1112
+ stateAsync(Promise.resolve(2)),
1113
+ ]);
1114
+ const onData = vi.fn();
1115
+ subscribe((t) => $array.$lastAction.get(t), onData);
1116
+
1117
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
1118
+
1119
+ $array.pop();
1120
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
1121
+ expect(onData).toHaveBeenLastCalledWith(
1122
+ expect.objectContaining({
1123
+ type: "pop",
1124
+ removedItem: expect.any(Object),
1125
+ }),
1126
+ );
1127
+
1128
+ $array.pop();
1129
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(3));
1130
+ expect(onData).toHaveBeenLastCalledWith(
1131
+ expect.objectContaining({
1132
+ type: "pop",
1133
+ removedItem: expect.any(Object),
1134
+ }),
1135
+ );
1136
+ });
1137
+ });
1138
+
1139
+ describe("unshift action", () => {
1140
+ it("should call effect when $lastAction is updated with unshift action", async () => {
1141
+ const $array = array<FlowStateAsync<number>>();
1142
+ const onData = vi.fn();
1143
+ subscribe((t) => $array.$lastAction.get(t), onData);
1144
+
1145
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
1146
+ expect(onData).toHaveBeenLastCalledWith(
1147
+ expect.objectContaining({
1148
+ type: "set",
1149
+ setItems: expect.any(Array),
1150
+ clearedItems: expect.any(Array),
1151
+ }),
1152
+ );
1153
+
1154
+ const $newItem = stateAsync(Promise.resolve(0));
1155
+ $array.unshift($newItem);
1156
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
1157
+ expect(onData).toHaveBeenLastCalledWith(
1158
+ expect.objectContaining({
1159
+ type: "unshift",
1160
+ addedItem: $newItem,
1161
+ }),
1162
+ );
1163
+
1164
+ const $newItem2 = stateAsync(Promise.resolve(1));
1165
+ $array.unshift($newItem2);
1166
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(3));
1167
+ expect(onData).toHaveBeenLastCalledWith(
1168
+ expect.objectContaining({
1169
+ type: "unshift",
1170
+ addedItem: $newItem2,
1171
+ }),
1172
+ );
1173
+ });
1174
+ });
1175
+
1176
+ describe("shift action", () => {
1177
+ it("should call effect when $lastAction is updated with shift action", async () => {
1178
+ const $array = array<FlowStateAsync<number>>([
1179
+ stateAsync(Promise.resolve(0)),
1180
+ stateAsync(Promise.resolve(1)),
1181
+ stateAsync(Promise.resolve(2)),
1182
+ ]);
1183
+ const onData = vi.fn();
1184
+ subscribe((t) => $array.$lastAction.get(t), onData);
1185
+
1186
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
1187
+
1188
+ $array.shift();
1189
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
1190
+ expect(onData).toHaveBeenLastCalledWith(
1191
+ expect.objectContaining({
1192
+ type: "shift",
1193
+ removedItem: expect.any(Object),
1194
+ }),
1195
+ );
1196
+
1197
+ $array.shift();
1198
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(3));
1199
+ expect(onData).toHaveBeenLastCalledWith(
1200
+ expect.objectContaining({
1201
+ type: "shift",
1202
+ removedItem: expect.any(Object),
1203
+ }),
1204
+ );
1205
+ });
1206
+ });
1207
+
1208
+ describe("splice action", () => {
1209
+ it("should call effect when $lastAction is updated with splice action", async () => {
1210
+ const $array = array<FlowStateAsync<number>>([
1211
+ stateAsync(Promise.resolve(0)),
1212
+ stateAsync(Promise.resolve(1)),
1213
+ stateAsync(Promise.resolve(2)),
1214
+ stateAsync(Promise.resolve(3)),
1215
+ stateAsync(Promise.resolve(4)),
1216
+ ]);
1217
+ const onData = vi.fn();
1218
+ subscribe((t) => $array.$lastAction.get(t), onData);
1219
+
1220
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
1221
+ expect(onData).toHaveBeenLastCalledWith(
1222
+ expect.objectContaining({
1223
+ type: "set",
1224
+ setItems: expect.any(Array),
1225
+ clearedItems: expect.any(Array),
1226
+ }),
1227
+ );
1228
+
1229
+ $array.splice(1, 2);
1230
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
1231
+ expect(onData).toHaveBeenLastCalledWith(
1232
+ expect.objectContaining({
1233
+ type: "splice",
1234
+ start: 1,
1235
+ deleteCount: 2,
1236
+ addedItems: expect.any(Array),
1237
+ removedItems: expect.any(Array),
1238
+ }),
1239
+ );
1240
+
1241
+ $array.splice(1, 0, stateAsync(Promise.resolve(1)), stateAsync(Promise.resolve(2)));
1242
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(3));
1243
+ expect(onData).toHaveBeenLastCalledWith(
1244
+ expect.objectContaining({
1245
+ type: "splice",
1246
+ start: 1,
1247
+ deleteCount: 0,
1248
+ addedItems: expect.any(Array),
1249
+ removedItems: expect.any(Array),
1250
+ }),
1251
+ );
1252
+ });
1253
+ });
1254
+
1255
+ describe("clear action", () => {
1256
+ it("should call effect when $lastAction is updated with clear action", async () => {
1257
+ const $array = array<FlowStateAsync<number>>([
1258
+ stateAsync(Promise.resolve(0)),
1259
+ stateAsync(Promise.resolve(1)),
1260
+ stateAsync(Promise.resolve(2)),
1261
+ stateAsync(Promise.resolve(3)),
1262
+ stateAsync(Promise.resolve(4)),
1263
+ ]);
1264
+ const onData = vi.fn();
1265
+ subscribe((t) => $array.$lastAction.get(t), onData);
1266
+
1267
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(1));
1268
+ expect(onData).toHaveBeenLastCalledWith(
1269
+ expect.objectContaining({
1270
+ type: "set",
1271
+ setItems: expect.any(Array),
1272
+ clearedItems: expect.any(Array),
1273
+ }),
1274
+ );
1275
+
1276
+ $array.clear();
1277
+ await vi.waitFor(() => expect(onData).toHaveBeenCalledTimes(2));
1278
+ expect(onData).toHaveBeenLastCalledWith(
1279
+ expect.objectContaining({
1280
+ type: "clear",
1281
+ clearedItems: expect.any(Array),
1282
+ }),
1283
+ );
1284
+ });
1285
+ });
1286
+ });
1287
+ });
1288
+ });
1289
+ });