---
id: sm-json-render-core
name: "json-render-core"
url: https://skills.yangsir.net/skill/sm-json-render-core
author: vercel-labs
domain: ai-backend-engineering
tags: ["json-processing", "data-serialization", "api-responses", "backend-development", "vercel"]
install_count: 356
rating: 4.10 (72 reviews)
github: https://github.com/vercel-labs/json-render
---

# json-render-core

> 提供JSON渲染的核心功能，包括Schema定义、目录创建和规范流处理，用于构建动态内容和组件。

**Stats**: 356 installs · 4.1/5 (72 reviews)

## Before / After 对比

### 优化JSON渲染核心功能，提升动态内容生成效率

## Readme

# json-render-core

# @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

```
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

```
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

```
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):

```
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`).

```
{
  "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" }
    }
  }
}

```

```
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:

```
{
  "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:

```
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:

```
import { buildUserPrompt } from "@json-render/core";

// Fresh generation
buildUserPrompt({ prompt: "create a todo app" });

// Refinement (patch-only mode)
buildUserPrompt({ prompt: "add a toggle", currentSpec: spec });

// With runtime state
buildUserPrompt({ prompt: "show data", state: { todos: [] } });

```

## Spec Validation

Validate spec structure and auto-fix common issues:

```
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 }`.

```
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:

```
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:

```
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

`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)

Weekly Installs340Repository[vercel-labs/json-render](https://github.com/vercel-labs/json-render)GitHub Stars12.7KFirst SeenFeb 6, 2026Security Audits[Gen Agent Trust HubPass](/vercel-labs/json-render/json-render-core/security/agent-trust-hub)[SocketPass](/vercel-labs/json-render/json-render-core/security/socket)[SnykPass](/vercel-labs/json-render/json-render-core/security/snyk)Installed oncodex316opencode315gemini-cli311github-copilot309amp294kimi-cli293

---
*Source: https://skills.yangsir.net/skill/sm-json-render-core*
*Markdown mirror: https://skills.yangsir.net/api/skill/sm-json-render-core/markdown*