Spaces:
Runtime error
Runtime error
File size: 1,826 Bytes
cd8bd0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | /**
* Shared JSONC-tolerant config reader for CLI-tools settings routes.
*
* Background: several upstream CLI tools (opencode, kilo, droid, cline, etc.)
* ship config files that are JSON with the occasional trailing comma or a
* stray comment — valid JSONC, but `JSON.parse()` rejects them with a
* `SyntaxError`. Until this helper, every `readSettings`/`readConfig` helper
* only caught `ENOENT` and re-threw, surfacing as a 500 that the dashboard
* misread as "tool not installed".
*
* Behaviour:
* - strip trailing commas before parsing so JSONC files load cleanly;
* - on ANY read or parse failure, return the caller-supplied fallback
* (typically `null` or `{}`) instead of throwing, so the dashboard shows
* "installed but not configured" rather than "not installed".
*
* Ported from upstream `decolua/9router@6c10edf8`. Co-authored-by: Zireael.
*/
import { promises as fs } from "node:fs";
/**
* Parse a JSON/JSONC string, returning `null` on syntax errors instead of
* throwing. Trailing commas before `}` or `]` are stripped before parsing.
*/
export function parseJsoncOrNull<T = unknown>(content: string): T | null {
try {
const stripped = content.replace(/,(\s*[}\]])/g, "$1");
return JSON.parse(stripped) as T;
} catch {
return null;
}
}
/**
* Read a JSON/JSONC config file. Returns `fallback` (default: `null`) on any
* filesystem or parse error so callers can render an "installed but not
* configured" state instead of crashing with a 500.
*/
export async function readJsoncConfig<T = unknown>(
path: string,
fallback: T | null = null
): Promise<T | null> {
let content: string;
try {
content = await fs.readFile(path, "utf-8");
} catch {
return fallback;
}
const parsed = parseJsoncOrNull<T>(content);
return parsed ?? fallback;
}
|