fix(config): fail closed when config content yields no JSON value

Treating every undefined parse as empty config let a file that is not JSON
at all (YAML, plain text) read as {}, so a later write would back it up and
replace it - the same data loss this fix is meant to prevent. Only a
comment-only parse, where ValueExpected is the sole error, counts as empty.
This commit is contained in:
Serhii Dziupin
2026-08-17 16:44:17 +03:00
parent 07f8264e72
commit 6d6ece6856
6 changed files with 49 additions and 16 deletions
+8 -3
View File
@@ -567,12 +567,17 @@ const formatJsoncParseError = (filePath: string, errors: ParseError[]): string =
const isInvalidJsoncError = (error: unknown): error is Error & { code: string } =>
Boolean(error && typeof error === 'object' && 'code' in error && error.code === INVALID_JSONC);
// Comment-only / whitespace-only files parse to undefined with nothing but
// ValueExpected. Any other error means real content we failed to understand
// (YAML, plain text, a stray leading token), which must not read as empty.
const isCommentOnlyParse = (parsed: unknown, errors: ParseError[]): boolean =>
parsed === undefined
&& errors.every((entry) => printParseErrorCode(entry.error) === 'ValueExpected');
const parseConfigObject = (content: string, filePath: string): Record<string, unknown> => {
const errors: ParseError[] = [];
const parsed = parseJsonc(content, errors, { allowTrailingComma: true });
// Comment-only / no JSON value: jsonc-parser returns undefined plus ValueExpected.
// That is empty config, not a partial tree. The data-loss bug is errors + object.
if (parsed === undefined) {
if (isCommentOnlyParse(parsed, errors)) {
return {};
}
if (errors.length > 0 || !parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {