@pwfabric/runtime 0.0.0-stage → 1.0.0-rc.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/LICENSE +90 -0
- package/README.md +43 -2
- package/dist/a11y/announcer.d.ts +65 -0
- package/dist/a11y/announcer.js +140 -0
- package/dist/a11y/announcer.js.map +1 -0
- package/dist/a11y/contrast.d.ts +54 -0
- package/dist/a11y/contrast.js +93 -0
- package/dist/a11y/contrast.js.map +1 -0
- package/dist/a11y/focus.d.ts +123 -0
- package/dist/a11y/focus.js +282 -0
- package/dist/a11y/focus.js.map +1 -0
- package/dist/a11y/index.d.ts +21 -0
- package/dist/a11y/index.js +18 -0
- package/dist/a11y/index.js.map +1 -0
- package/dist/a11y/keyboard.d.ts +144 -0
- package/dist/a11y/keyboard.js +317 -0
- package/dist/a11y/keyboard.js.map +1 -0
- package/dist/adapters/default-image.d.ts +25 -0
- package/dist/adapters/default-image.js +37 -0
- package/dist/adapters/default-image.js.map +1 -0
- package/dist/adapters/index.d.ts +27 -0
- package/dist/adapters/index.js +28 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/next-image.d.ts +38 -0
- package/dist/adapters/next-image.js +124 -0
- package/dist/adapters/next-image.js.map +1 -0
- package/dist/adapters/types.d.ts +61 -0
- package/dist/adapters/types.js +11 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/analytics/index.d.ts +14 -0
- package/dist/analytics/index.js +15 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/tracker.d.ts +65 -0
- package/dist/analytics/tracker.js +251 -0
- package/dist/analytics/tracker.js.map +1 -0
- package/dist/analytics/types.d.ts +130 -0
- package/dist/analytics/types.js +11 -0
- package/dist/analytics/types.js.map +1 -0
- package/dist/auth/index.d.ts +15 -0
- package/dist/auth/index.js +14 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/provider.d.ts +132 -0
- package/dist/auth/provider.js +473 -0
- package/dist/auth/provider.js.map +1 -0
- package/dist/auth/types.d.ts +117 -0
- package/dist/auth/types.js +9 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/binding/collection.d.ts +190 -0
- package/dist/binding/collection.js +358 -0
- package/dist/binding/collection.js.map +1 -0
- package/dist/binding/datasource.d.ts +319 -0
- package/dist/binding/datasource.js +556 -0
- package/dist/binding/datasource.js.map +1 -0
- package/dist/binding/engine.d.ts +65 -0
- package/dist/binding/engine.js +268 -0
- package/dist/binding/engine.js.map +1 -0
- package/dist/binding/expression.d.ts +150 -0
- package/dist/binding/expression.js +787 -0
- package/dist/binding/expression.js.map +1 -0
- package/dist/binding/index.d.ts +19 -0
- package/dist/binding/index.js +14 -0
- package/dist/binding/index.js.map +1 -0
- package/dist/binding/two-way.d.ts +149 -0
- package/dist/binding/two-way.js +462 -0
- package/dist/binding/two-way.js.map +1 -0
- package/dist/binding/types.d.ts +119 -0
- package/dist/binding/types.js +9 -0
- package/dist/binding/types.js.map +1 -0
- package/dist/blocks/component-types.d.ts +81 -0
- package/dist/blocks/component-types.js +11 -0
- package/dist/blocks/component-types.js.map +1 -0
- package/dist/blocks/composition-rules.d.ts +168 -0
- package/dist/blocks/composition-rules.js +391 -0
- package/dist/blocks/composition-rules.js.map +1 -0
- package/dist/blocks/hooks.d.ts +31 -0
- package/dist/blocks/hooks.js +42 -0
- package/dist/blocks/hooks.js.map +1 -0
- package/dist/blocks/index.d.ts +14 -0
- package/dist/blocks/index.js +23 -0
- package/dist/blocks/index.js.map +1 -0
- package/dist/blocks/registry.d.ts +84 -0
- package/dist/blocks/registry.js +136 -0
- package/dist/blocks/registry.js.map +1 -0
- package/dist/blocks/rule-engine.d.ts +131 -0
- package/dist/blocks/rule-engine.js +321 -0
- package/dist/blocks/rule-engine.js.map +1 -0
- package/dist/blocks/surface-event-context.d.ts +13 -0
- package/dist/blocks/surface-event-context.js +14 -0
- package/dist/blocks/surface-event-context.js.map +1 -0
- package/dist/blocks/surface-id-context.d.ts +13 -0
- package/dist/blocks/surface-id-context.js +15 -0
- package/dist/blocks/surface-id-context.js.map +1 -0
- package/dist/bus.d.ts +41 -0
- package/dist/bus.js +158 -0
- package/dist/bus.js.map +1 -0
- package/dist/cache/index.d.ts +9 -0
- package/dist/cache/index.js +10 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/memory.d.ts +32 -0
- package/dist/cache/memory.js +138 -0
- package/dist/cache/memory.js.map +1 -0
- package/dist/cache/types.d.ts +62 -0
- package/dist/cache/types.js +9 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/capability/index.d.ts +72 -0
- package/dist/capability/index.js +87 -0
- package/dist/capability/index.js.map +1 -0
- package/dist/capability/kernel-capabilities.d.ts +31 -0
- package/dist/capability/kernel-capabilities.js +36 -0
- package/dist/capability/kernel-capabilities.js.map +1 -0
- package/dist/capability/platform-capabilities.d.ts +71 -0
- package/dist/capability/platform-capabilities.js +267 -0
- package/dist/capability/platform-capabilities.js.map +1 -0
- package/dist/capability/type-mapping.d.ts +70 -0
- package/dist/capability/type-mapping.js +107 -0
- package/dist/capability/type-mapping.js.map +1 -0
- package/dist/capability/validation.d.ts +46 -0
- package/dist/capability/validation.js +54 -0
- package/dist/capability/validation.js.map +1 -0
- package/dist/connectors/declared-connector.d.ts +48 -0
- package/dist/connectors/declared-connector.js +333 -0
- package/dist/connectors/declared-connector.js.map +1 -0
- package/dist/connectors/engine-registry.d.ts +50 -0
- package/dist/connectors/engine-registry.js +135 -0
- package/dist/connectors/engine-registry.js.map +1 -0
- package/dist/connectors/index.d.ts +14 -0
- package/dist/connectors/index.js +14 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/module-loader.d.ts +70 -0
- package/dist/connectors/module-loader.js +143 -0
- package/dist/connectors/module-loader.js.map +1 -0
- package/dist/connectors/types.d.ts +174 -0
- package/dist/connectors/types.js +23 -0
- package/dist/connectors/types.js.map +1 -0
- package/dist/context.d.ts +27 -0
- package/dist/context.js +38 -0
- package/dist/context.js.map +1 -0
- package/dist/data/DataCapabilityProvider.d.ts +39 -0
- package/dist/data/DataCapabilityProvider.js +58 -0
- package/dist/data/DataCapabilityProvider.js.map +1 -0
- package/dist/data/index.d.ts +17 -0
- package/dist/data/index.js +18 -0
- package/dist/data/index.js.map +1 -0
- package/dist/data/manager.d.ts +40 -0
- package/dist/data/manager.js +442 -0
- package/dist/data/manager.js.map +1 -0
- package/dist/data/types.d.ts +218 -0
- package/dist/data/types.js +2 -0
- package/dist/data/types.js.map +1 -0
- package/dist/entity/aggregate.d.ts +8 -0
- package/dist/entity/aggregate.js +24 -0
- package/dist/entity/aggregate.js.map +1 -0
- package/dist/entity/apply-query.d.ts +58 -0
- package/dist/entity/apply-query.js +264 -0
- package/dist/entity/apply-query.js.map +1 -0
- package/dist/entity/behavior.d.ts +94 -0
- package/dist/entity/behavior.js +78 -0
- package/dist/entity/behavior.js.map +1 -0
- package/dist/entity/connector.d.ts +141 -0
- package/dist/entity/connector.js +89 -0
- package/dist/entity/connector.js.map +1 -0
- package/dist/entity/connectors/index.d.ts +12 -0
- package/dist/entity/connectors/index.js +11 -0
- package/dist/entity/connectors/index.js.map +1 -0
- package/dist/entity/connectors/static.d.ts +51 -0
- package/dist/entity/connectors/static.js +245 -0
- package/dist/entity/connectors/static.js.map +1 -0
- package/dist/entity/entity-datasource.d.ts +50 -0
- package/dist/entity/entity-datasource.js +33 -0
- package/dist/entity/entity-datasource.js.map +1 -0
- package/dist/entity/facade.d.ts +70 -0
- package/dist/entity/facade.js +70 -0
- package/dist/entity/facade.js.map +1 -0
- package/dist/entity/http-connector.d.ts +123 -0
- package/dist/entity/http-connector.js +295 -0
- package/dist/entity/http-connector.js.map +1 -0
- package/dist/entity/index.d.ts +38 -0
- package/dist/entity/index.js +31 -0
- package/dist/entity/index.js.map +1 -0
- package/dist/entity/postgres-connector.d.ts +64 -0
- package/dist/entity/postgres-connector.js +239 -0
- package/dist/entity/postgres-connector.js.map +1 -0
- package/dist/entity/registry.d.ts +59 -0
- package/dist/entity/registry.js +90 -0
- package/dist/entity/registry.js.map +1 -0
- package/dist/entity/store.d.ts +66 -0
- package/dist/entity/store.js +349 -0
- package/dist/entity/store.js.map +1 -0
- package/dist/entity/types.d.ts +180 -0
- package/dist/entity/types.js +10 -0
- package/dist/entity/types.js.map +1 -0
- package/dist/execution-context.d.ts +88 -0
- package/dist/execution-context.js +146 -0
- package/dist/execution-context.js.map +1 -0
- package/dist/executor.d.ts +27 -0
- package/dist/executor.js +33 -0
- package/dist/executor.js.map +1 -0
- package/dist/forms/form-entity-bridge.d.ts +94 -0
- package/dist/forms/form-entity-bridge.js +96 -0
- package/dist/forms/form-entity-bridge.js.map +1 -0
- package/dist/forms/form-write-target.d.ts +34 -0
- package/dist/forms/form-write-target.js +81 -0
- package/dist/forms/form-write-target.js.map +1 -0
- package/dist/forms/index.d.ts +22 -0
- package/dist/forms/index.js +25 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms/named-control-values.d.ts +27 -0
- package/dist/forms/named-control-values.js +42 -0
- package/dist/forms/named-control-values.js.map +1 -0
- package/dist/forms/processor.d.ts +55 -0
- package/dist/forms/processor.js +154 -0
- package/dist/forms/processor.js.map +1 -0
- package/dist/forms/types.d.ts +174 -0
- package/dist/forms/types.js +33 -0
- package/dist/forms/types.js.map +1 -0
- package/dist/forms/validator.d.ts +61 -0
- package/dist/forms/validator.js +218 -0
- package/dist/forms/validator.js.map +1 -0
- package/dist/graph/index.d.ts +10 -0
- package/dist/graph/index.js +9 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/resolver.d.ts +66 -0
- package/dist/graph/resolver.js +243 -0
- package/dist/graph/resolver.js.map +1 -0
- package/dist/graph/types.d.ts +125 -0
- package/dist/graph/types.js +9 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/hooks/useInstalledAtoms.d.ts +96 -0
- package/dist/hooks/useInstalledAtoms.js +92 -0
- package/dist/hooks/useInstalledAtoms.js.map +1 -0
- package/dist/i18n/index.d.ts +15 -0
- package/dist/i18n/index.js +14 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/translator.d.ts +76 -0
- package/dist/i18n/translator.js +357 -0
- package/dist/i18n/translator.js.map +1 -0
- package/dist/i18n/types.d.ts +93 -0
- package/dist/i18n/types.js +9 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel.d.ts +47 -0
- package/dist/kernel.js +258 -0
- package/dist/kernel.js.map +1 -0
- package/dist/perf/budget.d.ts +92 -0
- package/dist/perf/budget.js +122 -0
- package/dist/perf/budget.js.map +1 -0
- package/dist/perf/index.d.ts +16 -0
- package/dist/perf/index.js +13 -0
- package/dist/perf/index.js.map +1 -0
- package/dist/perf/render-timer.d.ts +90 -0
- package/dist/perf/render-timer.js +136 -0
- package/dist/perf/render-timer.js.map +1 -0
- package/dist/perf/reporter.d.ts +126 -0
- package/dist/perf/reporter.js +241 -0
- package/dist/perf/reporter.js.map +1 -0
- package/dist/perf/web-vitals.d.ts +111 -0
- package/dist/perf/web-vitals.js +268 -0
- package/dist/perf/web-vitals.js.map +1 -0
- package/dist/registry.d.ts +63 -0
- package/dist/registry.js +126 -0
- package/dist/registry.js.map +1 -0
- package/dist/render/BehaviorSurfaceProvider.d.ts +65 -0
- package/dist/render/BehaviorSurfaceProvider.js +185 -0
- package/dist/render/BehaviorSurfaceProvider.js.map +1 -0
- package/dist/render/BlockErrorBoundary.d.ts +26 -0
- package/dist/render/BlockErrorBoundary.js +41 -0
- package/dist/render/BlockErrorBoundary.js.map +1 -0
- package/dist/render/DataBoundSurfaceRenderer.d.ts +78 -0
- package/dist/render/DataBoundSurfaceRenderer.js +998 -0
- package/dist/render/DataBoundSurfaceRenderer.js.map +1 -0
- package/dist/render/DynamicBlockWrapper.d.ts +23 -0
- package/dist/render/DynamicBlockWrapper.js +117 -0
- package/dist/render/DynamicBlockWrapper.js.map +1 -0
- package/dist/render/appearance-resolver.d.ts +50 -0
- package/dist/render/appearance-resolver.js +78 -0
- package/dist/render/appearance-resolver.js.map +1 -0
- package/dist/render/capability-gate.d.ts +69 -0
- package/dist/render/capability-gate.js +94 -0
- package/dist/render/capability-gate.js.map +1 -0
- package/dist/render/conditional-states-css.d.ts +41 -0
- package/dist/render/conditional-states-css.js +82 -0
- package/dist/render/conditional-states-css.js.map +1 -0
- package/dist/render/connections-context.d.ts +31 -0
- package/dist/render/connections-context.js +34 -0
- package/dist/render/connections-context.js.map +1 -0
- package/dist/render/dark-theme-css.d.ts +36 -0
- package/dist/render/dark-theme-css.js +67 -0
- package/dist/render/dark-theme-css.js.map +1 -0
- package/dist/render/data-binding-types.d.ts +191 -0
- package/dist/render/data-binding-types.js +11 -0
- package/dist/render/data-binding-types.js.map +1 -0
- package/dist/render/data-cache.d.ts +30 -0
- package/dist/render/data-cache.js +37 -0
- package/dist/render/data-cache.js.map +1 -0
- package/dist/render/derive-dark-theme.d.ts +17 -0
- package/dist/render/derive-dark-theme.js +18 -0
- package/dist/render/derive-dark-theme.js.map +1 -0
- package/dist/render/dynamic-artifact-context.d.ts +77 -0
- package/dist/render/dynamic-artifact-context.js +89 -0
- package/dist/render/dynamic-artifact-context.js.map +1 -0
- package/dist/render/dynamic-block-loader.d.ts +80 -0
- package/dist/render/dynamic-block-loader.js +197 -0
- package/dist/render/dynamic-block-loader.js.map +1 -0
- package/dist/render/endpoint.d.ts +18 -0
- package/dist/render/endpoint.js +109 -0
- package/dist/render/endpoint.js.map +1 -0
- package/dist/render/entity-facade-context.d.ts +34 -0
- package/dist/render/entity-facade-context.js +37 -0
- package/dist/render/entity-facade-context.js.map +1 -0
- package/dist/render/group-states-css.d.ts +41 -0
- package/dist/render/group-states-css.js +73 -0
- package/dist/render/group-states-css.js.map +1 -0
- package/dist/render/hooks/useSurfaceEvents.d.ts +8 -0
- package/dist/render/hooks/useSurfaceEvents.js +9 -0
- package/dist/render/hooks/useSurfaceEvents.js.map +1 -0
- package/dist/render/hooks/useSurfaceId.d.ts +8 -0
- package/dist/render/hooks/useSurfaceId.js +9 -0
- package/dist/render/hooks/useSurfaceId.js.map +1 -0
- package/dist/render/index.d.ts +48 -0
- package/dist/render/index.js +61 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/interaction-rule-engine.d.ts +12 -0
- package/dist/render/interaction-rule-engine.js +47 -0
- package/dist/render/interaction-rule-engine.js.map +1 -0
- package/dist/render/keyframes-css.d.ts +31 -0
- package/dist/render/keyframes-css.js +44 -0
- package/dist/render/keyframes-css.js.map +1 -0
- package/dist/render/query-state.d.ts +3 -0
- package/dist/render/query-state.js +70 -0
- package/dist/render/query-state.js.map +1 -0
- package/dist/render/renderer.d.ts +44 -0
- package/dist/render/renderer.js +937 -0
- package/dist/render/renderer.js.map +1 -0
- package/dist/render/resolve-expressions.d.ts +37 -0
- package/dist/render/resolve-expressions.js +309 -0
- package/dist/render/resolve-expressions.js.map +1 -0
- package/dist/render/responsive-style-css.d.ts +42 -0
- package/dist/render/responsive-style-css.js +123 -0
- package/dist/render/responsive-style-css.js.map +1 -0
- package/dist/render/responsive.d.ts +49 -0
- package/dist/render/responsive.js +99 -0
- package/dist/render/responsive.js.map +1 -0
- package/dist/render/scoped-css.d.ts +71 -0
- package/dist/render/scoped-css.js +102 -0
- package/dist/render/scoped-css.js.map +1 -0
- package/dist/render/shell-selection.d.ts +69 -0
- package/dist/render/shell-selection.js +117 -0
- package/dist/render/shell-selection.js.map +1 -0
- package/dist/render/states-css.d.ts +32 -0
- package/dist/render/states-css.js +63 -0
- package/dist/render/states-css.js.map +1 -0
- package/dist/render/surface-data-context.d.ts +18 -0
- package/dist/render/surface-data-context.js +21 -0
- package/dist/render/surface-data-context.js.map +1 -0
- package/dist/render/surface-event-bus.d.ts +19 -0
- package/dist/render/surface-event-bus.js +68 -0
- package/dist/render/surface-event-bus.js.map +1 -0
- package/dist/render/surface-event-context.d.ts +11 -0
- package/dist/render/surface-event-context.js +12 -0
- package/dist/render/surface-event-context.js.map +1 -0
- package/dist/render/surface-id-context.d.ts +8 -0
- package/dist/render/surface-id-context.js +9 -0
- package/dist/render/surface-id-context.js.map +1 -0
- package/dist/render/theme-utils.d.ts +14 -0
- package/dist/render/theme-utils.js +15 -0
- package/dist/render/theme-utils.js.map +1 -0
- package/dist/render/types.d.ts +282 -0
- package/dist/render/types.js +9 -0
- package/dist/render/types.js.map +1 -0
- package/dist/render/visibility-css.d.ts +42 -0
- package/dist/render/visibility-css.js +119 -0
- package/dist/render/visibility-css.js.map +1 -0
- package/dist/render/width-scope.d.ts +34 -0
- package/dist/render/width-scope.js +44 -0
- package/dist/render/width-scope.js.map +1 -0
- package/dist/render/write-only-sources.d.ts +33 -0
- package/dist/render/write-only-sources.js +99 -0
- package/dist/render/write-only-sources.js.map +1 -0
- package/dist/routing/index.d.ts +14 -0
- package/dist/routing/index.js +15 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/routing/router.d.ts +42 -0
- package/dist/routing/router.js +218 -0
- package/dist/routing/router.js.map +1 -0
- package/dist/routing/types.d.ts +124 -0
- package/dist/routing/types.js +9 -0
- package/dist/routing/types.js.map +1 -0
- package/dist/seo/generator.d.ts +39 -0
- package/dist/seo/generator.js +236 -0
- package/dist/seo/generator.js.map +1 -0
- package/dist/seo/index.d.ts +14 -0
- package/dist/seo/index.js +15 -0
- package/dist/seo/index.js.map +1 -0
- package/dist/seo/types.d.ts +181 -0
- package/dist/seo/types.js +9 -0
- package/dist/seo/types.js.map +1 -0
- package/dist/state/index.d.ts +15 -0
- package/dist/state/index.js +16 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/manager.d.ts +33 -0
- package/dist/state/manager.js +81 -0
- package/dist/state/manager.js.map +1 -0
- package/dist/state/store.d.ts +40 -0
- package/dist/state/store.js +145 -0
- package/dist/state/store.js.map +1 -0
- package/dist/state/types.d.ts +107 -0
- package/dist/state/types.js +9 -0
- package/dist/state/types.js.map +1 -0
- package/dist/surface/expression.d.ts +65 -0
- package/dist/surface/expression.js +179 -0
- package/dist/surface/expression.js.map +1 -0
- package/dist/surface/index.d.ts +32 -0
- package/dist/surface/index.js +25 -0
- package/dist/surface/index.js.map +1 -0
- package/dist/surface/interpreter.d.ts +96 -0
- package/dist/surface/interpreter.js +231 -0
- package/dist/surface/interpreter.js.map +1 -0
- package/dist/surface/layout.d.ts +54 -0
- package/dist/surface/layout.js +288 -0
- package/dist/surface/layout.js.map +1 -0
- package/dist/surface/output.d.ts +90 -0
- package/dist/surface/output.js +104 -0
- package/dist/surface/output.js.map +1 -0
- package/dist/surface/primitives.d.ts +180 -0
- package/dist/surface/primitives.js +339 -0
- package/dist/surface/primitives.js.map +1 -0
- package/dist/surface/renderer.d.ts +96 -0
- package/dist/surface/renderer.js +190 -0
- package/dist/surface/renderer.js.map +1 -0
- package/dist/surface/schemas.d.ts +181 -0
- package/dist/surface/schemas.js +142 -0
- package/dist/surface/schemas.js.map +1 -0
- package/dist/surface/transforms.d.ts +144 -0
- package/dist/surface/transforms.js +120 -0
- package/dist/surface/transforms.js.map +1 -0
- package/dist/surface/types.d.ts +160 -0
- package/dist/surface/types.js +51 -0
- package/dist/surface/types.js.map +1 -0
- package/dist/surface/validation.d.ts +123 -0
- package/dist/surface/validation.js +147 -0
- package/dist/surface/validation.js.map +1 -0
- package/dist/validator.d.ts +55 -0
- package/dist/validator.js +100 -0
- package/dist/validator.js.map +1 -0
- package/package.json +106 -3
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surface Renderer
|
|
3
|
+
*
|
|
4
|
+
* Deterministic surface rendering engine
|
|
5
|
+
*
|
|
6
|
+
* The renderer takes an interpreted surface and produces a render tree.
|
|
7
|
+
* Rendering is deterministic: same input + context = same output.
|
|
8
|
+
*
|
|
9
|
+
* INVARIANTS:
|
|
10
|
+
* - Rendering is pure (no side effects)
|
|
11
|
+
* - Same input always produces same output
|
|
12
|
+
* - Render order is deterministic
|
|
13
|
+
* - All expressions are evaluated synchronously
|
|
14
|
+
*
|
|
15
|
+
* @module @pwfabric/runtime/surface/renderer
|
|
16
|
+
*/
|
|
17
|
+
import { createRenderContext, renderSuccess, renderError, createNode } from './types.js';
|
|
18
|
+
import { resolveLayout } from './layout.js';
|
|
19
|
+
// ============================================================
|
|
20
|
+
// DETERMINISTIC RENDERER
|
|
21
|
+
// ============================================================
|
|
22
|
+
/**
|
|
23
|
+
* Deterministic surface renderer implementation
|
|
24
|
+
*
|
|
25
|
+
* This renderer guarantees:
|
|
26
|
+
* - Same input produces same output
|
|
27
|
+
* - No hidden state or side effects
|
|
28
|
+
* - Predictable ordering
|
|
29
|
+
*/
|
|
30
|
+
export class DeterministicRenderer {
|
|
31
|
+
render(surface, options = {}) {
|
|
32
|
+
const startTime = performance.now();
|
|
33
|
+
// Create render context
|
|
34
|
+
const context = createRenderContext({
|
|
35
|
+
surfaceId: surface.id,
|
|
36
|
+
bindings: surface.bindings,
|
|
37
|
+
data: options.data ?? {},
|
|
38
|
+
slots: options.slots ? new Map(Object.entries(options.slots)) : new Map(),
|
|
39
|
+
});
|
|
40
|
+
// Resolve layout to render nodes
|
|
41
|
+
const layoutResult = resolveLayout(surface.layout, context);
|
|
42
|
+
if (!layoutResult.success) {
|
|
43
|
+
return renderError({
|
|
44
|
+
type: 'layout_error',
|
|
45
|
+
message: layoutResult.error,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// Build root node
|
|
49
|
+
const root = createRootNode(surface.id, layoutResult.nodes);
|
|
50
|
+
const nodeCount = countNodes(root);
|
|
51
|
+
const renderTime = performance.now() - startTime;
|
|
52
|
+
const output = {
|
|
53
|
+
surfaceId: surface.id,
|
|
54
|
+
root,
|
|
55
|
+
metadata: {
|
|
56
|
+
renderTime,
|
|
57
|
+
nodeCount,
|
|
58
|
+
bindings: Array.from(surface.bindings.keys()),
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
return renderSuccess(output);
|
|
62
|
+
}
|
|
63
|
+
renderLayout(layout, context) {
|
|
64
|
+
return resolveLayout(layout, context);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Create a root container node
|
|
69
|
+
*/
|
|
70
|
+
function createRootNode(surfaceId, children) {
|
|
71
|
+
return createNode('fragment', {
|
|
72
|
+
'data-surface-id': surfaceId,
|
|
73
|
+
'data-surface-root': true,
|
|
74
|
+
}, children);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Count total nodes in a tree
|
|
78
|
+
*/
|
|
79
|
+
function countNodes(node) {
|
|
80
|
+
let count = 1;
|
|
81
|
+
for (const child of node.children) {
|
|
82
|
+
count += countNodes(child);
|
|
83
|
+
}
|
|
84
|
+
return count;
|
|
85
|
+
}
|
|
86
|
+
// ============================================================
|
|
87
|
+
// FACTORY
|
|
88
|
+
// ============================================================
|
|
89
|
+
/**
|
|
90
|
+
* Create a new surface renderer
|
|
91
|
+
*/
|
|
92
|
+
export function createRenderer() {
|
|
93
|
+
return new DeterministicRenderer();
|
|
94
|
+
}
|
|
95
|
+
// ============================================================
|
|
96
|
+
// RENDER HELPERS
|
|
97
|
+
// ============================================================
|
|
98
|
+
/**
|
|
99
|
+
* Render a surface to a render tree
|
|
100
|
+
*/
|
|
101
|
+
export function renderSurface(surface, options) {
|
|
102
|
+
const renderer = createRenderer();
|
|
103
|
+
return renderer.render(surface, options);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Check if a render result is successful
|
|
107
|
+
*/
|
|
108
|
+
export function isRenderSuccess(result) {
|
|
109
|
+
return result.success;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Check if a render result is a failure
|
|
113
|
+
*/
|
|
114
|
+
export function isRenderError(result) {
|
|
115
|
+
return !result.success;
|
|
116
|
+
}
|
|
117
|
+
// ============================================================
|
|
118
|
+
// SERIALIZATION
|
|
119
|
+
// ============================================================
|
|
120
|
+
/**
|
|
121
|
+
* Serialize a render node to JSON
|
|
122
|
+
*/
|
|
123
|
+
export function serializeNode(node) {
|
|
124
|
+
return {
|
|
125
|
+
type: node.type,
|
|
126
|
+
props: node.props,
|
|
127
|
+
children: node.children.map(serializeNode),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Serialize render output to JSON
|
|
132
|
+
*/
|
|
133
|
+
export function serializeOutput(output) {
|
|
134
|
+
return {
|
|
135
|
+
surfaceId: output.surfaceId,
|
|
136
|
+
root: serializeNode(output.root),
|
|
137
|
+
metadata: output.metadata,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// ============================================================
|
|
141
|
+
// HASH FOR DETERMINISM VERIFICATION
|
|
142
|
+
// ============================================================
|
|
143
|
+
/**
|
|
144
|
+
* Compute a hash of a render node for determinism verification
|
|
145
|
+
*
|
|
146
|
+
* Same input should always produce same hash
|
|
147
|
+
*/
|
|
148
|
+
export function hashNode(node) {
|
|
149
|
+
const parts = [node.type];
|
|
150
|
+
// Add sorted props
|
|
151
|
+
const propKeys = Object.keys(node.props).sort();
|
|
152
|
+
for (const key of propKeys) {
|
|
153
|
+
const value = node.props[key];
|
|
154
|
+
parts.push(`${key}=${JSON.stringify(value)}`);
|
|
155
|
+
}
|
|
156
|
+
// Add child hashes
|
|
157
|
+
for (const child of node.children) {
|
|
158
|
+
parts.push(hashNode(child));
|
|
159
|
+
}
|
|
160
|
+
return simpleHash(parts.join('|'));
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Simple string hash (djb2)
|
|
164
|
+
*/
|
|
165
|
+
function simpleHash(str) {
|
|
166
|
+
let hash = 5381;
|
|
167
|
+
for (let i = 0; i < str.length; i++) {
|
|
168
|
+
hash = (hash * 33) ^ str.charCodeAt(i);
|
|
169
|
+
}
|
|
170
|
+
return (hash >>> 0).toString(16);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Verify determinism by rendering twice and comparing hashes
|
|
174
|
+
*/
|
|
175
|
+
export function verifyDeterminism(surface, options) {
|
|
176
|
+
const renderer = createRenderer();
|
|
177
|
+
const result1 = renderer.render(surface, options);
|
|
178
|
+
const result2 = renderer.render(surface, options);
|
|
179
|
+
if (!result1.success || !result2.success) {
|
|
180
|
+
return { deterministic: false, hash1: 'error', hash2: 'error' };
|
|
181
|
+
}
|
|
182
|
+
const hash1 = hashNode(result1.output.root);
|
|
183
|
+
const hash2 = hashNode(result2.output.root);
|
|
184
|
+
return {
|
|
185
|
+
deterministic: hash1 === hash2,
|
|
186
|
+
hash1,
|
|
187
|
+
hash2,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/surface/renderer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Surface Renderer\n *\n * Deterministic surface rendering engine\n *\n * The renderer takes an interpreted surface and produces a render tree.\n * Rendering is deterministic: same input + context = same output.\n *\n * INVARIANTS:\n * - Rendering is pure (no side effects)\n * - Same input always produces same output\n * - Render order is deterministic\n * - All expressions are evaluated synchronously\n *\n * @module @pwfabric/runtime/surface/renderer\n */\n\nimport type { SurfaceId } from '@pwfabric/contracts'\nimport type {\n RenderNode,\n RenderContext,\n RenderResult,\n RenderOutput,\n RenderError,\n LayoutJSON,\n} from './types.js'\nimport { createRenderContext, renderSuccess, renderError, createNode } from './types.js'\nimport { resolveLayout, type LayoutResult } from './layout.js'\nimport type { InterpretedSurface } from './interpreter.js'\n\n// ============================================================\n// RENDERER INTERFACE\n// ============================================================\n\n/**\n * Surface renderer options\n */\nexport interface RenderOptions {\n readonly data?: Record<string, unknown>\n readonly slots?: Record<string, readonly RenderNode[]>\n readonly strict?: boolean\n}\n\n/**\n * Surface renderer\n */\nexport interface SurfaceRenderer {\n /**\n * Render an interpreted surface\n */\n render(surface: InterpretedSurface, options?: RenderOptions): RenderResult\n\n /**\n * Render a layout directly\n */\n renderLayout(layout: LayoutJSON, context: RenderContext): LayoutResult\n}\n\n// ============================================================\n// DETERMINISTIC RENDERER\n// ============================================================\n\n/**\n * Deterministic surface renderer implementation\n *\n * This renderer guarantees:\n * - Same input produces same output\n * - No hidden state or side effects\n * - Predictable ordering\n */\nexport class DeterministicRenderer implements SurfaceRenderer {\n render(surface: InterpretedSurface, options: RenderOptions = {}): RenderResult {\n const startTime = performance.now()\n\n // Create render context\n const context = createRenderContext({\n surfaceId: surface.id,\n bindings: surface.bindings,\n data: options.data ?? {},\n slots: options.slots ? new Map(Object.entries(options.slots)) : new Map(),\n })\n\n // Resolve layout to render nodes\n const layoutResult = resolveLayout(surface.layout, context)\n\n if (!layoutResult.success) {\n return renderError({\n type: 'layout_error',\n message: layoutResult.error,\n })\n }\n\n // Build root node\n const root = createRootNode(surface.id, layoutResult.nodes)\n const nodeCount = countNodes(root)\n const renderTime = performance.now() - startTime\n\n const output: RenderOutput = {\n surfaceId: surface.id,\n root,\n metadata: {\n renderTime,\n nodeCount,\n bindings: Array.from(surface.bindings.keys()),\n },\n }\n\n return renderSuccess(output)\n }\n\n renderLayout(layout: LayoutJSON, context: RenderContext): LayoutResult {\n return resolveLayout(layout, context)\n }\n}\n\n/**\n * Create a root container node\n */\nfunction createRootNode(surfaceId: SurfaceId, children: readonly RenderNode[]): RenderNode {\n return createNode(\n 'fragment',\n {\n 'data-surface-id': surfaceId,\n 'data-surface-root': true,\n },\n children\n )\n}\n\n/**\n * Count total nodes in a tree\n */\nfunction countNodes(node: RenderNode): number {\n let count = 1\n for (const child of node.children) {\n count += countNodes(child)\n }\n return count\n}\n\n// ============================================================\n// FACTORY\n// ============================================================\n\n/**\n * Create a new surface renderer\n */\nexport function createRenderer(): SurfaceRenderer {\n return new DeterministicRenderer()\n}\n\n// ============================================================\n// RENDER HELPERS\n// ============================================================\n\n/**\n * Render a surface to a render tree\n */\nexport function renderSurface(surface: InterpretedSurface, options?: RenderOptions): RenderResult {\n const renderer = createRenderer()\n return renderer.render(surface, options)\n}\n\n/**\n * Check if a render result is successful\n */\nexport function isRenderSuccess(\n result: RenderResult\n): result is { success: true; output: RenderOutput } {\n return result.success\n}\n\n/**\n * Check if a render result is a failure\n */\nexport function isRenderError(\n result: RenderResult\n): result is { success: false; error: RenderError } {\n return !result.success\n}\n\n// ============================================================\n// SERIALIZATION\n// ============================================================\n\n/**\n * Serialize a render node to JSON\n */\nexport function serializeNode(node: RenderNode): object {\n return {\n type: node.type,\n props: node.props,\n children: node.children.map(serializeNode),\n }\n}\n\n/**\n * Serialize render output to JSON\n */\nexport function serializeOutput(output: RenderOutput): object {\n return {\n surfaceId: output.surfaceId,\n root: serializeNode(output.root),\n metadata: output.metadata,\n }\n}\n\n// ============================================================\n// HASH FOR DETERMINISM VERIFICATION\n// ============================================================\n\n/**\n * Compute a hash of a render node for determinism verification\n *\n * Same input should always produce same hash\n */\nexport function hashNode(node: RenderNode): string {\n const parts: string[] = [node.type]\n\n // Add sorted props\n const propKeys = Object.keys(node.props).sort()\n for (const key of propKeys) {\n const value = node.props[key]\n parts.push(`${key}=${JSON.stringify(value)}`)\n }\n\n // Add child hashes\n for (const child of node.children) {\n parts.push(hashNode(child))\n }\n\n return simpleHash(parts.join('|'))\n}\n\n/**\n * Simple string hash (djb2)\n */\nfunction simpleHash(str: string): string {\n let hash = 5381\n for (let i = 0; i < str.length; i++) {\n hash = (hash * 33) ^ str.charCodeAt(i)\n }\n return (hash >>> 0).toString(16)\n}\n\n/**\n * Verify determinism by rendering twice and comparing hashes\n */\nexport function verifyDeterminism(\n surface: InterpretedSurface,\n options?: RenderOptions\n): { deterministic: boolean; hash1: string; hash2: string } {\n const renderer = createRenderer()\n\n const result1 = renderer.render(surface, options)\n const result2 = renderer.render(surface, options)\n\n if (!result1.success || !result2.success) {\n return { deterministic: false, hash1: 'error', hash2: 'error' }\n }\n\n const hash1 = hashNode(result1.output.root)\n const hash2 = hashNode(result2.output.root)\n\n return {\n deterministic: hash1 === hash2,\n hash1,\n hash2,\n }\n}\n"]}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surface JSON Zod Schemas
|
|
3
|
+
*
|
|
4
|
+
* Zod validation schemas for Surface JSON definitions
|
|
5
|
+
*
|
|
6
|
+
* Provides schema-based validation to replace manual string-based
|
|
7
|
+
* validation in the interpreter. Ensures SurfaceJSON, LayoutJSON,
|
|
8
|
+
* and BindingJSON conform to their TypeScript interfaces.
|
|
9
|
+
*
|
|
10
|
+
* @module @pwfabric/runtime/surface/schemas
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import type { SurfaceJSON, LayoutJSON, BindingJSON } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Valid environment types for surfaces
|
|
16
|
+
*/
|
|
17
|
+
export declare const environmentSchema: z.ZodEnum<["web", "api", "cli", "worker", "edge", "node", "native", "test"]>;
|
|
18
|
+
/**
|
|
19
|
+
* Zod schema for BindingJSON
|
|
20
|
+
*
|
|
21
|
+
* Validates capability bindings in surface definitions.
|
|
22
|
+
* - capability: required string identifying the capability
|
|
23
|
+
* - alias: optional string alias for the binding
|
|
24
|
+
* - transform: optional input/output transform configuration
|
|
25
|
+
*/
|
|
26
|
+
export declare const bindingJsonSchema: z.ZodObject<{
|
|
27
|
+
capability: z.ZodString;
|
|
28
|
+
alias: z.ZodOptional<z.ZodString>;
|
|
29
|
+
transform: z.ZodOptional<z.ZodObject<{
|
|
30
|
+
input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
31
|
+
output: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
input?: Record<string, unknown> | undefined;
|
|
34
|
+
output?: Record<string, unknown> | undefined;
|
|
35
|
+
}, {
|
|
36
|
+
input?: Record<string, unknown> | undefined;
|
|
37
|
+
output?: Record<string, unknown> | undefined;
|
|
38
|
+
}>>;
|
|
39
|
+
}, "strip", z.ZodTypeAny, {
|
|
40
|
+
capability: string;
|
|
41
|
+
alias?: string | undefined;
|
|
42
|
+
transform?: {
|
|
43
|
+
input?: Record<string, unknown> | undefined;
|
|
44
|
+
output?: Record<string, unknown> | undefined;
|
|
45
|
+
} | undefined;
|
|
46
|
+
}, {
|
|
47
|
+
capability: string;
|
|
48
|
+
alias?: string | undefined;
|
|
49
|
+
transform?: {
|
|
50
|
+
input?: Record<string, unknown> | undefined;
|
|
51
|
+
output?: Record<string, unknown> | undefined;
|
|
52
|
+
} | undefined;
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* Zod schema for LayoutJSON
|
|
56
|
+
*
|
|
57
|
+
* Uses z.lazy() for recursive children validation.
|
|
58
|
+
* - type: required string identifying the layout element type
|
|
59
|
+
* - props: optional record of properties
|
|
60
|
+
* - children: optional array of nested LayoutJSON (recursive)
|
|
61
|
+
* - slot: optional named slot reference
|
|
62
|
+
* - if: optional conditional expression
|
|
63
|
+
* - each: optional loop configuration (items, as, key)
|
|
64
|
+
*/
|
|
65
|
+
export declare const layoutJsonSchema: z.ZodType;
|
|
66
|
+
/**
|
|
67
|
+
* Zod schema for SurfaceJSON
|
|
68
|
+
*
|
|
69
|
+
* Validates the top-level surface definition structure.
|
|
70
|
+
* - id: required non-empty string
|
|
71
|
+
* - version: required non-empty string (semver)
|
|
72
|
+
* - environment: required enum of valid environment types
|
|
73
|
+
* - $schema: optional schema reference
|
|
74
|
+
* - metadata: optional name, description, tags
|
|
75
|
+
* - bindings: optional array of capability bindings
|
|
76
|
+
* - layout: required recursive layout definition
|
|
77
|
+
*/
|
|
78
|
+
export declare const surfaceJsonSchema: z.ZodObject<{
|
|
79
|
+
$schema: z.ZodOptional<z.ZodString>;
|
|
80
|
+
id: z.ZodString;
|
|
81
|
+
version: z.ZodString;
|
|
82
|
+
environment: z.ZodEnum<["web", "api", "cli", "worker", "edge", "node", "native", "test"]>;
|
|
83
|
+
metadata: z.ZodOptional<z.ZodObject<{
|
|
84
|
+
name: z.ZodOptional<z.ZodString>;
|
|
85
|
+
description: z.ZodOptional<z.ZodString>;
|
|
86
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
87
|
+
}, "strip", z.ZodTypeAny, {
|
|
88
|
+
description?: string | undefined;
|
|
89
|
+
name?: string | undefined;
|
|
90
|
+
tags?: string[] | undefined;
|
|
91
|
+
}, {
|
|
92
|
+
description?: string | undefined;
|
|
93
|
+
name?: string | undefined;
|
|
94
|
+
tags?: string[] | undefined;
|
|
95
|
+
}>>;
|
|
96
|
+
bindings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
97
|
+
capability: z.ZodString;
|
|
98
|
+
alias: z.ZodOptional<z.ZodString>;
|
|
99
|
+
transform: z.ZodOptional<z.ZodObject<{
|
|
100
|
+
input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
101
|
+
output: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
102
|
+
}, "strip", z.ZodTypeAny, {
|
|
103
|
+
input?: Record<string, unknown> | undefined;
|
|
104
|
+
output?: Record<string, unknown> | undefined;
|
|
105
|
+
}, {
|
|
106
|
+
input?: Record<string, unknown> | undefined;
|
|
107
|
+
output?: Record<string, unknown> | undefined;
|
|
108
|
+
}>>;
|
|
109
|
+
}, "strip", z.ZodTypeAny, {
|
|
110
|
+
capability: string;
|
|
111
|
+
alias?: string | undefined;
|
|
112
|
+
transform?: {
|
|
113
|
+
input?: Record<string, unknown> | undefined;
|
|
114
|
+
output?: Record<string, unknown> | undefined;
|
|
115
|
+
} | undefined;
|
|
116
|
+
}, {
|
|
117
|
+
capability: string;
|
|
118
|
+
alias?: string | undefined;
|
|
119
|
+
transform?: {
|
|
120
|
+
input?: Record<string, unknown> | undefined;
|
|
121
|
+
output?: Record<string, unknown> | undefined;
|
|
122
|
+
} | undefined;
|
|
123
|
+
}>, "many">>;
|
|
124
|
+
layout: z.ZodType<any, z.ZodTypeDef, any>;
|
|
125
|
+
}, "strip", z.ZodTypeAny, {
|
|
126
|
+
id: string;
|
|
127
|
+
version: string;
|
|
128
|
+
environment: "web" | "api" | "cli" | "worker" | "edge" | "node" | "native" | "test";
|
|
129
|
+
metadata?: {
|
|
130
|
+
description?: string | undefined;
|
|
131
|
+
name?: string | undefined;
|
|
132
|
+
tags?: string[] | undefined;
|
|
133
|
+
} | undefined;
|
|
134
|
+
$schema?: string | undefined;
|
|
135
|
+
bindings?: {
|
|
136
|
+
capability: string;
|
|
137
|
+
alias?: string | undefined;
|
|
138
|
+
transform?: {
|
|
139
|
+
input?: Record<string, unknown> | undefined;
|
|
140
|
+
output?: Record<string, unknown> | undefined;
|
|
141
|
+
} | undefined;
|
|
142
|
+
}[] | undefined;
|
|
143
|
+
layout?: any;
|
|
144
|
+
}, {
|
|
145
|
+
id: string;
|
|
146
|
+
version: string;
|
|
147
|
+
environment: "web" | "api" | "cli" | "worker" | "edge" | "node" | "native" | "test";
|
|
148
|
+
metadata?: {
|
|
149
|
+
description?: string | undefined;
|
|
150
|
+
name?: string | undefined;
|
|
151
|
+
tags?: string[] | undefined;
|
|
152
|
+
} | undefined;
|
|
153
|
+
$schema?: string | undefined;
|
|
154
|
+
bindings?: {
|
|
155
|
+
capability: string;
|
|
156
|
+
alias?: string | undefined;
|
|
157
|
+
transform?: {
|
|
158
|
+
input?: Record<string, unknown> | undefined;
|
|
159
|
+
output?: Record<string, unknown> | undefined;
|
|
160
|
+
} | undefined;
|
|
161
|
+
}[] | undefined;
|
|
162
|
+
layout?: any;
|
|
163
|
+
}>;
|
|
164
|
+
/**
|
|
165
|
+
* Type guard for SurfaceJSON
|
|
166
|
+
*
|
|
167
|
+
* Returns true if the provided data conforms to the SurfaceJSON schema.
|
|
168
|
+
*/
|
|
169
|
+
export declare function isSurfaceJSON(data: unknown): data is SurfaceJSON;
|
|
170
|
+
/**
|
|
171
|
+
* Type guard for LayoutJSON
|
|
172
|
+
*
|
|
173
|
+
* Returns true if the provided data conforms to the LayoutJSON schema.
|
|
174
|
+
*/
|
|
175
|
+
export declare function isLayoutJSON(data: unknown): data is LayoutJSON;
|
|
176
|
+
/**
|
|
177
|
+
* Type guard for BindingJSON
|
|
178
|
+
*
|
|
179
|
+
* Returns true if the provided data conforms to the BindingJSON schema.
|
|
180
|
+
*/
|
|
181
|
+
export declare function isBindingJSON(data: unknown): data is BindingJSON;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surface JSON Zod Schemas
|
|
3
|
+
*
|
|
4
|
+
* Zod validation schemas for Surface JSON definitions
|
|
5
|
+
*
|
|
6
|
+
* Provides schema-based validation to replace manual string-based
|
|
7
|
+
* validation in the interpreter. Ensures SurfaceJSON, LayoutJSON,
|
|
8
|
+
* and BindingJSON conform to their TypeScript interfaces.
|
|
9
|
+
*
|
|
10
|
+
* @module @pwfabric/runtime/surface/schemas
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
// ============================================================
|
|
14
|
+
// ENVIRONMENT SCHEMA
|
|
15
|
+
// ============================================================
|
|
16
|
+
/**
|
|
17
|
+
* Valid environment types for surfaces
|
|
18
|
+
*/
|
|
19
|
+
export const environmentSchema = z.enum([
|
|
20
|
+
'web',
|
|
21
|
+
'api',
|
|
22
|
+
'cli',
|
|
23
|
+
'worker',
|
|
24
|
+
'edge',
|
|
25
|
+
'node',
|
|
26
|
+
'native',
|
|
27
|
+
'test',
|
|
28
|
+
]);
|
|
29
|
+
// ============================================================
|
|
30
|
+
// BINDING JSON SCHEMA
|
|
31
|
+
// ============================================================
|
|
32
|
+
/**
|
|
33
|
+
* Zod schema for BindingJSON
|
|
34
|
+
*
|
|
35
|
+
* Validates capability bindings in surface definitions.
|
|
36
|
+
* - capability: required string identifying the capability
|
|
37
|
+
* - alias: optional string alias for the binding
|
|
38
|
+
* - transform: optional input/output transform configuration
|
|
39
|
+
*/
|
|
40
|
+
export const bindingJsonSchema = z.object({
|
|
41
|
+
capability: z.string().min(1, 'Binding capability must be a non-empty string'),
|
|
42
|
+
alias: z.string().optional(),
|
|
43
|
+
transform: z
|
|
44
|
+
.object({
|
|
45
|
+
input: z.record(z.unknown()).optional(),
|
|
46
|
+
output: z.record(z.unknown()).optional(),
|
|
47
|
+
})
|
|
48
|
+
.optional(),
|
|
49
|
+
});
|
|
50
|
+
// ============================================================
|
|
51
|
+
// LAYOUT JSON SCHEMA (RECURSIVE)
|
|
52
|
+
// ============================================================
|
|
53
|
+
/**
|
|
54
|
+
* Zod schema for LayoutJSON
|
|
55
|
+
*
|
|
56
|
+
* Uses z.lazy() for recursive children validation.
|
|
57
|
+
* - type: required string identifying the layout element type
|
|
58
|
+
* - props: optional record of properties
|
|
59
|
+
* - children: optional array of nested LayoutJSON (recursive)
|
|
60
|
+
* - slot: optional named slot reference
|
|
61
|
+
* - if: optional conditional expression
|
|
62
|
+
* - each: optional loop configuration (items, as, key)
|
|
63
|
+
*/
|
|
64
|
+
// Recursive schema uses z.lazy() with a forward-declared type variable.
|
|
65
|
+
// The explicit ZodType cast is required because z.lazy() needs the
|
|
66
|
+
// schema variable to exist at the point of self-reference in children.
|
|
67
|
+
export const layoutJsonSchema = z.lazy(() => z.object({
|
|
68
|
+
type: z.string().min(1, 'Layout must have a type'),
|
|
69
|
+
props: z.record(z.unknown()).optional(),
|
|
70
|
+
children: z.array(layoutJsonSchema).optional(),
|
|
71
|
+
slot: z.string().optional(),
|
|
72
|
+
if: z.string().optional(),
|
|
73
|
+
each: z
|
|
74
|
+
.object({
|
|
75
|
+
items: z.string().min(1, 'Loop layout must have items expression'),
|
|
76
|
+
as: z.string().min(1, 'Loop layout must have as variable name'),
|
|
77
|
+
key: z.string().optional(),
|
|
78
|
+
})
|
|
79
|
+
.optional(),
|
|
80
|
+
}));
|
|
81
|
+
// ============================================================
|
|
82
|
+
// SURFACE JSON SCHEMA
|
|
83
|
+
// ============================================================
|
|
84
|
+
/**
|
|
85
|
+
* Metadata schema for surface definitions
|
|
86
|
+
*/
|
|
87
|
+
const metadataSchema = z
|
|
88
|
+
.object({
|
|
89
|
+
name: z.string().optional(),
|
|
90
|
+
description: z.string().optional(),
|
|
91
|
+
tags: z.array(z.string()).optional(),
|
|
92
|
+
})
|
|
93
|
+
.optional();
|
|
94
|
+
/**
|
|
95
|
+
* Zod schema for SurfaceJSON
|
|
96
|
+
*
|
|
97
|
+
* Validates the top-level surface definition structure.
|
|
98
|
+
* - id: required non-empty string
|
|
99
|
+
* - version: required non-empty string (semver)
|
|
100
|
+
* - environment: required enum of valid environment types
|
|
101
|
+
* - $schema: optional schema reference
|
|
102
|
+
* - metadata: optional name, description, tags
|
|
103
|
+
* - bindings: optional array of capability bindings
|
|
104
|
+
* - layout: required recursive layout definition
|
|
105
|
+
*/
|
|
106
|
+
export const surfaceJsonSchema = z.object({
|
|
107
|
+
$schema: z.string().optional(),
|
|
108
|
+
id: z.string().min(1, 'Surface must have a string id'),
|
|
109
|
+
version: z.string().min(1, 'Surface must have a string version'),
|
|
110
|
+
environment: environmentSchema,
|
|
111
|
+
metadata: metadataSchema,
|
|
112
|
+
bindings: z.array(bindingJsonSchema).optional(),
|
|
113
|
+
layout: layoutJsonSchema,
|
|
114
|
+
});
|
|
115
|
+
// ============================================================
|
|
116
|
+
// TYPE GUARDS
|
|
117
|
+
// ============================================================
|
|
118
|
+
/**
|
|
119
|
+
* Type guard for SurfaceJSON
|
|
120
|
+
*
|
|
121
|
+
* Returns true if the provided data conforms to the SurfaceJSON schema.
|
|
122
|
+
*/
|
|
123
|
+
export function isSurfaceJSON(data) {
|
|
124
|
+
return surfaceJsonSchema.safeParse(data).success;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Type guard for LayoutJSON
|
|
128
|
+
*
|
|
129
|
+
* Returns true if the provided data conforms to the LayoutJSON schema.
|
|
130
|
+
*/
|
|
131
|
+
export function isLayoutJSON(data) {
|
|
132
|
+
return layoutJsonSchema.safeParse(data).success;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Type guard for BindingJSON
|
|
136
|
+
*
|
|
137
|
+
* Returns true if the provided data conforms to the BindingJSON schema.
|
|
138
|
+
*/
|
|
139
|
+
export function isBindingJSON(data) {
|
|
140
|
+
return bindingJsonSchema.safeParse(data).success;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/surface/schemas.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Surface JSON Zod Schemas\n *\n * Zod validation schemas for Surface JSON definitions\n *\n * Provides schema-based validation to replace manual string-based\n * validation in the interpreter. Ensures SurfaceJSON, LayoutJSON,\n * and BindingJSON conform to their TypeScript interfaces.\n *\n * @module @pwfabric/runtime/surface/schemas\n */\n\nimport { z } from 'zod'\nimport type { SurfaceJSON, LayoutJSON, BindingJSON } from './types.js'\n\n// ============================================================\n// ENVIRONMENT SCHEMA\n// ============================================================\n\n/**\n * Valid environment types for surfaces\n */\nexport const environmentSchema = z.enum([\n 'web',\n 'api',\n 'cli',\n 'worker',\n 'edge',\n 'node',\n 'native',\n 'test',\n])\n\n// ============================================================\n// BINDING JSON SCHEMA\n// ============================================================\n\n/**\n * Zod schema for BindingJSON\n *\n * Validates capability bindings in surface definitions.\n * - capability: required string identifying the capability\n * - alias: optional string alias for the binding\n * - transform: optional input/output transform configuration\n */\nexport const bindingJsonSchema = z.object({\n capability: z.string().min(1, 'Binding capability must be a non-empty string'),\n alias: z.string().optional(),\n transform: z\n .object({\n input: z.record(z.unknown()).optional(),\n output: z.record(z.unknown()).optional(),\n })\n .optional(),\n})\n\n// ============================================================\n// LAYOUT JSON SCHEMA (RECURSIVE)\n// ============================================================\n\n/**\n * Zod schema for LayoutJSON\n *\n * Uses z.lazy() for recursive children validation.\n * - type: required string identifying the layout element type\n * - props: optional record of properties\n * - children: optional array of nested LayoutJSON (recursive)\n * - slot: optional named slot reference\n * - if: optional conditional expression\n * - each: optional loop configuration (items, as, key)\n */\n// Recursive schema uses z.lazy() with a forward-declared type variable.\n// The explicit ZodType cast is required because z.lazy() needs the\n// schema variable to exist at the point of self-reference in children.\nexport const layoutJsonSchema: z.ZodType = z.lazy(() =>\n z.object({\n type: z.string().min(1, 'Layout must have a type'),\n props: z.record(z.unknown()).optional(),\n children: z.array(layoutJsonSchema).optional(),\n slot: z.string().optional(),\n if: z.string().optional(),\n each: z\n .object({\n items: z.string().min(1, 'Loop layout must have items expression'),\n as: z.string().min(1, 'Loop layout must have as variable name'),\n key: z.string().optional(),\n })\n .optional(),\n })\n)\n\n// ============================================================\n// SURFACE JSON SCHEMA\n// ============================================================\n\n/**\n * Metadata schema for surface definitions\n */\nconst metadataSchema = z\n .object({\n name: z.string().optional(),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n })\n .optional()\n\n/**\n * Zod schema for SurfaceJSON\n *\n * Validates the top-level surface definition structure.\n * - id: required non-empty string\n * - version: required non-empty string (semver)\n * - environment: required enum of valid environment types\n * - $schema: optional schema reference\n * - metadata: optional name, description, tags\n * - bindings: optional array of capability bindings\n * - layout: required recursive layout definition\n */\nexport const surfaceJsonSchema = z.object({\n $schema: z.string().optional(),\n id: z.string().min(1, 'Surface must have a string id'),\n version: z.string().min(1, 'Surface must have a string version'),\n environment: environmentSchema,\n metadata: metadataSchema,\n bindings: z.array(bindingJsonSchema).optional(),\n layout: layoutJsonSchema,\n})\n\n// ============================================================\n// TYPE GUARDS\n// ============================================================\n\n/**\n * Type guard for SurfaceJSON\n *\n * Returns true if the provided data conforms to the SurfaceJSON schema.\n */\nexport function isSurfaceJSON(data: unknown): data is SurfaceJSON {\n return surfaceJsonSchema.safeParse(data).success\n}\n\n/**\n * Type guard for LayoutJSON\n *\n * Returns true if the provided data conforms to the LayoutJSON schema.\n */\nexport function isLayoutJSON(data: unknown): data is LayoutJSON {\n return layoutJsonSchema.safeParse(data).success\n}\n\n/**\n * Type guard for BindingJSON\n *\n * Returns true if the provided data conforms to the BindingJSON schema.\n */\nexport function isBindingJSON(data: unknown): data is BindingJSON {\n return bindingJsonSchema.safeParse(data).success\n}\n"]}
|