Skip to content

Commit

Permalink
Add support for AggregateError (#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
fregante authored Jan 4, 2025
1 parent 64ce883 commit b6ff2eb
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
1 change: 1 addition & 0 deletions error-constructors.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const list = [
SyntaxError,
TypeError,
URIError,
AggregateError,

// Built-in errors
globalThis.DOMException,
Expand Down
21 changes: 15 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ const errorProperties = [
property: 'cause',
enumerable: false,
},
{
property: 'errors',
enumerable: false,
},
];

const toJsonWasCalled = new WeakSet();
Expand All @@ -48,7 +52,12 @@ const toJSON = from => {
return json;
};

const getErrorConstructor = name => errorConstructors.get(name) ?? Error;
const newError = name => {
const ErrorConstructor = errorConstructors.get(name) ?? Error;
return ErrorConstructor === AggregateError
? new ErrorConstructor([])
: new ErrorConstructor();
};

// eslint-disable-next-line complexity
const destroyCircular = ({
Expand All @@ -65,8 +74,7 @@ const destroyCircular = ({
if (Array.isArray(from)) {
to = [];
} else if (!serialize && isErrorLike(from)) {
const Error = getErrorConstructor(from.name);
to = new Error();
to = newError(from.name);
} else {
to = {};
}
Expand Down Expand Up @@ -131,7 +139,9 @@ const destroyCircular = ({
for (const {property, enumerable} of errorProperties) {
if (from[property] !== undefined && from[property] !== null) {
Object.defineProperty(to, property, {
value: isErrorLike(from[property]) ? continueDestroyCircular(from[property]) : from[property],
value: isErrorLike(from[property]) || Array.isArray(from[property])
? continueDestroyCircular(from[property])
: from[property],
enumerable: forceEnumerable ? true : enumerable,
configurable: true,
writable: true,
Expand Down Expand Up @@ -179,11 +189,10 @@ export function deserializeError(value, options = {}) {
}

if (isMinimumViableSerializedError(value)) {
const Error = getErrorConstructor(value.name);
return destroyCircular({
from: value,
seen: [],
to: new Error(),
to: newError(value.name),
maxDepth,
depth: 0,
serialize: false,
Expand Down
29 changes: 29 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,20 @@ test('should serialize the cause property', t => {
t.false(serialized.cause.cause instanceof Error);
});

test('should serialize AggregateError', t => {
// eslint-disable-next-line unicorn/error-message -- Testing this eventuality
const error = new AggregateError([new Error('inner error')]);

const serialized = serializeError(error);
t.is(serialized.message, ''); // Default error message
t.true(Array.isArray(serialized.errors));
t.like(serialized.errors[0], {
name: 'Error',
message: 'inner error',
});
t.false(serialized.errors[0] instanceof Error);
});

test('should handle top-level null values', t => {
const serialized = serializeError(null);
t.is(serialized, null);
Expand Down Expand Up @@ -369,6 +383,21 @@ test('should deserialize properties up to `Options.maxDepth` levels deep', t =>
t.deepEqual(levelThree, error);
});

test('should deserialize AggregateError', t => {
const deserialized = deserializeError({
name: 'AggregateError',
message: '',
errors: [
{name: 'Error', message: 'inner error', stack: ''},
],
});
t.true(deserialized instanceof AggregateError);
t.is(deserialized.message, '');
t.true(Array.isArray(deserialized.errors));
t.is(deserialized.errors[0].message, 'inner error');
t.true(deserialized.errors[0] instanceof Error);
});

test('should ignore invalid error-like objects', t => {
const errorLike = {
name: 'Error',
Expand Down

0 comments on commit b6ff2eb

Please sign in to comment.