From c10dd08c8974591d697a3a234be07ff6165dd814 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 dc947c096..817e37fa5 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 7847b9322..745d0ea81 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({