@wevu/json-render 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 ice breaker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,158 @@
1
+ # @wevu/json-render
2
+
3
+ json-render 的 Wevu 微信小程序适配层。复用 `@json-render/core@0.21.0` 的表达式、绑定与 SpecStream 解析,以预编译 SFC 渲染界面,并通过小程序泛型组件接入业务组件。
4
+
5
+ 当前为实验性 workspace 包,尚未发布到 npm;首轮仅承诺本页列出的协议子集与微信目标。不会在 AppService 中生成模板或执行模型返回的代码。
6
+
7
+ ## 安装与构建配置
8
+
9
+ 仓库内的消费项目添加 `"@wevu/json-render": "workspace:*"` 与 `"@wevu/json-render-components": "workspace:*"`,并保留 `wevu` 和 `zod` 依赖。小程序 npm 构建按应用显式依赖识别组件包,因此配套组件也要列入应用 dependencies;业务代码只导入主包 API。包先构建,再构建应用:
10
+
11
+ ```sh
12
+ pnpm --filter @wevu/json-render-components build
13
+ pnpm --filter @wevu/json-render build
14
+ pnpm --filter wevu-json-render-demo build
15
+ ```
16
+
17
+ 注册构建期 resolver,使用包内由 weapp-vite lib 模式预编译的组件:
18
+
19
+ ```ts
20
+ import { JsonRendererResolver } from '@wevu/json-render/resolver'
21
+ import { defineConfig } from 'weapp-vite/config'
22
+
23
+ export default defineConfig({
24
+ weapp: {
25
+ autoImportComponents: { resolvers: [JsonRendererResolver()] },
26
+ },
27
+ })
28
+ ```
29
+
30
+ `/resolver` 是独立的构建入口。主包保持 ESM 运行时入口,响应式 API 随宿主应用打包。自动依赖的 `@wevu/json-render-components` 通过 Vite/Rolldown lib emit 产出递归组件与默认组件,其 `miniprogram` 字段用于宿主 npm 解析。两者分开,避免响应式 API 进入另一份原生 npm 运行时。无需复制组件源码;应用需要显式声明配套组件依赖,resolver 负责组件注册。
31
+
32
+ ## 目录、状态与动作
33
+
34
+ ```ts
35
+ import type { CatalogSpec } from '@wevu/json-render'
36
+ import { defineRendererCatalog, standardComponents, useJsonRenderer } from '@wevu/json-render'
37
+ import { z } from 'zod'
38
+
39
+ z.config({ jitless: true })
40
+
41
+ const catalog = defineRendererCatalog({
42
+ components: {
43
+ ...standardComponents,
44
+ Counter: {
45
+ props: z.object({ value: z.number() }).strict(),
46
+ events: ['increase'],
47
+ },
48
+ },
49
+ actions: { increase: z.object({ step: z.number() }).strict() },
50
+ })
51
+
52
+ const spec: CatalogSpec<typeof catalog> = {
53
+ root: 'counter',
54
+ elements: {
55
+ counter: {
56
+ type: 'Counter',
57
+ props: { value: { $state: '/count' } },
58
+ on: { increase: { action: 'increase', params: { step: 1 } } },
59
+ },
60
+ },
61
+ }
62
+
63
+ // 在页面或组件同步 setup 中调用。
64
+ const renderer = useJsonRenderer({
65
+ catalog,
66
+ spec,
67
+ initialState: { count: 0 },
68
+ actions: {
69
+ increase({ step }, context) {
70
+ context.setState('/count', context.state.count + step)
71
+ },
72
+ },
73
+ })
74
+ const tree = renderer.tree
75
+ const onNodeEvent = renderer.dispatch
76
+ ```
77
+
78
+ `props` schema 校验表达式求值后的属性;动作参数在执行前校验,因此尚未填写的表单不会因动作参数校验而阻止首屏渲染。输入绑定由组件目录的 `bindings` 映射声明,例如 `{ value: 'input' }`;对应事件携带 `value`,由适配层写回 `$bindState` 指向的现有状态路径。
79
+
80
+ `CatalogSpec<typeof catalog>` 推导组件名称、属性类型和动作参数;`ActionHandlers` 推导处理器参数和业务状态。运行时仍验证从网络等边界传入的未知数据。
81
+
82
+ ## 自定义组件
83
+
84
+ 在页面 JSON 中静态注册业务节点,模板中将其传给 renderer 的 `custom-node` 泛型:
85
+
86
+ ```vue
87
+ <script setup lang="ts">
88
+ definePageJson({
89
+ usingComponents: { 'business-node': '/components/business-node/index' },
90
+ })
91
+ // tree 与 onNodeEvent 来自上面的 renderer。
92
+ </script>
93
+
94
+ <template>
95
+ <json-renderer v-if="tree" :node="tree" generic:custom-node="business-node" @node-event="onNodeEvent" />
96
+ </template>
97
+ ```
98
+
99
+ 业务节点接收 `RenderNode`,通过静态分支选择预注册组件,通过 `node-event` 发出 `RendererEvent`。Wevu 自定义事件会解包 detail;原生 input 事件仍读取 `event.detail.value`。
100
+
101
+ ```vue
102
+ <script setup lang="ts">
103
+ import type { RendererEvent, RenderNode } from '@wevu/json-render'
104
+
105
+ const props = defineProps<{ node: RenderNode }>()
106
+ const emit = defineEmits<{ (event: 'node-event', payload: RendererEvent): void }>()
107
+ function increase() {
108
+ emit('node-event', { id: props.node.id, name: 'increase' })
109
+ }
110
+ </script>
111
+
112
+ <template>
113
+ <view v-if="props.node.type === 'Counter'">
114
+ <text>{{ props.node.props.value }}</text>
115
+ <button @tap="increase">增加</button>
116
+ </view>
117
+ </template>
118
+ ```
119
+
120
+ 业务容器可在目录中声明 `container: true`,并在自己的模板里提供默认 `<slot />` 接收渲染后的子节点。泛型映射逐层传递,组件身份以 spec 节点 ID 保持。只有基础控件的界面可不提供业务节点;使用自定义类型时必须注册对应分支。本包不使用 `<component :is>`,也不承诺 Web Vue 的 VNode 语义。
121
+
122
+ ## 会话 API
123
+
124
+ | API | 行为 |
125
+ | --- | --- |
126
+ | `createJsonRenderer(options)` | 创建独立会话,由调用者负责 `dispose()` |
127
+ | `useJsonRenderer(options)` | 在同步 setup 中创建会话,自动绑定页面/组件卸载清理 |
128
+ | `state` | 唯一的响应式业务状态;通过 `setState` 更新,避免绕过路径和 props 校验 |
129
+ | `spec` / `tree` | 当前完整描述和求值后的节点树,均为 ref;通过方法更新描述 |
130
+ | `error` / `pending` | 最近的适配错误和执行中的 `节点ID:动作名` 列表 |
131
+ | `dispatch(event)` | 输入回写及动作调度,返回 `Promise<boolean>`;忽略已移除/不可见节点和未声明事件,同一节点的同名进行中动作去重 |
132
+ | `setState(path, value)` | 写入现有 JSON Pointer 路径,校验可序列化值与当前可见 props,不存在或非法路径抛错 |
133
+ | `load(spec, nextState?)` | 校验后替换描述;取消旧动作与流,不传第二参则保留业务状态;失败保留旧界面并返回 false |
134
+ | `createStream(initialSpec?)` | 开始新流,旧流失效;可用完整初始描述重播 UI,同时保留状态和进行中的业务动作 |
135
+ | `stream.push(text, done?)` | 应用字符串分块,返回是否提交了完整新描述;部分行/暂缺引用返回 false,错误记录到 `error` |
136
+ | `stream.dispose()` / `dispose()` | 停止当前流 / 清理会话,重复调用安全 |
137
+
138
+ 异步动作通过 `context.setState` 提交结果,重置或卸载后的旧上下文不会写入新会话。`context.isActive()` 可判断是否仍有效;用 `context.onCleanup(fn)` 注册计时器、请求等资源的清理函数,动作结束、会话重置或卸载时执行一次。清理函数应同时让已取消的异步等待结束。本包不假设宿主存在 AbortController,不接管网络传输。
139
+
140
+ ## 协议与边界
141
+
142
+ - 基础组件:`Stack`、`Card`、`Text`、`Input`、`Button`,可扩展目录和自定义组件。
143
+ - 属性表达式:`$state`;声明过绑定的顶层属性可使用 `$bindState`。不接受任意函数或动态代码。
144
+ - 可见性:布尔值,或 `$state` 配合 `eq`、`not: true`。
145
+ - 事件:`on[event] = { action, params? }`;参数支持 `$state`。
146
+ - 流式协议:JSONL 的 `add`、`replace`、`remove`,仅允许 `/root` 和 `/elements`。先挂引用后补节点可暂存,结束时必须形成完整合法树。
147
+ - 默认上限:200 个节点、8 层深度、单次待解析缓冲 65536 个字符,通过 `limits` 配置正整数。
148
+ - 不支持 repeat、slots 协议字段、watch、computed/cond 指令、action chains 或远程 state patch;未知能力明确拒绝。自定义容器的本地默认插槽不等于支持上游 slots 协议。
149
+ - 业务状态独立于 spec,只接受 JSON 数据;JSON Pointer 支持 `~0`/`~1` 转义,拒绝原型链键和不存在的状态路径。
150
+ - 在 Core 初始化前将共享 Zod 配置为 `jitless: true`,这是刻意的全局配置副作用;消费项目不要随后重新开启 JIT;消费端直接导入 Zod 自建 schema 时,也应在创建 schema 前执行 `z.config({ jitless: true })`,不依赖打包边界外的实例配置。
151
+
152
+ ## 验证与发布边界
153
+
154
+ 包级单测使用独立的搜索/计数目录,覆盖绑定、动作参数、去重、取消、结构校验和事务化 Patch;tsd 锁定公开类型。售后 demo 仅通过包公开入口消费,并以构建后的隔离执行检查保证没有动态求值尝试。
155
+
156
+ `apps/wevu-json-render-demo` 与 `e2e/ide/wevu-json-render.runtime.test.ts` 提供 headless/真实 DevTools 的同场景验收,包括自定义订单节点及其事件。simulator 的 `recursiveProps` Node、browser 单测和浏览器回归覆盖对象属性隔离与泛型递归传递。
157
+
158
+ 此包未实现模型调用、真实网络分块解码、其他平台适配或完整上游 renderer 行为,也未执行 npm 发布。
@@ -0,0 +1,42 @@
1
+ import { RendererCatalog } from "./types.mjs";
2
+ import { z } from "zod";
3
+ //#region src/catalog.d.ts
4
+ /** 保留组件、动作及其参数 schema 的类型推导。 */
5
+ export declare function defineRendererCatalog<const C extends RendererCatalog>(catalog: C): C;
6
+ export declare const standardComponents: {
7
+ readonly Stack: {
8
+ readonly props: z.ZodObject<{}, z.core.$strict>;
9
+ readonly container: true;
10
+ };
11
+ readonly Card: {
12
+ readonly props: z.ZodObject<{
13
+ title: z.ZodString;
14
+ }, z.core.$strict>;
15
+ readonly container: true;
16
+ };
17
+ readonly Text: {
18
+ readonly props: z.ZodObject<{
19
+ text: z.ZodString;
20
+ }, z.core.$strict>;
21
+ };
22
+ readonly Input: {
23
+ readonly props: z.ZodObject<{
24
+ label: z.ZodString;
25
+ placeholder: z.ZodString;
26
+ value: z.ZodString;
27
+ }, z.core.$strict>;
28
+ readonly events: readonly ["input"];
29
+ readonly bindings: {
30
+ readonly value: "input";
31
+ };
32
+ };
33
+ readonly Button: {
34
+ readonly props: z.ZodObject<{
35
+ label: z.ZodString;
36
+ disabled: z.ZodOptional<z.ZodBoolean>;
37
+ }, z.core.$strict>;
38
+ readonly events: readonly ["press"];
39
+ };
40
+ };
41
+ //#endregion
42
+ //# sourceMappingURL=catalog.d.mts.map
@@ -0,0 +1,2 @@
1
+ import"./compat.mjs";import{z as e}from"zod";function t(e){return e}const n={Stack:{props:e.object({}).strict(),container:!0},Card:{props:e.object({title:e.string()}).strict(),container:!0},Text:{props:e.object({text:e.string()}).strict()},Input:{props:e.object({label:e.string(),placeholder:e.string(),value:e.string()}).strict(),events:[`input`],bindings:{value:`input`}},Button:{props:e.object({label:e.string(),disabled:e.boolean().optional()}).strict(),events:[`press`]}};export{t as defineRendererCatalog,n as standardComponents};
2
+ //# sourceMappingURL=catalog.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.mjs","names":[],"sources":["../src/catalog.ts"],"sourcesContent":["import type { RendererCatalog } from './types'\nimport { z } from 'zod'\nimport './compat'\n\n/** 保留组件、动作及其参数 schema 的类型推导。 */\nexport function defineRendererCatalog<const C extends RendererCatalog>(catalog: C): C {\n return catalog\n}\n\nexport const standardComponents = {\n Stack: { props: z.object({}).strict(), container: true },\n Card: { props: z.object({ title: z.string() }).strict(), container: true },\n Text: { props: z.object({ text: z.string() }).strict() },\n Input: {\n props: z.object({ label: z.string(), placeholder: z.string(), value: z.string() }).strict(),\n events: ['input'],\n bindings: { value: 'input' },\n },\n Button: {\n props: z.object({ label: z.string(), disabled: z.boolean().optional() }).strict(),\n events: ['press'],\n },\n} as const\n"],"mappings":"6CAKA,SAAgB,EAAuD,EAAe,CACpF,OAAO,CACT,CAEA,MAAa,EAAqB,CAChC,MAAO,CAAE,MAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,EAAG,UAAW,EAAK,EACvD,KAAM,CAAE,MAAO,EAAE,OAAO,CAAE,MAAO,EAAE,OAAO,CAAE,CAAC,CAAC,CAAC,OAAO,EAAG,UAAW,EAAK,EACzE,KAAM,CAAE,MAAO,EAAE,OAAO,CAAE,KAAM,EAAE,OAAO,CAAE,CAAC,CAAC,CAAC,OAAO,CAAE,EACvD,MAAO,CACL,MAAO,EAAE,OAAO,CAAE,MAAO,EAAE,OAAO,EAAG,YAAa,EAAE,OAAO,EAAG,MAAO,EAAE,OAAO,CAAE,CAAC,CAAC,CAAC,OAAO,EAC1F,OAAQ,CAAC,OAAO,EAChB,SAAU,CAAE,MAAO,OAAQ,CAC7B,EACA,OAAQ,CACN,MAAO,EAAE,OAAO,CAAE,MAAO,EAAE,OAAO,EAAG,SAAU,EAAE,QAAQ,CAAC,CAAC,SAAS,CAAE,CAAC,CAAC,CAAC,OAAO,EAChF,OAAQ,CAAC,OAAO,CAClB,CACF"}
@@ -0,0 +1,2 @@
1
+ import{z as e}from"zod";e.config({jitless:!0});export{};
2
+ //# sourceMappingURL=compat.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compat.mjs","names":[],"sources":["../src/compat.ts"],"sourcesContent":["import { z } from 'zod'\n\n// 必须先于 Core 的模块初始化执行,避免 Zod 构造 schema 时探测动态求值。\nz.config({ jitless: true })\n"],"mappings":"wBAGA,EAAE,OAAO,CAAE,QAAS,EAAK,CAAC"}
package/dist/core.mjs ADDED
@@ -0,0 +1 @@
1
+ import"./compat.mjs";import{createSpecStreamCompiler as e,evaluateVisibility as t,resolveBindings as n,resolveElementProps as r}from"@json-render/core";export{e as createSpecStreamCompiler,t as evaluateVisibility,n as resolveBindings,r as resolveElementProps};
@@ -0,0 +1,7 @@
1
+ import { ActionBinding, ActionContext, ActionHandlers, BindingExpression, CatalogSpec, ComponentDefinition, JsonValue, RenderNode, RendererCatalog, RendererEvent, RendererLimits, RendererOptions, RendererSpec, StateExpression, Visibility } from "./types.mjs";
2
+ import { defineRendererCatalog, standardComponents } from "./catalog.mjs";
3
+ import { createJsonRenderer } from "./renderer.mjs";
4
+ import { createSpecStream } from "./stream.mjs";
5
+ import { useJsonRenderer } from "./useRenderer.mjs";
6
+ import { validateRendererSpec } from "./validation.mjs";
7
+ export { type ActionBinding, type ActionContext, type ActionHandlers, type BindingExpression, type CatalogSpec, type ComponentDefinition, type JsonValue, type RenderNode, type RendererCatalog, type RendererEvent, type RendererLimits, type RendererOptions, type RendererSpec, type StateExpression, type Visibility, createJsonRenderer, createSpecStream, defineRendererCatalog, standardComponents, useJsonRenderer, validateRendererSpec };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ import{defineRendererCatalog as e,standardComponents as t}from"./catalog.mjs";import{validateRendererSpec as n}from"./validation.mjs";import{createSpecStream as r}from"./stream.mjs";import{createJsonRenderer as i}from"./renderer.mjs";import{useJsonRenderer as a}from"./useRenderer.mjs";export{i as createJsonRenderer,r as createSpecStream,e as defineRendererCatalog,t as standardComponents,a as useJsonRenderer,n as validateRendererSpec};
package/dist/path.mjs ADDED
@@ -0,0 +1,2 @@
1
+ function e(e){if(!e.startsWith(`/`)||/~(?![01])/u.test(e))throw Error(`无效的 JSON Pointer:${e}`);let t=e.slice(1).split(`/`).map(e=>e.replace(/~1/g,`/`).replace(/~0/g,`~`));if(t.some(e=>[`__proto__`,`prototype`,`constructor`].includes(e)))throw Error(`路径不能包含原型链键`);return t}function t(t,n){let r=t;for(let t of e(n)){if(Array.isArray(r)&&!/^(?:0|[1-9]\d*)$/.test(t))throw Error(`数组路径必须使用索引:${n}`);if(!r||typeof r!=`object`||!Object.prototype.hasOwnProperty.call(r,t))throw Error(`状态路径不存在:${n}`);r=r[t]}return r}function n(e,t=/* @__PURE__ */ new Set){if(e===null||typeof e==`string`||typeof e==`boolean`||typeof e==`number`&&Number.isFinite(e))return;if(!e||typeof e!=`object`||t.has(e))throw Error(`值必须是可序列化的 JSON 数据`);let r=Object.getPrototypeOf(e);if(!Array.isArray(e)&&r!==Object.prototype&&r!==null)throw Error(`值必须是普通 JSON 对象`);let i=new Set(t).add(e);for(let t of Object.values(e))n(t,i)}function r(e){return n(e),JSON.parse(JSON.stringify(e))}function i(n,i,a){t(n,i);let o=e(i),s=n;for(let e of o.slice(0,-1))s=s[e];s[o[o.length-1]]=r(a)}export{n as assertJson,r as cloneJson,e as parsePointer,t as readState,i as writeState};
2
+ //# sourceMappingURL=path.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.mjs","names":[],"sources":["../src/path.ts"],"sourcesContent":["import type { JsonValue } from './types'\n\n/** 解析 JSON Pointer,拒绝原型链键及不规范的转义。 */\nexport function parsePointer(path: string) {\n if (!path.startsWith('/') || /~(?![01])/u.test(path)) {\n throw new Error(`无效的 JSON Pointer:${path}`)\n }\n const parts = path.slice(1).split('/').map(part => part.replace(/~1/g, '/').replace(/~0/g, '~'))\n if (parts.some(part => ['__proto__', 'prototype', 'constructor'].includes(part))) {\n throw new Error('路径不能包含原型链键')\n }\n return parts\n}\n\nexport function readState(state: object, path: string): unknown {\n let current: unknown = state\n for (const part of parsePointer(path)) {\n if (Array.isArray(current) && !/^(?:0|[1-9]\\d*)$/.test(part)) {\n throw new Error(`数组路径必须使用索引:${path}`)\n }\n if (!current || typeof current !== 'object' || !Object.prototype.hasOwnProperty.call(current, part)) {\n throw new Error(`状态路径不存在:${path}`)\n }\n current = (current as Record<string, unknown>)[part]\n }\n return current\n}\n\n/** 在进入宿主数据层之前拒绝函数、循环、非有限数及非普通对象。 */\nexport function assertJson(value: unknown, ancestors = new Set<object>()): asserts value is JsonValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') {\n return\n }\n if (typeof value === 'number' && Number.isFinite(value)) {\n return\n }\n if (!value || typeof value !== 'object' || ancestors.has(value)) {\n throw new Error('值必须是可序列化的 JSON 数据')\n }\n const prototype = Object.getPrototypeOf(value)\n if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) {\n throw new Error('值必须是普通 JSON 对象')\n }\n const next = new Set(ancestors).add(value)\n for (const child of Object.values(value)) {\n assertJson(child, next)\n }\n}\n\nexport function cloneJson<T>(value: T): T {\n assertJson(value)\n return JSON.parse(JSON.stringify(value)) as T\n}\n\nexport function writeState(state: object, path: string, value: JsonValue) {\n readState(state, path)\n const parts = parsePointer(path)\n let parent = state as Record<string, unknown>\n for (const part of parts.slice(0, -1)) {\n parent = parent[part] as Record<string, unknown>\n }\n parent[parts[parts.length - 1]!] = cloneJson(value)\n}\n"],"mappings":"AAGA,SAAgB,EAAa,EAAc,CACzC,GAAI,CAAC,EAAK,WAAW,GAAG,GAAK,aAAa,KAAK,CAAI,EACjD,MAAU,MAAM,oBAAoB,GAAM,EAE5C,IAAM,EAAQ,EAAK,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,GAAQ,EAAK,QAAQ,MAAO,GAAG,CAAC,CAAC,QAAQ,MAAO,GAAG,CAAC,EAC/F,GAAI,EAAM,KAAK,GAAQ,CAAC,YAAa,YAAa,aAAa,CAAC,CAAC,SAAS,CAAI,CAAC,EAC7E,MAAU,MAAM,YAAY,EAE9B,OAAO,CACT,CAEA,SAAgB,EAAU,EAAe,EAAuB,CAC9D,IAAI,EAAmB,EACvB,IAAK,IAAM,KAAQ,EAAa,CAAI,EAAG,CACrC,GAAI,MAAM,QAAQ,CAAO,GAAK,CAAC,mBAAmB,KAAK,CAAI,EACzD,MAAU,MAAM,cAAc,GAAM,EAEtC,GAAI,CAAC,GAAW,OAAO,GAAY,UAAY,CAAC,OAAO,UAAU,eAAe,KAAK,EAAS,CAAI,EAChG,MAAU,MAAM,WAAW,GAAM,EAEnC,EAAW,EAAoC,EACjD,CACA,OAAO,CACT,CAGA,SAAgB,EAAW,EAAgB,kBAAY,IAAI,IAA2C,CAIpG,GAHI,IAAU,MAAQ,OAAO,GAAU,UAAY,OAAO,GAAU,WAGhE,OAAO,GAAU,UAAY,OAAO,SAAS,CAAK,EACpD,OAEF,GAAI,CAAC,GAAS,OAAO,GAAU,UAAY,EAAU,IAAI,CAAK,EAC5D,MAAU,MAAM,mBAAmB,EAErC,IAAM,EAAY,OAAO,eAAe,CAAK,EAC7C,GAAI,CAAC,MAAM,QAAQ,CAAK,GAAK,IAAc,OAAO,WAAa,IAAc,KAC3E,MAAU,MAAM,gBAAgB,EAElC,IAAM,EAAO,IAAI,IAAI,CAAS,CAAC,CAAC,IAAI,CAAK,EACzC,IAAK,IAAM,KAAS,OAAO,OAAO,CAAK,EACrC,EAAW,EAAO,CAAI,CAE1B,CAEA,SAAgB,EAAa,EAAa,CAExC,OADA,EAAW,CAAK,EACT,KAAK,MAAM,KAAK,UAAU,CAAK,CAAC,CACzC,CAEA,SAAgB,EAAW,EAAe,EAAc,EAAkB,CACxE,EAAU,EAAO,CAAI,EACrB,IAAM,EAAQ,EAAa,CAAI,EAC3B,EAAS,EACb,IAAK,IAAM,KAAQ,EAAM,MAAM,EAAG,EAAE,EAClC,EAAS,EAAO,GAElB,EAAO,EAAM,EAAM,OAAS,IAAO,EAAU,CAAK,CACpD"}
@@ -0,0 +1,2 @@
1
+ import{evaluateVisibility as e}from"./core.mjs";import{resolveProps as t}from"./validation.mjs";function n(n,r,i){function a(o){var s;let c=n.elements[o];return e(c.visible,{stateModel:i})?{id:o,type:c.type,props:t(c,r,i),children:((s=c.children)==null?[]:s).map(a).filter(e=>e!==null)}:null}return a(n.root)}function r(e,t){if(e){if(e.id===t)return e;for(let n of e.children){let e=r(n,t);if(e)return e}}}export{r as findRenderNode,n as projectRendererSpec};
2
+ //# sourceMappingURL=projection.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.mjs","names":[],"sources":["../src/projection.ts"],"sourcesContent":["import type { RendererCatalog, RendererSpec, RenderNode } from './types'\nimport { evaluateVisibility } from './core'\nimport { resolveProps } from './validation'\n\nexport function projectRendererSpec(spec: RendererSpec, catalog: RendererCatalog, state: object): RenderNode | null {\n function project(id: string): RenderNode | null {\n const node = spec.elements[id]!\n if (!evaluateVisibility(node.visible, { stateModel: state as Record<string, unknown> })) {\n return null\n }\n return {\n id,\n type: node.type,\n props: resolveProps(node, catalog, state),\n children: (node.children ?? []).map(project).filter((child): child is RenderNode => child !== null),\n }\n }\n return project(spec.root)\n}\n\nexport function findRenderNode(tree: RenderNode | null, id: string): RenderNode | undefined {\n if (!tree) {\n return undefined\n }\n if (tree.id === id) {\n return tree\n }\n for (const child of tree.children) {\n const found = findRenderNode(child, id)\n if (found) {\n return found\n }\n }\n}\n"],"mappings":"gGAIA,SAAgB,EAAoB,EAAoB,EAA0B,EAAkC,CAClH,SAAS,EAAQ,EAA+B,OAC9C,IAAM,EAAO,EAAK,SAAS,GAI3B,OAHK,EAAmB,EAAK,QAAS,CAAE,WAAY,CAAiC,CAAC,EAG/E,CACL,KACA,KAAM,EAAK,KACX,MAAO,EAAa,EAAM,EAAS,CAAK,EACxC,WAAA,EAAW,EAAK,WAAA,KAAY,CAAC,EAAb,EAAa,CAAG,IAAI,CAAO,CAAC,CAAC,OAAQ,GAA+B,IAAU,IAAI,CACpG,EAPS,IAQX,CACA,OAAO,EAAQ,EAAK,IAAI,CAC1B,CAEA,SAAgB,EAAe,EAAyB,EAAoC,CAC1F,GAAK,EAGL,IAAI,EAAK,KAAO,EACd,OAAO,EAET,IAAK,IAAM,KAAS,EAAK,SAAU,CACjC,IAAM,EAAQ,EAAe,EAAO,CAAE,EACtC,GAAI,EACF,OAAO,CAEX,CAPS,CAQX"}
@@ -0,0 +1,20 @@
1
+ import { CatalogSpec, JsonValue, RendererCatalog, RendererEvent, RendererOptions, RendererSpec } from "./types.mjs";
2
+ //#region src/renderer.d.ts
3
+ /** 创建与页面生命周期解耦的渲染会话;动作只通过上下文提交有效状态更新。 */
4
+ export declare function createJsonRenderer<C extends RendererCatalog, State extends object>(options: RendererOptions<C, State>): {
5
+ state: State;
6
+ spec: import("wevu").Ref<RendererSpec>;
7
+ tree: import("wevu").ComputedRef<import("@wevu/json-render-components/types").RenderNode | null>;
8
+ error: import("wevu").Ref<string | null>;
9
+ pending: import("wevu").Ref<string[]>;
10
+ setState: (path: string, value: JsonValue) => void;
11
+ load: (input: unknown, nextState?: State) => boolean;
12
+ dispatch: (event: RendererEvent) => Promise<boolean>;
13
+ createStream: (initialSpec?: CatalogSpec<C>) => {
14
+ push(chunk: string, done?: boolean): boolean;
15
+ dispose: () => void;
16
+ };
17
+ dispose(): void;
18
+ };
19
+ //#endregion
20
+ //# sourceMappingURL=renderer.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{resolveBindings as e,resolveElementProps as t}from"./core.mjs";import{cloneJson as n,writeState as r}from"./path.mjs";import{validateRendererSpec as i}from"./validation.mjs";import{findRenderNode as a,projectRendererSpec as o}from"./projection.mjs";import{createSpecStream as s}from"./stream.mjs";import{computed as c,reactive as l,shallowRef as u}from"wevu";function d(d){let f=l(n(d.initialState)),p=u(i(d.spec,d.catalog,f,d.limits).spec),m=u(null),h=u([]),g=c(()=>o(p.value,d.catalog,f)),_=!1,v=0,y=0,b,x=/* @__PURE__ */ new Set;function S(e){m.value=e instanceof Error?e.message:String(e)}function C(){v++,y++,b==null||b.dispose(),b=void 0;for(let e of[...x])try{e()}catch(e){S(e)}x.clear(),h.value=[]}function w(e,t){if(_)return;let i=n(f);r(i,e,t),o(p.value,d.catalog,i),r(f,e,t)}function T(e,t){if(_)return!1;try{let r=n(t==null?f:t),a=i(e,d.catalog,r,d.limits);if(C(),t){for(let e of Object.keys(f))Reflect.deleteProperty(f,e);Object.assign(f,r)}return p.value=a.spec,m.value=null,!0}catch(e){return S(e),!1}}async function E(n){var r;if(_||!a(g.value,n.id))return!1;let i=p.value.elements[n.id],o=d.catalog.components[i.type];if(!((r=o.events)!=null&&r.includes(n.name)))return!1;try{var s,c,l;let r=e(i.props,{stateModel:f});for(let[e,t]of Object.entries((s=o.bindings)==null?{}:s))if(t===n.name&&r!=null&&r[e]){if(n.value===void 0)throw Error(`绑定事件缺少 value:${n.name}`);w(r[e],n.value)}let a=(c=i.on)==null?void 0:c[n.name];if(!a)return!0;let u=`${n.id}:${a.action}`;if(h.value.includes(u))return!1;let p=d.actions[a.action];if(!Object.prototype.hasOwnProperty.call(d.actions,a.action)||typeof p!=`function`)throw TypeError(`动作缺少处理器:${a.action}`);let g=d.catalog.actions[a.action].parse(t((l=a.params)==null?{}:l,{stateModel:f})),y=v,b=()=>!_&&v===y,C=/* @__PURE__ */ new Set,T={state:f,event:n,isActive:b,setState(e,t){b()&&w(e,t)},onCleanup(e){b()?(x.add(e),C.add(e)):e()}};h.value=[...h.value,u],m.value=null;try{return await p(g,T),b()}catch(e){return b()&&S(e),!1}finally{for(let e of C)if(x.delete(e))try{e()}catch(e){S(e)}b()&&(h.value=h.value.filter(e=>e!==u))}}catch(e){return S(e),!1}}function D(e){let t=i(e==null?p.value:e,d.catalog,f,d.limits).spec,n=s(t,d.catalog,f,d.limits);b==null||b.dispose();let r=++y;return p.value=t,b=n,m.value=null,{push(e,t=!1){if(_||r!==y)return!1;try{let r=n.push(e,t);return r&&(p.value=r),r!==null}catch(e){return S(e),!1}},dispose:()=>n.dispose()}}return{state:f,spec:p,tree:g,error:m,pending:h,setState:w,load:T,dispatch:E,createStream:D,dispose(){_||(_=!0,C())}}}export{d as createJsonRenderer};
2
+ //# sourceMappingURL=renderer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.mjs","names":[],"sources":["../src/renderer.ts"],"sourcesContent":["import type { ActionContext, CatalogSpec, JsonValue, RendererCatalog, RendererEvent, RendererOptions, RendererSpec } from './types'\nimport { computed, reactive, shallowRef } from 'wevu'\nimport { resolveBindings, resolveElementProps } from './core'\nimport { cloneJson, writeState } from './path'\nimport { findRenderNode, projectRendererSpec } from './projection'\nimport { createSpecStream } from './stream'\nimport { validateRendererSpec } from './validation'\n\n/** 创建与页面生命周期解耦的渲染会话;动作只通过上下文提交有效状态更新。 */\nexport function createJsonRenderer<C extends RendererCatalog, State extends object>(options: RendererOptions<C, State>) {\n const state = reactive(cloneJson(options.initialState)) as State\n const spec = shallowRef<RendererSpec>(validateRendererSpec(options.spec, options.catalog, state, options.limits).spec)\n const error = shallowRef<string | null>(null)\n const pending = shallowRef<string[]>([])\n const tree = computed(() => projectRendererSpec(spec.value, options.catalog, state))\n let disposed = false\n let generation = 0\n let streamGeneration = 0\n let currentStream: ReturnType<typeof createSpecStream> | undefined\n const cleanups = new Set<() => void>()\n\n function report(reason: unknown) {\n error.value = reason instanceof Error ? reason.message : String(reason)\n }\n\n function cancel() {\n generation++\n streamGeneration++\n currentStream?.dispose()\n currentStream = undefined\n for (const cleanup of [...cleanups]) {\n try {\n cleanup()\n }\n catch (reason) {\n report(reason)\n }\n }\n cleanups.clear()\n pending.value = []\n }\n\n function setState(path: string, value: JsonValue) {\n if (disposed) {\n return\n }\n const draft = cloneJson(state)\n writeState(draft, path, value)\n // 同时验证投影,拒绝导致宿主 props 类型不匹配的状态更新。\n projectRendererSpec(spec.value, options.catalog, draft)\n writeState(state, path, value)\n }\n\n function load(input: unknown, nextState?: State) {\n if (disposed) {\n return false\n }\n try {\n const draftState = cloneJson(nextState ?? state)\n const checked = validateRendererSpec(input, options.catalog, draftState, options.limits)\n cancel()\n if (nextState) {\n for (const key of Object.keys(state)) {\n Reflect.deleteProperty(state, key)\n }\n Object.assign(state, draftState)\n }\n spec.value = checked.spec\n error.value = null\n return true\n }\n catch (reason) {\n report(reason)\n return false\n }\n }\n\n async function dispatch(event: RendererEvent): Promise<boolean> {\n if (disposed || !findRenderNode(tree.value, event.id)) {\n return false\n }\n const node = spec.value.elements[event.id]!\n const definition = options.catalog.components[node.type]!\n if (!definition.events?.includes(event.name)) {\n return false\n }\n try {\n const bindings = resolveBindings(node.props, { stateModel: state as Record<string, unknown> })\n for (const [prop, name] of Object.entries(definition.bindings ?? {})) {\n if (name === event.name && bindings?.[prop]) {\n if (event.value === undefined) {\n throw new Error(`绑定事件缺少 value:${event.name}`)\n }\n setState(bindings[prop], event.value)\n }\n }\n const binding = node.on?.[event.name]\n if (!binding) {\n return true\n }\n const key = `${event.id}:${binding.action}`\n if (pending.value.includes(key)) {\n return false\n }\n const handler = options.actions[binding.action]\n if (!Object.prototype.hasOwnProperty.call(options.actions, binding.action) || typeof handler !== 'function') {\n throw new TypeError(`动作缺少处理器:${binding.action}`)\n }\n const params = options.catalog.actions[binding.action]!.parse(resolveElementProps(binding.params ?? {}, { stateModel: state as Record<string, unknown> }))\n const ownGeneration = generation\n const isActive = () => !disposed && generation === ownGeneration\n const actionCleanups = new Set<() => void>()\n const context: ActionContext<State> = {\n state,\n event,\n isActive,\n setState(path, value) {\n if (isActive()) {\n setState(path, value)\n }\n },\n onCleanup(cleanup) {\n if (isActive()) {\n cleanups.add(cleanup)\n actionCleanups.add(cleanup)\n }\n else {\n cleanup()\n }\n },\n }\n pending.value = [...pending.value, key]\n error.value = null\n try {\n await handler(params as Parameters<typeof handler>[0], context)\n return isActive()\n }\n catch (reason) {\n if (isActive()) {\n report(reason)\n }\n return false\n }\n finally {\n for (const cleanup of actionCleanups) {\n if (cleanups.delete(cleanup)) {\n try {\n cleanup()\n }\n catch (reason) {\n report(reason)\n }\n }\n }\n if (isActive()) {\n pending.value = pending.value.filter(item => item !== key)\n }\n }\n }\n catch (reason) {\n report(reason)\n return false\n }\n }\n\n function createStream(initialSpec?: CatalogSpec<C>) {\n const initial = validateRendererSpec(initialSpec ?? spec.value, options.catalog, state, options.limits).spec\n const stream = createSpecStream(initial, options.catalog, state, options.limits)\n currentStream?.dispose()\n const ownGeneration = ++streamGeneration\n spec.value = initial\n currentStream = stream\n error.value = null\n return {\n push(chunk: string, done = false) {\n if (disposed || ownGeneration !== streamGeneration) {\n return false\n }\n try {\n const next = stream.push(chunk, done)\n if (next) {\n spec.value = next\n }\n return next !== null\n }\n catch (reason) {\n report(reason)\n return false\n }\n },\n dispose: () => stream.dispose(),\n }\n }\n\n return {\n state,\n spec,\n tree,\n error,\n pending,\n setState,\n load,\n dispatch,\n createStream,\n dispose() {\n if (!disposed) {\n disposed = true\n cancel()\n }\n },\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ //#region src/resolver.d.ts
2
+ /** 在消费项目中注册已经由 lib 模式编译的组件,不向 AppService 引入构建依赖。 */
3
+ export declare function JsonRendererResolver(): {
4
+ components: Readonly<Record<string, string>>;
5
+ resolve(name: string): {
6
+ name: string;
7
+ from: string;
8
+ sourceType: "native";
9
+ typeImport: boolean;
10
+ } | undefined;
11
+ };
12
+ //#endregion
13
+ //# sourceMappingURL=resolver.d.mts.map
@@ -0,0 +1,2 @@
1
+ const e=`@wevu/json-render-components/renderer/index`;function t(){let t=Object.freeze({"json-renderer":e,"json-render-node":e});return{components:t,resolve(e){let n=t[e];if(n)return{name:e,from:n,sourceType:`native`,typeImport:!1}}}}export{t as JsonRendererResolver};
2
+ //# sourceMappingURL=resolver.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.mjs","names":[],"sources":["../src/resolver.ts"],"sourcesContent":["const componentPath = '@wevu/json-render-components/renderer/index'\n\n/** 在消费项目中注册已经由 lib 模式编译的组件,不向 AppService 引入构建依赖。 */\nexport function JsonRendererResolver() {\n const components: Readonly<Record<string, string>> = Object.freeze({\n 'json-renderer': componentPath,\n 'json-render-node': componentPath,\n })\n return {\n components,\n resolve(name: string) {\n const from = components[name]\n if (!from) {\n return undefined\n }\n return { name, from, sourceType: 'native' as const, typeImport: false }\n },\n }\n}\n"],"mappings":"AAAA,MAAM,EAAgB,8CAGtB,SAAgB,GAAuB,CACrC,IAAM,EAA+C,OAAO,OAAO,CACjE,gBAAiB,EACjB,mBAAoB,CACtB,CAAC,EACD,MAAO,CACL,aACA,QAAQ,EAAc,CACpB,IAAM,EAAO,EAAW,GACxB,GAAK,EAGL,MAAO,CAAE,OAAM,OAAM,WAAY,SAAmB,WAAY,EAAM,CACxE,CACF,CACF"}
@@ -0,0 +1,9 @@
1
+ import { RendererCatalog, RendererLimits, RendererSpec } from "./types.mjs";
2
+ //#region src/stream.d.ts
3
+ /** 按批应用描述 Patch,保留上一次完整界面并等待暂缺的节点引用。 */
4
+ export declare function createSpecStream(initial: RendererSpec, catalog: RendererCatalog, state: object, limits?: RendererLimits): {
5
+ push(chunk: string, done?: boolean): RendererSpec | null;
6
+ dispose(): void;
7
+ };
8
+ //#endregion
9
+ //# sourceMappingURL=stream.d.mts.map
@@ -0,0 +1,3 @@
1
+ import{createSpecStreamCompiler as e}from"./core.mjs";import{cloneJson as t,parsePointer as n}from"./path.mjs";import{validateRendererSpec as r}from"./validation.mjs";function i(i,a,o,s={}){var c;let l=t(i),u=``,d=!1,f=(c=s.maxBufferedCharacters)==null?65536:c;if(!Number.isInteger(f)||f<1)throw Error(`流缓冲上限必须是正整数`);return{push(i,c=!1){if(d)throw Error(`流已停止,请创建新的流`);try{if(u+=i,u.length>f)throw Error(`单批流数据过大`);let p=u.split(`
2
+ `);u=c?``:p.pop();let m=t(l),h=!1;for(let t of p){if(!t.trim())continue;let r=JSON.parse(t);if(!r||![`add`,`replace`,`remove`].includes(String(r.op))||typeof r.path!=`string`||!/^\/(?:root|elements)(?:\/|$)/.test(r.path)||Object.keys(r).some(e=>![`op`,`path`,`value`].includes(e))||r.op!==`remove`&&!Object.prototype.hasOwnProperty.call(r,`value`))throw Error(`不支持的 Patch,只允许更新 root/elements`);n(r.path),m=e(m).push(`${t}\n`).result,h=!0}let g=r(m,a,o,s,!c);return l=g.spec,d=c,g.complete&&h?g.spec:null}catch(e){throw d=!0,e}},dispose(){d=!0,u=``}}}export{i as createSpecStream};
3
+ //# sourceMappingURL=stream.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.mjs","names":[],"sources":["../src/stream.ts"],"sourcesContent":["import type { RendererCatalog, RendererLimits, RendererSpec } from './types'\nimport { createSpecStreamCompiler } from './core'\nimport { cloneJson, parsePointer } from './path'\nimport { validateRendererSpec } from './validation'\n\n/** 按批应用描述 Patch,保留上一次完整界面并等待暂缺的节点引用。 */\nexport function createSpecStream(initial: RendererSpec, catalog: RendererCatalog, state: object, limits: RendererLimits = {}) {\n let candidate = cloneJson(initial)\n let buffer = ''\n let stopped = false\n const maxBufferedCharacters = limits.maxBufferedCharacters ?? 65_536\n if (!Number.isInteger(maxBufferedCharacters) || maxBufferedCharacters < 1) {\n throw new Error('流缓冲上限必须是正整数')\n }\n return {\n push(chunk: string, done = false): RendererSpec | null {\n if (stopped) {\n throw new Error('流已停止,请创建新的流')\n }\n try {\n buffer += chunk\n if (buffer.length > maxBufferedCharacters) {\n throw new Error('单批流数据过大')\n }\n const lines = buffer.split('\\n')\n buffer = done ? '' : lines.pop()!\n let draft = cloneJson(candidate)\n let changed = false\n for (const line of lines) {\n if (!line.trim()) {\n continue\n }\n const patch = JSON.parse(line) as Record<string, unknown>\n if (!patch || !['add', 'replace', 'remove'].includes(String(patch.op)) || typeof patch.path !== 'string'\n || !/^\\/(?:root|elements)(?:\\/|$)/.test(patch.path)\n || Object.keys(patch).some(key => !['op', 'path', 'value'].includes(key))\n || (patch.op !== 'remove' && !Object.prototype.hasOwnProperty.call(patch, 'value'))) {\n throw new Error('不支持的 Patch,只允许更新 root/elements')\n }\n parsePointer(patch.path)\n // 每行独立编译,避免上游按文本去重吞掉合法的重复数组操作。\n draft = createSpecStreamCompiler<RendererSpec>(draft).push(`${line}\\n`).result\n changed = true\n }\n const checked = validateRendererSpec(draft, catalog, state, limits, !done)\n candidate = checked.spec\n stopped = done\n return checked.complete && changed ? checked.spec : null\n }\n catch (error) {\n stopped = true\n throw error\n }\n },\n dispose() {\n stopped = true\n buffer = ''\n },\n }\n}\n"],"mappings":"uKAMA,SAAgB,EAAiB,EAAuB,EAA0B,EAAe,EAAyB,CAAC,EAAG,OAC5H,IAAI,EAAY,EAAU,CAAO,EAC7B,EAAS,GACT,EAAU,GACR,GAAA,EAAwB,EAAO,wBAAA,KAAyB,MAAzB,EACrC,GAAI,CAAC,OAAO,UAAU,CAAqB,GAAK,EAAwB,EACtE,MAAU,MAAM,aAAa,EAE/B,MAAO,CACL,KAAK,EAAe,EAAO,GAA4B,CACrD,GAAI,EACF,MAAU,MAAM,aAAa,EAE/B,GAAI,CAEF,GADA,GAAU,EACN,EAAO,OAAS,EAClB,MAAU,MAAM,SAAS,EAE3B,IAAM,EAAQ,EAAO,MAAM;CAAI,EAC/B,EAAS,EAAO,GAAK,EAAM,IAAI,EAC/B,IAAI,EAAQ,EAAU,CAAS,EAC3B,EAAU,GACd,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAI,CAAC,EAAK,KAAK,EACb,SAEF,IAAM,EAAQ,KAAK,MAAM,CAAI,EAC7B,GAAI,CAAC,GAAS,CAAC,CAAC,MAAO,UAAW,QAAQ,CAAC,CAAC,SAAS,OAAO,EAAM,EAAE,CAAC,GAAK,OAAO,EAAM,MAAS,UAC3F,CAAC,+BAA+B,KAAK,EAAM,IAAI,GAC/C,OAAO,KAAK,CAAK,CAAC,CAAC,KAAK,GAAO,CAAC,CAAC,KAAM,OAAQ,OAAO,CAAC,CAAC,SAAS,CAAG,CAAC,GACpE,EAAM,KAAO,UAAY,CAAC,OAAO,UAAU,eAAe,KAAK,EAAO,OAAO,EACjF,MAAU,MAAM,gCAAgC,EAElD,EAAa,EAAM,IAAI,EAEvB,EAAQ,EAAuC,CAAK,CAAC,CAAC,KAAK,GAAG,EAAK,GAAG,CAAC,CAAC,OACxE,EAAU,EACZ,CACA,IAAM,EAAU,EAAqB,EAAO,EAAS,EAAO,EAAQ,CAAC,CAAI,EAGzE,MAFA,GAAY,EAAQ,KACpB,EAAU,EACH,EAAQ,UAAY,EAAU,EAAQ,KAAO,IACtD,OACO,EAAO,CAEZ,KADA,GAAU,GACJ,CACR,CACF,EACA,SAAU,CACR,EAAU,GACV,EAAS,EACX,CACF,CACF"}
@@ -0,0 +1,79 @@
1
+ import { z } from "zod";
2
+ import { JsonValue, JsonValue as JsonValue$1, RenderNode, RendererEvent, RendererEvent as RendererEvent$1 } from "@wevu/json-render-components/types";
3
+ //#region src/types.d.ts
4
+ export interface StateExpression {
5
+ $state: string;
6
+ }
7
+ export interface BindingExpression {
8
+ $bindState: string;
9
+ }
10
+ export type Visibility = boolean | {
11
+ $state: string;
12
+ eq?: JsonValue;
13
+ not?: true;
14
+ };
15
+ export interface ComponentDefinition {
16
+ props: z.ZodType<Record<string, unknown>>;
17
+ container?: boolean;
18
+ events?: readonly string[];
19
+ bindings?: Readonly<Record<string, string>>;
20
+ }
21
+ export interface RendererCatalog {
22
+ components: Record<string, ComponentDefinition>;
23
+ actions: Record<string, z.ZodType<Record<string, unknown>>>;
24
+ }
25
+ export interface ActionBinding {
26
+ action: string;
27
+ params?: Record<string, JsonValue | StateExpression>;
28
+ }
29
+ export interface SpecElement {
30
+ type: string;
31
+ props: Record<string, unknown>;
32
+ children?: string[];
33
+ visible?: Visibility;
34
+ on?: Record<string, ActionBinding>;
35
+ }
36
+ export interface RendererSpec {
37
+ root: string;
38
+ elements: Record<string, SpecElement>;
39
+ }
40
+ type ComponentProps<D extends ComponentDefinition> = z.input<D['props']>;
41
+ type BindingKeys<D> = D extends {
42
+ bindings: infer Bindings;
43
+ } ? keyof Bindings : never;
44
+ type ExpressionParams<Params> = { [Key in keyof Params]: Params[Key] | StateExpression; };
45
+ type TypedElement<C extends RendererCatalog> = { [Name in keyof C['components'] & string]: Omit<SpecElement, 'type' | 'props' | 'on'> & {
46
+ type: Name;
47
+ props: { [Key in keyof ComponentProps<C['components'][Name]>]: ComponentProps<C['components'][Name]>[Key] | StateExpression | (Key extends BindingKeys<C['components'][Name]> ? BindingExpression : never); };
48
+ on?: Record<string, { [Action in keyof C['actions'] & string]: {
49
+ action: Action;
50
+ params?: ExpressionParams<z.input<C['actions'][Action]>>;
51
+ }; }[keyof C['actions'] & string]>;
52
+ }; }[keyof C['components'] & string];
53
+ export interface CatalogSpec<C extends RendererCatalog> {
54
+ root: string;
55
+ elements: Record<string, TypedElement<C>>;
56
+ }
57
+ export interface RendererLimits {
58
+ maxNodes?: number;
59
+ maxDepth?: number;
60
+ maxBufferedCharacters?: number;
61
+ }
62
+ export interface ActionContext<State extends object> {
63
+ readonly state: State;
64
+ readonly event: RendererEvent;
65
+ setState: (path: string, value: JsonValue) => void;
66
+ isActive: () => boolean;
67
+ onCleanup: (cleanup: () => void) => void;
68
+ }
69
+ export type ActionHandlers<C extends RendererCatalog, State extends object> = { [Name in keyof C['actions']]: (params: z.output<C['actions'][Name]>, context: ActionContext<State>) => void | Promise<void>; };
70
+ export interface RendererOptions<C extends RendererCatalog, State extends object> {
71
+ catalog: C;
72
+ spec: CatalogSpec<C>;
73
+ initialState: State;
74
+ actions: ActionHandlers<C, State>;
75
+ limits?: RendererLimits;
76
+ }
77
+ //#endregion
78
+ export type { JsonValue$1 as JsonValue, RenderNode, RendererEvent$1 as RendererEvent };
79
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1,20 @@
1
+ import { CatalogSpec, RendererCatalog, RendererOptions, RendererSpec } from "./types.mjs";
2
+ //#region src/useRenderer.d.ts
3
+ /** 在同步 setup 中创建会话,页面和组件卸载时均释放动作及流。 */
4
+ export declare function useJsonRenderer<C extends RendererCatalog, State extends object>(options: RendererOptions<C, State>): {
5
+ state: State;
6
+ spec: import("wevu").Ref<RendererSpec>;
7
+ tree: import("wevu").ComputedRef<import("@wevu/json-render-components/types").RenderNode | null>;
8
+ error: import("wevu").Ref<string | null>;
9
+ pending: import("wevu").Ref<string[]>;
10
+ setState: (path: string, value: import("@wevu/json-render-components/types").JsonValue) => void;
11
+ load: (input: unknown, nextState?: State | undefined) => boolean;
12
+ dispatch: (event: import("@wevu/json-render-components/types").RendererEvent) => Promise<boolean>;
13
+ createStream: (initialSpec?: CatalogSpec<C> | undefined) => {
14
+ push(chunk: string, done?: boolean): boolean;
15
+ dispose: () => void;
16
+ };
17
+ dispose(): void;
18
+ };
19
+ //#endregion
20
+ //# sourceMappingURL=useRenderer.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{createJsonRenderer as e}from"./renderer.mjs";import{onUnload as t,onUnmounted as n}from"wevu";function r(r){let i=e(r);return t(i.dispose),n(i.dispose),i}export{r as useJsonRenderer};
2
+ //# sourceMappingURL=useRenderer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRenderer.mjs","names":[],"sources":["../src/useRenderer.ts"],"sourcesContent":["import type { RendererCatalog, RendererOptions } from './types'\nimport { onUnload, onUnmounted } from 'wevu'\nimport { createJsonRenderer } from './renderer'\n\n/** 在同步 setup 中创建会话,页面和组件卸载时均释放动作及流。 */\nexport function useJsonRenderer<C extends RendererCatalog, State extends object>(options: RendererOptions<C, State>) {\n const renderer = createJsonRenderer(options)\n onUnload(renderer.dispose)\n onUnmounted(renderer.dispose)\n return renderer\n}\n"],"mappings":"qGAKA,SAAgB,EAAiE,EAAoC,CACnH,IAAM,EAAW,EAAmB,CAAO,EAG3C,OAFA,EAAS,EAAS,OAAO,EACzB,EAAY,EAAS,OAAO,EACrB,CACT"}
@@ -0,0 +1,9 @@
1
+ import { RendererCatalog, RendererLimits, RendererSpec } from "./types.mjs";
2
+ //#region src/validation.d.ts
3
+ /** 完整描述与流式中间态共用目录和图结构校验。 */
4
+ export declare function validateRendererSpec(input: unknown, catalog: RendererCatalog, state: object, limits?: RendererLimits, partial?: boolean): {
5
+ spec: RendererSpec;
6
+ complete: boolean;
7
+ };
8
+ //#endregion
9
+ //# sourceMappingURL=validation.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{resolveElementProps as e}from"./core.mjs";import{assertJson as t,parsePointer as n}from"./path.mjs";import{z as r}from"zod";const i=r.union([r.boolean(),r.object({$state:r.string(),not:r.literal(!0).optional(),eq:r.unknown().optional()}).strict()]),a=r.object({root:r.string().min(1),elements:r.record(r.string().regex(/^[a-z][\w-]*$/i),r.object({type:r.string(),props:r.record(r.string(),r.unknown()),children:r.array(r.string().min(1)).optional(),visible:i.optional(),on:r.record(r.string(),r.object({action:r.string(),params:r.record(r.string(),r.unknown()).optional()}).strict()).optional()}).strict())}).strict();function o(e,t=!1){if(e&&typeof e==`object`)for(let[r,i]of Object.entries(e))if(r.startsWith(`$`)){if(![`$state`,...t?[`$bindState`]:[]].includes(r)||Object.keys(e).length!==1||typeof i!=`string`)throw Error(`不支持的表达式:${r}`);n(i)}else o(i)}function s(n,r,i){let a=e(n.props,{stateModel:i}),o=r.components[n.type].props.parse(a);if(t(o),!o||typeof o!=`object`||Array.isArray(o))throw Error(`组件 props schema 必须输出对象`);return o}function c(e,r,i,c={},l=!1){var u,d;t(e);let f=a.parse(e),p=(u=c.maxNodes)==null?200:u,m=(d=c.maxDepth)==null?8:d;if(!Number.isInteger(p)||p<1||!Number.isInteger(m)||m<1)throw Error(`节点及深度上限必须是正整数`);let h=Object.keys(f.elements);if(h.length>p)throw Error(`节点数量不能超过 ${p}`);let g=/* @__PURE__ */ new Set,_=Object.prototype.hasOwnProperty.call(f.elements,f.root);for(let[e,t]of Object.entries(f.elements)){var v,y,b;if(!Object.prototype.hasOwnProperty.call(r.components,t.type))throw Error(`未注册组件:${t.type}`);let a=r.components[t.type];if(!a.container&&(v=t.children)!=null&&v.length)throw Error(`${t.type} 不支持 children`);for(let[e,n]of Object.entries(t.props)){var x;o(n,Object.prototype.hasOwnProperty.call((x=a.bindings)==null?{}:x,e))}typeof t.visible==`object`&&n(t.visible.$state),s(t,r,i);for(let[e,n]of Object.entries((y=t.on)==null?{}:y)){var S,C;if(!((S=a.events)!=null&&S.includes(e)))throw Error(`${t.type} 未声明事件:${e}`);if(!Object.prototype.hasOwnProperty.call(r.actions,n.action))throw Error(`未注册动作:${n.action}`);o((C=n.params)==null?{}:C)}for(let e of(b=t.children)==null?[]:b){if(g.has(e))throw Error(`节点重复引用:${e}`);g.add(e)}n(`/elements/${e}`)}function w(e,t){var n;if(t.has(e))throw Error(`节点循环引用:${e}`);if(t.size>=m)throw Error(`节点深度不能超过 ${m}`);if(!Object.prototype.hasOwnProperty.call(f.elements,e)){_=!1;return}let r=new Set(t).add(e);for(let t of(n=f.elements[e].children)==null?[]:n)w(t,r)}if(h.forEach(e=>w(e,/* @__PURE__ */ new Set)),!l&&!_)throw Error(`节点引用不存在`);return{spec:f,complete:_}}export{s as resolveProps,c as validateRendererSpec};
2
+ //# sourceMappingURL=validation.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.mjs","names":[],"sources":["../src/validation.ts"],"sourcesContent":["import type { RendererCatalog, RendererLimits, RendererSpec, SpecElement } from './types'\nimport { z } from 'zod'\nimport { resolveElementProps } from './core'\nimport { assertJson, parsePointer } from './path'\n\nconst visibleSchema = z.union([z.boolean(), z.object({ $state: z.string(), not: z.literal(true).optional(), eq: z.unknown().optional() }).strict()])\nconst specSchema = z.object({\n root: z.string().min(1),\n elements: z.record(z.string().regex(/^[a-z][\\w-]*$/i), z.object({\n type: z.string(),\n props: z.record(z.string(), z.unknown()),\n children: z.array(z.string().min(1)).optional(),\n visible: visibleSchema.optional(),\n on: z.record(z.string(), z.object({ action: z.string(), params: z.record(z.string(), z.unknown()).optional() }).strict()).optional(),\n }).strict()),\n}).strict()\n\n/** v1 只解释状态读取和输入绑定,拒绝静默接受未实现的表达式。 */\nfunction validateExpressions(value: unknown, binding = false) {\n if (!value || typeof value !== 'object') {\n return\n }\n for (const [key, child] of Object.entries(value)) {\n if (key.startsWith('$')) {\n if (!['$state', ...(binding ? ['$bindState'] : [])].includes(key)\n || Object.keys(value).length !== 1 || typeof child !== 'string') {\n throw new Error(`不支持的表达式:${key}`)\n }\n parsePointer(child)\n }\n else {\n validateExpressions(child)\n }\n }\n}\n\nexport function resolveProps(node: SpecElement, catalog: RendererCatalog, state: object) {\n const resolved = resolveElementProps(node.props, { stateModel: state as Record<string, unknown> })\n const parsed: unknown = catalog.components[node.type]!.props.parse(resolved)\n assertJson(parsed)\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('组件 props schema 必须输出对象')\n }\n return parsed\n}\n\n/** 完整描述与流式中间态共用目录和图结构校验。 */\nexport function validateRendererSpec(\n input: unknown,\n catalog: RendererCatalog,\n state: object,\n limits: RendererLimits = {},\n partial = false,\n): { spec: RendererSpec, complete: boolean } {\n assertJson(input)\n const spec = specSchema.parse(input) as RendererSpec\n const maxNodes = limits.maxNodes ?? 200\n const maxDepth = limits.maxDepth ?? 8\n if (!Number.isInteger(maxNodes) || maxNodes < 1 || !Number.isInteger(maxDepth) || maxDepth < 1) {\n throw new Error('节点及深度上限必须是正整数')\n }\n const ids = Object.keys(spec.elements)\n if (ids.length > maxNodes) {\n throw new Error(`节点数量不能超过 ${maxNodes}`)\n }\n const parents = new Set<string>()\n let complete = Object.prototype.hasOwnProperty.call(spec.elements, spec.root)\n for (const [id, node] of Object.entries(spec.elements)) {\n if (!Object.prototype.hasOwnProperty.call(catalog.components, node.type)) {\n throw new Error(`未注册组件:${node.type}`)\n }\n const definition = catalog.components[node.type]!\n if (!definition.container && node.children?.length) {\n throw new Error(`${node.type} 不支持 children`)\n }\n for (const [key, value] of Object.entries(node.props)) {\n validateExpressions(value, Object.prototype.hasOwnProperty.call(definition.bindings ?? {}, key))\n }\n if (typeof node.visible === 'object') {\n parsePointer(node.visible.$state)\n }\n resolveProps(node, catalog, state)\n for (const [event, action] of Object.entries(node.on ?? {})) {\n if (!definition.events?.includes(event)) {\n throw new Error(`${node.type} 未声明事件:${event}`)\n }\n if (!Object.prototype.hasOwnProperty.call(catalog.actions, action.action)) {\n throw new Error(`未注册动作:${action.action}`)\n }\n validateExpressions(action.params ?? {})\n }\n for (const child of node.children ?? []) {\n if (parents.has(child)) {\n throw new Error(`节点重复引用:${child}`)\n }\n parents.add(child)\n }\n parsePointer(`/elements/${id}`)\n }\n function visit(id: string, ancestors: Set<string>) {\n if (ancestors.has(id)) {\n throw new Error(`节点循环引用:${id}`)\n }\n if (ancestors.size >= maxDepth) {\n throw new Error(`节点深度不能超过 ${maxDepth}`)\n }\n if (!Object.prototype.hasOwnProperty.call(spec.elements, id)) {\n complete = false\n return\n }\n const next = new Set(ancestors).add(id)\n for (const child of spec.elements[id]!.children ?? []) {\n visit(child, next)\n }\n }\n ids.forEach(id => visit(id, new Set()))\n if (!partial && !complete) {\n throw new Error('节点引用不存在')\n }\n return { spec, complete }\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@wevu/json-render",
3
+ "type": "module",
4
+ "version": "0.0.0",
5
+ "description": "json-render 的 Wevu 小程序渲染与交互适配层",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/weapp-vite/weapp-vite#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/weapp-vite/weapp-vite.git",
11
+ "directory": "packages-runtime/json-render"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/weapp-vite/weapp-vite/issues"
15
+ },
16
+ "keywords": [
17
+ "wevu",
18
+ "json-render",
19
+ "mini-program",
20
+ "generative-ui"
21
+ ],
22
+ "sideEffects": [
23
+ "./src/compat.ts",
24
+ "./dist/compat.mjs"
25
+ ],
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.mts",
29
+ "import": "./dist/index.mjs"
30
+ },
31
+ "./resolver": {
32
+ "types": "./dist/resolver.d.mts",
33
+ "import": "./dist/resolver.mjs"
34
+ }
35
+ },
36
+ "main": "./dist/index.mjs",
37
+ "module": "./dist/index.mjs",
38
+ "types": "./dist/index.d.mts",
39
+ "files": [
40
+ "README.md",
41
+ "dist"
42
+ ],
43
+ "engines": {
44
+ "node": "^20.19.0 || >=22.12.0"
45
+ },
46
+ "peerDependencies": {
47
+ "wevu": "7.3.0"
48
+ },
49
+ "dependencies": {
50
+ "@json-render/core": "0.21.0",
51
+ "@wevu/json-render-components": "0.0.0",
52
+ "zod": "^4.6.5"
53
+ },
54
+ "devDependencies": {
55
+ "miniprogram-api-typings": "^5.2.3",
56
+ "wevu": "7.3.0"
57
+ },
58
+ "tsd": {
59
+ "compilerOptions": {
60
+ "module": "NodeNext",
61
+ "moduleResolution": "NodeNext",
62
+ "paths": {}
63
+ }
64
+ },
65
+ "publishConfig": {
66
+ "access": "public",
67
+ "registry": "https://registry.npmjs.org"
68
+ },
69
+ "scripts": {
70
+ "dev": "tsdown -w",
71
+ "build": "tsdown",
72
+ "test": "vitest run",
73
+ "test:types": "pnpm build && tsd --files \"test-d/**/*.test-d.{ts,tsx}\"",
74
+ "typecheck": "tsc --noEmit",
75
+ "lint": "eslint .",
76
+ "lint:fix": "eslint . --fix"
77
+ }
78
+ }