关于 core
@json-render/core 是用于构建 json-render 应用的 TypeScript 核心包,面向需要定义规范、组件目录并处理 AI 生成界面的开发者。它提供规范流、验证和状态表达式,也包含实验性的决策模型组合 API。
主要功能
- 01定义 schema 和组件目录
- 02生成提示词并流式处理规范
- 03解析状态绑定与可见性表达式
- 04验证并修复规范结构
- 05组合和编辑决策模型规范
适用场景
- 01为界面生成定义组件目录
- 02逐步处理 JSONL 规范流
- 03验证生成的界面规范
- 04按候选组件组合或修改界面
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ vercel-labs/ json-render --skill core安装后在 Claude Code 中输入/core确认已加载。
详细介绍
@json-render/core
用于定义架构、创建目录和流式传输规范的核心包。
核心概念
- Schema:定义规范和目录的结构(使用
defineSchema) - Catalog:将组件/操作名称映射到其定义(使用
defineCatalog) - Spec:符合架构的 AI JSON 输出
- SpecStream:用于渐进式构建规范的 JSONL 流式格式
实验性决策模型组合
要组合决策模型,请从 @json-render/core 导入 experimental_composeSpec 和 experimental_createEvaluator。这些 API 自 v0.21.0 起可用;请固定使用精确版本,并确保所有 json-render 包的版本相同。实验性导出和 Experimental_ 类型可能在任何版本中发生变化。
- 在服务端使用
{ model: "typesafe-ai/jev", apiKey: process.env.AI_GATEWAY_API_KEY! }运行 Gateway 评估器。必须使用纯模型标识符;Jev 是当前示例;不要导入提供商构造函数。 - 调用
experimental_composeSpec({ catalog, candidates, prompt, evaluate, initialState, signal })。它是异步生成器;将step.spec快照流式传给现有渲染器,并检查complete.stopReason(finish、limit、unavailable)。错误和取消会抛出异常;保留最后一个快照作为部分 UI。 - 新树默认使用
strategy: "batch":一次评估选择根元素和成员,必要时再进行第二次评估来排列所选元素。第一个快照会将所选内容按目录顺序放在根元素的默认/首个插槽下。资源变体共用一个互斥问题;重复计数包含根元素。对于相同的配方/资源,根元素选择优先于冲突的推测成员关系。位置相同的同级元素保留目录顺序。组合布局会在发布前进行验证;出现循环或深度超限时会抛出异常。maxElements限制批量创建的元素数量(默认值为 32)。选择被限制截断或缺少必要布局调用时,会返回limit。对于旧版next/parent适配器或顺序创建,请使用strategy: "sequential"。编辑始终按顺序进行。 - 批量追踪步骤使用
choice: "select" | "layout"和answers记录。每条追踪都计为一次评估,其令牌和延迟也只计算一次。自定义评估器必须回答所有已提供的问题;名称/选项均为不透明值。批量操作依次包含root/select_*,然后是parent_*/order_*。 - 对于后续编辑,将选定版本作为
initialSpec传入。它会被克隆并验证;评估器可以添加、替换、移除非根子树,或移动/重新排序这些子树。不变的 ID、绑定和状态会保留。可选的elementDescriptions会共享用于识别的描述,但不会暴露原始 props/state。initialState会覆盖种子状态。种子必须是符合目录、表达式子集和深度限制的有效树。匹配配方会消耗使用次数/资源限制;移除/替换会释放这些限制。替换/移动需要两次评估(选择目标,然后选择配方/目的地),每次都计入预算。将操作键和位置键视为不透明值。 - 提供原子候选项
{ id, description, element: { type, props, on?, visible? }, root?, maxUses?, resource? }。仅有目录并不足够:应用必须提供值和绑定配方。Jev 只选择元素和父级插槽,不会生成自由文本或代码。它不会执行操作。 - 候选项是已配置的组件实例,而不是页面模板。根据当前应用记录/操作构建候选项,或将 props 绑定到
initialState;为图表类型、字段配置和布局变体提供明确选项。模型会在这些选项范围内选择分组和顺序。在提示词中注明必需的部分;结构有效并不意味着语义完整。 - V1 支持扁平 Spec 目录、命名插槽、字面量、
$state、$bindState和状态可见性。不支持预置子元素、repeat/watch、computed/template/conditional props 或自定义指令。成功/错误回调必须引用允许的操作。事件必须在组件目录中声明。 - Props 和操作参数会根据初始状态进行验证,但不会应用 schema 转换/默认值。请提供有效的初始值,并在运行时验证/授权操作调用。没有参数 schema 的内置项只会进行名称验证。
root默认值为 true,maxUses默认值为 one,共享的resource值会使候选项互斥。默认值:32 次评估(包含终止调用;批量操作不会额外进行 finish 调用)、深度为 8、每次 Gateway 调用超时为 10 秒。请提供整体中止信号。- 候选项描述、提示词、指令、拓扑和显式
context会发送给评估器。初始状态和原始 props/绑定值不会自动发送。 - 对于自定义提供商,请实现
Experimental_CompositionEvaluator:接收{ state, questions, signal },返回{ answers: { [question]: { choice, confidence? } }, usage?: { inputTokens? } }。仅返回已提供的 criteria 键。 请参阅packages/core/README.md和/docs/jev,了解应用集成和安装说明。Web playground 是一个示例使用方,并非 API 的依赖项。
定义 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
});
创建目录
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",
},
},
});
生成 AI 提示词
const systemPrompt = catalog.prompt(); // Uses schema's promptTemplate
const systemPrompt = catalog.prompt({ customRules: ["Rule 1", "Rule 2"] });
SpecStream 工具
用于流式传输 AI 响应(JSONL 补丁):
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();
操作处理程序中的表单值
使用 findFormValue("email", params, state),读取直接参数、点分隔的参数键(例如 "form.email")、匹配的扁平状态键,或嵌套状态中的斜杠分隔路径(例如 "/form/email")。参数值按字面处理,因此电子邮件和 URL 中的点号会保留。对于读取嵌套状态的操作绑定,请使用 { $state: "/form/email" };解析器会将该值传递给处理程序。单独的 "email" 字段名不会搜索嵌套的 state.form.email。
动态 Prop 表达式
任何 prop 值都可以是渲染时解析的动态表达式:
{ "$state": "/state/key" }- 读取状态模型中的值(单向读取){ "$bindState": "/path" }- 双向绑定:读取状态并启用写回。在表单组件的自然值 prop(value、checked、pressed 等)上使用。{ "$bindItem": "field" }- 双向绑定到重复项字段。在重复项作用域内使用。{ "$cond": <condition>, "$then": <value>, "$else": <value> }- 计算可见性条件并选择一个分支{ "$template": "Hello, ${/user/name}!" }- 使用状态值插入${/path}引用{ "$computed": "fnName", "args": { "key": <expression> } }- 使用解析后的参数调用已注册函数
$cond 使用与可见性条件相同的语法($state、eq、neq、not,数组表示 AND)。$then 和 $else 本身也可以是表达式(递归)。
组件不使用 statePath prop 进行双向绑定。相反,请在自然值 prop(例如 value、checked、pressed)上使用 { "$bindState": "/path" }。
{
"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 });
状态观察器
元素可以声明 watch 字段(顶层,与 type/props/children 同级),在状态值发生变化时触发操作:
{
"type": "Select",
"props": { "value": { "$bindState": "/form/country" }, "options": ["US", "Canada"] },
"watch": {
"/form/country": { "action": "loadCities", "params": { "country": { "$state": "/form/country" } } }
},
"children": []
}
观察器只会在值发生变化时触发,不会在初始渲染时触发。
验证
内置验证函数:required、email、url、numeric、minLength、maxLength、min、max、pattern、matches、equalTo、lessThan、greaterThan、requiredIf。
跨字段验证在参数中使用 $state 表达式:
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");
用户提示词构建器
构建结构化的用户提示词,可选择优化 spec 并加入状态上下文:
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: [] } });
可用的编辑模式:"patch"(RFC 6902 JSON Patch)、"merge"(RFC 7396 Merge Patch)、"diff"(统一 diff)。
Spec 验证
验证 spec 结构并自动修正常见问题:
import { validateSpec, autoFixSpec } from "@json-render/core";
const { valid, issues } = validateSpec(spec);
// issues include: missing_child, invalid_visible (malformed conditions),
// repeat_without_children, repeat_item_outside_scope, repeat_state_mismatch
const { spec: fixed, fixDetails } = autoFixSpec(spec);
// fixDetails entries are { message, lossy }. Lossless fixes relocate
// misplaced fields; lossy fixes prune dangling children references.
// In a repair loop, withhold lossy fixes until retries are exhausted:
const attempt = autoFixSpec(spec, { lossy: retriesExhausted });
可见性条件
使用基于状态的条件控制元素可见性。VisibilityContext 是 { 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
Schema 中的内置操作
Schema 可以声明 builtInActions ——始终可在运行时使用并自动注入提示词的操作:
const schema = defineSchema(builder, {
builtInActions: [
{ name: "setState", description: "Update a value in the state model" },
],
});
这些操作会在提示词中显示为 [built-in],且无需在 defineRegistry 中设置处理程序。
StateStore
StateStore 接口允许将外部状态管理库(Redux、Zustand、XState 等)接入 json-render 渲染器。createStateStore 工厂会创建一个简单的内存实现:
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 }
});
StateStore 接口:get(path)、set(path, value)、update(updates)、getSnapshot()、subscribe(listener)。
主要导出
| 导出 | 用途 |
|---|---|
defineSchema | 创建新架构 |
defineCatalog | 根据架构创建目录 |
createStateStore | 创建与框架无关的内存 StateStore |
resolvePropValue | 根据数据解析单个属性表达式 |
resolveElementProps | 解析元素中的所有属性表达式 |
buildUserPrompt | 构建包含优化和状态上下文的用户提示词 |
buildEditUserPrompt | 构建用于编辑现有规范的用户提示词 |
buildEditInstructions | 生成包含可用编辑模式的提示词部分 |
isNonEmptySpec | 检查规范是否包含根节点和至少一个元素 |
deepMergeSpec | RFC 7396 深度合并(null 表示删除,数组替换,递归合并对象) |
diffToPatches | 根据对象差异生成 RFC 6902 JSON Patch 操作 |
EditMode | 类型:"patch" | "merge" | "diff" |
validateSpec | 验证规范结构 |
autoFixSpec | 自动修复常见的规范问题;将修复分为有损和无损,{ lossy: false } 会禁用剪枝 |
createSpecStreamCompiler | 将 JSONL 补丁流式写入规范 |
createJsonRenderTransform | 用于在混合流中分离文本与 JSONL 的 TransformStream |
parseSpecStreamLine | 解析单行 JSONL |
applySpecStreamPatch | 将补丁应用于对象 |
StateStore | 用于接入外部状态管理的接口 |
ComputedFunction | $computed 表达式的函数签名 |
check | 用于创建验证检查项的 TypeScript 辅助工具 |
BuiltInAction | 内置操作定义的类型(name + description) |
ActionBinding | 操作绑定类型(包含 preventDefault 字段) |