Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 53 54 | 162x 1837x 2x 1835x 1835x 3x 3x 1832x 3x 3x 1829x | /**
* Safe JSON parsing for values read from the SQLite cache layer.
*
* Cached JSON columns can be corrupted by partial writes, manual DB edits, or
* incompatible schema migrations. A bare `JSON.parse` on such data throws a
* `SyntaxError` that crashes whatever command triggered the cache read. This
* module centralizes the defensive parse so every cache reader treats
* corruption as a cache miss instead of a fatal error.
*/
import { logger } from "../logger.js";
const log = logger.withTag("db-json");
/**
* Parse a JSON string read from the cache, returning `undefined` on failure.
*
* Failure modes handled:
* - `raw` is `null`/`undefined` (column was never written) → `undefined`.
* - `JSON.parse` throws (corrupt JSON) → logged at debug level → `undefined`.
* - An optional `validate` predicate rejects the parsed shape → `undefined`.
*
* Callers should treat `undefined` as a cache miss and recompute the value.
*
* @typeParam T - Expected shape of the parsed value.
* @param raw - Raw JSON string from a SQLite column (may be null/undefined).
* @param validate - Optional type guard run against the parsed value; when it
* returns `false` the result is discarded and `undefined` is returned.
* @returns The parsed value, or `undefined` if parsing/validation failed.
*/
export function safeParseJson<T>(
raw: string | null | undefined,
validate?: (value: unknown) => value is T
): T | undefined {
if (raw === null || raw === undefined) {
return;
}
let parsed: unknown;
try {
parsed = JSON.parse(raw);
} catch (error) {
log.debug("Failed to parse cached JSON; treating as cache miss", error);
return;
}
if (validate && !validate(parsed)) {
log.debug("Cached JSON failed validation; treating as cache miss");
return;
}
return parsed as T;
}
|