@playfast/reform 0.0.7 → 0.0.8
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/package.json +2 -2
- package/src/boundary/boundary.test.ts +301 -0
- package/src/boundary/boundary.ts +192 -0
- package/src/calc/asyncCalc.test.ts +556 -0
- package/src/calc/asyncCalc.ts +267 -0
- package/src/calc/asyncData.ts +96 -0
- package/src/calc/calc.test.ts +287 -0
- package/src/calc/calc.ts +120 -0
- package/src/calc/calcFamily.test.ts +206 -0
- package/src/calc/calcFamily.ts +194 -0
- package/src/calc/compose.test.ts +68 -0
- package/src/calc/compose.ts +69 -0
- package/src/channel/channel.ts +269 -0
- package/src/compose/composition.ts +112 -0
- package/{dist/compose/host.d.ts → src/compose/host.ts} +9 -8
- package/{dist/compose/props.js → src/compose/props.ts} +7 -5
- package/src/compose/provide.ts +70 -0
- package/{dist/compose/slot.d.ts → src/compose/slot.ts} +36 -19
- package/src/compose/ui.test.ts +62 -0
- package/src/compose/ui.ts +226 -0
- package/src/compose/ui.typecheck.ts +56 -0
- package/src/definition/definition.ts +76 -0
- package/src/event/event.test.ts +23 -0
- package/src/event/event.ts +65 -0
- package/src/event/eventGroup.ts +14 -0
- package/src/feature/feature.mount.test.ts +82 -0
- package/src/feature/feature.test.ts +60 -0
- package/{dist/feature/feature.d.ts → src/feature/feature.ts} +178 -92
- package/src/feature/feature.typecheck.ts +108 -0
- package/src/index.ts +176 -0
- package/{dist/internal/capture.d.ts → src/internal/capture.ts} +13 -11
- package/{dist/internal/ctx.d.ts → src/internal/ctx.ts} +8 -4
- package/src/internal/errors.test.ts +33 -0
- package/src/internal/errors.ts +145 -0
- package/src/internal/inspect.test.ts +28 -0
- package/src/internal/inspect.ts +34 -0
- package/src/internal/queryDriver.ts +247 -0
- package/src/internal/reuse.test.ts +116 -0
- package/src/internal/reuse.ts +73 -0
- package/src/internal/scheduler.ts +93 -0
- package/{dist/internal/seeds.d.ts → src/internal/seeds.ts} +6 -3
- package/src/internal/sources.ts +104 -0
- package/{dist/internal/stateRegistry.js → src/internal/stateRegistry.ts} +18 -14
- package/src/internal/store.test.ts +80 -0
- package/src/internal/store.ts +105 -0
- package/{dist/internal/track.d.ts → src/internal/track.ts} +17 -11
- package/src/procedure/procedure.ts +89 -0
- package/src/reducer/reducer.ts +137 -0
- package/src/remote/remoteState.test.ts +695 -0
- package/src/remote/remoteState.ts +571 -0
- package/src/remote/remoteState.typecheck.ts +195 -0
- package/src/runtime/bus.ts +40 -0
- package/src/runtime/hardening.test.ts +69 -0
- package/src/runtime/loop.test.ts +178 -0
- package/src/runtime/loop.ts +171 -0
- package/src/scene/scene.ts +76 -0
- package/src/scene/seedScene.test.ts +169 -0
- package/src/state/state.ts +94 -0
- package/src/state/stateFamily.test.ts +138 -0
- package/src/state/stateFamily.ts +174 -0
- package/src/state/stateGroup.ts +105 -0
- package/{dist/state/token.d.ts → src/state/token.ts} +22 -13
- package/src/synced/syncedStore.ts +99 -0
- package/{dist/ui/node.d.ts → src/ui/node.ts} +3 -3
- package/{dist/ui/trigger.d.ts → src/ui/trigger.ts} +1 -2
- package/src/wire/tree.test.ts +81 -0
- package/src/wire/tree.ts +129 -0
- package/src/wire/triggers.test.ts +76 -0
- package/src/wire/triggers.ts +98 -0
- package/dist/boundary/boundary.d.ts +0 -72
- package/dist/boundary/boundary.d.ts.map +0 -1
- package/dist/boundary/boundary.js +0 -83
- package/dist/boundary/boundary.js.map +0 -1
- package/dist/calc/asyncCalc.d.ts +0 -91
- package/dist/calc/asyncCalc.d.ts.map +0 -1
- package/dist/calc/asyncCalc.js +0 -95
- package/dist/calc/asyncCalc.js.map +0 -1
- package/dist/calc/asyncData.d.ts +0 -57
- package/dist/calc/asyncData.d.ts.map +0 -1
- package/dist/calc/asyncData.js +0 -34
- package/dist/calc/asyncData.js.map +0 -1
- package/dist/calc/calc.d.ts +0 -57
- package/dist/calc/calc.d.ts.map +0 -1
- package/dist/calc/calc.js +0 -58
- package/dist/calc/calc.js.map +0 -1
- package/dist/calc/calcFamily.d.ts +0 -57
- package/dist/calc/calcFamily.d.ts.map +0 -1
- package/dist/calc/calcFamily.js +0 -124
- package/dist/calc/calcFamily.js.map +0 -1
- package/dist/calc/compose.d.ts +0 -16
- package/dist/calc/compose.d.ts.map +0 -1
- package/dist/calc/compose.js +0 -7
- package/dist/calc/compose.js.map +0 -1
- package/dist/channel/channel.d.ts +0 -115
- package/dist/channel/channel.d.ts.map +0 -1
- package/dist/channel/channel.js +0 -138
- package/dist/channel/channel.js.map +0 -1
- package/dist/compose/composition.d.ts +0 -72
- package/dist/compose/composition.d.ts.map +0 -1
- package/dist/compose/composition.js +0 -46
- package/dist/compose/composition.js.map +0 -1
- package/dist/compose/host.d.ts.map +0 -1
- package/dist/compose/host.js +0 -6
- package/dist/compose/host.js.map +0 -1
- package/dist/compose/props.d.ts +0 -13
- package/dist/compose/props.d.ts.map +0 -1
- package/dist/compose/props.js.map +0 -1
- package/dist/compose/provide.d.ts +0 -22
- package/dist/compose/provide.d.ts.map +0 -1
- package/dist/compose/provide.js +0 -28
- package/dist/compose/provide.js.map +0 -1
- package/dist/compose/slot.d.ts.map +0 -1
- package/dist/compose/slot.js +0 -23
- package/dist/compose/slot.js.map +0 -1
- package/dist/compose/ui.d.ts +0 -135
- package/dist/compose/ui.d.ts.map +0 -1
- package/dist/compose/ui.js +0 -63
- package/dist/compose/ui.js.map +0 -1
- package/dist/definition/definition.d.ts +0 -33
- package/dist/definition/definition.d.ts.map +0 -1
- package/dist/definition/definition.js +0 -42
- package/dist/definition/definition.js.map +0 -1
- package/dist/event/event.d.ts +0 -33
- package/dist/event/event.d.ts.map +0 -1
- package/dist/event/event.js +0 -30
- package/dist/event/event.js.map +0 -1
- package/dist/event/eventGroup.d.ts +0 -9
- package/dist/event/eventGroup.d.ts.map +0 -1
- package/dist/event/eventGroup.js +0 -4
- package/dist/event/eventGroup.js.map +0 -1
- package/dist/feature/feature.d.ts.map +0 -1
- package/dist/feature/feature.js +0 -98
- package/dist/feature/feature.js.map +0 -1
- package/dist/index.d.ts +0 -53
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -62
- package/dist/index.js.map +0 -1
- package/dist/internal/capture.d.ts.map +0 -1
- package/dist/internal/capture.js +0 -12
- package/dist/internal/capture.js.map +0 -1
- package/dist/internal/ctx.d.ts.map +0 -1
- package/dist/internal/ctx.js +0 -2
- package/dist/internal/ctx.js.map +0 -1
- package/dist/internal/errors.d.ts +0 -89
- package/dist/internal/errors.d.ts.map +0 -1
- package/dist/internal/errors.js +0 -102
- package/dist/internal/errors.js.map +0 -1
- package/dist/internal/inspect.d.ts +0 -17
- package/dist/internal/inspect.d.ts.map +0 -1
- package/dist/internal/inspect.js +0 -32
- package/dist/internal/inspect.js.map +0 -1
- package/dist/internal/queryDriver.d.ts +0 -65
- package/dist/internal/queryDriver.d.ts.map +0 -1
- package/dist/internal/queryDriver.js +0 -134
- package/dist/internal/queryDriver.js.map +0 -1
- package/dist/internal/reuse.d.ts +0 -10
- package/dist/internal/reuse.d.ts.map +0 -1
- package/dist/internal/reuse.js +0 -68
- package/dist/internal/reuse.js.map +0 -1
- package/dist/internal/scheduler.d.ts +0 -47
- package/dist/internal/scheduler.d.ts.map +0 -1
- package/dist/internal/scheduler.js +0 -70
- package/dist/internal/scheduler.js.map +0 -1
- package/dist/internal/seeds.d.ts.map +0 -1
- package/dist/internal/seeds.js +0 -17
- package/dist/internal/seeds.js.map +0 -1
- package/dist/internal/sources.d.ts +0 -39
- package/dist/internal/sources.d.ts.map +0 -1
- package/dist/internal/sources.js +0 -59
- package/dist/internal/sources.js.map +0 -1
- package/dist/internal/stateRegistry.d.ts +0 -2
- package/dist/internal/stateRegistry.d.ts.map +0 -1
- package/dist/internal/stateRegistry.js.map +0 -1
- package/dist/internal/store.d.ts +0 -47
- package/dist/internal/store.d.ts.map +0 -1
- package/dist/internal/store.js +0 -73
- package/dist/internal/store.js.map +0 -1
- package/dist/internal/track.d.ts.map +0 -1
- package/dist/internal/track.js +0 -19
- package/dist/internal/track.js.map +0 -1
- package/dist/procedure/procedure.d.ts +0 -40
- package/dist/procedure/procedure.d.ts.map +0 -1
- package/dist/procedure/procedure.js +0 -50
- package/dist/procedure/procedure.js.map +0 -1
- package/dist/reducer/reducer.d.ts +0 -44
- package/dist/reducer/reducer.d.ts.map +0 -1
- package/dist/reducer/reducer.js +0 -63
- package/dist/reducer/reducer.js.map +0 -1
- package/dist/remote/remoteState.d.ts +0 -119
- package/dist/remote/remoteState.d.ts.map +0 -1
- package/dist/remote/remoteState.js +0 -270
- package/dist/remote/remoteState.js.map +0 -1
- package/dist/runtime/bus.d.ts +0 -27
- package/dist/runtime/bus.d.ts.map +0 -1
- package/dist/runtime/bus.js +0 -21
- package/dist/runtime/bus.js.map +0 -1
- package/dist/runtime/loop.d.ts +0 -45
- package/dist/runtime/loop.d.ts.map +0 -1
- package/dist/runtime/loop.js +0 -117
- package/dist/runtime/loop.js.map +0 -1
- package/dist/scene/scene.d.ts +0 -44
- package/dist/scene/scene.d.ts.map +0 -1
- package/dist/scene/scene.js +0 -31
- package/dist/scene/scene.js.map +0 -1
- package/dist/state/state.d.ts +0 -37
- package/dist/state/state.d.ts.map +0 -1
- package/dist/state/state.js +0 -46
- package/dist/state/state.js.map +0 -1
- package/dist/state/stateFamily.d.ts +0 -79
- package/dist/state/stateFamily.d.ts.map +0 -1
- package/dist/state/stateFamily.js +0 -99
- package/dist/state/stateFamily.js.map +0 -1
- package/dist/state/stateGroup.d.ts +0 -50
- package/dist/state/stateGroup.d.ts.map +0 -1
- package/dist/state/stateGroup.js +0 -54
- package/dist/state/stateGroup.js.map +0 -1
- package/dist/state/token.d.ts.map +0 -1
- package/dist/state/token.js +0 -20
- package/dist/state/token.js.map +0 -1
- package/dist/synced/syncedStore.d.ts +0 -51
- package/dist/synced/syncedStore.d.ts.map +0 -1
- package/dist/synced/syncedStore.js +0 -43
- package/dist/synced/syncedStore.js.map +0 -1
- package/dist/ui/node.d.ts.map +0 -1
- package/dist/ui/node.js +0 -2
- package/dist/ui/node.js.map +0 -1
- package/dist/ui/trigger.d.ts.map +0 -1
- package/dist/ui/trigger.js +0 -2
- package/dist/ui/trigger.js.map +0 -1
- package/dist/wire/tree.d.ts +0 -66
- package/dist/wire/tree.d.ts.map +0 -1
- package/dist/wire/tree.js +0 -60
- package/dist/wire/tree.js.map +0 -1
- package/dist/wire/triggers.d.ts +0 -44
- package/dist/wire/triggers.d.ts.map +0 -1
- package/dist/wire/triggers.js +0 -31
- package/dist/wire/triggers.js.map +0 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Effect, Layer } from 'effect'
|
|
2
|
+
import { type Manifest, definitionClass } from '../definition/definition'
|
|
3
|
+
import { AsyncReducer } from '../internal/errors'
|
|
4
|
+
import { type AnyEvent, type EventType } from '../event/event'
|
|
5
|
+
import type { Store } from '../internal/store'
|
|
6
|
+
import { type AnyState, type StateValue } from '../state/state'
|
|
7
|
+
import {
|
|
8
|
+
type AnyFamily,
|
|
9
|
+
type FamilyKey,
|
|
10
|
+
type FamilyStore,
|
|
11
|
+
type FamilyValue,
|
|
12
|
+
Tombstone,
|
|
13
|
+
} from '../state/stateFamily'
|
|
14
|
+
import { narrowHandled, type Tagged } from '../runtime/bus'
|
|
15
|
+
import { type ReducerEntry, Reducers } from '../runtime/loop'
|
|
16
|
+
|
|
17
|
+
/** The reflectable descriptor a reducer carries, like every other primitive's `*Manifest`. */
|
|
18
|
+
export interface ReducerManifest extends Manifest {
|
|
19
|
+
readonly kind: 'Reducer'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface StateReducerConfig<S extends AnyState, Events extends ReadonlyArray<AnyEvent>> {
|
|
23
|
+
readonly states: readonly [S]
|
|
24
|
+
readonly events: Events
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface FamilyReducerConfig<F extends AnyFamily, Events extends ReadonlyArray<AnyEvent>> {
|
|
28
|
+
readonly family: F
|
|
29
|
+
readonly keyOf: (event: EventType<Events[number]>) => FamilyKey<F>
|
|
30
|
+
readonly events: Events
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface StateReducerClass<S extends AnyState, Events extends ReadonlyArray<AnyEvent>> {
|
|
34
|
+
new (): {}
|
|
35
|
+
readonly manifest: ReducerManifest
|
|
36
|
+
/** Marker data read by `Reducer.live`. */
|
|
37
|
+
readonly config: StateReducerConfig<S, Events>
|
|
38
|
+
readonly handles: ReadonlySet<string>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface FamilyReducerClass<F extends AnyFamily, Events extends ReadonlyArray<AnyEvent>> {
|
|
42
|
+
new (): {}
|
|
43
|
+
readonly manifest: ReducerManifest
|
|
44
|
+
readonly config: FamilyReducerConfig<F, Events>
|
|
45
|
+
readonly handles: ReadonlySet<string>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Reducers are the only writers of state. The *definition* (`Reducer.make`)
|
|
50
|
+
* declares which state and events it touches; the *implementation*
|
|
51
|
+
* (`Reducer.live`) is the pure fold. An unhandled event is a no-op because
|
|
52
|
+
* it is never in `handles`.
|
|
53
|
+
*/
|
|
54
|
+
export function make<S extends AnyState, const Events extends ReadonlyArray<AnyEvent>>(
|
|
55
|
+
name: string,
|
|
56
|
+
config: StateReducerConfig<S, Events>,
|
|
57
|
+
): StateReducerClass<S, Events>
|
|
58
|
+
export function make<F extends AnyFamily, const Events extends ReadonlyArray<AnyEvent>>(
|
|
59
|
+
name: string,
|
|
60
|
+
config: FamilyReducerConfig<F, Events>,
|
|
61
|
+
): FamilyReducerClass<F, Events>
|
|
62
|
+
export function make(
|
|
63
|
+
name: string,
|
|
64
|
+
config:
|
|
65
|
+
| StateReducerConfig<AnyState, ReadonlyArray<AnyEvent>>
|
|
66
|
+
| FamilyReducerConfig<AnyFamily, ReadonlyArray<AnyEvent>>,
|
|
67
|
+
): unknown {
|
|
68
|
+
return definitionClass<unknown>({
|
|
69
|
+
manifest: { kind: 'Reducer' as const, name } satisfies ReducerManifest,
|
|
70
|
+
config,
|
|
71
|
+
handles: new Set(config.events.map((e) => e.tag)),
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Reject an accidentally-async fold up front: a reducer must be a pure sync write. */
|
|
76
|
+
const sync = <A>(value: A): A => {
|
|
77
|
+
// Loose `!= null` so a reducer returning `undefined` doesn't crash the guard.
|
|
78
|
+
if (value != null && typeof (value as { then?: unknown }).then === 'function') {
|
|
79
|
+
throw new AsyncReducer()
|
|
80
|
+
}
|
|
81
|
+
return value
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function live<S extends AnyState, Events extends ReadonlyArray<AnyEvent>>(
|
|
85
|
+
reducer: StateReducerClass<S, Events>,
|
|
86
|
+
fold: (value: StateValue<S>, event: EventType<Events[number]>) => StateValue<S>,
|
|
87
|
+
): Layer.Layer<never, never, Reducers | Store<StateValue<S>>>
|
|
88
|
+
export function live<F extends AnyFamily, Events extends ReadonlyArray<AnyEvent>>(
|
|
89
|
+
reducer: FamilyReducerClass<F, Events>,
|
|
90
|
+
fold: (entry: FamilyValue<F>, event: EventType<Events[number]>) => FamilyValue<F> | Tombstone,
|
|
91
|
+
): Layer.Layer<never, never, Reducers | FamilyStore<FamilyKey<F>, FamilyValue<F>>>
|
|
92
|
+
export function live(
|
|
93
|
+
reducer:
|
|
94
|
+
| StateReducerClass<AnyState, ReadonlyArray<AnyEvent>>
|
|
95
|
+
| FamilyReducerClass<AnyFamily, ReadonlyArray<AnyEvent>>,
|
|
96
|
+
fold: (acc: any, event: any) => any,
|
|
97
|
+
): Layer.Layer<never, never, any> {
|
|
98
|
+
const { config, handles } = reducer
|
|
99
|
+
const name = reducer.manifest.name
|
|
100
|
+
// Scoped registration: register on build, unregister on scope close. For an eager
|
|
101
|
+
// app the scope is the root runtime's (closes only at dispose), so behavior is
|
|
102
|
+
// unchanged; for a lazy feature the scope is the feature's, so unmount removes the
|
|
103
|
+
// entry — it stops folding and is reclaimed instead of leaking onto a dead store.
|
|
104
|
+
return Layer.scopedDiscard(
|
|
105
|
+
Effect.gen(function* () {
|
|
106
|
+
const reducers = yield* Reducers
|
|
107
|
+
if (reducers.entries.some((e) => e.name === name)) {
|
|
108
|
+
yield* Effect.logWarning(`reform: duplicate reducer name '${name}' registered`)
|
|
109
|
+
}
|
|
110
|
+
const entry: ReducerEntry = yield* Effect.gen(function* () {
|
|
111
|
+
if ('family' in config) {
|
|
112
|
+
const family = yield* config.family.store
|
|
113
|
+
return {
|
|
114
|
+
name,
|
|
115
|
+
handles,
|
|
116
|
+
apply: (event: Tagged) => {
|
|
117
|
+
// The loop only invokes `apply` for events in `handles`, so `event`
|
|
118
|
+
// is one of this reducer's declared events; `narrowHandled` restores
|
|
119
|
+
// that typed view from the erased `Tagged` envelope `keyOf` is fed.
|
|
120
|
+
const key = config.keyOf(narrowHandled(event))
|
|
121
|
+
const next = fold(family.at(key).get(), event)
|
|
122
|
+
// A fold may return the eviction sentinel to drop the key's store
|
|
123
|
+
// (bounding an otherwise-unbounded family) instead of a new value.
|
|
124
|
+
if (next === Tombstone) family.forget(key)
|
|
125
|
+
else family.at(key).set(sync(next))
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const store = yield* config.states[0].store
|
|
130
|
+
return { name, handles, apply: (event: Tagged) => store.set(sync(fold(store.get(), event))) }
|
|
131
|
+
})
|
|
132
|
+
yield* Effect.acquireRelease(Effect.sync(() => reducers.register(entry)), () =>
|
|
133
|
+
Effect.sync(() => reducers.unregister(entry)),
|
|
134
|
+
)
|
|
135
|
+
}),
|
|
136
|
+
)
|
|
137
|
+
}
|