UNPKG

errlop

Version:

An extended Error class that envelops a parent error, such that the stack trace contains the causation

211 lines (210 loc) 7.89 kB
"use strict"; /* eslint-disable @typescript-eslint/no-explicit-any */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; Object.defineProperty(exports, "__esModule", { value: true }); /** * Convert to a valid number or null. * @param input */ function getNumber(input) { if (input == null || input === '') return null; var number = Number(input); if (isNaN(number)) return null; return number; } /** * Fetch the exit code from the value * @param value */ function getExitCode(value) { if (value != null) { if (typeof value.exitCode !== 'undefined') return getNumber(value.exitCode); if (typeof value.errno !== 'undefined') return getNumber(value.errno); if (typeof value.code !== 'undefined') return getNumber(value.code); } return null; } /** * Prepend a code to the stack if applicable. * @param code * @param stack */ function prependCode(code, stack) { if (code && typeof code === 'string' && stack.includes(code) === false) return "[".concat(code, "]: ").concat(stack); return stack; } /** Errlop, an extended Error class that envelops a parent Error to provide ancestry stack inforation. */ var Errlop = /** @class */ (function (_super) { __extends(Errlop, _super); /** * Turn the input and parent into an Errlop instance. * @param input * @param parent */ function Errlop(input, parent) { var _a, e_1, _b; if (parent === void 0) { parent = null; } var _this = this; var _c, _d; if (!input) throw new Error('Attempted to create an Errlop without an input'); // construct with message _this = _super.call(this, input.message || input) || this; // implements _this.parent = null; _this.ancestors = []; _this.exitCode = null; _this.orphanStack = ''; _this.code = ''; _this.level = ''; /** Duck typing so native classes can work with transpiled classes, as otherwise they would fail instanceof checks. */ _this.klass = Errlop; // parent // if override not set, fallback to parent or cause if (!parent) parent = input.parent || input.cause; // if override, or parent/cause was set, then set this.parent if (parent) { if (Errlop.isError(parent)) { _this.parent = parent; } else { _this.parent = new Errlop(parent); } } // ancestors, assumed to only exist on Errlop if (_this.parent) { _this.ancestors.push(_this.parent); if (Errlop.isErrlop(_this.parent)) { (_a = _this.ancestors).push.apply(_a, __spreadArray([], __read(_this.parent.ancestors), false)); } } try { // exitCode, code, level for (var _e = __values(__spreadArray([input, _this], __read(_this.ancestors), false)), _f = _e.next(); !_f.done; _f = _e.next()) { var error = _f.value; if (_this.exitCode == null) { _this.exitCode = getExitCode(error); } if (_this.code === '' && error.code != null && error.code !== '') { _this.code = (_c = getNumber(error.code)) !== null && _c !== void 0 ? _c : error.code.toString(); } if (_this.level === '' && error.level != null && error.level !== '') { _this.level = (_d = getNumber(error.level)) !== null && _d !== void 0 ? _d : error.level.toString(); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_f && !_f.done && (_b = _e.return)) _b.call(_e); } finally { if (e_1) throw e_1.error; } } // orphanStack _this.orphanStack = prependCode(_this.code, (input.orphanStack || input.stack || _this.stack || // this.stack should exist, unless something that extended Errlop broke it _this.message || _this || '').toString()); // stack _this.stack = __spreadArray([_this], __read(_this.ancestors), false).map(function (error) { // error is either Errlop or Error, however that doesn't stop extenders from breaking them return prependCode(error.code, (error.orphanStack || error.stack || // those should exist, unless something that extended Error broke it error.message || error || '').toString()); }) .filter(function (s) { return Boolean(s); }) // filter out Error instances that have no stack .join(Errlop.stackSeparator); return _this; } Errlop.isErrlop = function (value) { return value && (value instanceof this || value.klass === this); }; Errlop.isError = function (value) { return value instanceof Error || Errlop.isErrlop(value); }; /** * Ensure that the value is an Errlop instance * @param value */ Errlop.ensure = function (value) { return this.isErrlop(value) ? value : this.create(value, null); }; /** * Syntactic sugar for Errlop class creation. * Enables `Errlop.create(...)` to achieve `new Errlop(...)` * @param input * @param parent */ Errlop.create = function (input, parent) { if (parent === void 0) { parent = null; } return new this(input, parent); }; // static methods /** The separator to use for the stack entries */ Errlop.stackSeparator = '\n↳ '; return Errlop; }(Error)); exports.default = Errlop;