From 4b79e53f0dd4705fbac2288defa2f369c8b18fee Mon Sep 17 00:00:00 2001 From: Guilhem Date: Wed, 20 Aug 2025 23:40:14 +0100 Subject: [PATCH] fix unsafe mutation in input picker getter (#6428) * fix bad mutation * remove unnecessary data structure for step args --- .../lib/components/ModulePreviewForm.svelte | 10 +-- frontend/src/lib/components/ModuleTest.svelte | 4 +- .../flows/propPicker/InputPickerInner.svelte | 2 +- .../lib/components/flows/testSteps.svelte.ts | 65 ++++++++++--------- frontend/src/lib/components/flows/utils.ts | 2 - 5 files changed, 41 insertions(+), 42 deletions(-) diff --git a/frontend/src/lib/components/ModulePreviewForm.svelte b/frontend/src/lib/components/ModulePreviewForm.svelte index 527c019950..58c0ee6782 100644 --- a/frontend/src/lib/components/ModulePreviewForm.svelte +++ b/frontend/src/lib/components/ModulePreviewForm.svelte @@ -98,14 +98,11 @@ loadResourceTypes() - let args = $state(>{}) - onMount(() => { if (!testSteps) { sendUserToast('testSteps module not initialized. Preview will not work.', true) } testSteps?.updateStepArgs(mod.id, flowStateStore.val, flowStore?.val, previewArgs?.val) - args = testSteps?.getStepArgs(mod.id) }) @@ -120,14 +117,17 @@ )} data-arg={argName} > - {#if typeof args.value == 'object' && schema?.properties?.[argName]} + {#if schema?.properties?.[argName]} testSteps?.getStepInputArgs(mod.id, argName) ?? {}, + (v) => testSteps?.setStepInputArgs(mod.id, argName, v) + } type={schema.properties[argName].type} oneOf={schema.properties[argName].oneOf} required={schema?.required?.includes(argName)} diff --git a/frontend/src/lib/components/ModuleTest.svelte b/frontend/src/lib/components/ModuleTest.svelte index d424321e8f..ba422ccee1 100644 --- a/frontend/src/lib/components/ModuleTest.svelte +++ b/frontend/src/lib/components/ModuleTest.svelte @@ -31,12 +31,12 @@ let stepHistoryLoader = getStepHistoryLoaderContext() export function runTestWithStepArgs() { - runTest(testSteps.getStepArgs(mod.id)?.value) + runTest(testSteps.getStepArgs(mod.id)) } export function loadArgsAndRunTest() { testSteps?.updateStepArgs(mod.id, flowStateStore.val, flowStore?.val, previewArgs?.val) - runTest(testSteps.getStepArgs(mod.id)?.value) + runTest(testSteps.getStepArgs(mod.id)) } export async function runTest(args: any) { diff --git a/frontend/src/lib/components/flows/propPicker/InputPickerInner.svelte b/frontend/src/lib/components/flows/propPicker/InputPickerInner.svelte index 11473aca9c..193574b044 100644 --- a/frontend/src/lib/components/flows/propPicker/InputPickerInner.svelte +++ b/frontend/src/lib/components/flows/propPicker/InputPickerInner.svelte @@ -20,7 +20,7 @@ testSteps?.updateStepArgs(id, flowStateStore?.val, flowStore?.val, previewArgs?.val) }) - const input = $derived(testSteps?.getStepArgs(id)?.value) + const input = $derived(testSteps?.getStepArgs(id))
diff --git a/frontend/src/lib/components/flows/testSteps.svelte.ts b/frontend/src/lib/components/flows/testSteps.svelte.ts index 7d66bb340f..71336cfe8f 100644 --- a/frontend/src/lib/components/flows/testSteps.svelte.ts +++ b/frontend/src/lib/components/flows/testSteps.svelte.ts @@ -6,34 +6,35 @@ import { getStepPropPicker, type PickableProperties } from './previousResults' -import { evalValue, type ModuleArgs } from './utils' +import { evalValue } from './utils' export class TestSteps { - #stepsEvaluated = $state>({}) - #steps = $state>({}) + #stepsEvaluated = $state>>({}) + #steps = $state>>({}) - constructor() { } + constructor() {} setStepArgsManually(moduleId: string, args: Record) { - if (!this.#steps[moduleId]) { - this.#steps[moduleId] = { value: {} } - } - this.#steps[moduleId].value = args + this.#steps[moduleId] = args } - getStepArgs(moduleId: string): ModuleArgs { - let args = this.#steps[moduleId] - if (!args) { - this.#steps[moduleId] = { value: {} } - } + getStepArgs(moduleId: string): Record | undefined { return this.#steps[moduleId] } + getStepInputArgs(moduleId: string, argName: string): any | undefined { + return this.#steps[moduleId]?.[argName] + } + setStepArgs(moduleId: string, args: Record) { + this.#steps[moduleId] = args + } + + setStepInputArgs(moduleId: string, argName: string, value: any) { if (!this.#steps[moduleId]) { - this.#steps[moduleId] = { value: {} } + this.#steps[moduleId] = {} } - this.#steps[moduleId].value = args + this.#steps[moduleId][argName] = value } getStepArg(moduleId: string, argName: string): any | undefined { @@ -42,26 +43,26 @@ export class TestSteps { setEvaluatedStepArg(moduleId: string, argName: string, value: any) { if (!this.#steps[moduleId]) { - this.#steps[moduleId] = { value: {} } + this.#steps[moduleId] = {} } if (!this.#stepsEvaluated[moduleId]) { - this.#stepsEvaluated[moduleId] = { value: {} } + this.#stepsEvaluated[moduleId] = {} } - this.#steps[moduleId].value[argName] = $state.snapshot(value) - this.#stepsEvaluated[moduleId].value[argName] = $state.snapshot(value) + this.#steps[moduleId][argName] = $state.snapshot(value) + this.#stepsEvaluated[moduleId][argName] = $state.snapshot(value) } isArgManuallySet(moduleId: string, argName: string): boolean { return ( - JSON.stringify(this.#steps[moduleId]?.value?.[argName]) !== - JSON.stringify(this.#stepsEvaluated[moduleId]?.value?.[argName]) + JSON.stringify(this.#steps[moduleId]?.[argName]) !== + JSON.stringify(this.#stepsEvaluated[moduleId]?.[argName]) ) } getManuallyEditedArgs(moduleId: string): string[] { const manuallyEditedArgs: string[] = [] - const moduleArgs = this.#steps[moduleId]?.value ?? {} + const moduleArgs = this.#steps[moduleId] ?? {} Object.keys(moduleArgs).forEach((argName) => { if (this.isArgManuallySet(moduleId, argName)) { @@ -105,8 +106,8 @@ export class TestSteps { const pickableProperties = stepPropPicker.pickableProperties const argSnapshot = $state.snapshot(evalValue(argName, modules[0], pickableProperties, false)) - this.#stepsEvaluated[moduleId].value[argName] = argSnapshot - this.#steps[moduleId].value[argName] = structuredClone(argSnapshot) + this.#stepsEvaluated[moduleId][argName] = argSnapshot + this.#steps[moduleId][argName] = structuredClone(argSnapshot) } initializeFromSchema( @@ -124,21 +125,21 @@ export class TestSteps { const manuallyEditedArgs = this.getManuallyEditedArgs(mod.id) if (!this.#steps[mod.id]) { - this.#steps[mod.id] = { value: {} } + this.#steps[mod.id] = {} } if (!this.#stepsEvaluated[mod.id]) { - this.#stepsEvaluated[mod.id] = { value: {} } + this.#stepsEvaluated[mod.id] = {} } - this.#stepsEvaluated[mod.id].value = $state.snapshot(args) + this.#stepsEvaluated[mod.id] = $state.snapshot(args) // Preserve manually edited args const argsSnapshot = $state.snapshot(args) Object.keys(argsSnapshot).forEach((key) => { if (manuallyEditedArgs.includes(key)) { - argsSnapshot[key] = this.#steps[mod.id]?.value?.[key] + argsSnapshot[key] = this.#steps[mod.id]?.[key] } }) - this.#steps[mod.id].value = argsSnapshot + this.#steps[mod.id] = argsSnapshot } updateStepArgs( @@ -177,11 +178,11 @@ export class TestSteps { return } const nargs = {} - Object.keys(this.#stepsEvaluated[moduleId]?.value ?? {}).forEach((key) => { + Object.keys(this.#stepsEvaluated[moduleId] ?? {}).forEach((key) => { if (keys.includes(key)) { - nargs[key] = this.#stepsEvaluated[moduleId]?.value?.[key] + nargs[key] = this.#stepsEvaluated[moduleId]?.[key] } }) - this.#stepsEvaluated[moduleId].value = nargs + this.#stepsEvaluated[moduleId] = nargs } } diff --git a/frontend/src/lib/components/flows/utils.ts b/frontend/src/lib/components/flows/utils.ts index cf5979c2b4..d7b5e1db90 100644 --- a/frontend/src/lib/components/flows/utils.ts +++ b/frontend/src/lib/components/flows/utils.ts @@ -31,8 +31,6 @@ return ${eval_string} }` } -export type ModuleArgs = { value: Record } - function make_context_evaluator(eval_string, context): (context) => any { let template = create_context_function_template(eval_string, context) let functor = Function(template)