@json-render/core 0.4.3 → 0.5.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
@@ -116,14 +116,16 @@ while (streaming) {
116
116
  const finalSpec = compiler.getResult();
117
117
  ```
118
118
 
119
- SpecStream format (each line is a JSON patch):
119
+ SpecStream format uses [RFC 6902 JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) operations (each line is a patch):
120
120
 
121
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"}}}
122
+ {"op":"add","path":"/root/type","value":"Card"}
123
+ {"op":"add","path":"/root/props","value":{"title":"Hello"}}
124
+ {"op":"add","path":"/root/children/0","value":{"type":"Button","props":{"label":"Click"}}}
125
125
  ```
126
126
 
127
+ All six RFC 6902 operations are supported: `add`, `remove`, `replace`, `move`, `copy`, `test`.
128
+
127
129
  ### Low-Level Utilities
128
130
 
129
131
  ```typescript
@@ -134,8 +136,8 @@ import {
134
136
  } from "@json-render/core";
135
137
 
136
138
  // Parse a single line
137
- const patch = parseSpecStreamLine('{"op":"set","path":"/root","value":{}}');
138
- // { op: "set", path: "/root", value: {} }
139
+ const patch = parseSpecStreamLine('{"op":"add","path":"/root","value":{}}');
140
+ // { op: "add", path: "/root", value: {} }
139
141
 
140
142
  // Apply a patch to an object
141
143
  const obj = {};
@@ -171,15 +173,141 @@ const spec = compileSpecStream<MySpec>(jsonlString);
171
173
  | `applySpecStreamPatch(obj, patch)` | Apply patch to object |
172
174
  | `compileSpecStream<T>(jsonl)` | Compile entire JSONL string |
173
175
 
176
+ ### Dynamic Props
177
+
178
+ | Export | Purpose |
179
+ |--------|---------|
180
+ | `resolvePropValue(value, ctx)` | Resolve a single prop expression |
181
+ | `resolveElementProps(props, ctx)` | Resolve all prop expressions in an element |
182
+ | `PropExpression<T>` | Type for prop values that may contain expressions |
183
+
184
+ ### User Prompt
185
+
186
+ | Export | Purpose |
187
+ |--------|---------|
188
+ | `buildUserPrompt(options)` | Build a user prompt with optional spec refinement and state context |
189
+ | `UserPromptOptions` | Options type for `buildUserPrompt` |
190
+
191
+ ### Spec Validation
192
+
193
+ | Export | Purpose |
194
+ |--------|---------|
195
+ | `validateSpec(spec, catalog?)` | Validate spec structure and return issues |
196
+ | `autoFixSpec(spec)` | Auto-fix common spec issues (returns corrected copy) |
197
+ | `formatSpecIssues(issues)` | Format validation issues as readable strings |
198
+
174
199
  ### Types
175
200
 
176
201
  | Export | Purpose |
177
202
  |--------|---------|
178
203
  | `Spec` | Base spec type |
179
204
  | `Catalog` | Catalog type |
205
+ | `VisibilityCondition` | Visibility condition type (used by `$cond`) |
206
+ | `VisibilityContext` | Context for evaluating visibility and prop expressions |
180
207
  | `SpecStreamLine` | Single patch operation |
181
208
  | `SpecStreamCompiler` | Streaming compiler interface |
182
209
 
210
+ ## Dynamic Prop Expressions
211
+
212
+ Any prop value can be a dynamic expression that resolves based on data state at render time. Expressions are resolved by the renderer before props reach components.
213
+
214
+ ### Data Binding (`$path`)
215
+
216
+ Read a value directly from the state model:
217
+
218
+ ```json
219
+ {
220
+ "color": { "$path": "/theme/primary" },
221
+ "label": { "$path": "/user/name" }
222
+ }
223
+ ```
224
+
225
+ ### Conditional (`$cond` / `$then` / `$else`)
226
+
227
+ Evaluate a condition (same syntax as visibility conditions) and pick a value:
228
+
229
+ ```json
230
+ {
231
+ "color": {
232
+ "$cond": { "eq": [{ "path": "/activeTab" }, "home"] },
233
+ "$then": "#007AFF",
234
+ "$else": "#8E8E93"
235
+ },
236
+ "name": {
237
+ "$cond": { "eq": [{ "path": "/activeTab" }, "home"] },
238
+ "$then": "home",
239
+ "$else": "home-outline"
240
+ }
241
+ }
242
+ ```
243
+
244
+ `$then` and `$else` can themselves be expressions (recursive):
245
+
246
+ ```json
247
+ {
248
+ "label": {
249
+ "$cond": { "path": "/user/isAdmin" },
250
+ "$then": { "$path": "/admin/greeting" },
251
+ "$else": "Welcome"
252
+ }
253
+ }
254
+ ```
255
+
256
+ ### API
257
+
258
+ ```typescript
259
+ import { resolvePropValue, resolveElementProps } from "@json-render/core";
260
+
261
+ // Resolve a single value
262
+ const color = resolvePropValue(
263
+ { $cond: { eq: [{ path: "/active" }, "yes"] }, $then: "blue", $else: "gray" },
264
+ { stateModel: myState }
265
+ );
266
+
267
+ // Resolve all props on an element
268
+ const resolved = resolveElementProps(element.props, { stateModel: myState });
269
+ ```
270
+
271
+ ## User Prompt Builder
272
+
273
+ Build structured user prompts for AI generation, with support for refinement and state context:
274
+
275
+ ```typescript
276
+ import { buildUserPrompt } from "@json-render/core";
277
+
278
+ // Fresh generation
279
+ const prompt = buildUserPrompt({ prompt: "create a todo app" });
280
+
281
+ // Refinement with existing spec (triggers patch-only mode)
282
+ const refinementPrompt = buildUserPrompt({
283
+ prompt: "add a dark mode toggle",
284
+ currentSpec: existingSpec,
285
+ });
286
+
287
+ // With runtime state context
288
+ const contextPrompt = buildUserPrompt({
289
+ prompt: "show my data",
290
+ state: { todos: [{ text: "Buy milk" }] },
291
+ });
292
+ ```
293
+
294
+ ## Spec Validation
295
+
296
+ Validate spec structure and auto-fix common issues:
297
+
298
+ ```typescript
299
+ import { validateSpec, autoFixSpec, formatSpecIssues } from "@json-render/core";
300
+
301
+ // Validate a spec
302
+ const { valid, issues } = validateSpec(spec, catalog);
303
+
304
+ // Format issues for display
305
+ console.log(formatSpecIssues(issues));
306
+
307
+ // Auto-fix common issues (returns a corrected copy)
308
+ const fixed = autoFixSpec(spec);
309
+ ```
310
+
183
311
  ## Custom Schemas
184
312
 
185
313
  json-render supports completely different spec formats for different renderers: