view-contracts 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,239 @@
1
+ # view-contracts CLI
2
+
3
+ Contract-first UI design toolchain. Compiles restricted view-contract TSX to language-neutral View IR and renders platform targets (React, SwiftUI, Compose).
4
+
5
+ **Version:** 0.1.0
6
+
7
+ ## Table of Contents
8
+
9
+ - [view-contracts](#view-contracts)
10
+ - [compile](#view-contracts-compile)
11
+ - [render.react](#view-contracts-render-react)
12
+ - [render.bridge](#view-contracts-render-bridge)
13
+ - [build](#view-contracts-build)
14
+ - [contracts.generate](#view-contracts-contracts-generate)
15
+ - [contracts.check](#view-contracts-contracts-check)
16
+ - [catalog.build](#view-contracts-catalog-build)
17
+
18
+ ---
19
+
20
+ ## view-contracts
21
+
22
+ View contract compiler and renderer toolchain.
23
+
24
+ ### Global Options
25
+
26
+ | Option | Aliases | Required | Default | Description |
27
+ |---|---|---|---|---|
28
+ | `--help` | -h | No | | Show help and exit. |
29
+ | `--version` | -V | No | | Print version and exit. |
30
+
31
+ ### compile
32
+
33
+ Compile .view.tsx files to View IR.
34
+
35
+ Parses restricted view-contract TSX via the TypeScript AST, validates allowed components and expressions, and holds View IR in memory.
36
+
37
+ **Usage:**
38
+
39
+ ```
40
+ view-contracts compile
41
+ ```
42
+ ```
43
+ view-contracts compile -c view-contracts.config.yaml
44
+ ```
45
+
46
+ #### Options
47
+
48
+ | Option | Aliases | Required | Default | Description |
49
+ |---|---|---|---|---|
50
+ | `--config` | -c | No | | Path to view-contracts.config.yaml (discovered upward from cwd when omitted). |
51
+
52
+ #### Exit Codes
53
+
54
+ **Exit 0:** Compilation succeeded.
55
+
56
+ **Exit 1:** Compilation failed.
57
+
58
+ ---
59
+
60
+ ### render.react
61
+
62
+ Generate React components from View IR.
63
+
64
+ Compiles views in memory and emits production React to generated/react/.
65
+
66
+ **Usage:**
67
+
68
+ ```
69
+ view-contracts render react
70
+ ```
71
+ ```
72
+ view-contracts render react -c view-contracts.config.yaml
73
+ ```
74
+
75
+ #### Options
76
+
77
+ | Option | Aliases | Required | Default | Description |
78
+ |---|---|---|---|---|
79
+ | `--config` | -c | No | | Path to view-contracts.config.yaml (discovered upward from cwd when omitted). |
80
+
81
+ #### Exit Codes
82
+
83
+ **Exit 0:** Render succeeded.
84
+
85
+ **Exit 1:** Render failed.
86
+
87
+ ---
88
+
89
+ ### render.bridge
90
+
91
+ Generate view ↔ ViewModel bridge registry.
92
+
93
+ Emits src/generated/view-bridge.generated.ts from view-bindings.yaml.
94
+
95
+ **Usage:**
96
+
97
+ ```
98
+ view-contracts render bridge
99
+ ```
100
+ ```
101
+ view-contracts render bridge -c view-contracts.config.yaml
102
+ ```
103
+
104
+ #### Options
105
+
106
+ | Option | Aliases | Required | Default | Description |
107
+ |---|---|---|---|---|
108
+ | `--config` | -c | No | | Path to view-contracts.config.yaml (discovered upward from cwd when omitted). |
109
+
110
+ #### Exit Codes
111
+
112
+ **Exit 0:** Bridge registry generated.
113
+
114
+ **Exit 1:** Generation failed.
115
+
116
+ ---
117
+
118
+ ### build
119
+
120
+ Full view pipeline (compile + render runtime + render react + bridge).
121
+
122
+ Compiles views in memory, copies React runtime to generated/, emits React components and bridge registry, and scaffolds .vite/ dev files.
123
+
124
+ **Usage:**
125
+
126
+ ```
127
+ view-contracts build
128
+ ```
129
+ ```
130
+ view-contracts build -c view-contracts.config.yaml
131
+ ```
132
+
133
+ #### Options
134
+
135
+ | Option | Aliases | Required | Default | Description |
136
+ |---|---|---|---|---|
137
+ | `--config` | -c | No | | Path to view-contracts.config.yaml (discovered upward from cwd when omitted). |
138
+
139
+ #### Exit Codes
140
+
141
+ **Exit 0:** Build succeeded.
142
+
143
+ **Exit 1:** Build failed.
144
+
145
+ ---
146
+
147
+ ### contracts.generate
148
+
149
+ Generate ViewModel types from OpenAPI via micro-contracts.
150
+
151
+ Delegates to micro-contracts generate using micro-contracts.config.yaml.
152
+
153
+ **Usage:**
154
+
155
+ ```
156
+ view-contracts contracts generate
157
+ ```
158
+ ```
159
+ view-contracts contracts generate -c view-contracts.config.yaml
160
+ ```
161
+
162
+ #### Options
163
+
164
+ | Option | Aliases | Required | Default | Description |
165
+ |---|---|---|---|---|
166
+ | `--config` | -c | No | | Path to view-contracts.config.yaml (discovered upward from cwd when omitted). |
167
+
168
+ #### Exit Codes
169
+
170
+ **Exit 0:** Generation succeeded.
171
+
172
+ **Exit 1:** Generation failed.
173
+
174
+ ---
175
+
176
+ ### contracts.check
177
+
178
+ Lint OpenAPI screen contracts via micro-contracts.
179
+
180
+ Delegates to micro-contracts lint.
181
+
182
+ **Usage:**
183
+
184
+ ```
185
+ view-contracts contracts check
186
+ ```
187
+ ```
188
+ view-contracts contracts check -c view-contracts.config.yaml
189
+ ```
190
+
191
+ #### Options
192
+
193
+ | Option | Aliases | Required | Default | Description |
194
+ |---|---|---|---|---|
195
+ | `--config` | -c | No | | Path to view-contracts.config.yaml (discovered upward from cwd when omitted). |
196
+
197
+ #### Exit Codes
198
+
199
+ **Exit 0:** Lint passed.
200
+
201
+ **Exit 1:** Lint failed.
202
+
203
+ ---
204
+
205
+ ### catalog.build
206
+
207
+ Build static catalog HTML for design review.
208
+
209
+ Renders all registered views with mock ViewModels into a single HTML file for design review, screenshot baselines, and accessibility checks.
210
+
211
+ **Usage:**
212
+
213
+ ```
214
+ view-contracts catalog build
215
+ ```
216
+ ```
217
+ view-contracts catalog build -c view-contracts.config.yaml
218
+ ```
219
+ ```
220
+ view-contracts catalog build -o dist/catalog.html
221
+ ```
222
+
223
+ #### Options
224
+
225
+ | Option | Aliases | Required | Default | Description |
226
+ |---|---|---|---|---|
227
+ | `--config` | -c | No | | Path to view-contracts.config.yaml (discovered upward from cwd when omitted). |
228
+ | `--output` | -o | No | | Output HTML path (defaults to dist/catalog.html next to bindings). |
229
+
230
+ #### Exit Codes
231
+
232
+ **Exit 0:** Catalog built.
233
+
234
+ - **Generated files:**
235
+ - `dist/catalog.html` (text/html) *(optional)*
236
+
237
+ **Exit 1:** Build failed.
238
+
239
+ ---
package/package.json ADDED
@@ -0,0 +1,94 @@
1
+ {
2
+ "name": "view-contracts",
3
+ "version": "0.1.0",
4
+ "description": "Contract-first UI design toolchain — restricted TSX to View IR to platform renderers",
5
+ "type": "module",
6
+ "workspaces": [
7
+ "packages/*"
8
+ ],
9
+ "bin": {
10
+ "view-contracts": "dist/view-contracts.bundle.mjs"
11
+ },
12
+ "files": [
13
+ "dist/view-contracts.bundle.mjs",
14
+ "dist/view-contracts.bundle.mjs.map",
15
+ "src/renderer/react/runtime",
16
+ "src/generated/schema",
17
+ "spec",
18
+ "renderers",
19
+ "cli-contract.yaml",
20
+ "docs/cli-reference.md",
21
+ "README.md",
22
+ "LICENSE"
23
+ ],
24
+ "scripts": {
25
+ "generate": "cli-contracts generate",
26
+ "dev": "npm run build:views && npm run dev:both --prefix examples/admin-dashboard",
27
+ "dev:preview": "npm run dev:preview --prefix examples/admin-dashboard",
28
+ "dev:app": "npm run dev:app --prefix examples/admin-dashboard",
29
+ "dev:both": "npm run build:views && npm run dev:both --prefix examples/admin-dashboard",
30
+ "check:both": "npm run check:both --prefix examples/admin-dashboard",
31
+ "serve:built": "npm run serve:built --prefix examples/admin-dashboard",
32
+ "build": "npm run build:cli && npm run build:views && tsc -b",
33
+ "build:cli": "npm run generate && tsc -p tsconfig.cli.json",
34
+ "build:publish": "npm run build:cli && npm run bundle:min",
35
+ "bundle": "node esbuild.bundle.mjs",
36
+ "bundle:min": "node esbuild.bundle.mjs --minify",
37
+ "build:views": "tsx src/cli.ts build -c examples/admin-dashboard/view-contracts.config.yaml",
38
+ "build:catalog": "tsx src/cli.ts catalog build -c examples/admin-dashboard/view-contracts.config.yaml",
39
+ "build:example": "vite build --config examples/admin-dashboard/.vite/vite.config.ts",
40
+ "compile": "tsx src/cli.ts compile -c examples/admin-dashboard/view-contracts.config.yaml",
41
+ "render:react": "tsx src/cli.ts render react -c examples/admin-dashboard/view-contracts.config.yaml",
42
+ "contracts:generate": "tsx src/cli.ts contracts generate -c examples/admin-dashboard/view-contracts.config.yaml",
43
+ "contracts:check": "tsx src/cli.ts contracts check -c examples/admin-dashboard/view-contracts.config.yaml",
44
+ "schema:generate": "tsx scripts/schema-generate.ts",
45
+ "cli-contracts:validate": "cli-contracts validate",
46
+ "test:ci": "node dist/view-contracts.bundle.mjs --version && node dist/view-contracts.bundle.mjs --help",
47
+ "version": "node -e \"const fs=require('fs');const f='cli-contract.yaml';fs.writeFileSync(f,fs.readFileSync(f,'utf8').replace(/^ version: .*/m,' version: '+process.env.npm_package_version))\" && git add cli-contract.yaml",
48
+ "prepublishOnly": "npm run build:publish && npm run test:ci"
49
+ },
50
+ "keywords": [
51
+ "ui",
52
+ "contract-first",
53
+ "tsx",
54
+ "view-model",
55
+ "code-generation",
56
+ "react",
57
+ "openapi",
58
+ "design-system",
59
+ "ai-development"
60
+ ],
61
+ "author": "foo-log-inc",
62
+ "license": "MIT",
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "git+https://github.com/foo-log-inc/view-contracts.git"
66
+ },
67
+ "homepage": "https://github.com/foo-log-inc/view-contracts#readme",
68
+ "bugs": {
69
+ "url": "https://github.com/foo-log-inc/view-contracts/issues"
70
+ },
71
+ "engines": {
72
+ "node": ">=20.0.0"
73
+ },
74
+ "dependencies": {
75
+ "commander": "^14.0.3",
76
+ "js-yaml": "^4.1.1",
77
+ "micro-contracts": "^0.17.10",
78
+ "react": "^19.2.0",
79
+ "react-dom": "^19.2.0",
80
+ "typescript": "^5.9.3"
81
+ },
82
+ "devDependencies": {
83
+ "@types/js-yaml": "^4.0.9",
84
+ "@types/node": "^22.19.21",
85
+ "@types/react": "^19.2.17",
86
+ "@types/react-dom": "^19.2.3",
87
+ "@vitejs/plugin-react": "^4.7.0",
88
+ "ajv": "^8.18.0",
89
+ "cli-contracts": "^0.33.13",
90
+ "esbuild": "^0.28.0",
91
+ "tsx": "^4.21.0",
92
+ "vite": "^6.4.1"
93
+ }
94
+ }
@@ -0,0 +1,8 @@
1
+ # Compose renderer scaffold
2
+
3
+ - Maps: `elements.yaml`, `properties.yaml` (hand-maintained under this directory)
4
+ - Routes: `routes.yaml`
5
+ - Templates: `templates/`
6
+
7
+ Implement Compose code generation by reading View IR + renderer maps.
8
+ Vocabulary: `spec/ui-dsl.schema.json` (from `ui-dsl-*.csv`).
@@ -0,0 +1,10 @@
1
+ # React renderer
2
+
3
+ Per-target mapping for view-contracts UI DSL → React.
4
+
5
+ - `routes.yaml` — generated output file routing
6
+ - `elements.yaml` — element → React component (hand-maintained)
7
+ - `properties.yaml` — property → style/attr (hand-maintained)
8
+
9
+ Vocabulary (elements/properties) is defined in `spec/ui-dsl.schema.json` (from `ui-dsl-*.csv`).
10
+ Sample-only preview helpers (Sidebar, Card, etc.) are **not** part of the vocabulary.
@@ -0,0 +1,27 @@
1
+ # Renderer output routing — separate from element/property mapping.
2
+ # Vocabulary: spec/ui-dsl.schema.json. Per-target maps: renderers/{target}/elements.yaml
3
+
4
+ react:
5
+ description: Production / preview React components via project componentsModule
6
+ importFrom: '@view-contracts/components'
7
+ themeCss: theme.css
8
+ outputs:
9
+ screen:
10
+ pattern: '{{projectRoot}}/generated/react/{{screenName}}.generated.tsx'
11
+ preview:
12
+ entry: views/preview.entry.tsx
13
+ generatedEntry: src/main.tsx
14
+
15
+ swiftui:
16
+ description: SwiftUI renderer (scaffold — implement using elements.map.yaml + properties.map.yaml)
17
+ outputs:
18
+ screen:
19
+ pattern: '{{projectRoot}}/generated/swiftui/{{screenName}}.swift'
20
+ template: templates/Screen.swift.hbs
21
+
22
+ compose:
23
+ description: Jetpack Compose renderer (scaffold)
24
+ outputs:
25
+ screen:
26
+ pattern: '{{projectRoot}}/generated/compose/{{screenName}}Screen.kt'
27
+ template: templates/Screen.kt.hbs
@@ -0,0 +1,8 @@
1
+ # SwiftUI renderer scaffold
2
+
3
+ - Maps: `elements.yaml`, `properties.yaml` (hand-maintained under this directory)
4
+ - Routes: `routes.yaml`
5
+ - Templates: `templates/`
6
+
7
+ Implement SwiftUI code generation by reading View IR + renderer maps.
8
+ Extend vocabulary via `spec/ui-dsl.schema.json` (from `ui-dsl-*.csv`), then update renderer maps.
@@ -0,0 +1,90 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "view-contracts UI DSL linter rules",
4
+ "description": "Structural constraints not expressible in ui-dsl.schema.json alone. Validated by schema linter, not JSON Schema.",
5
+ "rules": [
6
+ {
7
+ "id": "spacer-parent",
8
+ "severity": "error",
9
+ "description": "Spacer must be a direct child of Row or Column",
10
+ "element": "Spacer",
11
+ "parent": ["Row", "Column"]
12
+ },
13
+ {
14
+ "id": "scroll-area-single-child",
15
+ "severity": "error",
16
+ "description": "ScrollArea must contain exactly one child",
17
+ "element": "ScrollArea",
18
+ "children": { "count": 1 }
19
+ },
20
+ {
21
+ "id": "list-listitem-only",
22
+ "severity": "error",
23
+ "description": "List children must be ListItem elements only",
24
+ "element": "List",
25
+ "children": { "allowed": ["ListItem"] }
26
+ },
27
+ {
28
+ "id": "icon-button-label-required",
29
+ "severity": "error",
30
+ "description": "IconButton requires label for accessibility",
31
+ "element": "IconButton",
32
+ "requiredProperties": ["label"]
33
+ },
34
+ {
35
+ "id": "image-src-required",
36
+ "severity": "error",
37
+ "description": "Image requires src",
38
+ "element": "Image",
39
+ "requiredProperties": ["src"]
40
+ },
41
+ {
42
+ "id": "icon-name-required",
43
+ "severity": "error",
44
+ "description": "Icon requires name (icon token)",
45
+ "element": "Icon",
46
+ "requiredProperties": ["name"]
47
+ },
48
+ {
49
+ "id": "heading-level-required",
50
+ "severity": "error",
51
+ "description": "Heading requires headingLevel for semantic hierarchy",
52
+ "element": "Heading",
53
+ "requiredProperties": ["headingLevel"]
54
+ },
55
+ {
56
+ "id": "form-no-onclick",
57
+ "severity": "error",
58
+ "description": "Form must use onSubmit, not onClick",
59
+ "element": "Form",
60
+ "forbiddenProperties": ["onClick"]
61
+ },
62
+ {
63
+ "id": "field-single-input",
64
+ "severity": "error",
65
+ "description": "Field must contain exactly one input element",
66
+ "element": "Field",
67
+ "children": {
68
+ "allowed": ["TextInput", "TextArea", "Select", "Checkbox", "Radio", "Switch"],
69
+ "count": 1
70
+ }
71
+ },
72
+ {
73
+ "id": "modal-placement",
74
+ "severity": "error",
75
+ "description": "Modal must be a direct child of Page or an overlay host",
76
+ "element": "Modal",
77
+ "parent": ["Page", "App"]
78
+ },
79
+ {
80
+ "id": "button-label-or-children",
81
+ "severity": "error",
82
+ "description": "Button requires label or text/icon children; when both exist, label is the accessibility name",
83
+ "element": "Button",
84
+ "oneOf": [
85
+ { "requiredProperties": ["label"] },
86
+ { "hasChildren": true }
87
+ ]
88
+ }
89
+ ]
90
+ }
@@ -0,0 +1,113 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://view-contracts.dev/schema/ui-dsl.meta.json",
4
+ "title": "view-contracts UI DSL vocabulary document",
5
+ "description": "JSON Schema for spec/ui-dsl.schema.json. Vocabulary is derived from ui-dsl-*.csv.",
6
+ "type": "object",
7
+ "required": ["tokens", "properties", "elements"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "$schema": { "type": "string" },
11
+ "tokens": {
12
+ "type": "object",
13
+ "additionalProperties": {
14
+ "type": "array",
15
+ "items": { "type": "string" },
16
+ "minItems": 1
17
+ }
18
+ },
19
+ "properties": {
20
+ "type": "object",
21
+ "description": "Shared DSL attributes (from ui-dsl-properties.csv).",
22
+ "additionalProperties": { "$ref": "#/$defs/propertyDef" }
23
+ },
24
+ "elements": {
25
+ "type": "object",
26
+ "description": "DSL elements (from ui-dsl-elements.csv).",
27
+ "additionalProperties": { "$ref": "#/$defs/elementDef" }
28
+ }
29
+ },
30
+ "$defs": {
31
+ "propertyDef": {
32
+ "type": "object",
33
+ "required": ["type", "x-category"],
34
+ "additionalProperties": false,
35
+ "properties": {
36
+ "type": {
37
+ "oneOf": [
38
+ { "type": "string", "enum": ["string", "number", "boolean", "array", "action"] },
39
+ { "type": "array", "items": { "type": "string" }, "minItems": 1 }
40
+ ]
41
+ },
42
+ "enum": { "type": "string", "description": "Token set name in tokens" },
43
+ "description": { "type": "string" },
44
+ "x-category": {
45
+ "type": "string",
46
+ "enum": [
47
+ "identity", "state", "size", "spacing", "alignment", "direction", "overflow",
48
+ "visual", "text", "image", "interaction", "data", "validation"
49
+ ]
50
+ },
51
+ "x-appliesTo": {
52
+ "type": "array",
53
+ "items": { "type": "string" }
54
+ },
55
+ "x-notes": { "type": "string" }
56
+ }
57
+ },
58
+ "propertyRef": {
59
+ "type": "object",
60
+ "required": ["$ref"],
61
+ "additionalProperties": false,
62
+ "properties": {
63
+ "$ref": {
64
+ "type": "string",
65
+ "pattern": "^#/properties/[A-Za-z][A-Za-z0-9]*$"
66
+ }
67
+ }
68
+ },
69
+ "elementProperty": {
70
+ "oneOf": [
71
+ { "$ref": "#/$defs/propertyDef" },
72
+ { "$ref": "#/$defs/propertyRef" }
73
+ ]
74
+ },
75
+ "elementDef": {
76
+ "type": "object",
77
+ "required": ["x-tier", "x-category", "description", "properties", "_children"],
78
+ "additionalProperties": false,
79
+ "properties": {
80
+ "description": { "type": "string" },
81
+ "x-tier": {
82
+ "type": "string",
83
+ "enum": ["core", "optional", "extension"]
84
+ },
85
+ "x-category": {
86
+ "type": "string",
87
+ "enum": ["structure", "layout", "scroll", "text", "media", "input", "form", "overlay", "feedback"]
88
+ },
89
+ "x-notes": { "type": "string" },
90
+ "properties": {
91
+ "type": "object",
92
+ "additionalProperties": { "$ref": "#/$defs/elementProperty" }
93
+ },
94
+ "_children": { "$ref": "#/$defs/childrenConstraint" }
95
+ }
96
+ },
97
+ "childrenConstraint": {
98
+ "type": "object",
99
+ "required": ["x-kind"],
100
+ "additionalProperties": false,
101
+ "properties": {
102
+ "x-kind": {
103
+ "type": "string",
104
+ "enum": ["any", "none", "single", "text", "list"]
105
+ },
106
+ "x-items": {
107
+ "type": "array",
108
+ "items": { "type": "string" }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ }