@gyral/core 0.3.0 → 0.3.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/CHANGELOG.md +42 -0
- package/NOTICE +19 -0
- package/README.md +30 -5
- package/dist/call.d.ts +32 -0
- package/dist/call.js +63 -0
- package/dist/call.js.map +1 -0
- package/dist/children.d.ts +25 -3
- package/dist/children.js +18 -1
- package/dist/children.js.map +1 -1
- package/dist/cli/gyral-types.d.ts +2 -0
- package/dist/cli/gyral-types.js +23 -0
- package/dist/cli/gyral-types.js.map +1 -0
- package/dist/command.d.ts +54 -12
- package/dist/command.js +25 -11
- package/dist/command.js.map +1 -1
- package/dist/compiler/ast.d.ts +2 -0
- package/dist/compiler/ast.js +5 -1
- package/dist/compiler/ast.js.map +1 -1
- package/dist/compiler/compile.d.ts +5 -2
- package/dist/compiler/compile.js +36 -17
- package/dist/compiler/compile.js.map +1 -1
- package/dist/compiler/component-entries.d.ts +7 -0
- package/dist/compiler/component-entries.js +42 -0
- package/dist/compiler/component-entries.js.map +1 -0
- package/dist/compiler/components.d.ts +4 -0
- package/dist/compiler/components.js +182 -0
- package/dist/compiler/components.js.map +1 -0
- package/dist/compiler/facts.d.ts +31 -0
- package/dist/compiler/facts.js +285 -0
- package/dist/compiler/facts.js.map +1 -0
- package/dist/compiler/features.d.ts +34 -0
- package/dist/compiler/features.js +158 -0
- package/dist/compiler/features.js.map +1 -0
- package/dist/compiler/hooks.d.ts +4 -0
- package/dist/compiler/hooks.js +144 -89
- package/dist/compiler/hooks.js.map +1 -1
- package/dist/compiler/loader-source.d.ts +14 -0
- package/dist/compiler/loader-source.js +86 -0
- package/dist/compiler/loader-source.js.map +1 -0
- package/dist/compiler/locate.d.ts +14 -0
- package/dist/compiler/locate.js +78 -0
- package/dist/compiler/locate.js.map +1 -0
- package/dist/compiler/parse5-check.d.ts +1 -1
- package/dist/compiler/parse5-check.js +8 -3
- package/dist/compiler/parse5-check.js.map +1 -1
- package/dist/compiler/prop-schemas.d.ts +4 -0
- package/dist/compiler/prop-schemas.js +108 -0
- package/dist/compiler/prop-schemas.js.map +1 -0
- package/dist/compiler/scan.d.ts +13 -3
- package/dist/compiler/scan.js +21 -13
- package/dist/compiler/scan.js.map +1 -1
- package/dist/compiler/scope.d.ts +8 -0
- package/dist/compiler/scope.js +116 -0
- package/dist/compiler/scope.js.map +1 -0
- package/dist/compiler/tag-map.d.ts +41 -0
- package/dist/compiler/tag-map.js +126 -0
- package/dist/compiler/tag-map.js.map +1 -0
- package/dist/components-ready.d.ts +7 -0
- package/dist/components-ready.js +19 -0
- package/dist/components-ready.js.map +1 -0
- package/dist/define.d.ts +13 -4
- package/dist/define.js +8 -12
- package/dist/define.js.map +1 -1
- package/dist/devtools-events.d.ts +8 -0
- package/dist/devtools-events.js.map +1 -1
- package/dist/devtools-off.d.ts +1 -0
- package/dist/devtools-off.js +1 -0
- package/dist/devtools-off.js.map +1 -1
- package/dist/devtools.d.ts +3 -0
- package/dist/devtools.js +14 -0
- package/dist/devtools.js.map +1 -1
- package/dist/drivers-scope.js.map +1 -1
- package/dist/element-internals.d.ts +1 -0
- package/dist/element-internals.js +11 -0
- package/dist/element-internals.js.map +1 -0
- package/dist/element-types.d.ts +6 -2
- package/dist/element-types.js.map +1 -1
- package/dist/element.js +80 -27
- package/dist/element.js.map +1 -1
- package/dist/error-view.d.ts +10 -0
- package/dist/error-view.js +30 -0
- package/dist/error-view.js.map +1 -0
- package/dist/errors.d.ts +21 -0
- package/dist/errors.js +47 -0
- package/dist/errors.js.map +1 -0
- package/dist/errors.json +289 -0
- package/dist/eslint/imports.d.ts +2 -0
- package/dist/eslint/imports.js +2 -2
- package/dist/eslint/imports.js.map +1 -1
- package/dist/eslint/index.d.ts +2 -1
- package/dist/eslint/index.js +11 -3
- package/dist/eslint/index.js.map +1 -1
- package/dist/eslint/template-rule.d.ts +1 -0
- package/dist/eslint/template-rule.js +15 -5
- package/dist/eslint/template-rule.js.map +1 -1
- package/dist/eslint/unused-intent-rule.d.ts +2 -0
- package/dist/eslint/unused-intent-rule.js +186 -0
- package/dist/eslint/unused-intent-rule.js.map +1 -0
- package/dist/features.d.ts +2 -2
- package/dist/features.js.map +1 -1
- package/dist/focus.d.ts +6 -0
- package/dist/focus.js +32 -2
- package/dist/focus.js.map +1 -1
- package/dist/form-associated.d.ts +46 -0
- package/dist/form-associated.js +77 -0
- package/dist/form-associated.js.map +1 -0
- package/dist/forms.d.ts +42 -30
- package/dist/forms.js +85 -41
- package/dist/forms.js.map +1 -1
- package/dist/frame-lane.d.ts +11 -0
- package/dist/frame-lane.js +28 -0
- package/dist/frame-lane.js.map +1 -0
- package/dist/head.d.ts +61 -0
- package/dist/head.js +85 -0
- package/dist/head.js.map +1 -0
- package/dist/host-model.d.ts +34 -5
- package/dist/host-model.js +146 -23
- package/dist/host-model.js.map +1 -1
- package/dist/hydration-client.js +2 -2
- package/dist/hydration-client.js.map +1 -1
- package/dist/hydration-loader.d.ts +13 -0
- package/dist/hydration-loader.js +58 -0
- package/dist/hydration-loader.js.map +1 -0
- package/dist/hydration-off.d.ts +8 -0
- package/dist/hydration-off.js +25 -0
- package/dist/hydration-off.js.map +1 -0
- package/dist/hydration.d.ts +0 -12
- package/dist/hydration.js +3 -52
- package/dist/hydration.js.map +1 -1
- package/dist/index.d.ts +20 -24
- package/dist/index.js +10 -19
- package/dist/index.js.map +1 -1
- package/dist/indexeddb-types.d.ts +97 -0
- package/dist/indexeddb-types.js +2 -0
- package/dist/indexeddb-types.js.map +1 -0
- package/dist/indexeddb.d.ts +5 -0
- package/dist/indexeddb.js +118 -0
- package/dist/indexeddb.js.map +1 -0
- package/dist/intent.d.ts +41 -19
- package/dist/intent.js +144 -106
- package/dist/intent.js.map +1 -1
- package/dist/internal/indexeddb-open.d.ts +8 -0
- package/dist/internal/indexeddb-open.js +96 -0
- package/dist/internal/indexeddb-open.js.map +1 -0
- package/dist/internal/indexeddb-transaction.d.ts +4 -0
- package/dist/internal/indexeddb-transaction.js +134 -0
- package/dist/internal/indexeddb-transaction.js.map +1 -0
- package/dist/internal/interpreter.d.ts +12 -4
- package/dist/internal/interpreter.js +36 -48
- package/dist/internal/interpreter.js.map +1 -1
- package/dist/internal/token.d.ts +1 -0
- package/dist/internal/token.js +7 -0
- package/dist/internal/token.js.map +1 -0
- package/dist/internal.d.ts +20 -0
- package/dist/internal.js +22 -0
- package/dist/internal.js.map +1 -0
- package/dist/invoker-fallback-used.d.ts +4 -0
- package/dist/invoker-fallback-used.js +10 -0
- package/dist/invoker-fallback-used.js.map +1 -0
- package/dist/invoker-fallback.d.ts +4 -0
- package/dist/invoker-fallback.js +15 -0
- package/dist/invoker-fallback.js.map +1 -0
- package/dist/light-dom.d.ts +1 -1
- package/dist/light-dom.js.map +1 -1
- package/dist/prop.d.ts +30 -7
- package/dist/prop.js +19 -0
- package/dist/prop.js.map +1 -1
- package/dist/props.d.ts +8 -3
- package/dist/props.js +22 -15
- package/dist/props.js.map +1 -1
- package/dist/retry.d.ts +15 -0
- package/dist/retry.js +48 -0
- package/dist/retry.js.map +1 -0
- package/dist/scheduler.d.ts +7 -3
- package/dist/scheduler.js +38 -56
- package/dist/scheduler.js.map +1 -1
- package/dist/script-json.d.ts +2 -0
- package/dist/script-json.js +13 -0
- package/dist/script-json.js.map +1 -0
- package/dist/server-component.d.ts +1 -1
- package/dist/server-component.js +45 -14
- package/dist/server-component.js.map +1 -1
- package/dist/server.d.ts +8 -2
- package/dist/server.js +11 -2
- package/dist/server.js.map +1 -1
- package/dist/settled.d.ts +4 -3
- package/dist/settled.js +48 -26
- package/dist/settled.js.map +1 -1
- package/dist/spec-features-used.d.ts +21 -0
- package/dist/spec-features-used.js +50 -0
- package/dist/spec-features-used.js.map +1 -0
- package/dist/spec-features.d.ts +28 -0
- package/dist/spec-features.js +42 -0
- package/dist/spec-features.js.map +1 -0
- package/dist/states.d.ts +3 -5
- package/dist/states.js +22 -8
- package/dist/states.js.map +1 -1
- package/dist/storage.d.ts +69 -0
- package/dist/storage.js +158 -0
- package/dist/storage.js.map +1 -0
- package/dist/store-binding.js +2 -2
- package/dist/store-binding.js.map +1 -1
- package/dist/store-scope.d.ts +2 -4
- package/dist/store-scope.js +6 -16
- package/dist/store-scope.js.map +1 -1
- package/dist/store.js +36 -8
- package/dist/store.js.map +1 -1
- package/dist/subscription.d.ts +35 -0
- package/dist/subscription.js +74 -0
- package/dist/subscription.js.map +1 -0
- package/dist/subscriptions.d.ts +26 -0
- package/dist/subscriptions.js +98 -0
- package/dist/subscriptions.js.map +1 -0
- package/dist/transitions.d.ts +4 -5
- package/dist/transitions.js +10 -4
- package/dist/transitions.js.map +1 -1
- package/dist/types.d.ts +124 -27
- package/dist/types.js.map +1 -1
- package/dist/use-dialogs.d.ts +2 -0
- package/dist/use-dialogs.js +9 -0
- package/dist/use-dialogs.js.map +1 -0
- package/dist/use-disposal.d.ts +2 -0
- package/dist/use-disposal.js +9 -0
- package/dist/use-disposal.js.map +1 -0
- package/dist/use-error-view.d.ts +2 -0
- package/dist/use-error-view.js +9 -0
- package/dist/use-error-view.js.map +1 -0
- package/dist/use-errored.d.ts +2 -0
- package/dist/use-errored.js +9 -0
- package/dist/use-errored.js.map +1 -0
- package/dist/use-form-associated.d.ts +2 -0
- package/dist/use-form-associated.js +7 -0
- package/dist/use-form-associated.js.map +1 -0
- package/dist/use-frame-lane.d.ts +2 -0
- package/dist/use-frame-lane.js +10 -0
- package/dist/use-frame-lane.js.map +1 -0
- package/dist/use-invokers.d.ts +2 -0
- package/dist/use-invokers.js +10 -0
- package/dist/use-invokers.js.map +1 -0
- package/dist/use-states.d.ts +2 -0
- package/dist/use-states.js +10 -0
- package/dist/use-states.js.map +1 -0
- package/dist/use-subscriptions.d.ts +2 -0
- package/dist/use-subscriptions.js +10 -0
- package/dist/use-subscriptions.js.map +1 -0
- package/dist/use-transitions.d.ts +2 -0
- package/dist/use-transitions.js +10 -0
- package/dist/use-transitions.js.map +1 -0
- package/dist/view/attributes.d.ts +5 -0
- package/dist/view/attributes.js +5 -0
- package/dist/view/attributes.js.map +1 -1
- package/dist/view/compiled.d.ts +1 -1
- package/dist/view/compiled.js +1 -1
- package/dist/view/compiled.js.map +1 -1
- package/dist/view/index.d.ts +9 -4
- package/dist/view/index.js +9 -3
- package/dist/view/index.js.map +1 -1
- package/dist/view/loc.d.ts +9 -0
- package/dist/view/loc.js +50 -0
- package/dist/view/loc.js.map +1 -0
- package/dist/view/message.d.ts +17 -0
- package/dist/view/message.js +40 -0
- package/dist/view/message.js.map +1 -0
- package/dist/view/messages.d.ts +43 -0
- package/dist/view/messages.js +84 -0
- package/dist/view/messages.js.map +1 -0
- package/dist/view/normalize/check.d.ts +5 -2
- package/dist/view/normalize/check.js +6 -3
- package/dist/view/normalize/check.js.map +1 -1
- package/dist/view/normalize/emit.d.ts +2 -0
- package/dist/view/normalize/emit.js +40 -11
- package/dist/view/normalize/emit.js.map +1 -1
- package/dist/view/normalize/errors.js +1 -1
- package/dist/view/normalize/errors.js.map +1 -1
- package/dist/view/normalize/id.d.ts +5 -2
- package/dist/view/normalize/id.js +9 -2
- package/dist/view/normalize/id.js.map +1 -1
- package/dist/view/normalize/normalize.d.ts +7 -4
- package/dist/view/normalize/normalize.js +15 -9
- package/dist/view/normalize/normalize.js.map +1 -1
- package/dist/view/normalize/rules.d.ts +9 -0
- package/dist/view/normalize/rules.js +35 -5
- package/dist/view/normalize/rules.js.map +1 -1
- package/dist/view/normalize/svg.d.ts +14 -0
- package/dist/view/normalize/svg.js +40 -0
- package/dist/view/normalize/svg.js.map +1 -0
- package/dist/view/normalize/tokens.d.ts +5 -1
- package/dist/view/normalize/tokens.js.map +1 -1
- package/dist/view/normalize/tree.d.ts +8 -2
- package/dist/view/normalize/tree.js +58 -13
- package/dist/view/normalize/tree.js.map +1 -1
- package/dist/view/normalize/types.d.ts +24 -4
- package/dist/view/normalize/types.js +4 -1
- package/dist/view/normalize/types.js.map +1 -1
- package/dist/view/normalize/whitespace.js +4 -3
- package/dist/view/normalize/whitespace.js.map +1 -1
- package/dist/view/prepare-stub.js +2 -2
- package/dist/view/prepare-stub.js.map +1 -1
- package/dist/view/prepare.d.ts +5 -2
- package/dist/view/prepare.js +9 -3
- package/dist/view/prepare.js.map +1 -1
- package/dist/view/registry.d.ts +15 -0
- package/dist/view/registry.js +10 -2
- package/dist/view/registry.js.map +1 -1
- package/dist/view/render/adopt-attr.js +7 -1
- package/dist/view/render/adopt-attr.js.map +1 -1
- package/dist/view/render/adopt.js +21 -4
- package/dist/view/render/adopt.js.map +1 -1
- package/dist/view/render/attr-parts.d.ts +12 -1
- package/dist/view/render/attr-parts.js +38 -5
- package/dist/view/render/attr-parts.js.map +1 -1
- package/dist/view/render/child-part.js +5 -2
- package/dist/view/render/child-part.js.map +1 -1
- package/dist/view/render/dispose.d.ts +3 -0
- package/dist/view/render/dispose.js +76 -0
- package/dist/view/render/dispose.js.map +1 -0
- package/dist/view/render/hook-part.d.ts +3 -1
- package/dist/view/render/hook-part.js +21 -5
- package/dist/view/render/hook-part.js.map +1 -1
- package/dist/view/render/hook-run.d.ts +2 -0
- package/dist/view/render/hook-run.js +72 -0
- package/dist/view/render/hook-run.js.map +1 -0
- package/dist/view/render/hooks.d.ts +73 -5
- package/dist/view/render/hooks.js +79 -17
- package/dist/view/render/hooks.js.map +1 -1
- package/dist/view/render/hydrate.js +2 -2
- package/dist/view/render/hydrate.js.map +1 -1
- package/dist/view/render/keyed.d.ts +6 -0
- package/dist/view/render/keyed.js +15 -0
- package/dist/view/render/keyed.js.map +1 -0
- package/dist/view/render/mismatch.js +5 -3
- package/dist/view/render/mismatch.js.map +1 -1
- package/dist/view/render/modal.d.ts +3 -0
- package/dist/view/render/modal.js +39 -0
- package/dist/view/render/modal.js.map +1 -0
- package/dist/view/render/raw.d.ts +4 -1
- package/dist/view/render/raw.js +6 -2
- package/dist/view/render/raw.js.map +1 -1
- package/dist/view/render/render.d.ts +4 -1
- package/dist/view/render/render.js +17 -12
- package/dist/view/render/render.js.map +1 -1
- package/dist/view/render/toggles.d.ts +6 -0
- package/dist/view/render/toggles.js +6 -0
- package/dist/view/render/toggles.js.map +1 -0
- package/dist/view/render/warn.d.ts +14 -0
- package/dist/view/render/warn.js +45 -0
- package/dist/view/render/warn.js.map +1 -1
- package/dist/view/server/component.d.ts +6 -3
- package/dist/view/server/component.js +29 -7
- package/dist/view/server/component.js.map +1 -1
- package/dist/view/server/index.d.ts +20 -0
- package/dist/view/server/index.js +12 -4
- package/dist/view/server/index.js.map +1 -1
- package/dist/view/server/tags.d.ts +13 -2
- package/dist/view/server/tags.js +13 -2
- package/dist/view/server/tags.js.map +1 -1
- package/dist/view/server/values.d.ts +2 -0
- package/dist/view/server/values.js +8 -0
- package/dist/view/server/values.js.map +1 -1
- package/dist/view/server/writer.d.ts +9 -4
- package/dist/view/server/writer.js +33 -18
- package/dist/view/server/writer.js.map +1 -1
- package/dist/view/template-element.d.ts +7 -0
- package/dist/view/template-element.js +25 -5
- package/dist/view/template-element.js.map +1 -1
- package/dist/view/template.d.ts +10 -2
- package/dist/view/template.js +62 -8
- package/dist/view/template.js.map +1 -1
- package/dist/view/trusted-html.d.ts +6 -0
- package/dist/view/trusted-html.js +34 -0
- package/dist/view/trusted-html.js.map +1 -0
- package/dist/vite.d.ts +38 -31
- package/dist/vite.js +198 -31
- package/dist/vite.js.map +1 -1
- package/package.json +34 -3
- package/dist/hooks/labelled-by.d.ts +0 -13
- package/dist/hooks/labelled-by.js +0 -51
- package/dist/hooks/labelled-by.js.map +0 -1
- package/dist/random.d.ts +0 -13
- package/dist/random.js +0 -19
- package/dist/random.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# @gyral/core
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
This release includes API removals and behavior changes. Read the
|
|
8
|
+
[0.3.0 → 0.3.1 migration guide](https://github.com/gyraljs/gyral/blob/main/docs/references/migrating-0.3.0-to-0.3.1.md) before upgrading, and keep the nine
|
|
9
|
+
Gyral packages on the same version.
|
|
10
|
+
|
|
11
|
+
- Components use `define<State, Msg>()(tag, spec)` with typed intent names, tag-only intents,
|
|
12
|
+
parser state access and typed outputs. A declined intent bubbles to the next matching
|
|
13
|
+
intent; child outputs stop at their direct consuming parent.
|
|
14
|
+
- Declarative `subscriptions` reconcile long-lived commands, with typed `subscription()`
|
|
15
|
+
builders, cancellation and stable command lanes. Drivers resolve through the host/root
|
|
16
|
+
override boundary; retry supports predicates, backoff and jitter.
|
|
17
|
+
- Views gain `svg` templates, `keyed` replacement, disposable `defineHook` hooks, delegated
|
|
18
|
+
shadow focus, `focus(..., { wait: true })` and post-render `call` commands. Hooks run after
|
|
19
|
+
child renders and dispose when their owned elements are removed.
|
|
20
|
+
- Native modal/popover bindings open after DOM insertion and child renders. Conditional
|
|
21
|
+
insertion, keyed replacement, initial opening and hydration follow the same ordering.
|
|
22
|
+
Intents dispatched by native focus complete their renders before focus commands and `settled`.
|
|
23
|
+
- Opt-in `formAssociated` components project native values and validity and receive reset,
|
|
24
|
+
disabled and restoration messages. Native SSR fallback controls can preserve edits made
|
|
25
|
+
before hydration without duplicate form entries.
|
|
26
|
+
- Optional `@gyral/core/storage` provides schema-decoded localStorage operations and change
|
|
27
|
+
subscriptions. Optional `@gyral/core/indexeddb` provides typed records, bounded queries,
|
|
28
|
+
synchronous migrations and atomic transaction batches. Neither adds code to unused apps.
|
|
29
|
+
- Forms validate and refill through their definitions, retain user edits until model values
|
|
30
|
+
change, and redact password/passcode/CSRF fields plus explicitly named secrets. Shared head
|
|
31
|
+
data covers title, metadata, canonical URLs and JSON-LD across server rendering and routing.
|
|
32
|
+
- The Vite preset supports client-only builds, automatic component modules, explicit wrapper
|
|
33
|
+
module mappings and generated element typings. Entry-imported components stay in their
|
|
34
|
+
entry; loader/preload work and spec features are reduced when unused.
|
|
35
|
+
- Unified `GyralError` reporting, `Errored` reducers and error views handle failures in the
|
|
36
|
+
browser and server. Production diagnostics use stable codes linked to the public reference.
|
|
37
|
+
Strict CSP style bindings use CSSOM; seeded hydration and Trusted Types paths are verified.
|
|
38
|
+
- Compiler/runtime/lint template rules agree, including boolean bindings written as `?name`.
|
|
39
|
+
Public exports have a checked inventory; duplicate/internal helper APIs are removed as
|
|
40
|
+
described in the migration guide.
|
|
41
|
+
|
|
42
|
+
The lockstep release also adds optional/catch-all routes in `@gyral/router` and native
|
|
43
|
+
EventSource/WebSocket entries in `@gyral/http`; see those packages' changelogs.
|
|
44
|
+
|
|
3
45
|
## 0.3.0
|
|
4
46
|
|
|
5
47
|
### Minor Changes
|
package/NOTICE
CHANGED
|
@@ -5,7 +5,26 @@ Gyral is inspired by Cycle.js (https://github.com/cyclejs/cyclejs), released
|
|
|
5
5
|
under the MIT License:
|
|
6
6
|
|
|
7
7
|
The MIT License (MIT)
|
|
8
|
+
|
|
8
9
|
Copyright (c) 2015-2019 The Cycle.js Core Team
|
|
9
10
|
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
10
29
|
Gyral is a new implementation. Where ideas, APIs or example programs are adapted
|
|
11
30
|
from Cycle.js, this notice applies.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @gyral/core
|
|
2
2
|
|
|
3
|
-
Model-View-Intent web components on the web platform, with their own view layer.
|
|
3
|
+
Model-View-Intent web components on the web platform, with their own view layer. Intent parses platform events into typed messages, the model is a set of pure reducers, and the view is a pure template that names intents. Side effects are commands: data that drivers run at the edges.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -15,11 +15,11 @@ import { define, html } from '@gyral/core';
|
|
|
15
15
|
|
|
16
16
|
type Msg = { _tag: 'Increment' } | { _tag: 'Decrement' };
|
|
17
17
|
|
|
18
|
-
define<{ count: number }, Msg>('gy-counter', {
|
|
18
|
+
define<{ count: number }, Msg>()('gy-counter', {
|
|
19
19
|
init: () => ({ count: 0 }),
|
|
20
20
|
intent: {
|
|
21
|
-
Increment:
|
|
22
|
-
Decrement:
|
|
21
|
+
Increment: true,
|
|
22
|
+
Decrement: true,
|
|
23
23
|
},
|
|
24
24
|
update: {
|
|
25
25
|
Increment: (s) => ({ count: s.count + 1 }),
|
|
@@ -35,10 +35,28 @@ define<{ count: number }, Msg>('gy-counter', {
|
|
|
35
35
|
|
|
36
36
|
`@gyral/core/vite` exports `gyralVitePreset()`, the Vite/Vitest settings every Gyral app needs
|
|
37
37
|
(the build-time template compiler). `@gyral/core/eslint` is an ESLint plugin with the same
|
|
38
|
-
template rules for the editor
|
|
38
|
+
template rules for the editor (`import gyral from '@gyral/core/eslint'`, then
|
|
39
|
+
`gyral.configs.recommended` in your flat config). `@gyral/ssr` renders components and pages
|
|
40
|
+
to HTML on the server. In tests, `await settled()` waits until
|
|
41
|
+
every component has rendered and messages have stopped arriving.
|
|
39
42
|
|
|
40
43
|
## Documentation
|
|
41
44
|
|
|
45
|
+
`@gyral/core/storage` (0.3.1) exports `makeLocalStorageDriver(schema, { prefix?, name?,
|
|
46
|
+
storage?, encode? })`: JSON Read/Write/Remove/Clear commands and cancellable Watch streams.
|
|
47
|
+
Reads validate persisted values with Standard Schema; watches report invalid data and keep
|
|
48
|
+
listening. Driver writes and native other-tab events produce changes. Clear respects the
|
|
49
|
+
prefix namespace. Start initial watches in `subscriptions` so SSR state hydrates first;
|
|
50
|
+
imports and factories do not access browser globals. This optional entry is absent from
|
|
51
|
+
apps that do not import it. See [the storage guide](../../skills/gyral/references/browser-storage.md).
|
|
52
|
+
|
|
53
|
+
`@gyral/core/indexeddb` (0.3.1) exports `makeIndexedDBDriver(stores, { database, version,
|
|
54
|
+
upgrade?, name?, factory?, encode? })`: typed Read/Put/Delete, bounded Query and atomic
|
|
55
|
+
Transaction batches. Applications own stores, indexes and synchronous migrations. Success
|
|
56
|
+
means the native transaction committed; stored records decode afterward. Blocked upgrades,
|
|
57
|
+
access and decoding failures are typed. Commands close connections and cancel native work;
|
|
58
|
+
an already committed write cannot be undone. This entry is also optional and SSR-safe.
|
|
59
|
+
|
|
42
60
|
Guides and API reference: **[gyral.dev](https://gyral.dev)**. Source, issues and the
|
|
43
61
|
consumer setup guide (packages, Vite preset, template compiler):
|
|
44
62
|
[github.com/gyraljs/gyral](https://github.com/gyraljs/gyral). Upgrading from 0.2:
|
|
@@ -46,6 +64,13 @@ consumer setup guide (packages, Vite preset, template compiler):
|
|
|
46
64
|
|
|
47
65
|
> Status: pre-alpha. APIs change between 0.x releases.
|
|
48
66
|
|
|
67
|
+
## Diagnostic codes
|
|
68
|
+
|
|
69
|
+
Production builds print codes such as `Gyral G0010 my-cart Increment`. The full table (code,
|
|
70
|
+
group, message, arguments, link) ships with the package as `@gyral/core/errors.json`, for tools
|
|
71
|
+
and docs sites: `import errors from '@gyral/core/errors.json' with { type: 'json' };`. The
|
|
72
|
+
same table, rendered: <https://gyral.dev/errors/>.
|
|
73
|
+
|
|
49
74
|
## License
|
|
50
75
|
|
|
51
76
|
MIT © Mike Zupper. See LICENSE and NOTICE (Cycle.js attribution). Gyral, gyraljs and
|
package/dist/call.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Command } from './command.js';
|
|
2
|
+
import type { LocalHost } from './features.js';
|
|
3
|
+
/** The input of a `call()` command. */
|
|
4
|
+
export interface CallInput {
|
|
5
|
+
readonly selector: string;
|
|
6
|
+
readonly method: string;
|
|
7
|
+
readonly args: readonly unknown[];
|
|
8
|
+
}
|
|
9
|
+
/** Marker driver: the host runs call commands itself (`local`), after the render. */
|
|
10
|
+
export declare const CALL: {
|
|
11
|
+
readonly name: "@gyral/call";
|
|
12
|
+
readonly run: () => undefined;
|
|
13
|
+
readonly local: (host: LocalHost, input: unknown) => void;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A command that calls `method` with `args` on the first element matching `selector` inside
|
|
17
|
+
* this component (its shadow root, or its own children in light-DOM mode) once the current
|
|
18
|
+
* update has rendered:
|
|
19
|
+
*
|
|
20
|
+
* Start: (s) => [{ ...s, playing: true }, [call('video', 'play')]]
|
|
21
|
+
* Join: (s, m) => [s, [call('room-stage', 'join', m.room)]]
|
|
22
|
+
*
|
|
23
|
+
* `args` must be plain data (structured-cloneable), so the command stays data a test can
|
|
24
|
+
* compare. A missing element or method, or a method that throws or rejects, is reported
|
|
25
|
+
* through the error channel (ADR 0024); the error's cause says which.
|
|
26
|
+
*/
|
|
27
|
+
export declare function call(selector: string, method: string, ...args: readonly unknown[]): Command<never>;
|
|
28
|
+
/**
|
|
29
|
+
* Runs a call command against `root`. No element, no such method, or a method that throws or
|
|
30
|
+
* rejects: reported with `host` (the cause says which).
|
|
31
|
+
*/
|
|
32
|
+
export declare function runCall(root: ParentNode, host: Element, tag: string, input: CallInput): void;
|
package/dist/call.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { fail } from './errors.js';
|
|
2
|
+
import { afterRender, POST_FOCUS } from './scheduler.js';
|
|
3
|
+
import { DEV, message } from './view/index.js';
|
|
4
|
+
/** Marker driver: the host runs call commands itself (`local`), after the render. */
|
|
5
|
+
export const CALL = {
|
|
6
|
+
name: '@gyral/call',
|
|
7
|
+
run: () => undefined,
|
|
8
|
+
local: (host, input) => {
|
|
9
|
+
afterRender(POST_FOCUS, () => {
|
|
10
|
+
const root = host.root();
|
|
11
|
+
if (host.el.isConnected && root !== undefined)
|
|
12
|
+
runCall(root, host.el, host.tag, input);
|
|
13
|
+
});
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A command that calls `method` with `args` on the first element matching `selector` inside
|
|
18
|
+
* this component (its shadow root, or its own children in light-DOM mode) once the current
|
|
19
|
+
* update has rendered:
|
|
20
|
+
*
|
|
21
|
+
* Start: (s) => [{ ...s, playing: true }, [call('video', 'play')]]
|
|
22
|
+
* Join: (s, m) => [s, [call('room-stage', 'join', m.room)]]
|
|
23
|
+
*
|
|
24
|
+
* `args` must be plain data (structured-cloneable), so the command stays data a test can
|
|
25
|
+
* compare. A missing element or method, or a method that throws or rejects, is reported
|
|
26
|
+
* through the error channel (ADR 0024); the error's cause says which.
|
|
27
|
+
*/
|
|
28
|
+
export function call(selector, method, ...args) {
|
|
29
|
+
if (DEV) {
|
|
30
|
+
try {
|
|
31
|
+
structuredClone(args);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new TypeError(message(86, selector, method));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const input = { selector, method, args };
|
|
38
|
+
return { driver: CALL, input, onSuccess: () => undefined };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Runs a call command against `root`. No element, no such method, or a method that throws or
|
|
42
|
+
* rejects: reported with `host` (the cause says which).
|
|
43
|
+
*/
|
|
44
|
+
export function runCall(root, host, tag, input) {
|
|
45
|
+
const { selector, method, args } = input;
|
|
46
|
+
const failed = (cause) => {
|
|
47
|
+
fail(cause, 'command', message(85, tag, selector, method), { host, tag, msg: method });
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
const target = root.querySelector(selector);
|
|
51
|
+
if (target === null)
|
|
52
|
+
throw new Error(`no element matches ${selector}`);
|
|
53
|
+
const result = target[method].apply(target, [
|
|
54
|
+
...args,
|
|
55
|
+
]);
|
|
56
|
+
if (result instanceof Promise)
|
|
57
|
+
result.catch(failed);
|
|
58
|
+
}
|
|
59
|
+
catch (cause) {
|
|
60
|
+
failed(cause);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=call.js.map
|
package/dist/call.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call.js","sourceRoot":"","sources":["../src/call.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAS/C,qFAAqF;AACrF,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,IAAI,EAAE,aAAa;IACnB,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS;IACpB,KAAK,EAAE,CAAC,IAAe,EAAE,KAAc,EAAE,EAAE;QACzC,WAAW,CAAC,UAAU,EAAE,GAAG,EAAE;YAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,EAAE,CAAC,WAAW,IAAI,IAAI,KAAK,SAAS;gBAC3C,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,KAAkB,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;IACL,CAAC;CACO,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,IAAI,CAClB,QAAgB,EAChB,MAAc,EACd,GAAG,IAAwB;IAE3B,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,CAAC;YACH,eAAe,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACpD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,IAAgB,EAAE,IAAa,EAAE,GAAW,EAAE,KAAgB;IACpF,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IACzC,MAAM,MAAM,GAAG,CAAC,KAAc,EAAQ,EAAE;QACtC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IACzF,CAAC,CAAC;IACF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAmC,CAAC;QAC9E,IAAI,MAAM,KAAK,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,QAAQ,EAAE,CAAC,CAAC;QACvE,MAAM,MAAM,GAAa,MAAM,CAAC,MAAM,CAAkC,CAAC,KAAK,CAAC,MAAM,EAAE;YACrF,GAAG,IAAI;SACR,CAAC,CAAC;QACH,IAAI,MAAM,YAAY,OAAO;YAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC;AACH,CAAC","sourcesContent":["// Calling a method on an element from the model (gyral-1zd.27, view/05-element.md \"Calling an\n// element's method\"). Telling a child component, a media element or a widget to do something\n// (play, reset, open a room) is a side effect, so the model asks for it with a command, as it\n// does for focus: `call(selector, method, ...args)`. It runs as post-render work against the\n// component's own tree, so the element already exists. Gyral's answer to refs and ports: the\n// request is plain data, so a model test reads it with `callsIn` (@gyral/testing).\nimport type { Command } from './command.js';\nimport { fail } from './errors.js';\nimport type { LocalHost } from './features.js';\nimport { afterRender, POST_FOCUS } from './scheduler.js';\nimport { DEV, message } from './view/index.js';\n\n/** The input of a `call()` command. */\nexport interface CallInput {\n readonly selector: string;\n readonly method: string;\n readonly args: readonly unknown[];\n}\n\n/** Marker driver: the host runs call commands itself (`local`), after the render. */\nexport const CALL = {\n name: '@gyral/call',\n run: () => undefined,\n local: (host: LocalHost, input: unknown) => {\n afterRender(POST_FOCUS, () => {\n const root = host.root();\n if (host.el.isConnected && root !== undefined)\n runCall(root, host.el, host.tag, input as CallInput);\n });\n },\n} as const;\n\n/**\n * A command that calls `method` with `args` on the first element matching `selector` inside\n * this component (its shadow root, or its own children in light-DOM mode) once the current\n * update has rendered:\n *\n * Start: (s) => [{ ...s, playing: true }, [call('video', 'play')]]\n * Join: (s, m) => [s, [call('room-stage', 'join', m.room)]]\n *\n * `args` must be plain data (structured-cloneable), so the command stays data a test can\n * compare. A missing element or method, or a method that throws or rejects, is reported\n * through the error channel (ADR 0024); the error's cause says which.\n */\nexport function call(\n selector: string,\n method: string,\n ...args: readonly unknown[]\n): Command<never> {\n if (DEV) {\n try {\n structuredClone(args);\n } catch {\n throw new TypeError(message(86, selector, method));\n }\n }\n const input: CallInput = { selector, method, args };\n return { driver: CALL, input, onSuccess: () => undefined };\n}\n\n/**\n * Runs a call command against `root`. No element, no such method, or a method that throws or\n * rejects: reported with `host` (the cause says which).\n */\nexport function runCall(root: ParentNode, host: Element, tag: string, input: CallInput): void {\n const { selector, method, args } = input;\n const failed = (cause: unknown): void => {\n fail(cause, 'command', message(85, tag, selector, method), { host, tag, msg: method });\n };\n try {\n const target = root.querySelector(selector) as Record<string, unknown> | null;\n if (target === null) throw new Error(`no element matches ${selector}`);\n const result: unknown = (target[method] as (...a: unknown[]) => unknown).apply(target, [\n ...args,\n ]);\n if (result instanceof Promise) result.catch(failed);\n } catch (cause) {\n failed(cause);\n }\n}\n"]}
|
package/dist/children.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Command } from './command.js';
|
|
2
2
|
import type { LocalHost } from './features.js';
|
|
3
|
-
import type { IntentParser, Tagged } from './types.js';
|
|
3
|
+
import type { IntentInput, IntentParser, Tagged } from './types.js';
|
|
4
4
|
/** Marker driver: the host runs emit commands itself (`local`), synchronously ordered. */
|
|
5
5
|
export declare const EMIT: {
|
|
6
6
|
readonly name: "@gyral/emit";
|
|
@@ -10,8 +10,30 @@ export declare const EMIT: {
|
|
|
10
10
|
/**
|
|
11
11
|
* A command that sends `output` to the parent component. The parent receives it as an
|
|
12
12
|
* intent on the child element: `<my-child data-intent=${i.Picked}>` + `child(MyChild, …)`.
|
|
13
|
+
* `outputs<Out>()` gives the same function typed by the component's output union.
|
|
13
14
|
*/
|
|
14
15
|
export declare function emit(output: Tagged & Readonly<Record<string, unknown>>): Command<never>;
|
|
16
|
+
/**
|
|
17
|
+
* `emit`, typed by a component's output union (the 4th `define` type parameter), so an
|
|
18
|
+
* output of the wrong shape fails to compile. A module-level constant, like `intentsOf()`:
|
|
19
|
+
*
|
|
20
|
+
* type Out = { readonly _tag: 'Picked'; readonly id: number };
|
|
21
|
+
* const emit = outputs<Out>();
|
|
22
|
+
* // in update: Pick: (s, m) => [s, [emit({ _tag: 'Picked', id: m.id })]]
|
|
23
|
+
*
|
|
24
|
+
* Costs nothing at run time: it returns `emit` itself.
|
|
25
|
+
*/
|
|
26
|
+
export declare function outputs<O extends Tagged>(): (output: O) => Command<never>;
|
|
27
|
+
/**
|
|
28
|
+
* The `gyral-output` event a child dispatches on its host for each output (ADR 0010): `detail`
|
|
29
|
+
* is the output. Bubbles, not composed. A non-Gyral parent listens for `OUTPUT_EVENT`. Only the
|
|
30
|
+
* direct parent's intent on the child host takes it, and once it does the event stops there.
|
|
31
|
+
*/
|
|
32
|
+
export type OutputEvent<O extends Tagged = Tagged> = CustomEvent<O>;
|
|
33
|
+
/** The output union of a `define()` class: `OutputsOf<typeof Item>`. */
|
|
34
|
+
export type OutputsOf<C> = C extends {
|
|
35
|
+
readonly outputs?: infer O;
|
|
36
|
+
} ? Exclude<O, undefined> : never;
|
|
15
37
|
/**
|
|
16
38
|
* Sends an output to the parent component. A microtask keeps outputs in order and out of the
|
|
17
39
|
* parent's render pass (settled() waits for it); the event bubbles through the parent's shadow
|
|
@@ -33,8 +55,8 @@ export type ChildSource<O extends Tagged, E extends Element> = OutputSource<O, E
|
|
|
33
55
|
* Pass `() => Child` when the class isn't defined yet, e.g. a component that contains
|
|
34
56
|
* itself; annotate the constant's type so TypeScript accepts the self-reference:
|
|
35
57
|
*
|
|
36
|
-
* const Folder: GyralElementClass<State, Msg, Props, Out> = define('x-folder', {
|
|
58
|
+
* const Folder: GyralElementClass<State, Msg, Props, Out> = define()('x-folder', {
|
|
37
59
|
* intent: { Child: child(() => Folder, (out, el) => …) }, …
|
|
38
60
|
* });
|
|
39
61
|
*/
|
|
40
|
-
export declare function child<O extends Tagged, E extends Element, M>(source: ChildSource<O, E>, toMsg: (output: O, el: E) => M | undefined): IntentParser<M
|
|
62
|
+
export declare function child<O extends Tagged, E extends Element, M>(source: ChildSource<O, E>, toMsg: (output: O, el: E) => M | undefined): (input: IntentInput) => ReturnType<IntentParser<M>>;
|
package/dist/children.js
CHANGED
|
@@ -11,10 +11,27 @@ export const EMIT = {
|
|
|
11
11
|
/**
|
|
12
12
|
* A command that sends `output` to the parent component. The parent receives it as an
|
|
13
13
|
* intent on the child element: `<my-child data-intent=${i.Picked}>` + `child(MyChild, …)`.
|
|
14
|
+
* `outputs<Out>()` gives the same function typed by the component's output union.
|
|
14
15
|
*/
|
|
15
16
|
export function emit(output) {
|
|
16
17
|
return { driver: EMIT, input: output, onSuccess: () => undefined };
|
|
17
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* `emit`, typed by a component's output union (the 4th `define` type parameter), so an
|
|
21
|
+
* output of the wrong shape fails to compile. A module-level constant, like `intentsOf()`:
|
|
22
|
+
*
|
|
23
|
+
* type Out = { readonly _tag: 'Picked'; readonly id: number };
|
|
24
|
+
* const emit = outputs<Out>();
|
|
25
|
+
* // in update: Pick: (s, m) => [s, [emit({ _tag: 'Picked', id: m.id })]]
|
|
26
|
+
*
|
|
27
|
+
* Costs nothing at run time: it returns `emit` itself.
|
|
28
|
+
*/
|
|
29
|
+
// A type-only argument: the caller names the union the result accepts.
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
|
31
|
+
export function outputs() {
|
|
32
|
+
// Sound: emit only forwards the output; the stricter parameter type is the point.
|
|
33
|
+
return emit;
|
|
34
|
+
}
|
|
18
35
|
/**
|
|
19
36
|
* Sends an output to the parent component. A microtask keeps outputs in order and out of the
|
|
20
37
|
* parent's render pass (settled() waits for it); the event bubbles through the parent's shadow
|
|
@@ -38,7 +55,7 @@ const resolveSource = (source) => 'prototype' in source && source.prototype !==
|
|
|
38
55
|
* Pass `() => Child` when the class isn't defined yet, e.g. a component that contains
|
|
39
56
|
* itself; annotate the constant's type so TypeScript accepts the self-reference:
|
|
40
57
|
*
|
|
41
|
-
* const Folder: GyralElementClass<State, Msg, Props, Out> = define('x-folder', {
|
|
58
|
+
* const Folder: GyralElementClass<State, Msg, Props, Out> = define()('x-folder', {
|
|
42
59
|
* intent: { Child: child(() => Folder, (out, el) => …) }, …
|
|
43
60
|
* });
|
|
44
61
|
*/
|
package/dist/children.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"children.js","sourceRoot":"","sources":["../src/children.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,0FAA0F;AAC1F,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,IAAI,EAAE,aAAa;IACnB,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS;IACpB,KAAK,EAAE,CAAC,IAAe,EAAE,MAAe,EAAE,EAAE;QAC1C,cAAc,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;CACO,CAAC;AAEX
|
|
1
|
+
{"version":3,"file":"children.js","sourceRoot":"","sources":["../src/children.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,0FAA0F;AAC1F,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,IAAI,EAAE,aAAa;IACnB,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS;IACpB,KAAK,EAAE,CAAC,IAAe,EAAE,MAAe,EAAE,EAAE;QAC1C,cAAc,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;CACO,CAAC;AAEX;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,MAAkD;IACrE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;AACrE,CAAC;AAED;;;;;;;;;GASG;AACH,uEAAuE;AACvE,6EAA6E;AAC7E,MAAM,UAAU,OAAO;IACrB,kFAAkF;IAClF,OAAO,IAAgD,CAAC;AAC1D,CAAC;AAYD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAa,EAAE,MAAe;IAC3D,KAAK,CAAC,GAAG,EAAE;QACT,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAC9B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAClF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAaD,oEAAoE;AACpE,MAAM,aAAa,GAAG,CACpB,MAAyB,EACL,EAAE,CACtB,WAAW,IAAI,MAAM,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS;IACrD,CAAC,CAAE,MAA6B;IAChC,CAAC,CAAE,MAAmC,EAAE,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,KAAK,CACnB,MAAyB,EACzB,KAA0C;IAE1C,OAAO,CAAC,KAAkB,EAAE,EAAE;QAC5B,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,sDAAsD;QAC1F,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,YAAY,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACpF,8EAA8E;QAC9E,OAAO,KAAK,CAAC,KAAK,CAAC,MAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAChD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["// Child components: props down, outputs up (docs/design-docs/0010-child-components.md).\nimport type { Command } from './command.js';\nimport type { LocalHost } from './features.js';\nimport { OUTPUT_EVENT } from './intent.js';\nimport { defer } from './scheduler.js';\nimport type { IntentInput, IntentParser, Tagged } from './types.js';\n\n/** Marker driver: the host runs emit commands itself (`local`), synchronously ordered. */\nexport const EMIT = {\n name: '@gyral/emit',\n run: () => undefined,\n local: (host: LocalHost, output: unknown) => {\n dispatchOutput(host.el, output);\n },\n} as const;\n\n/**\n * A command that sends `output` to the parent component. The parent receives it as an\n * intent on the child element: `<my-child data-intent=${i.Picked}>` + `child(MyChild, …)`.\n * `outputs<Out>()` gives the same function typed by the component's output union.\n */\nexport function emit(output: Tagged & Readonly<Record<string, unknown>>): Command<never> {\n return { driver: EMIT, input: output, onSuccess: () => undefined };\n}\n\n/**\n * `emit`, typed by a component's output union (the 4th `define` type parameter), so an\n * output of the wrong shape fails to compile. A module-level constant, like `intentsOf()`:\n *\n * type Out = { readonly _tag: 'Picked'; readonly id: number };\n * const emit = outputs<Out>();\n * // in update: Pick: (s, m) => [s, [emit({ _tag: 'Picked', id: m.id })]]\n *\n * Costs nothing at run time: it returns `emit` itself.\n */\n// A type-only argument: the caller names the union the result accepts.\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters\nexport function outputs<O extends Tagged>(): (output: O) => Command<never> {\n // Sound: emit only forwards the output; the stricter parameter type is the point.\n return emit as unknown as (output: O) => Command<never>;\n}\n\n/**\n * The `gyral-output` event a child dispatches on its host for each output (ADR 0010): `detail`\n * is the output. Bubbles, not composed. A non-Gyral parent listens for `OUTPUT_EVENT`. Only the\n * direct parent's intent on the child host takes it, and once it does the event stops there.\n */\nexport type OutputEvent<O extends Tagged = Tagged> = CustomEvent<O>;\n\n/** The output union of a `define()` class: `OutputsOf<typeof Item>`. */\nexport type OutputsOf<C> = C extends { readonly outputs?: infer O } ? Exclude<O, undefined> : never;\n\n/**\n * Sends an output to the parent component. A microtask keeps outputs in order and out of the\n * parent's render pass (settled() waits for it); the event bubbles through the parent's shadow\n * tree only (not composed).\n */\nexport function dispatchOutput(host: Element, output: unknown): void {\n defer(() => {\n if (!host.isConnected) return;\n host.dispatchEvent(\n new CustomEvent(OUTPUT_EVENT, { detail: output, bubbles: true, composed: false }),\n );\n });\n}\n\n/** Anything `child()` can read an output type from: a `define()` class. */\nexport interface OutputSource<O extends Tagged, E extends Element> {\n new (): E;\n /** Type-only marker for the component's output union. Never set at runtime. */\n readonly outputs?: O;\n}\n\n/** A child class, or a function returning it (for recursive or later-defined components). */\nexport type ChildSource<O extends Tagged, E extends Element> =\n OutputSource<O, E> | (() => OutputSource<O, E>);\n\n// Classes have a prototype; arrow functions (the lazy form) do not.\nconst resolveSource = <O extends Tagged, E extends Element>(\n source: ChildSource<O, E>,\n): OutputSource<O, E> =>\n 'prototype' in source && source.prototype !== undefined\n ? (source as OutputSource<O, E>)\n : (source as () => OutputSource<O, E>)();\n\n/**\n * Intent parser for a child component's outputs, typed by the child's output union.\n * `el` is the child element, for reading its props (an item id, for example).\n *\n * Pass `() => Child` when the class isn't defined yet, e.g. a component that contains\n * itself; annotate the constant's type so TypeScript accepts the self-reference:\n *\n * const Folder: GyralElementClass<State, Msg, Props, Out> = define()('x-folder', {\n * intent: { Child: child(() => Folder, (out, el) => …) }, …\n * });\n */\nexport function child<O extends Tagged, E extends Element, M>(\n source: ChildSource<O, E>,\n toMsg: (output: O, el: E) => M | undefined,\n): (input: IntentInput) => ReturnType<IntentParser<M>> {\n return (input: IntentInput) => {\n const type = resolveSource(source); // resolved per event, so the lazy form never hits TDZ\n if (!(input.target instanceof type) || input.detail === undefined) return undefined;\n // Sound: only `emit()` from a component of this class dispatches this detail.\n return toMsg(input.detail as O, input.target);\n };\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// gyral-types: writes the element typings gyralVitePreset() writes (gyral-1zd.25), for type
|
|
3
|
+
// checks that run without Vite (`gyral-types && tsc --noEmit`).
|
|
4
|
+
// gyral-types [--root <dir>] [--dir <src dir>]... [--out <file>]
|
|
5
|
+
import { resolve } from 'node:path';
|
|
6
|
+
import { parseArgs } from 'node:util';
|
|
7
|
+
import { writeTagMap } from '../compiler/tag-map.js';
|
|
8
|
+
const { values } = parseArgs({
|
|
9
|
+
options: {
|
|
10
|
+
root: { type: 'string', default: '.' },
|
|
11
|
+
dir: { type: 'string', multiple: true },
|
|
12
|
+
out: { type: 'string' },
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
const { entries, written } = writeTagMap({
|
|
16
|
+
root: resolve(values.root),
|
|
17
|
+
...(values.dir === undefined ? {} : { dirs: values.dir }),
|
|
18
|
+
...(values.out === undefined ? {} : { out: values.out }),
|
|
19
|
+
});
|
|
20
|
+
const where = values.out ?? '.gyral/elements.d.ts';
|
|
21
|
+
console.log(`gyral-types: ${String(entries.length)} element${entries.length === 1 ? '' : 's'} ` +
|
|
22
|
+
`${written ? 'written to' : 'unchanged in'} ${where}`);
|
|
23
|
+
//# sourceMappingURL=gyral-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gyral-types.js","sourceRoot":"","sources":["../../src/cli/gyral-types.ts"],"names":[],"mappings":";AACA,4FAA4F;AAC5F,gEAAgE;AAChE,mEAAmE;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE;QACP,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE;QACtC,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;QACvC,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KACxB;CACF,CAAC,CAAC;AAEH,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC;IACvC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;IAC1B,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;IACzD,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;CACzD,CAAC,CAAC;AACH,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,IAAI,sBAAsB,CAAC;AACnD,OAAO,CAAC,GAAG,CACT,gBAAgB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG;IACjF,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,IAAI,KAAK,EAAE,CACxD,CAAC","sourcesContent":["#!/usr/bin/env node\n// gyral-types: writes the element typings gyralVitePreset() writes (gyral-1zd.25), for type\n// checks that run without Vite (`gyral-types && tsc --noEmit`).\n// gyral-types [--root <dir>] [--dir <src dir>]... [--out <file>]\nimport { resolve } from 'node:path';\nimport { parseArgs } from 'node:util';\nimport { writeTagMap } from '../compiler/tag-map.js';\n\nconst { values } = parseArgs({\n options: {\n root: { type: 'string', default: '.' },\n dir: { type: 'string', multiple: true },\n out: { type: 'string' },\n },\n});\n\nconst { entries, written } = writeTagMap({\n root: resolve(values.root),\n ...(values.dir === undefined ? {} : { dirs: values.dir }),\n ...(values.out === undefined ? {} : { out: values.out }),\n});\nconst where = values.out ?? '.gyral/elements.d.ts';\nconsole.log(\n `gyral-types: ${String(entries.length)} element${entries.length === 1 ? '' : 's'} ` +\n `${written ? 'written to' : 'unchanged in'} ${where}`,\n);\n"]}
|
package/dist/command.d.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import type { IntentRejected } from './types.js';
|
|
2
2
|
/** How commands in the same lane interact. See ADR 0006 for the table. */
|
|
3
3
|
export type Concurrency = 'merge' | 'switch' | 'exhaust' | 'queue';
|
|
4
|
-
|
|
4
|
+
/** How `retry(driver, policy)` retries a rejected run (retry.ts). `E`: the driver's error. */
|
|
5
|
+
export interface RetryPolicy<E = unknown> {
|
|
5
6
|
/** Retries after the first failure. */
|
|
6
7
|
readonly times: number;
|
|
7
8
|
/** Delay before each retry (the base delay for exponential backoff). Default 0. */
|
|
8
9
|
readonly delayMs?: number;
|
|
9
10
|
readonly backoff?: 'fixed' | 'exponential';
|
|
11
|
+
/** Full jitter: wait a random time between 0 and the computed delay, so clients spread out. */
|
|
12
|
+
readonly jitter?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Which failures to retry, given the driver's typed error (its `toError`, else the thrown
|
|
15
|
+
* value). Default: every failure. For `@gyral/http`, `retryableHttpError`.
|
|
16
|
+
*/
|
|
17
|
+
readonly retryIf?: (error: E) => boolean;
|
|
10
18
|
}
|
|
11
19
|
export interface DriverContext<O = unknown> {
|
|
12
20
|
/** Aborts when the command is switched away or its component disconnects. */
|
|
@@ -24,15 +32,35 @@ export interface Driver<I, O, E = unknown> {
|
|
|
24
32
|
readonly run: (input: I, ctx: DriverContext<O>) => O | Promise<O>;
|
|
25
33
|
/** Default policy for this driver's commands. Default `'merge'`. */
|
|
26
34
|
readonly concurrency?: Concurrency;
|
|
27
|
-
readonly retry?: RetryPolicy;
|
|
28
35
|
/** Turns a thrown or rejected value into this driver's typed error. */
|
|
29
36
|
readonly toError?: (cause: unknown) => E;
|
|
30
37
|
}
|
|
31
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Any driver, with its input type erased. Every `Driver<I, O, E>` (from `defineDriver`,
|
|
40
|
+
* `subscription`, a test fake) is assignable to it as is: no cast.
|
|
41
|
+
*/
|
|
32
42
|
export type AnyDriver = Driver<never, unknown>;
|
|
33
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* A driver with no implementation of its own (`defineDriver<I, O, E>('session')`): commands built
|
|
45
|
+
* from it are typed by `I`, `O` and `E`, and it runs only when `provideDrivers` or `el.drivers`
|
|
46
|
+
* supplies a driver of that name (ADR 0006 addendum "Driver tokens").
|
|
47
|
+
*/
|
|
48
|
+
export interface DriverToken<E = unknown> {
|
|
49
|
+
readonly name: string;
|
|
50
|
+
readonly concurrency?: Concurrency;
|
|
51
|
+
readonly toError?: (cause: unknown) => E;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Drivers substituted by name (test fakes, configured instances): `el.drivers`,
|
|
55
|
+
* `provideDrivers`. Annotate a driver map with this type (or `Record<string, AnyDriver>`), not
|
|
56
|
+
* `Record<string, Driver<unknown, unknown>>`, which rejects drivers with a typed input.
|
|
57
|
+
*/
|
|
34
58
|
export type DriverOverrides = Readonly<Record<string, AnyDriver>>;
|
|
35
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* A side effect described as data, plus pure mappers from its outcome to messages. Commands
|
|
61
|
+
* that answer with no message (`focus()`, `call()`, `navigate()`) are `Command<never>`,
|
|
62
|
+
* which fits wherever a `Command<Msg>` is expected: no type argument needed.
|
|
63
|
+
*/
|
|
36
64
|
export interface Command<M> {
|
|
37
65
|
readonly driver: AnyDriver;
|
|
38
66
|
readonly input: unknown;
|
|
@@ -40,24 +68,38 @@ export interface Command<M> {
|
|
|
40
68
|
readonly key?: string;
|
|
41
69
|
readonly concurrency?: Concurrency;
|
|
42
70
|
readonly onSuccess: (output: unknown) => M | undefined;
|
|
43
|
-
/** If omitted,
|
|
71
|
+
/** If omitted, a failure is reported to the error channel (ADR 0024, G0041). */
|
|
44
72
|
readonly onFailure?: (error: unknown) => M | undefined;
|
|
45
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* How a command's outcome becomes a message. Every field is optional: without `onSuccess` the
|
|
76
|
+
* command answers with nothing (`Command<never>`); without `onFailure` a failure is reported to
|
|
77
|
+
* the error channel (ADR 0024).
|
|
78
|
+
*/
|
|
46
79
|
export interface CommandHandlers<O, E, MS, MF = MS> {
|
|
47
|
-
readonly onSuccess
|
|
80
|
+
readonly onSuccess?: (output: O) => MS | undefined;
|
|
48
81
|
readonly onFailure?: (error: E) => MF | undefined;
|
|
49
82
|
readonly key?: string;
|
|
50
83
|
readonly concurrency?: Concurrency;
|
|
51
84
|
}
|
|
52
85
|
/**
|
|
53
86
|
* What a reducer (or `init`) returns: new state, optionally with commands to run. Commands may
|
|
54
|
-
* also answer with the framework message `IntentRejected` (e.g. `submitForm` in
|
|
87
|
+
* also answer with the framework message `IntentRejected` (e.g. `submitForm` in `@gyral/http`
|
|
55
88
|
* when the server rejects a form), which goes to the optional `IntentRejected` reducer.
|
|
56
89
|
*/
|
|
57
90
|
export type Next<S, M> = S | readonly [S, ReadonlyArray<Command<M | IntentRejected>>];
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Defines a driver. Given an implementation (`run`), it returns it as is, so literals infer
|
|
93
|
+
* `I`, `O` and `E`. Given only a name, it returns a typed **token**: commands built from it are
|
|
94
|
+
* typed, and it runs only when a provider (`provideDrivers`) or `el.drivers` supplies a driver of
|
|
95
|
+
* that name. A command whose token nothing provides fails with G0043, naming the driver.
|
|
96
|
+
*/
|
|
97
|
+
export declare function defineDriver<I, O, E = unknown>(spec: Driver<I, O, E> | DriverToken<E> | string): Driver<I, O, E>;
|
|
98
|
+
/**
|
|
99
|
+
* Builds a command whose mappers are typed by the driver's input, output and error. Without
|
|
100
|
+
* handlers (or without `onSuccess`) it answers with no message: `command(log, line)` is a
|
|
101
|
+
* `Command<never>`, which fits any `Command<Msg>`.
|
|
102
|
+
*/
|
|
103
|
+
export declare function command<I, O, E, const MS = never, const MF = MS>(driver: Driver<I, O, E>, input: I, handlers?: CommandHandlers<O, E, MS, MF>): Command<MS | MF>;
|
|
62
104
|
/** Splits a reducer result into state and commands. State is never an array (ADR 0006). */
|
|
63
105
|
export declare function splitNext<S, M>(next: Next<S, M>): readonly [S, ReadonlyArray<Command<M | IntentRejected>>];
|
package/dist/command.js
CHANGED
|
@@ -3,21 +3,35 @@
|
|
|
3
3
|
// that build no commands don't bundle it.
|
|
4
4
|
import { features } from './features.js';
|
|
5
5
|
import { hostInterpreter } from './internal/interpreter.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import { unprovided } from './internal/token.js';
|
|
7
|
+
/**
|
|
8
|
+
* Defines a driver. Given an implementation (`run`), it returns it as is, so literals infer
|
|
9
|
+
* `I`, `O` and `E`. Given only a name, it returns a typed **token**: commands built from it are
|
|
10
|
+
* typed, and it runs only when a provider (`provideDrivers`) or `el.drivers` supplies a driver of
|
|
11
|
+
* that name. A command whose token nothing provides fails with G0043, naming the driver.
|
|
12
|
+
*/
|
|
13
|
+
export function defineDriver(spec) {
|
|
14
|
+
if (typeof spec === 'string')
|
|
15
|
+
return { name: spec, run: unprovided };
|
|
16
|
+
return 'run' in spec ? spec : { ...spec, run: unprovided };
|
|
9
17
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
18
|
+
const none = () => undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Builds a command whose mappers are typed by the driver's input, output and error. Without
|
|
21
|
+
* handlers (or without `onSuccess`) it answers with no message: `command(log, line)` is a
|
|
22
|
+
* `Command<never>`, which fits any `Command<Msg>`.
|
|
23
|
+
*/
|
|
24
|
+
// Two message parameters so success and failure may produce different variants; `const` keeps
|
|
25
|
+
// a mapper's `{ _tag: 'Loaded' }` literal, so no type arguments are needed.
|
|
26
|
+
export function command(driver, input, handlers = {}) {
|
|
13
27
|
features.commands = hostInterpreter;
|
|
14
|
-
const { onFailure, key, concurrency } = handlers;
|
|
28
|
+
const { onSuccess = none, onFailure, key, concurrency } = handlers;
|
|
29
|
+
// Sound: the interpreter only passes this driver's output and toError() result.
|
|
15
30
|
return {
|
|
16
|
-
driver
|
|
31
|
+
driver,
|
|
17
32
|
input,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
...(onFailure === undefined ? {} : { onFailure: (error) => onFailure(error) }),
|
|
33
|
+
onSuccess,
|
|
34
|
+
...(onFailure && { onFailure }),
|
|
21
35
|
...(key === undefined ? {} : { key }),
|
|
22
36
|
...(concurrency === undefined ? {} : { concurrency }),
|
|
23
37
|
};
|
package/dist/command.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.js","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,+FAA+F;AAC/F,0CAA0C;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,+FAA+F;AAC/F,0CAA0C;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAsGjD;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,IAA+C;IAE/C,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;IACrE,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;AAC7D,CAAC;AAED,MAAM,IAAI,GAAG,GAAc,EAAE,CAAC,SAAS,CAAC;AAExC;;;;GAIG;AACH,8FAA8F;AAC9F,4EAA4E;AAC5E,MAAM,UAAU,OAAO,CACrB,MAAuB,EACvB,KAAQ,EACR,WAA0C,EAAE;IAE5C,QAAQ,CAAC,QAAQ,GAAG,eAAe,CAAC;IACpC,MAAM,EAAE,SAAS,GAAG,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,QAAQ,CAAC;IACnE,gFAAgF;IAChF,OAAO;QACL,MAAM;QACN,KAAK;QACL,SAAS;QACT,GAAG,CAAC,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;QAC/B,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC;QACrC,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;KAClC,CAAC;AACxB,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,SAAS,CACvB,IAAgB;IAEhB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,OAAO,IAAgE,CAAC;IAC1E,CAAC;IACD,OAAO,CAAC,IAAS,EAAE,EAAE,CAAC,CAAC;AACzB,CAAC","sourcesContent":["// Effects as data (docs/design-docs/0006-effects-and-drivers.md). Plain TypeScript only: the\n// interpreter lives in ./internal/ (ADR 0015); `command()` registers it (features.ts), so apps\n// that build no commands don't bundle it.\nimport { features } from './features.js';\nimport { hostInterpreter } from './internal/interpreter.js';\nimport { unprovided } from './internal/token.js';\nimport type { IntentRejected } from './types.js';\n\n/** How commands in the same lane interact. See ADR 0006 for the table. */\nexport type Concurrency = 'merge' | 'switch' | 'exhaust' | 'queue';\n\n/** How `retry(driver, policy)` retries a rejected run (retry.ts). `E`: the driver's error. */\nexport interface RetryPolicy<E = unknown> {\n /** Retries after the first failure. */\n readonly times: number;\n /** Delay before each retry (the base delay for exponential backoff). Default 0. */\n readonly delayMs?: number;\n readonly backoff?: 'fixed' | 'exponential';\n /** Full jitter: wait a random time between 0 and the computed delay, so clients spread out. */\n readonly jitter?: boolean;\n /**\n * Which failures to retry, given the driver's typed error (its `toError`, else the thrown\n * value). Default: every failure. For `@gyral/http`, `retryableHttpError`.\n */\n readonly retryIf?: (error: E) => boolean;\n}\n\nexport interface DriverContext<O = unknown> {\n /** Aborts when the command is switched away or its component disconnects. */\n readonly signal: AbortSignal;\n /**\n * Delivers an extra result while the command runs (streaming drivers: routers, timers,\n * sockets). Each value goes through the command's `onSuccess`. Ignored once the command\n * has settled or been aborted. A streaming `run` usually never resolves; abort ends it.\n */\n readonly emit: (output: O) => void;\n}\n\n/** Performs one kind of side effect. A plain object: easy to fake in tests. */\nexport interface Driver<I, O, E = unknown> {\n readonly name: string;\n readonly run: (input: I, ctx: DriverContext<O>) => O | Promise<O>;\n /** Default policy for this driver's commands. Default `'merge'`. */\n readonly concurrency?: Concurrency;\n /** Turns a thrown or rejected value into this driver's typed error. */\n readonly toError?: (cause: unknown) => E;\n}\n\n/**\n * Any driver, with its input type erased. Every `Driver<I, O, E>` (from `defineDriver`,\n * `subscription`, a test fake) is assignable to it as is: no cast.\n */\nexport type AnyDriver = Driver<never, unknown>;\n\n/**\n * A driver with no implementation of its own (`defineDriver<I, O, E>('session')`): commands built\n * from it are typed by `I`, `O` and `E`, and it runs only when `provideDrivers` or `el.drivers`\n * supplies a driver of that name (ADR 0006 addendum \"Driver tokens\").\n */\nexport interface DriverToken<E = unknown> {\n readonly name: string;\n readonly concurrency?: Concurrency;\n readonly toError?: (cause: unknown) => E;\n}\n\n/**\n * Drivers substituted by name (test fakes, configured instances): `el.drivers`,\n * `provideDrivers`. Annotate a driver map with this type (or `Record<string, AnyDriver>`), not\n * `Record<string, Driver<unknown, unknown>>`, which rejects drivers with a typed input.\n */\nexport type DriverOverrides = Readonly<Record<string, AnyDriver>>;\n\n/**\n * A side effect described as data, plus pure mappers from its outcome to messages. Commands\n * that answer with no message (`focus()`, `call()`, `navigate()`) are `Command<never>`,\n * which fits wherever a `Command<Msg>` is expected: no type argument needed.\n */\nexport interface Command<M> {\n readonly driver: AnyDriver;\n readonly input: unknown;\n /** Concurrency lane. Default: the driver's name. */\n readonly key?: string;\n readonly concurrency?: Concurrency;\n readonly onSuccess: (output: unknown) => M | undefined;\n /** If omitted, a failure is reported to the error channel (ADR 0024, G0041). */\n readonly onFailure?: (error: unknown) => M | undefined;\n}\n\n/**\n * How a command's outcome becomes a message. Every field is optional: without `onSuccess` the\n * command answers with nothing (`Command<never>`); without `onFailure` a failure is reported to\n * the error channel (ADR 0024).\n */\nexport interface CommandHandlers<O, E, MS, MF = MS> {\n readonly onSuccess?: (output: O) => MS | undefined;\n readonly onFailure?: (error: E) => MF | undefined;\n readonly key?: string;\n readonly concurrency?: Concurrency;\n}\n\n/**\n * What a reducer (or `init`) returns: new state, optionally with commands to run. Commands may\n * also answer with the framework message `IntentRejected` (e.g. `submitForm` in `@gyral/http`\n * when the server rejects a form), which goes to the optional `IntentRejected` reducer.\n */\nexport type Next<S, M> = S | readonly [S, ReadonlyArray<Command<M | IntentRejected>>];\n\n/**\n * Defines a driver. Given an implementation (`run`), it returns it as is, so literals infer\n * `I`, `O` and `E`. Given only a name, it returns a typed **token**: commands built from it are\n * typed, and it runs only when a provider (`provideDrivers`) or `el.drivers` supplies a driver of\n * that name. A command whose token nothing provides fails with G0043, naming the driver.\n */\nexport function defineDriver<I, O, E = unknown>(\n spec: Driver<I, O, E> | DriverToken<E> | string,\n): Driver<I, O, E> {\n if (typeof spec === 'string') return { name: spec, run: unprovided };\n return 'run' in spec ? spec : { ...spec, run: unprovided };\n}\n\nconst none = (): undefined => undefined;\n\n/**\n * Builds a command whose mappers are typed by the driver's input, output and error. Without\n * handlers (or without `onSuccess`) it answers with no message: `command(log, line)` is a\n * `Command<never>`, which fits any `Command<Msg>`.\n */\n// Two message parameters so success and failure may produce different variants; `const` keeps\n// a mapper's `{ _tag: 'Loaded' }` literal, so no type arguments are needed.\nexport function command<I, O, E, const MS = never, const MF = MS>(\n driver: Driver<I, O, E>,\n input: I,\n handlers: CommandHandlers<O, E, MS, MF> = {},\n): Command<MS | MF> {\n features.commands = hostInterpreter;\n const { onSuccess = none, onFailure, key, concurrency } = handlers;\n // Sound: the interpreter only passes this driver's output and toError() result.\n return {\n driver,\n input,\n onSuccess,\n ...(onFailure && { onFailure }),\n ...(key === undefined ? {} : { key }),\n ...(concurrency === undefined ? {} : { concurrency }),\n } as Command<MS | MF>;\n}\n\n/** Splits a reducer result into state and commands. State is never an array (ADR 0006). */\nexport function splitNext<S, M>(\n next: Next<S, M>,\n): readonly [S, ReadonlyArray<Command<M | IntentRejected>>] {\n if (Array.isArray(next) && next.length === 2 && Array.isArray(next[1])) {\n return next as readonly [S, ReadonlyArray<Command<M | IntentRejected>>];\n }\n return [next as S, []];\n}\n"]}
|
package/dist/compiler/ast.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** The `lang` to parse a module with, from its id (`this.parse(code, { lang })`). */
|
|
2
|
+
export declare const langOf: (id: string) => "js" | "jsx" | "ts" | "tsx";
|
|
1
3
|
/** An ESTree node: `start`/`end` are UTF-16 offsets into the module's code. */
|
|
2
4
|
export interface Node {
|
|
3
5
|
readonly type: string;
|