Skip to content

Commit d30564d

Browse files
committed
feat: add errorToJSON function
1 parent 383942f commit d30564d

File tree

2 files changed

+58
-3
lines changed

2 files changed

+58
-3
lines changed

src/__tests__/exception.test.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import type { Simplify } from 'type-fest';
22
import { describe, expect, expectTypeOf, it, test } from 'vitest';
33

4-
import { BaseException, ExceptionBuilder, OutOfRangeException, parseStack, ValueException } from '../exception.js';
4+
import {
5+
BaseException,
6+
errorToJSON,
7+
ExceptionBuilder,
8+
OutOfRangeException,
9+
parseStack,
10+
RuntimeException,
11+
ValueException
12+
} from '../exception.js';
513
import { Err } from '../vendor/neverthrow.js';
614

715
import type { ExceptionConstructor } from '../exception.js';
@@ -194,7 +202,31 @@ describe('parseStack', () => {
194202
it('should return the same value, in terms of value, whether called with an error or a string', () => {
195203
const error = new Error();
196204
const r1 = parseStack(error);
197-
const r2 = parseStack(error.stack!);
205+
const r2 = parseStack(error.stack);
198206
expect(r1).toStrictEqual(r2);
199207
});
200208
});
209+
210+
describe('errorToJSON', () => {
211+
it('should return the expected output', () => {
212+
const cause = new RuntimeException('Something else went wrong', {
213+
details: {
214+
foo: true
215+
}
216+
});
217+
const error = new Error('Something went wrong', { cause });
218+
expect(JSON.parse(errorToJSON(error))).toStrictEqual({
219+
cause: {
220+
details: {
221+
foo: true
222+
},
223+
message: 'Something else went wrong',
224+
name: 'RuntimeException',
225+
stack: expect.toSatisfy((arg) => Array.isArray(arg) && arg.every((item) => typeof item === 'string'))
226+
},
227+
message: 'Something went wrong',
228+
name: 'Error',
229+
stack: expect.toSatisfy((arg) => Array.isArray(arg) && arg.every((item) => typeof item === 'string'))
230+
});
231+
});
232+
});

src/exception.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import cleanStack from 'clean-stack';
66
import extractStack from 'extract-stack';
7+
import { isErrorLike, serializeError } from 'serialize-error';
78
import stringifyObject from 'stringify-object';
89
import type { IsNever, RequiredKeysOf } from 'type-fest';
910
import type { z } from 'zod';
@@ -70,6 +71,18 @@ function parseStack(errorOrStack: Error | string | undefined): string[] {
7071
return extractStack.lines(cleanStack(stack, { pretty: true }));
7172
}
7273

74+
function errorToJSON(error: Error): string {
75+
const serialize = (error: Error): { [key: string]: unknown } => {
76+
const { cause, stack, ...serialized } = serializeError(error);
77+
return {
78+
...serialized,
79+
cause: isErrorLike(cause) ? serialize(cause) : cause,
80+
stack: parseStack(stack)
81+
};
82+
};
83+
return JSON.stringify(serialize(error), null, 2);
84+
}
85+
7386
abstract class BaseException<TParams extends ExceptionParams, TOptions extends ExceptionOptions>
7487
extends Error
7588
implements ExceptionLike
@@ -231,4 +244,14 @@ export type {
231244
ExceptionStatic,
232245
ExceptionType
233246
};
234-
export { BaseException, ExceptionBuilder, OutOfRangeException, parseStack, RuntimeException, ValueException };
247+
248+
export {
249+
BaseException,
250+
errorToJSON,
251+
ExceptionBuilder,
252+
OutOfRangeException,
253+
parseStack,
254+
RuntimeException,
255+
serializeError,
256+
ValueException
257+
};

0 commit comments

Comments
 (0)