@jchip/error
Version:
utilities and polyfill for node.js errors
117 lines • 4.11 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AggregateError = exports.aggregateErrorStack = exports.aggregateStack = exports.cleanErrorStack = void 0;
const path_1 = __importDefault(require("path"));
/* eslint-disable @typescript-eslint/ban-ts-comment */
const defaultPathFilter = [
new RegExp(`/node_modules.*/(pirates/|isomorphic-loader/lib/extend-require)`),
];
/**
* Return the stack text of an error with internal modules removed
*
* @param error - error
* @param options - clean error stack options
* @returns cleaned up stack trace
*/
function cleanErrorStack(error, { replacePath = `${process.cwd()}/`, ignorePathFilter = [] } = {}) {
const stack = error && (error.stack || error.message);
if (!stack) {
return String(stack);
}
const result = stack
.split("\n")
.map((line) => {
// keep all non stack tracing lines
if (!line.match(/ {4,}at/)) {
return line;
}
const match = line.match(/( {4,}at)([^\(]+\()([^\)]+\))(.*)/);
// skip any stack tracing line not in these formats:
// - " at Blah (/foo/bar:##:##)" format
// - "scheme://path" (ie: webpack://path)
if (!match || (!match[3].match(/[^:]+:\/\//) && !path_1.default.isAbsolute(match[3]))) {
return false;
}
const path = match[3].replace(/\\/g, "/");
if (defaultPathFilter
.concat(ignorePathFilter)
.find((s) => s && (s instanceof RegExp ? path.match(s) : path.includes(s)))) {
return false;
}
const path2 = replacePath && replacePath.length > 1 ? path.replace(replacePath, "") : path;
return `${match[1]}${match[2]}${path2}${match[4]}`;
})
.filter((x) => x)
.join("\n");
return result;
}
exports.cleanErrorStack = cleanErrorStack;
/**
* Build stack of aggregate errors
*
* @param stack - top error
* @param errors - aggregated errors
* @returns aggregate stack
*/
function aggregateStack(stack, errors) {
return [stack]
.concat(errors &&
errors.map &&
errors.map((e) => {
const s = e && (e.stack || e.message);
return (s || String(e)).replace(/^/gm, " ");
}))
.join("\n");
}
exports.aggregateStack = aggregateStack;
/**
* build the aggregate stack of an AggregateError
*
* @param error aggregate error
* @returns aggregate stack
*/
/* eslint-disable-next-line no-use-before-define */
function aggregateErrorStack(error) {
return aggregateStack(error.__stack || error.message || String(error), error.errors);
}
exports.aggregateErrorStack = aggregateErrorStack;
/**
* AggregateError
* - https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-aggregate-error-objects
*/
class AggregateError extends Error {
constructor(errors, msg) {
if (!errors || !(errors[Symbol.iterator] instanceof Function)) {
throw new TypeError(`input errors must be iterable but it's ${typeof errors}`);
}
super(msg);
// Using defineProperty to replicate behavior of Object.keys(new Error()) returns []
Object.defineProperty(this, "name", { value: "AggregateError" });
let aggStack;
Object.defineProperties(this, {
// specify errors according to spec
errors: {
configurable: true,
enumerable: false,
writable: true,
value: [].concat(errors),
},
// save original stack
__stack: {
enumerable: false,
value: this.stack,
},
// make aggregate stack
stack: {
get() {
return aggStack || (aggStack = aggregateErrorStack(this));
},
},
});
}
}
exports.AggregateError = AggregateError;
//# sourceMappingURL=index.js.map
;