diff --git a/packages/sdk/src/types/json.ts b/packages/sdk/src/types/json.ts index fe1d479e6..74757a3c1 100644 --- a/packages/sdk/src/types/json.ts +++ b/packages/sdk/src/types/json.ts @@ -228,8 +228,11 @@ export function jsonStringify( * This should be used if you want to manually deserialize the inner property values, as the serialization is irreversible. * * @param value A JavaScript value, usually an object or array, to be converted. - * @param bigintFormat Determines how to handle bigints. - * Can be set to either 'number' (uses 'json-bigint to safely serialize), 'string', or undefined (must be taken care of in replacer function) + * @param bigintFormat Determines how to handle bigints. Can be set to either: + * - `'number'`: uses 'json-bigint to safely serialize, + * - `'string'`: converts `bigint` to strings + * - `undefined`: must be taken care of manually, e.g. in replacer function. + * Defaults to 'number' * @param replacer A function that transforms the results. * @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read. */ @@ -239,21 +242,30 @@ export function jsonUnwrapStringify( replacer?: ReplacerFun, space?: string | number ): string { - function replacerFunction(this: any, key: string, value: any) { - let transformedValue = ccdUnwrapReplacer.call(this, key, value); - + function replaceBigintValue(value: any): any { switch (bigintFormat) { case 'string': if (typeof value === 'bigint') { - transformedValue = value.toString(); + return value.toString(); } default: - break; + return value; } + } + + function replacerFunction(this: any, key: string, value: any) { + let transformedValue = ccdUnwrapReplacer.call(this, key, value); + transformedValue = replaceBigintValue(transformedValue); return replacer?.call(this, key, transformedValue) ?? transformedValue; } + let replaced = input; + + if (typeof input !== 'object') { + replaced = replaceBigintValue(replaced); + } + const stringify = bigintFormat === 'number' ? JSONBig.stringify : JSON.stringify; - return stringify(input, replacerFunction, space); + return stringify(replaced, replacerFunction, space); } diff --git a/packages/sdk/test/ci/types/json.test.ts b/packages/sdk/test/ci/types/json.test.ts index 706aca9d3..758d8737f 100644 --- a/packages/sdk/test/ci/types/json.test.ts +++ b/packages/sdk/test/ci/types/json.test.ts @@ -87,6 +87,43 @@ describe('jsonStringify', () => { }); }); +describe(jsonUnwrapStringify, () => { + test('Serializes bigint values as expected', () => { + const t = 100n; + expect(jsonUnwrapStringify(t)).toEqual('100'); + expect(jsonUnwrapStringify(t, 'string')).toEqual('"100"'); + expect( + jsonUnwrapStringify(t, undefined, (_, v) => + typeof v === 'bigint' ? -v : v + ) + ).toEqual('-100'); + }); + + test('Serializes nested bigint (arrays) values as expected', () => { + const t = [100n, 200n]; + expect(jsonUnwrapStringify(t)).toEqual('[100,200]'); + expect(jsonUnwrapStringify(t, 'string')).toEqual('["100","200"]'); + expect( + jsonUnwrapStringify(t, undefined, (_, v) => + typeof v === 'bigint' ? -v : v + ) + ).toEqual('[-100,-200]'); + }); + + test('Serializes nested bigint (objects) values as expected', () => { + const t = { a: 100n, b: 200n }; + expect(jsonUnwrapStringify(t)).toEqual('{"a":100,"b":200}'); + expect(jsonUnwrapStringify(t, 'string')).toEqual( + '{"a":"100","b":"200"}' + ); + expect( + jsonUnwrapStringify(t, undefined, (_, v) => + typeof v === 'bigint' ? -v : v + ) + ).toEqual('{"a":-100,"b":-200}'); + }); +}); + describe('ContractName', () => { test('Unwraps as expected', () => { const t = ContractName.fromString('some-name'); @@ -151,6 +188,12 @@ describe('SequenceNumber', () => { let t = SequenceNumber.create(300); let e = '300'; expect(jsonUnwrapStringify(t)).toEqual(e); + expect(jsonUnwrapStringify(t, 'string')).toEqual(`"${e}"`); + expect( + jsonUnwrapStringify(t, undefined, (_, v) => + typeof v === 'bigint' ? -v : v + ) + ).toEqual('-300'); // Test for numbers bigger than Number.MAX_SAFE_INTEGER t = SequenceNumber.create(9007199254740997n); @@ -204,6 +247,9 @@ describe('ContractAddress', () => { let t = ContractAddress.create(100, 10); let e = '{"index":100,"subindex":10}'; expect(jsonUnwrapStringify(t)).toEqual(e); + expect(jsonUnwrapStringify(t, 'string')).toEqual( + '{"index":"100","subindex":"10"}' + ); // Test for numbers bigger than Number.MAX_SAFE_INTEGER t = ContractAddress.create(9007199254740997n, 10);