diff --git a/tsp-typescript-client/src/models/annotation.ts b/tsp-typescript-client/src/models/annotation.ts index 83cf453..6c6abec 100644 --- a/tsp-typescript-client/src/models/annotation.ts +++ b/tsp-typescript-client/src/models/annotation.ts @@ -1,4 +1,4 @@ -import { array, assertNumber, createNormalizer, record } from '../protocol/serialization'; +import { array, assertNumber, createNormalizer, record } from '../utils/serialization'; import { OutputElementStyle } from './styles'; export enum Type { diff --git a/tsp-typescript-client/src/models/bookmark.ts b/tsp-typescript-client/src/models/bookmark.ts index fd8452e..8c48815 100644 --- a/tsp-typescript-client/src/models/bookmark.ts +++ b/tsp-typescript-client/src/models/bookmark.ts @@ -1,4 +1,4 @@ -import { createNormalizer } from '../protocol/serialization'; +import { createNormalizer } from '../utils/serialization'; export const Bookmark = createNormalizer({ endTime: BigInt, diff --git a/tsp-typescript-client/src/models/entry.ts b/tsp-typescript-client/src/models/entry.ts index ec7a3b5..764c13c 100644 --- a/tsp-typescript-client/src/models/entry.ts +++ b/tsp-typescript-client/src/models/entry.ts @@ -1,4 +1,4 @@ -import { array, assertNumber, createNormalizer, Normalizer } from '../protocol/serialization'; +import { array, assertNumber, createNormalizer, Normalizer } from '../utils/serialization'; import { OutputElementStyle } from './styles'; export const Entry = createNormalizer({ diff --git a/tsp-typescript-client/src/models/experiment.ts b/tsp-typescript-client/src/models/experiment.ts index ddfc9ae..15b0384 100644 --- a/tsp-typescript-client/src/models/experiment.ts +++ b/tsp-typescript-client/src/models/experiment.ts @@ -1,4 +1,4 @@ -import { array, assertNumber, createNormalizer } from '../protocol/serialization'; +import { array, assertNumber, createNormalizer } from '../utils/serialization'; import { Trace } from './trace'; export const Experiment = createNormalizer({ diff --git a/tsp-typescript-client/src/models/output-descriptor.ts b/tsp-typescript-client/src/models/output-descriptor.ts index 2e703b3..56202a1 100644 --- a/tsp-typescript-client/src/models/output-descriptor.ts +++ b/tsp-typescript-client/src/models/output-descriptor.ts @@ -1,4 +1,4 @@ -import { createNormalizer } from '../protocol/serialization'; +import { createNormalizer } from '../utils/serialization'; export const OutputDescriptor = createNormalizer({ end: BigInt, diff --git a/tsp-typescript-client/src/models/response/responses.ts b/tsp-typescript-client/src/models/response/responses.ts index 152feaf..8e84fed 100644 --- a/tsp-typescript-client/src/models/response/responses.ts +++ b/tsp-typescript-client/src/models/response/responses.ts @@ -1,4 +1,4 @@ -import { Deserialized, createNormalizer, Normalizer } from '../../protocol/serialization'; +import { Deserialized, createNormalizer, Normalizer } from '../../utils/serialization'; /** * Response status diff --git a/tsp-typescript-client/src/models/styles.ts b/tsp-typescript-client/src/models/styles.ts index c5ae19e..610965c 100644 --- a/tsp-typescript-client/src/models/styles.ts +++ b/tsp-typescript-client/src/models/styles.ts @@ -1,4 +1,4 @@ -import { createNormalizer } from '../protocol/serialization'; +import { createNormalizer } from '../utils/serialization'; export const OutputElementStyle = createNormalizer({ values: undefined, diff --git a/tsp-typescript-client/src/models/table.ts b/tsp-typescript-client/src/models/table.ts index b0c0c0a..f7d4ee3 100644 --- a/tsp-typescript-client/src/models/table.ts +++ b/tsp-typescript-client/src/models/table.ts @@ -1,4 +1,4 @@ -import { array, assertNumber, createNormalizer } from '../protocol/serialization'; +import { array, assertNumber, createNormalizer } from '../utils/serialization'; export const ColumnHeaderEntry = createNormalizer({ id: assertNumber, diff --git a/tsp-typescript-client/src/models/timegraph.ts b/tsp-typescript-client/src/models/timegraph.ts index 856f07f..83b76a9 100644 --- a/tsp-typescript-client/src/models/timegraph.ts +++ b/tsp-typescript-client/src/models/timegraph.ts @@ -1,4 +1,4 @@ -import { array, assertNumber, createNormalizer } from '../protocol/serialization'; +import { array, assertNumber, createNormalizer } from '../utils/serialization'; import { Entry } from './entry'; import { OutputElementStyle } from './styles'; diff --git a/tsp-typescript-client/src/models/trace.ts b/tsp-typescript-client/src/models/trace.ts index ec1d4ba..497d628 100644 --- a/tsp-typescript-client/src/models/trace.ts +++ b/tsp-typescript-client/src/models/trace.ts @@ -1,4 +1,4 @@ -import { assertNumber, createNormalizer } from '../protocol/serialization'; +import { assertNumber, createNormalizer } from '../utils/serialization'; export const Trace = createNormalizer({ end: BigInt, diff --git a/tsp-typescript-client/src/models/xy.ts b/tsp-typescript-client/src/models/xy.ts index 0864b3a..be87544 100644 --- a/tsp-typescript-client/src/models/xy.ts +++ b/tsp-typescript-client/src/models/xy.ts @@ -1,4 +1,4 @@ -import { array, assertNumber, createNormalizer, toBigInt } from '../protocol/serialization'; +import { array, assertNumber, createNormalizer, toBigInt } from '../utils/serialization'; export const XYSeries = createNormalizer({ seriesId: assertNumber, diff --git a/tsp-typescript-client/src/protocol/rest-client.ts b/tsp-typescript-client/src/protocol/rest-client.ts index c231638..dd8c4b1 100644 --- a/tsp-typescript-client/src/protocol/rest-client.ts +++ b/tsp-typescript-client/src/protocol/rest-client.ts @@ -1,5 +1,5 @@ import fetch, { Headers } from 'node-fetch'; -import { Deserialized, Normalizer } from './serialization'; +import { Deserialized, Normalizer } from '../utils/serialization'; import { TspClientResponse } from './tsp-client-response'; import JSONBigConfig = require('json-bigint'); diff --git a/tsp-typescript-client/src/protocol/tsp-client.ts b/tsp-typescript-client/src/protocol/tsp-client.ts index 3544f74..58a2e76 100644 --- a/tsp-typescript-client/src/protocol/tsp-client.ts +++ b/tsp-typescript-client/src/protocol/tsp-client.ts @@ -13,7 +13,7 @@ import { TspClientResponse } from './tsp-client-response'; import { OutputStyleModel } from '../models/styles'; import { HealthStatus } from '../models/health'; import { MarkerSet } from '../models/markerset'; -import { array } from './serialization'; +import { array } from '../utils/serialization'; /** * Trace Server Protocol client diff --git a/tsp-typescript-client/src/utils/serialization-utils.test.ts b/tsp-typescript-client/src/utils/serialization-utils.test.ts new file mode 100644 index 0000000..ee4a89a --- /dev/null +++ b/tsp-typescript-client/src/utils/serialization-utils.test.ts @@ -0,0 +1,49 @@ +// tslint:disable: no-unused-expression + +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 { SerializationUtil } from './serialization-utils'; +import { Experiment } from '../models/experiment'; + +describe('SerializationUtils 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('testSerializationUtil', async () => { + httpRequestMock.mockReturnValueOnce(fixtures.asResponse('create-experiment-0.json')); + const response = await client.createExperiment(new Query({})); + const experiment = response.getModel()!; + + const input = SerializationUtil.serialize(experiment); + const experiment2 = SerializationUtil.deserialize(input, Experiment); + + expect(experiment).toEqual(experiment2); + }); + + it('testSerializationUtil-no-normalizer', async () => { + const inputObj = 'hallo'; + const input = SerializationUtil.serialize(inputObj); + const output = SerializationUtil.deserialize(input); + expect(typeof output).toEqual('string'); + + let bigIntObj = BigInt("1234567890123456789"); + const bigIntInput = SerializationUtil.serialize(bigIntObj); + const bigIntOutput = SerializationUtil.deserialize(bigIntInput); + expect(typeof bigIntOutput).toEqual('bigint'); + }); +}); diff --git a/tsp-typescript-client/src/utils/serialization-utils.ts b/tsp-typescript-client/src/utils/serialization-utils.ts new file mode 100644 index 0000000..123f309 --- /dev/null +++ b/tsp-typescript-client/src/utils/serialization-utils.ts @@ -0,0 +1,63 @@ +import { Deserialized, Normalizer } from './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 SerializationUtil { + + static deserialize(url: string): Deserialized; + static deserialize(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 + */ + static deserialize(input: string, normalizer?: Normalizer) { + try { + const parsed = this.jsonParse(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. + */ + static serialize(object: any): string { + return this.jsonStringify(object); + } + + /** + * Stringify JS objects. Can stringify `BigInt` values. + */ + protected static jsonStringify(data: any): string { + return JSONBig.stringify(data); + } + + /** + * Parse JSON-encoded data. If a number is too large to fit into a regular + * `number` then it will be deserialized as `BigInt`. + */ + protected static jsonParse(text: string): any { + return JSONBig.parse(text); + } +} diff --git a/tsp-typescript-client/src/protocol/serialization.ts b/tsp-typescript-client/src/utils/serialization.ts similarity index 100% rename from tsp-typescript-client/src/protocol/serialization.ts rename to tsp-typescript-client/src/utils/serialization.ts