UNPKG

rc-js-util

Version:

A collection of TS and C++ utilities to help writing performant and correct applications, achieved through strict typing and (removable) invariant checking.

136 lines 5.85 kB
import { _Debug } from "../debug/_debug.js"; /** * @public * Factory for creating a localized `NestedError` class, see {@link INestedError}. This should be used * to create a base class, from which you can create extensions to represent specific error cases. */ export function getNestedErrorCtor(config) { var _a; return _a = class NestedError { static isError(error) { return error instanceof this; } static normalizeError(error) { if (_a.isError(error)) { return error; } return new _a(_a.ctorConfig.defaultError, error); } static getRootCause(error) { const normalizedError = _a.normalizeError(error); if (_a.isError(normalizedError.causedBy)) { return _a.getRootCause(normalizedError.causedBy); } else { return normalizedError; } } constructor(message, causedBy) { this.message = message; this.causedBy = causedBy; this.stack = _Debug.getStackTrace(); } getMessage() { return this.message; } composeErrorMessages() { const messages = [this.getMessage()]; // we're only ever interested in the innermost exception for stack traces etc. let exceptionDetail = this.stack; // eslint-disable-next-line @typescript-eslint/no-this-alias let currentError = this; while (currentError.causedBy != null) { if (_a.isError(currentError.causedBy)) { messages.push(currentError.causedBy.message); currentError = currentError.causedBy; } else { const detail = currentError.causeToString(); if (detail != null) { // it's likely to provide more context than the composable error stack trace exceptionDetail = detail; } break; } } return { messages: messages, detail: exceptionDetail, }; } causeToString() { if (this.causedBy == null) { return undefined; } if (this.causedBy instanceof _a) { // one of ours... return this.causedBy.toString(); } if (this.causedBy instanceof Error) { // firefox sometimes populates things with empty strings (e.g. network errors) // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (this.causedBy.message && this.causedBy.stack) { return [this.causedBy.stack, this.stack].join("\n"); } if (this.causedBy.message) { return this.causedBy.message; } // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (this.causedBy.stack) { return this.causedBy.stack; } // it's an error, but not as we know it... return guardedToString(this.causedBy); } switch (typeof this.causedBy) { case "string": return this.causedBy; case "object": // generally speaking, an object's toString method doesn't produce useful output // => don't throw random objects... return JSON.stringify(this.causedBy); case "boolean": case "number": case "function": case "symbol": case "bigint": // hanging offense if you actually hit this return this.causedBy.toString(); case "undefined": // we checked for == null above default: // notionally it's not possible to get here, but just in case _BUILD.DEBUG && _Debug.error(`unexpected code path, unknown type ${typeof this.causedBy}`); return "Received non-serializable exception, skipping."; } } toString() { const cause = this.causeToString(); if (cause == null) { return [ _a.ctorConfig.getTxFallback(this.getMessage()), this.stack, ].join("\n"); } else { return [ _a.ctorConfig.getTxFallback(this.getMessage()), this.stack + "\n", `=======================CAUSE FOLLOWS=======================`, cause ].join("\n"); } } }, _a.ctorConfig = config, _a; } // guard against very silly toString overrides... function guardedToString(object) { if (typeof object.toString !== "function") { return undefined; } // eslint-disable-next-line @typescript-eslint/no-base-to-string const result = object.toString(); return typeof result === "string" ? result : undefined; } //# sourceMappingURL=nested-error-factory.js.map