docs(core): clarify capture validation and replay guarantees
This commit is contained in:
@@ -5,11 +5,13 @@
|
||||
*/
|
||||
import type { Id, Json, ReadonlyValueSet } from './types.ts';
|
||||
|
||||
/** 构造携带稳定错误码和相关对象 ID 的错误,供命令层返回可解释的拒绝结果。 */
|
||||
/** 构造携带稳定错误码和相关对象 ID 的错误,供命令层返回可解释的拒绝结果。
|
||||
* targets 沿用传入数组引用;这个辅助函数本身不捕获或冻结错误明细。 */
|
||||
export function fault(code: string, targets: readonly Id[] = []): Error & { code: string; targets: readonly Id[] } {
|
||||
return Object.assign(new Error(code), { code, targets });
|
||||
}
|
||||
/** 将捕获的异常归一化为只读 rejected 结果;无领域错误码时使用 invalid_command。 */
|
||||
/** 将捕获的异常归一化为浅冻结的 rejected 外壳;无领域错误码时使用 invalid_command。
|
||||
* 已有 targets 数组仍沿用原引用,不应把外壳冻结解释为整个错误结果深度不可变。 */
|
||||
export function reject(error: unknown) {
|
||||
const value = error as { code?: string; targets?: readonly string[] };
|
||||
return Object.freeze({ status: 'rejected' as const, code: value?.code || 'invalid_command', targets: value?.targets || [] });
|
||||
@@ -24,13 +26,15 @@ export function freeze<T>(value: T): T {
|
||||
return value;
|
||||
}
|
||||
/** JSON 往返复制已验证的数据,切断共享引用;undefined 原样返回。
|
||||
* 此处不是校验器:JSON 会丢弃某些非法字段,因此外部输入必须在复制前验证。 */
|
||||
* 此处不是校验器:JSON 会执行 toJSON、读取可枚举字段并丢弃/改写不支持的值。
|
||||
* 不保留原型、描述符或共享子对象身份;需要严格输入语义时须在调用边界捕获。 */
|
||||
export function clone<T>(value: T): T {
|
||||
if (value === undefined) return value;
|
||||
return JSON.parse(JSON.stringify(value)) as T;
|
||||
}
|
||||
/** 按可枚举自有键递归比较 JSON 风格的值;数组与对象不能互相视为相等。
|
||||
* 不处理任意循环对象,也不把 Map/Set 等实例当成业务值来比较。 */
|
||||
/** 先以 Object.is 判断,再按可枚举自有字符串键递归比较 JSON 风格的值;数组与对象不能互相视为相等。
|
||||
* 不检查 Symbol/不可枚举字段,数组长度本身也不在 Object.keys 中;稀疏数组不适合作为此比较器的输入。
|
||||
* 不处理任意循环对象,也不提供 Map/Set 成员比较语义。 */
|
||||
export function equal(a: unknown, b: unknown): boolean {
|
||||
if (Object.is(a, b)) return true;
|
||||
if (!a || !b || typeof a !== 'object' || typeof b !== 'object' || Array.isArray(a) !== Array.isArray(b)) return false;
|
||||
@@ -46,6 +50,7 @@ export function isOwnedMapView(value:object){return ownedMapViews.has(value);}
|
||||
/** 复制表成员并仅暴露读取能力,外部既拿不到原 Map,也拿不到 set/delete。
|
||||
* value 保留原引用,深度不可变性由生产这些 value 的模块负责。 */
|
||||
export function readMap<K, V>(input: ReadonlyMap<K, V>): ReadonlyMap<K, V> {
|
||||
// 从此以后 input 的增删与本视图无关;但 K/V 对象仍共享引用,键/值本身不是在此深复制的。
|
||||
const map = new Map(input);
|
||||
const view: ReadonlyMap<K, V> = {
|
||||
get size() { return map.size; }, get: key => map.get(key), has: key => map.has(key),
|
||||
@@ -58,6 +63,7 @@ export function readMap<K, V>(input: ReadonlyMap<K, V>): ReadonlyMap<K, V> {
|
||||
}
|
||||
/** 捕获一份成员集合并隐藏 add/delete;回调同样只接触只读视图。 */
|
||||
export function readSet<T>(input: Iterable<T>): ReadonlyValueSet<T> {
|
||||
// 成员表独立于原 iterable,成员若为对象则仍保留原身份;隐藏可变方法并不冻结对象成员。
|
||||
const set = new Set(input);
|
||||
const view: ReadonlyValueSet<T> = {
|
||||
get size() { return set.size; }, has: key => set.has(key), entries: () => set.entries(), keys: () => set.keys(), values: () => set.values(),
|
||||
@@ -66,7 +72,9 @@ export function readSet<T>(input: Iterable<T>): ReadonlyValueSet<T> {
|
||||
return Object.freeze(view);
|
||||
}
|
||||
/** 递归检查 JSON 值域:排除 undefined/函数/非有限数,最多允许 64 层。
|
||||
* 这里只检查值形状,不验证组件 schema,也不是所有原型/属性描述符的严格捕获器。 */
|
||||
* 对象要求 Object.prototype 原型,但只遍历 Object.values;Symbol/不可枚举属性不参与。
|
||||
* 数组用 every 跳过空洞,也不检查额外属性;它不是稠密数组或所有属性描述符的严格捕获器。
|
||||
* 校验读取可能触发 getter;这里不证明组件 schema、输入稳定性或数据所有权。 */
|
||||
export function validJson(value: unknown, depth = 0): value is Json {
|
||||
if (depth > 64) return false;
|
||||
if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;
|
||||
|
||||
Reference in New Issue
Block a user