@ersbeth/picoflow 0.2.4 → 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 (248) hide show
  1. package/.cursor/plans/update-js-e795d61b.plan.md +567 -0
  2. package/.gitlab-ci.yml +24 -0
  3. package/.vscode/settings.json +3 -3
  4. package/CHANGELOG.md +51 -0
  5. package/IMPLEMENTATION_GUIDE.md +1578 -0
  6. package/README.md +9 -134
  7. package/biome.json +32 -32
  8. package/dist/picoflow.js +610 -436
  9. package/dist/types/advanced/array.d.ts +0 -6
  10. package/dist/types/advanced/array.d.ts.map +1 -1
  11. package/dist/types/advanced/index.d.ts +5 -5
  12. package/dist/types/advanced/index.d.ts.map +1 -1
  13. package/dist/types/advanced/map.d.ts +114 -23
  14. package/dist/types/advanced/map.d.ts.map +1 -1
  15. package/dist/types/advanced/resource.d.ts +51 -12
  16. package/dist/types/advanced/resource.d.ts.map +1 -1
  17. package/dist/types/advanced/resourceAsync.d.ts +28 -13
  18. package/dist/types/advanced/resourceAsync.d.ts.map +1 -1
  19. package/dist/types/advanced/stream.d.ts +74 -16
  20. package/dist/types/advanced/stream.d.ts.map +1 -1
  21. package/dist/types/advanced/streamAsync.d.ts +69 -15
  22. package/dist/types/advanced/streamAsync.d.ts.map +1 -1
  23. package/dist/types/basic/constant.d.ts +44 -16
  24. package/dist/types/basic/constant.d.ts.map +1 -1
  25. package/dist/types/basic/derivation.d.ts +73 -24
  26. package/dist/types/basic/derivation.d.ts.map +1 -1
  27. package/dist/types/basic/disposable.d.ts +65 -6
  28. package/dist/types/basic/disposable.d.ts.map +1 -1
  29. package/dist/types/basic/effect.d.ts +27 -16
  30. package/dist/types/basic/effect.d.ts.map +1 -1
  31. package/dist/types/basic/index.d.ts +7 -8
  32. package/dist/types/basic/index.d.ts.map +1 -1
  33. package/dist/types/basic/observable.d.ts +62 -13
  34. package/dist/types/basic/observable.d.ts.map +1 -1
  35. package/dist/types/basic/signal.d.ts +35 -6
  36. package/dist/types/basic/signal.d.ts.map +1 -1
  37. package/dist/types/basic/state.d.ts +25 -4
  38. package/dist/types/basic/state.d.ts.map +1 -1
  39. package/dist/types/basic/trackingContext.d.ts +33 -0
  40. package/dist/types/basic/trackingContext.d.ts.map +1 -0
  41. package/dist/types/creators.d.ts +271 -26
  42. package/dist/types/creators.d.ts.map +1 -1
  43. package/dist/types/index.d.ts +60 -7
  44. package/dist/types/index.d.ts.map +1 -1
  45. package/dist/types/solid/converters.d.ts +5 -5
  46. package/dist/types/solid/converters.d.ts.map +1 -1
  47. package/dist/types/solid/index.d.ts +2 -2
  48. package/dist/types/solid/index.d.ts.map +1 -1
  49. package/dist/types/solid/primitives.d.ts +96 -4
  50. package/dist/types/solid/primitives.d.ts.map +1 -1
  51. package/docs/.vitepress/config.mts +110 -0
  52. package/docs/api/classes/FlowArray.md +489 -0
  53. package/docs/api/classes/FlowConstant.md +350 -0
  54. package/docs/api/classes/FlowDerivation.md +334 -0
  55. package/docs/api/classes/FlowEffect.md +100 -0
  56. package/docs/api/classes/FlowMap.md +512 -0
  57. package/docs/api/classes/FlowObservable.md +306 -0
  58. package/docs/api/classes/FlowResource.md +380 -0
  59. package/docs/api/classes/FlowResourceAsync.md +362 -0
  60. package/docs/api/classes/FlowSignal.md +160 -0
  61. package/docs/api/classes/FlowState.md +368 -0
  62. package/docs/api/classes/FlowStream.md +367 -0
  63. package/docs/api/classes/FlowStreamAsync.md +364 -0
  64. package/docs/api/classes/SolidDerivation.md +75 -0
  65. package/docs/api/classes/SolidResource.md +91 -0
  66. package/docs/api/classes/SolidState.md +71 -0
  67. package/docs/api/classes/TrackingContext.md +33 -0
  68. package/docs/api/functions/array.md +58 -0
  69. package/docs/api/functions/constant.md +45 -0
  70. package/docs/api/functions/derivation.md +53 -0
  71. package/docs/api/functions/effect.md +49 -0
  72. package/docs/api/functions/from.md +220 -0
  73. package/docs/api/functions/isDisposable.md +49 -0
  74. package/docs/api/functions/map.md +57 -0
  75. package/docs/api/functions/resource.md +52 -0
  76. package/docs/api/functions/resourceAsync.md +50 -0
  77. package/docs/api/functions/signal.md +36 -0
  78. package/docs/api/functions/state.md +47 -0
  79. package/docs/api/functions/stream.md +53 -0
  80. package/docs/api/functions/streamAsync.md +50 -0
  81. package/docs/api/index.md +118 -0
  82. package/docs/api/interfaces/FlowDisposable.md +65 -0
  83. package/docs/api/interfaces/SolidObservable.md +19 -0
  84. package/docs/api/type-aliases/FlowArrayAction.md +49 -0
  85. package/docs/api/type-aliases/FlowStreamDisposer.md +15 -0
  86. package/docs/api/type-aliases/FlowStreamSetter.md +27 -0
  87. package/docs/api/type-aliases/FlowStreamUpdater.md +32 -0
  88. package/docs/api/type-aliases/NotPromise.md +18 -0
  89. package/docs/api/type-aliases/SolidGetter.md +17 -0
  90. package/docs/api/typedoc-sidebar.json +1 -0
  91. package/docs/examples/examples.md +2313 -0
  92. package/docs/examples/patterns.md +649 -0
  93. package/docs/guide/advanced/disposal.md +426 -0
  94. package/docs/guide/advanced/solidjs.md +221 -0
  95. package/docs/guide/advanced/upgrading.md +464 -0
  96. package/docs/guide/introduction/concepts.md +56 -0
  97. package/docs/guide/introduction/conventions.md +61 -0
  98. package/docs/guide/introduction/getting-started.md +134 -0
  99. package/docs/guide/introduction/lifecycle.md +371 -0
  100. package/docs/guide/primitives/array.md +400 -0
  101. package/docs/guide/primitives/constant.md +380 -0
  102. package/docs/guide/primitives/derivations.md +348 -0
  103. package/docs/guide/primitives/effects.md +458 -0
  104. package/docs/guide/primitives/map.md +387 -0
  105. package/docs/guide/primitives/overview.md +175 -0
  106. package/docs/guide/primitives/resources.md +858 -0
  107. package/docs/guide/primitives/signal.md +259 -0
  108. package/docs/guide/primitives/state.md +368 -0
  109. package/docs/guide/primitives/streams.md +931 -0
  110. package/docs/index.md +47 -0
  111. package/docs/public/logo.svg +1 -0
  112. package/package.json +57 -41
  113. package/src/advanced/array.ts +208 -210
  114. package/src/advanced/index.ts +7 -7
  115. package/src/advanced/map.ts +178 -68
  116. package/src/advanced/resource.ts +87 -43
  117. package/src/advanced/resourceAsync.ts +62 -42
  118. package/src/advanced/stream.ts +113 -50
  119. package/src/advanced/streamAsync.ts +120 -61
  120. package/src/basic/constant.ts +82 -49
  121. package/src/basic/derivation.ts +128 -84
  122. package/src/basic/disposable.ts +74 -15
  123. package/src/basic/effect.ts +85 -77
  124. package/src/basic/index.ts +7 -8
  125. package/src/basic/observable.ts +94 -36
  126. package/src/basic/signal.ts +133 -105
  127. package/src/basic/state.ts +46 -25
  128. package/src/basic/trackingContext.ts +45 -0
  129. package/src/creators.ts +297 -54
  130. package/src/index.ts +96 -43
  131. package/src/solid/converters.ts +186 -67
  132. package/src/solid/index.ts +8 -2
  133. package/src/solid/primitives.ts +167 -65
  134. package/test/array.test.ts +592 -612
  135. package/test/constant.test.ts +31 -33
  136. package/test/derivation.test.ts +531 -536
  137. package/test/effect.test.ts +21 -21
  138. package/test/map.test.ts +233 -137
  139. package/test/resource.test.ts +119 -121
  140. package/test/resourceAsync.test.ts +98 -100
  141. package/test/signal.test.ts +51 -55
  142. package/test/state.test.ts +186 -168
  143. package/test/stream.test.ts +189 -189
  144. package/test/streamAsync.test.ts +186 -186
  145. package/tsconfig.json +19 -18
  146. package/typedoc.json +37 -0
  147. package/vite.config.ts +23 -23
  148. package/vitest.config.ts +7 -7
  149. package/api/doc/index.md +0 -31
  150. package/api/doc/picoflow.array.md +0 -55
  151. package/api/doc/picoflow.constant.md +0 -55
  152. package/api/doc/picoflow.derivation.md +0 -55
  153. package/api/doc/picoflow.effect.md +0 -55
  154. package/api/doc/picoflow.flowarray._constructor_.md +0 -49
  155. package/api/doc/picoflow.flowarray._lastaction.md +0 -13
  156. package/api/doc/picoflow.flowarray.clear.md +0 -17
  157. package/api/doc/picoflow.flowarray.dispose.md +0 -55
  158. package/api/doc/picoflow.flowarray.get.md +0 -19
  159. package/api/doc/picoflow.flowarray.length.md +0 -13
  160. package/api/doc/picoflow.flowarray.md +0 -273
  161. package/api/doc/picoflow.flowarray.pop.md +0 -17
  162. package/api/doc/picoflow.flowarray.push.md +0 -53
  163. package/api/doc/picoflow.flowarray.set.md +0 -53
  164. package/api/doc/picoflow.flowarray.setitem.md +0 -69
  165. package/api/doc/picoflow.flowarray.shift.md +0 -17
  166. package/api/doc/picoflow.flowarray.splice.md +0 -85
  167. package/api/doc/picoflow.flowarray.unshift.md +0 -53
  168. package/api/doc/picoflow.flowarrayaction.md +0 -37
  169. package/api/doc/picoflow.flowconstant._constructor_.md +0 -49
  170. package/api/doc/picoflow.flowconstant.get.md +0 -25
  171. package/api/doc/picoflow.flowconstant.md +0 -88
  172. package/api/doc/picoflow.flowderivation._constructor_.md +0 -49
  173. package/api/doc/picoflow.flowderivation.get.md +0 -23
  174. package/api/doc/picoflow.flowderivation.md +0 -86
  175. package/api/doc/picoflow.flowdisposable.dispose.md +0 -55
  176. package/api/doc/picoflow.flowdisposable.md +0 -43
  177. package/api/doc/picoflow.floweffect._constructor_.md +0 -54
  178. package/api/doc/picoflow.floweffect.dispose.md +0 -21
  179. package/api/doc/picoflow.floweffect.disposed.md +0 -13
  180. package/api/doc/picoflow.floweffect.md +0 -131
  181. package/api/doc/picoflow.flowgetter.md +0 -15
  182. package/api/doc/picoflow.flowmap._lastdeleted.md +0 -21
  183. package/api/doc/picoflow.flowmap._lastset.md +0 -21
  184. package/api/doc/picoflow.flowmap.delete.md +0 -61
  185. package/api/doc/picoflow.flowmap.md +0 -133
  186. package/api/doc/picoflow.flowmap.setat.md +0 -77
  187. package/api/doc/picoflow.flowobservable.get.md +0 -19
  188. package/api/doc/picoflow.flowobservable.md +0 -68
  189. package/api/doc/picoflow.flowobservable.subscribe.md +0 -55
  190. package/api/doc/picoflow.flowresource._constructor_.md +0 -49
  191. package/api/doc/picoflow.flowresource.fetch.md +0 -27
  192. package/api/doc/picoflow.flowresource.get.md +0 -23
  193. package/api/doc/picoflow.flowresource.md +0 -100
  194. package/api/doc/picoflow.flowresourceasync._constructor_.md +0 -49
  195. package/api/doc/picoflow.flowresourceasync.fetch.md +0 -27
  196. package/api/doc/picoflow.flowresourceasync.get.md +0 -23
  197. package/api/doc/picoflow.flowresourceasync.md +0 -100
  198. package/api/doc/picoflow.flowsignal.dispose.md +0 -59
  199. package/api/doc/picoflow.flowsignal.disposed.md +0 -18
  200. package/api/doc/picoflow.flowsignal.md +0 -112
  201. package/api/doc/picoflow.flowsignal.trigger.md +0 -21
  202. package/api/doc/picoflow.flowstate.md +0 -52
  203. package/api/doc/picoflow.flowstate.set.md +0 -61
  204. package/api/doc/picoflow.flowstream._constructor_.md +0 -49
  205. package/api/doc/picoflow.flowstream.dispose.md +0 -21
  206. package/api/doc/picoflow.flowstream.get.md +0 -23
  207. package/api/doc/picoflow.flowstream.md +0 -100
  208. package/api/doc/picoflow.flowstreamasync._constructor_.md +0 -54
  209. package/api/doc/picoflow.flowstreamasync.dispose.md +0 -21
  210. package/api/doc/picoflow.flowstreamasync.get.md +0 -23
  211. package/api/doc/picoflow.flowstreamasync.md +0 -100
  212. package/api/doc/picoflow.flowstreamdisposer.md +0 -13
  213. package/api/doc/picoflow.flowstreamsetter.md +0 -13
  214. package/api/doc/picoflow.flowstreamupdater.md +0 -19
  215. package/api/doc/picoflow.flowwatcher.md +0 -15
  216. package/api/doc/picoflow.from.md +0 -55
  217. package/api/doc/picoflow.from_1.md +0 -55
  218. package/api/doc/picoflow.from_2.md +0 -55
  219. package/api/doc/picoflow.from_3.md +0 -55
  220. package/api/doc/picoflow.from_4.md +0 -55
  221. package/api/doc/picoflow.from_5.md +0 -55
  222. package/api/doc/picoflow.isdisposable.md +0 -55
  223. package/api/doc/picoflow.map.md +0 -59
  224. package/api/doc/picoflow.md +0 -544
  225. package/api/doc/picoflow.resource.md +0 -55
  226. package/api/doc/picoflow.resourceasync.md +0 -55
  227. package/api/doc/picoflow.signal.md +0 -19
  228. package/api/doc/picoflow.solidderivation._constructor_.md +0 -49
  229. package/api/doc/picoflow.solidderivation.get.md +0 -13
  230. package/api/doc/picoflow.solidderivation.md +0 -94
  231. package/api/doc/picoflow.solidgetter.md +0 -13
  232. package/api/doc/picoflow.solidobservable.get.md +0 -13
  233. package/api/doc/picoflow.solidobservable.md +0 -57
  234. package/api/doc/picoflow.solidresource._constructor_.md +0 -49
  235. package/api/doc/picoflow.solidresource.get.md +0 -13
  236. package/api/doc/picoflow.solidresource.latest.md +0 -13
  237. package/api/doc/picoflow.solidresource.md +0 -157
  238. package/api/doc/picoflow.solidresource.refetch.md +0 -13
  239. package/api/doc/picoflow.solidresource.state.md +0 -13
  240. package/api/doc/picoflow.solidstate._constructor_.md +0 -49
  241. package/api/doc/picoflow.solidstate.get.md +0 -13
  242. package/api/doc/picoflow.solidstate.md +0 -115
  243. package/api/doc/picoflow.solidstate.set.md +0 -13
  244. package/api/doc/picoflow.state.md +0 -55
  245. package/api/doc/picoflow.stream.md +0 -55
  246. package/api/doc/picoflow.streamasync.md +0 -55
  247. package/api/picoflow.public.api.md +0 -244
  248. package/api-extractor.json +0 -61
@@ -0,0 +1,1578 @@
1
+ # Implementation Guide - PicoFlow API v1.0.0
2
+
3
+ > **Note for Library Users:** This guide is intended for library maintainers and contributors who need detailed implementation instructions. If you're a user upgrading your project from v0.x to v1.0.0, please see [UPGRADING.md](UPGRADING.md) instead.
4
+
5
+ ---
6
+
7
+ ## Vue d'ensemble
8
+
9
+ Cette migration transforme l'API de PicoFlow d'un système basé sur des fonctions getter/watcher vers un système basé sur un contexte de tracking explicite (`TrackingContext`).
10
+
11
+ ### Philosophie de simplification
12
+
13
+ La nouvelle API élimine les méthodes internes comme `_watch()`, `_watchFrom()`, et `_getFrom()` au profit d'overrides directs de méthodes publiques. Cela rend le code plus simple, plus lisible et plus maintenable.
14
+
15
+ **Architecture simplifiée :**
16
+
17
+ ```
18
+ Ancienne API (complexe) :
19
+ ├─ FlowSignal._watch() [interne]
20
+ ├─ FlowSignal._watchFrom() [interne]
21
+ ├─ FlowObservable._getFrom() [interne]
22
+ └─ Overrides de _watch() dans FlowDerivation
23
+
24
+ Nouvelle API (simple) :
25
+ ├─ FlowSignal.watch(context) [publique]
26
+ ├─ FlowObservable.get(context) [publique]
27
+ ├─ FlowObservable.pick() [publique]
28
+ └─ Override de watch(context) dans FlowDerivation
29
+ ```
30
+
31
+ ### Aperçu des Modifications
32
+
33
+ **Fichiers à créer :** 1
34
+ - `src/basic/trackingContext.ts`
35
+
36
+ **Fichiers à modifier :** 16
37
+ - Basic (7) : `signal.ts`, `observable.ts`, `constant.ts`, `state.ts` (aucun changement), `derivation.ts`, `effect.ts`, `index.ts`
38
+ - Advanced (5) : `resource.ts`, `resourceAsync.ts`, `array.ts`, `stream.ts`, `streamAsync.ts`
39
+ - Creators (1) : `creators.ts`
40
+ - Solid (1) : `converters.ts`
41
+
42
+ **Fichiers sans modification :** 3
43
+ - `src/advanced/map.ts` (hérite via FlowState)
44
+ - `src/solid/primitives.ts` (dépend uniquement de SolidJS)
45
+ - `src/solid/index.ts` (fichier d'exports)
46
+
47
+ **Tests à migrer :** 11 fichiers
48
+ - Basic (5) : `state.test.ts`, `effect.test.ts`, `derivation.test.ts`, `signal.test.ts`, `constant.test.ts`
49
+ - Advanced (6) : `array.test.ts`, `map.test.ts`, `resource.test.ts`, `resourceAsync.test.ts`, `stream.test.ts`, `streamAsync.test.ts`
50
+
51
+ ### Changements clés
52
+
53
+ **Avant :**
54
+ ```typescript
55
+ effect((get, watch) => {
56
+ const value = get($state);
57
+ watch($signal);
58
+ });
59
+
60
+ derivation((get, watch) => {
61
+ return get($stateA) + get($stateB);
62
+ });
63
+ ```
64
+
65
+ **Après :**
66
+ ```typescript
67
+ effect((t) => {
68
+ const value = $state.get(t);
69
+ $signal.watch(t);
70
+ });
71
+
72
+ derivation((t) => {
73
+ return $stateA.get(t) + $stateB.get(t);
74
+ });
75
+ ```
76
+
77
+ ### Bénéfices de la Nouvelle API
78
+
79
+ 1. **Syntaxe chaînée naturelle** : `$parent.get(t).child.get(t)` au lieu de `get(get($parent).child)`
80
+ 2. **Contrôle explicite** : `get(t)` pour tracking, `pick()` pour non-tracking
81
+ 3. **Code plus simple** : Moins de méthodes internes, architecture plus claire
82
+ 4. **API unifiée** : Toutes les classes (basic et advanced) utilisent le même pattern
83
+ 5. **Meilleure lisibilité** : L'intention (réactif ou non) est évidente à la lecture
84
+ 6. **Plus flexible** : Possibilité de lectures mixtes réactives/non-réactives dans le même scope
85
+
86
+ ---
87
+
88
+ ## Nouvelle API des Observables
89
+
90
+ ### `FlowObservable.get(context)`
91
+
92
+ **Avant :**
93
+ ```typescript
94
+ observable.get() // Pas de tracking automatique
95
+ ```
96
+
97
+ **Après :**
98
+ ```typescript
99
+ observable.get(t) // Avec tracking (dans effect/derivation)
100
+ observable.get(null) // Sans tracking
101
+ observable.pick() // Sans tracking (syntaxe alternative)
102
+ ```
103
+
104
+ ### `FlowObservable.pick()`
105
+
106
+ **Nouvelle méthode** - équivalent à `get(null)` :
107
+ ```typescript
108
+ const value = $state.pick(); // Lecture sans tracking
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Nouvelle API des Signaux
114
+
115
+ ### `FlowSignal.watch(context)`
116
+
117
+ **Avant :**
118
+ ```typescript
119
+ watch($signal) // Via la fonction watcher
120
+ ```
121
+
122
+ **Après :**
123
+ ```typescript
124
+ $signal.watch(t) // Méthode directe, contexte obligatoire
125
+ ```
126
+
127
+ ⚠️ **Important** : `watch()` nécessite TOUJOURS un contexte. Pas de version sans paramètre.
128
+
129
+ ---
130
+
131
+ ## Changements dans les Fichiers Source
132
+
133
+ ### 1. Créer `src/basic/trackingContext.ts` (NOUVEAU FICHIER)
134
+
135
+ ```typescript
136
+ import type { FlowEffect } from "./effect";
137
+ import type { FlowDerivation } from "./derivation";
138
+ import type { FlowSignal } from "./signal";
139
+
140
+ /**
141
+ * Represents a tracking context used to register dependencies
142
+ * during reactive computations.
143
+ *
144
+ * @public
145
+ */
146
+ export class TrackingContext {
147
+ /*@internal*/
148
+ constructor(
149
+ private _owner: FlowEffect | FlowDerivation<unknown>
150
+ ) {}
151
+
152
+ /**
153
+ * Registers a dependency on the given signal.
154
+ * @internal
155
+ */
156
+ /*@internal*/ _registerDependency(signal: FlowSignal): void {
157
+ this._owner._registerDependency(signal);
158
+ }
159
+ }
160
+ ```
161
+
162
+ ### 2. Modifier `src/basic/signal.ts`
163
+
164
+ **Ajouts :**
165
+ - Import `TrackingContext`
166
+ - Méthode publique `watch(context: TrackingContext)`
167
+
168
+ **Changements à apporter :**
169
+
170
+ ```typescript
171
+ // AJOUTER cet import en haut du fichier
172
+ import type { TrackingContext } from "./trackingContext";
173
+
174
+ // AJOUTER cette méthode dans la classe FlowSignal (après la méthode trigger)
175
+ /**
176
+ * Watches the signal, registering it as a dependency in the tracking context.
177
+ * @param context - The tracking context (required).
178
+ * @public
179
+ */
180
+ public watch(context: TrackingContext): void {
181
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
182
+ context._registerDependency(this);
183
+ }
184
+ ```
185
+
186
+ **Suppressions :**
187
+ - SUPPRIMER le type `FlowWatcher` (ligne 5-9)
188
+ - SUPPRIMER la méthode `_watch()` (ligne 77-80)
189
+ - SUPPRIMER la méthode `_watchFrom()` (ligne 87-90)
190
+
191
+ ### 3. Modifier `src/basic/observable.ts`
192
+
193
+ **Changements majeurs :**
194
+ - Remplacer la méthode abstraite `get()` par `get(context: TrackingContext | null)`
195
+ - Ajouter la méthode abstraite protégée `_getRaw()`
196
+ - Ajouter la méthode publique `pick()`
197
+ - Supprimer la méthode `_getFrom()`
198
+
199
+ **Code complet de la classe :**
200
+
201
+ ```typescript
202
+ import { FlowSignal } from "./signal";
203
+ import type { TrackingContext } from "./trackingContext";
204
+ import { FlowEffect } from "./effect";
205
+
206
+ /**
207
+ * Represents a reactive observable that holds and tracks a value.
208
+ *
209
+ * @remarks Subclasses must implement the {@link FlowObservable._getRaw} method to return the current value.
210
+ * @typeParam T - The type of the value held by the observable.
211
+ * @public
212
+ */
213
+ export abstract class FlowObservable<T> extends FlowSignal {
214
+ /**
215
+ * Gets the current value with optional dependency tracking.
216
+ * @param context - The tracking context for reactive tracking, or null for untracked access.
217
+ * @returns The current value of type T.
218
+ * @public
219
+ */
220
+ get(context: TrackingContext | null): T {
221
+ if (context) {
222
+ this.watch(context);
223
+ }
224
+ return this._getRaw();
225
+ }
226
+
227
+ /**
228
+ * Gets the current value without any dependency tracking.
229
+ * Equivalent to calling get(null).
230
+ * @returns The current value of type T.
231
+ * @public
232
+ */
233
+ pick(): T {
234
+ return this._getRaw();
235
+ }
236
+
237
+ /**
238
+ * Internal method to retrieve the raw value.
239
+ * Subclasses must override this method to provide the current value.
240
+ * @internal
241
+ */
242
+ protected abstract _getRaw(): T;
243
+
244
+ /* INTERNAL -------------------------------------------*/
245
+
246
+ /*@internal*/ protected _value!: T;
247
+
248
+ /**
249
+ * Subscribes a listener function to changes of the observable.
250
+ * The listener is executed immediately with the current value and on subsequent updates.
251
+ * @param listener - A callback function that receives the new value.
252
+ * @returns A disposer function to cancel the subscription.
253
+ */
254
+ subscribe(listener: (value: T) => void): () => void {
255
+ const effect = new FlowEffect((t) => {
256
+ listener(this.get(t));
257
+ });
258
+ return () => effect.dispose();
259
+ }
260
+ }
261
+ ```
262
+
263
+ **Suppressions :**
264
+ - SUPPRIMER le type `FlowGetter` (ligne 5-11)
265
+ - SUPPRIMER la méthode `abstract get(): T` (ligne 23-28)
266
+ - SUPPRIMER la méthode `_getFrom` (ligne 34-37)
267
+
268
+ ### 4. Modifier `src/basic/constant.ts`
269
+
270
+ **Changements :**
271
+ - Remplacer la méthode `get()` par la méthode protégée `_getRaw()`
272
+
273
+ **Avant :**
274
+ ```typescript
275
+ get(): T {
276
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
277
+ this._initLazy();
278
+ return this._value;
279
+ }
280
+ ```
281
+
282
+ **Après :**
283
+ ```typescript
284
+ /**
285
+ * Internal method to get the raw value.
286
+ * @internal
287
+ */
288
+ protected _getRaw(): T {
289
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
290
+ this._initLazy();
291
+ return this._value;
292
+ }
293
+ ```
294
+
295
+ ### 5. Modifier `src/basic/state.ts`
296
+
297
+ **Aucun changement nécessaire** - La classe hérite automatiquement des nouvelles méthodes `get()` et `pick()` de `FlowObservable`.
298
+
299
+ ### 6. Modifier `src/basic/derivation.ts`
300
+
301
+ **Changements majeurs :**
302
+ - Remplacer le type du paramètre `compute` : `(get: FlowGetter, watch: FlowWatcher) => T` → `(t: TrackingContext) => T`
303
+ - Supprimer `_trackedGet`, `_untrackedGet`, `_trackedWatch`, `_untrackedWatch`
304
+ - Ajouter `_trackedContext: TrackingContext`
305
+ - Remplacer `_trackedCompute` et `_untrackedCompute` par un seul `_compute`
306
+ - Remplacer la méthode `get()` par `_getRaw()`
307
+ - Renommer la méthode `_compute()` en `_update()`
308
+ - Override la méthode `watch()` pour gérer le compute lazy
309
+
310
+ **Code complet de la classe :**
311
+
312
+ ```typescript
313
+ import { FlowObservable } from "./observable";
314
+ import { TrackingContext } from "./trackingContext";
315
+
316
+ /**
317
+ * Represents a reactive derivation whose value is computed based on other reactive signals.
318
+ * @remarks
319
+ * It tracks dependencies automatically and recomputes its value when any dependency changes.
320
+ * Use FlowDerivation to create derived values in a reactive manner. It lazily initializes the computed value,
321
+ * ensuring that computations only occur when necessary.
322
+ * @typeParam T - The type of the computed value.
323
+ * @public
324
+ */
325
+ export class FlowDerivation<T> extends FlowObservable<T> {
326
+ /**
327
+ * Creates a new FlowDerivation.
328
+ * @param compute - A function that computes the derived value using a tracking context.
329
+ * @public
330
+ */
331
+ constructor(compute: (t: TrackingContext) => T) {
332
+ super();
333
+ this._compute = compute;
334
+ this._trackedContext = new TrackingContext(this);
335
+ }
336
+
337
+ /**
338
+ * Internal method to get the raw value.
339
+ * @internal
340
+ */
341
+ protected _getRaw(): T {
342
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
343
+ this._initLazy();
344
+ this._update();
345
+ return this._value;
346
+ }
347
+
348
+ /* INTERNAL --------------------------------------------------------- */
349
+
350
+ private _initialized = false;
351
+ private _dirty = false;
352
+ private _compute: (t: TrackingContext) => T;
353
+ private _trackedContext: TrackingContext;
354
+
355
+ private _initLazy(): void {
356
+ if (!this._initialized) {
357
+ this._value = this._compute(this._trackedContext);
358
+ this._initialized = true;
359
+ }
360
+ }
361
+
362
+ /* @internal */ private _update(): void {
363
+ if (this._dirty) {
364
+ // Store current dependencies
365
+ const dependencies = [...this._dependencies];
366
+
367
+ // Clear current dependencies, compute and retrack dependencies
368
+ this._dependencies.clear();
369
+ this._value = this._compute(this._trackedContext);
370
+
371
+ // Unsubscribe from dependencies that are no longer needed
372
+ const dependenciesToRemove = dependencies.filter(
373
+ (dependency) => !this._dependencies.has(dependency),
374
+ );
375
+ dependenciesToRemove.forEach((dependency) =>
376
+ dependency._unregisterDependency(this),
377
+ );
378
+
379
+ this._dirty = false;
380
+ }
381
+ }
382
+
383
+ /* @internal */ override _notify(): void {
384
+ this._dirty = true;
385
+ super._notify();
386
+ }
387
+
388
+ /**
389
+ * Override watch to ensure the derivation computes its value
390
+ * and tracks its own dependencies when watched.
391
+ * @public
392
+ */
393
+ public override watch(context: TrackingContext): void {
394
+ super.watch(context); // Register this derivation as a dependency
395
+
396
+ // Ensure the derivation is initialized and up-to-date
397
+ // This is needed when watching a derivation without reading its value
398
+ this._initLazy();
399
+ this._update();
400
+ }
401
+ }
402
+ ```
403
+
404
+ **À supprimer complètement :**
405
+ - `_trackedGet`
406
+ - `_untrackedGet`
407
+ - `_trackedWatch`
408
+ - `_untrackedWatch`
409
+ - `_initEager`
410
+ - `_trackedCompute`
411
+ - `_untrackedCompute`
412
+ - `_watch()` (l'override est remplacé par l'override de `watch()`)
413
+
414
+ ### 7. Modifier `src/basic/effect.ts`
415
+
416
+ **Changements majeurs :**
417
+ - Remplacer le type du paramètre `apply` : `(get: FlowGetter, watch: FlowWatcher) => void` → `(t: TrackingContext) => void`
418
+ - Supprimer `_trackedGet`, `_untrackedGet`, `_trackedWatch`, `_untrackedWatch`
419
+ - Ajouter `_trackedContext: TrackingContext`
420
+ - Simplifier `_trackedExec` et `_untrackedExec` en un seul `_apply`
421
+ - Modifier la logique de `_exec()`
422
+
423
+ **Code complet de la classe :**
424
+
425
+ ```typescript
426
+ import type { FlowSignal } from "./signal";
427
+ import { TrackingContext } from "./trackingContext";
428
+
429
+ /**
430
+ * Represents a reactive effect that executes side-effect functions based
431
+ * on its tracked dependencies.
432
+ *
433
+ * @remarks
434
+ * The FlowEffect executes an apply function that performs side effects,
435
+ * running initially in a tracked mode to register dependencies.
436
+ *
437
+ * @public
438
+ */
439
+ export class FlowEffect {
440
+ /**
441
+ * Creates a new FlowEffect.
442
+ *
443
+ * @param apply - A side-effect function that receives a tracking context to
444
+ * access and register dependencies on reactive observables and signals.
445
+ *
446
+ * @remarks
447
+ * The provided function is executed immediately with a tracking context to collect dependencies.
448
+ *
449
+ * @public
450
+ */
451
+ constructor(apply: (t: TrackingContext) => void) {
452
+ this._trackedContext = new TrackingContext(this);
453
+ this._apply = apply;
454
+ this._exec();
455
+ }
456
+
457
+ /**
458
+ * Disposes the effect, unregistering all its tracked dependencies.
459
+ *
460
+ * @remarks
461
+ * Once disposed, the effect must no longer be used. Trying to dispose an effect
462
+ * that is already disposed will throw an error.
463
+ *
464
+ * @public
465
+ */
466
+ public dispose(): void {
467
+ if (this._disposed) throw new Error("[PicoFlow] Effect is disposed");
468
+ Array.from(this._dependencies).forEach((dependency) => {
469
+ this._unregisterDependency(dependency);
470
+ });
471
+ this._disposed = true;
472
+ }
473
+
474
+ /**
475
+ * Indicates whether this effect has been disposed.
476
+ *
477
+ * @returns A boolean value that is true if the effect is disposed, false otherwise.
478
+ *
479
+ * @public
480
+ */
481
+ public get disposed(): boolean {
482
+ return this._disposed;
483
+ }
484
+
485
+ /* INTERNAL ------------------------------------------------------------ */
486
+
487
+ private _disposed = false;
488
+ private _dependencies = new Set<FlowSignal>();
489
+ private _trackedContext: TrackingContext;
490
+ private _apply: (t: TrackingContext) => void;
491
+
492
+ /*@internal*/ _exec(): void {
493
+ if (this._disposed)
494
+ /* v8 ignore next 1 */
495
+ throw new Error("[PicoFlow] Effect is disposed");
496
+
497
+ // Always execute with tracking context
498
+ this._apply(this._trackedContext);
499
+ }
500
+
501
+ /*@internal*/ _registerDependency(dependency: FlowSignal): void {
502
+ this._dependencies.add(dependency);
503
+ dependency._registerEffect(this);
504
+ }
505
+
506
+ /*@internal*/ _unregisterDependency(dependency: FlowSignal): void {
507
+ this._dependencies.delete(dependency);
508
+ dependency._unregisterEffect(this);
509
+ }
510
+ }
511
+ ```
512
+
513
+ **À supprimer complètement :**
514
+ - `_initialized`
515
+ - `_trackedGet`
516
+ - `_untrackedGet`
517
+ - `_trackedWatch`
518
+ - `_untrackedWatch`
519
+ - `_trackedExec`
520
+ - `_untrackedExec`
521
+
522
+ **Changement comportemental important :**
523
+ Dans l'ancienne API, les effects s'exécutaient en mode "tracked" la première fois, puis "untracked" les fois suivantes. Dans la nouvelle API, ils s'exécutent **toujours en mode tracked**, et c'est l'utilisateur qui décide explicitement avec `.get(t)` ou `.pick()` ce qui doit être tracké ou non.
524
+
525
+ ### 8. Modifier `src/basic/index.ts`
526
+
527
+ **Ajouts :**
528
+ ```typescript
529
+ export { TrackingContext } from "./trackingContext";
530
+ ```
531
+
532
+ **Suppressions :**
533
+ ```typescript
534
+ // SUPPRIMER ces exports (s'ils existent)
535
+ export type { FlowGetter } from "./observable";
536
+ export type { FlowWatcher } from "./signal";
537
+ ```
538
+
539
+ ---
540
+
541
+ ## Changements dans les Fichiers Advanced
542
+
543
+ Les classes dans `src/advanced/` qui étendent `FlowObservable` et override la méthode `get()` doivent être modifiées. Le pattern est identique pour toutes : remplacer `public get()` par `protected _getRaw()`.
544
+
545
+ **Résumé :** 5 fichiers à modifier, 1 fichier sans modification.
546
+
547
+ **Pattern uniforme :**
548
+ Toutes les classes advanced qui override `get()` suivent le même pattern de migration :
549
+ 1. Remplacer `public get()` → `protected _getRaw()`
550
+ 2. La classe hérite automatiquement de `get(context)` et `pick()`
551
+ 3. Aucun autre changement nécessaire
552
+
553
+ ### 9. Modifier `src/advanced/resource.ts`
554
+
555
+ **Changement unique :**
556
+ Remplacer la méthode `get()` par `_getRaw()`
557
+
558
+ **Avant :**
559
+ ```typescript
560
+ public get(): T | undefined {
561
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
562
+ return this._value;
563
+ }
564
+ ```
565
+
566
+ **Après :**
567
+ ```typescript
568
+ protected _getRaw(): T | undefined {
569
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
570
+ return this._value;
571
+ }
572
+ ```
573
+
574
+ **Bénéfices :**
575
+ La classe hérite automatiquement de `get(context)` et `pick()` de `FlowObservable`.
576
+
577
+ ### 10. Modifier `src/advanced/resourceAsync.ts`
578
+
579
+ **Changement unique :**
580
+ Remplacer la méthode `get()` par `_getRaw()`
581
+
582
+ **Avant :**
583
+ ```typescript
584
+ public get(): Promise<T> {
585
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
586
+ if (!this._value) this._value = this._fetch();
587
+ return this._value;
588
+ }
589
+ ```
590
+
591
+ **Après :**
592
+ ```typescript
593
+ protected _getRaw(): Promise<T> {
594
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
595
+ if (!this._value) this._value = this._fetch();
596
+ return this._value;
597
+ }
598
+ ```
599
+
600
+ ### 11. Modifier `src/advanced/array.ts`
601
+
602
+ **Changement unique :**
603
+ Remplacer la méthode `get()` par `_getRaw()`
604
+
605
+ **Avant :**
606
+ ```typescript
607
+ get(): T[] {
608
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
609
+ return [...this._value]; // Ensure nobody can modify the original array
610
+ }
611
+ ```
612
+
613
+ **Après :**
614
+ ```typescript
615
+ protected _getRaw(): T[] {
616
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
617
+ return [...this._value]; // Ensure nobody can modify the original array
618
+ }
619
+ ```
620
+
621
+ **Note :** La propriété `length` n'est pas impactée par ce changement.
622
+
623
+ ### 12. Modifier `src/advanced/stream.ts`
624
+
625
+ **Changement unique :**
626
+ Remplacer la méthode `get()` par `_getRaw()`
627
+
628
+ **Avant :**
629
+ ```typescript
630
+ public get(): T | undefined {
631
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
632
+ return this._value;
633
+ }
634
+ ```
635
+
636
+ **Après :**
637
+ ```typescript
638
+ protected _getRaw(): T | undefined {
639
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
640
+ return this._value;
641
+ }
642
+ ```
643
+
644
+ ### 13. Modifier `src/advanced/streamAsync.ts`
645
+
646
+ **Changement unique :**
647
+ Remplacer la méthode `get()` par `_getRaw()`
648
+
649
+ **Avant :**
650
+ ```typescript
651
+ public get(): Promise<T> {
652
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
653
+ return this._value;
654
+ }
655
+ ```
656
+
657
+ **Après :**
658
+ ```typescript
659
+ protected _getRaw(): Promise<T> {
660
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
661
+ return this._value;
662
+ }
663
+ ```
664
+
665
+ ### 14. `src/advanced/map.ts` - AUCUNE MODIFICATION
666
+
667
+ **Important :** `FlowMap` étend `FlowState`, qui étend `FlowConstant`, qui implémente déjà `_getRaw()`. Aucune modification n'est nécessaire pour ce fichier.
668
+
669
+ ---
670
+
671
+ ## Changements dans le Fichier Creators
672
+
673
+ ### 15. Modifier `src/creators.ts`
674
+
675
+ **Changements :**
676
+ - Modifier les signatures de `derivation()` et `effect()`
677
+ - Supprimer les imports de `FlowGetter` et `FlowWatcher`
678
+ - Ajouter l'import de `TrackingContext`
679
+
680
+ **Imports - Avant :**
681
+ ```typescript
682
+ import type { FlowGetter, FlowWatcher } from "./basic/";
683
+ ```
684
+
685
+ **Imports - Après :**
686
+ ```typescript
687
+ import type { TrackingContext } from "./basic/";
688
+ ```
689
+
690
+ **Fonction `derivation()` - Avant :**
691
+ ```typescript
692
+ /**
693
+ * Creates a new reactive derivation whose value is computed based on other reactive signals.
694
+ * @typeParam T - The type of the derived value.
695
+ * @param fn - A function that computes the derived value. It receives a getter and a watcher
696
+ * function to access and register dependencies.
697
+ * @returns A new instance of {@link FlowDerivation}.
698
+ * @public
699
+ */
700
+ export function derivation<T>(
701
+ fn: (get: FlowGetter, watch: FlowWatcher) => T,
702
+ ): FlowDerivation<T> {
703
+ return new FlowDerivation(fn);
704
+ }
705
+ ```
706
+
707
+ **Fonction `derivation()` - Après :**
708
+ ```typescript
709
+ /**
710
+ * Creates a new reactive derivation whose value is computed based on other reactive signals.
711
+ * @typeParam T - The type of the derived value.
712
+ * @param fn - A function that computes the derived value using a tracking context.
713
+ * @returns A new instance of {@link FlowDerivation}.
714
+ * @public
715
+ */
716
+ export function derivation<T>(
717
+ fn: (t: TrackingContext) => T,
718
+ ): FlowDerivation<T> {
719
+ return new FlowDerivation(fn);
720
+ }
721
+ ```
722
+
723
+ **Fonction `effect()` - Avant :**
724
+ ```typescript
725
+ /**
726
+ * Creates a new reactive effect that executes a side-effect function based on its dependencies.
727
+ * @param fn - A function that performs side effects. It receives a getter and a watcher
728
+ * function for tracking reactive dependencies.
729
+ * @returns A new instance of {@link FlowEffect}.
730
+ * @public
731
+ */
732
+ export function effect(
733
+ fn: (get: FlowGetter, watch: FlowWatcher) => void,
734
+ ): FlowEffect {
735
+ return new FlowEffect(fn);
736
+ }
737
+ ```
738
+
739
+ **Fonction `effect()` - Après :**
740
+ ```typescript
741
+ /**
742
+ * Creates a new reactive effect that executes a side-effect function based on its dependencies.
743
+ * @param fn - A function that performs side effects using a tracking context.
744
+ * @returns A new instance of {@link FlowEffect}.
745
+ * @public
746
+ */
747
+ export function effect(
748
+ fn: (t: TrackingContext) => void,
749
+ ): FlowEffect {
750
+ return new FlowEffect(fn);
751
+ }
752
+ ```
753
+
754
+ **Note :** Les autres fonctions creator (`signal`, `state`, `constant`, `resource`, etc.) ne sont pas impactées.
755
+
756
+ ---
757
+
758
+ ## Changements dans les Fichiers Solid (Intégration SolidJS)
759
+
760
+ Les fichiers dans `src/solid/` sont des adaptateurs d'intégration entre PicoFlow et SolidJS. Ils convertissent les observables PicoFlow en primitives SolidJS.
761
+
762
+ ### 16. Modifier `src/solid/converters.ts`
763
+
764
+ Ce fichier nécessite plusieurs modifications pour utiliser la nouvelle API avec `TrackingContext`.
765
+
766
+ #### Imports
767
+
768
+ **Avant :**
769
+ ```typescript
770
+ import { FlowEffect, FlowObservable, type FlowGetter, FlowDerivation } from '../basic';
771
+ ```
772
+
773
+ **Après :**
774
+ ```typescript
775
+ import { FlowEffect, FlowObservable, type TrackingContext, FlowDerivation } from '../basic';
776
+ ```
777
+
778
+ #### Fonction `fromSync`
779
+
780
+ **Avant :**
781
+ ```typescript
782
+ function fromSync<T>(state: FlowObservable<T>): SolidDerivation<T> {
783
+ const solidState = new SolidState<T>(state.get());
784
+
785
+ let fx: FlowEffect;
786
+
787
+ onMount(() => {
788
+ fx = new FlowEffect((get) => {
789
+ const value = get(state);
790
+ solidState.set(() => value);
791
+ });
792
+ });
793
+
794
+ onCleanup(() => fx.dispose());
795
+
796
+ return solidState
797
+ }
798
+ ```
799
+
800
+ **Après :**
801
+ ```typescript
802
+ function fromSync<T>(state: FlowObservable<T>): SolidDerivation<T> {
803
+ const solidState = new SolidState<T>(state.pick()); // Lecture initiale non-réactive
804
+
805
+ let fx: FlowEffect;
806
+
807
+ onMount(() => {
808
+ fx = new FlowEffect((t) => { // t au lieu de get
809
+ const value = state.get(t); // state.get(t) au lieu de get(state)
810
+ solidState.set(() => value);
811
+ });
812
+ });
813
+
814
+ onCleanup(() => fx.dispose());
815
+
816
+ return solidState
817
+ }
818
+ ```
819
+
820
+ #### Fonction `fromAsync`
821
+
822
+ **Avant :**
823
+ ```typescript
824
+ function fromAsync<T>(derivation: FlowObservable<Promise<T>>): SolidResource<T> {
825
+ const solidResource = new SolidResource<T>(async () => {
826
+ const value = await derivation.get();
827
+ return value;
828
+ });
829
+
830
+ let fx: FlowEffect;
831
+
832
+ onMount(() => {
833
+ fx = new FlowEffect(async (get) => {
834
+ await get(derivation);
835
+ solidResource.refetch();
836
+ });
837
+ });
838
+
839
+ onCleanup(() => fx.dispose());
840
+
841
+ return solidResource;
842
+ }
843
+ ```
844
+
845
+ **Après :**
846
+ ```typescript
847
+ function fromAsync<T>(derivation: FlowObservable<Promise<T>>): SolidResource<T> {
848
+ const solidResource = new SolidResource<T>(async () => {
849
+ const value = await derivation.pick(); // pick() au lieu de get()
850
+ return value;
851
+ });
852
+
853
+ let fx: FlowEffect;
854
+
855
+ onMount(() => {
856
+ fx = new FlowEffect(async (t) => { // t au lieu de get
857
+ await derivation.get(t); // derivation.get(t) au lieu de get(derivation)
858
+ solidResource.refetch();
859
+ });
860
+ });
861
+
862
+ onCleanup(() => fx.dispose());
863
+
864
+ return solidResource;
865
+ }
866
+ ```
867
+
868
+ #### Fonction `shallowFrom`
869
+
870
+ **Changement :**
871
+ Remplacer `flow.get()` par `flow.pick()`
872
+
873
+ **Avant :**
874
+ ```typescript
875
+ function shallowFrom<T>(flow: FlowObservable<Promise<T>> | FlowObservable<T>): SolidDerivation<T> | SolidResource<T> {
876
+ const initialValue = flow.get();
877
+ // ...
878
+ }
879
+ ```
880
+
881
+ **Après :**
882
+ ```typescript
883
+ function shallowFrom<T>(flow: FlowObservable<Promise<T>> | FlowObservable<T>): SolidDerivation<T> | SolidResource<T> {
884
+ const initialValue = flow.pick(); // pick() au lieu de get()
885
+ // ...
886
+ }
887
+ ```
888
+
889
+ #### Fonction `deepFrom`
890
+
891
+ **Changements :**
892
+ - Signatures : `(get: FlowGetter)` → `(t: TrackingContext)`
893
+ - Implémentation : `(get) =>` → `(t) =>`
894
+ - Lecture : `derivation.get()` → `derivation.pick()`
895
+
896
+ **Avant :**
897
+ ```typescript
898
+ function deepFrom<T>(getter: (get: FlowGetter) => T): SolidDerivation<T>;
899
+ function deepFrom<T>(getter: (get: FlowGetter) => Promise<T>): SolidResource<T>;
900
+ function deepFrom<T>(getter: (get: FlowGetter) => T | Promise<T>): SolidDerivation<T> | SolidResource<T> {
901
+ const derivation = new FlowDerivation((get) => {
902
+ return getter(get);
903
+ });
904
+
905
+ const initialValue = derivation.get();
906
+ const isAsync = initialValue instanceof Promise;
907
+
908
+ if (isAsync) {
909
+ return fromAsync(derivation as FlowObservable<Promise<T>>);
910
+ }
911
+
912
+ return fromSync(derivation as FlowObservable<T>);
913
+ }
914
+ ```
915
+
916
+ **Après :**
917
+ ```typescript
918
+ function deepFrom<T>(getter: (t: TrackingContext) => T): SolidDerivation<T>;
919
+ function deepFrom<T>(getter: (t: TrackingContext) => Promise<T>): SolidResource<T>;
920
+ function deepFrom<T>(getter: (t: TrackingContext) => T | Promise<T>): SolidDerivation<T> | SolidResource<T> {
921
+ const derivation = new FlowDerivation((t) => {
922
+ return getter(t);
923
+ });
924
+
925
+ const initialValue = derivation.pick(); // pick() au lieu de get()
926
+ const isAsync = initialValue instanceof Promise;
927
+
928
+ if (isAsync) {
929
+ return fromAsync(derivation as FlowObservable<Promise<T>>);
930
+ }
931
+
932
+ return fromSync(derivation as FlowObservable<T>);
933
+ }
934
+ ```
935
+
936
+ #### Fonction `from` - Signatures TypeScript
937
+
938
+ Mettre à jour toutes les signatures qui utilisent `FlowGetter` :
939
+
940
+ **Avant :**
941
+ ```typescript
942
+ export function from<T>(flow: (get: FlowGetter) => NotPromise<T>): SolidDerivation<NotPromise<T>>;
943
+ export function from<T>(flow: (get: FlowGetter) => Promise<NotPromise<T>>): SolidResource<NotPromise<T>>;
944
+ export function from<T>(
945
+ flow: ((get: FlowGetter) => NotPromise<T>) | ((get: FlowGetter) => Promise<NotPromise<T>>),
946
+ ): SolidDerivation<T> | SolidResource<T>;
947
+ ```
948
+
949
+ **Après :**
950
+ ```typescript
951
+ export function from<T>(flow: (t: TrackingContext) => NotPromise<T>): SolidDerivation<NotPromise<T>>;
952
+ export function from<T>(flow: (t: TrackingContext) => Promise<NotPromise<T>>): SolidResource<NotPromise<T>>;
953
+ export function from<T>(
954
+ flow: ((t: TrackingContext) => NotPromise<T>) | ((t: TrackingContext) => Promise<NotPromise<T>>),
955
+ ): SolidDerivation<T> | SolidResource<T>;
956
+ ```
957
+
958
+ #### Fonction `from` - Implémentation
959
+
960
+ **Avant :**
961
+ ```typescript
962
+ export function from<T>(
963
+ flow: FlowObservable<Promise<T>> | FlowObservable<T> | ((get: FlowGetter) => T) | ((get: FlowGetter) => Promise<T>),
964
+ ): SolidDerivation<T> | SolidResource<T> {
965
+ if (flow instanceof FlowObservable) {
966
+ return shallowFrom(flow as FlowObservable<T | Promise<T>>) as SolidDerivation<T> | SolidResource<T>;
967
+ }
968
+
969
+ return deepFrom(flow as (get: FlowGetter) => T | Promise<T>) as SolidDerivation<T> | SolidResource<T>;
970
+ }
971
+ ```
972
+
973
+ **Après :**
974
+ ```typescript
975
+ export function from<T>(
976
+ flow: FlowObservable<Promise<T>> | FlowObservable<T> | ((t: TrackingContext) => T) | ((t: TrackingContext) => Promise<T>),
977
+ ): SolidDerivation<T> | SolidResource<T> {
978
+ if (flow instanceof FlowObservable) {
979
+ return shallowFrom(flow as FlowObservable<T | Promise<T>>) as SolidDerivation<T> | SolidResource<T>;
980
+ }
981
+
982
+ return deepFrom(flow as (t: TrackingContext) => T | Promise<T>) as SolidDerivation<T> | SolidResource<T>;
983
+ }
984
+ ```
985
+
986
+ **Résumé des changements dans converters.ts :**
987
+ - Import : `FlowGetter` → `TrackingContext`
988
+ - FlowEffect : `(get) =>` → `(t) =>`
989
+ - FlowDerivation : `(get) =>` → `(t) =>`
990
+ - Lecture réactive : `get(observable)` → `observable.get(t)`
991
+ - Lecture initiale : `observable.get()` → `observable.pick()`
992
+ - Toutes les signatures : `(get: FlowGetter)` → `(t: TrackingContext)`
993
+
994
+ ### 17. `src/solid/primitives.ts` - AUCUNE MODIFICATION
995
+
996
+ Ce fichier ne dépend que de SolidJS et n'utilise pas l'API PicoFlow. Aucune modification nécessaire.
997
+
998
+ ### 18. `src/solid/index.ts` - AUCUNE MODIFICATION
999
+
1000
+ Simple fichier d'exports. Aucune modification nécessaire.
1001
+
1002
+ ---
1003
+
1004
+ ## Migration des Tests
1005
+
1006
+ ### Pattern 1 : Effect simple avec get
1007
+
1008
+ **Avant :**
1009
+ ```typescript
1010
+ effect((get) => {
1011
+ const value = get($state);
1012
+ effectFn(value);
1013
+ });
1014
+ ```
1015
+
1016
+ **Après :**
1017
+ ```typescript
1018
+ effect((t) => {
1019
+ const value = $state.get(t);
1020
+ effectFn(value);
1021
+ });
1022
+ ```
1023
+
1024
+ ### Pattern 2 : Effect avec watch
1025
+
1026
+ **Avant :**
1027
+ ```typescript
1028
+ effect((get, watch) => {
1029
+ watch($signal);
1030
+ effectFn();
1031
+ });
1032
+ ```
1033
+
1034
+ **Après :**
1035
+ ```typescript
1036
+ effect((t) => {
1037
+ $signal.watch(t);
1038
+ effectFn();
1039
+ });
1040
+ ```
1041
+
1042
+ ### Pattern 3 : Derivation
1043
+
1044
+ **Avant :**
1045
+ ```typescript
1046
+ const $derived = derivation((get) => {
1047
+ return get($stateA) + get($stateB);
1048
+ });
1049
+ ```
1050
+
1051
+ **Après :**
1052
+ ```typescript
1053
+ const $derived = derivation((t) => {
1054
+ return $stateA.get(t) + $stateB.get(t);
1055
+ });
1056
+ ```
1057
+
1058
+ ### Pattern 4 : Nested states
1059
+
1060
+ **Avant :**
1061
+ ```typescript
1062
+ effect((get) => {
1063
+ const a = get(get($stateC).a);
1064
+ effectFn(a);
1065
+ });
1066
+ ```
1067
+
1068
+ **Après :**
1069
+ ```typescript
1070
+ effect((t) => {
1071
+ const a = $stateC.get(t).a.get(t);
1072
+ effectFn(a);
1073
+ });
1074
+ ```
1075
+
1076
+ ### Pattern 5 : Lecture non-réactive (nouveau)
1077
+
1078
+ **Après uniquement :**
1079
+ ```typescript
1080
+ effect((t) => {
1081
+ const tracked = $stateA.get(t); // Réactif
1082
+ const untracked = $stateB.pick(); // Non-réactif
1083
+ // ou
1084
+ const untracked2 = $stateB.get(null); // Non-réactif
1085
+
1086
+ effectFn(tracked, untracked);
1087
+ });
1088
+ ```
1089
+
1090
+ ### Pattern 6 : Subscribe (modification mineure)
1091
+
1092
+ Les `subscribe` sont impactés car ils utilisent des effects en interne.
1093
+
1094
+ **Avant :**
1095
+ ```typescript
1096
+ $state.subscribe((value) => {
1097
+ console.log(value);
1098
+ });
1099
+ ```
1100
+
1101
+ **Après :**
1102
+ ```typescript
1103
+ // Le code reste identique pour l'utilisateur
1104
+ $state.subscribe((value) => {
1105
+ console.log(value);
1106
+ });
1107
+
1108
+ // Mais en interne, la méthode a changé (voir src/basic/observable.ts)
1109
+ ```
1110
+
1111
+ ### Pattern 7 : Utilisation des classes Advanced
1112
+
1113
+ Les classes advanced (`FlowArray`, `FlowResource`, `FlowStream`, etc.) héritent automatiquement de la nouvelle API.
1114
+
1115
+ **Avant :**
1116
+ ```typescript
1117
+ const $items = array([1, 2, 3]);
1118
+
1119
+ effect((get) => {
1120
+ const items = get($items);
1121
+ console.log(items.length);
1122
+ });
1123
+ ```
1124
+
1125
+ **Après :**
1126
+ ```typescript
1127
+ const $items = array([1, 2, 3]);
1128
+
1129
+ effect((t) => {
1130
+ const items = $items.get(t); // Réactif
1131
+ // ou
1132
+ const items2 = $items.pick(); // Non-réactif
1133
+ console.log(items.length);
1134
+ });
1135
+ ```
1136
+
1137
+ **Nouveau : Accès mixte dans les collections**
1138
+ ```typescript
1139
+ const $users = array<User>([]);
1140
+
1141
+ effect((t) => {
1142
+ // Réagir aux changements du tableau
1143
+ const users = $users.get(t);
1144
+
1145
+ // Mais lire les propriétés des users sans réagir à leurs changements
1146
+ users.forEach(user => {
1147
+ console.log(user.$name.pick()); // Non-réactif
1148
+ });
1149
+ });
1150
+ ```
1151
+
1152
+ ---
1153
+
1154
+ ## Exemples Complets de Migration
1155
+
1156
+ ### Exemple 1 : state.test.ts - Test "nested states"
1157
+
1158
+ **Avant :**
1159
+ ```typescript
1160
+ test("nested states", ()=> {
1161
+ const $stateA = state(1);
1162
+ const $stateB = state(2);
1163
+ const $stateC = state({
1164
+ a: $stateA,
1165
+ b: $stateB,
1166
+ });
1167
+
1168
+ const effectFn = vi.fn();
1169
+ effect((get) => {
1170
+ const a = get(get($stateC).a);
1171
+ effectFn(a)
1172
+ });
1173
+
1174
+ expect(effectFn).toHaveBeenCalledTimes(1);
1175
+ expect(effectFn).toHaveBeenLastCalledWith(1);
1176
+ })
1177
+ ```
1178
+
1179
+ **Après :**
1180
+ ```typescript
1181
+ test("nested states", ()=> {
1182
+ const $stateA = state(1);
1183
+ const $stateB = state(2);
1184
+ const $stateC = state({
1185
+ a: $stateA,
1186
+ b: $stateB,
1187
+ });
1188
+
1189
+ const effectFn = vi.fn();
1190
+ effect((t) => {
1191
+ const a = $stateC.get(t).a.get(t);
1192
+ effectFn(a)
1193
+ });
1194
+
1195
+ expect(effectFn).toHaveBeenCalledTimes(1);
1196
+ expect(effectFn).toHaveBeenLastCalledWith(1);
1197
+ })
1198
+ ```
1199
+
1200
+ ### Exemple 2 : Derivation complexe
1201
+
1202
+ **Avant :**
1203
+ ```typescript
1204
+ const $fullName = derivation((get) => {
1205
+ const firstName = get($firstName);
1206
+ const lastName = get($lastName);
1207
+ return `${firstName} ${lastName}`;
1208
+ });
1209
+ ```
1210
+
1211
+ **Après :**
1212
+ ```typescript
1213
+ const $fullName = derivation((t) => {
1214
+ const firstName = $firstName.get(t);
1215
+ const lastName = $lastName.get(t);
1216
+ return `${firstName} ${lastName}`;
1217
+ });
1218
+ ```
1219
+
1220
+ ### Exemple 3 : Effect avec lecture mixte
1221
+
1222
+ **Nouveau pattern possible :**
1223
+ ```typescript
1224
+ // Réagir uniquement à $trigger, mais lire $data sans créer de dépendance
1225
+ effect((t) => {
1226
+ $trigger.watch(t); // Crée une dépendance
1227
+ const data = $data.pick(); // Ne crée PAS de dépendance
1228
+ console.log("Triggered with data:", data);
1229
+ });
1230
+ ```
1231
+
1232
+ ### Exemple 4 : FlowArray avec effet
1233
+
1234
+ **Avant :**
1235
+ ```typescript
1236
+ const $items = array([1, 2, 3]);
1237
+
1238
+ effect((get) => {
1239
+ const items = get($items);
1240
+ console.log("Array length:", items.length);
1241
+ });
1242
+
1243
+ $items.push(4); // L'effect se déclenche
1244
+ ```
1245
+
1246
+ **Après :**
1247
+ ```typescript
1248
+ const $items = array([1, 2, 3]);
1249
+
1250
+ effect((t) => {
1251
+ const items = $items.get(t);
1252
+ console.log("Array length:", items.length);
1253
+ });
1254
+
1255
+ $items.push(4); // L'effect se déclenche
1256
+ ```
1257
+
1258
+ ### Exemple 5 : FlowResource avec dérivation
1259
+
1260
+ **Avant :**
1261
+ ```typescript
1262
+ const $user = resource(() => fetchUser());
1263
+
1264
+ const $userName = derivation((get) => {
1265
+ const user = get($user);
1266
+ return user?.name ?? "Unknown";
1267
+ });
1268
+
1269
+ effect((get) => {
1270
+ console.log(get($userName));
1271
+ });
1272
+ ```
1273
+
1274
+ **Après :**
1275
+ ```typescript
1276
+ const $user = resource(() => fetchUser());
1277
+
1278
+ const $userName = derivation((t) => {
1279
+ const user = $user.get(t);
1280
+ return user?.name ?? "Unknown";
1281
+ });
1282
+
1283
+ effect((t) => {
1284
+ console.log($userName.get(t));
1285
+ });
1286
+ ```
1287
+
1288
+ ### Exemple 6 : FlowStream avec tracking sélectif
1289
+
1290
+ **Nouveau pattern :**
1291
+ ```typescript
1292
+ const $messages = stream<string>((set) => {
1293
+ const ws = new WebSocket("ws://...");
1294
+ ws.onmessage = (e) => set(e.data);
1295
+ return () => ws.close();
1296
+ });
1297
+
1298
+ const $config = state({ showLogs: true });
1299
+
1300
+ effect((t) => {
1301
+ const message = $messages.get(t); // Réactif aux messages
1302
+ const config = $config.pick(); // Non-réactif au config
1303
+
1304
+ if (config.showLogs) {
1305
+ console.log(message);
1306
+ }
1307
+ });
1308
+ ```
1309
+
1310
+ ### Exemple 7 : Intégration SolidJS avec from()
1311
+
1312
+ **Avant :**
1313
+ ```typescript
1314
+ import { from } from 'picoflow/solid';
1315
+
1316
+ const $picoState = state(42);
1317
+
1318
+ // Convertir en SolidJS
1319
+ const solidSignal = from($picoState);
1320
+
1321
+ // Ou avec une fonction getter
1322
+ const solidDerived = from((get) => {
1323
+ return get($stateA) + get($stateB);
1324
+ });
1325
+ ```
1326
+
1327
+ **Après :**
1328
+ ```typescript
1329
+ import { from } from 'picoflow/solid';
1330
+
1331
+ const $picoState = state(42);
1332
+
1333
+ // Convertir en SolidJS
1334
+ const solidSignal = from($picoState);
1335
+
1336
+ // Ou avec une fonction getter utilisant TrackingContext
1337
+ const solidDerived = from((t) => {
1338
+ return $stateA.get(t) + $stateB.get(t);
1339
+ });
1340
+ ```
1341
+
1342
+ ---
1343
+
1344
+ ## Checklist de Migration
1345
+
1346
+ ### Fichiers source - Basic
1347
+
1348
+ - [ ] Créer `src/basic/trackingContext.ts`
1349
+ - [ ] Modifier `src/basic/signal.ts`
1350
+ - [ ] Ajouter import `TrackingContext`
1351
+ - [ ] Ajouter méthode `watch(context: TrackingContext)`
1352
+ - [ ] Supprimer type `FlowWatcher`
1353
+ - [ ] Supprimer méthode `_watch()`
1354
+ - [ ] Supprimer méthode `_watchFrom()`
1355
+ - [ ] Modifier `src/basic/observable.ts`
1356
+ - [ ] Ajouter import `TrackingContext`
1357
+ - [ ] Remplacer `abstract get()` par `get(context: TrackingContext | null)`
1358
+ - [ ] Ajouter méthode `pick()`
1359
+ - [ ] Ajouter `abstract _getRaw()`
1360
+ - [ ] Supprimer type `FlowGetter`
1361
+ - [ ] Supprimer méthode `_getFrom`
1362
+ - [ ] Mettre à jour `subscribe` pour utiliser `(t) =>` au lieu de `(get) =>`
1363
+ - [ ] Modifier `src/basic/constant.ts`
1364
+ - [ ] Remplacer `get()` par `protected _getRaw()`
1365
+ - [ ] Modifier `src/basic/derivation.ts`
1366
+ - [ ] Ajouter import `TrackingContext`
1367
+ - [ ] Changer signature du constructeur
1368
+ - [ ] Remplacer logique de tracking
1369
+ - [ ] Remplacer `get()` par `_getRaw()`
1370
+ - [ ] Override la méthode `watch(context)` pour gérer le compute lazy
1371
+ - [ ] Modifier `src/basic/effect.ts`
1372
+ - [ ] Ajouter import `TrackingContext`
1373
+ - [ ] Changer signature du constructeur
1374
+ - [ ] Simplifier logique d'exécution
1375
+ - [ ] Supprimer `_initialized`
1376
+ - [ ] Modifier `src/basic/index.ts`
1377
+ - [ ] Ajouter export de `TrackingContext`
1378
+ - [ ] Supprimer exports de `FlowGetter` et `FlowWatcher`
1379
+
1380
+ ### Fichiers source - Advanced
1381
+
1382
+ - [ ] Modifier `src/advanced/resource.ts`
1383
+ - [ ] Remplacer `public get()` par `protected _getRaw()`
1384
+ - [ ] Modifier `src/advanced/resourceAsync.ts`
1385
+ - [ ] Remplacer `public get()` par `protected _getRaw()`
1386
+ - [ ] Modifier `src/advanced/array.ts`
1387
+ - [ ] Remplacer `get()` par `protected _getRaw()`
1388
+ - [ ] Modifier `src/advanced/stream.ts`
1389
+ - [ ] Remplacer `public get()` par `protected _getRaw()`
1390
+ - [ ] Modifier `src/advanced/streamAsync.ts`
1391
+ - [ ] Remplacer `public get()` par `protected _getRaw()`
1392
+ - [ ] Vérifier `src/advanced/map.ts` (aucune modification nécessaire)
1393
+
1394
+ ### Fichiers source - Creators
1395
+
1396
+ - [ ] Modifier `src/creators.ts`
1397
+ - [ ] Supprimer import de `FlowGetter` et `FlowWatcher`
1398
+ - [ ] Ajouter import de `TrackingContext`
1399
+ - [ ] Modifier signature de `derivation()` : `(get, watch) => T` → `(t) => T`
1400
+ - [ ] Modifier signature de `effect()` : `(get, watch) => void` → `(t) => void`
1401
+
1402
+ ### Fichiers source - Solid (Intégration SolidJS)
1403
+
1404
+ - [ ] Modifier `src/solid/converters.ts`
1405
+ - [ ] Modifier import : `FlowGetter` → `TrackingContext`
1406
+ - [ ] Modifier fonction `fromSync` : `(get) =>` → `(t) =>` et `state.get()` → `state.pick()`
1407
+ - [ ] Modifier fonction `fromAsync` : `(get) =>` → `(t) =>` et `derivation.get()` → `derivation.pick()`
1408
+ - [ ] Modifier fonction `shallowFrom` : `flow.get()` → `flow.pick()`
1409
+ - [ ] Modifier fonction `deepFrom` : signatures et implémentation avec `TrackingContext`
1410
+ - [ ] Modifier fonction `from` : toutes les signatures `FlowGetter` → `TrackingContext`
1411
+ - [ ] Vérifier `src/solid/primitives.ts` (aucune modification nécessaire)
1412
+ - [ ] Vérifier `src/solid/index.ts` (aucune modification nécessaire)
1413
+
1414
+ ### Tests - Basic
1415
+
1416
+ - [ ] Migrer tous les tests de `test/state.test.ts`
1417
+ - [ ] Migrer tous les tests de `test/effect.test.ts`
1418
+ - [ ] Migrer tous les tests de `test/derivation.test.ts`
1419
+ - [ ] Migrer tous les tests de `test/signal.test.ts`
1420
+ - [ ] Migrer tous les tests de `test/constant.test.ts`
1421
+
1422
+ ### Tests - Advanced
1423
+
1424
+ - [ ] Migrer tous les tests de `test/array.test.ts`
1425
+ - [ ] Migrer tous les tests de `test/map.test.ts`
1426
+ - [ ] Migrer tous les tests de `test/resource.test.ts`
1427
+ - [ ] Migrer tous les tests de `test/resourceAsync.test.ts`
1428
+ - [ ] Migrer tous les tests de `test/stream.test.ts`
1429
+ - [ ] Migrer tous les tests de `test/streamAsync.test.ts`
1430
+
1431
+ ### Vérifications
1432
+
1433
+ - [ ] Tous les tests passent
1434
+ - [ ] Aucune erreur TypeScript
1435
+ - [ ] La documentation API est à jour
1436
+ - [ ] Exécuter `npm run build` avec succès
1437
+ - [ ] Exécuter les linters sans erreurs
1438
+
1439
+ ---
1440
+
1441
+ ## Points d'Attention
1442
+
1443
+ ### 0. Architecture simplifiée - Pas de méthode interne `_watch()`
1444
+
1445
+ **Design simplifié** : Dans cette migration, nous supprimons complètement les méthodes internes `_watch()` et `_watchFrom()` qui existaient dans le code original. À la place, nous utilisons des overrides directs de la méthode publique `watch()`.
1446
+
1447
+ **Pourquoi FlowDerivation override-t-elle `watch()` ?**
1448
+
1449
+ Pour gérer le cas où on track une derivation sans lire sa valeur :
1450
+
1451
+ ```typescript
1452
+ effect((t) => {
1453
+ $myDerivation.watch(t); // On track la derivation sans lire sa valeur
1454
+ // La derivation DOIT quand même computer pour établir SES dépendances
1455
+ });
1456
+ ```
1457
+
1458
+ **Architecture :**
1459
+ - `FlowSignal.watch(context)` : Enregistre simplement la dépendance
1460
+ - `FlowDerivation.watch(context)` : Override qui appelle `super.watch()` + initialise et compute
1461
+
1462
+ Cette approche est plus simple et plus directe que d'utiliser une méthode interne `_watch()` qui serait appelée par `watch()` puis overridée dans les sous-classes.
1463
+
1464
+ ### 1. Comportement des Effects
1465
+
1466
+ **Important** : Le comportement des effects change légèrement. Avant, ils n'étaient "tracked" que lors de la première exécution. Maintenant, ils sont toujours exécutés avec un contexte de tracking, mais c'est à l'utilisateur de décider explicitement quoi tracker avec `.get(t)` vs `.pick()`.
1467
+
1468
+ ### 2. Lecture non-réactive
1469
+
1470
+ La nouvelle API permet explicitement des lectures non-réactives dans les contexts réactifs :
1471
+ ```typescript
1472
+ effect((t) => {
1473
+ const reactive = $state.get(t); // Crée une dépendance
1474
+ const snapshot = $other.pick(); // Ne crée PAS de dépendance
1475
+ });
1476
+ ```
1477
+
1478
+ ### 3. Chaînage
1479
+
1480
+ Le chaînage devient plus fluide :
1481
+ ```typescript
1482
+ // Avant
1483
+ const nested = get(get($parent).child);
1484
+
1485
+ // Après
1486
+ const nested = $parent.get(t).child.get(t);
1487
+ ```
1488
+
1489
+ ### 4. Types TypeScript
1490
+
1491
+ Les types `FlowGetter` et `FlowWatcher` sont supprimés. Si du code utilisateur les référence, il faudra les remplacer par `TrackingContext`.
1492
+
1493
+ ### 5. Classes Advanced
1494
+
1495
+ Toutes les classes advanced bénéficient automatiquement de la nouvelle API :
1496
+ - `FlowResource`, `FlowResourceAsync` → supportent `get(t)` et `pick()`
1497
+ - `FlowArray` → supporte `get(t)` et `pick()` pour l'accès au tableau
1498
+ - `FlowStream`, `FlowStreamAsync` → supportent `get(t)` et `pick()`
1499
+ - `FlowMap` → pas de changement nécessaire (hérite via FlowState)
1500
+
1501
+ Cela offre un contrôle granulaire sur la réactivité dans les structures de données complexes.
1502
+
1503
+ ### 6. Ordre de Migration
1504
+
1505
+ **Ordre recommandé :**
1506
+ 1. Fichiers `basic/` (fondation)
1507
+ 2. Fichiers `advanced/` (extensions des basic)
1508
+ 3. Fichier `creators.ts` (factory functions)
1509
+ 4. Fichiers `solid/` (intégration SolidJS, dépend de basic)
1510
+ 5. Tests
1511
+
1512
+ Cette séquence assure que chaque couche est migrée avant celle qui en dépend. Les fichiers `solid/` peuvent être migrés en parallèle avec `creators.ts` car ils dépendent tous deux des fichiers `basic/` mais pas l'un de l'autre.
1513
+
1514
+ ### 7. Intégration SolidJS
1515
+
1516
+ Les fichiers `src/solid/` fournissent une intégration avec SolidJS via la fonction `from()`. Cette fonction accepte soit :
1517
+ - Un `FlowObservable` directement → converti en SolidDerivation ou SolidResource
1518
+ - Une fonction getter avec `TrackingContext` → crée une dérivation PicoFlow puis la convertit
1519
+
1520
+ **Important** : Les lectures initiales (pour déterminer sync vs async) utilisent `pick()` car elles ne doivent pas être réactives. Les lectures réactives dans les effects utilisent `get(t)`.
1521
+
1522
+ ### 8. Compatibilité
1523
+
1524
+ Cette migration casse **complètement** l'API publique. C'est un changement majeur de version (v2.0.0).
1525
+
1526
+ ---
1527
+
1528
+ ## Commandes de Vérification
1529
+
1530
+ Après migration, exécuter ces commandes :
1531
+
1532
+ ```bash
1533
+ # Vérifier les types TypeScript
1534
+ npx tsc --noEmit
1535
+
1536
+ # Exécuter les tests
1537
+ npm test
1538
+
1539
+ # Build
1540
+ npm run build
1541
+
1542
+ # Linter
1543
+ npm run lint
1544
+ ```
1545
+
1546
+ ---
1547
+
1548
+ ## Support
1549
+
1550
+ Si vous rencontrez des patterns non couverts par ce guide, référez-vous aux principes de base :
1551
+ - `get(t)` = lecture réactive
1552
+ - `pick()` ou `get(null)` = lecture non-réactive
1553
+ - `watch(t)` = enregistrement de dépendance réactive (signaux uniquement)
1554
+
1555
+ **Ces principes s'appliquent à TOUTES les classes** :
1556
+ - Classes basic : `FlowSignal`, `FlowConstant`, `FlowState`, `FlowDerivation`
1557
+ - Classes advanced : `FlowArray`, `FlowMap`, `FlowResource`, `FlowResourceAsync`, `FlowStream`, `FlowStreamAsync`
1558
+ - Effects et derivations : utilisent `TrackingContext` au lieu de `get`/`watch`
1559
+ - Intégration Solid : `converters.ts` utilise `TrackingContext` dans `from()` et ses helpers
1560
+
1561
+ ## Résumé de la Migration
1562
+
1563
+ Ce guide couvre la migration complète de PicoFlow vers une API basée sur le contexte de tracking :
1564
+
1565
+ ✅ **17 fichiers source** modifiés ou créés (1 créé + 16 modifiés)
1566
+ ✅ **11 fichiers de tests** à migrer
1567
+ ✅ **Architecture simplifiée** avec moins de méthodes internes
1568
+ ✅ **API unifiée** pour toutes les classes (basic, advanced, solid)
1569
+ ✅ **Contrôle granulaire** de la réactivité avec `get(t)` vs `pick()`
1570
+ ✅ **Intégration SolidJS** mise à jour pour utiliser TrackingContext
1571
+
1572
+ **Détails des fichiers :**
1573
+ - 1 nouveau : `trackingContext.ts`
1574
+ - 16 modifiés : 7 basic + 5 advanced + 1 creators + 1 solid + 2 index
1575
+ - 3 sans modification : `map.ts`, `solid/primitives.ts`, `solid/index.ts`
1576
+
1577
+ **Temps estimé :** 2-4 heures pour une migration complète avec tests.
1578
+