From 6f74207a7d74c023329ded8945d5174bc83a8449 Mon Sep 17 00:00:00 2001 From: Benno Stein Date: Fri, 22 Nov 2024 13:31:43 +0000 Subject: [PATCH] Clone proxy objects when they're bound as mapper/resource params --- skiplang/skjson/ts/src/skjson.ts | 4 ++- .../wasm/src/internals/skipruntime_module.ts | 33 +++++++++---------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/skiplang/skjson/ts/src/skjson.ts b/skiplang/skjson/ts/src/skjson.ts index da7c9ca7a..13053bf42 100644 --- a/skiplang/skjson/ts/src/skjson.ts +++ b/skiplang/skjson/ts/src/skjson.ts @@ -151,7 +151,9 @@ type ObjectProxy = { keys: IterableIterator; } & Base; -function isObjectProxy(x: any): x is ObjectProxy<{ [k: string]: Exportable }> { +export function isObjectProxy( + x: any, +): x is ObjectProxy<{ [k: string]: Exportable }> { return sk_isObjectProxy in x && (x[sk_isObjectProxy] as boolean); } diff --git a/skipruntime-ts/wasm/src/internals/skipruntime_module.ts b/skipruntime-ts/wasm/src/internals/skipruntime_module.ts index adc6b637f..ce1759ad4 100644 --- a/skipruntime-ts/wasm/src/internals/skipruntime_module.ts +++ b/skipruntime-ts/wasm/src/internals/skipruntime_module.ts @@ -37,6 +37,7 @@ import { NonUniqueValueException } from "@skipruntime/api"; import { Frozen, type Constant } from "@skipruntime/api/internals.js"; import type { Exportable, SKJSON } from "@skip-wasm/json"; +import { isObjectProxy } from "@skip-wasm/json"; import { UnknownCollectionError } from "@skipruntime/helpers/errors.js"; export type Handle = Internal.Opaque; @@ -64,22 +65,20 @@ abstract class SkFrozen extends Frozen { } } -export function check(value: T): void { +function checkOrCloneParam(value: T): T { if ( typeof value == "string" || typeof value == "number" || typeof value == "boolean" - ) { - return; - } else if (typeof value == "object") { - if (value === null || isSkFrozen(value)) { - return; - } else { - throw new Error("Invalid object: must be deep-frozen."); - } - } else { - throw new Error(`'${typeof value}' cannot be deep-frozen.`); + ) + return value; + if (typeof value == "object") { + if (value === null) return value; + if (isObjectProxy(value)) return value.clone() as T; + if (isSkFrozen(value)) return value; + throw new Error("Invalid object: must be deep-frozen."); } + throw new Error(`'${typeof value}' cannot be deep-frozen.`); } /** @@ -985,8 +984,8 @@ class EagerCollectionImpl mapper: new (...params: Params) => Mapper, ...params: Params ): EagerCollection { - params.forEach(check); - const mapperObj = new mapper(...params); + const mapperParams = params.map(checkOrCloneParam) as Params; + const mapperObj = new mapper(...mapperParams); Object.freeze(mapperObj); if (!mapperObj.constructor.name) { throw new Error("Mapper classes must be defined at top-level."); @@ -1011,8 +1010,8 @@ class EagerCollectionImpl reducer: Reducer, ...params: Params ) { - params.forEach(check); - const mapperObj = new mapper(...params); + const mapperParams = params.map(checkOrCloneParam) as Params; + const mapperObj = new mapper(...mapperParams); Object.freeze(mapperObj); if (!mapperObj.constructor.name) { throw new Error("Mapper classes must be defined at top-level."); @@ -1116,8 +1115,8 @@ class ContextImpl extends SkFrozen implements Context { compute: new (...params: Params) => LazyCompute, ...params: Params ): LazyCollection { - params.forEach(check); - const computeObj = new compute(...params); + const mapperParams = params.map(checkOrCloneParam) as Params; + const computeObj = new compute(...mapperParams); Object.freeze(computeObj); if (!computeObj.constructor.name) { throw new Error("LazyCompute classes must be defined at top-level.");