@playfast/reform 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -55
- package/package.json +17 -17
- package/src/boundary/boundary.test.ts +82 -33
- package/src/boundary/boundary.ts +141 -32
- package/src/calc/asyncCalc.invalidate.test.ts +733 -32
- package/src/calc/asyncCalc.test.ts +397 -225
- package/src/calc/asyncCalc.ts +115 -100
- package/src/calc/asyncCalcTypes.ts +147 -0
- package/src/calc/calc.test.ts +13 -16
- package/src/calc/calc.ts +44 -18
- package/src/calc/calcFamily.test.ts +90 -32
- package/src/calc/calcFamily.ts +56 -25
- package/src/calc/compose.ts +1 -14
- package/src/channel/channel.ts +25 -6
- package/src/channel/{procedureRegistry.ts → procedures.ts} +41 -23
- package/src/compose/composition.test.ts +19 -0
- package/src/compose/composition.ts +168 -81
- package/src/compose/compositionTypes.ts +249 -0
- package/src/compose/props.ts +13 -6
- package/src/compose/provide.ts +187 -46
- package/src/compose/slot.ts +156 -19
- package/src/compose/structure.test.ts +6 -3
- package/src/compose/structure.ts +106 -13
- package/src/compose/ui.test.ts +19 -3
- package/src/compose/ui.ts +147 -54
- package/src/compose/ui.typecheck.ts +40 -4
- package/src/definition/definition.ts +22 -9
- package/src/event/event.fromSource.test.ts +172 -0
- package/src/event/event.test.ts +10 -0
- package/src/event/event.ts +102 -18
- package/src/feature/feature.mount.test.ts +123 -56
- package/src/feature/feature.test.ts +67 -63
- package/src/feature/feature.ts +222 -262
- package/src/feature/feature.typecheck.ts +224 -91
- package/src/feature/featureBinding.ts +130 -20
- package/src/feature/featureClass.ts +162 -0
- package/src/feature/featureConfig.ts +192 -0
- package/src/feature/featureFactory.ts +163 -0
- package/src/feature/featureModule.ts +136 -0
- package/src/feature/featureModule.typecheck.ts +63 -0
- package/src/feature/featureNativeTree.ts +152 -0
- package/src/feature/featureRequirement.ts +82 -0
- package/src/feature/featureVariants.ts +234 -0
- package/src/feature/mountFeature.ts +54 -0
- package/src/graph/closure.ts +222 -0
- package/src/graph/services.ts +95 -0
- package/src/graph/summary.ts +134 -0
- package/src/index.ts +171 -245
- package/src/internal/bucketCache.ts +39 -0
- package/src/internal/capture.ts +9 -4
- package/src/internal/env.ts +1 -3
- package/src/internal/errors.ts +21 -10
- package/src/internal/queryDriver.ts +61 -25
- package/src/internal/queryDriverHydrate.ts +45 -0
- package/src/internal/queryDriverStore.ts +8 -5
- package/src/internal/queryDriverTypes.ts +11 -11
- package/src/internal/reuse.test.ts +10 -3
- package/src/internal/reuse.ts +5 -2
- package/src/internal/scheduler.ts +4 -1
- package/src/internal/sources.ts +25 -11
- package/src/internal/store.test.ts +27 -6
- package/src/internal/track.ts +3 -2
- package/src/internal.ts +222 -0
- package/src/namespace/namespace.ts +46 -25
- package/src/procedure/procedure.ts +38 -11
- package/src/reducer/reducer.ts +78 -34
- package/src/remote/pendingQueue.ts +145 -0
- package/src/remote/remoteState.test.ts +536 -354
- package/src/remote/remoteState.ts +145 -106
- package/src/remote/remoteState.typecheck.ts +47 -23
- package/src/remote/remoteStateMake.ts +97 -0
- package/src/remote/remoteStateSend.ts +95 -37
- package/src/remote/remoteStateTypes.ts +155 -0
- package/src/runtime/appRuntime.activation.test.ts +104 -0
- package/src/runtime/appRuntime.test.ts +187 -111
- package/src/runtime/appRuntime.ts +36 -130
- package/src/runtime/capturedAppRuntime.ts +274 -0
- package/src/runtime/eventBudget.test.ts +39 -12
- package/src/runtime/eventBudget.ts +9 -8
- package/src/runtime/featureMount.ts +94 -0
- package/src/runtime/hardening.test.ts +22 -13
- package/src/runtime/instrumentation.test.ts +213 -194
- package/src/runtime/instrumentation.ts +6 -11
- package/src/runtime/loop.test.ts +84 -7
- package/src/runtime/loop.ts +69 -40
- package/src/runtime/runtimeHandle.ts +124 -0
- package/src/scene/featureScene.test.ts +4 -2
- package/src/scene/scene.ts +234 -64
- package/src/scene/seedScene.test.ts +69 -86
- package/src/state/state.nominal.typecheck.ts +68 -0
- package/src/state/state.test.ts +17 -0
- package/src/state/state.ts +79 -26
- package/src/state/stateFamily.test.ts +39 -8
- package/src/state/stateFamily.ts +55 -22
- package/src/state/stateGroup.ts +53 -17
- package/src/state/token.ts +40 -10
- package/src/synced/syncedStore.ts +46 -23
- package/src/testkit/flight.testkit.ts +84 -0
- package/src/wire/tree.test.ts +8 -4
- package/src/wire/triggers.test.ts +6 -2
- package/src/wire/triggers.ts +14 -10
- package/src/calc/asyncCalcDefinitions.ts +0 -48
- package/src/internal/ctx.ts +0 -9
- package/src/remote/remoteStateDefinition.ts +0 -135
- package/src/remote/remoteStateLayers.ts +0 -118
- package/src/remote/remoteStateLiveTypes.ts +0 -59
|
@@ -1,121 +1,254 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Store } from '../internal/store'
|
|
1
|
+
import { Layer, Schema as S } from 'effect'
|
|
3
2
|
import * as Composition from '../compose/composition'
|
|
4
3
|
import { provide } from '../compose/provide'
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type ContractOfSlotTarget,
|
|
6
|
+
type FeatureSlotTarget,
|
|
7
|
+
type PropsOfSlotTarget,
|
|
8
|
+
type SlotChild,
|
|
9
|
+
type SlotService,
|
|
10
|
+
slot,
|
|
11
|
+
} from '../compose/slot'
|
|
12
|
+
import { mount } from '../compose/structure'
|
|
6
13
|
import { type Contract, type UiClass, ui } from '../compose/ui'
|
|
7
|
-
import
|
|
8
|
-
import * as StateGroup from '../state/stateGroup'
|
|
14
|
+
import { scene } from '../scene/scene'
|
|
9
15
|
import { type EngineServices, type FeatureModule, featureModule, lazyImport } from './feature'
|
|
10
16
|
import * as Feature from './feature'
|
|
17
|
+
import { Clock, okService } from './featureModule.typecheck'
|
|
11
18
|
|
|
12
|
-
const FeedStateBase: State.StateClass<'feed', string> = State.make('feed', S.String)
|
|
13
|
-
class FeedState extends FeedStateBase {}
|
|
14
|
-
const FilterStateBase: State.StateClass<'filter', string> = State.make('filter', S.String)
|
|
15
|
-
class FilterState extends FilterStateBase {}
|
|
16
|
-
const TodosStatesBase: StateGroup.StateGroupClass<readonly [typeof FeedState, typeof FilterState]> =
|
|
17
|
-
StateGroup.make(FeedState, FilterState)
|
|
18
|
-
class TodosStates extends TodosStatesBase {}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
readonly
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
const AppUiBase: UiClass<{ props: { readonly a: string }; events: {} }, 'AppUi'> = ui('AppUi')<{
|
|
21
|
+
props: { readonly a: string }
|
|
22
|
+
events: {}
|
|
23
|
+
}>()
|
|
24
|
+
class AppUi extends AppUiBase {}
|
|
25
|
+
class AppComp extends Composition.make('AppComp', {
|
|
26
|
+
title: 'App',
|
|
27
|
+
props: S.Struct({ a: S.String }),
|
|
28
|
+
ui: AppUi,
|
|
29
|
+
})<AppComp>() {}
|
|
30
|
+
const AppLive = Composition.live(AppComp, function* () {
|
|
31
|
+
const props = yield* AppComp.props
|
|
32
|
+
return mount({ props: { a: props.a }, slots: {} })
|
|
33
|
+
})
|
|
34
|
+
declare const FailedPlaceholder: Composition.AnyComposition &
|
|
35
|
+
Composition.CompositionPropsReceiver<Feature.FailedProps>
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
class AppFeature extends Feature.make('appFeature', {
|
|
38
|
+
loadingStrategy: 'lazy',
|
|
39
|
+
composition: AppComp,
|
|
40
|
+
load: lazyImport(async () => ({ default: featureModule([], AppLive) })),
|
|
41
|
+
placeholder: { loading: AppComp, failed: FailedPlaceholder },
|
|
42
|
+
}) {}
|
|
43
|
+
type AppFeatureTarget = FeatureSlotTarget<typeof AppFeature>
|
|
44
|
+
class AppFeatureSlot extends slot('AppFeature')<AppFeatureSlot, AppFeatureTarget>() {}
|
|
32
45
|
|
|
33
|
-
|
|
34
|
-
|
|
46
|
+
class EmptyAppFeature extends Feature.make('emptyAppFeature', {
|
|
47
|
+
composition: AppComp,
|
|
48
|
+
// @ts-expect-error Layer.empty does not provide CompositionId<'AppComp'>
|
|
49
|
+
module: featureModule([], Layer.empty),
|
|
50
|
+
}) {}
|
|
35
51
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
52
|
+
declare const exactUnionModule: FeatureModule<
|
|
53
|
+
Composition.CompositionId<'AppComp', AppComp> | Clock,
|
|
54
|
+
readonly []
|
|
55
|
+
>
|
|
39
56
|
|
|
40
|
-
|
|
57
|
+
class ExactUnionAppFeature extends Feature.make('exactUnionAppFeature', {
|
|
58
|
+
composition: AppComp,
|
|
59
|
+
module: exactUnionModule,
|
|
60
|
+
}) {}
|
|
41
61
|
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
declare const unknownRootModule: FeatureModule<unknown, readonly []>
|
|
63
|
+
class UnknownRootAppFeature extends Feature.make('unknownRootAppFeature', {
|
|
64
|
+
composition: AppComp,
|
|
65
|
+
// @ts-expect-error unknown output does not prove the exact root composition service
|
|
66
|
+
module: unknownRootModule,
|
|
67
|
+
}) {}
|
|
44
68
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
69
|
+
declare const broadRootModule: FeatureModule<
|
|
70
|
+
Composition.CompositionId<string, unknown>,
|
|
71
|
+
readonly []
|
|
72
|
+
>
|
|
73
|
+
class BroadRootAppFeature extends Feature.make('broadRootAppFeature', {
|
|
74
|
+
composition: AppComp,
|
|
75
|
+
// @ts-expect-error a broad identifier does not prove the exact root identity
|
|
76
|
+
module: broadRootModule,
|
|
77
|
+
}) {}
|
|
48
78
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
events: {}
|
|
52
|
-
}>()
|
|
53
|
-
class AppUi extends AppUiBase {}
|
|
54
|
-
const AppCompBase: Composition.CompositionClass<{ readonly a: string }, Contract<typeof AppUi>> =
|
|
55
|
-
Composition.make('AppComp', {
|
|
56
|
-
title: 'App',
|
|
57
|
-
props: S.Struct({ a: S.String }),
|
|
58
|
-
ui: AppUi,
|
|
59
|
-
})
|
|
60
|
-
class AppComp extends AppCompBase {}
|
|
61
|
-
const AppSlotBase: SlotClass<typeof AppComp> = slot('App')<typeof AppComp>()
|
|
62
|
-
class AppSlot extends AppSlotBase {}
|
|
63
|
-
|
|
64
|
-
const AppFeatureBase: Feature.FeatureClass<
|
|
65
|
-
{ readonly a: string },
|
|
66
|
-
Contract<typeof AppUi>,
|
|
79
|
+
declare const exactUnionLayer: Layer.Layer<
|
|
80
|
+
Composition.CompositionId<'AppComp', AppComp> | Clock,
|
|
67
81
|
never,
|
|
68
|
-
|
|
69
|
-
>
|
|
82
|
+
never
|
|
83
|
+
>
|
|
84
|
+
|
|
85
|
+
const exactUnionScene = scene(AppComp, { provide: [exactUnionLayer] })
|
|
86
|
+
|
|
87
|
+
declare const unknownRootLayer: Layer.Layer<unknown, never, never>
|
|
88
|
+
// @ts-expect-error unknown services do not prove the exact scene root
|
|
89
|
+
const unknownRootScene = scene(AppComp, { provide: [unknownRootLayer] })
|
|
90
|
+
|
|
91
|
+
declare const broadRootLayer: Layer.Layer<Composition.CompositionId<string, unknown>, never, never>
|
|
92
|
+
// @ts-expect-error a broad composition identifier does not prove the exact scene root
|
|
93
|
+
const broadRootScene = scene(AppComp, { provide: [broadRootLayer] })
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
const wired = provide(AppFeatureSlot, AppFeature)
|
|
97
|
+
|
|
98
|
+
type Equal<Left, Right> =
|
|
99
|
+
(<Value>() => Value extends Left ? 1 : 2) extends <Value>() => Value extends Right ? 1 : 2
|
|
100
|
+
? true
|
|
101
|
+
: false
|
|
102
|
+
type Assert<Condition extends true> = Condition
|
|
103
|
+
type WiredRequirementsAreExact = Assert<Equal<Layer.Layer.Context<typeof wired>, EngineServices>>
|
|
104
|
+
type WiredOutputIsOnlySummary = Assert<
|
|
105
|
+
Equal<
|
|
106
|
+
Layer.Layer.Success<typeof wired>,
|
|
107
|
+
SlotService<'AppFeature', AppFeatureSlot, typeof AppFeature.summary>
|
|
108
|
+
>
|
|
109
|
+
>
|
|
110
|
+
type FeatureTargetSummaryIsExact = Assert<
|
|
111
|
+
Equal<AppFeatureTarget['summary'], typeof AppFeature.summary>
|
|
112
|
+
>
|
|
113
|
+
type FeatureTargetPropsAreExact = Assert<
|
|
114
|
+
Equal<PropsOfSlotTarget<AppFeatureTarget>, { readonly a: string }>
|
|
115
|
+
>
|
|
116
|
+
type FeatureTargetContractIsExact = Assert<
|
|
117
|
+
Equal<ContractOfSlotTarget<AppFeatureTarget>, Contract<typeof AppUi>>
|
|
118
|
+
>
|
|
119
|
+
type FeatureTargetCannotOpenTree = Assert<
|
|
120
|
+
Equal<AppFeatureTarget extends Feature.FeatureTreeCarrier ? true : false, false>
|
|
121
|
+
>
|
|
122
|
+
const appNative = Feature.tree<typeof AppFeature>(AppFeature.token)
|
|
123
|
+
type AppNative = typeof appNative
|
|
124
|
+
type ExactTreeComposition = Assert<Equal<AppNative['composition'], typeof AppComp>>
|
|
125
|
+
type NoDirectNativeFields = Assert<
|
|
126
|
+
Equal<
|
|
127
|
+
Extract<
|
|
128
|
+
'composition' | 'binding' | 'load' | 'eagerModule' | 'supportModule' | 'tree',
|
|
129
|
+
keyof typeof AppFeature
|
|
130
|
+
>,
|
|
131
|
+
never
|
|
132
|
+
>
|
|
133
|
+
>
|
|
134
|
+
|
|
135
|
+
class AppFeatureTwin extends Feature.make('appFeature', {
|
|
70
136
|
loadingStrategy: 'lazy',
|
|
71
137
|
composition: AppComp,
|
|
72
|
-
load: lazyImport(async () => ({ default: featureModule([],
|
|
73
|
-
placeholder: { loading: AppComp, failed:
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
138
|
+
load: lazyImport(async () => ({ default: featureModule([], AppLive) })),
|
|
139
|
+
placeholder: { loading: AppComp, failed: FailedPlaceholder },
|
|
140
|
+
}) {}
|
|
141
|
+
type SameCompositionTokenIsInterchangeable = Assert<
|
|
142
|
+
Equal<typeof AppFeatureTwin.token extends typeof AppFeature.token ? true : false, true>
|
|
143
|
+
>
|
|
144
|
+
type BroadFeatureIdentityIsRejected = Assert<
|
|
145
|
+
Equal<
|
|
146
|
+
Feature.FeatureIdentityToken<unknown> extends Feature.FeatureIdentityToken<AppComp>
|
|
147
|
+
? true
|
|
148
|
+
: false,
|
|
149
|
+
false
|
|
150
|
+
>
|
|
151
|
+
>
|
|
152
|
+
|
|
153
|
+
class AppCompositionSlot extends slot('AppComposition')<AppCompositionSlot, typeof AppComp>() {}
|
|
154
|
+
|
|
155
|
+
// @ts-expect-error composition slots accept the Composition value, not a Feature
|
|
156
|
+
provide(AppCompositionSlot, AppFeature)
|
|
78
157
|
|
|
79
158
|
class SupportedAppFeature extends Feature.make('supportedAppFeature', {
|
|
80
159
|
loadingStrategy: 'lazy',
|
|
81
160
|
composition: AppComp,
|
|
82
|
-
load: lazyImport(async () => ({ default: featureModule([],
|
|
161
|
+
load: lazyImport(async () => ({ default: featureModule([], AppLive) })),
|
|
83
162
|
eager: okService,
|
|
84
|
-
placeholder: { loading: AppComp, failed:
|
|
163
|
+
placeholder: { loading: AppComp, failed: FailedPlaceholder },
|
|
85
164
|
}) {}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
const
|
|
165
|
+
type SupportedAppFeatureTarget = FeatureSlotTarget<typeof SupportedAppFeature>
|
|
166
|
+
class SupportedAppFeatureSlot extends slot('SupportedAppFeature')<
|
|
167
|
+
SupportedAppFeatureSlot,
|
|
168
|
+
SupportedAppFeatureTarget
|
|
169
|
+
>() {}
|
|
170
|
+
|
|
171
|
+
const wiredWithSupport = provide(SupportedAppFeatureSlot, SupportedAppFeature)
|
|
172
|
+
type SupportedRequirementsAreExact = Assert<
|
|
173
|
+
Equal<Layer.Layer.Context<typeof wiredWithSupport>, EngineServices | Clock>
|
|
174
|
+
>
|
|
175
|
+
type SupportedOutputIsOnlySummary = Assert<
|
|
176
|
+
Equal<
|
|
177
|
+
Layer.Layer.Success<typeof wiredWithSupport>,
|
|
178
|
+
SlotService<'SupportedAppFeature', SupportedAppFeatureSlot, typeof SupportedAppFeature.summary>
|
|
179
|
+
>
|
|
180
|
+
>
|
|
181
|
+
|
|
182
|
+
const OtherUiBase: UiClass<{ props: { readonly n: number }; events: {} }, 'OtherUi'> = ui(
|
|
183
|
+
'OtherUi',
|
|
184
|
+
)<{
|
|
93
185
|
props: { readonly n: number }
|
|
94
186
|
events: {}
|
|
95
187
|
}>()
|
|
96
188
|
class OtherUi extends OtherUiBase {}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
never,
|
|
108
|
-
readonly []
|
|
109
|
-
> = Feature.make('otherFeature', {
|
|
189
|
+
class OtherComp extends Composition.make('OtherComp', {
|
|
190
|
+
title: 'Other',
|
|
191
|
+
props: S.Struct({ n: S.Number }),
|
|
192
|
+
ui: OtherUi,
|
|
193
|
+
})<OtherComp>() {}
|
|
194
|
+
const OtherLive = Composition.live(OtherComp, function* () {
|
|
195
|
+
const props = yield* OtherComp.props
|
|
196
|
+
return mount({ props, slots: {} })
|
|
197
|
+
})
|
|
198
|
+
class OtherFeature extends Feature.make('otherFeature', {
|
|
110
199
|
loadingStrategy: 'lazy',
|
|
111
200
|
composition: OtherComp,
|
|
112
|
-
load: lazyImport(async () => ({ default: featureModule([],
|
|
113
|
-
placeholder: { loading: OtherComp, failed:
|
|
114
|
-
})
|
|
115
|
-
class OtherFeature extends OtherFeatureBase {}
|
|
201
|
+
load: lazyImport(async () => ({ default: featureModule([], OtherLive) })),
|
|
202
|
+
placeholder: { loading: OtherComp, failed: FailedPlaceholder },
|
|
203
|
+
}) {}
|
|
116
204
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
205
|
+
type OtherFeatureIsRejectedByAppTarget = Assert<
|
|
206
|
+
Equal<typeof OtherFeature extends AppFeatureTarget ? true : false, false>
|
|
207
|
+
>
|
|
208
|
+
type DifferentCompositionTokenIsRejected = Assert<
|
|
209
|
+
Equal<typeof OtherFeature.token extends typeof AppFeature.token ? true : false, false>
|
|
210
|
+
>
|
|
211
|
+
const otherNative = Feature.tree<typeof OtherFeature>(OtherFeature.token)
|
|
212
|
+
type OtherNative = typeof otherNative
|
|
213
|
+
type DifferentCompositionBindingIsRejected = Assert<
|
|
214
|
+
Equal<OtherNative['binding'] extends SlotChild<AppFeatureTarget> ? true : false, false>
|
|
215
|
+
>
|
|
216
|
+
|
|
217
|
+
// @ts-expect-error OtherFeature.token does not belong to AppFeature
|
|
218
|
+
Feature.tree<typeof AppFeature>(OtherFeature.token)
|
|
219
|
+
|
|
220
|
+
// @ts-expect-error AppFeatureSlot accepts only features over AppComp
|
|
221
|
+
provide(AppFeatureSlot, OtherFeature)
|
|
222
|
+
|
|
223
|
+
type FeatureTypeProofs = [
|
|
224
|
+
WiredRequirementsAreExact,
|
|
225
|
+
WiredOutputIsOnlySummary,
|
|
226
|
+
FeatureTargetSummaryIsExact,
|
|
227
|
+
FeatureTargetPropsAreExact,
|
|
228
|
+
FeatureTargetContractIsExact,
|
|
229
|
+
FeatureTargetCannotOpenTree,
|
|
230
|
+
ExactTreeComposition,
|
|
231
|
+
NoDirectNativeFields,
|
|
232
|
+
SameCompositionTokenIsInterchangeable,
|
|
233
|
+
BroadFeatureIdentityIsRejected,
|
|
234
|
+
DifferentCompositionTokenIsRejected,
|
|
235
|
+
DifferentCompositionBindingIsRejected,
|
|
236
|
+
SupportedRequirementsAreExact,
|
|
237
|
+
SupportedOutputIsOnlySummary,
|
|
238
|
+
OtherFeatureIsRejectedByAppTarget,
|
|
239
|
+
]
|
|
240
|
+
declare const featureTypeProofs: FeatureTypeProofs
|
|
241
|
+
|
|
242
|
+
void featureTypeProofs
|
|
243
|
+
void appNative
|
|
244
|
+
void otherNative
|
|
245
|
+
void AppFeatureTwin
|
|
246
|
+
void EmptyAppFeature
|
|
247
|
+
void ExactUnionAppFeature
|
|
248
|
+
void UnknownRootAppFeature
|
|
249
|
+
void BroadRootAppFeature
|
|
250
|
+
void exactUnionScene
|
|
251
|
+
void unknownRootScene
|
|
252
|
+
void broadRootScene
|
|
253
|
+
|
|
254
|
+
export {}
|
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
import { Effect,
|
|
1
|
+
import type { Effect, Option } from 'effect'
|
|
2
|
+
import type { AnyComposition, CompositionClass } from '../compose/composition'
|
|
2
3
|
import type { Manifest } from '../definition/definition'
|
|
3
|
-
import
|
|
4
|
-
|
|
4
|
+
import {
|
|
5
|
+
type AnyFeatureGraphSummary,
|
|
6
|
+
FeatureGraphValidTypeId,
|
|
7
|
+
type FeatureSummaryCompositionIdentity,
|
|
8
|
+
type FeatureSummaryCompositionProps,
|
|
9
|
+
type FeatureSummaryContract,
|
|
10
|
+
type FeatureSummaryInput,
|
|
11
|
+
type FeatureSummaryName,
|
|
12
|
+
type FeatureSummaryOpenServices,
|
|
13
|
+
type FeatureSummaryStates,
|
|
14
|
+
type FeatureSummarySupportOpenServices,
|
|
15
|
+
type FeatureSummaryUsesInput,
|
|
16
|
+
} from '../graph/closure'
|
|
5
17
|
import type { FeatureLoadFailed } from '../internal/errors'
|
|
6
|
-
import type {
|
|
18
|
+
import type { Tagged } from '../runtime/bus'
|
|
19
|
+
import type { LoadedModule } from './featureModule'
|
|
20
|
+
import type { FeatureRequirement } from './featureRequirement'
|
|
7
21
|
|
|
8
22
|
export interface FailedProps {
|
|
9
23
|
readonly error: FeatureLoadFailed
|
|
@@ -21,28 +35,124 @@ export interface FeatureManifest extends Manifest {
|
|
|
21
35
|
}>
|
|
22
36
|
}
|
|
23
37
|
|
|
24
|
-
export interface LoadedModule {
|
|
25
|
-
readonly requires: ReadonlyArray<FeatureRequirement>
|
|
26
|
-
readonly usesInput: boolean
|
|
27
|
-
readonly layer: Layer.Layer<never, never, unknown>
|
|
28
|
-
}
|
|
29
|
-
|
|
30
38
|
export const FeatureBindingTypeId: unique symbol = Symbol.for('reform/FeatureBinding')
|
|
31
39
|
export type FeatureBindingTypeId = typeof FeatureBindingTypeId
|
|
40
|
+
export type FeatureBindingType = FeatureBindingTypeId
|
|
41
|
+
|
|
42
|
+
export const FeatureTokenIdentityTypeId: unique symbol = Symbol('reform/FeatureTokenIdentity')
|
|
43
|
+
export const FeatureNativeTypeId: unique symbol = Symbol('reform/FeatureNative')
|
|
44
|
+
|
|
45
|
+
export interface FeatureIdentityToken<out FeatureIdentity> {
|
|
46
|
+
readonly identity: symbol
|
|
47
|
+
readonly [FeatureTokenIdentityTypeId]: readonly [] | readonly [FeatureIdentity]
|
|
48
|
+
}
|
|
32
49
|
|
|
33
|
-
export interface
|
|
50
|
+
export interface FeatureToken<
|
|
51
|
+
out FeatureIdentity,
|
|
52
|
+
out NativeTree extends object,
|
|
53
|
+
> extends FeatureIdentityToken<FeatureIdentity> {
|
|
54
|
+
readonly [FeatureNativeTypeId]: NativeTree
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface FeatureTreeCarrier {
|
|
58
|
+
readonly token: FeatureToken<unknown, object>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type Native<
|
|
62
|
+
Feature extends FeatureTreeCarrier,
|
|
63
|
+
Token extends Feature['token'] = Feature['token'],
|
|
64
|
+
> = Token[typeof FeatureNativeTypeId]
|
|
65
|
+
|
|
66
|
+
export const tree = <
|
|
67
|
+
Feature extends FeatureTreeCarrier,
|
|
68
|
+
Token extends Feature['token'] = Feature['token'],
|
|
69
|
+
>(
|
|
70
|
+
token: Token,
|
|
71
|
+
): Native<Feature, Token> => token[FeatureNativeTypeId]
|
|
72
|
+
|
|
73
|
+
export interface ProvideableFeature<
|
|
74
|
+
out FeatureIdentity,
|
|
75
|
+
out Summary extends AnyFeatureGraphSummary,
|
|
76
|
+
> {
|
|
77
|
+
new (): {}
|
|
78
|
+
readonly manifest: FeatureManifest
|
|
79
|
+
readonly token: FeatureIdentityToken<FeatureIdentity>
|
|
80
|
+
readonly summary: Summary
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface FeatureDefinition<
|
|
84
|
+
out FeatureIdentity,
|
|
85
|
+
out Summary extends AnyFeatureGraphSummary,
|
|
86
|
+
out NativeTree extends object,
|
|
87
|
+
> extends ProvideableFeature<FeatureIdentity, Summary> {
|
|
88
|
+
readonly token: FeatureToken<FeatureIdentity, NativeTree>
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export type FeatureOpenServices<Feature extends { readonly summary: AnyFeatureGraphSummary }> =
|
|
92
|
+
FeatureSummaryOpenServices<Feature['summary']>
|
|
93
|
+
|
|
94
|
+
export type FeatureSupportOpenServices<
|
|
95
|
+
Feature extends { readonly summary: AnyFeatureGraphSummary },
|
|
96
|
+
> = FeatureSummarySupportOpenServices<Feature['summary']>
|
|
97
|
+
|
|
98
|
+
export interface AnyFeatureBindingExternalApi {
|
|
34
99
|
readonly [FeatureBindingTypeId]: FeatureBindingTypeId
|
|
100
|
+
readonly [FeatureGraphValidTypeId]: FeatureGraphValidTypeId
|
|
101
|
+
readonly capture: <Result>(visit: FeatureBindingCapture<Result>) => Result
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export type AnyFeatureBinding = AnyFeatureBindingExternalApi
|
|
105
|
+
|
|
106
|
+
export interface FeatureBinding<
|
|
107
|
+
Summary extends AnyFeatureGraphSummary,
|
|
108
|
+
ROut,
|
|
109
|
+
DirectRequires extends ReadonlyArray<FeatureRequirement>,
|
|
110
|
+
> extends AnyFeatureBindingExternalApi {
|
|
35
111
|
readonly manifest: FeatureManifest
|
|
36
|
-
readonly
|
|
112
|
+
readonly identity: symbol
|
|
113
|
+
readonly summary: Summary
|
|
114
|
+
readonly composition: CompositionClass<
|
|
115
|
+
FeatureSummaryCompositionProps<Summary>,
|
|
116
|
+
FeatureSummaryContract<Summary>,
|
|
117
|
+
FeatureSummaryStates<Summary>,
|
|
118
|
+
FeatureSummaryName<Summary>,
|
|
119
|
+
FeatureSummaryCompositionIdentity<Summary>
|
|
120
|
+
>
|
|
37
121
|
readonly strategy: 'lazy' | 'default'
|
|
38
|
-
readonly load: Effect.Effect<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
122
|
+
readonly load: Effect.Effect<
|
|
123
|
+
LoadedModule<
|
|
124
|
+
ROut,
|
|
125
|
+
DirectRequires,
|
|
126
|
+
FeatureSummaryOpenServices<Summary>,
|
|
127
|
+
FeatureSummaryUsesInput<Summary>,
|
|
128
|
+
FeatureSummaryInput<Summary>
|
|
129
|
+
>,
|
|
130
|
+
FeatureLoadFailed
|
|
131
|
+
>
|
|
132
|
+
readonly placeholder: Option.Option<{
|
|
133
|
+
readonly loading: AnyComposition
|
|
134
|
+
readonly failed: AnyComposition
|
|
135
|
+
}>
|
|
136
|
+
readonly parseInput: (input: unknown) => Option.Option<unknown>
|
|
43
137
|
readonly boot: ReadonlyArray<Tagged>
|
|
44
138
|
}
|
|
45
|
-
export type FeatureBinding = FeatureBindingExternalApi
|
|
46
139
|
|
|
47
|
-
export
|
|
48
|
-
|
|
140
|
+
export type CapturedFeatureBinding<
|
|
141
|
+
Summary extends AnyFeatureGraphSummary,
|
|
142
|
+
ROut,
|
|
143
|
+
DirectRequires extends ReadonlyArray<FeatureRequirement>,
|
|
144
|
+
> = FeatureBinding<Summary, ROut, DirectRequires>
|
|
145
|
+
|
|
146
|
+
export type FeatureBindingCapture<Result> = <
|
|
147
|
+
Summary extends AnyFeatureGraphSummary,
|
|
148
|
+
ROut,
|
|
149
|
+
DirectRequires extends ReadonlyArray<FeatureRequirement>,
|
|
150
|
+
>(
|
|
151
|
+
binding: FeatureBinding<Summary, ROut, DirectRequires>,
|
|
152
|
+
) => Result
|
|
153
|
+
|
|
154
|
+
export const isFeatureBinding = (candidate: unknown): candidate is AnyFeatureBinding =>
|
|
155
|
+
typeof candidate === 'object' &&
|
|
156
|
+
candidate !== null &&
|
|
157
|
+
FeatureBindingTypeId in candidate &&
|
|
158
|
+
FeatureGraphValidTypeId in candidate
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type { CompositionClass } from '../compose/composition'
|
|
2
|
+
import type { UiContract } from '../compose/ui'
|
|
3
|
+
import type { FeatureDefinition } from './featureBinding'
|
|
4
|
+
import type {
|
|
5
|
+
EagerFeatureNativeTree,
|
|
6
|
+
FeatureNativeTree,
|
|
7
|
+
FeatureSummaryOf,
|
|
8
|
+
LazyFeatureNativeTree,
|
|
9
|
+
} from './featureNativeTree'
|
|
10
|
+
import type {
|
|
11
|
+
DefaultFeatureOpenServices,
|
|
12
|
+
FeatureRequirement,
|
|
13
|
+
RootCompositionIdentity,
|
|
14
|
+
RootCompositionName,
|
|
15
|
+
} from './featureRequirement'
|
|
16
|
+
|
|
17
|
+
export interface FeatureClass<
|
|
18
|
+
FeatureIdentity,
|
|
19
|
+
P,
|
|
20
|
+
C extends UiContract,
|
|
21
|
+
ROut,
|
|
22
|
+
DirectRequires extends ReadonlyArray<FeatureRequirement>,
|
|
23
|
+
OpenServices = DefaultFeatureOpenServices<ROut, DirectRequires>,
|
|
24
|
+
SupportOut = never,
|
|
25
|
+
SupportDirectRequires extends ReadonlyArray<FeatureRequirement> = readonly [],
|
|
26
|
+
SupportOpenServices = DefaultFeatureOpenServices<SupportOut, SupportDirectRequires>,
|
|
27
|
+
UsesInput extends boolean = false,
|
|
28
|
+
Input = UsesInput extends true ? P : never,
|
|
29
|
+
S extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,
|
|
30
|
+
N extends string = RootCompositionName<ROut>,
|
|
31
|
+
CompositionProps = P,
|
|
32
|
+
Identity = RootCompositionIdentity<ROut>,
|
|
33
|
+
Composition extends CompositionClass<CompositionProps, C, S, N, Identity> = CompositionClass<
|
|
34
|
+
CompositionProps,
|
|
35
|
+
C,
|
|
36
|
+
S,
|
|
37
|
+
N,
|
|
38
|
+
Identity
|
|
39
|
+
>,
|
|
40
|
+
> extends FeatureDefinition<
|
|
41
|
+
FeatureIdentity,
|
|
42
|
+
FeatureSummaryOf<
|
|
43
|
+
FeatureIdentity,
|
|
44
|
+
P,
|
|
45
|
+
CompositionProps,
|
|
46
|
+
C,
|
|
47
|
+
S,
|
|
48
|
+
N,
|
|
49
|
+
Identity,
|
|
50
|
+
OpenServices,
|
|
51
|
+
SupportOpenServices,
|
|
52
|
+
UsesInput,
|
|
53
|
+
Input
|
|
54
|
+
>,
|
|
55
|
+
FeatureNativeTree<
|
|
56
|
+
FeatureSummaryOf<
|
|
57
|
+
FeatureIdentity,
|
|
58
|
+
P,
|
|
59
|
+
CompositionProps,
|
|
60
|
+
C,
|
|
61
|
+
S,
|
|
62
|
+
N,
|
|
63
|
+
Identity,
|
|
64
|
+
OpenServices,
|
|
65
|
+
SupportOpenServices,
|
|
66
|
+
UsesInput,
|
|
67
|
+
Input
|
|
68
|
+
>,
|
|
69
|
+
ROut,
|
|
70
|
+
DirectRequires,
|
|
71
|
+
SupportOut,
|
|
72
|
+
SupportDirectRequires,
|
|
73
|
+
Composition
|
|
74
|
+
>
|
|
75
|
+
> {}
|
|
76
|
+
|
|
77
|
+
export type EagerFeatureClass<
|
|
78
|
+
FeatureIdentity,
|
|
79
|
+
P,
|
|
80
|
+
C extends UiContract,
|
|
81
|
+
ROut,
|
|
82
|
+
DirectRequires extends ReadonlyArray<FeatureRequirement>,
|
|
83
|
+
OpenServices,
|
|
84
|
+
S extends ReadonlyArray<unknown>,
|
|
85
|
+
N extends string,
|
|
86
|
+
Identity,
|
|
87
|
+
Composition extends CompositionClass<P, C, S, N, Identity> = CompositionClass<
|
|
88
|
+
P,
|
|
89
|
+
C,
|
|
90
|
+
S,
|
|
91
|
+
N,
|
|
92
|
+
Identity
|
|
93
|
+
>,
|
|
94
|
+
> = FeatureDefinition<
|
|
95
|
+
FeatureIdentity,
|
|
96
|
+
FeatureSummaryOf<FeatureIdentity, P, P, C, S, N, Identity, OpenServices, never, false, never>,
|
|
97
|
+
EagerFeatureNativeTree<
|
|
98
|
+
FeatureSummaryOf<FeatureIdentity, P, P, C, S, N, Identity, OpenServices, never, false, never>,
|
|
99
|
+
ROut,
|
|
100
|
+
DirectRequires,
|
|
101
|
+
Composition
|
|
102
|
+
>
|
|
103
|
+
>
|
|
104
|
+
|
|
105
|
+
export type LazyFeatureClass<
|
|
106
|
+
FeatureIdentity,
|
|
107
|
+
P,
|
|
108
|
+
C extends UiContract,
|
|
109
|
+
ROut,
|
|
110
|
+
DirectRequires extends ReadonlyArray<FeatureRequirement>,
|
|
111
|
+
OpenServices,
|
|
112
|
+
SupportOut,
|
|
113
|
+
SupportDirectRequires extends ReadonlyArray<FeatureRequirement>,
|
|
114
|
+
SupportOpenServices,
|
|
115
|
+
UsesInput extends boolean,
|
|
116
|
+
S extends ReadonlyArray<unknown>,
|
|
117
|
+
N extends string,
|
|
118
|
+
CompositionProps,
|
|
119
|
+
Identity,
|
|
120
|
+
Composition extends CompositionClass<CompositionProps, C, S, N, Identity> = CompositionClass<
|
|
121
|
+
CompositionProps,
|
|
122
|
+
C,
|
|
123
|
+
S,
|
|
124
|
+
N,
|
|
125
|
+
Identity
|
|
126
|
+
>,
|
|
127
|
+
> = FeatureDefinition<
|
|
128
|
+
FeatureIdentity,
|
|
129
|
+
FeatureSummaryOf<
|
|
130
|
+
FeatureIdentity,
|
|
131
|
+
P,
|
|
132
|
+
CompositionProps,
|
|
133
|
+
C,
|
|
134
|
+
S,
|
|
135
|
+
N,
|
|
136
|
+
Identity,
|
|
137
|
+
OpenServices,
|
|
138
|
+
SupportOpenServices,
|
|
139
|
+
UsesInput,
|
|
140
|
+
UsesInput extends true ? P : never
|
|
141
|
+
>,
|
|
142
|
+
LazyFeatureNativeTree<
|
|
143
|
+
FeatureSummaryOf<
|
|
144
|
+
FeatureIdentity,
|
|
145
|
+
P,
|
|
146
|
+
CompositionProps,
|
|
147
|
+
C,
|
|
148
|
+
S,
|
|
149
|
+
N,
|
|
150
|
+
Identity,
|
|
151
|
+
OpenServices,
|
|
152
|
+
SupportOpenServices,
|
|
153
|
+
UsesInput,
|
|
154
|
+
UsesInput extends true ? P : never
|
|
155
|
+
>,
|
|
156
|
+
ROut,
|
|
157
|
+
DirectRequires,
|
|
158
|
+
SupportOut,
|
|
159
|
+
SupportDirectRequires,
|
|
160
|
+
Composition
|
|
161
|
+
>
|
|
162
|
+
>
|