Skip to content

Semantic string types declare Validate* format rules that are never enforced and contradict what the library actually accepts #156

Description

@matt-edmondson

What's wrong

Every semantic string type in Keybinding/Models carries a [GeneratedRegex] pattern and a public static Validate* method describing a strict format, but nothing calls these methods and no validation attribute is applied, so Create(...) accepts anything non-empty. Worse, the declared rules contradict behaviour the library deliberately relies on, so they can't simply be switched on.

Type Declared rule Reality
NoteName ^[A-Z0-9_]+$ Note stores + and , as keys ("Ctrl++", "Ctrl+,", fixed in #108), and SeparatorKeyParsingTests asserts this
CommandId ^[a-z0-9]+(\.[a-z0-9]+)*$ ("category.action") Any id works: "File.Save", "myCommand", "File.Save!!"
ProfileId kebab-case, at least 2 chars Never used: Profile.Id is a plain string
ProfileName letters/digits/space/-/_ Never used: Profile.Name is a plain string
ChordString, PhraseString letters/digits/+/,/space/-/_ Never referenced anywhere. Their patterns would also reject valid chords like "Ctrl+," in ChordString
CommandName, CommandCategory, CommandDescription restricted character sets Not enforced: CommandName.Create("Save & Close") succeeds

I checked this against the build at HEAD with a small console app:

NoteName.Create("+")            -> OK "+"
NoteName.Create("a b!")         -> OK "a b!"
CommandId.Create("File.Save!!") -> OK
ProfileId.Create("X")           -> OK
CommandId.ValidateCommandId("File.Save") -> "Command ID must follow the format 'category.action' ..."

Why it matters

  • A reader or contributor reads ValidateNoteName/ValidateCommandId and concludes that ids and keys are restricted. They aren't, and code written on that assumption (for example, using a command id as a file name) is wrong.
  • The repository's CLAUDE.md tells contributors to "use validation attributes on semantic strings". Anyone who does that for these types by wiring up the existing rules would break +/, key bindings and every mixed-case command id that users already have in commands.json/profiles.json.
  • ProfileId, ProfileName, ChordString and PhraseString are public, unused API that ships in the package. The same goes for the ModifierKeys and SpecialKeys enums, which nothing in the library reads.

Suggested fix

Make the declared rules match what the library accepts, in one of two ways:

  1. Remove the dead rules (preferred). Delete the GeneratedRegex/Validate* members that aren't enforced. Mark the unused public types (ProfileId, ProfileName, ChordString, PhraseString, ModifierKeys, SpecialKeys) [Obsolete] now and remove them in the next major version.
  2. Enforce corrected rules. If some constraint is wanted (for example, no control characters in a NoteName), rewrite the rule so it accepts everything the library already produces and persists, including +, ,, and mixed-case or dotted command ids. Then apply it with a proper validation attribute and add tests.

Acceptance criteria

  • No semantic type exposes a validation rule that Create doesn't enforce.
  • Any enforced rule accepts every key and id the existing tests and README examples use ("+", ",", "file.save", "File.Save").
  • Unused public model types are either deprecated or given a real use.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions