Skip to content

Refuse a save that can't be loaded back, and load a hand-added $schema [patch] - #382

Open
matt-edmondson wants to merge 1 commit into
mainfrom
fix/dollar-keys-376
Open

matt-edmondson wants to merge 1 commit into
mainfrom
fix/dollar-keys-376

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #376

What was wrong

AppData.JsonSerializerOptions uses ReferenceHandler.Preserve. Under that option System.Text.Json writes a dictionary key such as "$HOME", but throws when it reads it back. LoadOrCreate then archived the file as .corrupt and reset every setting, not only the dictionary. A top-level "$schema" added by hand for editor validation failed the same way.

Change

This is the "at minimum" step from the issue and its triage comment:

  • Save() deserializes the document it is about to write, using the same exceptions the load path recovers from. If that fails, it throws JsonException naming the type and the likely cause, before anything is written. The file on disk keeps its last good contents, so the data loss now shows up as an error at save time.
  • LoadOrCreate removes a top-level "$schema" property before deserializing. It only parses when the text contains "$schema". A document that can't be parsed goes to the deserializer unchanged and is archived as before. The next save does not write the $schema back.

The move away from Preserve itself, which could also close #353, is left for a separate change. It needs a fallback reader for existing $id/$values files.

Cost: every save now runs one extra deserialize of the settings document. Settings files are small.

Tests

New DollarPropertyTests:

  • SaveRefusesADollarKeyAndKeepsTheLastGoodFile ($HOME, $schema, $id): the save throws, the last good save still loads, and nothing is archived.
  • HandAddedSchemaPropertyLoads: this is the issue's {"$schema":...,"Theme":"Dark"} case.
  • SchemaPropertyBeforePreservedReferenceMetadataLoads: a $schema placed before the file's own $id.
  • Guards that pass either way: OrdinaryDictionaryKeysStillRoundTrip (HOME, a$b) and NestedSchemaKeyIsStillUnreadable.

With AppData.cs reverted, 5 of the 7 new cases fail. The two guards pass either way. Full suite on Linux / .NET 10: 152/152 passed. A Release build of the library succeeds for all six target frameworks.


Generated by Claude Code

…a [patch]

ReferenceHandler.Preserve writes a dictionary key starting with '$' but
throws on reading it, so the next load archived the file as corrupt and
reset every setting. Save() now reads the document back first and throws
JsonException without touching the file. A top-level "$schema" added by
hand for editor validation is dropped before deserializing.

Fixes #376

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW44rALLJaHHtXa8D2t
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant