Skip to content

feat: Parse remap.layout_options extension in keyboard.json - #928

Open
yoichiro wants to merge 1 commit into
feature/workbench-remap-module-togglefrom
feature/workbench-remap-layout-options
Open

feat: Parse remap.layout_options extension in keyboard.json#928
yoichiro wants to merge 1 commit into
feature/workbench-remap-module-togglefrom
feature/workbench-remap-layout-options

Conversation

@yoichiro

@yoichiro yoichiro commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

Phase 1 of the runtime layout options work coordinated with the remap-qmk-module and remap-build-server sessions: the type definitions and validating parser for a new Remap-only extension field in QMK's keyboard.json.

  • Adds RemapLayoutOptions / RemapLayoutVariant types under src/services/workbench/types/RemapLayoutOptions.ts, mirroring the exchanged spec (remap.layout_options.{labels, variants}).
  • Adds parseRemapLayoutOptions() under src/services/workbench/RemapLayoutOptionsParser.ts. A missing remap.layout_options is a valid state and yields { success: true, data: null }; a present-but-broken field yields { success: false, errors: [...] } with a full list of human-readable errors.
  • QMK ignores the unknown remap field, and remap-qmk-module will convert it into VIA-style layouts.labels + KLE-encoded layouts.keymap at firmware-build time. Client-side validation mirrors the invariants the converter enforces so any keyboard.json that the Form Editor accepts will convert cleanly server-side.
  • Stacks on top of feat: Add Remap module toggle to keyboard.json form editor #927 (Remap module toggle). The next phases will surface this in the Form Editor UI and in the Visual Editor preview.

Invariants enforced by the parser

  • One-element labels (e.g. ["Split Backspace"]) is the implicit Off/On idiom. Two-element labels are ambiguous and are rejected up-front so a well-defined mapping to VIA JSON is always possible.
  • variants[].option must index into labels.
  • variants[].choice must fit that option's choice count (two for a one-element label, labels[option].length - 1 for an explicit multi-choice label).
  • Every required (option, choice) pair must be covered by at least one variant.
  • A matrix cell cannot appear both in the default layout keys and in variants, and cannot repeat within the same (option, choice).
  • The optional layoutDefaultKeys input drives the LAYOUT-vs-variants matrix-collision check; callers that only want to validate the remap section in isolation can omit it.

Test plan

  • npm run type-check passes.
  • npm run lint — no new errors from the touched files.
  • npm test -- --run — all tests pass (1237 total).
  • npm test -- RemapLayoutOptionsParser.test.ts --run — 24 targeted cases pass, covering: absence handling (null / non-object inputs), a minimal Split Backspace layout, implicit Off/On labels, an explicit three-choice layout, optional key fields (w, h, r, rx, ry) round-trip, two-element label rejection, empty label / non-array label rejection, empty variants rejection, empty variants[].keys rejection, out-of-range option / choice, malformed matrix / missing x/y, missing choice coverage (implicit and explicit), matrix collision with LAYOUT_default, (option, choice, matrix) duplication within variants, same matrix allowed across different (option, choice) pairs, and the LAYOUT cross-check being skipped when layoutDefaultKeys is omitted.

Adds the phase 1 types and parser for the runtime layout options
extension embedded in a QMK keyboard.json. QMK ignores the unknown
`remap` field, and the `remap-qmk-module` build tool later converts
it into VIA-style `layouts.labels` + KLE-encoded `layouts.keymap`.

The parser mirrors the invariants that will be enforced server-side:
- one-element labels are the implicit Off/On idiom; two-element labels
  are ambiguous and rejected up-front
- variants[].option must index into labels, variants[].choice must
  fit that option's choice count, and every required (option, choice)
  must be covered by at least one variant
- a matrix cell cannot appear both in LAYOUT_default and in variants,
  and cannot repeat within the same (option, choice)

The next phases will surface this in the Form Editor UI and in the
Visual Editor preview.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant