Repository navigation
fix(cli): preserve UTF-8 BOM project configuration settings - #5725
Conversation
jrusso1020
left a comment
There was a problem hiding this comment.
Approving. A hyperframes.json with a UTF-8 BOM is valid JSON to every editor that writes one, and on main all three readers in projectConfig.ts hand it straight to JSON.parse, which throws on the marker. So the reader reports the config as unreadable and the two patch writers silently skip.
The fix strips exactly one leading \uFEFF before parsing and puts it back on write, which keeps the user's file byte-for-byte in the shape they saved it. Markers inside string values are untouched, and a double marker still counts as unreadable, which is the conservative call.
I ran the new tests against main without the fix: 3 fail. With the fix, all 42 pass.
Two optional notes, neither blocking:
- The strip and the re-add are now written out three and two times. A tiny
stripBom(text)/withBomOf(text, out)pair in this file would keep the next reader from missing it. - Studio's
projectProvenance.tsalso does a bareJSON.parseofhyperframes.json. It is provenance metadata only, so a BOM there just drops the badge, but it is the same class of bug.
Need: yes, BOM-saved configs are ignored today · Size: ok · Reuse: core's colorLuts.ts uses the same replace(/^\uFEFF/, "") idiom, no shared helper exists · Simpler: a local helper would collapse the five repeats, otherwise minimal
— Rames
An otherwise valid
hyperframes.jsonsaved with a UTF-8 byte order mark is treated as unreadable, so custom registry paths and media settings are ignored. The same marker prevents the existing authoring-skill and installed-item writers from updating the config.Accept exactly one leading marker in all three config-reading paths. Preserve it when patching existing settings, along with their indentation and unknown keys. Markers inside JSON strings remain untouched; malformed, marker-only and double-marker files remain unreadable.
Validation: the same existing public
projectConfig.test.tsfile fails 3 new regressions on baseline and passes all 42 tests after the fix. Tests use real temporary files and actual reader/normalizer/writer functions. The private minimal Vitest configuration aliases only the unrelated registry barrel to its exact default-URL constant; no mocks were committed. Existing missing-file, unmarked-config, round-trip and invalid-config controls pass. Lockfile-version Oxlint 1.64.0, Oxfmt 0.41.0, comment citations and comment ratchet pass.Full workspace build/typecheck/suite and native Windows editor behavior have not been verified locally. The earlier prescribed workspace build attempt was blocked by unavailable
tsup.