From e8d6080f69d85897696d788bd921e7caad8118ec Mon Sep 17 00:00:00 2001 From: Bernd Hufmann Date: Thu, 17 Mar 2022 09:44:47 -0400 Subject: [PATCH] Add utility to support json stringify/parse with JSONBigInt fixes #57 Example Usages: // Usage with normalizer import { Experiment } from 'tsp-typescript-client/lib/models/experiment'; let input = JSONBigUtils.stringify(experiment); let output: Experiment = JSONBigUtils.parse(input, Experiment); // Usage no normalizer input = JSONBigUtils.stringify(inputObj); output = JSONBigUtils.parse(input); input = JSONBigUtils.stringify(BigInt("1234567890123456789")); output = JSONBigUtils.parse(bigIntInput); Signed-off-by: Bernd Hufmann --- .../src/utils/jsonbig-utils.test.ts | 66 +++++++++++++++++++ .../src/utils/jsonbig-utils.ts | 48 ++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 tsp-typescript-client/src/utils/jsonbig-utils.test.ts create mode 100644 tsp-typescript-client/src/utils/jsonbig-utils.ts diff --git a/tsp-typescript-client/src/utils/jsonbig-utils.test.ts b/tsp-typescript-client/src/utils/jsonbig-utils.test.ts new file mode 100644 index 0000000..ce0b7ff --- /dev/null +++ b/tsp-typescript-client/src/utils/jsonbig-utils.test.ts @@ -0,0 +1,66 @@ +// tslint:disable: no-unused-expression + +import { Experiment } from '../models/experiment'; +import { Identifier } from '../models/identifier'; +import { Query } from '../models/query/query'; +import { HttpRequest, HttpResponse, RestClient } from '../protocol/rest-client'; +import { FixtureSet } from '../protocol/test-utils'; +import { TspClient } from '../protocol/tsp-client'; +import { JSONBigUtils } from './jsonbig-utils'; + +describe('JSONBigUtils tests', () => { + + const client = new TspClient('not-relevant'); + const httpRequestMock = jest.fn, [req: HttpRequest]>(); + + let fixtures: FixtureSet; + + beforeAll(async () => { + fixtures = await FixtureSet.fromFolder(__dirname, '../../fixtures/tsp-client'); + RestClient['httpRequest'] = httpRequestMock; + }); + + beforeEach(() => { + httpRequestMock.mockReset(); + httpRequestMock.mockResolvedValue({ text: '', status: 404, statusText: 'Not found' }); + }); + + it('testJSONBigUtils-with-normalizer', async () => { + httpRequestMock.mockReturnValueOnce(fixtures.asResponse('create-experiment-0.json')); + const response = await client.createExperiment(new Query({})); + const experiment = response.getModel()!; + + const input = JSONBigUtils.stringify(experiment); + const experiment2: Experiment = JSONBigUtils.parse(input, Experiment); + + expect(experiment).toEqual(experiment2); + }); + + it('testJSONBigUtils-no-normalizer', async () => { + const inputObj = 'hallo'; + const input = JSONBigUtils.stringify(inputObj); + const output = JSONBigUtils.parse(input); + expect(typeof output).toEqual('string'); + + let bigIntObj = BigInt("1234567890123456789"); + const bigIntInput = JSONBigUtils.stringify(bigIntObj); + const bigIntOutput = JSONBigUtils.parse(bigIntInput); + expect(typeof bigIntOutput).toEqual('bigint'); + + const idObj: Identifier = { + version: "version", + buildTime: "buildTime", + os: "os", + osArch: "osArch", + osVersion: "osVersion", + cpuCount: "cpuCount", + maxMemory: "maxMemory", + launcherName: "launcherName", + productId: "productId" + }; + const idInput = JSONBigUtils.stringify(idObj); + const idOutput: Identifier = JSONBigUtils.parse(idInput); + expect(typeof idOutput).toEqual('object'); + expect(idOutput).toEqual(idObj); + }); +}); diff --git a/tsp-typescript-client/src/utils/jsonbig-utils.ts b/tsp-typescript-client/src/utils/jsonbig-utils.ts new file mode 100644 index 0000000..732303e --- /dev/null +++ b/tsp-typescript-client/src/utils/jsonbig-utils.ts @@ -0,0 +1,48 @@ +import { Normalizer } from '../protocol/serialization'; +import JSONBigConfig = require('json-bigint'); + +const JSONBig = JSONBigConfig({ + useNativeBigInt: true, +}); + +/** + * Rest client helper to make request. + * The request response status code indicates if the request is successful. + * The json object in the response may be undefined when an error occurs. + */ +export class JSONBigUtils { + + static parse(url: string): T; + static parse(input: string, normalizer?: Normalizer): T; + /** + * Parse JSON-encoded data using a normalizer. It will create `BigInt' + * values instead of `number` as defined by normalizer. + * + * @template T is the expected type of the json object returned + * @param input Input JSON string to deserialize + * @param normalizer Normalizer to create type T + */ + public static parse(input: string, normalizer?: Normalizer) { + try { + const parsed = JSONBig.parse(input); + try { + if (normalizer) { + return normalizer(parsed) as T; + } + return parsed as T; + } catch (err) { + console.log('Error normalizing parsed input string: ' + err.toString()); + } + } catch (err) { + console.log('Error parsing input string: ' + JSON.stringify(err)); + } + return null; + } + + /** + * Stringify JS objects. Can stringify `BigInt` values. + */ + public static stringify(data: any): string { + return JSONBig.stringify(data); + } +}