fix: schema inference not updating on reset and language switch (#8446)

Three root causes:

1. Editor.setCode() never dispatched `change` — it pre-set `code = ncode`
   before the Monaco edit, so the debounced updateCode() saw code == ncode
   and skipped dispatch. The Reset button, copilot accept, and other
   setCode callers never triggered schema inference. Fixed by capturing
   `changed` before the pre-set and dispatching directly when true.

2. EditableSchemaForm's $effect only tracked the schema reference, not
   its properties. Since inferArgs mutates schema in-place through the
   Svelte 5 proxy, the reference never changes and the effect never
   re-ran. Added schema?.order and Object.keys(schema?.properties ?? {})
   reads to detect in-place mutations (matching SchemaForm's pattern).

3. ScriptEditor's $effect depended on both selectedTab and code, causing
   a redundant double inferSchema call on every code change (racing with
   the on:change handler and initContent's explicit call). Moved code
   into untrack() so the effect only fires on tab switches.

Also removed the no-op `testPanelSchema = testPanelSchema` in
inferModuleSchema.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-03-19 06:23:38 +00:00
committed by GitHub
co-authored by Claude Opus 4.6
parent a8fa0cccef
commit c0edbe4317
3 changed files with 22 additions and 5 deletions
@@ -297,7 +297,9 @@
}
const editTabDefaultSize = untrack(() => noPreview) ? 100 : 50
editPanelSize = untrack(() => editTab) ? (untrack(() => editPanelInitialSize) ?? editTabDefaultSize) : 0
editPanelSize = untrack(() => editTab)
? (untrack(() => editPanelInitialSize) ?? editTabDefaultSize)
: 0
let inputPanelSize = $state(100 - editPanelSize)
let editPanelSizeSmooth = tweened(editPanelSize, {
duration: 150
@@ -331,6 +333,10 @@
}
})
$effect(() => {
// Track schema properties and order so this effect re-runs when
// inferArgs rebuilds the schema (not just on reference change).
schema?.order
Object.keys(schema?.properties ?? {})
schema && untrack(() => onSchemaChange())
})
$effect(() => {
+10 -2
View File
@@ -347,7 +347,9 @@
}
export function setCode(ncode: string, noHistory: boolean = false): void {
if (code != ncode) {
// Track whether the code actually changed before updating.
const changed = code != ncode
if (changed) {
code = ncode
}
@@ -368,7 +370,13 @@
editor.pushUndoStop()
}
}
// Update lint diagnostics after code change
// Dispatch change immediately when code actually changed. This ensures
// callers like the Reset button and copilot trigger on:change handlers.
// The debounced onDidChangeModelContent handler will no-op since code
// will already match by the time it fires.
if (changed) {
dispatch('change', ncode)
}
updateRawAppLintDiagnostics()
}
@@ -751,7 +751,6 @@
if (activeModuleTab === null) return
try {
await inferArgs(effectiveLang, editorCode, testPanelSchema)
testPanelSchema = testPanelSchema
moduleTestState[activeModuleTab] = { args: testPanelArgs, schema: testPanelSchema }
} catch (e) {
// Module code may be in-progress; silently ignore
@@ -1196,7 +1195,11 @@
!hasPreprocessor && (selectedTab = 'main')
})
$effect(() => {
selectedTab && code && untrack(() => inferSchema(code))
// Only depend on selectedTab (preprocessor ↔ main toggle).
// Code changes are handled by the editor on:change handler and
// explicit inferSchema calls (initContent, onMount), so we read
// `code` inside untrack to avoid a redundant double-inference race.
selectedTab && untrack(() => code && inferSchema(code))
})
let argsRender = $state(0)