@fuaran-ui/ops

中文文档
0.33.5发布于 2026/11/15Apache-2.0TypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 2008

Canonical-JSON codec (encoder + structural decoder) and tree-op apply engine for the Fuaran UI wire format — a conformant TypeScript host of the language-neutral contract in fuaran-dotnet/docs/WIRE_FORMAT.md, verified byte-for-byte against the workspace w

原始使用文档
文档目录8 节
  1. What it is
  2. API
  3. Three modules
  4. DecodeError codes (WIRE_FORMAT.md §6)
  5. Placement helpers
  6. Storage-shape erasure
  7. Conformance is the stability contract
  8. Licence

@fuaran-ui/ops

Canonical-JSON codec (encoder + structural decoder) and tree-op apply engine for the Fuaran UI wire format — a conformant TypeScript host of the language-neutral contract specified in fuaran-dotnet/docs/WIRE_FORMAT.md, sibling to the F# host. Built on the typed shapes from @fuaran-ui/schema (a peer dependency).

npm install @fuaran-ui/ops @fuaran-ui/schema

What it is

The correctness layer of the TypeScript reference implementation. @fuaran-ui/schema gives you the typed tree; this package makes a TS-authored tree wire-conformant — it can be serialised, persisted, replayed, and exchanged with the F# tier byte-for-byte. Verified end-to-end against the workspace wire-format-fixtures/ corpus: every valid fixture round-trips byte-identically to the F# encoder, and every reject fixture surfaces the same DecodeErrorCode at the same JSON path.

API

import { encodeNode, decodeNode, encodeOp, decodeOp, apply } from '@fuaran-ui/ops';
import type { TreeOp, DecodeError, ApplyError } from '@fuaran-ui/ops';

// Encode (typed tree → canonical JSON string)
const json: string = encodeNode(node);

// Decode (canonical JSON string → storage-shape Node<unknown> | DecodeError)
const decoded = decodeNode(json); // Result<Node<unknown>, DecodeError>
if (decoded.ok) {
  /* decoded.value : Node<unknown> */
}

// TreeOp codec
const opJson = encodeOp(op);
const op = decodeOp(opJson); // Result<TreeOp<unknown>, DecodeError>

// Apply a tree-op (→ new tree + telemetry | ApplyError)
const result = apply(tree, op); // ApplyResult<TMsg>
if (result.ok) {
  /* result.value.newTree, result.value.emittedTelemetry */
}

Three modules

ModuleRole
encodeSymmetric port of the F# CanonicalJson encoder. Deterministic, byte-stable output.
decodePort of the F# JsonDecode decoder. Structural, Result-returning, six error codes.
applyPort of the F# apply engine. Atomic (Batch), revert-on-error, emits telemetry.

DecodeError codes (WIRE_FORMAT.md §6)

INVALID_JSON, MISSING_FIELD, WRONG_TYPE, UNKNOWN_DU_CASE, WRONG_NODE_KIND, EMPTY_NODE_ID — byte-identical to the F# decoder's codes, surfaced at a $-rooted dotted path.

Placement helpers

placeOp / moveOp / nudgeOp / canPlace (plus the clone verbs duplicateOp / pasteOp and their …With variants taking an injectable fresh-id strategy) derive the ops that put a node at a stated position — first, last, before or after a named sibling — from the positionless op vocabulary.

import { placeOp, moveOp, nudgeOp, canPlace, apply } from '@fuaran-ui/ops';

// Insert `child` immediately before sibling "b" under parent "left".
const r = placeOp(tree, child, {
  parentId: 'left',
  placement: { kind: 'Before', anchor: 'b' },
}); // Result<TreeOp, PlaceError>
if (r.ok) apply(tree, r.value);

These helpers emit only existing TreeOp shapes — a bare InsertChild / MoveNode when appending already yields the wanted order, otherwise Batch [InsertChild|MoveNode, ReorderChildren], and ReorderChildren alone for a nudge. There is no new op case and no wire-format change; anything they emit encodes, decodes, and applies exactly as if a consumer had assembled it by hand. Pre-checks mirror the apply engine's own rejections (absent or childless parent, move-into-self, move-into-descendant, duplicate id), so a helper refusal and an apply refusal always agree; an anchor that is not among the destination's children is refused (UnknownAnchor) rather than silently appended. The clone verbs remap colliding ids across the whole traversal surface before insert, so a duplicate or paste never trips the tree-wide duplicate-id check.

Storage-shape erasure

Decode is storage-shape erased: it always yields Node<unknown> / TreeOp<unknown>, because the wire carries no typed-'Msg information (every 'Msg payload and every closure encodes as the "<closure>" sentinel). Opaque Binding.Static payloads the encoder couldn't decompose decode to the literal string "<opaque>". Both placeholders re-encode to the same sentinel, so the round-trip stays byte-stable; typed re-attachment of the erased payloads is the host's responsibility.

Conformance is the stability contract

Per the wire-format forward-coupling rule (WIRE_FORMAT.md §11), adding a NodeKind / Spec / TreeOp / Binding / Action case updates the F# encoder + decoder + the corpus and this TS codec + @fuaran-ui/schema in the same commit. Byte-equality against the corpus — not just API non-breakage — is the contract.

Licence

Apache-2.0. See STABILITY.md for the per-surface stability declaration.

版本与发布记录

@fuaran-ui/ops 共发布 28 个版本,首次发布于 2026/07/25;过去 12 个月发布了 28 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.33.5latest2026/11/15今天
0.33.42026/11/142 天前
0.33.32026/11/133 天前
0.33.22026/11/123 天前
0.33.12026/11/114 天前
0.33.02026/11/114 天前

关于 @fuaran-ui/ops 的常见问题

@fuaran-ui/ops 是什么?

Canonical-JSON codec (encoder + structural decoder) and tree-op apply engine for the Fuaran UI wire format — a conformant TypeScript host of the language-neutral contract in fuaran-dotnet/docs/WIRE_FORMAT.md, verified byte-for-byte against the workspace w

如何安装 @fuaran-ui/ops?

在项目目录运行 npm install @fuaran-ui/ops,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@fuaran-ui/schema(^0.28.1)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@fuaran-ui/ops 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@fuaran-ui/ops 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@fuaran-ui/ops 可以商用吗?

@fuaran-ui/ops 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@fuaran-ui/ops 的下载量有多少?

根据 npm 官方下载统计,@fuaran-ui/ops 在 2026/10/16 – 2026/11/14 这 30 天内被下载 2,008 次,日均约 67 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@fuaran-ui/ops 还在维护吗?

最新版本 0.33.5 发布于 2026/11/15(今天);至今共发布 28 个版本,其中过去 12 个月发布了 28 个;首次发布于 2026/07/25。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。