Repository navigation
refactor(config): type grid-style colors, fold validation (#118) - #178
Merged
Merged
Conversation
The flat validation stack maintained the grid-style key structure three times: 53 raw #RRGGBB strings on the records, a 242-line color-enumerating validator, and the mappers' string plumbing. Slice 4 of the #118 debloat replaces the strings with a typed value and moves validation to the one place hex is parsed, deleting the standalone validator. - StyleColor: a readonly record struct in Core (A/R/G/B, Avalonia-free) with Parse/TryParse/ToString. ToString emits #RRGGBB when opaque and #AARRGGBB otherwise, uppercase; Parse accepts exactly 6 or 8 hex digits and rejects the #RGB/#ARGB shorthand the file header wrongly advertised. - The 53 color fields across the group records become StyleColor. PaletteBrushFactory and the view model convert channel-wise via a new StyleColorConversions; HexColor is deleted. - GridStyleMapper.Map now returns Result<GridStyleOptions> and accumulates per-key errors in the load mapper: the same typed errors the deleted GridStyleValidator emitted, keyed by the same section path and key name, aggregated not fail-fast, in the same emission order. ReasonLocalizer output and the error tests are unchanged. GridStyleValidator is deleted; its two call sites (ConfigFacade startup, GridStyleEditorFacade) map through the same seat. The facade's Validate is a vacuous pass-through kept until slice 5 trims the interface. - Both shipped config headers drop the #RGB/#ARGB shorthand claim; the architecture doc's pipeline description follows the new one-pass mapper. The DTOs keep their string properties, so the on-disk YAML is unchanged; StyleColor.Default values are byte-equal to the old strings. The one behavior change is that hex case normalizes to uppercase on save, which the editor already does by rewriting the whole file. #118 stays open; slice 5 splits the view model and closes it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Problem
The grid-style config layer restated its key structure three times: 53 raw
#RRGGBBstrings on the group records, a 242-line color-enumeratingGridStyleValidator, and the mappers' string plumbing. "Is this hex valid" was asked far from where the string is parsed, and a color was an untypedstringeverywhere it flowed. Slice 4 of the #118 debloat types the colors and moves validation to the one place hex is parsed.What changed
StyleColor— areadonly record structin Core (A/R/G/B channels, Avalonia-free) withParse/TryParse/ToString.ToStringemits#RRGGBBwhen opaque and#AARRGGBBotherwise, uppercase;Parseaccepts exactly 6 or 8 hex digits and rejects the#RGB/#ARGBshorthand the file header wrongly advertised (the validator always rejected it too).StyleColoracross the group records.PaletteBrushFactoryand the view model convert channel-wise through a newStyleColorConversions;HexColoris deleted.GridStyleMapper.Mapnow returnsResult<GridStyleOptions>and accumulates per-key errors: the same typed errors the deletedGridStyleValidatoremitted, keyed by the same section path + key name, aggregated (not fail-fast), in the same emission order. Both call sites (ConfigFacadestartup,GridStyleEditorFacade) map through the one seat; the facade'sValidateis a deliberate vacuous pass-through kept until slice 5.GridStyleValidator(242 lines) is deleted.#RGB/#ARGBshorthand claim (comment-only; the writer copies headers forward, so the lie would have persisted); the architecture doc's load-pipeline description follows the new one-pass mapper.Out of scope by design (slice 5): the view-model split, grouped AXAML, and trimming the vacuous
Validateoff the interface. The DTOs keep theirstringproperties, so the on-disk YAML is unchanged.Verification
dotnet build SemiStep.slnx— 0 warnings;dotnet test— 1716 passed, 0 failed;dotnet formatclean.GridStyleValidator.Validate(dto)toGridStyleMapper.Map(dto)with byte-identical assertion bodies; the untouched localization + Russian-culture end-to-end message test pass unchanged. Diffed the deleted validator against the new mapper line-by-line: same error types, same section/key strings, same emission order.Validate_NullCells_FailsWithExactlyThreeSectionErrors— a nullCellsyields exactlycolors.cells.execution/readonly/disabledand no barecolors.cellserror (a path the entire prior suite never exercised).StyleColor.Defaultis byte-equal to the old strings;SaveThenLoad_DistinctFixture(record→dto→yaml→dto→record) green. The one behavior change is hex case normalizing to uppercase on save, which the editor already does by rewriting the whole file.Cellsregression test, 3StyleColoredge cases, the hand-rolled hex parse simplified tobyte.TryParse(AllowHexSpecifier), 2 comment trims.Slice 4 of #118 (stays open). Next: slice 5 splits the view model into per-group drafts + grouped AXAML, and closes #118.
Per-task commits before collapse
🤖 Generated with Claude Code