From badf25dacadcd82b718dae9694b8ff78f7298414 Mon Sep 17 00:00:00 2001 From: Maarten Zuidhoorn Date: Tue, 10 Dec 2024 13:07:33 +0100 Subject: [PATCH 1/3] Improve error message for invalid JSON values --- src/json.ts | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/json.ts b/src/json.ts index 159ce5e37..29f492729 100644 --- a/src/json.ts +++ b/src/json.ts @@ -16,6 +16,8 @@ import { union, unknown, Struct, + assert, + refine, } from '@metamask/superstruct'; import type { Context, @@ -215,18 +217,20 @@ export const UnsafeJsonStruct: Struct = define('JSON', (json) => * This struct sanitizes the value before validating it, so that it is safe to * use with untrusted input. */ -export const JsonStruct = coerce(UnsafeJsonStruct, any(), (value) => { - assertStruct(value, UnsafeJsonStruct); - return JSON.parse( - JSON.stringify(value, (propKey, propValue) => { - // Strip __proto__ and constructor properties to prevent prototype pollution. - if (propKey === '__proto__' || propKey === 'constructor') { - return undefined; - } - return propValue; - }), - ); -}); +export const JsonStruct = coerce( + UnsafeJsonStruct, + refine(any(), 'JSON', (value) => is(value, UnsafeJsonStruct)), + (value) => + JSON.parse( + JSON.stringify(value, (propKey, propValue) => { + // Strip __proto__ and constructor properties to prevent prototype pollution. + if (propKey === '__proto__' || propKey === 'constructor') { + return undefined; + } + return propValue; + }), + ), +); /** * Check if the given value is a valid {@link Json} value, i.e., a value that is From 1943d742be4ad90c94a231e7bbc11e6450772fc8 Mon Sep 17 00:00:00 2001 From: Maarten Zuidhoorn Date: Tue, 10 Dec 2024 13:13:49 +0100 Subject: [PATCH 2/3] Remove unused import --- src/json.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/json.ts b/src/json.ts index 29f492729..0182a332b 100644 --- a/src/json.ts +++ b/src/json.ts @@ -16,7 +16,6 @@ import { union, unknown, Struct, - assert, refine, } from '@metamask/superstruct'; import type { From c70a520523f0f87c046488bd193f43f4ebd4eb98 Mon Sep 17 00:00:00 2001 From: Maarten Zuidhoorn Date: Tue, 10 Dec 2024 13:26:28 +0100 Subject: [PATCH 3/3] Add test --- src/json.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/json.test.ts b/src/json.test.ts index c4e620a58..96c16bec8 100644 --- a/src/json.test.ts +++ b/src/json.test.ts @@ -239,6 +239,18 @@ describe('json', () => { 'Expected a value of type `JSON`, but received: `undefined`', ); }); + + it('returns a readable error message for a nested JsonStruct', () => { + const struct = object({ + value: JsonStruct, + }); + + const [error] = validate({ value: undefined }, struct); + assert(error !== undefined); + expect(error.message).toBe( + 'At path: value -- Expected a value of type `JSON`, but received: `undefined`', + ); + }); }); describe('getSafeJson', () => {