Repository navigation
Open
Labels
enhancementNew feature or requestNew feature or request
Description
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/ValidateCommandIdand 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 incommands.json/profiles.json. ProfileId,ProfileName,ChordStringandPhraseStringare public, unused API that ships in the package. The same goes for theModifierKeysandSpecialKeysenums, which nothing in the library reads.
Suggested fix
Make the declared rules match what the library accepts, in one of two ways:
- 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. - 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
Createdoesn'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.
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Activity
matt-edmondson commentedon Sep 29, 2026
Triage
Validate*rules and the unused public types mislead readers, and wiring the rules up as written would break existing+/,bindings. Option 1 in the issue (remove the dead rules, mark the unused types[Obsolete]) is the safer path, and it defers the breaking removal to the next major version.Keybinding/Models(semantic string types)Generated by Claude Code