From 6a78b8369e248dd39d1e519e7d2a97763562bdf2 Mon Sep 17 00:00:00 2001 From: Olaf Tomalka Date: Mon, 7 Nov 2022 14:41:59 +0100 Subject: [PATCH] Cast JsonRPC to Json (#51) * Cast JsonRPC to Json JsonRpcStruct params was type Record | unknown[], but in other parts of the code we use Json to denote such structures. unknown is not castable to Json because of undefined and classes. This commit solves the compatibillity issue with other parts of the code * PR review changes * Nicer JSON validation msg * Fix lint --- src/json.test.ts | 21 +++++++++++++++++---- src/json.ts | 13 +++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/json.test.ts b/src/json.test.ts index 208908b2..5ef2e8c1 100644 --- a/src/json.test.ts +++ b/src/json.test.ts @@ -1,4 +1,5 @@ import * as superstructModule from 'superstruct'; +import { validate } from 'superstruct'; import { ARRAY_OF_DIFFRENT_KINDS_OF_NUMBERS, COMPLEX_OBJECT, @@ -13,6 +14,8 @@ import { NON_SERIALIZABLE_NESTED_OBJECT, } from './__fixtures__'; import { + assert, + assertIsJsonRpcError, assertIsJsonRpcFailure, assertIsJsonRpcNotification, assertIsJsonRpcRequest, @@ -20,6 +23,7 @@ import { assertIsJsonRpcSuccess, assertIsPendingJsonRpcResponse, getJsonRpcIdValidator, + isJsonRpcError, isJsonRpcFailure, isJsonRpcNotification, isJsonRpcRequest, @@ -27,12 +31,21 @@ import { isJsonRpcSuccess, isPendingJsonRpcResponse, isValidJson, + JsonStruct, validateJsonAndGetSize, - isJsonRpcError, - assertIsJsonRpcError, } from '.'; describe('json', () => { + describe('JsonStruct', () => { + it('returns error message', () => { + const [error] = validate(undefined, JsonStruct); + assert(error !== undefined); + expect(error.message).toStrictEqual( + 'Expected a valid JSON-serializable value', + ); + }); + }); + // TODO: Make this test suite exhaustive. // The current implementation is guaranteed to be correct, but in the future // we may opt for a bespoke implementation that is more performant, but may @@ -425,11 +438,11 @@ describe('json', () => { }; const validateAll = ( - validate: ReturnType, + validator: ReturnType, inputs: ReturnType, ) => { for (const input of Object.values(inputs)) { - expect(validate(input.value)).toStrictEqual(input.expected); + expect(validator(input.value)).toStrictEqual(input.expected); } }; diff --git a/src/json.ts b/src/json.ts index ecb13c35..0ee25e7e 100644 --- a/src/json.ts +++ b/src/json.ts @@ -10,22 +10,26 @@ import { object, omit, optional, + record, string, Struct, union, unknown, } from 'superstruct'; +import { AssertionErrorConstructor, assertStruct } from './assert'; import { calculateNumberSize, calculateStringSize, isPlainObject, JsonSize, } from './misc'; -import { AssertionErrorConstructor, assertStruct } from './assert'; export const JsonStruct = define('Json', (value) => { const [isValid] = validateJsonAndGetSize(value, true); - return isValid; + if (!isValid) { + return 'Expected a valid JSON-serializable value'; + } + return true; }); /** @@ -99,8 +103,9 @@ export type JsonRpcError = OptionalField< 'data' >; -export const JsonRpcParamsStruct = optional(union([object(), array()])); - +export const JsonRpcParamsStruct = optional( + union([record(string(), JsonStruct), array(JsonStruct)]), +); export type JsonRpcParams = Infer; export const JsonRpcRequestStruct = object({