From e59fe717bdb2dac0fb043317ed45128188ef88ee Mon Sep 17 00:00:00 2001 From: protobuf-ci-cd Date: Thu, 24 Apr 2025 14:54:29 +0200 Subject: [PATCH] feat(marshalling): add any marshalling --- packages/client/src/helpers/json.ts | 65 +++++++++++++++++++ packages/client/src/scw/custom-marshalling.ts | 60 ++++++++++++++++- 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/packages/client/src/helpers/json.ts b/packages/client/src/helpers/json.ts index 459f218ed..14d8f07ca 100644 --- a/packages/client/src/helpers/json.ts +++ b/packages/client/src/helpers/json.ts @@ -42,3 +42,68 @@ export const isJSONObject = (obj: unknown): obj is JSONObject => { objT === 'object' ) } + +/** + * Camelizes a string. + * + * @param str - The string to camelize + * @returns The camelized string + * + * @internal + */ +export const camelize = (str: string): string => { + const strLength = str.length + if (strLength <= 0) { + return str + } + let out = '' + for (let capNext = false, index = 0; index < strLength; index += 1) { + const char = str.charAt(index) + if (char >= 'a' && char <= 'z') { + if (capNext) { + out += char.toUpperCase() + } else { + out += char + } + } else if (char >= 'A' && char <= 'Z') { + out += char + } else if (char >= '0' && char <= '9') { + out += char + } + capNext = char === '_' || char === ' ' || char === '-' || char === '.' + } + + return out.charAt(0).toLowerCase() + out.substring(1) +} + +/** + * Camelizes keys of an object (deeply). + * + * @param obj - The object + * @param ignoreKeys - The keys to ignore + * @returns The object with camelized keys + * + * @internal + */ +export const camelizeKeys = ( + obj: object | unknown[] | unknown, + ignoreKeys: string[] = [], +): T => { + if (Array.isArray(obj)) { + return obj.map(v => camelizeKeys(v, ignoreKeys)) as unknown as T + } + + if (obj && typeof obj === 'object' && !(obj instanceof Date)) { + return Object.entries(obj).reduce( + (acc, [key, value]) => ({ + ...acc, + [camelize(key)]: ignoreKeys.includes(key) + ? (value as unknown) + : camelizeKeys(value, ignoreKeys), + }), + {}, + ) as T + } + + return obj as T +} diff --git a/packages/client/src/scw/custom-marshalling.ts b/packages/client/src/scw/custom-marshalling.ts index 8a0368741..cfbd73786 100644 --- a/packages/client/src/scw/custom-marshalling.ts +++ b/packages/client/src/scw/custom-marshalling.ts @@ -1,4 +1,4 @@ -import { isJSONObject } from '../helpers/json' +import { camelizeKeys, isJSONObject } from '../helpers/json' import { unmarshalArrayOfObject, unmarshalDate } from '../helpers/marshalling' import { fromByteArray } from '../vendor/base64' import type { @@ -207,3 +207,61 @@ export const marshalTimeSeries = ( export const marshalDecimal = (obj: Decimal): { value: string } => ({ value: obj.toString(), }) + +/** + * Unmarshals record to convert iso dates from string to Dates. + * + * @param obj - The input + * @param keys - The keys requiring a conversion + * @returns The updated input + * + * @internal + */ +export const unmarshalDates = (obj: unknown, keys: string[]): T => { + if (Array.isArray(obj)) { + return obj.map(v => unmarshalDates(v, keys)) as unknown as T + } + + if (obj && typeof obj === 'object') { + return Object.entries(obj).reduce( + (acc, [key, value]) => ({ + ...acc, + [key]: + typeof value === 'string' && keys.includes(key) + ? new Date(value) + : unmarshalDates(value, keys), + }), + {}, + ) as T + } + + return obj as T +} + +/** + * Unmarshals input to a record with camilized keys and instanciated Date. + * + * @param obj - The input + * @param ignoreKeys - The keys which should be not be transformed + * @param dateKeys - The keys which should be transformed to Date + * @returns The record + * + * @throws TypeError + * Thrown if the input isn't {@link JSONObject}. + * + * @internal + */ +export const unmarshalAnyRes = ( + obj: unknown, + ignoreKeys: string[] = [], + dateKeys?: string[], +): T => { + if (!isJSONObject(obj)) { + throw new TypeError(`Data isn't a dictionary.`) + } + + return camelizeKeys( + dateKeys && dateKeys.length > 0 ? unmarshalDates(obj, dateKeys) : obj, + ignoreKeys, + ) +}