# JavaScript / Wasm GC SDK 与 Form.io

SDK 调用编译后的 MoonBit 求值器，传递 JSON 文本并返回 JSON 结果；不回退到 `json-logic-js`。提供源码构建和可直接安装的本地／CI 压缩包，尚未发布到 npm registry。

## 构建和调用

需要 MoonBit 工具链在 PATH、Node.js 24+ 和 npm。Node 22 可运行 JS 后端，但不支持此 Wasm GC 模块的字符串导入；Wasm GC 加载会明确失败。先运行：

```sh
npm ci
npm run build:sdk
npm run check:types
```

生成 `output/sdk/interop.mjs` 和 `output/sdk/interop.wasm`。加载器和声明位于 `sdk/index.mjs`、`sdk/index.d.mts`。

```js
import {createJsEvaluator} from './sdk/index.mjs';
const evaluator = await createJsEvaluator();
const result = evaluator.evaluate({'>=': [{var: 'age'}, 18]}, {age: 22});
if (result.ok) console.log(result.value, result.logs, result.steps_used);
else console.error(result.error.kind, result.error.path, result.error.message);
```

浏览器可传入编译模块 URL；部署时同时提供 SDK 与编译模块。Node 使用 Wasm GC 时从文件读取字节：

```js
import {readFile} from 'node:fs/promises';
import {createWasmGcEvaluator} from './sdk/index.mjs';
const evaluator = await createWasmGcEvaluator(await readFile('./output/sdk/interop.wasm'));
console.log(evaluator.apply({var: 'amount'}, {amount: 12.5}));
```

`createWasmGcEvaluator(urlOrBytes)` 要求宿主支持 Wasm GC 和 WebAssembly JS string builtins；不支持时直接报告加载失败。`evaluateJson(ruleText, dataText, options)` 接受 JSON 文本，`evaluate(rule, data, options)` 接受 JSON 值。`apply` 返回值，失败时抛出 `JsonLogicError`。

`options` 只接纳 `maxSteps`（默认 100000）与 `maxDepth`（默认 128，范围 1–256）。错误分类为 `invalid_input`、`invalid_rule`、`limit_exceeded`、`non_finite_number`，位置使用 JSON Pointer。SDK 拒绝 undefined、非有限数、BigInt、循环、稀疏数组、访问器、Symbol 属性、非枚举属性及 Date 等非 JSON 宿主对象，避免序列化静默改变输入。宿主遍历限 100000 个节点、256 层、每份 JSON 文本 2097152 UTF-16 单位；执行预算另由核心求值器实施。预算不等于墙钟时间／内存隔离。

## 安装到其他应用

在本仓库构建并检查压缩包：

```sh
npm run bundle:sdk
npm run check:bundle
```

生成 `output/sdk-dist/kaigeliang-jsonlogic-sdk-0.2.1.tgz`，CI 的 `jsonlogic-sdk-formio-browser` artifact 也包含它。构建读取工具链的 `~/.moon/lib/core` 许可证；自定义工具链可设置 `MOON_CORE` 指向对应 core 目录。压缩包包含预编译模块、SDK、类型声明和 MIT／MoonBit core Apache-2.0 许可证及 notices，不包含 Form.io、开发依赖或测试 fixtures。消费应用无需 MoonBit 编译器：

```sh
npm install /absolute/path/to/kaigeliang-jsonlogic-sdk-0.2.1.tgz
```

```js
import {createJsEvaluator, createWasmGcEvaluator} from '@kaigeliang/jsonlogic-sdk';
import {readFile} from 'node:fs/promises';
const js = await createJsEvaluator();
const wasm = await createWasmGcEvaluator(await readFile(
  new URL(import.meta.resolve('@kaigeliang/jsonlogic-sdk/wasm'))));
console.log(js.apply({var: 'amount'}, {amount: 12.5}));
console.log(wasm.apply({var: 'amount'}, {amount: 12.5}));
```

包的 `/formio` 导出适配器，`/module` 和 `/wasm` 导出编译模块路径。浏览器部署保持包内 `sdk/` 与 `output/sdk/` 的相对布局，或显式传入编译模块 URL。此压缩包是本地／CI 交付，不能直接从 npm registry 按包名安装。

## 实际表单接入

```sh
npm run build:browser
npm run serve:browser
```

打开终端地址。`examples/browser/form.json` 包含三个规则：年龄至少 18 显示备注、数量乘单价计算金额、校验码必须为 `MOON`。修改实际输入、验证当前表单、切换后端，页面显示调用结果和诊断。切换后端和运行接入验证均保留当前输入；加载期间暂时禁用表单操作。

`validateFormioSchema(schema)` 在渲染前检查三种配置：`conditional.json`、对象形式的 `calculateValue`、`validate.json`。`installFormioJsonLogic(jsonLogic, evaluator, schema)` 替换实际 `@formio/core/utils` 共享的 `jsonLogic.apply`；Form.io 渲染器继续负责组件生命周期，求值由 MoonBit 完成。

```js
import {Formio} from '@formio/js/form';
import {jsonLogic} from '@formio/core/utils';
import {installFormioJsonLogic} from './sdk/formio.mjs';
const hook = installFormioJsonLogic(jsonLogic, evaluator, schema);
const form = await Formio.createForm(container, structuredClone(schema));
// Form.io may swallow rule exceptions: enforce the retained diagnostic gate.
hook.assertHealthy();
// Before switching evaluators or disposing:
await form.destroy();
hook.restore();
```

同一 JavaScript 上下文只安装一个活动接入 hook；多个表单或其他调用若使用不同规则需自行隔离。只执行预检 schema 中的规则，规则身份改变需要重新预检。错误由 hook 留存，应用提交前必须调用 `assertHealthy()`；不能只依赖表单自身的验证成功状态。Form.io 的 undefined 空对象字段会被省略，空数组位置会被转换为 null；其余非 JSON 值拒绝。

组件预检沿 `components`、`columns`、`rows` 布局遍历；默认值和 metadata 按字面数据处理。规则身份比较前先严格验证 JSON 数据属性，不执行 getter 或 `toJSON`。

支持标准数据、条件、比较、算术、字符串、`in`、`merge` 和 missing 操作。`var` 必须静态引用 `data.*`、`row.*`、`input`、`value` 或整个 data／row。集合操作、`log`、`_sum`、`getDate` 等扩展和脚本配置拒绝。此接入范围比核心求值器窄，也不声明支持全部 Form.io schema。

Form.io 使用已有实际渲染器，包含界面与 DOM 依赖。esbuild 为其旧式依赖明确设置 `global: globalThis`，SDK 和 Wasm 模块仍分别加载。

## 可复现验证

```sh
npm run check:sdk
npm run check:formio
npm run check:bundle
npm run build:browser
npx --no-install playwright install chromium
npm run check:browser
```

- SDK：JS／Wasm GC 各对照 315 个固定用例，并检查日志、18 种宿主值拒绝、11 类错误边界与负控。
- 压缩包：离线安装到仓库外临时应用；核验安装文件、两后端各 315 用例、预算错误、日志、Form.io 导出以及 TypeScript 类型约束。
- Form.io：jsdom 中运行真实 5.6.1 渲染器，两后端各三个场景；捕获实际规则和上下文并逐项对照固定原版，再由 native CLI 重放所有调用。`output/sdk/formio-native-report.json` 绑定观察输入和 native 二进制的 SHA-256。
- Chromium：通过真实 textbox 输入检查三场景、两后端以及 JS → Wasm GC → JS 切换；额外使用不同于 fixtures 的输入验证切换后端和自检后数据保留。断言无页面／console 错误，保存六张截图和机器可读报告到 `output/playwright/`。脚本使用 Playwright CLI 隔离会话和临时本地服务，结束后只关闭自身会话与服务。

以上验证针对固定版本和指定场景，不代表任意框架配置、浏览器或生产接入均兼容。Form.io 配置概念见[官方文档](https://help.form.io/form-building/logic-and-conditions)；SDK 的完整 JSONLogic 边界见[兼容契约](compatibility.md)。
