@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.
- package/.cursor/plans/update-js-e795d61b.plan.md +567 -0
- package/.gitlab-ci.yml +24 -0
- package/.vscode/settings.json +3 -3
- package/CHANGELOG.md +51 -0
- package/IMPLEMENTATION_GUIDE.md +1578 -0
- package/README.md +9 -134
- package/biome.json +32 -32
- package/dist/picoflow.js +610 -436
- package/dist/types/advanced/array.d.ts +0 -6
- package/dist/types/advanced/array.d.ts.map +1 -1
- package/dist/types/advanced/index.d.ts +5 -5
- package/dist/types/advanced/index.d.ts.map +1 -1
- package/dist/types/advanced/map.d.ts +114 -23
- package/dist/types/advanced/map.d.ts.map +1 -1
- package/dist/types/advanced/resource.d.ts +51 -12
- package/dist/types/advanced/resource.d.ts.map +1 -1
- package/dist/types/advanced/resourceAsync.d.ts +28 -13
- package/dist/types/advanced/resourceAsync.d.ts.map +1 -1
- package/dist/types/advanced/stream.d.ts +74 -16
- package/dist/types/advanced/stream.d.ts.map +1 -1
- package/dist/types/advanced/streamAsync.d.ts +69 -15
- package/dist/types/advanced/streamAsync.d.ts.map +1 -1
- package/dist/types/basic/constant.d.ts +44 -16
- package/dist/types/basic/constant.d.ts.map +1 -1
- package/dist/types/basic/derivation.d.ts +73 -24
- package/dist/types/basic/derivation.d.ts.map +1 -1
- package/dist/types/basic/disposable.d.ts +65 -6
- package/dist/types/basic/disposable.d.ts.map +1 -1
- package/dist/types/basic/effect.d.ts +27 -16
- package/dist/types/basic/effect.d.ts.map +1 -1
- package/dist/types/basic/index.d.ts +7 -8
- package/dist/types/basic/index.d.ts.map +1 -1
- package/dist/types/basic/observable.d.ts +62 -13
- package/dist/types/basic/observable.d.ts.map +1 -1
- package/dist/types/basic/signal.d.ts +35 -6
- package/dist/types/basic/signal.d.ts.map +1 -1
- package/dist/types/basic/state.d.ts +25 -4
- package/dist/types/basic/state.d.ts.map +1 -1
- package/dist/types/basic/trackingContext.d.ts +33 -0
- package/dist/types/basic/trackingContext.d.ts.map +1 -0
- package/dist/types/creators.d.ts +271 -26
- package/dist/types/creators.d.ts.map +1 -1
- package/dist/types/index.d.ts +60 -7
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/solid/converters.d.ts +5 -5
- package/dist/types/solid/converters.d.ts.map +1 -1
- package/dist/types/solid/index.d.ts +2 -2
- package/dist/types/solid/index.d.ts.map +1 -1
- package/dist/types/solid/primitives.d.ts +96 -4
- package/dist/types/solid/primitives.d.ts.map +1 -1
- package/docs/.vitepress/config.mts +110 -0
- package/docs/api/classes/FlowArray.md +489 -0
- package/docs/api/classes/FlowConstant.md +350 -0
- package/docs/api/classes/FlowDerivation.md +334 -0
- package/docs/api/classes/FlowEffect.md +100 -0
- package/docs/api/classes/FlowMap.md +512 -0
- package/docs/api/classes/FlowObservable.md +306 -0
- package/docs/api/classes/FlowResource.md +380 -0
- package/docs/api/classes/FlowResourceAsync.md +362 -0
- package/docs/api/classes/FlowSignal.md +160 -0
- package/docs/api/classes/FlowState.md +368 -0
- package/docs/api/classes/FlowStream.md +367 -0
- package/docs/api/classes/FlowStreamAsync.md +364 -0
- package/docs/api/classes/SolidDerivation.md +75 -0
- package/docs/api/classes/SolidResource.md +91 -0
- package/docs/api/classes/SolidState.md +71 -0
- package/docs/api/classes/TrackingContext.md +33 -0
- package/docs/api/functions/array.md +58 -0
- package/docs/api/functions/constant.md +45 -0
- package/docs/api/functions/derivation.md +53 -0
- package/docs/api/functions/effect.md +49 -0
- package/docs/api/functions/from.md +220 -0
- package/docs/api/functions/isDisposable.md +49 -0
- package/docs/api/functions/map.md +57 -0
- package/docs/api/functions/resource.md +52 -0
- package/docs/api/functions/resourceAsync.md +50 -0
- package/docs/api/functions/signal.md +36 -0
- package/docs/api/functions/state.md +47 -0
- package/docs/api/functions/stream.md +53 -0
- package/docs/api/functions/streamAsync.md +50 -0
- package/docs/api/index.md +118 -0
- package/docs/api/interfaces/FlowDisposable.md +65 -0
- package/docs/api/interfaces/SolidObservable.md +19 -0
- package/docs/api/type-aliases/FlowArrayAction.md +49 -0
- package/docs/api/type-aliases/FlowStreamDisposer.md +15 -0
- package/docs/api/type-aliases/FlowStreamSetter.md +27 -0
- package/docs/api/type-aliases/FlowStreamUpdater.md +32 -0
- package/docs/api/type-aliases/NotPromise.md +18 -0
- package/docs/api/type-aliases/SolidGetter.md +17 -0
- package/docs/api/typedoc-sidebar.json +1 -0
- package/docs/examples/examples.md +2313 -0
- package/docs/examples/patterns.md +649 -0
- package/docs/guide/advanced/disposal.md +426 -0
- package/docs/guide/advanced/solidjs.md +221 -0
- package/docs/guide/advanced/upgrading.md +464 -0
- package/docs/guide/introduction/concepts.md +56 -0
- package/docs/guide/introduction/conventions.md +61 -0
- package/docs/guide/introduction/getting-started.md +134 -0
- package/docs/guide/introduction/lifecycle.md +371 -0
- package/docs/guide/primitives/array.md +400 -0
- package/docs/guide/primitives/constant.md +380 -0
- package/docs/guide/primitives/derivations.md +348 -0
- package/docs/guide/primitives/effects.md +458 -0
- package/docs/guide/primitives/map.md +387 -0
- package/docs/guide/primitives/overview.md +175 -0
- package/docs/guide/primitives/resources.md +858 -0
- package/docs/guide/primitives/signal.md +259 -0
- package/docs/guide/primitives/state.md +368 -0
- package/docs/guide/primitives/streams.md +931 -0
- package/docs/index.md +47 -0
- package/docs/public/logo.svg +1 -0
- package/package.json +57 -41
- package/src/advanced/array.ts +208 -210
- package/src/advanced/index.ts +7 -7
- package/src/advanced/map.ts +178 -68
- package/src/advanced/resource.ts +87 -43
- package/src/advanced/resourceAsync.ts +62 -42
- package/src/advanced/stream.ts +113 -50
- package/src/advanced/streamAsync.ts +120 -61
- package/src/basic/constant.ts +82 -49
- package/src/basic/derivation.ts +128 -84
- package/src/basic/disposable.ts +74 -15
- package/src/basic/effect.ts +85 -77
- package/src/basic/index.ts +7 -8
- package/src/basic/observable.ts +94 -36
- package/src/basic/signal.ts +133 -105
- package/src/basic/state.ts +46 -25
- package/src/basic/trackingContext.ts +45 -0
- package/src/creators.ts +297 -54
- package/src/index.ts +96 -43
- package/src/solid/converters.ts +186 -67
- package/src/solid/index.ts +8 -2
- package/src/solid/primitives.ts +167 -65
- package/test/array.test.ts +592 -612
- package/test/constant.test.ts +31 -33
- package/test/derivation.test.ts +531 -536
- package/test/effect.test.ts +21 -21
- package/test/map.test.ts +233 -137
- package/test/resource.test.ts +119 -121
- package/test/resourceAsync.test.ts +98 -100
- package/test/signal.test.ts +51 -55
- package/test/state.test.ts +186 -168
- package/test/stream.test.ts +189 -189
- package/test/streamAsync.test.ts +186 -186
- package/tsconfig.json +19 -18
- package/typedoc.json +37 -0
- package/vite.config.ts +23 -23
- package/vitest.config.ts +7 -7
- package/api/doc/index.md +0 -31
- package/api/doc/picoflow.array.md +0 -55
- package/api/doc/picoflow.constant.md +0 -55
- package/api/doc/picoflow.derivation.md +0 -55
- package/api/doc/picoflow.effect.md +0 -55
- package/api/doc/picoflow.flowarray._constructor_.md +0 -49
- package/api/doc/picoflow.flowarray._lastaction.md +0 -13
- package/api/doc/picoflow.flowarray.clear.md +0 -17
- package/api/doc/picoflow.flowarray.dispose.md +0 -55
- package/api/doc/picoflow.flowarray.get.md +0 -19
- package/api/doc/picoflow.flowarray.length.md +0 -13
- package/api/doc/picoflow.flowarray.md +0 -273
- package/api/doc/picoflow.flowarray.pop.md +0 -17
- package/api/doc/picoflow.flowarray.push.md +0 -53
- package/api/doc/picoflow.flowarray.set.md +0 -53
- package/api/doc/picoflow.flowarray.setitem.md +0 -69
- package/api/doc/picoflow.flowarray.shift.md +0 -17
- package/api/doc/picoflow.flowarray.splice.md +0 -85
- package/api/doc/picoflow.flowarray.unshift.md +0 -53
- package/api/doc/picoflow.flowarrayaction.md +0 -37
- package/api/doc/picoflow.flowconstant._constructor_.md +0 -49
- package/api/doc/picoflow.flowconstant.get.md +0 -25
- package/api/doc/picoflow.flowconstant.md +0 -88
- package/api/doc/picoflow.flowderivation._constructor_.md +0 -49
- package/api/doc/picoflow.flowderivation.get.md +0 -23
- package/api/doc/picoflow.flowderivation.md +0 -86
- package/api/doc/picoflow.flowdisposable.dispose.md +0 -55
- package/api/doc/picoflow.flowdisposable.md +0 -43
- package/api/doc/picoflow.floweffect._constructor_.md +0 -54
- package/api/doc/picoflow.floweffect.dispose.md +0 -21
- package/api/doc/picoflow.floweffect.disposed.md +0 -13
- package/api/doc/picoflow.floweffect.md +0 -131
- package/api/doc/picoflow.flowgetter.md +0 -15
- package/api/doc/picoflow.flowmap._lastdeleted.md +0 -21
- package/api/doc/picoflow.flowmap._lastset.md +0 -21
- package/api/doc/picoflow.flowmap.delete.md +0 -61
- package/api/doc/picoflow.flowmap.md +0 -133
- package/api/doc/picoflow.flowmap.setat.md +0 -77
- package/api/doc/picoflow.flowobservable.get.md +0 -19
- package/api/doc/picoflow.flowobservable.md +0 -68
- package/api/doc/picoflow.flowobservable.subscribe.md +0 -55
- package/api/doc/picoflow.flowresource._constructor_.md +0 -49
- package/api/doc/picoflow.flowresource.fetch.md +0 -27
- package/api/doc/picoflow.flowresource.get.md +0 -23
- package/api/doc/picoflow.flowresource.md +0 -100
- package/api/doc/picoflow.flowresourceasync._constructor_.md +0 -49
- package/api/doc/picoflow.flowresourceasync.fetch.md +0 -27
- package/api/doc/picoflow.flowresourceasync.get.md +0 -23
- package/api/doc/picoflow.flowresourceasync.md +0 -100
- package/api/doc/picoflow.flowsignal.dispose.md +0 -59
- package/api/doc/picoflow.flowsignal.disposed.md +0 -18
- package/api/doc/picoflow.flowsignal.md +0 -112
- package/api/doc/picoflow.flowsignal.trigger.md +0 -21
- package/api/doc/picoflow.flowstate.md +0 -52
- package/api/doc/picoflow.flowstate.set.md +0 -61
- package/api/doc/picoflow.flowstream._constructor_.md +0 -49
- package/api/doc/picoflow.flowstream.dispose.md +0 -21
- package/api/doc/picoflow.flowstream.get.md +0 -23
- package/api/doc/picoflow.flowstream.md +0 -100
- package/api/doc/picoflow.flowstreamasync._constructor_.md +0 -54
- package/api/doc/picoflow.flowstreamasync.dispose.md +0 -21
- package/api/doc/picoflow.flowstreamasync.get.md +0 -23
- package/api/doc/picoflow.flowstreamasync.md +0 -100
- package/api/doc/picoflow.flowstreamdisposer.md +0 -13
- package/api/doc/picoflow.flowstreamsetter.md +0 -13
- package/api/doc/picoflow.flowstreamupdater.md +0 -19
- package/api/doc/picoflow.flowwatcher.md +0 -15
- package/api/doc/picoflow.from.md +0 -55
- package/api/doc/picoflow.from_1.md +0 -55
- package/api/doc/picoflow.from_2.md +0 -55
- package/api/doc/picoflow.from_3.md +0 -55
- package/api/doc/picoflow.from_4.md +0 -55
- package/api/doc/picoflow.from_5.md +0 -55
- package/api/doc/picoflow.isdisposable.md +0 -55
- package/api/doc/picoflow.map.md +0 -59
- package/api/doc/picoflow.md +0 -544
- package/api/doc/picoflow.resource.md +0 -55
- package/api/doc/picoflow.resourceasync.md +0 -55
- package/api/doc/picoflow.signal.md +0 -19
- package/api/doc/picoflow.solidderivation._constructor_.md +0 -49
- package/api/doc/picoflow.solidderivation.get.md +0 -13
- package/api/doc/picoflow.solidderivation.md +0 -94
- package/api/doc/picoflow.solidgetter.md +0 -13
- package/api/doc/picoflow.solidobservable.get.md +0 -13
- package/api/doc/picoflow.solidobservable.md +0 -57
- package/api/doc/picoflow.solidresource._constructor_.md +0 -49
- package/api/doc/picoflow.solidresource.get.md +0 -13
- package/api/doc/picoflow.solidresource.latest.md +0 -13
- package/api/doc/picoflow.solidresource.md +0 -157
- package/api/doc/picoflow.solidresource.refetch.md +0 -13
- package/api/doc/picoflow.solidresource.state.md +0 -13
- package/api/doc/picoflow.solidstate._constructor_.md +0 -49
- package/api/doc/picoflow.solidstate.get.md +0 -13
- package/api/doc/picoflow.solidstate.md +0 -115
- package/api/doc/picoflow.solidstate.set.md +0 -13
- package/api/doc/picoflow.state.md +0 -55
- package/api/doc/picoflow.stream.md +0 -55
- package/api/doc/picoflow.streamasync.md +0 -55
- package/api/picoflow.public.api.md +0 -244
- 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
|
+
|