From daae6ed05b6fdda4ebb91795d890576efaef6e15 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 7 Apr 2026 14:48:30 +0900 Subject: [PATCH] fix(jsonc-parser): strip UTF-8 BOM before parsing to fix Windows "InvalidSymbol at offset 0" errors Windows editors often save UTF-8 files with a BOM (Byte Order Mark: \uFEFF). When this is present, jsonc-parser reports InvalidSymbol at offset 0 because the BOM is not valid JSON/JSONC syntax. This commit strips the BOM before parsing, fixing issues #3164 where Windows users report their opencode.jsonc file fails to parse even though it appears to start with a valid '{' character. Fixes: #3164 Co-authored-by: Jobdori --- src/shared/jsonc-parser.test.ts | 27 +++++++++++++++++++++++++++ src/shared/jsonc-parser.ts | 3 +++ 2 files changed, 30 insertions(+) diff --git a/src/shared/jsonc-parser.test.ts b/src/shared/jsonc-parser.test.ts index 26c0914e2..aacd69113 100644 --- a/src/shared/jsonc-parser.test.ts +++ b/src/shared/jsonc-parser.test.ts @@ -139,6 +139,33 @@ describe("parseJsonc", () => { // then expect(() => parseJsonc(invalid)).toThrow() }) + + test("parses JSONC with UTF-8 BOM (Windows BOM files)", () => { + // given - JSON with UTF-8 BOM marker + const bom = "\uFEFF" + const jsonc = `${bom}{ "key": "value" }` + + // when + const result = parseJsonc<{ key: string }>(jsonc) + + // then + expect(result.key).toBe("value") + }) + + test("parses JSONC with BOM and comments", () => { + // given - JSONC with UTF-8 BOM and comments + const bom = "\uFEFF" + const jsonc = `${bom}{ + // Windows editor saved with BOM + "key": "value" + }` + + // when + const result = parseJsonc<{ key: string }>(jsonc) + + // then + expect(result.key).toBe("value") + }) }) describe("parseJsoncSafe", () => { diff --git a/src/shared/jsonc-parser.ts b/src/shared/jsonc-parser.ts index 66c886310..818d0a63b 100644 --- a/src/shared/jsonc-parser.ts +++ b/src/shared/jsonc-parser.ts @@ -10,6 +10,9 @@ export interface JsoncParseResult { } export function parseJsonc(content: string): T { + // Strip UTF-8 BOM if present (Windows UTF-8 with BOM files) + content = content.replace(/^\uFEFF/, "") + const errors: ParseError[] = [] const result = parse(content, errors, { allowTrailingComma: true,