Skip to content

Commit

Permalink
Add useToJSON option (#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
fregante committed Apr 4, 2022
1 parent 392081c commit e9e8666
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 4 deletions.
7 changes: 7 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ export interface Options {
```
*/
readonly maxDepth?: number;

/**
Indicate whether to use a `.toJSON()` method if encountered in the object. This is useful when a custom error implements its own serialization logic via `.toJSON()` but you prefer to not use it.
@default true
*/
readonly useToJSON?: boolean;
}

/**
Expand Down
11 changes: 9 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ const toJSON = from => {
return json;
};

// eslint-disable-next-line complexity
const destroyCircular = ({
from,
seen,
to_,
forceEnumerable,
maxDepth,
depth,
useToJSON,
}) => {
const to = to_ || (Array.isArray(from) ? [] : {});

Expand All @@ -62,7 +64,7 @@ const destroyCircular = ({
return to;
}

if (typeof from.toJSON === 'function' && from[toJsonWasCalled] !== true) {
if (useToJSON && typeof from.toJSON === 'function' && from[toJsonWasCalled] !== true) {
return toJSON(from);
}

Expand Down Expand Up @@ -97,6 +99,7 @@ const destroyCircular = ({
forceEnumerable,
maxDepth,
depth,
useToJSON,
});
continue;
}
Expand All @@ -119,7 +122,10 @@ const destroyCircular = ({
};

export function serializeError(value, options = {}) {
const {maxDepth = Number.POSITIVE_INFINITY} = options;
const {
maxDepth = Number.POSITIVE_INFINITY,
useToJSON = true,
} = options;

if (typeof value === 'object' && value !== null) {
return destroyCircular({
Expand All @@ -128,6 +134,7 @@ export function serializeError(value, options = {}) {
forceEnumerable: true,
maxDepth,
depth: 0,
useToJSON,
});
}

Expand Down
11 changes: 9 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,19 @@ const error = new Error('🦄');
error.one = {two: {three: {}}};

console.log(serializeError(error, {maxDepth: 1}));
//=> {name: 'Error', message: '', one: {}}
//=> {name: 'Error', message: '🦄', one: {}}

console.log(serializeError(error, {maxDepth: 2}));
//=> {name: 'Error', message: '', one: { two: {}}}
//=> {name: 'Error', message: '🦄', one: { two: {}}}
```

#### useToJSON

Type: `boolean`\
Default: `true`

Indicate whether to use a `.toJSON()` method if encountered in the object. This is useful when a custom error implements [its own serialization logic via `.toJSON()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#tojson_behavior) but you prefer to not use it.

### isErrorLike(value)

Predicate to determine whether a value looks like an error, even if it's not an instance of `Error`. It must have at least the `name`, `message`, and `stack` properties.
Expand Down
27 changes: 27 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ test('should serialize custom error with `.toJSON`', t => {
};
}
}

const error = new CustomError();
const serialized = serializeError(error);
t.deepEqual(serialized, {
Expand Down Expand Up @@ -366,6 +367,32 @@ test('should serialize custom error with `.toJSON` defined with `serializeError`
t.not(stack, undefined);
});

test('should ignore `.toJSON` methods if set in the options', t => {
class CustomError extends Error {
constructor() {
super('foo');
this.name = this.constructor.name;
this.value = 10;
}

toJSON() {
return {
message: this.message,
amount: `$${this.value}`,
};
}
}

const error = new CustomError();
const serialized = serializeError(error, {useToJSON: false});
t.like(serialized, {
name: 'CustomError',
message: 'foo',
value: 10,
});
t.truthy(serialized.stack);
});

test('should serialize properties up to `Options.maxDepth` levels deep', t => {
const error = new Error('errorMessage');
error.one = {two: {three: {}}};
Expand Down

0 comments on commit e9e8666

Please sign in to comment.