Skip to content

Commit 65d0f41

Browse files
committed
feat: support native Error causes
1 parent e6350af commit 65d0f41

File tree

5 files changed

+52
-18
lines changed

5 files changed

+52
-18
lines changed

jest.config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ module.exports = {
4545
// An object that configures minimum threshold enforcement for coverage results
4646
coverageThreshold: {
4747
global: {
48-
branches: 93.05,
48+
branches: 92.64,
4949
functions: 94.44,
50-
lines: 92.96,
51-
statements: 92.96,
50+
lines: 92.85,
51+
statements: 92.85,
5252
},
5353
},
5454

src/classes.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { hasProperty, isObject, isPlainObject } from '@metamask/utils';
66
import safeStringify from 'fast-safe-stringify';
77

88
import type { OptionalDataWithOptionalCause } from './utils';
9-
import { serializeCause } from './utils';
9+
import { dataHasCause, serializeCause } from './utils';
1010

1111
export type { SerializedJsonRpcError };
1212

@@ -19,9 +19,6 @@ export type { SerializedJsonRpcError };
1919
export class JsonRpcError<
2020
Data extends OptionalDataWithOptionalCause,
2121
> extends Error {
22-
// This can be removed when tsconfig lib and/or target have changed to >=es2022
23-
public cause: OptionalDataWithOptionalCause;
24-
2522
public code: number;
2623

2724
public data?: Data;
@@ -35,18 +32,21 @@ export class JsonRpcError<
3532
throw new Error('"message" must be a non-empty string.');
3633
}
3734

38-
super(message);
39-
this.code = code;
40-
if (data !== undefined) {
41-
this.data = data;
42-
if (
43-
isObject(data) &&
44-
hasProperty(data, 'cause') &&
45-
isObject(data.cause)
46-
) {
35+
if (dataHasCause(data)) {
36+
super(message, { cause: data.cause });
37+
// Browser backwards-compatibility
38+
if (!this.cause) {
4739
this.cause = data.cause;
4840
}
41+
} else {
42+
super(message);
43+
}
44+
45+
if (data !== undefined) {
46+
this.data = data;
4947
}
48+
49+
this.code = code;
5050
}
5151

5252
/**

src/utils.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
dummyMessage,
1717
dummyData,
1818
} from './__fixtures__';
19-
import { getMessageFromCode, serializeError } from './utils';
19+
import { dataHasCause, getMessageFromCode, serializeError } from './utils';
2020

2121
const rpcCodes = errorCodes.rpc;
2222

@@ -310,3 +310,23 @@ describe('serializeError', () => {
310310
});
311311
});
312312
});
313+
314+
describe('dataHasCause', () => {
315+
it('returns false for invalid data types', () => {
316+
[undefined, null, 'hello', 1234].forEach(data => {
317+
const result = dataHasCause(data);
318+
expect(result).toBe(false);
319+
});
320+
});
321+
it('returns false for invalid cause types', () => {
322+
[undefined, null, 'hello', 1234].forEach(cause => {
323+
const result = dataHasCause({cause});
324+
expect(result).toBe(false);
325+
});
326+
});
327+
it('returns true when cause is object', () => {
328+
const data = {cause: {}};
329+
const result = dataHasCause(data);
330+
expect(result).toBe(true);
331+
});
332+
});

src/utils.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,17 @@ function serializeObject(object: RuntimeObject): Json {
211211
{},
212212
);
213213
}
214+
215+
/**
216+
* Returns true if supplied error data has a usable `cause` property; false otherwise.
217+
*
218+
* @param data - Optional data to validate.
219+
* @returns Whether cause property is present and an object.
220+
*/
221+
export function dataHasCause(
222+
data: OptionalDataWithOptionalCause,
223+
): data is { cause: object } {
224+
return isObject(data)
225+
&& hasProperty(data, 'cause')
226+
&& isObject(data.cause);
227+
}

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"exactOptionalPropertyTypes": true,
55
"forceConsistentCasingInFileNames": true,
66
// Remove custom `cause` field from JsonRpcError when updating
7-
"lib": ["ES2020"],
7+
"lib": ["ES2022"],
88
"module": "CommonJS",
99
"moduleResolution": "node",
1010
"noEmit": true,

0 commit comments

Comments
 (0)