Files
Endoleap/src/lib/canvas-core/element-data.ts
T

39 lines
2.6 KiB
TypeScript

/**
* 元素数据的捕获来源与内置 schema 校验缓存。
* 缓存是性能优化,只能用于框架掌控的不可变记录/纯校验器;自定义校验器每次仍调用。
*/
import type {ElementRecord,ComponentDefinition} from './types.ts';
import {detachJsonData} from './json-data.ts';
// Provenance comes from detaching JSON data, never from an external freeze or
// document envelope. This does not assert record validity or registry support.
const owned=new WeakSet<object>();
/** 已由本模块捕获的记录直接复用;外部记录重新按 JSON 语义复制冻结,再标记新记录身份。
* 此处不调用组件 schema;捕获成功与记录合法是两项独立事实。 */
export function detachElementData(record:ElementRecord):ElementRecord{
if(record&&typeof record==='object'&&owned.has(record))return record;
const value=detachJsonData(record);
if(value&&typeof value==='object')owned.add(value);
return value;
}
/** 证明记录来自本模块捕获;不证明其 type、版本、结构或关联引用有效。 */
export const hasOwnedElementData=(record:ElementRecord)=>!!record&&typeof record==='object'&&owned.has(record);
// Framework-owned validators depend only on detached immutable data. Custom
// validators remain live, including their method receiver and external context.
const builtinValidators=new WeakSet<Function>(),dataProofs=new WeakMap<object,ComponentDefinition['validate']>();
/** 标记框架内置、仅依赖输入的纯校验器;不要用它包装依赖外部可变状态的校验器。
* WeakSet 只记录这项声明,不能自动证明函数无副作用或不读取闭包状态。 */
export function builtinDataValidator<T extends ComponentDefinition['validate']>(validate:T):T{builtinValidators.add(validate);return validate;}
/** 检查组件 data,只有“owned 记录 + 内置 validator”组合才允许复用成功结果。
* 失败不缓存;更换 validator 后缓存也不命中;Reflect.apply 保留定义对象作为 this。 */
export function componentDataValid(record:ElementRecord,definition:ComponentDefinition):boolean{
// record 身份和具体 validator 函数同时匹配,才能跳过一次已成功的 schema 检查。
const validate=definition.validate,reusable=hasOwnedElementData(record)&&builtinValidators.has(validate);
if(reusable&&dataProofs.get(record)===validate)return true;
// 校验器抛错会直接传播给上层;这里只缓存正常返回且通过的结果,不吞错或缓存失败。
const valid=Reflect.apply(validate,definition,[record.data]);
if(valid&&reusable)dataProofs.set(record,validate);
return valid;
}