fix(scripting): apply step params in place instead of rebuilding from display text#251
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
FmScript.Applyrouted param maps through display-text synthesis (SynthesizeHrParams) and rebuilt the step withStepDisplayFactory.TryCreate, replacing the instance. That made every update destructive: params not named in the map reset to constructor defaults, state the display line can't carry (dialog geometry, button configuration, passthrough XML) was wiped, andHrOnly/ variant / value-type slots were dropped with no error. A Value-only update onSet Variable [ $x ; Value: 1 ]producedSet Variable [ Value: 2 ; Value: ]— the synthesized token mis-bound positionally into the Name slot.How
ScriptStep.ApplyParam(name, value): sets one shape-bound public property in place and returns an error message or null. TheScriptStep<TSelf>default dispatches to the newStepParamApplier, the validating counterpart ofStepDisplayParser— unknown names, non-On/Off booleans, and out-of-range enum values return errors instead of silently dropping.HrOnly, variant / value-type / list slots, emit-only wire projections (e.g. Perform Script'sParameterBeforeScript), and enums whoseDisplayValueshave no pairedValidValues— route through the step's own display-token grammar generically, with no per-step wiring: the synthesized token is validated against a blank probe (it must produce a wire-level change, so unrecognized values fail loudly), then re-parsed onto the live instance together with its current display tokens. Same-label current tokens are dropped and both token positions are tried, so first-match and last-match parser styles both take the new value; a token already present is an idempotent success.<SortList>…</SortList>,<Query>…</Query>): the fragment replaces the step element's same-named children and the merged element is re-read in place throughPopulateFromXml— so typed readers normalize it to canonical wire form. The fragment root must match the slot's wire element and the re-emitted step must retain it, otherwise the original state is restored and an error returned.ApplyUpdatemutatesSteps[i]in place; properties the map does not name keep their values.ApplyAddconstructs a blank POCO through the registry factory, applies params the same way, and no longer inserts when a param errors.SynthesizeHrParamsis deleted.ShowCustomDialogStep'sInputFieldsslot gainsHrLabel = "Inputs"so label-addressed lookups resolve to the token form its parser recognizes.Catalog audit
A probe swept all 438 (step, display slot) pairs in the catalog, attempting to set each param through
Applywith kind-appropriate values (On/Off for booleans, declared enum values, calc text, and a wire-element XML fragment for structured slots), verifying against the emitted XML. On the old path, 68 of the 438 were accepted and silently dropped or mangled; none returned an error.With this PR:
The 14 rejected pairs and the 1 quiet case
Real gap — wire lives nested inside a wrapper element the fragment graft cannot address:
TemplateName,SQLPrompt,NaturalLanguagePrompt,FindRequestPrompt,RAGPromptInternal wire-alias names — duplicates of params that work under their friendly name, or state with no addressable display form:
UseDialPreferencesValueLayoutDestination(the target is settable viaLayout)ExitWire,LocationCalcWireScriptWire,CalculatedWireAudit artifacts — the params behave correctly; the probe's synthetic values can't show it:
CreatePDFFileaccepts real fragments; the probe's placeholder fragment normalizes to the step's defaults, so the diff registers as unchangedContentTypecorrectly rejects a fragment aimed at a typed enum whose only valid value is the defaultQuiet case: Go to Portal Row's
CalculationWirewrite lands on the property but only emits onceRowPageLocationisByCalculation.Test plan
FmScriptApplyTestscover in-place instance identity, preservation of unmentioned params and XML-only state, loud errors (unknown param, invalid boolean, null value, unaddressable slot, wrong fragment root, malformed fragment), Perform Script targets and parameter, Show Custom Dialog buttons/inputs, Go to Layout targets, first-match parser ordering, idempotent re-application, and XML-fragment set/replace for SortList and Querydotnet test SharpFM.sln— 2343 passed, including the display round-trip contract suites