@ersbeth/picoflow 2.0.2 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/SKILL.md +106 -0
- package/package.json +5 -1
- package/.gitlab-ci.yml +0 -24
- package/.vscode/settings.json +0 -5
- package/CHANGELOG.md +0 -94
- package/biome.json +0 -47
- package/docs/.vitepress/config.mts +0 -145
- package/docs/api/functions/array.md +0 -35
- package/docs/api/functions/constant.md +0 -33
- package/docs/api/functions/constantAsync.md +0 -69
- package/docs/api/functions/derivation.md +0 -34
- package/docs/api/functions/derivationAsync.md +0 -34
- package/docs/api/functions/from.md +0 -129
- package/docs/api/functions/isDisposable.md +0 -27
- package/docs/api/functions/map.md +0 -36
- package/docs/api/functions/signal.md +0 -21
- package/docs/api/functions/state.md +0 -67
- package/docs/api/functions/stateAsync.md +0 -69
- package/docs/api/functions/subscribe.md +0 -40
- package/docs/api/functions/writableDerivation.md +0 -33
- package/docs/api/functions/writableDerivationAsync.md +0 -34
- package/docs/api/index.md +0 -61
- package/docs/api/interfaces/FlowArray.md +0 -439
- package/docs/api/interfaces/FlowConstant.md +0 -220
- package/docs/api/interfaces/FlowConstantAsync.md +0 -221
- package/docs/api/interfaces/FlowDerivation.md +0 -241
- package/docs/api/interfaces/FlowDerivationAsync.md +0 -242
- package/docs/api/interfaces/FlowDisposable.md +0 -59
- package/docs/api/interfaces/FlowEffect.md +0 -64
- package/docs/api/interfaces/FlowMap.md +0 -374
- package/docs/api/interfaces/FlowObservable.md +0 -155
- package/docs/api/interfaces/FlowSignal.md +0 -156
- package/docs/api/interfaces/FlowState.md +0 -269
- package/docs/api/interfaces/FlowStateAsync.md +0 -268
- package/docs/api/interfaces/FlowSubscribable.md +0 -55
- package/docs/api/interfaces/FlowTracker.md +0 -61
- package/docs/api/interfaces/FlowValue.md +0 -222
- package/docs/api/interfaces/FlowWritableDerivation.md +0 -292
- package/docs/api/interfaces/FlowWritableDerivationAsync.md +0 -293
- package/docs/api/type-aliases/DerivationFunction.md +0 -28
- package/docs/api/type-aliases/DerivationFunctionAsync.md +0 -28
- package/docs/api/type-aliases/FlowArrayAction.md +0 -60
- package/docs/api/type-aliases/FlowDataTracker.md +0 -33
- package/docs/api/type-aliases/FlowMapAction.md +0 -48
- package/docs/api/type-aliases/FlowOnDataListener.md +0 -33
- package/docs/api/type-aliases/FlowOnErrorListener.md +0 -27
- package/docs/api/type-aliases/FlowOnPendingListener.md +0 -21
- package/docs/api/type-aliases/FlowReadonly.md +0 -22
- package/docs/api/type-aliases/InitFunction.md +0 -21
- package/docs/api/type-aliases/InitFunctionAsync.md +0 -21
- package/docs/api/type-aliases/NotPromise.md +0 -21
- package/docs/api/type-aliases/UpdateFunction.md +0 -27
- package/docs/api/type-aliases/UpdateFunctionAsync.md +0 -27
- package/docs/api/typedoc-sidebar.json +0 -65
- package/docs/examples/examples.md +0 -2311
- package/docs/examples/patterns.md +0 -649
- package/docs/guide/advanced/architecture.md +0 -1234
- package/docs/guide/advanced/disposal.md +0 -426
- package/docs/guide/advanced/migration-v1.md +0 -464
- package/docs/guide/advanced/migration-v2.md +0 -204
- package/docs/guide/advanced/solidjs.md +0 -135
- package/docs/guide/introduction/concepts.md +0 -57
- package/docs/guide/introduction/conventions.md +0 -30
- package/docs/guide/introduction/getting-started.md +0 -139
- package/docs/guide/introduction/lifecycle.md +0 -368
- package/docs/guide/primitives/array.md +0 -286
- package/docs/guide/primitives/constant.md +0 -207
- package/docs/guide/primitives/derivations.md +0 -281
- package/docs/guide/primitives/effects.md +0 -372
- package/docs/guide/primitives/map.md +0 -265
- package/docs/guide/primitives/overview.md +0 -92
- package/docs/guide/primitives/signal.md +0 -222
- package/docs/guide/primitives/state.md +0 -272
- package/docs/index.md +0 -47
- package/docs/public/logo.svg +0 -1
- package/src/api/base/flowDisposable.ts +0 -44
- package/src/api/base/flowObservable.ts +0 -28
- package/src/api/base/flowSubscribable.ts +0 -87
- package/src/api/base/flowTracker.ts +0 -7
- package/src/api/base/index.ts +0 -4
- package/src/api/index.ts +0 -2
- package/src/api/nodes/async/flowConstantAsync.ts +0 -36
- package/src/api/nodes/async/flowDerivationAsync.ts +0 -42
- package/src/api/nodes/async/flowStateAsync.ts +0 -47
- package/src/api/nodes/async/flowWritableDerivationAsync.ts +0 -33
- package/src/api/nodes/async/index.ts +0 -4
- package/src/api/nodes/collections/flowArray.ts +0 -155
- package/src/api/nodes/collections/flowMap.ts +0 -115
- package/src/api/nodes/collections/index.ts +0 -2
- package/src/api/nodes/flowEffect.ts +0 -42
- package/src/api/nodes/flowSignal.ts +0 -28
- package/src/api/nodes/flowValue.ts +0 -37
- package/src/api/nodes/index.ts +0 -7
- package/src/api/nodes/sync/flowConstant.ts +0 -33
- package/src/api/nodes/sync/flowDerivation.ts +0 -41
- package/src/api/nodes/sync/flowState.ts +0 -45
- package/src/api/nodes/sync/flowWritableDerivation.ts +0 -31
- package/src/api/nodes/sync/index.ts +0 -4
- package/src/api/nodes/utils.ts +0 -24
- package/src/base/disposable.ts +0 -18
- package/src/base/executionStack.ts +0 -42
- package/src/base/index.ts +0 -5
- package/src/base/node.ts +0 -98
- package/src/base/observable.ts +0 -92
- package/src/base/observer.ts +0 -51
- package/src/converters/index.ts +0 -1
- package/src/converters/solid.ts +0 -109
- package/src/index.ts +0 -2
- package/src/nodes/arrayNode.ts +0 -180
- package/src/nodes/effectNode.ts +0 -58
- package/src/nodes/index.ts +0 -7
- package/src/nodes/mapNode.ts +0 -125
- package/src/nodes/signalNode.ts +0 -19
- package/src/nodes/valueAsyncNode.ts +0 -85
- package/src/nodes/valueNode.ts +0 -148
- package/src/nodes/valueSyncNode.ts +0 -125
- package/src/schedulers/asyncResolver.ts +0 -78
- package/src/schedulers/asyncScheduler.ts +0 -66
- package/src/schedulers/index.ts +0 -4
- package/src/schedulers/pendingError.ts +0 -13
- package/src/schedulers/scheduler.ts +0 -9
- package/src/schedulers/syncResolver.ts +0 -69
- package/src/schedulers/syncScheduler.ts +0 -55
- package/test/base/pendingError.test.ts +0 -67
- package/test/converters/solid.derivation.browser.test.tsx +0 -69
- package/test/converters/solid.node.test.ts +0 -654
- package/test/converters/solid.state.browser.test.tsx +0 -1592
- package/test/reactivity/flowSignal.test.ts +0 -226
- package/test/reactivity/nodes/async/asyncScheduler/asyncResolver.test.ts +0 -593
- package/test/reactivity/nodes/async/asyncScheduler/asyncScheduler.test.ts +0 -317
- package/test/reactivity/nodes/async/flowConstantAsync.test.ts +0 -652
- package/test/reactivity/nodes/async/flowDerivation.test.ts +0 -898
- package/test/reactivity/nodes/async/flowDerivationAsync.test.ts +0 -1716
- package/test/reactivity/nodes/async/flowStateAsync.test.ts +0 -708
- package/test/reactivity/nodes/async/flowWritableDerivationAsync.test.ts +0 -614
- package/test/reactivity/nodes/collections/flowArray.asyncStates.test.ts +0 -1289
- package/test/reactivity/nodes/collections/flowArray.scalars.test.ts +0 -961
- package/test/reactivity/nodes/collections/flowArray.states.test.ts +0 -1035
- package/test/reactivity/nodes/collections/flowMap.asyncStates.test.ts +0 -960
- package/test/reactivity/nodes/collections/flowMap.scalars.test.ts +0 -775
- package/test/reactivity/nodes/collections/flowMap.states.test.ts +0 -958
- package/test/reactivity/nodes/sync/flowConstant.test.ts +0 -377
- package/test/reactivity/nodes/sync/flowDerivation.test.ts +0 -896
- package/test/reactivity/nodes/sync/flowState.test.ts +0 -341
- package/test/reactivity/nodes/sync/flowWritableDerivation.test.ts +0 -603
- package/test/vitest.d.ts +0 -10
- package/tsconfig.json +0 -37
- package/typedoc.json +0 -37
- package/vite.config.ts +0 -31
- package/vitest.browser.config.ts +0 -21
- package/vitest.config.ts +0 -17
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
# Upgrading from v0.x
|
|
2
|
-
|
|
3
|
-
PicoFlow v1.0.0 introduces a new API based on an explicit tracking context instead of getter and watcher functions. This change brings several benefits:
|
|
4
|
-
|
|
5
|
-
1. **More intuitive:** The method-based API (`$state.get(t)`) is more natural than `get($state)`
|
|
6
|
-
2. **Better chaining:** Nested access is much more readable: `$a.get(t).b.get(t)` vs `get(get($a).b)`
|
|
7
|
-
3. **Explicit control:** Clear distinction between reactive (`.get(t)`) and non-reactive (`.pick()`) reads
|
|
8
|
-
4. **Simpler architecture:** Fewer internal abstractions make the library easier to understand and maintain
|
|
9
|
-
5. **More flexible:** Fine-grained control over dependencies within a single effect
|
|
10
|
-
|
|
11
|
-
We believe this change makes PicoFlow better for both new and experienced users, and we're excited for you to try it!
|
|
12
|
-
|
|
13
|
-
## Quick Start
|
|
14
|
-
|
|
15
|
-
The core change is simple:
|
|
16
|
-
|
|
17
|
-
**Before (v0.x):**
|
|
18
|
-
```typescript
|
|
19
|
-
effect((get, watch) => {
|
|
20
|
-
const value = get($state);
|
|
21
|
-
watch($signal);
|
|
22
|
-
});
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
**After (v1.0.0):**
|
|
26
|
-
```typescript
|
|
27
|
-
effect((t) => {
|
|
28
|
-
const value = $state.get(t);
|
|
29
|
-
$signal.watch(t);
|
|
30
|
-
});
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Breaking Changes Summary
|
|
34
|
-
|
|
35
|
-
| v0.x | v1.0.0 | Notes |
|
|
36
|
-
|------|--------|-------|
|
|
37
|
-
| `effect((get, watch) => {})` | `effect((t) => {})` | Single tracking context parameter |
|
|
38
|
-
| `derivation((get, watch) => {})` | `derivation((t) => {})` | Single tracking context parameter |
|
|
39
|
-
| `get($observable)` | `$observable.get(t)` | Method-based API |
|
|
40
|
-
| `watch($signal)` | `$signal.watch(t)` | Method-based API |
|
|
41
|
-
| `FlowGetter` type | `TrackingContext` type | New type for tracking context |
|
|
42
|
-
| `FlowWatcher` type | `TrackingContext` type | New type for tracking context |
|
|
43
|
-
| N/A | `$observable.pick()` | New: non-reactive reads |
|
|
44
|
-
|
|
45
|
-
## TypeScript Type Changes
|
|
46
|
-
|
|
47
|
-
If you've imported these types, update them:
|
|
48
|
-
|
|
49
|
-
**Before:**
|
|
50
|
-
```typescript
|
|
51
|
-
import type { FlowGetter, FlowWatcher } from '@ersbeth/picoflow';
|
|
52
|
-
|
|
53
|
-
function myHelper(get: FlowGetter, watch: FlowWatcher) {
|
|
54
|
-
// ...
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
**After:**
|
|
59
|
-
```typescript
|
|
60
|
-
import type { TrackingContext } from '@ersbeth/picoflow';
|
|
61
|
-
|
|
62
|
-
function myHelper(t: TrackingContext) {
|
|
63
|
-
// ...
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Step-by-Step Migration
|
|
68
|
-
|
|
69
|
-
### 1. Update PicoFlow
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
npm install @ersbeth/picoflow@1.0.0
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### 2. Replace Effect and Derivation Parameters
|
|
76
|
-
|
|
77
|
-
Find all `effect()` and `derivation()` calls in your codebase:
|
|
78
|
-
|
|
79
|
-
**Pattern to find:** `(get, watch) =>` or `(get) =>`
|
|
80
|
-
**Replace with:** `(t) =>`
|
|
81
|
-
|
|
82
|
-
### 3. Update Observable Reads
|
|
83
|
-
|
|
84
|
-
Replace getter function calls with method calls:
|
|
85
|
-
|
|
86
|
-
**Pattern to find:** `get($observable)`
|
|
87
|
-
**Replace with:** `$observable.get(t)`
|
|
88
|
-
|
|
89
|
-
### 4. Update Signal Watches
|
|
90
|
-
|
|
91
|
-
Replace watcher function calls with method calls:
|
|
92
|
-
|
|
93
|
-
**Pattern to find:** `watch($signal)`
|
|
94
|
-
**Replace with:** `$signal.watch(t)`
|
|
95
|
-
|
|
96
|
-
### 5. Test Your Application
|
|
97
|
-
|
|
98
|
-
Run your tests and verify everything works as expected.
|
|
99
|
-
|
|
100
|
-
## Common Migration Patterns
|
|
101
|
-
|
|
102
|
-
### Pattern 1: Simple Effect with State
|
|
103
|
-
|
|
104
|
-
**Before:**
|
|
105
|
-
```typescript
|
|
106
|
-
import { state, effect } from '@ersbeth/picoflow';
|
|
107
|
-
|
|
108
|
-
const $count = state(0);
|
|
109
|
-
|
|
110
|
-
const $effect = effect((get) => {
|
|
111
|
-
console.log('Count:', get($count));
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
$count.set(42);
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
**After:**
|
|
118
|
-
```typescript
|
|
119
|
-
import { state, effect } from '@ersbeth/picoflow';
|
|
120
|
-
|
|
121
|
-
const $count = state(0);
|
|
122
|
-
|
|
123
|
-
const $effect = effect((t) => {
|
|
124
|
-
console.log('Count:', $count.get(t));
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
$count.set(42);
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Pattern 2: Effect with Signal Watch
|
|
131
|
-
|
|
132
|
-
**Before:**
|
|
133
|
-
```typescript
|
|
134
|
-
import { signal, effect } from '@ersbeth/picoflow';
|
|
135
|
-
|
|
136
|
-
const $signal = signal();
|
|
137
|
-
|
|
138
|
-
const $effect = effect((get, watch) => {
|
|
139
|
-
watch($signal);
|
|
140
|
-
console.log('Signal triggered!');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
$signal.trigger();
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
**After:**
|
|
147
|
-
```typescript
|
|
148
|
-
import { signal, effect } from '@ersbeth/picoflow';
|
|
149
|
-
|
|
150
|
-
const $signal = signal();
|
|
151
|
-
|
|
152
|
-
const $effect = effect((t) => {
|
|
153
|
-
$signal.watch(t);
|
|
154
|
-
console.log('Signal triggered!');
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
$signal.trigger();
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Pattern 3: Derivations
|
|
161
|
-
|
|
162
|
-
**Before:**
|
|
163
|
-
```typescript
|
|
164
|
-
import { state, derivation } from '@ersbeth/picoflow';
|
|
165
|
-
|
|
166
|
-
const $firstName = state('John');
|
|
167
|
-
const $lastName = state('Doe');
|
|
168
|
-
|
|
169
|
-
const $fullName = derivation((get) => {
|
|
170
|
-
return `${get($firstName)} ${get($lastName)}`;
|
|
171
|
-
});
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
**After:**
|
|
175
|
-
```typescript
|
|
176
|
-
import { state, derivation } from '@ersbeth/picoflow';
|
|
177
|
-
|
|
178
|
-
const $firstName = state('John');
|
|
179
|
-
const $lastName = state('Doe');
|
|
180
|
-
|
|
181
|
-
const $fullName = derivation((t) => {
|
|
182
|
-
return `${$firstName.get(t)} ${$lastName.get(t)}`;
|
|
183
|
-
});
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### Pattern 4: Nested States (Chained Access)
|
|
187
|
-
|
|
188
|
-
This is where the new API really shines!
|
|
189
|
-
|
|
190
|
-
**Before:**
|
|
191
|
-
```typescript
|
|
192
|
-
const $user = state({
|
|
193
|
-
profile: $profile,
|
|
194
|
-
settings: $settings
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
effect((get) => {
|
|
198
|
-
const name = get(get($user).profile).name;
|
|
199
|
-
console.log(name);
|
|
200
|
-
});
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
**After:**
|
|
204
|
-
```typescript
|
|
205
|
-
const $user = state({
|
|
206
|
-
profile: $profile,
|
|
207
|
-
settings: $settings
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
effect((t) => {
|
|
211
|
-
const name = $user.get(t).profile.get(t).name;
|
|
212
|
-
console.log(name);
|
|
213
|
-
});
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
Much more readable!
|
|
217
|
-
|
|
218
|
-
### Pattern 5: Non-Reactive Reads (NEW CAPABILITY!)
|
|
219
|
-
|
|
220
|
-
v1.0.0 introduces `pick()` for reading values without creating dependencies:
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
const $data = state({ count: 0 });
|
|
224
|
-
const $trigger = signal();
|
|
225
|
-
|
|
226
|
-
effect((t) => {
|
|
227
|
-
// Only react to $trigger, not to $data
|
|
228
|
-
$trigger.watch(t);
|
|
229
|
-
const snapshot = $data.pick(); // Non-reactive read!
|
|
230
|
-
console.log('Triggered, current data:', snapshot);
|
|
231
|
-
});
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
You can also use `get(null)` for the same effect:
|
|
235
|
-
```typescript
|
|
236
|
-
const snapshot = $data.get(null); // Equivalent to pick()
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
### Pattern 6: Arrays and Collections
|
|
240
|
-
|
|
241
|
-
**Before:**
|
|
242
|
-
```typescript
|
|
243
|
-
import { array, effect } from '@ersbeth/picoflow';
|
|
244
|
-
|
|
245
|
-
const $items = array([1, 2, 3]);
|
|
246
|
-
|
|
247
|
-
effect((get) => {
|
|
248
|
-
const items = get($items);
|
|
249
|
-
console.log('Items:', items);
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
$items.push(4);
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
**After:**
|
|
256
|
-
```typescript
|
|
257
|
-
import { array, effect } from '@ersbeth/picoflow';
|
|
258
|
-
|
|
259
|
-
const $items = array([1, 2, 3]);
|
|
260
|
-
|
|
261
|
-
effect((t) => {
|
|
262
|
-
const items = $items.get(t);
|
|
263
|
-
console.log('Items:', items);
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
$items.push(4);
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Pattern 7: Reactive Maps
|
|
270
|
-
|
|
271
|
-
**Before:**
|
|
272
|
-
```typescript
|
|
273
|
-
import { map, effect } from '@ersbeth/picoflow';
|
|
274
|
-
|
|
275
|
-
const $map = map({ foo: 'bar' });
|
|
276
|
-
|
|
277
|
-
effect((get) => {
|
|
278
|
-
const data = get($map);
|
|
279
|
-
console.log('Map:', data);
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
$map.setAt('key', 'value');
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
**After:**
|
|
286
|
-
```typescript
|
|
287
|
-
import { map, effect } from '@ersbeth/picoflow';
|
|
288
|
-
|
|
289
|
-
const $map = map({ foo: 'bar' });
|
|
290
|
-
|
|
291
|
-
effect((t) => {
|
|
292
|
-
const data = $map.get(t);
|
|
293
|
-
console.log('Map:', data);
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
$map.setAt('key', 'value');
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### Pattern 8: Async Resources
|
|
300
|
-
|
|
301
|
-
**Before:**
|
|
302
|
-
```typescript
|
|
303
|
-
import { resource, effect } from '@ersbeth/picoflow';
|
|
304
|
-
|
|
305
|
-
const $data = resource(fetchData, {});
|
|
306
|
-
|
|
307
|
-
effect((get) => {
|
|
308
|
-
const data = get($data);
|
|
309
|
-
console.log('Data loaded:', data);
|
|
310
|
-
});
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
**After:**
|
|
314
|
-
```typescript
|
|
315
|
-
import { resource, effect } from '@ersbeth/picoflow';
|
|
316
|
-
|
|
317
|
-
const $data = resource(fetchData, {});
|
|
318
|
-
|
|
319
|
-
effect((t) => {
|
|
320
|
-
const data = $data.get(t);
|
|
321
|
-
console.log('Data loaded:', data);
|
|
322
|
-
});
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
### Pattern 9: Streams
|
|
326
|
-
|
|
327
|
-
**Before:**
|
|
328
|
-
```typescript
|
|
329
|
-
import { stream, effect } from '@ersbeth/picoflow';
|
|
330
|
-
|
|
331
|
-
const $messages = stream((set) => {
|
|
332
|
-
const ws = new WebSocket('ws://...');
|
|
333
|
-
ws.onmessage = (e) => set(e.data);
|
|
334
|
-
return () => ws.close();
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
effect((get) => {
|
|
338
|
-
console.log('Message:', get($messages));
|
|
339
|
-
});
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
**After:**
|
|
343
|
-
```typescript
|
|
344
|
-
import { stream, effect } from '@ersbeth/picoflow';
|
|
345
|
-
|
|
346
|
-
const $messages = stream((set) => {
|
|
347
|
-
const ws = new WebSocket('ws://...');
|
|
348
|
-
ws.onmessage = (e) => set(e.data);
|
|
349
|
-
return () => ws.close();
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
effect((t) => {
|
|
353
|
-
console.log('Message:', $messages.get(t));
|
|
354
|
-
});
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
### Pattern 10: SolidJS Integration
|
|
358
|
-
|
|
359
|
-
If you're using `picoflow/solid`:
|
|
360
|
-
|
|
361
|
-
**Before:**
|
|
362
|
-
```typescript
|
|
363
|
-
import { from } from '@ersbeth/picoflow/solid';
|
|
364
|
-
import { state } from '@ersbeth/picoflow';
|
|
365
|
-
|
|
366
|
-
const $picoState = state(42);
|
|
367
|
-
|
|
368
|
-
// Convert to SolidJS signal
|
|
369
|
-
const solidSignal = from($picoState);
|
|
370
|
-
|
|
371
|
-
// Or with a getter function
|
|
372
|
-
const solidDerived = from((get) => {
|
|
373
|
-
return get($stateA) + get($stateB);
|
|
374
|
-
});
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
**After:**
|
|
378
|
-
```typescript
|
|
379
|
-
import { from } from '@ersbeth/picoflow/solid';
|
|
380
|
-
import { state } from '@ersbeth/picoflow';
|
|
381
|
-
|
|
382
|
-
const $picoState = state(42);
|
|
383
|
-
|
|
384
|
-
// Convert to SolidJS signal
|
|
385
|
-
const solidSignal = from($picoState);
|
|
386
|
-
|
|
387
|
-
// Or with a getter function
|
|
388
|
-
const solidDerived = from((t) => {
|
|
389
|
-
return $stateA.get(t) + $stateB.get(t);
|
|
390
|
-
});
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
## Advanced: Mixed Reactive and Non-Reactive Reads
|
|
394
|
-
|
|
395
|
-
One powerful new feature is the ability to mix reactive and non-reactive reads in the same effect:
|
|
396
|
-
|
|
397
|
-
```typescript
|
|
398
|
-
const $config = state({ debug: true });
|
|
399
|
-
const $data = state({ value: 0 });
|
|
400
|
-
|
|
401
|
-
effect((t) => {
|
|
402
|
-
// Reactive: effect re-runs when $data changes
|
|
403
|
-
const data = $data.get(t);
|
|
404
|
-
|
|
405
|
-
// Non-reactive: effect does NOT re-run when $config changes
|
|
406
|
-
const config = $config.pick();
|
|
407
|
-
|
|
408
|
-
if (config.debug) {
|
|
409
|
-
console.log('Debug:', data);
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
// This triggers the effect:
|
|
414
|
-
$data.set({ value: 1 });
|
|
415
|
-
|
|
416
|
-
// This does NOT trigger the effect:
|
|
417
|
-
$config.set({ debug: false });
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
This is useful for:
|
|
421
|
-
- Reading configuration that rarely changes
|
|
422
|
-
- Accessing reference data without creating dependencies
|
|
423
|
-
- Performance optimization by avoiding unnecessary re-runs
|
|
424
|
-
|
|
425
|
-
## Troubleshooting
|
|
426
|
-
|
|
427
|
-
### Error: "Cannot read property 'get' of undefined"
|
|
428
|
-
|
|
429
|
-
Make sure you're passing the tracking context to the `get()` method:
|
|
430
|
-
|
|
431
|
-
```typescript
|
|
432
|
-
// ❌ Wrong
|
|
433
|
-
effect((t) => {
|
|
434
|
-
const value = $state.get(); // Missing parameter
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
// ✅ Correct
|
|
438
|
-
effect((t) => {
|
|
439
|
-
const value = $state.get(t);
|
|
440
|
-
});
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
### Error: "watch is not a function"
|
|
444
|
-
|
|
445
|
-
You're trying to use the old API. Update to the new method-based syntax:
|
|
446
|
-
|
|
447
|
-
```typescript
|
|
448
|
-
// ❌ Wrong (old API)
|
|
449
|
-
effect((get, watch) => {
|
|
450
|
-
watch($signal);
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
// ✅ Correct (new API)
|
|
454
|
-
effect((t) => {
|
|
455
|
-
$signal.watch(t);
|
|
456
|
-
});
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
### My effect runs too often / too rarely
|
|
460
|
-
|
|
461
|
-
Check if you're using `.get(t)` vs `.pick()` correctly:
|
|
462
|
-
- Use `.get(t)` to create a reactive dependency
|
|
463
|
-
- Use `.pick()` or `.get(null)` for snapshot reads without dependencies
|
|
464
|
-
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
# Migration Guide: v1.x.x → v2.0.0
|
|
2
|
-
|
|
3
|
-
PicoFlow v2 introduces several breaking changes that improve consistency, performance, and API clarity. This guide will help you migrate your codebase from v1.x.x to v2.0.0.
|
|
4
|
-
|
|
5
|
-
## Quick Summary
|
|
6
|
-
|
|
7
|
-
- **Effect API removed** - replaced with `subscribe()` and `.subscribe()`
|
|
8
|
-
- **FlowMap tracking simplified** - single `$lastAction` signal instead of three separate signals
|
|
9
|
-
- **FlowArray method renamed** - `setItem()` → `update()`
|
|
10
|
-
- **Constant always lazy** - must use function initializer
|
|
11
|
-
- **Improved terminology** - "effects" → "subscriptions", clearer naming
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## Breaking Changes
|
|
15
|
-
|
|
16
|
-
### 1. Effect API Removed
|
|
17
|
-
|
|
18
|
-
The global `effect()` function has been removed in favor of `subscribe()` and `.subscribe()` methods.
|
|
19
|
-
|
|
20
|
-
**v1.x.x:**
|
|
21
|
-
```typescript
|
|
22
|
-
import { effect } from '@ersbeth/picoflow'
|
|
23
|
-
|
|
24
|
-
effect((t) => {
|
|
25
|
-
const value = $state.get(t)
|
|
26
|
-
console.log(value)
|
|
27
|
-
})
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**v2.0.0:**
|
|
31
|
-
```typescript
|
|
32
|
-
// Option A: Single primitive - use .subscribe()
|
|
33
|
-
$state.subscribe((value) => {
|
|
34
|
-
console.log(value)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
// Option B: Multiple primitives - use subscribe()
|
|
38
|
-
import { subscribe } from '@ersbeth/picoflow'
|
|
39
|
-
|
|
40
|
-
subscribe(
|
|
41
|
-
(t) => ({ a: $state1.get(t), b: $state2.get(t) }),
|
|
42
|
-
(data) => {
|
|
43
|
-
console.log(data.a, data.b)
|
|
44
|
-
}
|
|
45
|
-
)
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### 2. FlowMap Fine-Grained Tracking Changed
|
|
49
|
-
|
|
50
|
-
FlowMap now uses a single `$lastAction` signal instead of three separate signals.
|
|
51
|
-
|
|
52
|
-
**v1.x.x:**
|
|
53
|
-
```typescript
|
|
54
|
-
const $users = map<number, User>()
|
|
55
|
-
|
|
56
|
-
// Three separate signals
|
|
57
|
-
$users.$lastAdded.subscribe((added) => {
|
|
58
|
-
console.log(added.key, added.value)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
$users.$lastUpdated.subscribe((updated) => {
|
|
62
|
-
console.log(updated.key, updated.value)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
$users.$lastDeleted.subscribe((deleted) => {
|
|
66
|
-
console.log(deleted.key, deleted.value)
|
|
67
|
-
})
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
**v2.0.0:**
|
|
71
|
-
```typescript
|
|
72
|
-
const $users = map<number, User>()
|
|
73
|
-
|
|
74
|
-
// Single $lastAction signal
|
|
75
|
-
$users.$lastAction.subscribe((action) => {
|
|
76
|
-
if (!action) return
|
|
77
|
-
|
|
78
|
-
switch (action.type) {
|
|
79
|
-
case 'add':
|
|
80
|
-
console.log(action.key, action.addedValue)
|
|
81
|
-
break
|
|
82
|
-
case 'update':
|
|
83
|
-
console.log(action.key, action.setValue, action.clearedValue)
|
|
84
|
-
break
|
|
85
|
-
case 'delete':
|
|
86
|
-
console.log(action.key, action.removedValue)
|
|
87
|
-
break
|
|
88
|
-
}
|
|
89
|
-
})
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### 3. FlowArray: `setItem()` → `update()`
|
|
93
|
-
|
|
94
|
-
The `setItem()` method has been renamed to `update()` for consistency.
|
|
95
|
-
|
|
96
|
-
**v1.x.x:**
|
|
97
|
-
```typescript
|
|
98
|
-
const $items = array([1, 2, 3])
|
|
99
|
-
$items.setItem(0, 10)
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
**v2.0.0:**
|
|
103
|
-
```typescript
|
|
104
|
-
const $items = array([1, 2, 3])
|
|
105
|
-
$items.update(0, 10)
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### 4. Constant Always Requires Function Initializer
|
|
109
|
-
|
|
110
|
-
Constants now always require a function initializer, enforcing lazy evaluation.
|
|
111
|
-
|
|
112
|
-
**v1.x.x (if direct values were allowed):**
|
|
113
|
-
```typescript
|
|
114
|
-
const $config = constant({ api: 'https://api.com' })
|
|
115
|
-
const $version = constant('1.0.0')
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
**v2.0.0:**
|
|
119
|
-
```typescript
|
|
120
|
-
const $config = constant(() => ({ api: 'https://api.com' }))
|
|
121
|
-
const $version = constant(() => '1.0.0')
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### 5. Terminology Updates
|
|
125
|
-
|
|
126
|
-
Some terminology has been clarified for better understanding.
|
|
127
|
-
|
|
128
|
-
#### Changes
|
|
129
|
-
|
|
130
|
-
| v1 Term | v2 Term | Notes |
|
|
131
|
-
|---------|---------|-------|
|
|
132
|
-
| "Effects" | "Side Effects" or "Subscriptions" | More precise |
|
|
133
|
-
| "TrackingContext" | "FlowTracker" | Official type name |
|
|
134
|
-
| `effect()` | `subscribe()` / `.subscribe()` | API change |
|
|
135
|
-
|
|
136
|
-
#### Migration
|
|
137
|
-
|
|
138
|
-
No code changes required - these are documentation updates. However, updating your comments and variable names to match the new terminology is recommended.
|
|
139
|
-
|
|
140
|
-
**Example:**
|
|
141
|
-
```typescript
|
|
142
|
-
// Before
|
|
143
|
-
const fx = effect((t) => { ... }) // Create effect
|
|
144
|
-
|
|
145
|
-
// After
|
|
146
|
-
const effect = $state.subscribe((value) => { ... }) // Create subscription
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## Step-by-Step Migration Guide
|
|
150
|
-
|
|
151
|
-
Follow these steps for a smooth migration:
|
|
152
|
-
|
|
153
|
-
### 1. Update Dependencies
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
npm install @ersbeth/picoflow@^2.0.0
|
|
157
|
-
# or
|
|
158
|
-
pnpm add @ersbeth/picoflow@^2.0.0
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### 2. Migrate Effects (Highest Priority)
|
|
162
|
-
|
|
163
|
-
Search for all `effect(` usages and migrate them:
|
|
164
|
-
- Single primitive → `.subscribe()`
|
|
165
|
-
- Multiple primitives → `subscribe()`
|
|
166
|
-
- Signals → `$signal.subscribe()`
|
|
167
|
-
|
|
168
|
-
**Tip**: Use your editor's "Find All" to locate all occurrences.
|
|
169
|
-
|
|
170
|
-
### 3. Update FlowMap Tracking
|
|
171
|
-
|
|
172
|
-
Search for:
|
|
173
|
-
- `$lastAdded` → migrate to `$lastAction` with type check
|
|
174
|
-
- `$lastUpdated` → migrate to `$lastAction` with type check
|
|
175
|
-
- `$lastDeleted` → migrate to `$lastAction` with type check
|
|
176
|
-
|
|
177
|
-
Update property names in action handlers.
|
|
178
|
-
|
|
179
|
-
### 4. Rename FlowArray Methods
|
|
180
|
-
|
|
181
|
-
Search and replace: `.setItem(` → `.update(`
|
|
182
|
-
|
|
183
|
-
### 5. Fix Constant Initialization
|
|
184
|
-
|
|
185
|
-
Search for `constant(` and ensure all have function initializers.
|
|
186
|
-
|
|
187
|
-
### 6. Test Thoroughly
|
|
188
|
-
|
|
189
|
-
Run your test suite and manually test reactive behaviors.
|
|
190
|
-
|
|
191
|
-
### 7. Update Documentation
|
|
192
|
-
|
|
193
|
-
Update internal docs, comments, and variable names to use v2 terminology.
|
|
194
|
-
|
|
195
|
-
## Getting Help
|
|
196
|
-
|
|
197
|
-
If you encounter issues during migration:
|
|
198
|
-
|
|
199
|
-
1. Check the [API documentation](/api/)
|
|
200
|
-
2. Review the [primitives guide](/guide/primitives/overview)
|
|
201
|
-
3. See the [side effects guide](/guide/primitives/effects)
|
|
202
|
-
4. Open an issue on GitHub with a minimal reproduction
|
|
203
|
-
|
|
204
|
-
Happy migrating! 🚀
|