mirror of
https://github.com/vercel-labs/json-render.git
synced 2026-10-15 05:29:19 +08:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72568f990e | ||
|
|
5473fe1314 | ||
|
|
85a7fa0091 | ||
|
|
fc2a696a50 |
+23
-2
@@ -1,9 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
## 0.21.0
|
||||
## 0.21.1
|
||||
|
||||
<!-- release:start -->
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Dotted form values:** Preserve literal emails, URLs, and version strings in form value lookups instead of treating them as missing state paths (#353)
|
||||
- **Numeric validation:** Reject partially numeric strings such as `"123abc"`, empty strings, and whitespace-only strings instead of accepting them as numbers (#389)
|
||||
- **Schema type inference:** Infer `s.any()` fields as `any`, matching `z.any()`, so validated specs remain assignable to `Spec` without casts (#390)
|
||||
|
||||
### Documentation
|
||||
|
||||
- Migrated the **docs site** to Geistdocs while preserving public URLs, page content, and anchors (#340)
|
||||
- Updated **native WebMCP discovery and search** with the Geistdocs MCP adapter (#363)
|
||||
|
||||
### Contributors
|
||||
|
||||
- @ctate
|
||||
- @Railly
|
||||
- @fix2015
|
||||
- @kevin9327
|
||||
- @tmchow
|
||||
<!-- release:end -->
|
||||
|
||||
## 0.21.0
|
||||
|
||||
### New Features
|
||||
|
||||
- **TanStack Start renderer:** Added `@json-render/tanstack-start` for JSON-defined applications with file-based routes, reusable layouts, SSR loaders, head metadata, prerender paths, client navigation, and route fallbacks (#334)
|
||||
@@ -19,7 +41,6 @@
|
||||
|
||||
- @ctate
|
||||
- @Railly
|
||||
<!-- release:end -->
|
||||
|
||||
## 0.20.0
|
||||
|
||||
|
||||
@@ -4,6 +4,28 @@ title: "Changelog"
|
||||
|
||||
Notable changes and updates to json-render.
|
||||
|
||||
## v0.21.1
|
||||
|
||||
October 13, 2026
|
||||
|
||||
### Fixed: Dotted Form Values
|
||||
|
||||
Form value lookups now preserve literal emails, URLs, and version strings instead of treating them as missing state paths.
|
||||
|
||||
### Fixed: Numeric Validation
|
||||
|
||||
The `numeric` validator now rejects partially numeric strings such as `"123abc"`, empty strings, and whitespace-only strings instead of accepting them as numbers.
|
||||
|
||||
### Fixed: Schema Type Inference
|
||||
|
||||
`s.any()` fields now infer as `any`, matching `z.any()`, so validated specs remain assignable to `Spec` without casts.
|
||||
|
||||
### Improved: Documentation
|
||||
|
||||
Migrated the docs site to Geistdocs while preserving public URLs, page content, and anchors. Updated native WebMCP discovery and search with the Geistdocs MCP adapter.
|
||||
|
||||
---
|
||||
|
||||
## v0.21.0
|
||||
|
||||
September 18, 2026
|
||||
|
||||
+3
-3
@@ -2139,9 +2139,9 @@
|
||||
"title": "Changelog",
|
||||
"metadataTitle": "Changelog | json-render",
|
||||
"prefix": "import { pageMetadata } from \"@/lib/page-metadata\"\nexport const metadata = pageMetadata(\"docs/changelog\")\n\n# Changelog\n",
|
||||
"sourceSha256": "645da4f33e85ac7bcb1642100bb0bde339dd2976c29f8501317f296c308e645e",
|
||||
"bodySha256": "54a0b41153dd3afd0a0c69ef4c19575978615420eaf15075952b5c317b6a6b1c",
|
||||
"markdownSha256": "73fa2d642e3235a7841b196625b948db486473c24c41deec1dbba07583706e2b",
|
||||
"sourceSha256": "ad86126e05152567880b659abff2b27d88cc7b696d27b8c6640dda13c38dc9c3",
|
||||
"bodySha256": "586921975f057696b57045a41fbdeba5d4f469a48592ea604f0262d65be3b74b",
|
||||
"markdownSha256": "3836699e187adc31520d62b168b1f921b7f9df4272798ebc28d90bc76272b063",
|
||||
"headings": [
|
||||
{
|
||||
"title": "v0.21.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/codegen",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Utilities for generating code from json-render UI trees",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/core",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "JSON becomes real things. Define your catalog, register your components, let AI generate.",
|
||||
"keywords": [
|
||||
@@ -47,6 +47,7 @@
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"dev": "tsup --watch",
|
||||
"check-types": "tsc -p tsconfig.check.json",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { z } from "zod";
|
||||
import { defineSchema, defineCatalog } from "./schema";
|
||||
import type { Spec } from "./types";
|
||||
|
||||
// =============================================================================
|
||||
// Shared test schema (mirrors the React schema shape)
|
||||
@@ -565,6 +566,21 @@ describe("catalog.validate", () => {
|
||||
actions: {},
|
||||
});
|
||||
|
||||
it("returns data assignable to Spec", () => {
|
||||
const result = catalog.validate({
|
||||
root: "card-1",
|
||||
elements: {
|
||||
"card-1": { type: "Card", props: { title: "Hello" }, children: [] },
|
||||
},
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success && result.data) {
|
||||
// s.any() fields such as `visible` must not infer as unknown.
|
||||
const spec: Spec = result.data;
|
||||
expect(spec.root).toBe("card-1");
|
||||
}
|
||||
});
|
||||
|
||||
it("validates a valid spec", () => {
|
||||
const spec = {
|
||||
root: "card-1",
|
||||
|
||||
@@ -355,7 +355,7 @@ type InferSpecField<T, TCatalog> =
|
||||
: T extends SchemaType<"propsOf", infer Path>
|
||||
? InferPropsOfType<Path, TCatalog>
|
||||
: T extends SchemaType<"any">
|
||||
? unknown
|
||||
? any
|
||||
: unknown;
|
||||
|
||||
type InferRefType<Path, TCatalog> = Path extends "catalog.components"
|
||||
|
||||
@@ -152,6 +152,16 @@ describe("builtInValidationFunctions", () => {
|
||||
expect(builtInValidationFunctions.numeric(NaN)).toBe(false);
|
||||
expect(builtInValidationFunctions.numeric(null)).toBe(false);
|
||||
});
|
||||
|
||||
it("fails for strings with trailing non-numeric characters", () => {
|
||||
expect(builtInValidationFunctions.numeric("123abc")).toBe(false);
|
||||
expect(builtInValidationFunctions.numeric("99bottles")).toBe(false);
|
||||
});
|
||||
|
||||
it("fails for empty and whitespace-only strings", () => {
|
||||
expect(builtInValidationFunctions.numeric("")).toBe(false);
|
||||
expect(builtInValidationFunctions.numeric(" ")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("url", () => {
|
||||
|
||||
@@ -153,7 +153,9 @@ export const builtInValidationFunctions: Record<string, ValidationFunction> = {
|
||||
*/
|
||||
numeric: (value: unknown) => {
|
||||
if (typeof value === "number") return !isNaN(value);
|
||||
if (typeof value === "string") return !isNaN(parseFloat(value));
|
||||
if (typeof value === "string") {
|
||||
return value.trim() !== "" && !isNaN(Number(value));
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
// Type-checks the tests that assert inferred types. The full core
|
||||
// project is not type-checked in CI yet.
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["src/schema.test.ts"]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/devtools-react",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "React adapter for @json-render/devtools. Drop-in <JsonRenderDevtools /> component.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/devtools-solid",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SolidJS adapter for @json-render/devtools. Drop-in <JsonRenderDevtools /> component.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/devtools-svelte",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Svelte adapter for @json-render/devtools. Drop-in <JsonRenderDevtools /> component.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/devtools-vue",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Vue adapter for @json-render/devtools. Drop-in <JsonRenderDevtools /> component.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/devtools",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Framework-agnostic devtools core for json-render: event store, panel UI, picker, stream taps.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/directives",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Pre-built directives for @json-render/core — $format, $math, $concat, $count, $truncate, $pluralize, $join, and $t (i18n).",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/image",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Image renderer for @json-render/core. JSON becomes SVG and PNG images via Satori.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/ink",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Ink terminal renderer for @json-render/core. JSON becomes terminal UIs.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/jotai",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Jotai adapter for json-render StateStore",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/mcp",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "MCP Apps integration for @json-render/core. Serve json-render UIs as interactive MCP Apps in Claude, ChatGPT, Cursor, and VS Code.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/next",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Next.js renderer for @json-render/core. JSON becomes full Next.js applications with routes, layouts, metadata, and SSR.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/react-email",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "React Email renderer for @json-render/core. JSON becomes HTML emails.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/react-native",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "React Native renderer for @json-render/core. JSON becomes React Native components.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/react-pdf",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "React PDF renderer for @json-render/core. JSON becomes PDF documents.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/react-three-fiber",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "React Three Fiber renderer for @json-render/core. JSON becomes 3D scenes.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/react",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "React renderer for @json-render/core. JSON becomes React components.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/redux",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Redux adapter for json-render StateStore",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/remotion",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Remotion renderer for @json-render/core. JSON becomes video compositions.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/shadcn-svelte",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "shadcn-svelte component library for @json-render/svelte. JSON becomes beautiful Tailwind-styled Svelte components.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/shadcn",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "shadcn/ui component library for @json-render/core. JSON becomes beautiful Tailwind-styled React components.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/solid",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "SolidJS renderer for @json-render/core. JSON becomes Solid components.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/svelte",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Svelte 5 renderer for @json-render/core. JSON becomes Svelte components.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/tanstack-start",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "TanStack Start renderer for @json-render/core. JSON becomes full TanStack Start applications with routes, layouts, head metadata, and SSR.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/vue",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Vue renderer for @json-render/core. JSON becomes Vue components.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/xstate",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "XState Store adapter for json-render StateStore",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/yaml",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "YAML wire format for @json-render/core. Progressive rendering and surgical edits via streaming YAML.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@json-render/zustand",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Zustand adapter for json-render StateStore",
|
||||
"keywords": [
|
||||
|
||||
Reference in New Issue
Block a user