@ersbeth/picoflow 1.1.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +3 -3
- package/CHANGELOG.md +43 -0
- package/README.md +2 -18
- package/biome.json +45 -35
- package/dist/picoflow.js +857 -1528
- package/dist/types/api/base/flowDisposable.d.ts +41 -0
- package/dist/types/api/base/flowDisposable.d.ts.map +1 -0
- package/dist/types/api/base/flowObservable.d.ts +27 -0
- package/dist/types/api/base/flowObservable.d.ts.map +1 -0
- package/dist/types/api/base/flowSubscribable.d.ts +79 -0
- package/dist/types/api/base/flowSubscribable.d.ts.map +1 -0
- package/dist/types/api/base/flowTracker.d.ts +8 -0
- package/dist/types/api/base/flowTracker.d.ts.map +1 -0
- package/dist/types/api/base/index.d.ts +5 -0
- package/dist/types/api/base/index.d.ts.map +1 -0
- package/dist/types/api/index.d.ts +3 -0
- package/dist/types/api/index.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowConstantAsync.d.ts +31 -0
- package/dist/types/api/nodes/async/flowConstantAsync.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowDerivationAsync.d.ts +37 -0
- package/dist/types/api/nodes/async/flowDerivationAsync.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowStateAsync.d.ts +41 -0
- package/dist/types/api/nodes/async/flowStateAsync.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowWritableDerivationAsync.d.ts +30 -0
- package/dist/types/api/nodes/async/flowWritableDerivationAsync.d.ts.map +1 -0
- package/dist/types/{flow → api}/nodes/async/index.d.ts +1 -2
- package/dist/types/api/nodes/async/index.d.ts.map +1 -0
- package/dist/types/api/nodes/collections/flowArray.d.ts +134 -0
- package/dist/types/api/nodes/collections/flowArray.d.ts.map +1 -0
- package/dist/types/api/nodes/collections/flowMap.d.ts +98 -0
- package/dist/types/api/nodes/collections/flowMap.d.ts.map +1 -0
- package/dist/types/api/nodes/collections/index.d.ts.map +1 -0
- package/dist/types/api/nodes/flowEffect.d.ts +28 -0
- package/dist/types/api/nodes/flowEffect.d.ts.map +1 -0
- package/dist/types/api/nodes/flowSignal.d.ts +25 -0
- package/dist/types/api/nodes/flowSignal.d.ts.map +1 -0
- package/dist/types/api/nodes/flowValue.d.ts +35 -0
- package/dist/types/api/nodes/flowValue.d.ts.map +1 -0
- package/dist/types/api/nodes/index.d.ts +8 -0
- package/dist/types/api/nodes/index.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowConstant.d.ts +29 -0
- package/dist/types/api/nodes/sync/flowConstant.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowDerivation.d.ts +36 -0
- package/dist/types/api/nodes/sync/flowDerivation.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowState.d.ts +39 -0
- package/dist/types/api/nodes/sync/flowState.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowWritableDerivation.d.ts +28 -0
- package/dist/types/api/nodes/sync/flowWritableDerivation.d.ts.map +1 -0
- package/dist/types/{flow → api}/nodes/sync/index.d.ts +1 -2
- package/dist/types/api/nodes/sync/index.d.ts.map +1 -0
- package/dist/types/api/nodes/utils.d.ts +22 -0
- package/dist/types/api/nodes/utils.d.ts.map +1 -0
- package/dist/types/base/disposable.d.ts +11 -0
- package/dist/types/base/disposable.d.ts.map +1 -0
- package/dist/types/base/executionStack.d.ts +14 -0
- package/dist/types/base/executionStack.d.ts.map +1 -0
- package/dist/types/base/index.d.ts +6 -0
- package/dist/types/base/index.d.ts.map +1 -0
- package/dist/types/base/node.d.ts +27 -0
- package/dist/types/base/node.d.ts.map +1 -0
- package/dist/types/base/observable.d.ts +37 -0
- package/dist/types/base/observable.d.ts.map +1 -0
- package/dist/types/base/observer.d.ts +25 -0
- package/dist/types/base/observer.d.ts.map +1 -0
- package/dist/types/converters/index.d.ts +2 -0
- package/dist/types/converters/index.d.ts.map +1 -0
- package/dist/types/converters/solid.d.ts +46 -0
- package/dist/types/converters/solid.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -63
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/nodes/arrayNode.d.ts +2 -0
- package/dist/types/nodes/arrayNode.d.ts.map +1 -0
- package/dist/types/nodes/effectNode.d.ts +2 -0
- package/dist/types/nodes/effectNode.d.ts.map +1 -0
- package/dist/types/nodes/index.d.ts +9 -0
- package/dist/types/nodes/index.d.ts.map +1 -0
- package/dist/types/nodes/mapNode.d.ts +2 -0
- package/dist/types/nodes/mapNode.d.ts.map +1 -0
- package/dist/types/nodes/signalNode.d.ts +2 -0
- package/dist/types/nodes/signalNode.d.ts.map +1 -0
- package/dist/types/nodes/valueAsyncNode.d.ts +2 -0
- package/dist/types/nodes/valueAsyncNode.d.ts.map +1 -0
- package/dist/types/nodes/valueNode.d.ts +2 -0
- package/dist/types/nodes/valueNode.d.ts.map +1 -0
- package/dist/types/nodes/valueSyncNode.d.ts +2 -0
- package/dist/types/nodes/valueSyncNode.d.ts.map +1 -0
- package/dist/types/schedulers/asyncResolver.d.ts +2 -0
- package/dist/types/schedulers/asyncResolver.d.ts.map +1 -0
- package/dist/types/schedulers/asyncScheduler.d.ts +2 -0
- package/dist/types/schedulers/asyncScheduler.d.ts.map +1 -0
- package/dist/types/schedulers/index.d.ts +5 -0
- package/dist/types/schedulers/index.d.ts.map +1 -0
- package/dist/types/schedulers/pendingError.d.ts +2 -0
- package/dist/types/schedulers/pendingError.d.ts.map +1 -0
- package/dist/types/schedulers/scheduler.d.ts +2 -0
- package/dist/types/schedulers/scheduler.d.ts.map +1 -0
- package/dist/types/schedulers/syncResolver.d.ts +2 -0
- package/dist/types/schedulers/syncResolver.d.ts.map +1 -0
- package/dist/types/schedulers/syncScheduler.d.ts +2 -0
- package/dist/types/schedulers/syncScheduler.d.ts.map +1 -0
- package/docs/.vitepress/config.mts +128 -93
- package/docs/api/functions/array.md +14 -37
- package/docs/api/functions/constant.md +13 -25
- package/docs/api/functions/constantAsync.md +69 -0
- package/docs/api/functions/derivation.md +14 -33
- package/docs/api/functions/derivationAsync.md +34 -0
- package/docs/api/functions/from.md +62 -153
- package/docs/api/functions/isDisposable.md +8 -30
- package/docs/api/functions/map.md +15 -36
- package/docs/api/functions/signal.md +8 -23
- package/docs/api/functions/state.md +43 -23
- package/docs/api/functions/stateAsync.md +69 -0
- package/docs/api/functions/subscribe.md +40 -0
- package/docs/api/functions/writableDerivation.md +33 -0
- package/docs/api/functions/writableDerivationAsync.md +34 -0
- package/docs/api/index.md +45 -102
- package/docs/api/interfaces/FlowArray.md +439 -0
- package/docs/api/interfaces/FlowConstant.md +220 -0
- package/docs/api/interfaces/FlowConstantAsync.md +221 -0
- package/docs/api/interfaces/FlowDerivation.md +241 -0
- package/docs/api/interfaces/FlowDerivationAsync.md +242 -0
- package/docs/api/interfaces/FlowDisposable.md +32 -38
- package/docs/api/interfaces/FlowEffect.md +64 -0
- package/docs/api/interfaces/FlowMap.md +374 -0
- package/docs/api/interfaces/FlowObservable.md +155 -0
- package/docs/api/interfaces/FlowSignal.md +156 -0
- package/docs/api/interfaces/FlowState.md +269 -0
- package/docs/api/interfaces/FlowStateAsync.md +268 -0
- package/docs/api/interfaces/FlowSubscribable.md +55 -0
- package/docs/api/interfaces/FlowTracker.md +61 -0
- package/docs/api/interfaces/FlowValue.md +222 -0
- package/docs/api/interfaces/FlowWritableDerivation.md +292 -0
- package/docs/api/interfaces/FlowWritableDerivationAsync.md +293 -0
- package/docs/api/type-aliases/DerivationFunction.md +28 -0
- package/docs/api/type-aliases/DerivationFunctionAsync.md +28 -0
- package/docs/api/type-aliases/FlowArrayAction.md +19 -8
- package/docs/api/type-aliases/FlowDataTracker.md +33 -0
- package/docs/api/type-aliases/FlowMapAction.md +48 -0
- package/docs/api/type-aliases/FlowOnDataListener.md +33 -0
- package/docs/api/type-aliases/FlowOnErrorListener.md +27 -0
- package/docs/api/type-aliases/FlowOnPendingListener.md +21 -0
- package/docs/api/type-aliases/FlowReadonly.md +22 -0
- package/docs/api/type-aliases/InitFunction.md +21 -0
- package/docs/api/type-aliases/InitFunctionAsync.md +21 -0
- package/docs/api/type-aliases/NotPromise.md +6 -3
- package/docs/api/type-aliases/UpdateFunction.md +27 -0
- package/docs/api/type-aliases/UpdateFunctionAsync.md +27 -0
- package/docs/api/typedoc-sidebar.json +1 -81
- package/docs/examples/examples.md +0 -2
- package/docs/guide/advanced/architecture.md +1234 -0
- package/docs/guide/advanced/migration-v2.md +204 -0
- package/docs/guide/advanced/solidjs.md +2 -88
- package/docs/guide/introduction/concepts.md +4 -3
- package/docs/guide/introduction/conventions.md +2 -33
- package/docs/guide/introduction/getting-started.md +28 -23
- package/docs/guide/introduction/lifecycle.md +16 -19
- package/docs/guide/primitives/array.md +102 -216
- package/docs/guide/primitives/constant.md +39 -212
- package/docs/guide/primitives/derivations.md +55 -122
- package/docs/guide/primitives/effects.md +155 -241
- package/docs/guide/primitives/map.md +64 -186
- package/docs/guide/primitives/overview.md +45 -128
- package/docs/guide/primitives/signal.md +51 -88
- package/docs/guide/primitives/state.md +34 -130
- package/package.json +56 -60
- package/src/api/base/flowDisposable.ts +44 -0
- package/src/api/base/flowObservable.ts +28 -0
- package/src/api/base/flowSubscribable.ts +87 -0
- package/src/api/base/flowTracker.ts +7 -0
- package/src/api/base/index.ts +4 -0
- package/src/{flow → api}/index.ts +0 -1
- package/src/api/nodes/async/flowConstantAsync.ts +36 -0
- package/src/api/nodes/async/flowDerivationAsync.ts +42 -0
- package/src/api/nodes/async/flowStateAsync.ts +47 -0
- package/src/api/nodes/async/flowWritableDerivationAsync.ts +33 -0
- package/src/{flow → api}/nodes/async/index.ts +1 -2
- package/src/api/nodes/collections/flowArray.ts +155 -0
- package/src/api/nodes/collections/flowMap.ts +115 -0
- package/src/api/nodes/flowEffect.ts +42 -0
- package/src/api/nodes/flowSignal.ts +28 -0
- package/src/api/nodes/flowValue.ts +36 -0
- package/src/api/nodes/index.ts +7 -0
- package/src/api/nodes/sync/flowConstant.ts +33 -0
- package/src/api/nodes/sync/flowDerivation.ts +41 -0
- package/src/api/nodes/sync/flowState.ts +45 -0
- package/src/api/nodes/sync/flowWritableDerivation.ts +31 -0
- package/src/{flow → api}/nodes/sync/index.ts +1 -2
- package/src/api/nodes/utils.ts +22 -0
- package/src/base/disposable.ts +18 -0
- package/src/base/executionStack.ts +42 -0
- package/src/base/index.ts +5 -0
- package/src/base/node.ts +98 -0
- package/src/base/observable.ts +87 -0
- package/src/base/observer.ts +51 -0
- package/src/converters/index.ts +1 -0
- package/src/converters/solid.ts +109 -0
- package/src/index.ts +2 -64
- package/src/nodes/arrayNode.ts +172 -0
- package/src/nodes/effectNode.ts +59 -0
- package/src/nodes/index.ts +8 -0
- package/src/nodes/mapNode.ts +127 -0
- package/src/nodes/signalNode.ts +21 -0
- package/src/nodes/valueAsyncNode.ts +88 -0
- package/src/nodes/valueNode.ts +144 -0
- package/src/nodes/valueSyncNode.ts +128 -0
- package/src/schedulers/asyncResolver.ts +78 -0
- package/src/schedulers/asyncScheduler.ts +66 -0
- package/src/schedulers/index.ts +4 -0
- package/src/schedulers/pendingError.ts +13 -0
- package/src/schedulers/scheduler.ts +9 -0
- package/src/schedulers/syncResolver.ts +69 -0
- package/src/schedulers/syncScheduler.ts +55 -0
- package/test/base/pendingError.test.ts +67 -0
- package/test/converters/solid.derivation.browser.test.tsx +69 -0
- package/test/converters/solid.node.test.ts +654 -0
- package/test/converters/solid.state.browser.test.tsx +1592 -0
- package/test/reactivity/flowSignal.test.ts +226 -0
- package/test/reactivity/nodes/async/asyncScheduler/asyncResolver.test.ts +593 -0
- package/test/reactivity/nodes/async/asyncScheduler/asyncScheduler.test.ts +317 -0
- package/test/reactivity/nodes/async/flowConstantAsync.test.ts +652 -0
- package/test/reactivity/nodes/async/flowDerivation.test.ts +898 -0
- package/test/reactivity/nodes/async/flowDerivationAsync.test.ts +1716 -0
- package/test/reactivity/nodes/async/flowStateAsync.test.ts +708 -0
- package/test/reactivity/nodes/async/flowWritableDerivationAsync.test.ts +614 -0
- package/test/reactivity/nodes/collections/flowArray.asyncStates.test.ts +1289 -0
- package/test/reactivity/nodes/collections/flowArray.scalars.test.ts +961 -0
- package/test/reactivity/nodes/collections/flowArray.states.test.ts +1035 -0
- package/test/reactivity/nodes/collections/flowMap.asyncStates.test.ts +960 -0
- package/test/reactivity/nodes/collections/flowMap.scalars.test.ts +775 -0
- package/test/reactivity/nodes/collections/flowMap.states.test.ts +958 -0
- package/test/reactivity/nodes/sync/flowConstant.test.ts +377 -0
- package/test/reactivity/nodes/sync/flowDerivation.test.ts +896 -0
- package/test/reactivity/nodes/sync/flowState.test.ts +341 -0
- package/test/reactivity/nodes/sync/flowWritableDerivation.test.ts +603 -0
- package/test/vitest.d.ts +10 -0
- package/tsconfig.json +31 -20
- package/typedoc.json +35 -35
- package/vite.config.ts +25 -23
- package/vitest.browser.config.ts +21 -0
- package/vitest.config.ts +12 -12
- package/.cursor/plans/unifier-flowresource-avec-flowderivation-c9506e24.plan.md +0 -372
- package/.cursor/plans/update-js-e795d61b.plan.md +0 -567
- package/dist/types/flow/base/flowDisposable.d.ts +0 -67
- package/dist/types/flow/base/flowDisposable.d.ts.map +0 -1
- package/dist/types/flow/base/flowEffect.d.ts +0 -127
- package/dist/types/flow/base/flowEffect.d.ts.map +0 -1
- package/dist/types/flow/base/flowGraph.d.ts +0 -97
- package/dist/types/flow/base/flowGraph.d.ts.map +0 -1
- package/dist/types/flow/base/flowSignal.d.ts +0 -134
- package/dist/types/flow/base/flowSignal.d.ts.map +0 -1
- package/dist/types/flow/base/flowTracker.d.ts +0 -15
- package/dist/types/flow/base/flowTracker.d.ts.map +0 -1
- package/dist/types/flow/base/index.d.ts +0 -7
- package/dist/types/flow/base/index.d.ts.map +0 -1
- package/dist/types/flow/base/utils.d.ts +0 -20
- package/dist/types/flow/base/utils.d.ts.map +0 -1
- package/dist/types/flow/collections/flowArray.d.ts +0 -148
- package/dist/types/flow/collections/flowArray.d.ts.map +0 -1
- package/dist/types/flow/collections/flowMap.d.ts +0 -224
- package/dist/types/flow/collections/flowMap.d.ts.map +0 -1
- package/dist/types/flow/collections/index.d.ts.map +0 -1
- package/dist/types/flow/index.d.ts +0 -4
- package/dist/types/flow/index.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowConstantAsync.d.ts +0 -137
- package/dist/types/flow/nodes/async/flowConstantAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowDerivationAsync.d.ts +0 -137
- package/dist/types/flow/nodes/async/flowDerivationAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowNodeAsync.d.ts +0 -343
- package/dist/types/flow/nodes/async/flowNodeAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowReadonlyAsync.d.ts +0 -81
- package/dist/types/flow/nodes/async/flowReadonlyAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowStateAsync.d.ts +0 -111
- package/dist/types/flow/nodes/async/flowStateAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/index.d.ts.map +0 -1
- package/dist/types/flow/nodes/index.d.ts +0 -3
- package/dist/types/flow/nodes/index.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowConstant.d.ts +0 -108
- package/dist/types/flow/nodes/sync/flowConstant.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowDerivation.d.ts +0 -100
- package/dist/types/flow/nodes/sync/flowDerivation.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowNode.d.ts +0 -314
- package/dist/types/flow/nodes/sync/flowNode.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowReadonly.d.ts +0 -57
- package/dist/types/flow/nodes/sync/flowReadonly.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowState.d.ts +0 -96
- package/dist/types/flow/nodes/sync/flowState.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/index.d.ts.map +0 -1
- package/dist/types/solid/converters.d.ts +0 -53
- package/dist/types/solid/converters.d.ts.map +0 -1
- package/dist/types/solid/index.d.ts +0 -3
- package/dist/types/solid/index.d.ts.map +0 -1
- package/dist/types/solid/primitives.d.ts +0 -181
- package/dist/types/solid/primitives.d.ts.map +0 -1
- package/docs/api/classes/FlowArray.md +0 -489
- package/docs/api/classes/FlowConstant.md +0 -350
- package/docs/api/classes/FlowDerivation.md +0 -334
- package/docs/api/classes/FlowEffect.md +0 -100
- package/docs/api/classes/FlowMap.md +0 -512
- package/docs/api/classes/FlowObservable.md +0 -306
- package/docs/api/classes/FlowResource.md +0 -380
- package/docs/api/classes/FlowResourceAsync.md +0 -362
- package/docs/api/classes/FlowSignal.md +0 -160
- package/docs/api/classes/FlowState.md +0 -368
- package/docs/api/classes/FlowStream.md +0 -367
- package/docs/api/classes/FlowStreamAsync.md +0 -364
- package/docs/api/classes/SolidDerivation.md +0 -75
- package/docs/api/classes/SolidResource.md +0 -91
- package/docs/api/classes/SolidState.md +0 -71
- package/docs/api/classes/TrackingContext.md +0 -33
- package/docs/api/functions/effect.md +0 -49
- package/docs/api/functions/resource.md +0 -52
- package/docs/api/functions/resourceAsync.md +0 -50
- package/docs/api/functions/stream.md +0 -53
- package/docs/api/functions/streamAsync.md +0 -50
- package/docs/api/interfaces/SolidObservable.md +0 -19
- package/docs/api/type-aliases/FlowStreamDisposer.md +0 -15
- package/docs/api/type-aliases/FlowStreamSetter.md +0 -27
- package/docs/api/type-aliases/FlowStreamUpdater.md +0 -32
- package/docs/api/type-aliases/SolidGetter.md +0 -17
- package/docs/guide/primitives/resources.md +0 -858
- package/docs/guide/primitives/streams.md +0 -931
- package/src/flow/base/flowDisposable.ts +0 -71
- package/src/flow/base/flowEffect.ts +0 -171
- package/src/flow/base/flowGraph.ts +0 -288
- package/src/flow/base/flowSignal.ts +0 -207
- package/src/flow/base/flowTracker.ts +0 -17
- package/src/flow/base/index.ts +0 -6
- package/src/flow/base/utils.ts +0 -19
- package/src/flow/collections/flowArray.ts +0 -409
- package/src/flow/collections/flowMap.ts +0 -398
- package/src/flow/nodes/async/flowConstantAsync.ts +0 -142
- package/src/flow/nodes/async/flowDerivationAsync.ts +0 -143
- package/src/flow/nodes/async/flowNodeAsync.ts +0 -474
- package/src/flow/nodes/async/flowReadonlyAsync.ts +0 -81
- package/src/flow/nodes/async/flowStateAsync.ts +0 -116
- package/src/flow/nodes/await/advanced/index.ts +0 -5
- package/src/flow/nodes/await/advanced/resource.ts +0 -134
- package/src/flow/nodes/await/advanced/resourceAsync.ts +0 -109
- package/src/flow/nodes/await/advanced/stream.ts +0 -188
- package/src/flow/nodes/await/advanced/streamAsync.ts +0 -176
- package/src/flow/nodes/await/flowConstantAwait.ts +0 -154
- package/src/flow/nodes/await/flowDerivationAwait.ts +0 -154
- package/src/flow/nodes/await/flowNodeAwait.ts +0 -508
- package/src/flow/nodes/await/flowReadonlyAwait.ts +0 -89
- package/src/flow/nodes/await/flowStateAwait.ts +0 -130
- package/src/flow/nodes/await/index.ts +0 -5
- package/src/flow/nodes/index.ts +0 -3
- package/src/flow/nodes/sync/flowConstant.ts +0 -111
- package/src/flow/nodes/sync/flowDerivation.ts +0 -105
- package/src/flow/nodes/sync/flowNode.ts +0 -439
- package/src/flow/nodes/sync/flowReadonly.ts +0 -57
- package/src/flow/nodes/sync/flowState.ts +0 -101
- package/src/solid/converters.ts +0 -139
- package/src/solid/index.ts +0 -2
- package/src/solid/primitives.ts +0 -215
- package/test/base/flowEffect.test.ts +0 -108
- package/test/base/flowGraph.test.ts +0 -485
- package/test/base/flowSignal.test.ts +0 -372
- package/test/collections/flowArray.asyncStates.test.ts +0 -1553
- package/test/collections/flowArray.scalars.test.ts +0 -1129
- package/test/collections/flowArray.states.test.ts +0 -1365
- package/test/collections/flowMap.asyncStates.test.ts +0 -1105
- package/test/collections/flowMap.scalars.test.ts +0 -877
- package/test/collections/flowMap.states.test.ts +0 -1097
- package/test/nodes/async/flowConstantAsync.test.ts +0 -860
- package/test/nodes/async/flowDerivationAsync.test.ts +0 -1517
- package/test/nodes/async/flowStateAsync.test.ts +0 -1387
- package/test/nodes/await/advanced/resource.test.ts +0 -129
- package/test/nodes/await/advanced/resourceAsync.test.ts +0 -108
- package/test/nodes/await/advanced/stream.test.ts +0 -198
- package/test/nodes/await/advanced/streamAsync.test.ts +0 -196
- package/test/nodes/await/flowConstantAwait.test.ts +0 -643
- package/test/nodes/await/flowDerivationAwait.test.ts +0 -1583
- package/test/nodes/await/flowStateAwait.test.ts +0 -999
- package/test/nodes/mixed/derivation.test.ts +0 -1527
- package/test/nodes/sync/flowConstant.test.ts +0 -620
- package/test/nodes/sync/flowDerivation.test.ts +0 -1373
- package/test/nodes/sync/flowState.test.ts +0 -945
- package/test/solid/converters.test.ts +0 -721
- package/test/solid/primitives.test.ts +0 -1031
- /package/dist/types/{flow → api/nodes}/collections/index.d.ts +0 -0
- /package/docs/guide/advanced/{upgrading.md → migration-v1.md} +0 -0
- /package/src/{flow → api/nodes}/collections/index.ts +0 -0
|
@@ -1,50 +1,38 @@
|
|
|
1
1
|
# Constants
|
|
2
2
|
|
|
3
|
-
A **constant** is a reactive primitive that holds an immutable value
|
|
3
|
+
A **constant** is a reactive primitive that holds an immutable value computed lazily on first access. Constants integrate immutable values into the reactive system, allowing them to be tracked as dependencies while ensuring they never change.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
### Key Characteristics
|
|
8
|
-
|
|
9
|
-
- **Immutable**: No `.set()` method - value never changes
|
|
10
|
-
- **Reactive**: Can be tracked with `.get(t)` just like state
|
|
11
|
-
- **Lazy evaluation**: Optional - compute value on first access
|
|
12
|
-
- **Cached forever**: Once computed, the value is permanently stored
|
|
5
|
+
The key benefit of constants is **lazy initialization** - the value isn't computed until it's first accessed, making them perfect for expensive one-time computations like parsing configuration files or building lookup tables.
|
|
13
6
|
|
|
14
7
|
## When to Use Constants
|
|
15
8
|
|
|
16
9
|
Use constants when you need to:
|
|
17
10
|
|
|
18
|
-
- ✅ Store configuration values that don't change
|
|
19
11
|
- ✅ Cache expensive computations that only run once
|
|
20
|
-
- ✅ Create reactive feature flags
|
|
21
|
-
- ✅ Provide stable reactive references to initialization values
|
|
22
12
|
|
|
23
13
|
Don't use constants when:
|
|
24
14
|
|
|
25
15
|
- ❌ The value needs to change (use state instead)
|
|
26
|
-
- ❌ You need a `.set()` method
|
|
27
16
|
- ❌ The value isn't reactive (use plain `const` instead)
|
|
28
17
|
|
|
29
18
|
## Creating Constants
|
|
30
19
|
|
|
31
|
-
|
|
20
|
+
Constants always take a function that returns the value. This function is called lazily on first access:
|
|
32
21
|
|
|
33
22
|
```typescript
|
|
34
23
|
import { constant } from '@ersbeth/picoflow'
|
|
35
24
|
|
|
36
|
-
//
|
|
37
|
-
const $apiUrl = constant('https://api.example.com')
|
|
38
|
-
const $config = constant({ apiUrl: 'https://api.example.com', timeout: 5000 })
|
|
39
|
-
const $version = constant('1.0.0')
|
|
25
|
+
// Function is required - value computed on first access
|
|
26
|
+
const $apiUrl = constant(() => 'https://api.example.com')
|
|
27
|
+
const $config = constant(() => ({ apiUrl: 'https://api.example.com', timeout: 5000 }))
|
|
28
|
+
const $version = constant(() => '1.0.0')
|
|
40
29
|
```
|
|
41
30
|
|
|
42
|
-
###
|
|
31
|
+
### Expensive Computations
|
|
43
32
|
|
|
44
|
-
|
|
33
|
+
The lazy initialization makes constants perfect for expensive one-time computations:
|
|
45
34
|
|
|
46
35
|
```typescript
|
|
47
|
-
// Lazy initialization - computed on first access
|
|
48
36
|
const $expensiveValue = constant(() => {
|
|
49
37
|
console.log('Computing expensive value...')
|
|
50
38
|
return performExpensiveCalculation()
|
|
@@ -52,8 +40,7 @@ const $expensiveValue = constant(() => {
|
|
|
52
40
|
|
|
53
41
|
// Nothing logged yet - function not called
|
|
54
42
|
|
|
55
|
-
|
|
56
|
-
const value = $expensiveValue.get(t)
|
|
43
|
+
$expensiveValue.subscribe((value) => {
|
|
57
44
|
// NOW it logs: "Computing expensive value..."
|
|
58
45
|
console.log(value)
|
|
59
46
|
})
|
|
@@ -65,92 +52,51 @@ effect((t) => {
|
|
|
65
52
|
|
|
66
53
|
Constants provide two ways to read values:
|
|
67
54
|
|
|
68
|
-
###
|
|
55
|
+
### Get
|
|
69
56
|
|
|
70
|
-
Inside
|
|
57
|
+
Inside a subscription or derivation, use `.get(t)` to read the value and create a dependency:
|
|
71
58
|
|
|
72
59
|
```typescript
|
|
73
|
-
import { constant
|
|
60
|
+
import { constant } from '@ersbeth/picoflow'
|
|
74
61
|
|
|
75
|
-
const $config = constant({ apiUrl: 'https://api.example.com' })
|
|
62
|
+
const $config = constant(() => ({ apiUrl: 'https://api.example.com' }))
|
|
63
|
+
const $merged = derivation((t) => ({url: $config.get(t).apiUrl, data: someOtherData}))
|
|
76
64
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
console.log('API URL:', config.apiUrl)
|
|
65
|
+
$merged.subscribe((merged) => {
|
|
66
|
+
console.log('Merged data', merged)
|
|
80
67
|
})
|
|
81
68
|
```
|
|
82
69
|
|
|
83
|
-
###
|
|
70
|
+
### Pick
|
|
84
71
|
|
|
85
72
|
Use `.pick()` when you want the current value without creating a dependency:
|
|
86
73
|
|
|
87
74
|
```typescript
|
|
88
|
-
const $config = constant({ apiUrl: 'https://api.example.com' })
|
|
75
|
+
const $config = constant(() => ({ apiUrl: 'https://api.example.com' }))
|
|
89
76
|
|
|
90
|
-
// Read without tracking (e.g., outside
|
|
91
|
-
const currentConfig = $config.pick()
|
|
77
|
+
// Read without tracking (e.g., outside a subscription or derivation)
|
|
78
|
+
const currentConfig = await $config.pick()
|
|
92
79
|
console.log(currentConfig.apiUrl)
|
|
93
80
|
|
|
94
|
-
// Or inside an effect, when you don't want to track changes
|
|
95
|
-
effect((t) => {
|
|
96
|
-
$trigger.watch(t) // Only track trigger
|
|
97
|
-
const config = $config.pick() // Don't track config
|
|
98
|
-
console.log(config)
|
|
99
|
-
})
|
|
100
81
|
```
|
|
101
82
|
|
|
102
|
-
###
|
|
103
|
-
|
|
104
|
-
Constants are immutable - attempting to call `.set()` will result in a TypeScript error:
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
const $config = constant({ apiUrl: 'https://api.example.com' })
|
|
108
|
-
|
|
109
|
-
$config.set({ apiUrl: 'new-url' }) // Type error! Constants have no .set() method
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Disposing with `.dispose()`
|
|
83
|
+
### Dispose
|
|
113
84
|
|
|
114
85
|
Constants can be disposed to free resources:
|
|
115
86
|
|
|
116
87
|
```typescript
|
|
117
|
-
const $config = constant({ apiUrl: 'https://api.example.com' })
|
|
88
|
+
const $config = constant(() => ({ apiUrl: 'https://api.example.com' }))
|
|
118
89
|
|
|
119
90
|
// Later, clean up
|
|
120
91
|
$config.dispose()
|
|
121
92
|
|
|
122
93
|
// Subsequent operations will throw
|
|
123
|
-
$config.
|
|
94
|
+
$config.pick() // Error: Primitive is disposed
|
|
124
95
|
```
|
|
125
96
|
|
|
126
97
|
## Lifecycle
|
|
127
98
|
|
|
128
|
-
Constants
|
|
129
|
-
|
|
130
|
-
### Eager Initialization Flow
|
|
131
|
-
|
|
132
|
-
When you pass a direct value, it's stored immediately:
|
|
133
|
-
|
|
134
|
-
```mermaid
|
|
135
|
-
sequenceDiagram
|
|
136
|
-
participant User
|
|
137
|
-
participant $config as $config (Constant)
|
|
138
|
-
|
|
139
|
-
User->>$config: constant({ value: 'data' })
|
|
140
|
-
activate $config
|
|
141
|
-
Note over $config: Store value immediately<br/>Mark as initialized
|
|
142
|
-
deactivate $config
|
|
143
|
-
|
|
144
|
-
User->>$config: get(t)
|
|
145
|
-
activate $config
|
|
146
|
-
Note over $config: Already initialized<br/>Return stored value
|
|
147
|
-
$config-->>User: { value: 'data' }
|
|
148
|
-
deactivate $config
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Lazy Initialization Flow
|
|
152
|
-
|
|
153
|
-
When you pass a function, it's executed on first access:
|
|
99
|
+
Constants use lazy initialization - the function you provide is executed only on first access:
|
|
154
100
|
|
|
155
101
|
```mermaid
|
|
156
102
|
sequenceDiagram
|
|
@@ -189,77 +135,38 @@ sequenceDiagram
|
|
|
189
135
|
|
|
190
136
|
**How it works:**
|
|
191
137
|
|
|
192
|
-
1. **Creation**:
|
|
193
|
-
- If function: store it, mark as not initialized
|
|
194
|
-
- If value: store it directly, mark as initialized
|
|
138
|
+
1. **Creation**: Store the initializer function, mark as not initialized
|
|
195
139
|
|
|
196
140
|
2. **First access**: When `.get(t)` or `.pick()` is called
|
|
197
141
|
- Check if initialized
|
|
198
|
-
- If not, execute
|
|
142
|
+
- If not, execute the function
|
|
199
143
|
- Cache result and mark as initialized
|
|
200
144
|
|
|
201
|
-
3. **Subsequent access**: Always return cached value
|
|
145
|
+
3. **Subsequent access**: Always return cached value (function never called again)
|
|
202
146
|
|
|
203
147
|
## Best Practices
|
|
204
148
|
|
|
205
|
-
### Use
|
|
206
|
-
|
|
207
|
-
Defer expensive work until it's actually needed:
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
// ✅ Good - lazy evaluation
|
|
211
|
-
const $parsedData = constant(() => {
|
|
212
|
-
return JSON.parse(largeDataString) // Only runs when accessed
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
// ❌ Less efficient - eager evaluation
|
|
216
|
-
const $parsedData = constant(JSON.parse(largeDataString)) // Runs immediately
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### Use Constants for Configuration
|
|
149
|
+
### Use Constants for Expensive Computations
|
|
220
150
|
|
|
221
|
-
|
|
151
|
+
Constants defer expensive work until it's actually needed:
|
|
222
152
|
|
|
223
153
|
```typescript
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
environment: process.env.NODE_ENV || 'development',
|
|
227
|
-
features: {
|
|
228
|
-
darkMode: true,
|
|
229
|
-
betaFeatures: false
|
|
230
|
-
}
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
effect((t) => {
|
|
234
|
-
const config = $appConfig.get(t)
|
|
235
|
-
setupApp(config)
|
|
236
|
-
})
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
### Name Constants Clearly
|
|
154
|
+
// ✅ Good - lazy evaluation with constant
|
|
155
|
+
const $parsedData = constant(() => JSON.parse(largeDataString))
|
|
240
156
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
```typescript
|
|
244
|
-
// ✅ Good - clear constant names
|
|
245
|
-
const $apiEndpoint = constant('https://api.example.com')
|
|
246
|
-
const $appVersion = constant('1.0.0')
|
|
247
|
-
const $maxRetries = constant(3)
|
|
248
|
-
|
|
249
|
-
// ❌ Less clear
|
|
250
|
-
const apiEndpoint = constant('https://api.example.com')
|
|
251
|
-
const APP_VERSION = constant('1.0.0')
|
|
157
|
+
// ❌ Eager - runs immediately (plain JavaScript)
|
|
158
|
+
const parsedData = JSON.parse(largeDataString)
|
|
252
159
|
```
|
|
253
160
|
|
|
254
161
|
### Prefer Plain const for Non-Reactive Values
|
|
255
162
|
|
|
256
|
-
If no
|
|
163
|
+
If no subscriptions or derivations will read it, use plain JavaScript:
|
|
257
164
|
|
|
258
165
|
```typescript
|
|
259
166
|
// ❌ Unnecessary - no reactivity needed
|
|
260
|
-
const $localConfig = constant({ timeout: 5000 })
|
|
261
|
-
function fetch() {
|
|
262
|
-
const config = $localConfig.pick() // Never tracked
|
|
167
|
+
const $localConfig = constant(() => ({ timeout: 5000 }))
|
|
168
|
+
function async fetch() {
|
|
169
|
+
const config = await $localConfig.pick() // Never tracked
|
|
263
170
|
return doFetch(config)
|
|
264
171
|
}
|
|
265
172
|
|
|
@@ -272,85 +179,6 @@ function fetch() {
|
|
|
272
179
|
|
|
273
180
|
## Common Pitfalls
|
|
274
181
|
|
|
275
|
-
### Using Constants When State Would Be Better
|
|
276
|
-
|
|
277
|
-
**Problem**: Using a constant for a value that actually needs to change.
|
|
278
|
-
|
|
279
|
-
```typescript
|
|
280
|
-
// ❌ Bad - theme should be changeable
|
|
281
|
-
const $theme = constant('light')
|
|
282
|
-
|
|
283
|
-
// Can't update it later!
|
|
284
|
-
// $theme.set('dark') // Type error!
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
**Solution**: Use state for mutable values:
|
|
288
|
-
|
|
289
|
-
```typescript
|
|
290
|
-
// ✅ Good - theme is mutable
|
|
291
|
-
const $theme = state('light')
|
|
292
|
-
|
|
293
|
-
// Can update it
|
|
294
|
-
$theme.set('dark')
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
### Creating Too Many Constants
|
|
298
|
-
|
|
299
|
-
**Problem**: Making every value a constant even when plain const would work.
|
|
300
|
-
|
|
301
|
-
```typescript
|
|
302
|
-
// ❌ Overkill - not used reactively
|
|
303
|
-
const $pi = constant(3.14159)
|
|
304
|
-
const $maxLength = constant(100)
|
|
305
|
-
|
|
306
|
-
function calculate() {
|
|
307
|
-
return $pi.pick() * radius // Just use plain const
|
|
308
|
-
}
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
**Solution**: Use plain const for non-reactive values:
|
|
312
|
-
|
|
313
|
-
```typescript
|
|
314
|
-
// ✅ Better - plain JavaScript
|
|
315
|
-
const PI = 3.14159
|
|
316
|
-
const MAX_LENGTH = 100
|
|
317
|
-
|
|
318
|
-
function calculate() {
|
|
319
|
-
return PI * radius
|
|
320
|
-
}
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### Expecting Constants to Update
|
|
324
|
-
|
|
325
|
-
**Problem**: Thinking constants will somehow update like state.
|
|
326
|
-
|
|
327
|
-
```typescript
|
|
328
|
-
// ❌ Wrong - constant won't update
|
|
329
|
-
const $userName = constant('Alice')
|
|
330
|
-
|
|
331
|
-
effect((t) => {
|
|
332
|
-
const name = $userName.get(t)
|
|
333
|
-
console.log(name) // Always "Alice"
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
// This won't work - no .set() method!
|
|
337
|
-
// $userName.set('Bob')
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
**Solution**: Use state if the value needs to change:
|
|
341
|
-
|
|
342
|
-
```typescript
|
|
343
|
-
// ✅ Correct - use state
|
|
344
|
-
const $userName = state('Alice')
|
|
345
|
-
|
|
346
|
-
effect((t) => {
|
|
347
|
-
const name = $userName.get(t)
|
|
348
|
-
console.log(name) // Updates when changed
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
$userName.set('Bob') // Now this works!
|
|
352
|
-
```
|
|
353
|
-
|
|
354
182
|
### Lazy Init with Side Effects
|
|
355
183
|
|
|
356
184
|
**Problem**: Using lazy initialization with side effects.
|
|
@@ -371,8 +199,7 @@ const $config = constant(() => {
|
|
|
371
199
|
const $config = constant(() => loadConfig())
|
|
372
200
|
|
|
373
201
|
// Handle side effects separately
|
|
374
|
-
|
|
375
|
-
const config = $config.get(t)
|
|
202
|
+
$config.subscribe((config) => {
|
|
376
203
|
console.log('Config loaded:', config)
|
|
377
204
|
localStorage.setItem('loaded', 'true')
|
|
378
205
|
})
|
|
@@ -6,9 +6,6 @@ Derivations are **reactive formulas** that compute values based on other reactiv
|
|
|
6
6
|
|
|
7
7
|
- **Lazy evaluation**: Computes only when accessed, not when created
|
|
8
8
|
- **Automatic caching**: Caches results until dependencies change
|
|
9
|
-
- **Dirty tracking**: Marked as "dirty" on changes, recomputes on next access
|
|
10
|
-
- **Pure computation**: Should have no side effects
|
|
11
|
-
- **Efficient**: Avoids unnecessary recomputation through smart caching
|
|
12
9
|
|
|
13
10
|
## When to Use Derivations
|
|
14
11
|
|
|
@@ -16,17 +13,14 @@ Use derivations when you need to:
|
|
|
16
13
|
|
|
17
14
|
- ✅ Compute values from other reactive primitives
|
|
18
15
|
- ✅ Transform or filter data reactively
|
|
19
|
-
- ✅ Create calculated fields (totals, averages, formatted values)
|
|
20
|
-
- ✅ Chain computations together
|
|
21
16
|
- ✅ Build complex reactive data flows
|
|
22
17
|
|
|
23
18
|
Don't use derivations when:
|
|
24
19
|
|
|
25
|
-
- ❌ You need to perform side effects (use
|
|
26
|
-
- ❌ The computation is not pure or deterministic
|
|
20
|
+
- ❌ You need to perform side effects (use subscribe instead)
|
|
27
21
|
|
|
28
22
|
::: tip
|
|
29
|
-
Not sure whether to use a derivation or
|
|
23
|
+
Not sure whether to use a derivation or a side effect? See the [Derivations vs Side Effects](./overview.md#derivations-vs-side-effects) section for a detailed comparison and guidance.
|
|
30
24
|
:::
|
|
31
25
|
|
|
32
26
|
|
|
@@ -37,6 +31,8 @@ Creating a derivation is straightforward:
|
|
|
37
31
|
```typescript
|
|
38
32
|
import { derivation } from '@ersbeth/picoflow'
|
|
39
33
|
|
|
34
|
+
const $count = state(1);
|
|
35
|
+
|
|
40
36
|
const $doubled = derivation((t) => {
|
|
41
37
|
// Your computation here
|
|
42
38
|
return $count.get(t) * 2
|
|
@@ -49,23 +45,23 @@ TypeScript automatically infers the return type based on what your function retu
|
|
|
49
45
|
|
|
50
46
|
Derivations have several methods for reading values and managing lifecycle.
|
|
51
47
|
|
|
52
|
-
###
|
|
48
|
+
### Get
|
|
53
49
|
|
|
54
|
-
Inside
|
|
50
|
+
Inside a subscription or another derivation, use `.get(t)` to read the value and track the dependency:
|
|
55
51
|
|
|
56
52
|
```typescript
|
|
57
53
|
const $count = state(10)
|
|
58
54
|
const $doubled = derivation((t) => $count.get(t) * 2)
|
|
55
|
+
const $result = derivation(t)=> $doubled.get(t) + 2)
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
console.log('Doubled:', value)
|
|
57
|
+
$result.subscribe((value) => {
|
|
58
|
+
console.log('Result:', value)
|
|
63
59
|
})
|
|
64
60
|
|
|
65
|
-
$count.set(20) // Logs: "
|
|
61
|
+
$count.set(20) // Logs: "Result: 42"
|
|
66
62
|
```
|
|
67
63
|
|
|
68
|
-
###
|
|
64
|
+
### Pick
|
|
69
65
|
|
|
70
66
|
Use `.pick()` to read the current value without tracking:
|
|
71
67
|
|
|
@@ -81,7 +77,26 @@ $count.set(20)
|
|
|
81
77
|
// No reaction because we used .pick()
|
|
82
78
|
```
|
|
83
79
|
|
|
84
|
-
###
|
|
80
|
+
### Dispose
|
|
81
|
+
|
|
82
|
+
Derivations can be disposed to free resources and prevent memory leaks:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
const $doubled = derivation((t) => $count.get(t) * 2)
|
|
86
|
+
|
|
87
|
+
// Use the derivation
|
|
88
|
+
$doubled.subscribe((value) => {
|
|
89
|
+
console.log(value)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
// Later, clean up
|
|
93
|
+
$doubled.dispose()
|
|
94
|
+
|
|
95
|
+
// Subsequent operations will throw
|
|
96
|
+
await $doubled.pick() // Error: Primitive is disposed
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Chaining Derivations
|
|
85
100
|
|
|
86
101
|
Derivations can depend on other derivations, creating chains of reactive computations:
|
|
87
102
|
|
|
@@ -96,7 +111,7 @@ const $sum = derivation((t) => {
|
|
|
96
111
|
// Second derivation: average (depends on $sum)
|
|
97
112
|
const $average = derivation((t) => {
|
|
98
113
|
const sum = $sum.get(t)
|
|
99
|
-
const count = $items.
|
|
114
|
+
const count = $items.get(t).length
|
|
100
115
|
return sum / count
|
|
101
116
|
})
|
|
102
117
|
|
|
@@ -106,8 +121,8 @@ const $formatted = derivation((t) => {
|
|
|
106
121
|
return `Average: ${avg.toFixed(2)}`
|
|
107
122
|
})
|
|
108
123
|
|
|
109
|
-
|
|
110
|
-
console.log(
|
|
124
|
+
$formatted.subscribe((value) => {
|
|
125
|
+
console.log(value)
|
|
111
126
|
})
|
|
112
127
|
|
|
113
128
|
$items.set([15, 25, 35]) // All derivations update in sequence
|
|
@@ -119,27 +134,10 @@ graph LR
|
|
|
119
134
|
B --> C[$average]
|
|
120
135
|
A -.-> C
|
|
121
136
|
C --> D[$formatted]
|
|
122
|
-
D --> E[
|
|
137
|
+
D --> E[Subscription]
|
|
123
138
|
```
|
|
124
139
|
|
|
125
|
-
### Disposing with `.dispose()`
|
|
126
140
|
|
|
127
|
-
Derivations can be disposed to free resources and prevent memory leaks:
|
|
128
|
-
|
|
129
|
-
```typescript
|
|
130
|
-
const $doubled = derivation((t) => $count.get(t) * 2)
|
|
131
|
-
|
|
132
|
-
// Use the derivation
|
|
133
|
-
effect((t) => {
|
|
134
|
-
console.log($doubled.get(t))
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
// Later, clean up
|
|
138
|
-
$doubled.dispose()
|
|
139
|
-
|
|
140
|
-
// Subsequent operations will throw
|
|
141
|
-
$doubled.get(someContext) // Error: Primitive is disposed
|
|
142
|
-
```
|
|
143
141
|
|
|
144
142
|
## Lifecycle
|
|
145
143
|
|
|
@@ -152,16 +150,16 @@ sequenceDiagram
|
|
|
152
150
|
participant User
|
|
153
151
|
participant $count as $count (State)
|
|
154
152
|
participant $doubled as $doubled (Derivation)
|
|
155
|
-
participant
|
|
153
|
+
participant Subscription
|
|
156
154
|
|
|
157
155
|
Note over User,$doubled: 1. Creation Phase
|
|
158
156
|
User->>$doubled: Create derivation
|
|
159
157
|
Note over $doubled: Store function<br/>NOT executed yet
|
|
160
158
|
|
|
161
|
-
Note over User,
|
|
162
|
-
User->>
|
|
163
|
-
activate
|
|
164
|
-
|
|
159
|
+
Note over User,Subscription: 2. First Access
|
|
160
|
+
User->>Subscription: Create subscription
|
|
161
|
+
activate Subscription
|
|
162
|
+
Subscription->>$doubled: get(t)
|
|
165
163
|
activate $doubled
|
|
166
164
|
Note over $doubled: Not computed yet<br/>Need to compute!
|
|
167
165
|
|
|
@@ -172,12 +170,12 @@ sequenceDiagram
|
|
|
172
170
|
deactivate $count
|
|
173
171
|
|
|
174
172
|
Note over $doubled: Compute: 0 * 2 = 0<br/>Cache result
|
|
175
|
-
$doubled-->>
|
|
173
|
+
$doubled-->>Subscription: 0
|
|
176
174
|
deactivate $doubled
|
|
177
|
-
Note over
|
|
178
|
-
deactivate
|
|
175
|
+
Note over Subscription: Log: "Doubled: 0"
|
|
176
|
+
deactivate Subscription
|
|
179
177
|
|
|
180
|
-
Note over User,
|
|
178
|
+
Note over User,Subscription: 3. Dependency Change
|
|
181
179
|
User->>$count: set(5)
|
|
182
180
|
activate $count
|
|
183
181
|
Note over $count: Value changed
|
|
@@ -187,12 +185,12 @@ sequenceDiagram
|
|
|
187
185
|
Note over $doubled: Mark as dirty<br/>NO recompute yet!
|
|
188
186
|
deactivate $doubled
|
|
189
187
|
|
|
190
|
-
$count->>
|
|
188
|
+
$count->>Subscription: Schedule execution
|
|
191
189
|
deactivate $count
|
|
192
190
|
|
|
193
|
-
Note over User,
|
|
194
|
-
activate
|
|
195
|
-
|
|
191
|
+
Note over User,Subscription: 4. Recompute on Access
|
|
192
|
+
activate Subscription
|
|
193
|
+
Subscription->>$doubled: get(t)
|
|
196
194
|
activate $doubled
|
|
197
195
|
Note over $doubled: Dirty? YES<br/>Recompute now!
|
|
198
196
|
|
|
@@ -202,12 +200,12 @@ sequenceDiagram
|
|
|
202
200
|
deactivate $count
|
|
203
201
|
|
|
204
202
|
Note over $doubled: Compute: 5 * 2 = 10<br/>Cache new result
|
|
205
|
-
$doubled-->>
|
|
203
|
+
$doubled-->>Subscription: 10
|
|
206
204
|
deactivate $doubled
|
|
207
|
-
Note over
|
|
208
|
-
deactivate
|
|
205
|
+
Note over Subscription: Log: "Doubled: 10"
|
|
206
|
+
deactivate Subscription
|
|
209
207
|
|
|
210
|
-
Note over User,
|
|
208
|
+
Note over User,Subscription: 5. Cached Access
|
|
211
209
|
User->>$doubled: pick()
|
|
212
210
|
activate $doubled
|
|
213
211
|
Note over $doubled: Not dirty<br/>Return cache
|
|
@@ -228,43 +226,6 @@ This lazy + cached approach means:
|
|
|
228
226
|
- **Multiple reads use the cache** (efficient)
|
|
229
227
|
- **Multiple dependency changes = one recompute** (optimized)
|
|
230
228
|
|
|
231
|
-
## Best Practices
|
|
232
|
-
|
|
233
|
-
### Keep Derivations Pure
|
|
234
|
-
|
|
235
|
-
Derivations should be pure functions with no side effects:
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
// ✅ Good - pure function
|
|
239
|
-
const $total = derivation((t) => {
|
|
240
|
-
return $items.get(t).reduce((sum, item) => sum + item.price, 0)
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
// ❌ Bad - side effect
|
|
244
|
-
const $total = derivation((t) => {
|
|
245
|
-
const total = $items.get(t).reduce((sum, item) => sum + item.price, 0)
|
|
246
|
-
console.log('Total:', total) // Side effect!
|
|
247
|
-
return total
|
|
248
|
-
})
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
**Why pure?** PicoFlow may skip recomputation if it thinks the result hasn't changed. Side effects would be unpredictable!
|
|
252
|
-
|
|
253
|
-
### Name Derivations Clearly
|
|
254
|
-
|
|
255
|
-
Use names that describe the computed value:
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
// ✅ Good - clear what it computes
|
|
259
|
-
const $totalPrice = derivation((t) => ...)
|
|
260
|
-
const $filteredUsers = derivation((t) => ...)
|
|
261
|
-
const $formattedDate = derivation((t) => ...)
|
|
262
|
-
|
|
263
|
-
// ❌ Bad - unclear purpose
|
|
264
|
-
const $result = derivation((t) => ...)
|
|
265
|
-
const $temp = derivation((t) => ...)
|
|
266
|
-
```
|
|
267
|
-
|
|
268
229
|
## Common Pitfalls
|
|
269
230
|
|
|
270
231
|
### Side Effects in Derivations
|
|
@@ -281,14 +242,13 @@ const $logged = derivation((t) => {
|
|
|
281
242
|
})
|
|
282
243
|
```
|
|
283
244
|
|
|
284
|
-
**Solution**: Move side effects to
|
|
245
|
+
**Solution**: Move side effects to a subscription:
|
|
285
246
|
|
|
286
247
|
```typescript
|
|
287
|
-
// ✅ Correct - side effect in
|
|
248
|
+
// ✅ Correct - side effect in subscription
|
|
288
249
|
const $count = state(0)
|
|
289
250
|
|
|
290
|
-
|
|
291
|
-
const value = $count.get(t)
|
|
251
|
+
$count.subscribe((value) => {
|
|
292
252
|
console.log('Count:', value) // Side effect here is fine
|
|
293
253
|
})
|
|
294
254
|
|
|
@@ -297,33 +257,6 @@ const $doubled = derivation((t) => {
|
|
|
297
257
|
})
|
|
298
258
|
```
|
|
299
259
|
|
|
300
|
-
### Using `.pick()` Instead of `.get(t)`
|
|
301
|
-
|
|
302
|
-
**Problem**: Using `.pick()` inside a derivation breaks doesn't trigger the reactivity system.
|
|
303
|
-
|
|
304
|
-
```typescript
|
|
305
|
-
// ❌ Derivation doesn't track $count
|
|
306
|
-
const $count = state(10)
|
|
307
|
-
const $doubled = derivation((t) => {
|
|
308
|
-
return $count.pick() * 2 // No dependency tracking!
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
effect((t) => {
|
|
312
|
-
console.log($doubled.get(t))
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
$count.set(20) // Effect won't run - no dependency!
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
**Solution**: Always use `.get(t)` to track dependencies:
|
|
319
|
-
|
|
320
|
-
```typescript
|
|
321
|
-
// ✅ Correct - tracks $count
|
|
322
|
-
const $doubled = derivation((t) => {
|
|
323
|
-
return $count.get(t) * 2
|
|
324
|
-
})
|
|
325
|
-
```
|
|
326
|
-
|
|
327
260
|
### Mutating Returned Values
|
|
328
261
|
|
|
329
262
|
**Problem**: Mutating arrays or objects returned from derivations doesn't trigger the reactivity system.
|