Skip to main content

json-render-core

Core package for defining schemas, catalogs, and AI prompt generation for json-render. Use when working with @json-render/core, defining schemas, creating catalogs, or building JSON specs for UI/video generation.

Aller à l'installation

Informations de source

Dépôt
pskoett/pmx-canvas
Dernière activité de la source
1 avril 2026 à 15:29
Langue détectée de SKILL.md
anglais
Étoiles
19
Forks
3

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
json-render-core
description
Core package for defining schemas, catalogs, and AI prompt generation for json-render. Use when working with @json-render/core, defining schemas, creating catalogs, or building JSON specs for UI/video generation.
# @json-render/core Core package for schema definition, catalog creation, and spec streaming. ## Key Concepts - **Schema**: Defines the structure of specs and catalogs (use `defineSchema`) - **Catalog**: Maps component/action names to their definitions (use `defineCatalog`) - **Spec**: JSON output from AI that conforms to the schema - **SpecStream**: JSONL streaming format for progressive spec building ## Defining a Schema ```typescript import { defineSchema } from "@json-render/core"; export const schema = defineSchema((s) => ({ spec: s.object({ // Define spec structure }), catalog: s.object({ components: s.map({ props: s.zod(), description: s.string(), }), }), }), { promptTemplate: myPromptTemplate, // Optional custom AI prompt }); ``` ## Creating a Catalog ```typescript import { defineCatalog } from "@json-render/core"; import { schema } from "./schema"; import { z } from "zod"; export const catalog = defineCatalog(schema, { components: { Button: { props: z.object({ label: z.string(), variant: z.enum(["primary", "secondary"]).nullable(), }), description: "Clickable button component", }, }, }); ``` ## Generating AI Prompts ```typescript const systemPrompt = catalog.prompt(); // Uses schema's promptTemplate const systemPrompt = catalog.prompt({ customRules: ["Rule 1", "Rule 2"] }); ``` ## SpecStream Utilities For streaming AI responses (JSONL patches): ```typescript import { createSpecStreamCompiler } from "@json-render/core"; const compiler = createSpecStreamCompiler<MySpec>(); // Process streaming chunks const { result, newPatches } = compiler.push(chunk); // Get final result const finalSpec = compiler.getResult(); ``` ## Dynamic Prop Expressions Any prop value can be a dynamic expression resolved at render time: - **`{ "$state": "/state/key" }`** - reads a value from the state model (one-way read) - **`{ "$bindState": "/path" }`** - two-way binding: reads from state and enables write-back. Use on the natural value prop (value, checked, pressed, etc.) of form components. - **`{ "$bindItem": "field" }`** - two-way binding to a repeat item field. Use inside repeat scopes. - **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** - evaluates a visibility condition and picks a branch - **`{ "$template": "Hello, ${/user/name}!" }`** - interpolates `${/path}` references with state values - **`{ "$computed": "fnName", "args": { "key": <expression> } }`** - calls a registered function with resolved args `$cond` uses the same syntax as visibility conditions (`$state`, `eq`, `neq`, `not`, arrays for AND). `$then` and `$else` can themselves be expressions (recursive). Components do not use a `statePath` prop for two-way binding. Instead, use `{ "$bindState": "/path" }` on the natural value prop (e.g. `value`, `checked`, `pressed`). ```json { "color": { "$cond": { "$state": "/activeTab", "eq": "home" }, "$then": "#007AFF", "$else": "#8E8E93" }, "label": { "$template": "Welcome, ${/user/name}!" }, "fullName": { "$computed": "fullName", "args": { "first": { "$state": "/form/firstName" }, "last": { "$state": "/form/lastName" } } } } ``` ```typescript import { resolvePropValue, resolveElementProps } from "@json-render/core"; const resolved = resolveElementProps(element.props, { stateModel: myState }); ``` ## State Watchers Elements can declare a `watch` field (top-level, sibling of type/props/children) to trigger actions when state values change: ```json { "type": "Select", "props": { "value": { "$bindState": "/form/country" }, "options": ["US", "Canada"] }, "watch": { "/form/country": { "action": "loadCities", "params": { "country": { "$state": "/form/country" } } } }, "children": [] } ``` Watchers only fire on value changes, not on initial render. ## Validation Built-in validation functions: `required`, `email`, `url`, `numeric`, `minLength`, `maxLength`, `min`, `max`, `pattern`, `matches`, `equalTo`, `lessThan`, `greaterThan`, `requiredIf`. Cross-field validation uses `$state` expressions in args: ```typescript import { check } from "@json-render/core"; check.required("Field is required"); check.matches("/form/password", "Passwords must match"); check.lessThan("/form/endDate", "Must be before end date"); check.greaterThan("/form/startDate", "Must be after start date"); check.requiredIf("/form/enableNotifications", "Required when enabled"); ``` ## User Prompt Builder Build structured user prompts with optional spec refinement and state context: ```typescript import { buildUserPrompt } from "@json-render/core"; // Fresh generation buildUserPrompt({ prompt: "create a todo app" }); // Refinement with edit modes (default: patch-only) buildUserPrompt({ prompt: "add a toggle", currentSpec: spec, editModes: ["patch", "merge"] }); // With runtime state buildUserPrompt({ prompt: "show data", state: { todos: [] } }); ``` Available edit modes: `"patch"` (RFC 6902 JSON Patch), `"merge"` (RFC 7396 Merge Patch), `"diff"` (unified diff). ## Spec Validation Validate spec structure and auto-fix common issues: ```typescript import { validateSpec, autoFixSpec } from "@json-render/core"; const { valid, issues } = validateSpec(spec); const fixed = autoFixSpec(spec); ``` ## Visibility Conditions Control element visibility with state-based conditions. `VisibilityContext` is `{ stateModel: StateModel }`. ```typescript import { visibility } from "@json-render/core"; // Syntax { "$state": "/path" } // truthiness { "$state": "/path", "not": true } // falsy { "$state": "/path", "eq": value } // equality [ cond1, cond2 ] // implicit AND // Helpers visibility.when("/path") // { $state: "/path" } visibility.unless("/path") // { $state: "/path", not: true } visibility.eq("/path", val) // { $state: "/path", eq: val } visibility.and(cond1, cond2) // { $and: [cond1, cond2] } visibility.or(cond1, cond2) // { $or: [cond1, cond2] } visibility.always // true visibility.never // false ``` ## Built-in Actions in Schema Schemas can declare `builtInActions` -- actions that are always available at runtime and auto-injected into prompts: ```typescript const schema = defineSchema(builder, { builtInActions: [ { name: "setState", description: "Update a value in the state model" }, ], }); ``` These appear in prompts as `[built-in]` and don't require handlers in `defineRegistry`. ## StateStore The `StateStore` interface allows external state management libraries (Redux, Zustand, XState, etc.) to be plugged into json-render renderers. The `createStateStore` factory creates a simple in-memory implementation: ```typescript import { createStateStore, type StateStore } from "@json-render/core"; const store = createStateStore({ count: 0 }); store.get("/count"); // 0 store.set("/count", 1); // updates and notifies subscribers store.update({ "/a": 1, "/b": 2 }); // batch update store.subscribe(() => { console.log(store.getSnapshot()); // { count: 1 } }); ``` The `StateStore` interface: `get(path)`, `set(path, value)`, `update(updates)`, `getSnapshot()`, `subscribe(listener)`. ## Key Exports | Export | Purpose | |--------|---------| | `defineSchema` | Create a new schema | | `defineCatalog` | Create a catalog from schema | | `createStateStore` | Create a framework-agnostic in-memory `StateStore` | | `resolvePropValue` | Resolve a single prop expression against data | | `resolveElementProps` | Resolve all prop expressions in an element | | `buildUserPrompt` | Build user prompts with refinement and state context | | `buildEditUserPrompt` | Build user prompt for editing existing specs | | `buildEditInstructions` | Generate prompt section for available edit modes | | `isNonEmptySpec` | Check if spec has root and at least one element | | `deepMergeSpec` | RFC 7396 deep merge (null deletes, arrays replace, objects recurse) | | `diffToPatches` | Generate RFC 6902 JSON Patch operations from object diff | | `EditMode` | Type: `"patch" \| "merge" \| "diff"` | | `validateSpec` | Validate spec structure | | `autoFixSpec` | Auto-fix common spec issues | | `createSpecStreamCompiler` | Stream JSONL patches into spec | | `createJsonRenderTransform` | TransformStream separating text from JSONL in mixed streams | | `parseSpecStreamLine` | Parse single JSONL line | | `applySpecStreamPatch` | Apply patch to object | | `StateStore` | Interface for plugging in external state management | | `ComputedFunction` | Function signature for `$computed` expressions | | `check` | TypeScript helpers for creating validation checks | | `BuiltInAction` | Type for built-in action definitions (`name` + `description`) | | `ActionBinding` | Action binding type (includes `preventDefault` field) |
Voir sur GitHub