import { existsSync, readFileSync } from "node:fs" import { parse, ParseError, printParseErrorCode } from "jsonc-parser" export interface JsoncParseResult { data: T | null errors: Array<{ message: string; offset: number; length: number }> } export function parseJsonc(content: string): T { const errors: ParseError[] = [] const result = parse(content, errors, { allowTrailingComma: true, disallowComments: false, }) as T if (errors.length > 0) { const errorMessages = errors .map((e) => `${printParseErrorCode(e.error)} at offset ${e.offset}`) .join(", ") throw new SyntaxError(`JSONC parse error: ${errorMessages}`) } return result } export function parseJsoncSafe(content: string): JsoncParseResult { const errors: ParseError[] = [] const data = parse(content, errors, { allowTrailingComma: true, disallowComments: false, }) as T | null return { data: errors.length > 0 ? null : data, errors: errors.map((e) => ({ message: printParseErrorCode(e.error), offset: e.offset, length: e.length, })), } } export function readJsoncFile(filePath: string): T | null { try { const content = readFileSync(filePath, "utf-8") return parseJsonc(content) } catch { return null } } export function detectConfigFile(basePath: string): { format: "json" | "jsonc" | "none" path: string } { const jsoncPath = `${basePath}.jsonc` const jsonPath = `${basePath}.json` if (existsSync(jsoncPath)) { return { format: "jsonc", path: jsoncPath } } if (existsSync(jsonPath)) { return { format: "json", path: jsonPath } } return { format: "none", path: jsonPath } }