// Error surface. Runtime-specific loader errors live here; the errno mapping // (toNodeError) is shared with the host's fs facade via shared/nodeerr.ts. import { inspect } from "./inspect"; import { toNodeError } from "../shared/nodeerr"; export { toNodeError }; /** Module-loader errors keep string codes (ERR_*), matching Node's SemVer contract. */ export function loaderError(code: string, specifier: string, from?: string): Error { const e = new Error(`${code}: Cannot find module '${specifier}'${from ? ` imported from ${from}` : ""}`); (e as Error & { code?: string }).code = code; return e; } /** An Error whose own keys are just `code` and whose stack opens `Error [CODE]:`, * the way Node's internal errors print. */ export function codedError(code: string, message: string): Error { const e = new Error(message); if (e.stack?.startsWith("Error: ")) e.stack = `Error [${code}]: ${e.stack.slice(7)}`; return Object.assign(e, { code }); } /** A web process runs only an ES module entry (VISION D2). */ export function webEntryNotEsm(entry: string, format: string): Error { return codedError("ERR_NIB_WEB_ENTRY_NOT_ESM", `A web process's entry must be an ES module; ${entry} is ${format}.`); } /** Node's ERR_INVALID_ARG_TYPE, with its description of the received value. A dotted * `name` (e.g. "options.foo") reads as a "property", otherwise an "argument" — Node's * internal/errors.js picks the word the same way. */ export function invalidArgType(name: string, expected: string, value: unknown): TypeError { const got = value === null || value === undefined ? ` Received ${value}` : typeof value === "function" ? ` Received function ${(value as { name?: string }).name || "anonymous"}` : typeof value === "object" ? ` Received an instance of ${(value as object).constructor?.name ?? "Object"}` : ` Received type ${typeof value} (${typeof value === "string" ? `'${value}'` : String(value)})`; const kind = name.includes(".") ? "property" : "argument"; return Object.assign(new TypeError(`The "${name}" ${kind} must be ${expected}.${got}`), { code: "ERR_INVALID_ARG_TYPE" }); } /** Node's ERR_INVALID_ARG_VALUE: `name` dotted (e.g. "options.foo") reads as a * property, otherwise an argument. inspect's output is truncated at 128 chars, as * Node's own message builder does. */ export function invalidArgValue(name: string, value: unknown, reason: unknown = "is invalid"): TypeError { let shown = inspect(value); if (shown.length > 128) shown = `${shown.slice(0, 128)}...`; const kind = name.includes(".") ? "property" : "argument"; return Object.assign(new TypeError(`The ${kind} '${name}' ${reason}. Received ${shown}`), { code: "ERR_INVALID_ARG_VALUE" }); } /** Node's internal/errors.js addNumericalSeparator: underscore-group a big integer's * digits the way ERR_OUT_OF_RANGE prints a received value that overflows 2**32. */ function addNumericalSeparator(val: string): string { let res = ""; let i = val.length; const start = val[0] === "-" ? 1 : 0; for (; i >= start + 4; i -= 3) res = `_${val.slice(i - 3, i)}${res}`; return `${val.slice(0, i)}${res}`; } /** Node's ERR_OUT_OF_RANGE. `replaceDefaultBoolean` swaps in a caller-built sentence for * the usual "The value of ... is out of range." lead-in, as Node's own helper does. */ export function outOfRange(name: string, range: string, value: unknown, replaceDefaultBoolean = false): RangeError { let msg = replaceDefaultBoolean ? name : `The value of "${name}" is out of range.`; let received: string; if (Number.isInteger(value) && Math.abs(value as number) > 2 ** 32) { received = addNumericalSeparator(String(value)); } else if (typeof value === "bigint") { received = String(value); if (value > 2n ** 32n || value < -(2n ** 32n)) received = addNumericalSeparator(received); received += "n"; } else { received = inspect(value); } msg += ` It must be ${range}. Received ${received}`; return Object.assign(new RangeError(msg), { code: "ERR_OUT_OF_RANGE" }); } /** Node's ERR_INVALID_STATE: `Invalid state: ${message}`, e.g. mock.timers.enable() * called twice or tick() before enable(). */ export function invalidState(message: string): Error { return Object.assign(new Error(`Invalid state: ${message}`), { code: "ERR_INVALID_STATE" }); } /** Node's ERR_INVALID_RETURN_VALUE (e.g. assert.rejects' promiseFn not returning a Promise). */ export function invalidReturnValue(expected: string, name: string, value: unknown): TypeError { const got = value === null ? "null" : value === undefined ? "undefined" : typeof value === "function" ? `function ${(value as { name?: string }).name ?? ""}` : typeof value === "object" ? `an instance of ${(value as object).constructor?.name ?? "Object"}` : `type ${typeof value} (${typeof value === "string" ? `'${value}'` : String(value)})`; return Object.assign(new TypeError(`Expected ${expected} to be returned from the "${name}" function but got ${got}.`), { code: "ERR_INVALID_RETURN_VALUE" }); } /** Node's CJS loader miss (Module._resolveFilename): MODULE_NOT_FOUND, not the ESM * loader's ERR_MODULE_NOT_FOUND, with the requiring files as the require stack. */ export function requireNotFound(specifier: string, requireStack: string[]): Error { const stack = requireStack.length ? `\nRequire stack:\n${requireStack.map((f) => `- ${f}`).join("\n")}` : ""; return Object.assign(new Error(`Cannot find module '${specifier}'${stack}`), { code: "MODULE_NOT_FOUND", requireStack }); } /** Build + throw a Node-flavoured Error from a kernel FsError (never throw raw data). */ export function throwFs(e: import("../shared/protocol").FsError): never { throw toNodeError(e); }