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.
140 lines • 6.04 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getNestedErrorCtor = void 0;
const _debug_js_1 = require("../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.
*/
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_js_1._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_js_1._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;
}
exports.getNestedErrorCtor = getNestedErrorCtor;
// 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