38 lines
1.9 KiB
TypeScript
38 lines
1.9 KiB
TypeScript
|
|
/**
|
||
|
|
* @module utils/errorClassification
|
||
|
|
* @description Shared classification of caught errors into "genuine absence" vs
|
||
|
|
* "real fault" — the antidote to blind `catch { return null }` handlers that
|
||
|
|
* cannot tell ENOENT (the object is legitimately not on disk) from EIO / EACCES
|
||
|
|
* / EMFILE / … (a transient or permission fault on data that IS on disk).
|
||
|
|
* Masking a fault as absence yields wrong results (a present record read as
|
||
|
|
* "not found") or a needless rebuild. Mandate: loud errors, never quiet losses.
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The error `code`s that denote GENUINE absence of a file/object. Only `ENOENT`
|
||
|
|
* ("no such file or directory") qualifies — on every platform Node maps a
|
||
|
|
* missing file/directory to ENOENT, and no other errno means "simply not
|
||
|
|
* there". Every other errno (EIO, EACCES, EPERM, EMFILE, ENFILE, EBUSY,
|
||
|
|
* ENOTDIR, EISDIR, ELOOP) is a real fault and must propagate, as must any error
|
||
|
|
* without an errno `code` (parse/decompress failures, generic Errors).
|
||
|
|
* `ENOTDIR`/`EISDIR` are deliberately faults: a path component of the wrong
|
||
|
|
* type is corruption, not benign absence. Named constant so a future
|
||
|
|
* genuine-absence code can be added in one reviewed place.
|
||
|
|
*/
|
||
|
|
const ABSENCE_CODES: ReadonlySet<string> = new Set(['ENOENT'])
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @description True IFF `e` represents genuine absence (an ENOENT-class errno),
|
||
|
|
* for which returning `null`/`[]`/`undefined` is the correct answer. Returns
|
||
|
|
* `false` for every real fault, so the canonical call site is:
|
||
|
|
* `catch (e) { if (isAbsentError(e)) return null; throw e }`.
|
||
|
|
*
|
||
|
|
* @param e - The caught value (typed `unknown`; non-objects are never absence).
|
||
|
|
* @returns Whether the error means "the thing is simply not there".
|
||
|
|
*/
|
||
|
|
export function isAbsentError(e: unknown): boolean {
|
||
|
|
if (e === null || typeof e !== 'object') return false
|
||
|
|
const code = (e as { code?: unknown }).code
|
||
|
|
return typeof code === 'string' && ABSENCE_CODES.has(code)
|
||
|
|
}
|