view-contracts 0.5.8 → 0.5.9

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.
Files changed (76) hide show
  1. package/README.md +1 -1
  2. package/cli-contract.yaml +1 -1
  3. package/dist/types/renderers/compose/elementMap.d.ts +10 -0
  4. package/dist/types/renderers/compose/lowering/lowerToCompose.d.ts +22 -0
  5. package/dist/types/renderers/compose/lowering/modifiers.d.ts +36 -0
  6. package/dist/types/renderers/compose/renderComponents.d.ts +9 -0
  7. package/dist/types/renderers/compose/renderRuntime.d.ts +10 -0
  8. package/dist/types/renderers/compose/renderTheme.d.ts +5 -0
  9. package/dist/types/renderers/react/elementMap.d.ts +32 -0
  10. package/dist/types/renderers/react/lowering/foldStyle.d.ts +7 -0
  11. package/dist/types/renderers/react/lowering/lowerToJsx.d.ts +6 -0
  12. package/dist/types/renderers/react/paths.d.ts +1 -0
  13. package/dist/types/renderers/react/renderComponents.d.ts +26 -0
  14. package/dist/types/renderers/react/renderRuntime.d.ts +3 -0
  15. package/dist/types/renderers/react/runtime/style.d.ts +19 -0
  16. package/dist/types/renderers/react/style/foldLiterals.d.ts +3 -0
  17. package/dist/types/renderers/react/syncGeneratedRuntime.d.ts +7 -0
  18. package/dist/types/renderers/registry.d.ts +35 -0
  19. package/dist/types/renderers/swiftui/elementMap.d.ts +10 -0
  20. package/dist/types/renderers/swiftui/lowering/lowerToSwiftUI.d.ts +15 -0
  21. package/dist/types/renderers/swiftui/lowering/modifiers.d.ts +16 -0
  22. package/dist/types/renderers/swiftui/renderComponents.d.ts +9 -0
  23. package/dist/types/renderers/swiftui/renderRuntime.d.ts +10 -0
  24. package/dist/types/renderers/swiftui/renderTheme.d.ts +6 -0
  25. package/dist/types/src/cli.d.ts +2 -0
  26. package/dist/types/src/commands/index.d.ts +2 -0
  27. package/dist/types/src/compiler/compileView.d.ts +27 -0
  28. package/dist/types/src/compiler/jsxToIr.d.ts +33 -0
  29. package/dist/types/src/compiler/viewPartial.d.ts +13 -0
  30. package/dist/types/src/config.d.ts +77 -0
  31. package/dist/types/src/design/buildThemeCss.d.ts +3 -0
  32. package/dist/types/src/design/cssEmitUtils.d.ts +3 -0
  33. package/dist/types/src/design/cssPropertyMap.d.ts +2 -0
  34. package/dist/types/src/design/emitDefaultCss.d.ts +2 -0
  35. package/dist/types/src/design/emitTokenCss.d.ts +4 -0
  36. package/dist/types/src/design/emitVariantCss.d.ts +2 -0
  37. package/dist/types/src/design/index.d.ts +19 -0
  38. package/dist/types/src/design/load.d.ts +1 -0
  39. package/dist/types/src/design/parseTheme.d.ts +2 -0
  40. package/dist/types/src/design/parseTokens.d.ts +2 -0
  41. package/dist/types/src/design/themeElementProperties.d.ts +5 -0
  42. package/dist/types/src/design/types.d.ts +37 -0
  43. package/dist/types/src/design/validate.d.ts +3 -0
  44. package/dist/types/src/design/validateProjectDesign.d.ts +3 -0
  45. package/dist/types/src/design/validateVcNamespace.d.ts +4 -0
  46. package/dist/types/src/design/validateViewVariants.d.ts +3 -0
  47. package/dist/types/src/dsl/index.d.ts +2 -0
  48. package/dist/types/src/dsl/screen.d.ts +17 -0
  49. package/dist/types/src/dsl/types.d.ts +59 -0
  50. package/dist/types/src/extensions/loadExtensions.d.ts +17 -0
  51. package/dist/types/src/extensions/validateExtensionUsage.d.ts +18 -0
  52. package/dist/types/src/generated/cli/contract.d.ts +2 -0
  53. package/dist/types/src/generated/cli/program.d.ts +28 -0
  54. package/dist/types/src/ir/collectViewRefs.d.ts +3 -0
  55. package/dist/types/src/ir/types.d.ts +67 -0
  56. package/dist/types/src/lib/packageRoot.d.ts +2 -0
  57. package/dist/types/src/lib/projectPath.d.ts +2 -0
  58. package/dist/types/src/lib/rendererPaths.d.ts +13 -0
  59. package/dist/types/src/preview/compileScreen.d.ts +15 -0
  60. package/dist/types/src/preview/previewAssets.d.ts +9 -0
  61. package/dist/types/src/preview/previewMock.d.ts +16 -0
  62. package/dist/types/src/preview/previewMockPlugin.d.ts +6 -0
  63. package/dist/types/src/preview/previewServer.d.ts +7 -0
  64. package/dist/types/src/preview/publish.d.ts +5 -0
  65. package/dist/types/src/preview/vitePlugin.d.ts +13 -0
  66. package/dist/types/src/renderer/bridge.d.ts +32 -0
  67. package/dist/types/src/renderer/elementMapValidation.d.ts +6 -0
  68. package/dist/types/src/renderer/style/mergeVisualProps.d.ts +20 -0
  69. package/dist/types/src/renderer/template.d.ts +2 -0
  70. package/dist/types/src/scaffold/standalone.d.ts +2 -0
  71. package/dist/types/src/schema/dsl-catalog.d.ts +56 -0
  72. package/dist/types/src/validate/validateViewProps.d.ts +5 -0
  73. package/dist/view-contracts.bundle.mjs +3 -3
  74. package/dist/view-contracts.bundle.mjs.map +1 -1
  75. package/docs/cli-reference.md +1 -1
  76. package/package.json +17 -6
@@ -0,0 +1,3 @@
1
+ import { type ThemeIR, type TokenIR } from './types.js';
2
+ export declare function validateTheme(tokens: TokenIR, theme: ThemeIR): void;
3
+ export declare function validateDesign(tokens: TokenIR, theme: ThemeIR): void;
@@ -0,0 +1,3 @@
1
+ import type { ViewContractsConfig } from '../config.js';
2
+ /** Validate project-owned design assets that must not use the DSL .vc-* namespace. */
3
+ export declare function validateProjectDesign(config: ViewContractsConfig, configPath: string): Promise<void>;
@@ -0,0 +1,4 @@
1
+ /** Reject .vc-* selectors in project extension CSS (.vc-* is DSL compiler output only). */
2
+ export declare function validateVcNamespaceCss(css: string, sourceLabel: string): void;
3
+ /** Reject hand-written vc-* class names in extension component source. */
4
+ export declare function validateVcNamespaceSource(source: string, sourceLabel: string): void;
@@ -0,0 +1,3 @@
1
+ import type { ViewIrDocument } from '../ir/types.js';
2
+ import type { ThemeIR } from './types.js';
3
+ export declare function validateViewVariants(docs: Iterable<ViewIrDocument>, theme: ThemeIR): void;
@@ -0,0 +1,2 @@
1
+ export { screen, view } from './screen.js';
2
+ export type { ViewAction, ActionHandlers, ScreenContext, ViewContract, ViewPartial, ViewScreenProps, CommonProps, Option, Tone, Align, Justify, ButtonVariant, FieldSize, } from './types.js';
@@ -0,0 +1,17 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { FC } from 'react';
3
+ import type { ScreenContext, ViewPartial, ViewScreenProps } from './types.js';
4
+ export type { ViewAction, ActionHandlers, ScreenContext, ViewContract, ViewPartial, ViewScreenProps, CommonProps, Option, Tone, Align, Justify, ButtonVariant, FieldSize, } from './types.js';
5
+ /**
6
+ * Wrap a restricted view-contract TSX definition.
7
+ *
8
+ * - **Preview runtime**: returns a React component (`vm` + `actions` props).
9
+ * - **Compiler**: statically extracts JSX from the render callback → View IR.
10
+ */
11
+ export declare function screen<TViewModel>(render: (ctx: ScreenContext<TViewModel>) => ReactNode): FC<ViewScreenProps<TViewModel>>;
12
+ /**
13
+ * Reusable view-contract sub-component (composable inside screen() or other view()).
14
+ *
15
+ * Compiled by inlining into the parent View IR; preview runtime renders as a normal React FC.
16
+ */
17
+ export declare function view<TProps>(render: (props: TProps) => ReactNode): FC<TProps> & ViewPartial<TProps>;
@@ -0,0 +1,59 @@
1
+ import type { ReactNode } from 'react';
2
+ /** Action descriptor referenced from view contracts (names must match OpenAPI operationId). */
3
+ export interface ViewAction {
4
+ name: string;
5
+ params?: Record<string, unknown>;
6
+ }
7
+ export type ActionHandlers = Record<string, (params?: unknown) => void | Promise<void>>;
8
+ export interface ScreenContext<TViewModel> {
9
+ vm: TViewModel;
10
+ actions: ActionHandlers;
11
+ }
12
+ export interface ViewContract<TViewModel> {
13
+ readonly __viewContract: true;
14
+ readonly render: (ctx: ScreenContext<TViewModel>) => ReactNode;
15
+ }
16
+ export type Tone = 'default' | 'muted' | 'primary' | 'success' | 'warning' | 'danger';
17
+ export type Align = 'start' | 'center' | 'end' | 'stretch';
18
+ export type Justify = 'start' | 'center' | 'end' | 'between' | 'around';
19
+ export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';
20
+ export type FieldSize = 'sm' | 'md' | 'lg';
21
+ /**
22
+ * Shared layout/visual props.
23
+ * Dimension props (width, height, gap, padding, …) are numbers in logical units;
24
+ * the web preview maps them to px.
25
+ */
26
+ export interface CommonProps {
27
+ id?: string;
28
+ testId?: string;
29
+ ariaLabel?: string;
30
+ children?: ReactNode;
31
+ hidden?: boolean;
32
+ width?: number;
33
+ minWidth?: number;
34
+ maxWidth?: number;
35
+ height?: number;
36
+ minHeight?: number;
37
+ maxHeight?: number;
38
+ padding?: number;
39
+ margin?: number;
40
+ gap?: number;
41
+ radius?: number;
42
+ border?: boolean;
43
+ shadow?: boolean;
44
+ tone?: Tone;
45
+ }
46
+ export interface Option {
47
+ label: string;
48
+ value: string;
49
+ }
50
+ export interface ViewPartial<TProps> {
51
+ readonly __viewPartial: true;
52
+ readonly render: (props: TProps) => ReactNode;
53
+ }
54
+ export type ViewScreenProps<TViewModel> = {
55
+ vm: TViewModel;
56
+ actions?: ActionHandlers;
57
+ /** Optional theme id — propagated from App element for future multi-theme runtime. */
58
+ theme?: string;
59
+ };
@@ -0,0 +1,17 @@
1
+ export type ExtensionChildren = 'none' | 'any';
2
+ export type ExtensionRenderer = 'react-only' | 'all';
3
+ export type ExtensionPropertyType = 'string' | 'number' | 'boolean' | 'binding' | 'array' | 'object';
4
+ export interface ExtensionPropertyDefinition {
5
+ type: ExtensionPropertyType;
6
+ category: string;
7
+ }
8
+ export interface ExtensionDefinition {
9
+ description: string;
10
+ children: ExtensionChildren;
11
+ renderer: ExtensionRenderer;
12
+ properties: Record<string, ExtensionPropertyDefinition>;
13
+ }
14
+ export interface ExtensionRegistryDocument {
15
+ extensions: Record<string, ExtensionDefinition>;
16
+ }
17
+ export declare function loadExtensions(extensionsPath?: string): Promise<ExtensionRegistryDocument>;
@@ -0,0 +1,18 @@
1
+ import type { IrNode } from '../ir/types.js';
2
+ import type { ExtensionRegistryDocument } from './loadExtensions.js';
3
+ export interface ExtensionUsageValidationResult {
4
+ errors: string[];
5
+ warnings: string[];
6
+ }
7
+ export interface ExtensionUsageValidationOptions {
8
+ /** Binding targets from view-bindings.yaml (e.g. react, swiftui, compose). */
9
+ targets?: string[];
10
+ /** View or partial source path for error messages. */
11
+ source?: string;
12
+ }
13
+ export declare function validateExtensionUsage(node: IrNode, registry: ExtensionRegistryDocument, options?: ExtensionUsageValidationOptions): ExtensionUsageValidationResult;
14
+ /** Validate extension usage for a screen and its reachable partial IR roots. */
15
+ export declare function validateExtensionUsageForView(screen: IrNode, partialRoots: IrNode[], registry: ExtensionRegistryDocument, targets: string[], sources: {
16
+ screen: string;
17
+ partials: string[];
18
+ }): ExtensionUsageValidationResult;
@@ -0,0 +1,2 @@
1
+ export declare const CONTRACT_YAML: string;
2
+ export declare const CONTRACT_JSON_STR: string;
@@ -0,0 +1,28 @@
1
+ import { Command } from "commander";
2
+ export interface CommandHandlers {
3
+ compile: (options: {
4
+ config?: string;
5
+ }, parentOpts: Record<string, unknown>) => Promise<void>;
6
+ renderReact: (options: {
7
+ config?: string;
8
+ }, parentOpts: Record<string, unknown>) => Promise<void>;
9
+ renderBridge: (options: {
10
+ config?: string;
11
+ }, parentOpts: Record<string, unknown>) => Promise<void>;
12
+ build: (options: {
13
+ config?: string;
14
+ }, parentOpts: Record<string, unknown>) => Promise<void>;
15
+ contractsGenerate: (options: {
16
+ config?: string;
17
+ }, parentOpts: Record<string, unknown>) => Promise<void>;
18
+ contractsCheck: (options: {
19
+ config?: string;
20
+ }, parentOpts: Record<string, unknown>) => Promise<void>;
21
+ preview: (options: {
22
+ config?: string;
23
+ port?: string;
24
+ host?: string;
25
+ screen?: string;
26
+ }, parentOpts: Record<string, unknown>) => Promise<void>;
27
+ }
28
+ export declare function createProgram(handlers: CommandHandlers, version: string): Command;
@@ -0,0 +1,3 @@
1
+ import type { IrNode, IrViewRefNode } from './types.js';
2
+ export declare function collectViewRefs(node: IrNode): IrViewRefNode[];
3
+ export declare function viewRefKey(ref: IrViewRefNode): string;
@@ -0,0 +1,67 @@
1
+ /** Language-neutral View Contract intermediate representation. */
2
+ export interface ViewIrDocument {
3
+ version: 1;
4
+ /**
5
+ * Project-root-relative POSIX path of the .view.tsx this document was compiled from.
6
+ * Stamped into generated artifacts, so it must not depend on the working directory
7
+ * the compiler was invoked from.
8
+ */
9
+ source: string;
10
+ viewModel: string;
11
+ exportName: string;
12
+ root: IrNode;
13
+ /** True when this IR document represents a view() partial, not a screen(). */
14
+ isPartial?: boolean;
15
+ /** TypeScript props type for partial exports (e.g. "{ items: KpiCardViewModel[] }"). */
16
+ propsType?: string;
17
+ }
18
+ export type IrNode = IrComponentNode | IrTextNode | IrMapNode | IrFragmentNode | IrBinding | IrViewRefNode;
19
+ export interface IrComponentNode {
20
+ kind: 'component';
21
+ name: string;
22
+ props: Record<string, IrValue>;
23
+ children: IrNode[];
24
+ }
25
+ export interface IrTextNode {
26
+ kind: 'text';
27
+ value: string;
28
+ }
29
+ export interface IrFragmentNode {
30
+ kind: 'fragment';
31
+ children: IrNode[];
32
+ }
33
+ /** Reference to a view() partial — preserved instead of inlining at compile time. */
34
+ export interface IrViewRefNode {
35
+ kind: 'viewRef';
36
+ name: string;
37
+ sourcePath: string;
38
+ props: Record<string, IrValue>;
39
+ }
40
+ export interface IrMapNode {
41
+ kind: 'map';
42
+ source: IrBinding;
43
+ item: string;
44
+ key?: IrBinding;
45
+ body: IrNode;
46
+ }
47
+ export type IrValue = string | number | boolean | null | IrBinding | IrAction | IrLiteral | IrConcat | IrValue[];
48
+ export interface IrBinding {
49
+ kind: 'binding';
50
+ /** Dot path relative to vm or map item scope (e.g. "title", "projects.rows") */
51
+ path: string;
52
+ /** When inside a map callback, names the scope variable (e.g. "item", "row") */
53
+ scope?: string;
54
+ }
55
+ export interface IrAction {
56
+ kind: 'action';
57
+ name: string;
58
+ params?: Record<string, IrValue>;
59
+ }
60
+ export interface IrLiteral {
61
+ kind: 'literal';
62
+ value: unknown;
63
+ }
64
+ export interface IrConcat {
65
+ kind: 'concat';
66
+ parts: (string | IrBinding)[];
67
+ }
@@ -0,0 +1,2 @@
1
+ /** Installed package root (directory containing package.json). */
2
+ export declare function packageRoot(): string;
@@ -0,0 +1,2 @@
1
+ /** Project-relative POSIX path for generated artifacts (no absolute paths). */
2
+ export declare function relativeProjectPath(projectDir: string, absolutePath: string): string;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Sole src/ module that may import or reference renderers/.
3
+ * All other src/ code must use loadRendererRegistry() or the path helpers here.
4
+ */
5
+ export type { RenderReactOptions } from '../../renderers/react/renderComponents.js';
6
+ type RendererRegistry = typeof import('../../renderers/registry.js');
7
+ /** Lazy-load the unified renderer registry (renderers/registry.ts). */
8
+ export declare function loadRendererRegistry(): Promise<RendererRegistry>;
9
+ export declare function reactTemplatesDir(customDir?: string): string;
10
+ export declare function reactRuntimeDir(): string;
11
+ export declare function reactStructuralCssPath(): string;
12
+ export declare function reactElementsYamlPath(): string;
13
+ export declare function isReactElementsYamlFile(filePath: string): boolean;
@@ -0,0 +1,15 @@
1
+ export declare const PREVIEW_SCREEN_PREFIX = "view-contracts:screen/";
2
+ export declare const PREVIEW_THEME_ID = "view-contracts:theme.css";
3
+ export declare function previewScreenModuleId(screenName: string): string;
4
+ export declare const PREVIEW_IMPORTS: {
5
+ readonly dispatch: "view-contracts:runtime/dispatch";
6
+ readonly style: "view-contracts:runtime/style";
7
+ readonly types: "view-contracts:runtime/types";
8
+ readonly styleHelpers: "view-contracts:runtime/style-helpers";
9
+ readonly contracts: "view-contracts:contracts";
10
+ readonly extensions: "view-contracts:extensions";
11
+ readonly mock: "view-contracts:preview/mock";
12
+ };
13
+ export declare function previewMockImport(screenName: string): string;
14
+ /** Compile views/*.view.tsx → lowered React source (same pipeline as build, not written to generated/). */
15
+ export declare function compilePreviewScreen(configPath: string, screenName: string): Promise<string>;
@@ -0,0 +1,9 @@
1
+ export interface PreviewAssets {
2
+ themeCss: string;
3
+ bundleJs: string;
4
+ version: number;
5
+ }
6
+ export declare function buildPreviewAssets(configPath: string, screenName: string, version: number): Promise<PreviewAssets & {
7
+ html: string;
8
+ }>;
9
+ export declare function resolvePreviewScreenName(configPath: string, requested?: string): Promise<string>;
@@ -0,0 +1,16 @@
1
+ import type { ViewContractsConfig } from '../config.js';
2
+ export declare const PREVIEW_MOCK_PREFIX = "view-contracts:preview/mock/";
3
+ export declare class PreviewMockError extends Error {
4
+ constructor(message: string);
5
+ }
6
+ export declare function defaultPreviewMocksDir(): string;
7
+ export declare function previewMockModuleId(screenName: string): string;
8
+ export declare function previewMockExportName(screenName: string): string;
9
+ export declare function previewMockFilePath(configPath: string, config: ViewContractsConfig, screenName: string): string;
10
+ export declare function parsePreviewMockDocument(source: unknown, sourceLabel: string): Record<string, unknown>;
11
+ export declare function loadPreviewMockYaml(filePath: string): Promise<Record<string, unknown>>;
12
+ export declare function emitPreviewMockModule(screenName: string, data: Record<string, unknown>): string;
13
+ export declare function buildPreviewMockModule(configPath: string, config: ViewContractsConfig, screenName: string): Promise<string>;
14
+ export declare function isPreviewMockModuleId(id: string): string | null;
15
+ export declare function previewMocksRoot(configPath: string, config: ViewContractsConfig): Promise<string>;
16
+ export declare function pathExists(target: string): Promise<boolean>;
@@ -0,0 +1,6 @@
1
+ import type { Plugin } from 'vite';
2
+ export interface PreviewMockPluginOptions {
3
+ configPath: string;
4
+ }
5
+ /** Resolve view-contracts:preview/mock/<Screen> from views/preview/*.mock.yaml */
6
+ export declare function viewContractsPreviewMockPlugin(options: PreviewMockPluginOptions): Plugin;
@@ -0,0 +1,7 @@
1
+ export interface PreviewServerOptions {
2
+ configPath: string;
3
+ port?: number;
4
+ host?: string;
5
+ screen?: string;
6
+ }
7
+ export declare function runPreviewServer(options: PreviewServerOptions): Promise<void>;
@@ -0,0 +1,5 @@
1
+ /** Public npm entry — Vite preview plugins for consumer projects. */
2
+ export { viewContractsPreviewPlugin, previewRuntimeAliases, previewFsAllowPaths, } from './vitePlugin.js';
3
+ export type { ViewContractsPreviewPluginOptions } from './vitePlugin.js';
4
+ export { viewContractsPreviewMockPlugin } from './previewMockPlugin.js';
5
+ export type { PreviewMockPluginOptions } from './previewMockPlugin.js';
@@ -0,0 +1,13 @@
1
+ import type { Plugin } from 'vite';
2
+ export { viewContractsPreviewMockPlugin } from './previewMockPlugin.js';
3
+ export interface ViewContractsPreviewPluginOptions {
4
+ configPath: string;
5
+ }
6
+ export declare function viewContractsPreviewPlugin(options: ViewContractsPreviewPluginOptions): Plugin;
7
+ /** Vite resolve.alias entries for preview dev (uses installed view-contracts package root). */
8
+ export declare function previewRuntimeAliases(projectRootDir: string): Array<{
9
+ find: string | RegExp;
10
+ replacement: string;
11
+ }>;
12
+ /** Paths for vite server.fs.allow — project + installed view-contracts package. */
13
+ export declare function previewFsAllowPaths(viteDir: string, projectRootDir: string): string[];
@@ -0,0 +1,32 @@
1
+ import type { ViewIrDocument } from '../ir/types.js';
2
+ import type { ViewContractsConfig } from '../config.js';
3
+ import { type RenderReactOptions } from '../lib/rendererPaths.js';
4
+ export type { RenderReactOptions };
5
+ export declare function renderReactFromIr(doc: ViewIrDocument, outputPath: string, options: RenderReactOptions): Promise<void>;
6
+ export declare function renderReactPreviewBundle(screen: ViewIrDocument, partials: ViewIrDocument[], options: RenderReactOptions): Promise<string>;
7
+ export declare function partialReactOutputPath(reactDir: string, partial: ViewIrDocument): string;
8
+ export declare function renderReactRuntime(configPath: string, config: ViewContractsConfig): Promise<void>;
9
+ export declare function renderSwiftUIRuntime(configPath: string, config: ViewContractsConfig, bindings: import('../config.js').ViewBindingsFile, design?: {
10
+ theme: import('../design/types.js').ThemeIR;
11
+ tokens: import('../design/types.js').TokenIR;
12
+ }, compiledDocs?: {
13
+ screens: Map<string, ViewIrDocument>;
14
+ partials: ViewIrDocument[];
15
+ }): Promise<void>;
16
+ export declare function renderSwiftComponent(doc: ViewIrDocument, options: {
17
+ theme: import('../design/types.js').ThemeIR;
18
+ tokens: import('../design/types.js').TokenIR;
19
+ allowlistExtra?: string[];
20
+ }): Promise<string>;
21
+ export declare function renderComposeComponent(doc: ViewIrDocument, options: {
22
+ theme: import('../design/types.js').ThemeIR;
23
+ tokens: import('../design/types.js').TokenIR;
24
+ allowlistExtra?: string[];
25
+ }): Promise<string>;
26
+ export declare function renderComposeRuntime(configPath: string, config: ViewContractsConfig, bindings: import('../config.js').ViewBindingsFile, design?: {
27
+ theme: import('../design/types.js').ThemeIR;
28
+ tokens: import('../design/types.js').TokenIR;
29
+ }, compiledDocs?: {
30
+ screens: Map<string, ViewIrDocument>;
31
+ partials: ViewIrDocument[];
32
+ }): Promise<void>;
@@ -0,0 +1,6 @@
1
+ /** Load a YAML file into a typed object (target-agnostic). */
2
+ export declare function loadYamlFile<T>(path: string): Promise<T>;
3
+ /** Ensure element names exist in the DSL vocabulary allowlist. */
4
+ export declare function validateVocabularyElementNames(elementNames: Iterable<string>, allowed: ReadonlySet<string>, sourceLabel: string): void;
5
+ /** Ensure each map entry has required fields (e.g. HTML tag for lowering). */
6
+ export declare function validateMapEntryFields<T extends object>(entries: Record<string, T>, requiredKeys: (keyof T)[], sourceLabel: string): void;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Renderer-agnostic compile-time visual property merge.
3
+ * Precedence: instance > variant > themeDefault (right wins — no modifier accumulation).
4
+ */
5
+ import type { ThemeIR, TokenIR } from '../../design/types.js';
6
+ export type VisualPropSet = Record<string, string | number | boolean>;
7
+ export interface MergeVisualPropsInput {
8
+ elementName: string;
9
+ theme: ThemeIR;
10
+ tokens: TokenIR;
11
+ /** Compile-time literal variant name from View IR, if any. */
12
+ variantLiteral?: string;
13
+ /** Compile-time literal visual props from the View IR node (DSL prop names). */
14
+ instanceLiterals: Record<string, unknown>;
15
+ }
16
+ /**
17
+ * Merge theme default, variant, and instance visual props for one vocabulary element.
18
+ * Later layers override earlier ones for the same property key (override, not accumulate).
19
+ */
20
+ export declare function mergeVisualProps(input: MergeVisualPropsInput): VisualPropSet;
@@ -0,0 +1,2 @@
1
+ /** Render a Handlebars template from a target-specific templates directory. */
2
+ export declare function renderTemplate(templatesDir: string, templateName: string, data: Record<string, unknown>): Promise<string>;
@@ -0,0 +1,2 @@
1
+ import type { ViewBindingsFile } from '../config.js';
2
+ export declare function scaffoldStandaloneApp(configPath: string, bindings: ViewBindingsFile): Promise<void>;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * DSL Vocabulary Catalog — Single Source of Truth.
3
+ *
4
+ * All vocabulary metadata lives here. Program code imports directly.
5
+ * The schema generator reads this to produce spec/ui-dsl.schema.json (user-facing).
6
+ */
7
+ export type LoweringMode = "inline-css" | "class-name" | "attribute" | "none";
8
+ export interface PropertyDef {
9
+ readonly type: string | readonly string[];
10
+ readonly category: string;
11
+ readonly lowering: LoweringMode;
12
+ readonly enum?: string;
13
+ readonly description?: string;
14
+ readonly notes?: string;
15
+ }
16
+ export interface ElementDef {
17
+ readonly description: string;
18
+ readonly tier: "core" | "optional" | "extension";
19
+ readonly category: string;
20
+ readonly notes?: string;
21
+ /** Accepted property names — sole authority for property-element binding. */
22
+ readonly properties: readonly string[];
23
+ readonly children: {
24
+ readonly kind: "any" | "none" | "single" | "text" | "list";
25
+ readonly items?: readonly string[];
26
+ };
27
+ }
28
+ export declare const TOKEN_CATALOG: {
29
+ readonly role: readonly ["button", "link", "heading", "list", "listitem", "main", "dialog", "status"];
30
+ readonly widthSize: readonly ["wrap", "fill"];
31
+ readonly heightSize: readonly ["wrap", "fill"];
32
+ readonly align: readonly ["start", "center", "end", "stretch"];
33
+ readonly justify: readonly ["start", "center", "end", "spaceBetween", "spaceAround", "spaceEvenly"];
34
+ readonly contentAlign: readonly ["topStart", "top", "topEnd", "start", "center", "end", "bottomStart", "bottom", "bottomEnd"];
35
+ readonly axis: readonly ["vertical", "horizontal"];
36
+ readonly direction: readonly ["ltr", "rtl", "system"];
37
+ readonly scroll: readonly ["none", "vertical", "horizontal", "both"];
38
+ readonly border: readonly ["none"];
39
+ readonly shadow: readonly ["none", "sm", "md", "lg"];
40
+ readonly textAlign: readonly ["start", "center", "end"];
41
+ readonly lineLimit: readonly ["none"];
42
+ readonly textOverflow: readonly ["clip", "ellipsis"];
43
+ readonly fontWeight: readonly ["regular", "medium", "bold"];
44
+ readonly imageFit: readonly ["contain", "cover", "fill", "none"];
45
+ readonly keyboardType: readonly ["text", "number", "email", "url", "password", "tel"];
46
+ readonly inputType: readonly ["text", "password", "email", "url", "tel"];
47
+ readonly clip: readonly ["none", "bounds", "shape"];
48
+ };
49
+ export declare const PROPERTY_CATALOG: Record<string, PropertyDef>;
50
+ export declare const ELEMENT_CATALOG: Record<string, ElementDef>;
51
+ export declare const ALLOWED_COMPONENTS: Set<string>;
52
+ export declare const LOWERING_STYLE_PROPERTIES: Set<string>;
53
+ export declare const CLASS_NAME_PROPERTIES: Set<string>;
54
+ export declare function elementProps(elementName: string): readonly string[];
55
+ /** Check if an element accepts a property. Element.properties is the sole authority. */
56
+ export declare function propertyAppliesTo(propName: string, elementName: string): boolean;
@@ -0,0 +1,5 @@
1
+ import type { ViewIrDocument } from '../ir/types.js';
2
+ import { type PropertyDef } from '../schema/dsl-catalog.js';
3
+ export declare function validateViewProps(docs: Iterable<ViewIrDocument>, allowlistExtra?: string[]): Promise<void>;
4
+ /** @internal Exported for tests. */
5
+ export declare function isVisualProperty(def: PropertyDef | undefined): boolean;
@@ -424,7 +424,7 @@ cli_contracts: 0.1.0
424
424
 
425
425
  info:
426
426
  title: view-contracts CLI
427
- version: 0.5.8
427
+ version: 0.5.9
428
428
  description: >-
429
429
  Contract-first UI design toolchain. Compiles restricted view-contract TSX
430
430
  to language-neutral View IR and renders platform targets (React, SwiftUI, Compose).
@@ -627,7 +627,7 @@ command_sets:
627
627
  "cli_contracts": "0.1.0",
628
628
  "info": {
629
629
  "title": "view-contracts CLI",
630
- "version": "0.5.8",
630
+ "version": "0.5.9",
631
631
  "description": "Contract-first UI design toolchain. Compiles restricted view-contract TSX to language-neutral View IR and renders platform targets (React, SwiftUI, Compose)."
632
632
  },
633
633
  "artifact_slots": {
@@ -1084,5 +1084,5 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
1084
1084
  `,s=wa(t,"entry.tsx");return await ud(s,o,"utf8"),s}async function pd(t,e,n){let r=await Ke(t),o=(await Et(r.bindings)).views.find(R=>R.screenName===e);if(!o)throw new Error(`No view binding for screen "${e}"`);if(!o.targets.includes("react"))throw new Error(`Screen "${e}" is not a react target`);let s=we(t),[a,l,c]=await Promise.all([Kb(t,e),Jv(t,r,e),qi(r,t)]),d=VT(o.exportName),p=Xp(e),f=wa(NT(),`view-contracts-preview-${process.pid}`);await OT(f,{recursive:!0});let m=await DT(f,a,l,d,p),g=Re(),y=[en(s,"node_modules"),en(g,"node_modules")],w=await MT({entryPoints:[m],bundle:!0,write:!1,format:"esm",platform:"browser",target:"es2022",jsx:"automatic",jsxImportSource:"react",absWorkingDir:s,nodePaths:y,alias:LT(s),logLevel:"silent"});if(w.errors.length>0)throw new Error(w.errors.map(R=>R.text).join(`
1085
1085
  `));let _=w.outputFiles[0]?.text??"";return{html:jT(),themeCss:c,bundleJs:_,version:n}}async function Yb(t,e){let n=await Et((await Ke(t)).bindings);if(e){let i=n.views.find(o=>o.screenName===e);if(!i)throw new Error(`Unknown screen "${e}" in view-bindings.yaml`);if(!i.targets.includes("react"))throw new Error(`Screen "${e}" is not a react target`);return e}let r=n.views.find(i=>i.targets.includes("react"));if(!r)throw new Error("No react target views in view-bindings.yaml");return r.screenName}jr();function lo(t,e,n,r){t.writeHead(e,{"Content-Type":r,"Cache-Control":"no-store"}),t.end(n)}function BT(t,e,n){let r=t.url?.split("?")[0]??"/";if(r==="/"||r==="/index.html"){lo(e,200,n.html,"text/html; charset=utf-8");return}if(r==="/bundle.js"){lo(e,200,n.bundleJs,"text/javascript; charset=utf-8");return}if(r==="/theme.css"){lo(e,200,n.themeCss,"text/css; charset=utf-8");return}if(r==="/__vc-reload"){lo(e,200,JSON.stringify({version:n.version}),"application/json");return}lo(e,404,"Not found","text/plain; charset=utf-8")}async function HT(t,e,n){let r=await Ke(t),i=we(t),{tokensPath:o,themePath:s}=on(r),a=await Kv(t,r),l=Fb(),c=[Un(i,r.viewsDir),Un(i,o),Un(i,s),a,l];r.extensions&&c.push(Un(i,r.extensions)),r.design?.extensionsCss&&c.push(Un(i,r.design.extensionsCss)),c.push(Un(i,"contracts/view-models.ts")),c.push(Un(i,"src/components/extensions.tsx"));let d,p=()=>{d&&clearTimeout(d),d=setTimeout(()=>n(),150)},f=[];for(let g of c)await Lr(g)&&f.push(g);let m=f.map(g=>FT(g,{recursive:!0},()=>p()));return()=>{d&&clearTimeout(d);for(let g of m)g.close()}}async function Xb(t){let e=t.port??5173,n=t.host??"127.0.0.1",r=await Yb(t.configPath,t.screen),i=0,o=await pd(t.configPath,r,i),s=!1,a=!1,l=async()=>{if(s){a=!0;return}s=!0;try{i+=1,o=await pd(t.configPath,r,i),console.log(`[preview] rebuilt (v${i})`)}catch(f){let m=f instanceof Error?f.message:String(f);console.error(`[preview] compile error:
1086
1086
  ${m}`)}finally{s=!1,a&&(a=!1,l())}},c=qT((f,m)=>BT(f,m,o));await new Promise((f,m)=>{c.once("error",m),c.listen(e,n,()=>f())});let d=`http://${n}:${e}/`;console.log(`[preview] ${r} \u2192 ${d}`),console.log("[preview] watching views/ and design files (Ctrl+C to stop)");let p=await HT(t.configPath,r,()=>{l()});await new Promise(f=>{let m=()=>{p(),c.close(()=>f())};process.once("SIGINT",m),process.once("SIGTERM",m)})}async function fd(t){if(!t.extensions)return{allowlistExtra:t.allowlistExtra??[]};let e=await ls(t.extensions),n=[...new Set([...t.allowlistExtra??[],...Object.keys(e.extensions)])];return{extensionRegistry:e,allowlistExtra:n}}async function Qb(t){await new Promise((e,n)=>{let r=GT("npx",["micro-contracts",...t],{stdio:"inherit"});r.on("error",n),r.on("close",i=>{i===0?e():n(new Error(`micro-contracts exited with code ${i}`))})})}async function dd(t){let e=await Ke(t),n=await Et(e.bindings),{extensionRegistry:r,allowlistExtra:i}=await fd(e),o=we(t),{screens:s,partials:a}=await Gd(n.views.map(l=>({sourcePath:Mt(o,l.source),exportName:l.exportName,screenName:l.screenName,targets:l.targets})),{projectRoot:o,allowlistExtra:i,extensionRegistry:r});return{screens:new Map(n.views.map((l,c)=>[l.screenName,s[c]])),partials:a}}function zn(t,e){let n=zT(t_(t),e).replace(/\\/g,"/");return n.startsWith(".")||(n=`./${n}`),n.replace(/\.tsx?$/,".js")}async function Zb(t,e,n){let r=await Ke(t),i=we(t),{allowlistExtra:o}=await fd(r),s=await Et(r.bindings);for(let a of n){let l=Mt(r.generated.reactDir,"components",`${a.exportName}.generated.tsx`),c=zn(l,Mt(r.generated.reactDir,"runtime.ts")),d=zn(l,Mt(r.generated.reactDir,"extensions.generated.ts")),p=zn(l,Mt(i,"contracts/view-models.ts"));await cd(a,l,{runtimeImportFrom:c,extensionsImportFrom:d,contractsImportFrom:p,allowlistExtra:o}),console.log(` ${a.exportName} \u2192 ${l}`)}for(let a of s.views){if(!a.targets.includes("react"))continue;let l=e.get(a.screenName);if(!l)throw new Error(`Missing View IR for ${a.screenName}`);let c=Df(r,a),d=zn(c,Mt(r.generated.reactDir,"runtime.ts")),p=zn(c,Mt(r.generated.reactDir,"extensions.generated.ts")),f=zn(c,Mt(i,"contracts/view-models.ts")),m=new Map;for(let g of n){let y=Hb(r.generated.reactDir,g);m.set(g.exportName,zn(c,y))}await cd(l,c,{runtimeImportFrom:d,extensionsImportFrom:p,contractsImportFrom:f,allowlistExtra:o,viewRefImportFrom:m}),console.log(` ${a.exportName} \u2192 ${c}`)}}async function e_(t){let e=await Ke(t),n=await Et(e.bindings),r=we(t),o=["// Auto-generated view bridge registry \u2014 DO NOT EDIT",`// Generated from ${Zr(r,e.bindings)}`,"","export const viewBridgeRegistry = {"];for(let s of n.views)o.push(` ${s.screenConst}: {`),o.push(` id: ${JSON.stringify(s.id)},`),o.push(` screenId: ${JSON.stringify(s.screenId)},`),o.push(` screenName: ${JSON.stringify(s.screenName)},`),o.push(` route: ${JSON.stringify(s.route)},`),o.push(` operationId: ${JSON.stringify(s.operationId)},`),o.push(` viewModel: ${JSON.stringify(s.viewModel)},`),o.push(` source: ${JSON.stringify(s.source)},`),o.push(` targets: ${JSON.stringify(s.targets)},`),o.push(" },");o.push("} as const;",""),o.push("export type ViewBridgeKey = keyof typeof viewBridgeRegistry;",""),await UT(t_(Mt(e.generated.bridge)),{recursive:!0}),await WT(Mt(e.generated.bridge),o.join(`
1087
- `),"utf-8"),console.log(`Bridge registry \u2192 ${e.generated.bridge} (${n.views.length} view(s))`)}var n_={compile:async(t,e)=>{let{screens:n,partials:r}=await dd(await rn(t.config));console.log(`Compiled ${n.size} screen(s) and ${r.length} partial(s) to View IR (in-memory)`)},renderReact:async(t,e)=>{let n=await rn(t.config),{screens:r,partials:i}=await dd(n);await Zb(n,r,i)},renderBridge:async(t,e)=>{await e_(await rn(t.config))},build:async(t,e)=>{let n=await rn(t.config),r=await Ke(n),i=await Et(r.bindings),{screens:o,partials:s}=await dd(n);console.log(`Compiled ${o.size} screen(s) and ${s.length} partial(s) to View IR (in-memory)`);let{tokensPath:a,themePath:l}=on(r),{tokenIR:c,themeIR:d}=await xr(a,l);await Vn(r,n);let{allowlistExtra:p}=await fd(r),f=[...o.values(),...s];await ma(f,p),Di(f,d),await Wb(n,r),await Zb(n,o,s),await e_(n),await Ub(n,r,i,{theme:d,tokens:c},{screens:o,partials:s}),await zb(n,r,i,{theme:d,tokens:c},{screens:o,partials:s}),await Jb(n,i)},contractsGenerate:async(t,e)=>{let n=await Ke(await rn(t.config));await Qb(["generate","-c",n.microContractsConfig]),console.log("Contracts generated via micro-contracts")},contractsCheck:async(t,e)=>{let n=await Ke(await rn(t.config));await Qb(["lint","-c",n.microContractsConfig])},preview:async(t,e)=>{try{await Xb({configPath:await rn(t.config),port:t.port!=null?Number(t.port):void 0,host:t.host,screen:t.screen})}catch(n){console.error(n instanceof Error?n.message:n),process.exit(1)}}};var JT={version:"0.5.8"};Td(n_,JT.version).parseAsync(process.argv).catch(t=>{console.error(t instanceof Error?t.message:t),process.exit(1)});
1087
+ `),"utf-8"),console.log(`Bridge registry \u2192 ${e.generated.bridge} (${n.views.length} view(s))`)}var n_={compile:async(t,e)=>{let{screens:n,partials:r}=await dd(await rn(t.config));console.log(`Compiled ${n.size} screen(s) and ${r.length} partial(s) to View IR (in-memory)`)},renderReact:async(t,e)=>{let n=await rn(t.config),{screens:r,partials:i}=await dd(n);await Zb(n,r,i)},renderBridge:async(t,e)=>{await e_(await rn(t.config))},build:async(t,e)=>{let n=await rn(t.config),r=await Ke(n),i=await Et(r.bindings),{screens:o,partials:s}=await dd(n);console.log(`Compiled ${o.size} screen(s) and ${s.length} partial(s) to View IR (in-memory)`);let{tokensPath:a,themePath:l}=on(r),{tokenIR:c,themeIR:d}=await xr(a,l);await Vn(r,n);let{allowlistExtra:p}=await fd(r),f=[...o.values(),...s];await ma(f,p),Di(f,d),await Wb(n,r),await Zb(n,o,s),await e_(n),await Ub(n,r,i,{theme:d,tokens:c},{screens:o,partials:s}),await zb(n,r,i,{theme:d,tokens:c},{screens:o,partials:s}),await Jb(n,i)},contractsGenerate:async(t,e)=>{let n=await Ke(await rn(t.config));await Qb(["generate","-c",n.microContractsConfig]),console.log("Contracts generated via micro-contracts")},contractsCheck:async(t,e)=>{let n=await Ke(await rn(t.config));await Qb(["lint","-c",n.microContractsConfig])},preview:async(t,e)=>{try{await Xb({configPath:await rn(t.config),port:t.port!=null?Number(t.port):void 0,host:t.host,screen:t.screen})}catch(n){console.error(n instanceof Error?n.message:n),process.exit(1)}}};var JT={version:"0.5.9"};Td(n_,JT.version).parseAsync(process.argv).catch(t=>{console.error(t instanceof Error?t.message:t),process.exit(1)});
1088
1088
  //# sourceMappingURL=view-contracts.bundle.mjs.map