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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 foo-log-inc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,297 @@
1
+ # view-contracts
2
+
3
+ **Contract-first UI development for AI-native applications.**
4
+
5
+ view-contracts is a UI definition system that separates:
6
+
7
+ - **Screen semantics** → OpenAPI
8
+ - **Visual structure** → Restricted TSX
9
+
10
+ Instead of mixing API contracts, business logic, and UI implementation inside React components, view-contracts treats UI as a **compilable contract**.
11
+
12
+ ---
13
+
14
+ ## Why?
15
+
16
+ Modern UI development has a structural problem.
17
+
18
+ ```txt
19
+ React Component
20
+ ├─ API knowledge
21
+ ├─ ViewModel mapping
22
+ ├─ Business rules
23
+ ├─ Layout
24
+ └─ Styling
25
+ ```
26
+
27
+ As applications grow:
28
+
29
+ - UI becomes difficult to regenerate
30
+ - AI-generated code drifts from design rules
31
+ - Multi-platform support becomes expensive
32
+ - Design systems become guidelines instead of contracts
33
+
34
+ view-contracts introduces a contract-first approach:
35
+
36
+ ```txt
37
+ OpenAPI
38
+
39
+ Screen Contract
40
+ Restricted TSX
41
+
42
+ View Definition
43
+ Compiler
44
+
45
+ Generated UI
46
+ ```
47
+
48
+ The goal is to make UI generation **deterministic**.
49
+
50
+ ---
51
+
52
+ ## Core Concepts
53
+
54
+ ### OpenAPI owns semantics
55
+
56
+ OpenAPI defines:
57
+
58
+ - screens
59
+ - actions
60
+ - navigation
61
+ - ViewModels
62
+
63
+ Example:
64
+
65
+ ```yaml
66
+ /admin/dashboard:
67
+ get:
68
+ operationId: getAdminDashboard
69
+ x-screen-id: SCR-ADMIN-DASHBOARD
70
+ ```
71
+
72
+ This is the source of truth for screen behavior.
73
+
74
+ ### TSX owns layout
75
+
76
+ A `.view.tsx` file defines:
77
+
78
+ - component hierarchy
79
+ - layout structure
80
+ - visual composition
81
+
82
+ Example:
83
+
84
+ ```tsx
85
+ export default screen<AdminDashboardViewModel>(({ vm }) => (
86
+ <Page id={vm.screenId} title={vm.title}>
87
+ <Heading level={1}>{vm.title}</Heading>
88
+ <Table rows={vm.projects} />
89
+ </Page>
90
+ ));
91
+ ```
92
+
93
+ The view describes **structure only** — not API calls, routing logic, or styling implementation details.
94
+
95
+ ### Compile instead of hand-coding
96
+
97
+ ```txt
98
+ .view.tsx
99
+
100
+ Compiler (in-memory View IR)
101
+
102
+ Renderer
103
+
104
+ generated/react/*.tsx + generated/runtime/
105
+ ```
106
+
107
+ The generated output is deterministic.
108
+
109
+ ---
110
+
111
+ ## Current Status
112
+
113
+ ### Supported
114
+
115
+ - React generation (`generated/react/`, `generated/components/`)
116
+ - DSL preview runtime (`src/preview/`)
117
+ - In-memory View IR compilation
118
+ - Standalone app scaffold (`.vite/` per example project)
119
+ - Static catalog generation
120
+
121
+ ### Planned
122
+
123
+ - SwiftUI renderer
124
+ - Jetpack Compose renderer
125
+ - PDF renderer
126
+
127
+ The contract model is designed for multi-target generation, but the first production target is React.
128
+
129
+ ---
130
+
131
+ ## Architecture
132
+
133
+ Two sources of truth converge through **bindings**, **type-checking**, and **View IR**.
134
+
135
+ ```mermaid
136
+ flowchart TB
137
+ subgraph ia ["Information architecture"]
138
+ openapi["contracts/openapi.yaml<br/>screens · ViewModels · actions"]
139
+ end
140
+
141
+ subgraph design ["Visual design"]
142
+ viewTsx["views/*.view.tsx<br/>layout · composition"]
143
+ end
144
+
145
+ openapi --> microContracts["micro-contracts generate"]
146
+ microContracts --> contractsTs["generated/contracts.ts"]
147
+ microContracts --> mockTs["generated/mock.ts"]
148
+
149
+ openapi --> bindings["view-bindings.yaml"]
150
+ viewTsx --> bindings
151
+
152
+ contractsTs -->|"imports ViewModel type<br/>validates vm.* and operationId"| viewTsx
153
+
154
+ bindings -->|"screen ↔ view mapping"| build["view-contracts build"]
155
+ viewTsx --> build
156
+
157
+ build --> viewIr["View IR (in-memory)"]
158
+ viewIr --> reactRenderer["renderComponents"]
159
+ build --> runtimeCopy["renderRuntime → generated/"]
160
+ build --> bridgeGen["render bridge"]
161
+
162
+ reactRenderer --> generatedReact["generated/react/*.generated.tsx"]
163
+ bridgeGen --> bridgeTs["generated/view-bridge.generated.ts"]
164
+ runtimeCopy --> generatedRuntime["generated/components + runtime/"]
165
+
166
+ generatedReact --> app["Standalone app (src/main.tsx)"]
167
+ bridgeTs --> app
168
+ generatedRuntime --> app
169
+ ```
170
+
171
+ **Where the two designs meet**
172
+
173
+ | Stage | What merges | Output |
174
+ | --- | --- | --- |
175
+ | Authoring | OpenAPI types flow into `.view.tsx` via `generated/contracts.ts` | Type-safe view source |
176
+ | Binding | `view-bindings.yaml` links a screen (`operationId`, `ViewModel`) to a view file | No schema duplication |
177
+ | Compilation | Compiler reads layout from TSX and lowers `vm.*` / `action` to language-neutral IR | In-memory View IR |
178
+ | Generation | Renderer copies runtime + emits React from IR + bridge registry | `generated/` (no `@view-contracts` imports) |
179
+
180
+ ### Preview path (no compile step)
181
+
182
+ ```mermaid
183
+ flowchart LR
184
+ openapi["openapi.yaml"] --> microContracts["micro-contracts"]
185
+ microContracts --> contractsTs["contracts.ts"]
186
+ microContracts --> mockTs["mock.ts"]
187
+
188
+ contractsTs --> viewTsx["*.view.tsx"]
189
+ viewTsx --> preview["src/preview/"]
190
+ mockTs --> preview
191
+
192
+ preview --> reactDev["Vite dev server<br/>design verification"]
193
+ ```
194
+
195
+ Designers and developers validate layouts **without running the full build**. The preview still consumes OpenAPI-derived ViewModel types and mock data.
196
+
197
+ See [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) and [docs/SPEC_COVERAGE.md](./docs/SPEC_COVERAGE.md) for implementation details.
198
+
199
+ ---
200
+
201
+ ## Quick Start
202
+
203
+ ```bash
204
+ npm install
205
+ npm run build:views # compile + generate + scaffold .vite/
206
+ npm run dev # preview (5173) + dev app (5174)
207
+ ```
208
+
209
+ | URL | Purpose |
210
+ | --- | --- |
211
+ | http://localhost:5173/.vite/preview.html | DSL preview — `views/*.view.tsx` only |
212
+ | http://localhost:5174/.vite/index.html | Dev app — `generated/` + `src/main.tsx` |
213
+
214
+ Ports are fixed in `examples/admin-dashboard/dev.ports.ts` (`strictPort: true`).
215
+
216
+ Other useful commands:
217
+
218
+ ```bash
219
+ npm run dev:preview # preview only
220
+ npm run dev:app # standalone dev app only
221
+ npm run check:both # build + preview dev + production bundle (4174)
222
+ npm run build:catalog # static gallery HTML
223
+ ```
224
+
225
+ ---
226
+
227
+ ## Example Project
228
+
229
+ The repository includes an example admin dashboard:
230
+
231
+ ```txt
232
+ examples/admin-dashboard/
233
+ ├── views/ # restricted .view.tsx (may import @view-contracts/*)
234
+ ├── src/ # app wiring, extension components, handlers
235
+ ├── generated/ # build output (standalone — no @view-contracts imports)
236
+ ├── contracts/ # OpenAPI + micro-contracts config
237
+ ├── dev.ports.ts # fixed dev server ports
238
+ ├── scripts/ # dev-both.sh, check-both.sh, ports.sh
239
+ └── .vite/ # auto-generated Vite configs (gitignored)
240
+ ```
241
+
242
+ See [examples/admin-dashboard/README.md](./examples/admin-dashboard/README.md) for local verification steps.
243
+
244
+ ---
245
+
246
+ ## Project Layout
247
+
248
+ ```txt
249
+ src/
250
+ ├── compiler/ # TSX → View IR
251
+ ├── renderer/
252
+ │ └── react/
253
+ │ ├── renderComponents.ts # IR → generated/react/*.tsx
254
+ │ ├── renderRuntime.ts # runtime SSoT → example/generated/
255
+ │ └── runtime/ # React primitives (@view-contracts/components SSoT)
256
+ ├── preview/ # DSL preview helpers (@view-contracts/preview)
257
+ ├── scaffold/ # .vite/ + package.json for example projects
258
+ ├── catalog/ # static catalog builder
259
+ └── commands/ # CLI handlers (build orchestrator)
260
+
261
+ packages/
262
+ ├── core/ # screen(), types (@view-contracts/core)
263
+ └── runtime/ # action dispatcher (@view-contracts/runtime)
264
+
265
+ renderers/
266
+ ├── react/ # element/property maps, routes.yaml
267
+ ├── swiftui/ # (planned)
268
+ └── compose/ # (planned)
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Vision
274
+
275
+ UI should be treated like an API contract.
276
+
277
+ The long-term goal of view-contracts is to make UI:
278
+
279
+ - **deterministic**
280
+ - **compilable**
281
+ - **AI-friendly**
282
+ - **portable** across platforms
283
+
284
+ while keeping designers and developers working from the same source of truth.
285
+
286
+ view-contracts is not a React replacement — it is **contract-first UI** for the AI era.
287
+
288
+ ---
289
+
290
+ ## npm
291
+
292
+ ```bash
293
+ npm install -D view-contracts
294
+ npx view-contracts build -c view-contracts.config.yaml
295
+ ```
296
+
297
+ Releases are published to npm when a [GitHub Release](https://github.com/foo-log-inc/view-contracts/releases) is published (`v*` tag).
@@ -0,0 +1,201 @@
1
+ # yaml-language-server: $schema=./node_modules/cli-contracts/schemas/cli-contract.schema.json
2
+ cli_contracts: 0.1.0
3
+
4
+ info:
5
+ title: view-contracts CLI
6
+ version: 0.1.0
7
+ description: >-
8
+ Contract-first UI design toolchain. Compiles restricted view-contract TSX
9
+ to language-neutral View IR and renders platform targets (React, SwiftUI, Compose).
10
+
11
+ artifact_slots:
12
+ openapi-specs:
13
+ direction: read
14
+ description: OpenAPI screen contracts
15
+ view-sources:
16
+ direction: read
17
+ description: Restricted .view.tsx design definitions
18
+ generated-react:
19
+ direction: write
20
+ description: Generated React components
21
+ bindings:
22
+ direction: read
23
+ description: view-bindings.yaml bridge registry input
24
+
25
+ command_sets:
26
+ view-contracts:
27
+ summary: View contract compiler and renderer toolchain.
28
+ executable: view-contracts
29
+
30
+ global_options:
31
+ - name: help
32
+ aliases: [h]
33
+ description: Show help and exit.
34
+ schema:
35
+ type: boolean
36
+
37
+ - name: version
38
+ aliases: [V]
39
+ description: Print version and exit.
40
+ schema:
41
+ type: boolean
42
+
43
+ commands:
44
+ compile:
45
+ summary: Compile .view.tsx files to View IR.
46
+ description: >-
47
+ Parses restricted view-contract TSX via the TypeScript AST, validates
48
+ allowed components and expressions, and holds View IR in memory.
49
+ usage:
50
+ - view-contracts compile
51
+ - view-contracts compile -c view-contracts.config.yaml
52
+ options:
53
+ - name: config
54
+ aliases: [c]
55
+ description: Path to view-contracts.config.yaml (discovered upward from cwd when omitted).
56
+ value_name: path
57
+ schema:
58
+ type: string
59
+ file:
60
+ mode: read
61
+ media_type: application/yaml
62
+ encoding: utf-8
63
+ exits:
64
+ '0':
65
+ description: Compilation succeeded.
66
+ '1':
67
+ description: Compilation failed.
68
+
69
+ render.react:
70
+ summary: Generate React components from View IR.
71
+ description: Compiles views in memory and emits production React to generated/react/.
72
+ usage:
73
+ - view-contracts render react
74
+ - view-contracts render react -c view-contracts.config.yaml
75
+ options:
76
+ - name: config
77
+ aliases: [c]
78
+ description: Path to view-contracts.config.yaml (discovered upward from cwd when omitted).
79
+ value_name: path
80
+ schema:
81
+ type: string
82
+ exits:
83
+ '0':
84
+ description: Render succeeded.
85
+ '1':
86
+ description: Render failed.
87
+
88
+ render.bridge:
89
+ summary: Generate view ↔ ViewModel bridge registry.
90
+ description: Emits src/generated/view-bridge.generated.ts from view-bindings.yaml.
91
+ usage:
92
+ - view-contracts render bridge
93
+ - view-contracts render bridge -c view-contracts.config.yaml
94
+ options:
95
+ - name: config
96
+ aliases: [c]
97
+ description: Path to view-contracts.config.yaml (discovered upward from cwd when omitted).
98
+ value_name: path
99
+ schema:
100
+ type: string
101
+ exits:
102
+ '0':
103
+ description: Bridge registry generated.
104
+ '1':
105
+ description: Generation failed.
106
+
107
+ build:
108
+ summary: Full view pipeline (compile + render runtime + render react + bridge).
109
+ description: >-
110
+ Compiles views in memory, copies React runtime to generated/, emits
111
+ React components and bridge registry, and scaffolds .vite/ dev files.
112
+ usage:
113
+ - view-contracts build
114
+ - view-contracts build -c view-contracts.config.yaml
115
+ options:
116
+ - name: config
117
+ aliases: [c]
118
+ description: Path to view-contracts.config.yaml (discovered upward from cwd when omitted).
119
+ value_name: path
120
+ schema:
121
+ type: string
122
+ exits:
123
+ '0':
124
+ description: Build succeeded.
125
+ '1':
126
+ description: Build failed.
127
+
128
+ contracts.generate:
129
+ summary: Generate ViewModel types from OpenAPI via micro-contracts.
130
+ description: Delegates to micro-contracts generate using micro-contracts.config.yaml.
131
+ usage:
132
+ - view-contracts contracts generate
133
+ - view-contracts contracts generate -c view-contracts.config.yaml
134
+ options:
135
+ - name: config
136
+ aliases: [c]
137
+ description: Path to view-contracts.config.yaml (discovered upward from cwd when omitted).
138
+ value_name: path
139
+ schema:
140
+ type: string
141
+ exits:
142
+ '0':
143
+ description: Generation succeeded.
144
+ '1':
145
+ description: Generation failed.
146
+
147
+ contracts.check:
148
+ summary: Lint OpenAPI screen contracts via micro-contracts.
149
+ description: Delegates to micro-contracts lint.
150
+ usage:
151
+ - view-contracts contracts check
152
+ - view-contracts contracts check -c view-contracts.config.yaml
153
+ options:
154
+ - name: config
155
+ aliases: [c]
156
+ description: Path to view-contracts.config.yaml (discovered upward from cwd when omitted).
157
+ value_name: path
158
+ schema:
159
+ type: string
160
+ exits:
161
+ '0':
162
+ description: Lint passed.
163
+ '1':
164
+ description: Lint failed.
165
+
166
+ catalog.build:
167
+ summary: Build static catalog HTML for design review.
168
+ description: >-
169
+ Renders all registered views with mock ViewModels into a single HTML file
170
+ for design review, screenshot baselines, and accessibility checks.
171
+ usage:
172
+ - view-contracts catalog build
173
+ - view-contracts catalog build -c view-contracts.config.yaml
174
+ - view-contracts catalog build -o dist/catalog.html
175
+ options:
176
+ - name: config
177
+ aliases: [c]
178
+ description: Path to view-contracts.config.yaml (discovered upward from cwd when omitted).
179
+ value_name: path
180
+ schema:
181
+ type: string
182
+ - name: output
183
+ aliases: [o]
184
+ description: Output HTML path (defaults to dist/catalog.html next to bindings).
185
+ value_name: path
186
+ schema:
187
+ type: string
188
+ file:
189
+ mode: write
190
+ media_type: text/html
191
+ encoding: utf-8
192
+ exits:
193
+ '0':
194
+ description: Catalog built.
195
+ files:
196
+ - path: dist/catalog.html
197
+ required: false
198
+ media_type: text/html
199
+ encoding: utf-8
200
+ '1':
201
+ description: Build failed.