20 lines
1.3 KiB
TypeScript
20 lines
1.3 KiB
TypeScript
/**
|
|
* 框架自建容器的来源标记:只证明容器由本模块复制并浅冻结。
|
|
* 元素本身仍可能可变,因此该标记不能替代 JSON 捕获或深度不可变证明。
|
|
*/
|
|
// Private shape provenance: values may still be mutable and require capture.
|
|
// Always copy; external Object.freeze is never accepted as ownership evidence.
|
|
// WeakSet 以新容器身份为键,不按内容相等判断;容器不再被外部引用时,标记不会单独阻止回收。
|
|
const owned = new WeakSet<object>();
|
|
/** 消费 iterable 得到新数组并浅冻结;不会冻结数组中的业务值。 */
|
|
export function dataArray<T>(values: Iterable<T>): readonly T[] {
|
|
const result = Object.freeze(Array.from(values)); owned.add(result); return result;
|
|
}
|
|
/** 浅复制对象的可枚举自有属性再冻结外壳;不是任意对象的深复制器。
|
|
* 对象展开会读取 getter 并保留嵌套值引用,也不保留原对象原型或属性描述符。 */
|
|
export function dataRecord<T extends object>(value: T): Readonly<T> {
|
|
const result = Object.freeze({...value}); owned.add(result); return result;
|
|
}
|
|
/** 查询私有 WeakSet 来源,外部 Object.freeze 不能伪造这个事实。 */
|
|
export const isDataContainer = (value: object) => owned.has(value);
|