@json-render/core 0.3.0 → 0.4.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/README.md CHANGED
@@ -1,184 +1,198 @@
1
1
  # @json-render/core
2
2
 
3
- **Predictable. Guardrailed. Fast.** Core library for safe, user-prompted UI generation.
4
-
5
- ## Features
6
-
7
- - **Conditional Visibility**: Show/hide components based on data paths, auth state, or complex logic expressions
8
- - **Rich Actions**: Actions with typed parameters, confirmation dialogs, and success/error callbacks
9
- - **Enhanced Validation**: Built-in validation functions with custom catalog functions support
10
- - **Type-Safe Catalog**: Define component schemas using Zod for full type safety
11
- - **Framework Agnostic**: Core logic is independent of UI frameworks
3
+ Core library for json-render. Define schemas, create catalogs, generate AI prompts, and stream specs.
12
4
 
13
5
  ## Installation
14
6
 
15
7
  ```bash
16
- npm install @json-render/core
17
- # or
18
- pnpm add @json-render/core
8
+ npm install @json-render/core zod
19
9
  ```
20
10
 
11
+ ## Key Concepts
12
+
13
+ - **Schema**: Defines the structure of specs and catalogs
14
+ - **Catalog**: Maps component/action names to their definitions with Zod props
15
+ - **Spec**: JSON output from AI that conforms to the schema
16
+ - **SpecStream**: JSONL streaming format for progressive spec building
17
+
21
18
  ## Quick Start
22
19
 
20
+ ### Define a Schema
21
+
22
+ ```typescript
23
+ import { defineSchema } from "@json-render/core";
24
+
25
+ export const schema = defineSchema((s) => ({
26
+ spec: s.object({
27
+ root: s.object({
28
+ type: s.ref("catalog.components"),
29
+ props: s.propsOf("catalog.components"),
30
+ children: s.array(s.self()),
31
+ }),
32
+ }),
33
+ catalog: s.object({
34
+ components: s.map({
35
+ props: s.zod(),
36
+ description: s.string(),
37
+ }),
38
+ actions: s.map({
39
+ description: s.string(),
40
+ }),
41
+ }),
42
+ }), {
43
+ promptTemplate: myPromptTemplate, // Optional custom AI prompt generator
44
+ });
45
+ ```
46
+
23
47
  ### Create a Catalog
24
48
 
25
49
  ```typescript
26
- import { createCatalog } from '@json-render/core';
27
- import { z } from 'zod';
50
+ import { defineCatalog } from "@json-render/core";
51
+ import { schema } from "./schema";
52
+ import { z } from "zod";
28
53
 
29
- const catalog = createCatalog({
30
- name: 'My Dashboard',
54
+ export const catalog = defineCatalog(schema, {
31
55
  components: {
32
56
  Card: {
33
57
  props: z.object({
34
58
  title: z.string(),
35
- description: z.string().nullable(),
59
+ subtitle: z.string().nullable(),
36
60
  }),
37
- hasChildren: true,
38
- description: 'A card container',
61
+ description: "A card container with title",
39
62
  },
40
63
  Button: {
41
64
  props: z.object({
42
65
  label: z.string(),
43
- action: ActionSchema,
66
+ variant: z.enum(["primary", "secondary"]).nullable(),
44
67
  }),
45
- description: 'A clickable button',
68
+ description: "A clickable button",
46
69
  },
47
70
  },
48
71
  actions: {
49
- submit: { description: 'Submit the form' },
50
- export: {
51
- params: z.object({ format: z.enum(['csv', 'pdf']) }),
52
- description: 'Export data',
53
- },
54
- },
55
- functions: {
56
- customValidation: (value) => typeof value === 'string' && value.length > 0,
72
+ submit: { description: "Submit the form" },
73
+ cancel: { description: "Cancel and close" },
57
74
  },
58
75
  });
59
76
  ```
60
77
 
61
- ### Visibility Conditions
78
+ ### Generate AI Prompts
62
79
 
63
80
  ```typescript
64
- import { visibility, evaluateVisibility } from '@json-render/core';
65
-
66
- // Simple path-based visibility
67
- const element1 = {
68
- key: 'error-banner',
69
- type: 'Alert',
70
- props: { message: 'Error!' },
71
- visible: { path: '/form/hasError' },
72
- };
73
-
74
- // Auth-based visibility
75
- const element2 = {
76
- key: 'admin-panel',
77
- type: 'Card',
78
- props: { title: 'Admin' },
79
- visible: { auth: 'signedIn' },
80
- };
81
-
82
- // Complex logic
83
- const element3 = {
84
- key: 'notification',
85
- type: 'Alert',
86
- props: { message: 'Warning' },
87
- visible: {
88
- and: [
89
- { path: '/settings/notifications' },
90
- { not: { path: '/user/dismissed' } },
91
- { gt: [{ path: '/items/count' }, 10] },
92
- ],
93
- },
94
- };
95
-
96
- // Evaluate visibility
97
- const isVisible = evaluateVisibility(element1.visible, {
98
- dataModel: { form: { hasError: true } },
81
+ // Generate system prompt for AI
82
+ const systemPrompt = catalog.prompt();
83
+
84
+ // With custom rules
85
+ const systemPrompt = catalog.prompt({
86
+ system: "You are a dashboard builder.",
87
+ customRules: [
88
+ "Always include a header",
89
+ "Use Card components for grouping",
90
+ ],
99
91
  });
100
92
  ```
101
93
 
102
- ### Rich Actions
94
+ ### Stream AI Responses (SpecStream)
95
+
96
+ The SpecStream format uses JSONL patches to progressively build specs:
103
97
 
104
98
  ```typescript
105
- import { resolveAction, executeAction } from '@json-render/core';
99
+ import { createSpecStreamCompiler } from "@json-render/core";
100
+
101
+ // Create a compiler for your spec type
102
+ const compiler = createSpecStreamCompiler<MySpec>();
103
+
104
+ // Process streaming chunks from AI
105
+ while (streaming) {
106
+ const chunk = await reader.read();
107
+ const { result, newPatches } = compiler.push(chunk);
108
+
109
+ if (newPatches.length > 0) {
110
+ // Update UI with partial result
111
+ setSpec(result);
112
+ }
113
+ }
114
+
115
+ // Get final compiled result
116
+ const finalSpec = compiler.getResult();
117
+ ```
106
118
 
107
- const buttonAction = {
108
- name: 'refund',
109
- params: {
110
- paymentId: { path: '/selected/id' },
111
- amount: 100,
112
- },
113
- confirm: {
114
- title: 'Confirm Refund',
115
- message: 'Refund $100 to customer?',
116
- variant: 'danger',
117
- },
118
- onSuccess: { navigate: '/payments' },
119
- onError: { set: { '/ui/error': '$error.message' } },
120
- };
119
+ SpecStream format (each line is a JSON patch):
121
120
 
122
- // Resolve dynamic values
123
- const resolved = resolveAction(buttonAction, dataModel);
121
+ ```jsonl
122
+ {"op":"set","path":"/root/type","value":"Card"}
123
+ {"op":"set","path":"/root/props","value":{"title":"Hello"}}
124
+ {"op":"set","path":"/root/children/0","value":{"type":"Button","props":{"label":"Click"}}}
124
125
  ```
125
126
 
126
- ### Validation
127
+ ### Low-Level Utilities
127
128
 
128
129
  ```typescript
129
- import { runValidation, check } from '@json-render/core';
130
+ import {
131
+ parseSpecStreamLine,
132
+ applySpecStreamPatch,
133
+ compileSpecStream,
134
+ } from "@json-render/core";
135
+
136
+ // Parse a single line
137
+ const patch = parseSpecStreamLine('{"op":"set","path":"/root","value":{}}');
138
+ // { op: "set", path: "/root", value: {} }
139
+
140
+ // Apply a patch to an object
141
+ const obj = {};
142
+ applySpecStreamPatch(obj, patch);
143
+ // obj is now { root: {} }
144
+
145
+ // Compile entire JSONL string at once
146
+ const spec = compileSpecStream<MySpec>(jsonlString);
147
+ ```
130
148
 
131
- const config = {
132
- checks: [
133
- check.required('Email is required'),
134
- check.email('Invalid email'),
135
- check.maxLength(100, 'Too long'),
136
- ],
137
- validateOn: 'blur',
138
- };
149
+ ## API Reference
139
150
 
140
- const result = runValidation(config, {
141
- value: 'user@example.com',
142
- dataModel: {},
143
- });
151
+ ### Schema
144
152
 
145
- // result.valid = true
146
- // result.errors = []
147
- ```
153
+ | Export | Purpose |
154
+ |--------|---------|
155
+ | `defineSchema(builder, options?)` | Create a schema with spec/catalog structure |
156
+ | `SchemaBuilder` | Builder with `s.object()`, `s.array()`, `s.map()`, etc. |
148
157
 
149
- ## API Reference
158
+ ### Catalog
150
159
 
151
- ### Visibility
160
+ | Export | Purpose |
161
+ |--------|---------|
162
+ | `defineCatalog(schema, data)` | Create a type-safe catalog from schema |
163
+ | `catalog.prompt(options?)` | Generate AI system prompt |
152
164
 
153
- - `evaluateVisibility(condition, context)` - Evaluate a visibility condition
154
- - `evaluateLogicExpression(expr, context)` - Evaluate a logic expression
155
- - `visibility.*` - Helper functions for creating visibility conditions
165
+ ### SpecStream
156
166
 
157
- ### Actions
167
+ | Export | Purpose |
168
+ |--------|---------|
169
+ | `createSpecStreamCompiler<T>()` | Create streaming compiler |
170
+ | `parseSpecStreamLine(line)` | Parse single JSONL line |
171
+ | `applySpecStreamPatch(obj, patch)` | Apply patch to object |
172
+ | `compileSpecStream<T>(jsonl)` | Compile entire JSONL string |
158
173
 
159
- - `resolveAction(action, dataModel)` - Resolve dynamic values in an action
160
- - `executeAction(context)` - Execute an action with callbacks
161
- - `interpolateString(template, dataModel)` - Interpolate `${path}` in strings
174
+ ### Types
162
175
 
163
- ### Validation
176
+ | Export | Purpose |
177
+ |--------|---------|
178
+ | `Spec` | Base spec type |
179
+ | `Catalog` | Catalog type |
180
+ | `SpecStreamLine` | Single patch operation |
181
+ | `SpecStreamCompiler` | Streaming compiler interface |
164
182
 
165
- - `runValidation(config, context)` - Run validation checks
166
- - `runValidationCheck(check, context)` - Run a single validation check
167
- - `builtInValidationFunctions` - Built-in validators (required, email, min, max, etc.)
168
- - `check.*` - Helper functions for creating validation checks
183
+ ## Custom Schemas
169
184
 
170
- ### Catalog
185
+ json-render supports completely different spec formats for different renderers:
171
186
 
172
- - `createCatalog(config)` - Create a catalog with components, actions, and functions
173
- - `generateCatalogPrompt(catalog)` - Generate an AI prompt describing the catalog
187
+ ```typescript
188
+ // React: Element tree
189
+ { root: { type: "Card", props: {...}, children: [...] } }
174
190
 
175
- ## Types
191
+ // Remotion: Timeline
192
+ { composition: {...}, tracks: [...], clips: [...] }
176
193
 
177
- See `src/types.ts` for full type definitions:
194
+ // Your own: Whatever you need
195
+ { pages: [...], navigation: {...}, theme: {...} }
196
+ ```
178
197
 
179
- - `UIElement` - Base element structure
180
- - `UITree` - Flat tree structure
181
- - `VisibilityCondition` - Visibility condition types
182
- - `LogicExpression` - Logic expression types
183
- - `Action` - Rich action definition
184
- - `ValidationConfig` - Validation configuration
198
+ Each renderer defines its own schema with `defineSchema()` and its own prompt template.