@json-render/core 0.2.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 +139 -125
- package/dist/index.d.mts +313 -8
- package/dist/index.d.ts +313 -8
- package/dist/index.js +682 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +674 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,184 +1,198 @@
|
|
|
1
1
|
# @json-render/core
|
|
2
2
|
|
|
3
|
-
|
|
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 {
|
|
27
|
-
import {
|
|
50
|
+
import { defineCatalog } from "@json-render/core";
|
|
51
|
+
import { schema } from "./schema";
|
|
52
|
+
import { z } from "zod";
|
|
28
53
|
|
|
29
|
-
const catalog =
|
|
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
|
-
|
|
59
|
+
subtitle: z.string().nullable(),
|
|
36
60
|
}),
|
|
37
|
-
|
|
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
|
-
|
|
66
|
+
variant: z.enum(["primary", "secondary"]).nullable(),
|
|
44
67
|
}),
|
|
45
|
-
description:
|
|
68
|
+
description: "A clickable button",
|
|
46
69
|
},
|
|
47
70
|
},
|
|
48
71
|
actions: {
|
|
49
|
-
submit: { description:
|
|
50
|
-
|
|
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
|
-
###
|
|
78
|
+
### Generate AI Prompts
|
|
62
79
|
|
|
63
80
|
```typescript
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
###
|
|
94
|
+
### Stream AI Responses (SpecStream)
|
|
95
|
+
|
|
96
|
+
The SpecStream format uses JSONL patches to progressively build specs:
|
|
103
97
|
|
|
104
98
|
```typescript
|
|
105
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
123
|
-
|
|
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
|
-
###
|
|
127
|
+
### Low-Level Utilities
|
|
127
128
|
|
|
128
129
|
```typescript
|
|
129
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
141
|
-
value: 'user@example.com',
|
|
142
|
-
dataModel: {},
|
|
143
|
-
});
|
|
151
|
+
### Schema
|
|
144
152
|
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
158
|
+
### Catalog
|
|
150
159
|
|
|
151
|
-
|
|
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
|
-
|
|
154
|
-
- `evaluateLogicExpression(expr, context)` - Evaluate a logic expression
|
|
155
|
-
- `visibility.*` - Helper functions for creating visibility conditions
|
|
165
|
+
### SpecStream
|
|
156
166
|
|
|
157
|
-
|
|
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
|
-
|
|
160
|
-
- `executeAction(context)` - Execute an action with callbacks
|
|
161
|
-
- `interpolateString(template, dataModel)` - Interpolate `${path}` in strings
|
|
174
|
+
### Types
|
|
162
175
|
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
|
|
185
|
+
json-render supports completely different spec formats for different renderers:
|
|
171
186
|
|
|
172
|
-
|
|
173
|
-
|
|
187
|
+
```typescript
|
|
188
|
+
// React: Element tree
|
|
189
|
+
{ root: { type: "Card", props: {...}, children: [...] } }
|
|
174
190
|
|
|
175
|
-
|
|
191
|
+
// Remotion: Timeline
|
|
192
|
+
{ composition: {...}, tracks: [...], clips: [...] }
|
|
176
193
|
|
|
177
|
-
|
|
194
|
+
// Your own: Whatever you need
|
|
195
|
+
{ pages: [...], navigation: {...}, theme: {...} }
|
|
196
|
+
```
|
|
178
197
|
|
|
179
|
-
|
|
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.
|