mcpField
J
json-render-core

json-render-core

github.com/vercel-labs開発18.8k340 回インストール5 日前に更新
リポジトリ

json-render-core について

@json-render/coreは、AI生成UIの構造を定義する開発者向けに、json-renderのスキーマ、カタログ、仕様ストリーミングを提供します。動的プロパティの解決、検証、外部状態ストア用インターフェースも備えています。

主な機能

  1. 01スキーマとコンポーネントカタログの定義
  2. 02AIプロンプトの生成
  3. 03JSONL仕様パッチのストリーミング
  4. 04状態駆動の動的プロパティ解決
  5. 05仕様の検証と自動修正
  6. 06交換可能な状態ストアインターフェース

活用シーン

  1. 01AI生成UIの構造定義
  2. 02ストリーミング仕様出力の逐次処理
  3. 03生成仕様の検証や修正

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/vercel-labs/json-render --skill json-render-core

インストール後、Claude Code で/json-render-coreを入力して読み込まれたか確認します。

詳細

@json-render/core

スキーマ定義、カタログ作成、仕様のストリーミングを行うコアパッケージです。

主な概念

  • スキーマ:仕様とカタログの構造を定義します(defineSchema を使用)
  • カタログ:コンポーネント名/アクション名を定義に対応付けます(defineCatalog を使用)
  • 仕様:スキーマに準拠した、AI による JSON 出力です
  • SpecStream:仕様を段階的に構築するための JSONL ストリーミング形式です

スキーマの定義

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();

動的なプロパティ式

レンダリング時に解決される動的な式を、任意のプロパティ値として指定できます。

  • { "$state": "/state/key" } - 状態モデルから値を読み取ります(単方向の読み取り)
  • { "$bindState": "/path" } - 双方向バインディングです。状態を読み取り、書き戻しを有効にします。フォームコンポーネントの自然な値プロパティ(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 プロパティを使用しません。代わりに、自然な値プロパティ(例: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");

ユーザープロンプトビルダー

仕様の任意の調整や状態コンテキストを含む、構造化されたユーザープロンプトを作成します。

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: [] } });

仕様のバリデーション

仕様の構造を検証し、よくある問題を自動修正します。

import { validateSpec, autoFixSpec } from "@json-render/core";

const { valid, issues } = validateSpec(spec);
const fixed = autoFixSpec(spec);

表示条件

状態に基づく条件で要素の表示を制御します。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

スキーマの組み込みアクション

スキーマでは 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改良内容と状態コンテキストを含むユーザープロンプトを作成します
validateSpec仕様の構造を検証します
autoFixSpecよくある仕様の問題を自動修正します
createSpecStreamCompilerJSONL パッチを仕様にストリーミングします
createJsonRenderTransform混在ストリーム内のテキストと JSONL を分離する TransformStream を作成します
parseSpecStreamLine単一の JSONL 行を解析します
applySpecStreamPatchオブジェクトにパッチを適用します
StateStore外部の状態管理を組み込むためのインターフェースです
ComputedFunction$computed 式の関数シグネチャです
check検証チェックを作成するための TypeScript ヘルパーです
BuiltInAction組み込みアクション定義の型です(name + description)
ActionBindingアクションバインディングの型です(preventDefault フィールドを含みます)

コメント