@opetope/runtime 0.1.0 → 0.2.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/CHANGELOG.md +27 -0
- package/README.md +24 -13
- package/README.ru.md +26 -13
- package/dist/feature-authoring-types.d.ts +6 -10
- package/dist/feature-authoring.js +1 -1
- package/dist/feature-authoring.js.map +1 -1
- package/dist/feature-body.d.ts +1 -1
- package/dist/feature-body.js.map +1 -1
- package/dist/feature-contribution.d.ts +5 -3
- package/dist/feature-contribution.js +1 -1
- package/dist/feature-contribution.js.map +1 -1
- package/dist/feature-definition-api.d.ts +1 -1
- package/dist/feature-generation.js +1 -1
- package/dist/feature-generation.js.map +1 -1
- package/dist/feature-lazy-generation.d.ts +1 -1
- package/dist/feature-lazy-generation.js +1 -1
- package/dist/feature-lazy-generation.js.map +1 -1
- package/dist/feature-own-values.d.ts +10 -0
- package/dist/feature-own-values.js +2 -0
- package/dist/feature-own-values.js.map +1 -0
- package/dist/feature-port-binding.d.ts +2 -1
- package/dist/feature-port-binding.js +1 -1
- package/dist/feature-port-binding.js.map +1 -1
- package/dist/feature-port.d.ts +13 -23
- package/dist/feature-port.js +1 -1
- package/dist/feature-port.js.map +1 -1
- package/dist/public-module-types.d.ts +1 -1
- package/dist/public-module.d.ts +1 -1
- package/docs/agent-guide.md +11 -4
- package/docs/agent-guide.ru.md +11 -4
- package/docs/cookbook.md +9 -7
- package/docs/cookbook.ru.md +9 -7
- package/docs/decisions.md +15 -1
- package/docs/how-it-works.md +20 -5
- package/docs/how-it-works.ru.md +19 -5
- package/docs/releases.md +38 -17
- package/docs/releases.ru.md +37 -17
- package/docs/spec.md +31 -17
- package/docs/spec.ru.md +32 -18
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @opetope/runtime
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2d41c56: Give `provides` only its declaration builders and let nested callbacks select the current instance's live values:
|
|
8
|
+
|
|
9
|
+
- The outer `provides` receives exactly `{ port, register, slot, pipe }`, with no `own`.
|
|
10
|
+
- `port(Port, ({ own }) => own.model.call)` or `port(Port, ({ own }) => own.call)` selects an authentic Call during instance preparation, before readiness and contribution publication. Its callback receives only `{ own }`.
|
|
11
|
+
- `register` factories receive `{ own, imports }`.
|
|
12
|
+
- `slot` factories receive `{ own, imports, model }` for per-mount UI models.
|
|
13
|
+
- `when` predicates and `pipe.fold` handlers receive `{ own, imports, read }`.
|
|
14
|
+
|
|
15
|
+
This is a breaking authoring API change. Remove `own` from the outer `provides` context. Replace both `port(Port, ref)` and `port(Port, { from, select })` with a selector of the ready value, such as `port(Port, ({ own }) => own.order.submit)`. Port targets remain known at declaration; selecting the Call waits for the concrete instance.
|
|
16
|
+
|
|
17
|
+
Contribution contexts no longer expose `exports` or `instance`, and `register` no longer exposes `model`. Replace `context.exports.submit` with the source value, such as `context.own.order.submit`; remove exports needed only for internal composition. Replace instance-based binding with the ready value from `own`. Private model calls can be registered without adding them to the feature's public API. There are no compatibility aliases.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- @opetope/core@0.2.0
|
|
22
|
+
|
|
23
|
+
## 0.1.1
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- Updated dependencies [0de624b]
|
|
28
|
+
- @opetope/core@0.1.1
|
|
29
|
+
|
|
3
30
|
## 0.1.0
|
|
4
31
|
|
|
5
32
|
Initial release. See the package README for the supported API and usage.
|
package/README.md
CHANGED
|
@@ -64,8 +64,9 @@ The data sugar lives in that same `own` section and is lowered into ordinary att
|
|
|
64
64
|
- `effect({ from, when?, run, onDispose? })` takes an imported `Readable`, runs for the
|
|
65
65
|
initial snapshot and then latest-wins; the signal, the per-run timers and the returned disposer belong to that
|
|
66
66
|
exact run;
|
|
67
|
-
- `event(from, subscribe, { run })` gives the `subscribe` context a non-replayed `emit`, serialises
|
|
68
|
-
limits the queue to one pending payload;
|
|
67
|
+
- `event(from, subscribe, { run, backpressure? })` gives the `subscribe` context a non-replayed `emit`, serialises
|
|
68
|
+
the handler and limits the queue to one pending payload; `latest()` replaces that waiting payload, while the
|
|
69
|
+
default keeps it and reports a newer emit as an overflow. A failure and an overflow go to the application reporter.
|
|
69
70
|
Retirement aborts the handler, drops the pending payload and drains work already started before the source is released;
|
|
70
71
|
- `resource(from, target, { key, load, retry?, retention? })` watches a
|
|
71
72
|
`Readable<T | null | undefined>` returned by the target selector:
|
|
@@ -97,9 +98,10 @@ its own context created (D139). The refs of `model()` take no part in the loweri
|
|
|
97
98
|
cannot be used in `within`. A contribution component reads the models of its feature through `useModel` inside the
|
|
98
99
|
contribution mount, which binds them automatically. A single field goes outward through
|
|
99
100
|
`exports: ({ own }) => ({ x: own.model.field })`. A model call can also provide a port:
|
|
100
|
-
`port(SubmitPort, {
|
|
101
|
-
|
|
102
|
-
through a dependency call.
|
|
101
|
+
`port(SubmitPort, ({ own }) => own.order.submit)`. The selector receives only `{ own }` and runs once during instance
|
|
102
|
+
preparation, before readiness and publication; the selected authentic `Call` is fenced by the provider's lifetime
|
|
103
|
+
even if it passes through a dependency call. Use `port(SubmitPort, ({ own }) => own.submit)` for a call declared
|
|
104
|
+
directly in `own`. Both forms select ready Calls; direct refs and `{ from, select }` descriptors are not accepted (D255).
|
|
103
105
|
|
|
104
106
|
`target` is a selector `(source) => Readable<T | null | undefined>` in both feature and model APIs.
|
|
105
107
|
TypeScript infers the payload of the returned `Readable`, whose shape is checked before opening; a scalar
|
|
@@ -111,11 +113,11 @@ Both APIs publish one atomic snapshot `idle | opening | ready | refreshing | err
|
|
|
111
113
|
work; demand is set by a separate `retain()` lease. Retention by default merges the StrictMode
|
|
112
114
|
release/reacquire into one microtask and aborts unfinished work after the last lease. An explicit
|
|
113
115
|
`scoped({ capacity })` holds the materialization until retirement and bounds the sticky
|
|
114
|
-
cache.
|
|
115
|
-
|
|
116
|
+
cache. A nested contribution factory reads the instance-bound resource as `own.x` and can pass it to the UI;
|
|
117
|
+
the React `useResource` holds one lease per mounted consumer.
|
|
116
118
|
|
|
117
|
-
There are exactly two
|
|
118
|
-
`latest()` for stream backpressure. The former `drop`, `sample` and `queue` are removed together with their branches:
|
|
119
|
+
There are exactly two policy factories, and both have a production pilot: `scoped({ capacity })` for retention and
|
|
120
|
+
`latest()` for stream and event backpressure. The former `drop`, `sample` and `queue` are removed together with their branches:
|
|
119
121
|
they could not be named from the author vocabulary, so they measured only themselves (D160).
|
|
120
122
|
|
|
121
123
|
## Calls and lanes
|
|
@@ -206,7 +208,7 @@ explicit `key` keeps the current generation. `keyed` holds an independent child
|
|
|
206
208
|
unique `string | number` key. A repeated key rejects the whole new snapshot before any change to the children that are
|
|
207
209
|
already active. Retire fences the children synchronously and waits for their physical drain.
|
|
208
210
|
|
|
209
|
-
The `provides` section declares both ports and contributions: `port`
|
|
211
|
+
The `provides` section declares both ports and contributions: `port` selects an owned Call for a `Port`, while `slot`, `pipe` and
|
|
210
212
|
`register` declare a contribution by the kind of its target:
|
|
211
213
|
|
|
212
214
|
```ts
|
|
@@ -222,16 +224,25 @@ const titleFeature = defineFeature({
|
|
|
222
224
|
});
|
|
223
225
|
```
|
|
224
226
|
|
|
225
|
-
The outer factory
|
|
226
|
-
|
|
227
|
+
The outer factory receives only `{ port, register, slot, pipe }`, runs synchronously at `defineFeature`, and records
|
|
228
|
+
targets, ids and priorities for the application compiler before an instance opens. A `port` selector runs later,
|
|
229
|
+
with the instance's `{ own }`, during preparation. The second argument of `pipe(...)` is a `{ fold }` descriptor:
|
|
227
230
|
the runtime binds it to the concrete instance after the critical barrier and calls the handler only on a fold (D223).
|
|
228
|
-
`slot` and `register` take either a value factory
|
|
231
|
+
`slot` and `register` take either a value factory for the concrete instance, which also runs only after
|
|
229
232
|
that barrier, or a ready contribution value. An exact plain record must
|
|
230
233
|
return every receipt exactly once; the id of an entry is derived as `featureId.key`. The whole batch goes through
|
|
231
234
|
preflight and is published atomically. The start of retirement removes the entries synchronously before the async cleanup, including
|
|
232
235
|
a reentrant retirement from a target listener; a failed opening or an error in the value factory leaves no partially
|
|
233
236
|
published contributions.
|
|
234
237
|
|
|
238
|
+
The `register` value factory receives `{ own, imports }`; `slot` receives `{ own, imports, model }`, where `model`
|
|
239
|
+
declares a UI model created for each mount. `when` predicates and `pipe.fold` handlers receive `{ own, imports, read }`.
|
|
240
|
+
Their `own` contains the live models, calls and resources of that instance (D255). For example,
|
|
241
|
+
`register(target, ({ own }) => ({ key: 'submit', value: own.order.submit }))` registers a private model call without
|
|
242
|
+
exporting it. These contexts have no `exports` or `instance` field; `register` also has no `model` builder.
|
|
243
|
+
The outer `provides` has no `own`; each nested callback receives its own context of ready values. Model calls keep
|
|
244
|
+
their existing lifetime and owned state is read-only outside its model.
|
|
245
|
+
|
|
235
246
|
The feature API is declared by the `exports: ({ own }) => ({ … })` section: the contract is created from the feature
|
|
236
247
|
definition under the id `<feature>.exports`, and a consumer imports the definition itself — `imports: { provider: providerFeature }`.
|
|
237
248
|
Assigned missing/extra keys and incompatible `Call` signatures are rejected at compile time. Host-only values
|
package/README.ru.md
CHANGED
|
@@ -64,8 +64,9 @@ Cleanup failure по умолчанию best-effort `report`; retryable `quarant
|
|
|
64
64
|
- `effect({ from, when?, run, onDispose? })` принимает imported `Readable`, запускается для
|
|
65
65
|
начального snapshot и затем latest-wins; signal, per-run timers и возвращённый disposer принадлежат
|
|
66
66
|
exact запуску;
|
|
67
|
-
- `event(from, subscribe, { run })` даёт `subscribe`-контексту non-replayed `emit`, сериализует
|
|
68
|
-
ограничивает очередь одним ожидающим payload;
|
|
67
|
+
- `event(from, subscribe, { run, backpressure? })` даёт `subscribe`-контексту non-replayed `emit`, сериализует
|
|
68
|
+
обработчик и ограничивает очередь одним ожидающим payload; `latest()` заменяет этот ожидающий payload, а поведение
|
|
69
|
+
по умолчанию сохраняет его и репортит новый emit как переполнение. Отказ и переполнение уходят reporter-у приложения.
|
|
69
70
|
Retirement abort-ит handler, удаляет ожидающий payload и drain-ит уже запущенную работу до release source;
|
|
70
71
|
- `resource(from, target, { key, load, retry?, retention? })` следит за
|
|
71
72
|
`Readable<T | null | undefined>`, возвращённым target-селектором:
|
|
@@ -97,9 +98,11 @@ lookup: requires.lookup }, create)` передаёт readonly-запись ра
|
|
|
97
98
|
нельзя использовать в `within`. Компонент вклада читает модели своей фичи через `useModel` внутри монтирования
|
|
98
99
|
вклада, которое связывает их автоматически. Отдельное поле уходит наружу через
|
|
99
100
|
`exports: ({ own }) => ({ x: own.model.field })`. Вызов модели также может предоставлять порт:
|
|
100
|
-
`port(SubmitPort, {
|
|
101
|
-
|
|
102
|
-
передан из зависимости. Для объявленного
|
|
101
|
+
`port(SubmitPort, ({ own }) => own.order.submit)`. Селектор получает только `{ own }` и вызывается один раз при
|
|
102
|
+
подготовке экземпляра, до readiness и публикации; выбранный подлинный `Call` ограничен временем жизни провайдера,
|
|
103
|
+
даже когда он напрямую передан из зависимости. Для вызова, объявленного прямо в `own`, используется
|
|
104
|
+
`port(SubmitPort, ({ own }) => own.submit)`. Обе формы выбирают готовые Calls; прямые refs и дескрипторы
|
|
105
|
+
`{ from, select }` не принимаются (D255).
|
|
103
106
|
|
|
104
107
|
`target` — селектор `(source) => Readable<T | null | undefined>` и у фичи, и у модели.
|
|
105
108
|
TypeScript выводит payload возвращённого `Readable`, форма которого проверяется перед открытием;
|
|
@@ -111,11 +114,11 @@ TypeScript выводит payload возвращённого `Readable`, фор
|
|
|
111
114
|
работу; спрос задаёт отдельный lease `retain()`. Удержание по умолчанию объединяет StrictMode
|
|
112
115
|
release/reacquire в одну микрозадачу и abort-ит незавершённую работу после последнего lease. Явный
|
|
113
116
|
`scoped({ capacity })` удерживает materialization до retirement и ограничивает sticky
|
|
114
|
-
кэша.
|
|
115
|
-
|
|
117
|
+
кэша. Вложенная фабрика вклада получает привязанный к экземпляру ресурс как `own.x` и может передать его в UI;
|
|
118
|
+
React `useResource` держит один lease на смонтированного потребителя.
|
|
116
119
|
|
|
117
|
-
|
|
118
|
-
backpressure
|
|
120
|
+
Фабрик политик ровно две, и обе с production-пилотом: `scoped({ capacity })` для удержания и `latest()` для
|
|
121
|
+
backpressure стрима и события. Прежние `drop`, `sample` и `queue` удалены вместе с их ветками: назвать их из авторского
|
|
119
122
|
словаря было нельзя, поэтому они измеряли только сами себя (D160).
|
|
120
123
|
|
|
121
124
|
## Calls and lanes
|
|
@@ -205,7 +208,7 @@ own: ({ imports, scope }) => ({
|
|
|
205
208
|
уникальный `string | number` key. Повтор ключа отклоняет весь новый snapshot до любых изменений уже
|
|
206
209
|
активных детей. Retire синхронно фенсит детей и ждёт их физический дренаж.
|
|
207
210
|
|
|
208
|
-
Секция `provides` объявляет и порты, и вклады: `port`
|
|
211
|
+
Секция `provides` объявляет и порты, и вклады: `port` выбирает владеемый Call для `Port`, `slot`, `pipe` и
|
|
209
212
|
`register` объявляют вклад по виду цели:
|
|
210
213
|
|
|
211
214
|
```ts
|
|
@@ -221,16 +224,26 @@ const titleFeature = defineFeature({
|
|
|
221
224
|
});
|
|
222
225
|
```
|
|
223
226
|
|
|
224
|
-
Внешняя factory
|
|
225
|
-
|
|
227
|
+
Внешняя factory получает только `{ port, register, slot, pipe }`, синхронно выполняется при `defineFeature` и
|
|
228
|
+
записывает target/id/priority для компилятора приложения до открытия экземпляра. Селектор `port` выполняется
|
|
229
|
+
позже, с `{ own }` конкретного экземпляра, при его подготовке. Второй аргумент `pipe(...)` — дескриптор `{ fold }`: рантайм
|
|
226
230
|
связывает его с конкретным экземпляром после critical barrier и вызывает обработчик только на свёртке (D223).
|
|
227
|
-
`slot` и `register` принимают либо value factory
|
|
231
|
+
`slot` и `register` принимают либо value factory конкретного экземпляра, которая тоже выполняется только
|
|
228
232
|
после этого барьера, либо готовое значение вклада. Exact plain record обязан
|
|
229
233
|
вернуть каждый receipt ровно один раз; id записи выводится как `featureId.key`. Весь batch проходит
|
|
230
234
|
preflight и публикуется атомарно. Начало retirement синхронно удаляет записи до async cleanup, включая
|
|
231
235
|
reentrant retirement из target listener; failed opening или ошибка value factory не оставляют частично
|
|
232
236
|
опубликованных вкладов.
|
|
233
237
|
|
|
238
|
+
Value factory `register` получает `{ own, imports }`, а `slot` — `{ own, imports, model }`, где `model` объявляет
|
|
239
|
+
UI-модель, создаваемую на каждое монтирование. Предикаты `when` и обработчики `pipe.fold` получают `{ own, imports, read }`.
|
|
240
|
+
Их `own` содержит готовые модели, вызовы и ресурсы конкретного экземпляра (D255). Например,
|
|
241
|
+
`register(target, ({ own }) => ({ key: 'submit', value: own.order.submit }))` регистрирует вызов внутренней модели
|
|
242
|
+
без его экспорта. В этих контекстах нет полей `exports` и `instance`; у `register` также нет построителя `model`.
|
|
243
|
+
У внешней `provides` нет `own`; каждый вложенный колбэк получает собственный контекст готовых значений.
|
|
244
|
+
Вызовы модели сохраняют своё время жизни, а owned state за пределами модели доступен
|
|
245
|
+
только для чтения.
|
|
246
|
+
|
|
234
247
|
Feature API объявляется секцией `exports: ({ own }) => ({ … })`: contract создаётся из определения
|
|
235
248
|
фичи под id `<feature>.exports`, а consumer импортирует само определение — `imports: { provider: providerFeature }`.
|
|
236
249
|
Assigned missing/extra keys и несовместимые `Call` signatures отклоняются compile-time. Host-only значения
|
|
@@ -6,7 +6,6 @@ import type { FeatureAttachBuilder, FeatureCallsBuilder, FeatureImportRef, Featu
|
|
|
6
6
|
import type { FeatureCallBuilder, FeatureCallLaneBuilder, FeatureExposureMode, FeatureImportedAttachmentRef } from './feature-call-types.js';
|
|
7
7
|
import type { FeatureContract, FeatureContractIdentity, FeatureImportRecord, FeatureImportValues } from './feature-contract.js';
|
|
8
8
|
import type { FeatureContributionDescriptor } from './feature-contribution.js';
|
|
9
|
-
import type { ContributionModelBuilder } from './feature-contribution-model.js';
|
|
10
9
|
import type { FeatureResourceRef, FeatureStreamRef } from './feature-materialization-types.js';
|
|
11
10
|
import type { FeatureDataDescriptor, FeatureModelBuilder, FeatureModelRef } from './feature-model.js';
|
|
12
11
|
import type { FeatureRequiredCalls, PortProviderDescriptor, PortRequirementRecord, RequiredPortValues } from './feature-port.js';
|
|
@@ -15,7 +14,7 @@ import type { FeatureResourceBuilder } from './feature-resource.js';
|
|
|
15
14
|
import type { FeatureScopeBuilder } from './feature-scope-types.js';
|
|
16
15
|
import type { FeatureStreamBuilder } from './feature-stream.js';
|
|
17
16
|
import type { FeatureTimers } from './feature-timers.js';
|
|
18
|
-
import type { ModuleAttachmentRefIdentity, ModuleCallRef,
|
|
17
|
+
import type { ModuleAttachmentRefIdentity, ModuleCallRef, ModuleRuntimeRefIdentity, ModuleScopeRef } from './public-module.js';
|
|
19
18
|
declare const featureBrand: unique symbol;
|
|
20
19
|
type FeatureLifecycleRef<Source, Id extends string, Imports extends FeatureImportRecord, Mode extends FeatureExposureMode> = FeatureImportedAttachmentRef<Source, Id, FeatureImportValues<Imports>, Mode>;
|
|
21
20
|
type FeatureEffectRunContext<Source, Value> = {
|
|
@@ -144,18 +143,15 @@ type FeatureRead = <Value>(source: Readable<Value>) => Value;
|
|
|
144
143
|
* is the materialized form `exports` already uses — a model field is a `Readable`, not the ref the declaration
|
|
145
144
|
* context carries — because a calculation reads values and never constructs a node (D220).
|
|
146
145
|
*/
|
|
147
|
-
type FeatureEvaluationContext<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id
|
|
148
|
-
readonly exports: Exports;
|
|
146
|
+
type FeatureEvaluationContext<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id>> = {
|
|
149
147
|
readonly imports: FeatureImportValues<Imports>;
|
|
150
148
|
readonly own: FeatureOwnValues<Id, Runtime>;
|
|
151
149
|
readonly read: FeatureRead;
|
|
152
150
|
};
|
|
153
|
-
|
|
154
|
-
|
|
151
|
+
/** Contribution factories select live values; the outer `provides` carries only declaration builders (D255). */
|
|
152
|
+
type FeatureOpenContext<Id extends string, Imports extends FeatureImportRecord, Runtime extends FeatureOwnRecord<Id>> = {
|
|
155
153
|
readonly imports: FeatureImportValues<Imports>;
|
|
156
|
-
readonly
|
|
157
|
-
readonly model: ContributionModelBuilder;
|
|
158
|
-
readonly own: Runtime;
|
|
154
|
+
readonly own: FeatureOwnValues<Id, Runtime>;
|
|
159
155
|
};
|
|
160
156
|
type FeatureRecord = {
|
|
161
157
|
readonly contributions: readonly FeatureContributionDescriptor[];
|
|
@@ -193,4 +189,4 @@ type FeatureExportDeclarationSnapshot = {
|
|
|
193
189
|
readonly own: unknown;
|
|
194
190
|
}) => unknown;
|
|
195
191
|
};
|
|
196
|
-
export type { AnyFeature, AttachmentLowering, AttachmentProjection, AttachmentRecipe, Feature, FeatureAttachBuilder, FeatureCallBuilder, FeatureCallOperation, FeatureConditionsOf, FeatureEffectBuilder, FeatureEvaluationContext, FeatureEventBuilder, FeatureExportDeclarationSnapshot, FeatureExportRecord, FeatureExportsFactory, FeatureExportsOf, FeatureExposureMode, FeatureIdOf, FeatureImportRecord, FeatureImportRef, FeatureImportsOf, FeatureImportValues, FeatureLifecycleRef, FeatureOpenContext, FeatureOwnBuilder, FeatureOwnRecord, FeatureRecord, FeatureRequirementsOf, };
|
|
192
|
+
export type { AnyFeature, AttachmentLowering, AttachmentProjection, AttachmentRecipe, Feature, FeatureAttachBuilder, FeatureCallBuilder, FeatureCallOperation, FeatureConditionsOf, FeatureEffectBuilder, FeatureEvaluationContext, FeatureEventBuilder, FeatureExportDeclarationSnapshot, FeatureExportRecord, FeatureExportsFactory, FeatureExportsOf, FeatureExposureMode, FeatureIdOf, FeatureImportRecord, FeatureImportRef, FeatureImportsOf, FeatureImportValues, FeatureLifecycleRef, FeatureOpenContext, FeatureOwnBuilder, FeatureOwnRecord, FeatureOwnValues, FeatureRecord, FeatureRequirementsOf, };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{declarationId as
|
|
1
|
+
import{declarationId as $}from"@opetope/core";import{snapshotFeatureConditions as O}from"./condition.js";import{preloadFeatureBody as I,featureBody as M,requireFeatureBody as k}from"./feature-body.js";import{defineFeatureContract as q}from"./feature-contract.js";import{isFeatureContributionDeclaration as z,snapshotFeatureContributions as L,createFeatureContributionBuilders as G}from"./feature-contribution.js";import{snapshotFeatureOptions as H,requireString as W,snapshotFeatureExportDeclaration as x,optionalFunction as b,snapshotFeatureImports as j,snapshotFeatureRequirements as K,registerFeatureRecord as g,requireFeatureRecord as A}from"./feature-definition-support.js";import{isFeature as we}from"./feature-definition-support.js";import{snapshotDeclaredProvided as J,registerLazyFeature as N,assertBodyMatchesHeader as Q}from"./feature-lazy.js";import{lowerFeatureOwn as E}from"./feature-own-lowering.js";import{createPortBuilder as U,snapshotPortProviders as V}from"./feature-port.js";import{dataEntries as y,assertPlainRecord as X}from"./feature-record.js";import{defineModule as Y}from"./public-module-definition.js";const P=Y;function Z(r){if((typeof r!="object"||r===null)&&typeof r!="function")return!1;let e=r;for(;e!==null;){const t=Object.getOwnPropertyDescriptor(e,"then");if(t!==void 0)return"value"in t&&typeof t.value=="function";e=Object.getPrototypeOf(e)}return!1}function D(r,e){const t=G();if(e===void 0)return Object.freeze({contributions:Object.freeze([]),providers:Object.freeze([])});const i=e({pipe:t.pipe,port:U(),register:t.register,slot:t.slot});if(Z(i))throw Promise.resolve(i).catch(()=>{}),new TypeError("defineFeature provides must return synchronously.");X(i,"defineFeature provides result");const u=y(i,"defineFeature provides result"),s=u.filter(([,n])=>z(t,n)),c=u.filter(([,n])=>!z(t,n));return Object.freeze({contributions:L(r,t,s),providers:V(c)})}const v=new WeakMap;function _(r,e){const t=b(e.own,"defineFeature own")??(()=>({})),i=x(e.exports),u=b(e.provides,"defineFeature provides");let s;const c=P({id:r.id,runtime:F=>(s=E(F,{build:t,id:r.id,importKeys:r.importKeys,imports:r.imports,requirementKeys:r.requirementKeys}),s.loweredRuntime)});if(s===void 0)throw new TypeError("defineFeature own did not produce a public record.");const{dataDescriptors:n,importScopeKey:p,publicRuntime:f,requirementScopeKey:d}=s,m=f,{contributions:o,providers:a}=D(r.id,u);return{own:m,record:{contributions:o,dataDescriptors:n,exports:i.from,importKeys:r.importKeys,importScopeKey:p,module:c,providers:a,requirementKeys:r.requirementKeys,requirementScopeKey:d}}}function ee(r,e){for(const o of["exports","own"])if(r[o]!==void 0)throw new TypeError(`defineFeature ${e} declares body and ${o}: the implementation belongs to the body.`);if(typeof r.provides=="function")throw new TypeError(`defineFeature ${e} declares body and a provides factory: the header declares targets only.`);const t=r.body;if(typeof t!="function")throw new TypeError("defineFeature body must be a loader function.");const i=j(r.imports),u=K(r.requires),s=Object.freeze(y(i,"defineFeature imports").map(([o])=>o)),c=Object.freeze(y(u,"defineFeature requires").map(([o])=>o)),n=J(e,r.provides),p=q(`${e}.exports`);let f=Object.freeze({});const d=Object.freeze({exports:p,id:$(e),imports:i,get own(){return f},requires:u,when:O(r.when)}),m={id:e,importKeys:s,imports:i,requirementKeys:c};return g(d,{contributions:n.contributions,dataDescriptors:Object.freeze([]),exports:()=>({}),importKeys:s,importScopeKey:void 0,module:Object.freeze({}),providers:n.providers.map(o=>Object.freeze({...o,target:void 0})),requirementKeys:c,requirementScopeKey:void 0}),N(d,{load:()=>Promise.resolve(t()).then(o=>k(e,o)),materialize:o=>{const a=_(m,o);return Q(e,n,a.record),f=Object.freeze(a.own),a.record}}),v.set(p,d),d}function re(r){const e=H(r),t=W(e.id,"defineFeature id");if(e.body!==void 0)return ee(e,t);const i=x(e.exports),u=b(e.own,"defineFeature own")??(()=>({})),s=i.from,c=b(e.provides,"defineFeature provides"),n=j(e.imports),p=K(e.requires),f=y(p,"defineFeature requires"),d=Object.freeze(y(n,"defineFeature imports").map(([l])=>l)),m=Object.freeze(f.map(([l])=>l));let o;const a=P({id:t,runtime:l=>(o=E(l,{build:u,id:t,importKeys:d,imports:n,requirementKeys:m}),o.loweredRuntime)});if(o===void 0)throw new TypeError("defineFeature own did not produce a public record.");const{dataDescriptors:F,importScopeKey:C,publicRuntime:B,requirementScopeKey:R}=o,{contributions:S,providers:T}=D(t,c),h=q(`${t}.exports`),w=Object.freeze({exports:h,id:a.id,imports:n,own:B,requires:p,when:O(e.when)});return g(w,{contributions:S,dataDescriptors:F,exports:s,importKeys:d,importScopeKey:C,module:a,providers:T,requirementKeys:m,requirementScopeKey:R}),v.set(h,w),w}function te(r){return v.get(r)}const oe=Object.assign(re,{body:M,preload:I});function ne(r){return A(r).contributions}export{oe as defineFeature,te as getFeatureByExportContract,ne as getFeatureContributionDescriptors,we as isFeature};
|
|
2
2
|
//# sourceMappingURL=feature-authoring.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-authoring.js","sources":["../src/feature-authoring.ts"],"sourcesContent":["import { declarationId } from '@opetope/core';\n\nimport { snapshotFeatureConditions } from './condition';\nimport type { Condition } from './condition';\nimport type {\n AnyFeature,\n Feature,\n FeatureEvaluationContext,\n FeatureExportRecord,\n FeatureImportRecord,\n FeatureOpenContext,\n FeatureOwnBuilder,\n FeatureOwnRecord,\n FeatureRecord,\n} from './feature-authoring-types';\nimport { featureBody, preloadFeatureBody, requireFeatureBody } from './feature-body';\nimport type { LoadedFeatureBody } from './feature-body';\nimport { defineFeatureContract } from './feature-contract';\nimport {\n createFeatureContributionBuilders,\n isFeatureContributionDeclaration,\n snapshotFeatureContributions,\n} from './feature-contribution';\nimport type { FeatureContributionDescriptor } from './feature-contribution';\nimport type { DefineFeature, FeatureInput } from './feature-definition-api';\nimport {\n isFeature,\n optionalFunction,\n registerFeatureRecord,\n requireFeatureRecord,\n requireString,\n snapshotFeatureExportDeclaration,\n snapshotFeatureImports,\n snapshotFeatureOptions,\n snapshotFeatureRequirements,\n} from './feature-definition-support';\nimport { assertBodyMatchesHeader, registerLazyFeature, snapshotDeclaredProvided } from './feature-lazy';\nimport { lowerFeatureOwn } from './feature-own-lowering';\nimport type { FeatureOwnLoweringResult } from './feature-own-lowering';\nimport { createPortBuilder, snapshotPortProviders } from './feature-port';\nimport type { FeatureProvidedRecord, FeatureProvidesFactory, PortRequirementRecord } from './feature-port';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport type { ExactKeys } from './feature-record';\nimport { defineModule } from './public-module';\nimport type { ModuleDefinition, ModuleRuntimeBuilder, ModuleRuntimeRecord } from './public-module';\n\ntype DefineGeneratedModule = <Id extends string, Runtime extends ModuleRuntimeRecord<Id>>(options: {\n readonly id: Id;\n readonly runtime: (builder: ModuleRuntimeBuilder<Id>) => Runtime;\n}) => ModuleDefinition<Id, Runtime>;\n\n// The public defineModule guard rejects union author records. Feature lowering has already applied\n// the same guard before it appends collision-free private refs to one concrete `own` record.\nconst defineGeneratedModule = defineModule as DefineGeneratedModule;\n\nfunction hasDataThen(value: unknown): boolean {\n if ((typeof value !== 'object' || value === null) && typeof value !== 'function') return false;\n\n let source: object | null = value;\n\n while (source !== null) {\n const descriptor = Object.getOwnPropertyDescriptor(source, 'then');\n\n if (descriptor !== undefined) return 'value' in descriptor && typeof descriptor.value === 'function';\n\n source = Object.getPrototypeOf(source) as object | null;\n }\n\n return false;\n}\n\n/** `provides` returns ports and contributions in one record; each entry is split by the builder that made it. */\nfunction buildFeatureProvided<\n Id extends string,\n Context,\n Evaluation,\n Runtime extends FeatureOwnRecord<Id>,\n Provided extends FeatureProvidedRecord<Id>,\n>(\n featureId: string,\n build: FeatureProvidesFactory<Id, Context, Evaluation, Runtime, Provided> | undefined,\n own: Runtime,\n runtimeValues: ReadonlySet<object>,\n): Readonly<{\n contributions: readonly FeatureContributionDescriptor[];\n providers: FeatureRecord['providers'];\n}> {\n const builders = createFeatureContributionBuilders<Context, Evaluation>();\n\n if (build === undefined) return Object.freeze({ contributions: Object.freeze([]), providers: Object.freeze([]) });\n\n const value = build({\n own,\n pipe: builders.pipe,\n port: createPortBuilder<Id>(),\n register: builders.register,\n slot: builders.slot,\n });\n\n if (hasDataThen(value)) {\n void Promise.resolve(value).catch(() => undefined);\n\n throw new TypeError('defineFeature provides must return synchronously.');\n }\n\n assertPlainRecord(value, 'defineFeature provides result');\n const entries = dataEntries(value, 'defineFeature provides result');\n const contributionEntries = entries.filter(([, entry]) => isFeatureContributionDeclaration(builders as never, entry));\n const providerEntries = entries.filter(([, entry]) => !isFeatureContributionDeclaration(builders as never, entry));\n\n return Object.freeze({\n contributions: snapshotFeatureContributions(featureId, builders, contributionEntries),\n providers: snapshotPortProviders(runtimeValues, providerEntries),\n });\n}\n\nconst featuresByExportContract = new WeakMap<object, AnyFeature>();\n\ntype FeatureHeader = {\n readonly exportsContract: object;\n readonly id: string;\n readonly importKeys: readonly string[];\n readonly imports: FeatureImportRecord;\n readonly requirementKeys: readonly string[];\n readonly requirements: PortRequirementRecord;\n};\n\n/**\n * The heavy half of a feature: lowering `own`, running `provides` and selecting `exports`. An eager feature runs it\n * at declaration; a lazy one runs the very same code once its body has loaded (D186).\n */\nfunction materializeFeatureImplementation(\n header: FeatureHeader,\n body: LoadedFeatureBody,\n): { readonly own: Readonly<Record<string, unknown>>; readonly record: FeatureRecord } {\n const build =\n optionalFunction<(builder: never) => Readonly<Record<string, unknown>>>(body.own, 'defineFeature own') ??\n (() => ({}));\n const exportDeclaration = snapshotFeatureExportDeclaration(body.exports);\n const buildProvides = optionalFunction<FeatureProvidesFactory<string, never, never, never, never>>(\n body.provides,\n 'defineFeature provides',\n );\n let lowering: FeatureOwnLoweringResult<string, never> | undefined;\n const module = defineGeneratedModule({\n id: header.id,\n runtime: low => {\n lowering = lowerFeatureOwn(low as never, {\n build: build as never,\n id: header.id,\n importKeys: header.importKeys,\n imports: header.imports,\n requirementKeys: header.requirementKeys,\n }) as FeatureOwnLoweringResult<string, never>;\n\n return lowering.loweredRuntime;\n },\n });\n\n if (lowering === undefined) throw new TypeError('defineFeature own did not produce a public record.');\n\n const { dataDescriptors, importScopeKey, publicRuntime, requirementScopeKey } = lowering;\n const own = publicRuntime as unknown as Readonly<Record<string, unknown>>;\n const runtimeValues = new Set<object>(\n Object.values(own).filter((value): value is object => typeof value === 'object'),\n );\n const { contributions, providers } = buildFeatureProvided(\n header.id,\n buildProvides as never,\n publicRuntime,\n runtimeValues,\n );\n\n return {\n own,\n record: {\n contributions,\n dataDescriptors,\n exports: exportDeclaration.from,\n importKeys: header.importKeys,\n importScopeKey,\n module,\n providers,\n requirementKeys: header.requirementKeys,\n requirementScopeKey,\n },\n };\n}\n\n/**\n * D186: a header opens nothing by itself. It registers the identity, the edges and the declared border, and keeps\n * the loader; the body is materialized once, on the first open, and every later open reuses the same code.\n */\nfunction defineLazyFeature(source: Readonly<Record<string, unknown>>, id: string): AnyFeature {\n for (const key of ['exports', 'own'] as const) {\n if (source[key] !== undefined) {\n throw new TypeError(`defineFeature ${id} declares body and ${key}: the implementation belongs to the body.`);\n }\n }\n\n if (typeof source['provides'] === 'function') {\n throw new TypeError(`defineFeature ${id} declares body and a provides factory: the header declares targets only.`);\n }\n\n const load = source['body'];\n\n if (typeof load !== 'function') throw new TypeError('defineFeature body must be a loader function.');\n\n const imports = snapshotFeatureImports(source['imports'] as FeatureImportRecord | undefined);\n const requirements = snapshotFeatureRequirements(source['requires'] as PortRequirementRecord | undefined);\n const importKeys = Object.freeze(dataEntries(imports, 'defineFeature imports').map(([key]) => key));\n const requirementKeys = Object.freeze(dataEntries(requirements, 'defineFeature requires').map(([key]) => key));\n const declared = snapshotDeclaredProvided(id, source['provides']);\n const exportsContract = defineFeatureContract<{}>(`${id}.exports`);\n // The refs of `own` are minted by the body, so the header reads them through the record it materializes later.\n let materializedOwn: Readonly<Record<string, unknown>> = Object.freeze({});\n const feature = Object.freeze({\n exports: exportsContract,\n id: declarationId(id),\n imports,\n get own(): Readonly<Record<string, unknown>> {\n return materializedOwn;\n },\n requires: requirements,\n when: snapshotFeatureConditions(source['when']),\n }) as unknown as AnyFeature;\n const header: FeatureHeader = { exportsContract, id, importKeys, imports, requirementKeys, requirements };\n\n registerFeatureRecord(feature, {\n contributions: declared.contributions,\n dataDescriptors: Object.freeze([]),\n exports: () => ({}),\n importKeys,\n importScopeKey: undefined,\n module: Object.freeze({}),\n providers: declared.providers.map(entry => Object.freeze({ ...entry, target: undefined })) as never,\n requirementKeys,\n requirementScopeKey: undefined,\n });\n registerLazyFeature(feature, {\n load: () => Promise.resolve((load as () => PromiseLike<unknown>)()).then(value => requireFeatureBody(id, value)),\n materialize: (body: LoadedFeatureBody) => {\n const materialized = materializeFeatureImplementation(header, body);\n assertBodyMatchesHeader(id, declared, materialized.record);\n materializedOwn = Object.freeze(materialized.own);\n\n return materialized.record;\n },\n });\n featuresByExportContract.set(exportsContract, feature);\n\n return feature;\n}\n\nfunction defineFeatureImplementation<\n const Id extends string,\n const Imports extends FeatureImportRecord,\n const Runtime extends FeatureOwnRecord<Id>,\n const Exports extends FeatureExportRecord,\n const Requires extends PortRequirementRecord = {},\n const Provided extends FeatureProvidedRecord<Id> = FeatureProvidedRecord<Id>,\n When extends readonly Condition[] = readonly Condition[],\n const Keys extends PropertyKey = keyof FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>,\n>(\n options: ExactKeys<Keys, FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>> &\n FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>,\n): Feature<Id, Imports, Runtime, Exports, Requires, When> {\n const source = snapshotFeatureOptions(options);\n const id = requireString<Id>(source['id'], 'defineFeature id');\n\n if (source['body'] !== undefined) {\n return defineLazyFeature(source, id) as unknown as Feature<Id, Imports, Runtime, Exports, Requires, When>;\n }\n\n const exportDeclaration = snapshotFeatureExportDeclaration(source['exports']);\n const build =\n optionalFunction<(builder: FeatureOwnBuilder<Id, Imports, Requires>) => Runtime>(\n source['own'],\n 'defineFeature own',\n ) ?? ((() => ({})) as unknown as (builder: FeatureOwnBuilder<Id, Imports, Requires>) => Runtime);\n const selectExports = exportDeclaration.from;\n const buildProvides = optionalFunction<\n FeatureProvidesFactory<\n Id,\n FeatureOpenContext<Id, Imports, Runtime, Exports>,\n FeatureEvaluationContext<Id, Imports, Runtime, Exports>,\n Runtime,\n Provided\n >\n >(source['provides'], 'defineFeature provides');\n\n const imports = snapshotFeatureImports(source['imports'] as Imports);\n const requirements = snapshotFeatureRequirements(source['requires'] as Requires | undefined);\n const requirementEntries = dataEntries(requirements, 'defineFeature requires');\n const importKeys = Object.freeze(dataEntries(imports, 'defineFeature imports').map(([key]) => key));\n const requirementKeys = Object.freeze(requirementEntries.map(([key]) => key));\n let lowering: FeatureOwnLoweringResult<Id, Runtime> | undefined;\n const module = defineGeneratedModule({\n id,\n runtime: low => {\n lowering = lowerFeatureOwn(low, {\n build,\n id,\n importKeys,\n imports,\n requirementKeys,\n });\n\n return lowering.loweredRuntime;\n },\n });\n\n if (lowering === undefined) throw new TypeError('defineFeature own did not produce a public record.');\n\n const { dataDescriptors, importScopeKey, publicRuntime, requirementScopeKey } = lowering;\n\n const runtimeValues = new Set(Object.values(publicRuntime));\n const { contributions, providers } = buildFeatureProvided<\n Id,\n FeatureOpenContext<Id, Imports, Runtime, Exports>,\n FeatureEvaluationContext<Id, Imports, Runtime, Exports>,\n Runtime,\n Provided\n >(id, buildProvides, publicRuntime, runtimeValues);\n\n const exportsContract = defineFeatureContract<{}>(`${id}.exports`);\n const feature = Object.freeze({\n exports: exportsContract,\n id: module.id,\n imports,\n own: publicRuntime,\n requires: requirements,\n when: snapshotFeatureConditions(source['when']),\n }) as unknown as Feature<Id, Imports, Runtime, Exports, Requires, When>;\n registerFeatureRecord(feature, {\n contributions,\n dataDescriptors,\n exports: selectExports,\n importKeys,\n importScopeKey,\n module,\n providers,\n requirementKeys,\n requirementScopeKey,\n });\n featuresByExportContract.set(exportsContract, feature);\n\n return feature;\n}\n\n/** `imports` stores the contract, so the application world resolves a feature edge back to the feature (D68). */\nfunction getFeatureByExportContract(contract: object): AnyFeature | undefined {\n return featuresByExportContract.get(contract);\n}\n\n// D186: one word, two forms — the eager triple and the lazy header, so the overload set is the public type.\n// D207: `defineFeature.body` writes the implementation of a header; a member costs no new word of the vocabulary.\nconst defineFeature = Object.assign(defineFeatureImplementation as unknown as DefineFeature, {\n body: featureBody,\n preload: preloadFeatureBody,\n});\n\nfunction getFeatureModule<\n const Id extends string,\n const Imports extends FeatureImportRecord,\n const Runtime extends FeatureOwnRecord<Id>,\n const Exports extends FeatureExportRecord,\n>(feature: Feature<Id, Imports, Runtime, Exports>): ModuleDefinition<Id> {\n return requireFeatureRecord(feature).module as ModuleDefinition<Id>;\n}\n\nfunction getFeatureContributionDescriptors(feature: AnyFeature): FeatureRecord['contributions'] {\n return requireFeatureRecord(feature).contributions;\n}\n\nexport { defineFeature, getFeatureByExportContract, getFeatureContributionDescriptors, getFeatureModule, isFeature };\nexport type {\n AnyFeature,\n Feature,\n FeatureConditionsOf,\n FeatureExportRecord,\n FeatureExportsOf,\n FeatureIdOf,\n FeatureImportRecord,\n FeatureImportsOf,\n FeatureImportValues,\n FeatureOwnRecord,\n FeatureRequirementsOf,\n} from './feature-authoring-types';\n"],"names":["defineGeneratedModule","defineModule","hasDataThen","value","source","descriptor","buildFeatureProvided","featureId","build","own","runtimeValues","builders","createFeatureContributionBuilders","createPortBuilder","assertPlainRecord","entries","dataEntries","contributionEntries","entry","isFeatureContributionDeclaration","providerEntries","snapshotFeatureContributions","snapshotPortProviders","featuresByExportContract","materializeFeatureImplementation","header","body","optionalFunction","exportDeclaration","snapshotFeatureExportDeclaration","buildProvides","lowering","module","low","lowerFeatureOwn","dataDescriptors","importScopeKey","publicRuntime","requirementScopeKey","contributions","providers","defineLazyFeature","id","key","load","imports","snapshotFeatureImports","requirements","snapshotFeatureRequirements","importKeys","requirementKeys","declared","snapshotDeclaredProvided","exportsContract","defineFeatureContract","materializedOwn","feature","declarationId","snapshotFeatureConditions","registerFeatureRecord","registerLazyFeature","requireFeatureBody","materialized","assertBodyMatchesHeader","defineFeatureImplementation","options","snapshotFeatureOptions","requireString","selectExports","requirementEntries","getFeatureByExportContract","contract","defineFeature","featureBody","preloadFeatureBody","getFeatureContributionDescriptors","requireFeatureRecord"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"feature-authoring.js","sources":["../src/feature-authoring.ts"],"sourcesContent":["import { declarationId } from '@opetope/core';\n\nimport { snapshotFeatureConditions } from './condition';\nimport type { Condition } from './condition';\nimport type {\n AnyFeature,\n Feature,\n FeatureEvaluationContext,\n FeatureExportRecord,\n FeatureImportRecord,\n FeatureOpenContext,\n FeatureOwnBuilder,\n FeatureOwnRecord,\n FeatureRecord,\n} from './feature-authoring-types';\nimport { featureBody, preloadFeatureBody, requireFeatureBody } from './feature-body';\nimport type { LoadedFeatureBody } from './feature-body';\nimport { defineFeatureContract } from './feature-contract';\nimport {\n createFeatureContributionBuilders,\n isFeatureContributionDeclaration,\n snapshotFeatureContributions,\n} from './feature-contribution';\nimport type { FeatureContributionDescriptor } from './feature-contribution';\nimport type { DefineFeature, FeatureInput } from './feature-definition-api';\nimport {\n isFeature,\n optionalFunction,\n registerFeatureRecord,\n requireFeatureRecord,\n requireString,\n snapshotFeatureExportDeclaration,\n snapshotFeatureImports,\n snapshotFeatureOptions,\n snapshotFeatureRequirements,\n} from './feature-definition-support';\nimport { assertBodyMatchesHeader, registerLazyFeature, snapshotDeclaredProvided } from './feature-lazy';\nimport { lowerFeatureOwn } from './feature-own-lowering';\nimport type { FeatureOwnLoweringResult } from './feature-own-lowering';\nimport { createPortBuilder, snapshotPortProviders } from './feature-port';\nimport type { FeatureProvidedRecord, FeatureProvidesFactory, PortRequirementRecord } from './feature-port';\nimport { assertPlainRecord, dataEntries } from './feature-record';\nimport type { ExactKeys } from './feature-record';\nimport { defineModule } from './public-module';\nimport type { ModuleDefinition, ModuleRuntimeBuilder, ModuleRuntimeRecord } from './public-module';\n\ntype DefineGeneratedModule = <Id extends string, Runtime extends ModuleRuntimeRecord<Id>>(options: {\n readonly id: Id;\n readonly runtime: (builder: ModuleRuntimeBuilder<Id>) => Runtime;\n}) => ModuleDefinition<Id, Runtime>;\n\n// The public defineModule guard rejects union author records. Feature lowering has already applied\n// the same guard before it appends collision-free private refs to one concrete `own` record.\nconst defineGeneratedModule = defineModule as DefineGeneratedModule;\n\nfunction hasDataThen(value: unknown): boolean {\n if ((typeof value !== 'object' || value === null) && typeof value !== 'function') return false;\n\n let source: object | null = value;\n\n while (source !== null) {\n const descriptor = Object.getOwnPropertyDescriptor(source, 'then');\n\n if (descriptor !== undefined) return 'value' in descriptor && typeof descriptor.value === 'function';\n\n source = Object.getPrototypeOf(source) as object | null;\n }\n\n return false;\n}\n\n/** `provides` returns ports and contributions in one record; each entry is split by the builder that made it. */\nfunction buildFeatureProvided<\n Id extends string,\n Context,\n Evaluation,\n Runtime extends FeatureOwnRecord<Id>,\n Provided extends FeatureProvidedRecord<Id>,\n>(\n featureId: string,\n build: FeatureProvidesFactory<Id, Context, Evaluation, Runtime, Provided> | undefined,\n): Readonly<{\n contributions: readonly FeatureContributionDescriptor[];\n providers: FeatureRecord['providers'];\n}> {\n const builders = createFeatureContributionBuilders<Context, Evaluation>();\n\n if (build === undefined) return Object.freeze({ contributions: Object.freeze([]), providers: Object.freeze([]) });\n\n const value = build({\n pipe: builders.pipe,\n port: createPortBuilder(),\n register: builders.register,\n slot: builders.slot,\n });\n\n if (hasDataThen(value)) {\n void Promise.resolve(value).catch(() => undefined);\n\n throw new TypeError('defineFeature provides must return synchronously.');\n }\n\n assertPlainRecord(value, 'defineFeature provides result');\n const entries = dataEntries(value, 'defineFeature provides result');\n const contributionEntries = entries.filter(([, entry]) => isFeatureContributionDeclaration(builders as never, entry));\n const providerEntries = entries.filter(([, entry]) => !isFeatureContributionDeclaration(builders as never, entry));\n\n return Object.freeze({\n contributions: snapshotFeatureContributions(featureId, builders, contributionEntries),\n providers: snapshotPortProviders(providerEntries),\n });\n}\n\nconst featuresByExportContract = new WeakMap<object, AnyFeature>();\n\ntype FeatureHeader = {\n readonly exportsContract: object;\n readonly id: string;\n readonly importKeys: readonly string[];\n readonly imports: FeatureImportRecord;\n readonly requirementKeys: readonly string[];\n readonly requirements: PortRequirementRecord;\n};\n\n/**\n * The heavy half of a feature: lowering `own`, running `provides` and selecting `exports`. An eager feature runs it\n * at declaration; a lazy one runs the very same code once its body has loaded (D186).\n */\nfunction materializeFeatureImplementation(\n header: FeatureHeader,\n body: LoadedFeatureBody,\n): { readonly own: Readonly<Record<string, unknown>>; readonly record: FeatureRecord } {\n const build =\n optionalFunction<(builder: never) => Readonly<Record<string, unknown>>>(body.own, 'defineFeature own') ??\n (() => ({}));\n const exportDeclaration = snapshotFeatureExportDeclaration(body.exports);\n const buildProvides = optionalFunction<FeatureProvidesFactory<string, never, never, never, never>>(\n body.provides,\n 'defineFeature provides',\n );\n let lowering: FeatureOwnLoweringResult<string, never> | undefined;\n const module = defineGeneratedModule({\n id: header.id,\n runtime: low => {\n lowering = lowerFeatureOwn(low as never, {\n build: build as never,\n id: header.id,\n importKeys: header.importKeys,\n imports: header.imports,\n requirementKeys: header.requirementKeys,\n }) as FeatureOwnLoweringResult<string, never>;\n\n return lowering.loweredRuntime;\n },\n });\n\n if (lowering === undefined) throw new TypeError('defineFeature own did not produce a public record.');\n\n const { dataDescriptors, importScopeKey, publicRuntime, requirementScopeKey } = lowering;\n const own = publicRuntime as unknown as Readonly<Record<string, unknown>>;\n const { contributions, providers } = buildFeatureProvided(header.id, buildProvides as never);\n\n return {\n own,\n record: {\n contributions,\n dataDescriptors,\n exports: exportDeclaration.from,\n importKeys: header.importKeys,\n importScopeKey,\n module,\n providers,\n requirementKeys: header.requirementKeys,\n requirementScopeKey,\n },\n };\n}\n\n/**\n * D186: a header opens nothing by itself. It registers the identity, the edges and the declared border, and keeps\n * the loader; the body is materialized once, on the first open, and every later open reuses the same code.\n */\nfunction defineLazyFeature(source: Readonly<Record<string, unknown>>, id: string): AnyFeature {\n for (const key of ['exports', 'own'] as const) {\n if (source[key] !== undefined) {\n throw new TypeError(`defineFeature ${id} declares body and ${key}: the implementation belongs to the body.`);\n }\n }\n\n if (typeof source['provides'] === 'function') {\n throw new TypeError(`defineFeature ${id} declares body and a provides factory: the header declares targets only.`);\n }\n\n const load = source['body'];\n\n if (typeof load !== 'function') throw new TypeError('defineFeature body must be a loader function.');\n\n const imports = snapshotFeatureImports(source['imports'] as FeatureImportRecord | undefined);\n const requirements = snapshotFeatureRequirements(source['requires'] as PortRequirementRecord | undefined);\n const importKeys = Object.freeze(dataEntries(imports, 'defineFeature imports').map(([key]) => key));\n const requirementKeys = Object.freeze(dataEntries(requirements, 'defineFeature requires').map(([key]) => key));\n const declared = snapshotDeclaredProvided(id, source['provides']);\n const exportsContract = defineFeatureContract<{}>(`${id}.exports`);\n // The refs of `own` are minted by the body, so the header reads them through the record it materializes later.\n let materializedOwn: Readonly<Record<string, unknown>> = Object.freeze({});\n const feature = Object.freeze({\n exports: exportsContract,\n id: declarationId(id),\n imports,\n get own(): Readonly<Record<string, unknown>> {\n return materializedOwn;\n },\n requires: requirements,\n when: snapshotFeatureConditions(source['when']),\n }) as unknown as AnyFeature;\n const header: FeatureHeader = { exportsContract, id, importKeys, imports, requirementKeys, requirements };\n\n registerFeatureRecord(feature, {\n contributions: declared.contributions,\n dataDescriptors: Object.freeze([]),\n exports: () => ({}),\n importKeys,\n importScopeKey: undefined,\n module: Object.freeze({}),\n providers: declared.providers.map(entry => Object.freeze({ ...entry, target: undefined })) as never,\n requirementKeys,\n requirementScopeKey: undefined,\n });\n registerLazyFeature(feature, {\n load: () => Promise.resolve((load as () => PromiseLike<unknown>)()).then(value => requireFeatureBody(id, value)),\n materialize: (body: LoadedFeatureBody) => {\n const materialized = materializeFeatureImplementation(header, body);\n assertBodyMatchesHeader(id, declared, materialized.record);\n materializedOwn = Object.freeze(materialized.own);\n\n return materialized.record;\n },\n });\n featuresByExportContract.set(exportsContract, feature);\n\n return feature;\n}\n\nfunction defineFeatureImplementation<\n const Id extends string,\n const Imports extends FeatureImportRecord,\n const Runtime extends FeatureOwnRecord<Id>,\n const Exports extends FeatureExportRecord,\n const Requires extends PortRequirementRecord = {},\n const Provided extends FeatureProvidedRecord<Id> = FeatureProvidedRecord<Id>,\n When extends readonly Condition[] = readonly Condition[],\n const Keys extends PropertyKey = keyof FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>,\n>(\n options: ExactKeys<Keys, FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>> &\n FeatureInput<Id, Imports, Requires, Runtime, Exports, Provided, When>,\n): Feature<Id, Imports, Runtime, Exports, Requires, When> {\n const source = snapshotFeatureOptions(options);\n const id = requireString<Id>(source['id'], 'defineFeature id');\n\n if (source['body'] !== undefined) {\n return defineLazyFeature(source, id) as unknown as Feature<Id, Imports, Runtime, Exports, Requires, When>;\n }\n\n const exportDeclaration = snapshotFeatureExportDeclaration(source['exports']);\n const build =\n optionalFunction<(builder: FeatureOwnBuilder<Id, Imports, Requires>) => Runtime>(\n source['own'],\n 'defineFeature own',\n ) ?? ((() => ({})) as unknown as (builder: FeatureOwnBuilder<Id, Imports, Requires>) => Runtime);\n const selectExports = exportDeclaration.from;\n const buildProvides = optionalFunction<\n FeatureProvidesFactory<\n Id,\n FeatureOpenContext<Id, Imports, Runtime>,\n FeatureEvaluationContext<Id, Imports, Runtime>,\n Runtime,\n Provided\n >\n >(source['provides'], 'defineFeature provides');\n\n const imports = snapshotFeatureImports(source['imports'] as Imports);\n const requirements = snapshotFeatureRequirements(source['requires'] as Requires | undefined);\n const requirementEntries = dataEntries(requirements, 'defineFeature requires');\n const importKeys = Object.freeze(dataEntries(imports, 'defineFeature imports').map(([key]) => key));\n const requirementKeys = Object.freeze(requirementEntries.map(([key]) => key));\n let lowering: FeatureOwnLoweringResult<Id, Runtime> | undefined;\n const module = defineGeneratedModule({\n id,\n runtime: low => {\n lowering = lowerFeatureOwn(low, {\n build,\n id,\n importKeys,\n imports,\n requirementKeys,\n });\n\n return lowering.loweredRuntime;\n },\n });\n\n if (lowering === undefined) throw new TypeError('defineFeature own did not produce a public record.');\n\n const { dataDescriptors, importScopeKey, publicRuntime, requirementScopeKey } = lowering;\n\n const { contributions, providers } = buildFeatureProvided<\n Id,\n FeatureOpenContext<Id, Imports, Runtime>,\n FeatureEvaluationContext<Id, Imports, Runtime>,\n Runtime,\n Provided\n >(id, buildProvides);\n\n const exportsContract = defineFeatureContract<{}>(`${id}.exports`);\n const feature = Object.freeze({\n exports: exportsContract,\n id: module.id,\n imports,\n own: publicRuntime,\n requires: requirements,\n when: snapshotFeatureConditions(source['when']),\n }) as unknown as Feature<Id, Imports, Runtime, Exports, Requires, When>;\n registerFeatureRecord(feature, {\n contributions,\n dataDescriptors,\n exports: selectExports,\n importKeys,\n importScopeKey,\n module,\n providers,\n requirementKeys,\n requirementScopeKey,\n });\n featuresByExportContract.set(exportsContract, feature);\n\n return feature;\n}\n\n/** `imports` stores the contract, so the application world resolves a feature edge back to the feature (D68). */\nfunction getFeatureByExportContract(contract: object): AnyFeature | undefined {\n return featuresByExportContract.get(contract);\n}\n\n// D186: one word, two forms — the eager triple and the lazy header, so the overload set is the public type.\n// D207: `defineFeature.body` writes the implementation of a header; a member costs no new word of the vocabulary.\nconst defineFeature = Object.assign(defineFeatureImplementation as unknown as DefineFeature, {\n body: featureBody,\n preload: preloadFeatureBody,\n});\n\nfunction getFeatureModule<\n const Id extends string,\n const Imports extends FeatureImportRecord,\n const Runtime extends FeatureOwnRecord<Id>,\n const Exports extends FeatureExportRecord,\n>(feature: Feature<Id, Imports, Runtime, Exports>): ModuleDefinition<Id> {\n return requireFeatureRecord(feature).module as ModuleDefinition<Id>;\n}\n\nfunction getFeatureContributionDescriptors(feature: AnyFeature): FeatureRecord['contributions'] {\n return requireFeatureRecord(feature).contributions;\n}\n\nexport { defineFeature, getFeatureByExportContract, getFeatureContributionDescriptors, getFeatureModule, isFeature };\nexport type {\n AnyFeature,\n Feature,\n FeatureConditionsOf,\n FeatureExportRecord,\n FeatureExportsOf,\n FeatureIdOf,\n FeatureImportRecord,\n FeatureImportsOf,\n FeatureImportValues,\n FeatureOwnRecord,\n FeatureRequirementsOf,\n} from './feature-authoring-types';\n"],"names":["defineGeneratedModule","defineModule","hasDataThen","value","source","descriptor","buildFeatureProvided","featureId","build","builders","createFeatureContributionBuilders","createPortBuilder","assertPlainRecord","entries","dataEntries","contributionEntries","entry","isFeatureContributionDeclaration","providerEntries","snapshotFeatureContributions","snapshotPortProviders","featuresByExportContract","materializeFeatureImplementation","header","body","optionalFunction","exportDeclaration","snapshotFeatureExportDeclaration","buildProvides","lowering","module","low","lowerFeatureOwn","dataDescriptors","importScopeKey","publicRuntime","requirementScopeKey","own","contributions","providers","defineLazyFeature","id","key","load","imports","snapshotFeatureImports","requirements","snapshotFeatureRequirements","importKeys","requirementKeys","declared","snapshotDeclaredProvided","exportsContract","defineFeatureContract","materializedOwn","feature","declarationId","snapshotFeatureConditions","registerFeatureRecord","registerLazyFeature","requireFeatureBody","materialized","assertBodyMatchesHeader","defineFeatureImplementation","options","snapshotFeatureOptions","requireString","selectExports","requirementEntries","getFeatureByExportContract","contract","defineFeature","featureBody","preloadFeatureBody","getFeatureContributionDescriptors","requireFeatureRecord"],"mappings":"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"}
|
package/dist/feature-body.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ interface FeatureBody<Exports extends FeatureExportRecord = FeatureExportRecord>
|
|
|
22
22
|
type FeatureBodyInput<Id extends string, Imports extends FeatureImportRecord, Requires extends PortRequirementRecord, Own extends FeatureOwnRecord<Id>, Exports extends FeatureExportRecord, Provided extends FeatureProvidedRecord<Id>> = {
|
|
23
23
|
readonly exports?: FeatureExportsFactory<Id, Own, Exports>;
|
|
24
24
|
readonly own?: ExactNonUnionRuntime<Own> & ((builder: FeatureOwnBuilder<Id, Imports, NoInfer<Requires>>) => Own);
|
|
25
|
-
readonly provides?: FeatureProvidesFactory<Id, FeatureOpenContext<Id, Imports, Own
|
|
25
|
+
readonly provides?: FeatureProvidesFactory<Id, FeatureOpenContext<Id, Imports, Own>, FeatureEvaluationContext<Id, Imports, Own>, Own, Provided>;
|
|
26
26
|
};
|
|
27
27
|
type FeatureImportRecordOf<Header> = Header extends Feature<infer _Id, infer Imports, infer _Own, infer _Exports, infer _Requires, infer _When> ? Imports : never;
|
|
28
28
|
type FeatureExportRecordOf<Header> = Header extends Feature<infer _Id, infer _Imports, infer _Own, infer Exports, infer _Requires, infer _When> ? Exports : never;
|
package/dist/feature-body.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-body.js","sources":["../src/feature-body.ts"],"sourcesContent":["import type { Condition } from './condition';\nimport type {\n Feature,\n FeatureEvaluationContext,\n FeatureExportRecord,\n FeatureExportsFactory,\n FeatureOpenContext,\n FeatureOwnBuilder,\n FeatureOwnRecord,\n} from './feature-authoring-types';\nimport type { FeatureImportRecord } from './feature-contract';\nimport { isFeature } from './feature-definition-support';\nimport { getLazyFeature, loadFeatureBody } from './feature-lazy';\nimport type { FeatureProvidedRecord, FeatureProvidesFactory, PortRequirementRecord } from './feature-port';\nimport type { ExactNonUnionRuntime } from './public-module';\n\n/**\n * D186: the header of a feature and its body are two files. The header is the identity every consumer imports; the\n * body is the implementation the loader brings in later. `FeatureBody<Exports>` is the narrow view the header names\n * in the return type of its loader — it carries the export contract and nothing else, so the header never depends on\n * the body module and the two types cannot form a cycle.\n */\ninterface FeatureBody<Exports extends FeatureExportRecord = FeatureExportRecord> {\n readonly exports?: (context: never) => Exports;\n readonly own?: unknown;\n readonly provides?: unknown;\n}\n\n/**\n * The body as its own file writes it: `own`, `exports` and `provides` of the declared header, with the builders typed\n * from the header's id, imports and requirements. The record is plain data — the header already owns the identity,\n * so a body needs no second authentic declaration.\n */\ntype FeatureBodyInput<\n Id extends string,\n Imports extends FeatureImportRecord,\n Requires extends PortRequirementRecord,\n Own extends FeatureOwnRecord<Id>,\n Exports extends FeatureExportRecord,\n Provided extends FeatureProvidedRecord<Id>,\n> = {\n readonly exports?: FeatureExportsFactory<Id, Own, Exports>;\n readonly own?: ExactNonUnionRuntime<Own> & ((builder: FeatureOwnBuilder<Id, Imports, NoInfer<Requires>>) => Own);\n readonly provides?: FeatureProvidesFactory<\n Id,\n FeatureOpenContext<Id, Imports, Own
|
|
1
|
+
{"version":3,"file":"feature-body.js","sources":["../src/feature-body.ts"],"sourcesContent":["import type { Condition } from './condition';\nimport type {\n Feature,\n FeatureEvaluationContext,\n FeatureExportRecord,\n FeatureExportsFactory,\n FeatureOpenContext,\n FeatureOwnBuilder,\n FeatureOwnRecord,\n} from './feature-authoring-types';\nimport type { FeatureImportRecord } from './feature-contract';\nimport { isFeature } from './feature-definition-support';\nimport { getLazyFeature, loadFeatureBody } from './feature-lazy';\nimport type { FeatureProvidedRecord, FeatureProvidesFactory, PortRequirementRecord } from './feature-port';\nimport type { ExactNonUnionRuntime } from './public-module';\n\n/**\n * D186: the header of a feature and its body are two files. The header is the identity every consumer imports; the\n * body is the implementation the loader brings in later. `FeatureBody<Exports>` is the narrow view the header names\n * in the return type of its loader — it carries the export contract and nothing else, so the header never depends on\n * the body module and the two types cannot form a cycle.\n */\ninterface FeatureBody<Exports extends FeatureExportRecord = FeatureExportRecord> {\n readonly exports?: (context: never) => Exports;\n readonly own?: unknown;\n readonly provides?: unknown;\n}\n\n/**\n * The body as its own file writes it: `own`, `exports` and `provides` of the declared header, with the builders typed\n * from the header's id, imports and requirements. The record is plain data — the header already owns the identity,\n * so a body needs no second authentic declaration.\n */\ntype FeatureBodyInput<\n Id extends string,\n Imports extends FeatureImportRecord,\n Requires extends PortRequirementRecord,\n Own extends FeatureOwnRecord<Id>,\n Exports extends FeatureExportRecord,\n Provided extends FeatureProvidedRecord<Id>,\n> = {\n readonly exports?: FeatureExportsFactory<Id, Own, Exports>;\n readonly own?: ExactNonUnionRuntime<Own> & ((builder: FeatureOwnBuilder<Id, Imports, NoInfer<Requires>>) => Own);\n readonly provides?: FeatureProvidesFactory<\n Id,\n FeatureOpenContext<Id, Imports, Own>,\n FeatureEvaluationContext<Id, Imports, Own>,\n Own,\n Provided\n >;\n};\n\ntype FeatureImportRecordOf<Header> =\n Header extends Feature<infer _Id, infer Imports, infer _Own, infer _Exports, infer _Requires, infer _When>\n ? Imports\n : never;\ntype FeatureExportRecordOf<Header> =\n Header extends Feature<infer _Id, infer _Imports, infer _Own, infer Exports, infer _Requires, infer _When>\n ? Exports\n : never;\ntype FeatureRequirementRecordOf<Header> =\n Header extends Feature<infer _Id, infer _Imports, infer _Own, infer _Exports, infer Requires, infer _When>\n ? Requires\n : never;\ntype FeatureHeaderIdOf<Header> =\n Header extends Feature<infer Id, infer _Imports, infer _Own, infer _Exports, infer _Requires, infer _When>\n ? Id\n : never;\n\n/** What the body file annotates itself with: everything the header already fixed, and the own record it invents. */\ntype FeatureBodyOf<\n Header,\n Own extends FeatureOwnRecord<FeatureHeaderIdOf<Header>> = FeatureOwnRecord<FeatureHeaderIdOf<Header>>,\n Provided extends FeatureProvidedRecord<FeatureHeaderIdOf<Header>> = FeatureProvidedRecord<FeatureHeaderIdOf<Header>>,\n> = FeatureBodyInput<\n FeatureHeaderIdOf<Header>,\n FeatureImportRecordOf<Header>,\n FeatureRequirementRecordOf<Header>,\n Own,\n FeatureExportRecordOf<Header>,\n Provided\n>;\n\ntype LoadedFeatureBody = {\n readonly exports?: unknown;\n readonly own?: unknown;\n readonly provides?: unknown;\n};\n\nconst bodyKeys = new Set(['exports', 'own', 'provides']);\n\nfunction assertPlainBodyRecord(featureId: string, value: unknown): asserts value is object {\n if (typeof value !== 'object' || value === null) {\n throw new TypeError(`Feature ${featureId} body must be a record of own, exports and provides.`);\n }\n\n const prototype: unknown = Object.getPrototypeOf(value);\n\n if (prototype !== Object.prototype && prototype !== null) {\n throw new TypeError(`Feature ${featureId} body must be a plain object record.`);\n }\n}\n\n/** The loader is foreign code, so what it returns is checked before anything of the feature is materialized. */\nfunction requireFeatureBody(featureId: string, value: unknown): LoadedFeatureBody {\n assertPlainBodyRecord(featureId, value);\n\n for (const key of Reflect.ownKeys(value)) {\n if (typeof key !== 'string' || !bodyKeys.has(key)) {\n throw new TypeError(`Feature ${featureId} body contains unknown field ${String(key)}.`);\n }\n }\n\n return value;\n}\n\n/**\n * D207: the body is written through `defineFeature.body`, a member of the word that already names a feature. A\n * function is what lets TypeScript infer `own` for `exports` and `provides`, exactly as the eager form does, and a\n * member spends no new word on the author's vocabulary. It mints no identity — the header already is the feature.\n */\nfunction featureBody<\n Id extends string,\n Imports extends FeatureImportRecord,\n Exports extends FeatureExportRecord,\n Requires extends PortRequirementRecord,\n Own extends FeatureOwnRecord<Id> = {},\n Provided extends FeatureProvidedRecord<Id> = {},\n>(\n header: Feature<Id, Imports, FeatureOwnRecord<Id>, Exports, Requires, readonly Condition[]>,\n body: FeatureBodyInput<Id, Imports, Requires, Own, Exports, Provided>,\n): FeatureBody<Exports> {\n if (!isFeature(header)) throw new TypeError('featureBody takes the feature its header declared.');\n\n return requireFeatureBody(header.id, body) as FeatureBody<Exports>;\n}\n\n/**\n * D186 asked for a way to fetch the code without opening anything: a host that knows a feature is about to be\n * needed — a hovered entry point, an idle callback — warms its chunk here. It opens no instance, holds no lease and\n * publishes no state; a failure is the caller's to observe, and the next open tries the loader again.\n */\nfunction preloadFeatureBody(header: unknown): Promise<void> {\n if (!isFeature(header)) throw new TypeError('defineFeature.preload takes a feature declaration.');\n\n if (getLazyFeature(header) === undefined) return Promise.resolve();\n\n return loadFeatureBody(header).then(() => undefined);\n}\n\nexport { featureBody, preloadFeatureBody, requireFeatureBody };\nexport type { FeatureBody, FeatureBodyOf, LoadedFeatureBody };\n"],"names":["bodyKeys","assertPlainBodyRecord","featureId","value","prototype","requireFeatureBody","key","featureBody","header","body","isFeature","preloadFeatureBody","getLazyFeature","loadFeatureBody"],"mappings":"oIAyFA,MAAMA,EAAW,IAAI,IAAI,CAAC,UAAW,MAAO,UAAU,CAAC,EAEvD,SAASC,EAAsBC,EAAmBC,EAAc,CAC9D,GAAI,OAAOA,GAAU,UAAYA,IAAU,KACzC,MAAM,IAAI,UAAU,WAAWD,CAAS,sDAAsD,EAGhG,MAAME,EAAqB,OAAO,eAAeD,CAAK,EAEtD,GAAIC,IAAc,OAAO,WAAaA,IAAc,KAClD,MAAM,IAAI,UAAU,WAAWF,CAAS,sCAAsC,CAElF,CAGA,SAASG,EAAmBH,EAAmBC,EAAc,CAC3DF,EAAsBC,EAAWC,CAAK,EAEtC,UAAWG,KAAO,QAAQ,QAAQH,CAAK,EACrC,GAAI,OAAOG,GAAQ,UAAY,CAACN,EAAS,IAAIM,CAAG,EAC9C,MAAM,IAAI,UAAU,WAAWJ,CAAS,gCAAgC,OAAOI,CAAG,CAAC,GAAG,EAI1F,OAAOH,CACT,CAOA,SAASI,EAQPC,EACAC,EAAqE,CAErE,GAAI,CAACC,EAAUF,CAAM,EAAG,MAAM,IAAI,UAAU,oDAAoD,EAEhG,OAAOH,EAAmBG,EAAO,GAAIC,CAAI,CAC3C,CAOA,SAASE,EAAmBH,EAAe,CACzC,GAAI,CAACE,EAAUF,CAAM,EAAG,MAAM,IAAI,UAAU,oDAAoD,EAEhG,OAAII,EAAeJ,CAAM,IAAM,OAAkB,QAAQ,QAAO,EAEzDK,EAAgBL,CAAM,EAAE,KAAK,IAAA,EAAe,CACrD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DeclarationId, Readable } from '@opetope/core';
|
|
2
2
|
import type { ContributionPublication, ContributionPublicationInput, ContributionTarget, PipeHandler } from '@opetope/core/internal';
|
|
3
|
-
import type { ContributionModelDeclaration, ContributionModelProps } from './feature-contribution-model.js';
|
|
3
|
+
import type { ContributionModelBuilder, ContributionModelDeclaration, ContributionModelProps } from './feature-contribution-model.js';
|
|
4
4
|
import type { ExactInput } from './feature-record.js';
|
|
5
5
|
declare const featureContributionBrand: unique symbol;
|
|
6
6
|
interface FeatureContribution {
|
|
@@ -70,7 +70,9 @@ type CheckedContribution<Spec, Value> = ExactContributionProps<Spec, Value> exte
|
|
|
70
70
|
* inference circular and TypeScript would fall back to the constraint.
|
|
71
71
|
*/
|
|
72
72
|
interface FeatureSlotBuilder<Context, Evaluation> {
|
|
73
|
-
<Value extends object, const Spec extends NoInfer<Value>, const Options extends FeatureContributionOptions<Evaluation>>(target: ContributionTarget<Value>, contribution: (context: Context
|
|
73
|
+
<Value extends object, const Spec extends NoInfer<Value>, const Options extends FeatureContributionOptions<Evaluation>>(target: ContributionTarget<Value>, contribution: (context: Context & {
|
|
74
|
+
readonly model: ContributionModelBuilder;
|
|
75
|
+
}) => Spec, options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>): CheckedContribution<Spec, Value>;
|
|
74
76
|
<Value extends object, const Spec extends NoInfer<Value>, const Options extends FeatureContributionOptions<Evaluation>>(target: ContributionTarget<Value>, contribution: Spec, options?: ExactInput<Options, FeatureContributionOptions<Evaluation>>): CheckedContribution<Spec, Value>;
|
|
75
77
|
}
|
|
76
78
|
/**
|
|
@@ -90,7 +92,6 @@ interface FeatureContributionDescriptor {
|
|
|
90
92
|
}
|
|
91
93
|
/** The live values of one instance, read by every reactive calculation that instance declared (D220). */
|
|
92
94
|
type FeatureEvaluationValues = Readonly<{
|
|
93
|
-
exports: unknown;
|
|
94
95
|
imports: unknown;
|
|
95
96
|
own: unknown;
|
|
96
97
|
}>;
|
|
@@ -104,6 +105,7 @@ type SnapshotContributionOptions = {
|
|
|
104
105
|
type FeaturePipeFold = (value: unknown, meta: unknown, context: unknown) => unknown;
|
|
105
106
|
type PendingFeatureContribution = SnapshotContributionOptions & {
|
|
106
107
|
readonly fold: FeaturePipeFold | undefined;
|
|
108
|
+
readonly slot: boolean;
|
|
107
109
|
readonly target: ContributionPublicationInput['target'];
|
|
108
110
|
readonly value: FeatureContributionValueFactory<unknown, unknown>;
|
|
109
111
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{declarationId as
|
|
1
|
+
import{declarationId as F,computed as E}from"@opetope/core";import{isContributionTarget as g,publishContributions as T}from"@opetope/core/internal";import{contributionModel as j}from"./feature-contribution-model.js";import{assertPlainRecord as a,dataEntries as d,assertExactDataKeys as C}from"./feature-record.js";const b=new WeakMap,y=new WeakMap,w=new WeakMap,h=new WeakSet,O=new Set(["priority","when"]);function x(e){if(e===void 0)return 0;if(typeof e!="number"||!Number.isFinite(e))throw new TypeError("Feature contribution priority must be a finite number.");return e}function z(e,t){if(t===void 0)throw new TypeError("Feature contribution when predicate has no instance to read.");return E({read:r=>{const n=e({...t,read:r});if(typeof n!="boolean")throw new TypeError("Feature contribution when predicate must return a boolean.");return n}})}function S(e){if(e===void 0)return;if(typeof e=="function"){const r=e;return n=>z(r,n)}if(typeof e!="object"||e===null||typeof e.getSnapshot!="function"||typeof e.subscribe!="function")throw new TypeError("Feature contribution when must be a readable or a predicate of the instance.");const t=e;return()=>t}function k(e){if(e===void 0)return{priority:0,when:void 0};a(e,"Feature contribution options");const t=d(e,"Feature contribution options");if(t.some(([n])=>!O.has(n)))throw new TypeError("Feature contribution options accept only priority and when.");const r=Object.fromEntries(t);return{priority:x(r.priority),when:S(r.when)}}function M(e){if(typeof e=="function"||typeof e!="object"||e===null)throw new TypeError("Feature pipe expects a descriptor: pipe(target, { fold: (value, meta, context) => next }).");a(e,"Feature pipe descriptor");const t=d(e,"Feature pipe descriptor");C(e,t,["fold"],"Feature pipe descriptor");const r=e.fold;if(typeof r!="function")throw new TypeError("Feature pipe fold must be a function.");return r}function P(){const e=new WeakMap,t=new Set,r=(n,o,i,s)=>{if(!g(n))throw new TypeError(`Feature ${s} target is not authentic.`);const u=s==="pipe"?M(o):void 0,c=typeof o=="function"?o:()=>o,f=Object.freeze({});return t.add(f),e.set(f,{...k(i),fold:u,slot:s==="slot"&&typeof o=="function",target:n,value:c}),f};return Object.freeze({declarations:e,declared:t,pipe:(n,o,i)=>r(n,o,i,"pipe"),register:(n,o,i)=>r(n,o,i,"register"),slot:((n,o,i)=>r(n,o,i,"slot"))})}function V(e,t){return typeof t=="object"&&t!==null&&e.declarations.has(t)}function W(e,t){b.set(e,t.value),t.slot&&h.add(e),t.when!==void 0&&y.set(e,t.when),t.fold!==void 0&&w.set(e,t.fold)}function $(e,t,r){const n=new Set,o=r.map(([i,s])=>{const u=typeof s=="object"&&s!==null?t.declarations.get(s):void 0;if(u===void 0)throw new TypeError(`Feature contribution ${i} is not authentic.`);if(n.has(s))throw new TypeError("Every feature contribution must be returned under exactly one key.");n.add(s);const c=Object.freeze({id:F(`${e}.${i}`),priority:u.priority,target:u.target});return W(c,u),c});if(n.size!==t.declared.size)throw new TypeError("Every feature contribution must be returned under exactly one key.");return Object.freeze(o)}function D(e,t){if(t===void 0)throw new TypeError("Feature pipe fold has no instance to read.");const r=[],n=Object.freeze({...t,read:o=>{const i=r[r.length-1];return i===void 0?o.getSnapshot():i(o)}});return(o,i,s)=>{r.push(s.read);try{return e(o,i,n)}finally{r.pop()}}}function K(e,t,r,n,o){let i;const s=e.map(u=>{const c=b.get(u);if(c===void 0)throw new TypeError(`Feature contribution ${u.id} is not authentic.`);const f=w.get(u),l=h.has(u)?i??(i=Object.freeze({...t,model:j})):t,m=f===void 0?c(l):D(f,o),p=y.get(u);return{id:u.id,...n===void 0?{}:{owner:n},priority:u.priority,target:u.target,value:m,when:p==null?void 0:p(o)}});return T(s,r)}export{P as createFeatureContributionBuilders,K as createFeatureContributionPublication,V as isFeatureContributionDeclaration,$ as snapshotFeatureContributions};
|
|
2
2
|
//# sourceMappingURL=feature-contribution.js.map
|