@ersbeth/picoflow 2.0.2 → 2.0.3

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 (152) hide show
  1. package/README.md +10 -0
  2. package/SKILL.md +106 -0
  3. package/package.json +5 -1
  4. package/.gitlab-ci.yml +0 -24
  5. package/.vscode/settings.json +0 -5
  6. package/CHANGELOG.md +0 -94
  7. package/biome.json +0 -47
  8. package/docs/.vitepress/config.mts +0 -145
  9. package/docs/api/functions/array.md +0 -35
  10. package/docs/api/functions/constant.md +0 -33
  11. package/docs/api/functions/constantAsync.md +0 -69
  12. package/docs/api/functions/derivation.md +0 -34
  13. package/docs/api/functions/derivationAsync.md +0 -34
  14. package/docs/api/functions/from.md +0 -129
  15. package/docs/api/functions/isDisposable.md +0 -27
  16. package/docs/api/functions/map.md +0 -36
  17. package/docs/api/functions/signal.md +0 -21
  18. package/docs/api/functions/state.md +0 -67
  19. package/docs/api/functions/stateAsync.md +0 -69
  20. package/docs/api/functions/subscribe.md +0 -40
  21. package/docs/api/functions/writableDerivation.md +0 -33
  22. package/docs/api/functions/writableDerivationAsync.md +0 -34
  23. package/docs/api/index.md +0 -61
  24. package/docs/api/interfaces/FlowArray.md +0 -439
  25. package/docs/api/interfaces/FlowConstant.md +0 -220
  26. package/docs/api/interfaces/FlowConstantAsync.md +0 -221
  27. package/docs/api/interfaces/FlowDerivation.md +0 -241
  28. package/docs/api/interfaces/FlowDerivationAsync.md +0 -242
  29. package/docs/api/interfaces/FlowDisposable.md +0 -59
  30. package/docs/api/interfaces/FlowEffect.md +0 -64
  31. package/docs/api/interfaces/FlowMap.md +0 -374
  32. package/docs/api/interfaces/FlowObservable.md +0 -155
  33. package/docs/api/interfaces/FlowSignal.md +0 -156
  34. package/docs/api/interfaces/FlowState.md +0 -269
  35. package/docs/api/interfaces/FlowStateAsync.md +0 -268
  36. package/docs/api/interfaces/FlowSubscribable.md +0 -55
  37. package/docs/api/interfaces/FlowTracker.md +0 -61
  38. package/docs/api/interfaces/FlowValue.md +0 -222
  39. package/docs/api/interfaces/FlowWritableDerivation.md +0 -292
  40. package/docs/api/interfaces/FlowWritableDerivationAsync.md +0 -293
  41. package/docs/api/type-aliases/DerivationFunction.md +0 -28
  42. package/docs/api/type-aliases/DerivationFunctionAsync.md +0 -28
  43. package/docs/api/type-aliases/FlowArrayAction.md +0 -60
  44. package/docs/api/type-aliases/FlowDataTracker.md +0 -33
  45. package/docs/api/type-aliases/FlowMapAction.md +0 -48
  46. package/docs/api/type-aliases/FlowOnDataListener.md +0 -33
  47. package/docs/api/type-aliases/FlowOnErrorListener.md +0 -27
  48. package/docs/api/type-aliases/FlowOnPendingListener.md +0 -21
  49. package/docs/api/type-aliases/FlowReadonly.md +0 -22
  50. package/docs/api/type-aliases/InitFunction.md +0 -21
  51. package/docs/api/type-aliases/InitFunctionAsync.md +0 -21
  52. package/docs/api/type-aliases/NotPromise.md +0 -21
  53. package/docs/api/type-aliases/UpdateFunction.md +0 -27
  54. package/docs/api/type-aliases/UpdateFunctionAsync.md +0 -27
  55. package/docs/api/typedoc-sidebar.json +0 -65
  56. package/docs/examples/examples.md +0 -2311
  57. package/docs/examples/patterns.md +0 -649
  58. package/docs/guide/advanced/architecture.md +0 -1234
  59. package/docs/guide/advanced/disposal.md +0 -426
  60. package/docs/guide/advanced/migration-v1.md +0 -464
  61. package/docs/guide/advanced/migration-v2.md +0 -204
  62. package/docs/guide/advanced/solidjs.md +0 -135
  63. package/docs/guide/introduction/concepts.md +0 -57
  64. package/docs/guide/introduction/conventions.md +0 -30
  65. package/docs/guide/introduction/getting-started.md +0 -139
  66. package/docs/guide/introduction/lifecycle.md +0 -368
  67. package/docs/guide/primitives/array.md +0 -286
  68. package/docs/guide/primitives/constant.md +0 -207
  69. package/docs/guide/primitives/derivations.md +0 -281
  70. package/docs/guide/primitives/effects.md +0 -372
  71. package/docs/guide/primitives/map.md +0 -265
  72. package/docs/guide/primitives/overview.md +0 -92
  73. package/docs/guide/primitives/signal.md +0 -222
  74. package/docs/guide/primitives/state.md +0 -272
  75. package/docs/index.md +0 -47
  76. package/docs/public/logo.svg +0 -1
  77. package/src/api/base/flowDisposable.ts +0 -44
  78. package/src/api/base/flowObservable.ts +0 -28
  79. package/src/api/base/flowSubscribable.ts +0 -87
  80. package/src/api/base/flowTracker.ts +0 -7
  81. package/src/api/base/index.ts +0 -4
  82. package/src/api/index.ts +0 -2
  83. package/src/api/nodes/async/flowConstantAsync.ts +0 -36
  84. package/src/api/nodes/async/flowDerivationAsync.ts +0 -42
  85. package/src/api/nodes/async/flowStateAsync.ts +0 -47
  86. package/src/api/nodes/async/flowWritableDerivationAsync.ts +0 -33
  87. package/src/api/nodes/async/index.ts +0 -4
  88. package/src/api/nodes/collections/flowArray.ts +0 -155
  89. package/src/api/nodes/collections/flowMap.ts +0 -115
  90. package/src/api/nodes/collections/index.ts +0 -2
  91. package/src/api/nodes/flowEffect.ts +0 -42
  92. package/src/api/nodes/flowSignal.ts +0 -28
  93. package/src/api/nodes/flowValue.ts +0 -37
  94. package/src/api/nodes/index.ts +0 -7
  95. package/src/api/nodes/sync/flowConstant.ts +0 -33
  96. package/src/api/nodes/sync/flowDerivation.ts +0 -41
  97. package/src/api/nodes/sync/flowState.ts +0 -45
  98. package/src/api/nodes/sync/flowWritableDerivation.ts +0 -31
  99. package/src/api/nodes/sync/index.ts +0 -4
  100. package/src/api/nodes/utils.ts +0 -24
  101. package/src/base/disposable.ts +0 -18
  102. package/src/base/executionStack.ts +0 -42
  103. package/src/base/index.ts +0 -5
  104. package/src/base/node.ts +0 -98
  105. package/src/base/observable.ts +0 -92
  106. package/src/base/observer.ts +0 -51
  107. package/src/converters/index.ts +0 -1
  108. package/src/converters/solid.ts +0 -109
  109. package/src/index.ts +0 -2
  110. package/src/nodes/arrayNode.ts +0 -180
  111. package/src/nodes/effectNode.ts +0 -58
  112. package/src/nodes/index.ts +0 -7
  113. package/src/nodes/mapNode.ts +0 -125
  114. package/src/nodes/signalNode.ts +0 -19
  115. package/src/nodes/valueAsyncNode.ts +0 -85
  116. package/src/nodes/valueNode.ts +0 -148
  117. package/src/nodes/valueSyncNode.ts +0 -125
  118. package/src/schedulers/asyncResolver.ts +0 -78
  119. package/src/schedulers/asyncScheduler.ts +0 -66
  120. package/src/schedulers/index.ts +0 -4
  121. package/src/schedulers/pendingError.ts +0 -13
  122. package/src/schedulers/scheduler.ts +0 -9
  123. package/src/schedulers/syncResolver.ts +0 -69
  124. package/src/schedulers/syncScheduler.ts +0 -55
  125. package/test/base/pendingError.test.ts +0 -67
  126. package/test/converters/solid.derivation.browser.test.tsx +0 -69
  127. package/test/converters/solid.node.test.ts +0 -654
  128. package/test/converters/solid.state.browser.test.tsx +0 -1592
  129. package/test/reactivity/flowSignal.test.ts +0 -226
  130. package/test/reactivity/nodes/async/asyncScheduler/asyncResolver.test.ts +0 -593
  131. package/test/reactivity/nodes/async/asyncScheduler/asyncScheduler.test.ts +0 -317
  132. package/test/reactivity/nodes/async/flowConstantAsync.test.ts +0 -652
  133. package/test/reactivity/nodes/async/flowDerivation.test.ts +0 -898
  134. package/test/reactivity/nodes/async/flowDerivationAsync.test.ts +0 -1716
  135. package/test/reactivity/nodes/async/flowStateAsync.test.ts +0 -708
  136. package/test/reactivity/nodes/async/flowWritableDerivationAsync.test.ts +0 -614
  137. package/test/reactivity/nodes/collections/flowArray.asyncStates.test.ts +0 -1289
  138. package/test/reactivity/nodes/collections/flowArray.scalars.test.ts +0 -961
  139. package/test/reactivity/nodes/collections/flowArray.states.test.ts +0 -1035
  140. package/test/reactivity/nodes/collections/flowMap.asyncStates.test.ts +0 -960
  141. package/test/reactivity/nodes/collections/flowMap.scalars.test.ts +0 -775
  142. package/test/reactivity/nodes/collections/flowMap.states.test.ts +0 -958
  143. package/test/reactivity/nodes/sync/flowConstant.test.ts +0 -377
  144. package/test/reactivity/nodes/sync/flowDerivation.test.ts +0 -896
  145. package/test/reactivity/nodes/sync/flowState.test.ts +0 -341
  146. package/test/reactivity/nodes/sync/flowWritableDerivation.test.ts +0 -603
  147. package/test/vitest.d.ts +0 -10
  148. package/tsconfig.json +0 -37
  149. package/typedoc.json +0 -37
  150. package/vite.config.ts +0 -31
  151. package/vitest.browser.config.ts +0 -21
  152. package/vitest.config.ts +0 -17
@@ -1,426 +0,0 @@
1
- # Disposal
2
-
3
- Memory management is crucial in long-running applications. PicoFlow provides explicit disposal mechanisms to prevent memory leaks and ensure resources are properly cleaned up.
4
-
5
- ## Why Disposal Matters
6
-
7
- All PicoFlow primitives are disposable. When you're done with them, you should clean them up:
8
-
9
- ```typescript
10
- const $count = state(0)
11
- const fx = effect((t) => {
12
- console.log($count.get(t))
13
- })
14
-
15
- // Later... clean up
16
- fx.dispose() // Effect stops running
17
- $count.dispose() // State is cleaned up
18
- ```
19
-
20
- **Why disposal matters:**
21
- - **Prevents memory leaks** - Unreferenced but undisposed primitives stay in memory
22
- - **Stops effects from running** - Effects continue executing until explicitly disposed
23
- - **Cleans up resources** - WebSocket connections, intervals, event listeners, etc.
24
- - **Important in long-running applications** - SPAs, dashboards, real-time apps
25
-
26
- ```mermaid
27
- flowchart LR
28
- A[Create primitive] --> B[Use in effects]
29
- B --> C[No longer needed]
30
- C --> D{Disposed?}
31
- D -->|Yes| E[Memory freed]
32
- D -->|No| F[Memory leak!]
33
-
34
- style E fill:#90EE90
35
- style F fill:#FFB6C6
36
- ```
37
-
38
- ## When to Dispose
39
-
40
- ### Component Cleanup
41
-
42
- In component-based architectures, dispose primitives when components unmount:
43
-
44
- ```typescript
45
- class TodoList {
46
- private $todos = state<Todo[]>([])
47
- private disposables: FlowDisposable[] = []
48
-
49
- constructor() {
50
- // Track all disposables
51
- this.disposables.push(
52
- effect((t) => {
53
- this.render($todos.get(t))
54
- })
55
- )
56
- }
57
-
58
- destroy() {
59
- // Clean up when component is destroyed
60
- this.disposables.forEach(d => d.dispose())
61
- this.$todos.dispose()
62
- }
63
- }
64
- ```
65
-
66
- ### Conditional Effects
67
-
68
- Dispose and recreate effects based on application state:
69
-
70
- ```typescript
71
- let currentEffect: FlowEffect | null = null
72
-
73
- function enableLogging(enable: boolean) {
74
- // Dispose previous effect
75
- currentEffect?.dispose()
76
-
77
- if (enable) {
78
- currentEffect = effect((t) => {
79
- console.log('Value:', $data.get(t))
80
- })
81
- }
82
- }
83
-
84
- // Toggle logging on/off
85
- enableLogging(true) // Effect starts
86
- enableLogging(false) // Effect disposed
87
- ```
88
-
89
- ### Resource Management
90
-
91
- Dispose primitives that manage external resources:
92
-
93
- ```typescript
94
- const $wsData = stream<string>((set) => {
95
- const ws = new WebSocket('ws://example.com')
96
- ws.onmessage = (e) => set(e.data)
97
-
98
- // Cleanup function called on disposal
99
- return () => ws.close()
100
- })
101
-
102
- // Use the stream
103
- effect((t) => {
104
- console.log('Message:', $wsData.get(t))
105
- })
106
-
107
- // Later... close the connection
108
- $wsData.dispose()
109
- ```
110
-
111
- ### Interval Cleanup
112
-
113
- ```typescript
114
- const $tick = stream<number>((set) => {
115
- let count = 0
116
- const interval = setInterval(() => {
117
- set(count++)
118
- }, 1000)
119
-
120
- // Cleanup: clear interval on disposal
121
- return () => clearInterval(interval)
122
- })
123
-
124
- // Later...
125
- $tick.dispose() // Interval cleared
126
- ```
127
-
128
- ## Automatic Cleanup
129
-
130
- Effects automatically clean up their dependencies when disposed:
131
-
132
- ```typescript
133
- const $a = state(1)
134
- const $b = state(2)
135
-
136
- const fx = effect((t) => {
137
- console.log($a.get(t) + $b.get(t))
138
- })
139
-
140
- fx.dispose()
141
-
142
- // These no longer trigger the effect
143
- $a.set(10) // No console log
144
- $b.set(20) // No console log
145
- ```
146
-
147
- When an effect is disposed:
148
- 1. It unregisters from all its dependencies
149
- 2. Future changes to those dependencies won't trigger it
150
- 3. The effect's memory is freed
151
-
152
- ## Best Practices
153
-
154
- ### 1. Always Dispose in Cleanup Hooks
155
-
156
- In any framework with lifecycle hooks, dispose in the cleanup phase:
157
-
158
- ```typescript
159
- // React
160
- useEffect(() => {
161
- const fx = effect((t) => {
162
- // ... effect code
163
- })
164
-
165
- return () => fx.dispose() // Cleanup
166
- }, [])
167
-
168
- // Vue
169
- onUnmounted(() => {
170
- fx.dispose()
171
- })
172
-
173
- // Svelte
174
- onDestroy(() => {
175
- fx.dispose()
176
- })
177
- ```
178
-
179
- ### 2. Group Related Disposables
180
-
181
- Use collections to manage multiple disposables:
182
-
183
- ```typescript
184
- class DataManager {
185
- private disposables = new Set<FlowDisposable>()
186
-
187
- track(disposable: FlowDisposable) {
188
- this.disposables.add(disposable)
189
- }
190
-
191
- cleanup() {
192
- this.disposables.forEach(d => d.dispose())
193
- this.disposables.clear()
194
- }
195
- }
196
-
197
- // Usage
198
- const manager = new DataManager()
199
- manager.track(effect((t) => { /* ... */ }))
200
- manager.track(effect((t) => { /* ... */ }))
201
- manager.track($someState)
202
-
203
- // Clean up everything
204
- manager.cleanup()
205
- ```
206
-
207
- ### 3. Dispose in Reverse Order of Creation
208
-
209
- Dispose dependents before dependencies:
210
-
211
- ```typescript
212
- const $data = state(0)
213
- const $derived = derivation((t) => $data.get(t) * 2)
214
- const fx = effect((t) => console.log($derived.get(t)))
215
-
216
- // Cleanup: dispose in reverse order
217
- fx.dispose() // Effect first (depends on $derived)
218
- $derived.dispose() // Derivation second (depends on $data)
219
- $data.dispose() // State last (no dependencies)
220
- ```
221
-
222
- **Why?** Disposing in reverse order prevents:
223
- - Accessing disposed dependencies
224
- - Unnecessary recomputations during cleanup
225
- - Race conditions during shutdown
226
-
227
- ### 4. Check Disposal State
228
-
229
- Use the `disposed` property to check if a primitive has been disposed:
230
-
231
- ```typescript
232
- const fx = effect((t) => {
233
- console.log($count.get(t))
234
- })
235
-
236
- console.log(fx.disposed) // false
237
-
238
- fx.dispose()
239
-
240
- console.log(fx.disposed) // true
241
- ```
242
-
243
- ### 5. Handle Disposal Errors
244
-
245
- Wrap disposal in try-catch for robust cleanup:
246
-
247
- ```typescript
248
- function cleanupResources(disposables: FlowDisposable[]) {
249
- const errors: Error[] = []
250
-
251
- for (const disposable of disposables) {
252
- try {
253
- disposable.dispose()
254
- } catch (error) {
255
- errors.push(error as Error)
256
- }
257
- }
258
-
259
- if (errors.length > 0) {
260
- console.error('Disposal errors:', errors)
261
- }
262
- }
263
- ```
264
-
265
- ## Common Pitfalls
266
-
267
- ### Pitfall 1: Not Disposing Effects
268
-
269
- ```typescript
270
- // ❌ Memory leak - effect never disposed
271
- function updateCounter() {
272
- effect((t) => {
273
- document.getElementById('count').textContent = $count.get(t)
274
- })
275
- }
276
-
277
- // Called 100 times = 100 effects running!
278
- for (let i = 0; i < 100; i++) {
279
- updateCounter()
280
- }
281
-
282
- // ✅ Proper cleanup
283
- function updateCounter(): () => void {
284
- const fx = effect((t) => {
285
- document.getElementById('count').textContent = $count.get(t)
286
- })
287
-
288
- return () => fx.dispose()
289
- }
290
-
291
- const cleanup = updateCounter()
292
- // Later...
293
- cleanup()
294
- ```
295
-
296
- ### Pitfall 2: Disposing Too Early
297
-
298
- ```typescript
299
- // ❌ Disposed too early
300
- const fx = effect((t) => {
301
- console.log($count.get(t))
302
- })
303
-
304
- fx.dispose() // Effect disposed immediately!
305
-
306
- $count.set(1) // No effect runs
307
-
308
- // ✅ Dispose at the right time
309
- const fx = effect((t) => {
310
- console.log($count.get(t))
311
- })
312
-
313
- // Use the effect...
314
- $count.set(1) // Effect runs
315
-
316
- // Now dispose when truly done
317
- fx.dispose()
318
- ```
319
-
320
- ### Pitfall 3: Forgetting Stream Cleanup
321
-
322
- ```typescript
323
- // ❌ WebSocket never closed
324
- function connectWebSocket() {
325
- const $ws = stream<string>((set) => {
326
- const socket = new WebSocket('ws://...')
327
- socket.onmessage = (e) => set(e.data)
328
- // Missing: return () => socket.close()
329
- })
330
- return $ws
331
- }
332
-
333
- // ✅ Proper cleanup
334
- function connectWebSocket() {
335
- const $ws = stream<string>((set) => {
336
- const socket = new WebSocket('ws://...')
337
- socket.onmessage = (e) => set(e.data)
338
-
339
- return () => socket.close() // Cleanup function
340
- })
341
- return $ws
342
- }
343
- ```
344
-
345
- ## Disposal Patterns
346
-
347
- ### Pattern 1: Disposable Builder
348
-
349
- ```typescript
350
- class DisposableBuilder {
351
- private disposables: FlowDisposable[] = []
352
-
353
- add<T extends FlowDisposable>(disposable: T): T {
354
- this.disposables.push(disposable)
355
- return disposable
356
- }
357
-
358
- disposeAll(): void {
359
- // Dispose in reverse order
360
- for (let i = this.disposables.length - 1; i >= 0; i--) {
361
- this.disposables[i].dispose()
362
- }
363
- this.disposables = []
364
- }
365
- }
366
-
367
- // Usage
368
- const builder = new DisposableBuilder()
369
- builder.add(effect((t) => { /* ... */ }))
370
- builder.add(effect((t) => { /* ... */ }))
371
- builder.disposeAll()
372
- ```
373
-
374
- ### Pattern 2: Scoped Disposables
375
-
376
- ```typescript
377
- function withDisposables<T>(
378
- fn: (track: <D extends FlowDisposable>(d: D) => D) => T
379
- ): T & { cleanup: () => void } {
380
- const disposables: FlowDisposable[] = []
381
-
382
- const track = <D extends FlowDisposable>(d: D): D => {
383
- disposables.push(d)
384
- return d
385
- }
386
-
387
- const result = fn(track) as T & { cleanup: () => void }
388
- result.cleanup = () => disposables.forEach(d => d.dispose())
389
-
390
- return result
391
- }
392
-
393
- // Usage
394
- const { cleanup } = withDisposables((track) => {
395
- const $count = track(state(0))
396
- const fx = track(effect((t) => console.log($count.get(t))))
397
- })
398
-
399
- // Clean up everything
400
- cleanup()
401
- ```
402
-
403
- ### Pattern 3: Auto-disposal on Condition
404
-
405
- ```typescript
406
- function createAutoDisposeEffect(
407
- condition: () => boolean,
408
- apply: (t: TrackingContext) => void
409
- ): FlowEffect {
410
- const fx = effect((t) => {
411
- if (!condition()) {
412
- fx.dispose()
413
- return
414
- }
415
- apply(t)
416
- })
417
- return fx
418
- }
419
-
420
- // Usage: effect auto-disposes when count > 10
421
- createAutoDisposeEffect(
422
- () => $count.pick() <= 10,
423
- (t) => console.log('Count:', $count.get(t))
424
- )
425
- ```
426
-