From b04a35109940a6ada4c9a1c207990ebfd78eb0cf Mon Sep 17 00:00:00 2001 From: Kevin Ennis Date: Sat, 21 Aug 2021 05:30:56 -0400 Subject: [PATCH] Call toJSON() on non-ext objects when it exists --- src/Encoder.ts | 10 +++++++++- test/decodeAsync.test.ts | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/Encoder.ts b/src/Encoder.ts index afea365c..9215f397 100644 --- a/src/Encoder.ts +++ b/src/Encoder.ts @@ -7,6 +7,10 @@ import type { ExtData } from "./ExtData"; export const DEFAULT_MAX_DEPTH = 100; export const DEFAULT_INITIAL_BUFFER_SIZE = 2048; +const hastoJSON = (value: unknown): value is { toJSON: unknown } => { + return typeof value === 'object' && value !== null && 'toJSON' in value; +}; + export class Encoder { private pos = 0; private view = new DataView(new ArrayBuffer(this.initialBufferSize)); @@ -194,7 +198,11 @@ export class Encoder { } else if (ArrayBuffer.isView(object)) { this.encodeBinary(object); } else if (typeof object === "object") { - this.encodeMap(object as Record, depth); + if (hastoJSON(object) && typeof object.toJSON === "function") { + this.doEncode(object.toJSON(), depth); + } else { + this.encodeMap(object as Record, depth); + } } else { // symbol, function and other special object come here unless extensionCodec handles them. throw new Error(`Unrecognized object: ${Object.prototype.toString.apply(object)}`); diff --git a/test/decodeAsync.test.ts b/test/decodeAsync.test.ts index 0e8d9017..4a2d90f5 100644 --- a/test/decodeAsync.test.ts +++ b/test/decodeAsync.test.ts @@ -120,4 +120,43 @@ describe("decodeAsync", () => { const object = await decodeAsync(createStream()); assert.deepStrictEqual(object, { "foo": "bar" }); }); + + it("decodes objects with toJSON methods", async () => { + const object = { + string: "Hello, world!", + nested: { + int: -45, + json: { + toJSON() { + return { + float: Math.PI, + int64: Number.MIN_SAFE_INTEGER, + timestamp: new Date( 0 ), + custom: { + toJSON: () => "custom" + } + } + } + } + } + }; + + const createStream = async function* () { + for (const byte of encode(object)) { + yield [byte]; + } + }; + assert.deepStrictEqual(await decodeAsync(createStream()), { + string: "Hello, world!", + nested: { + int: -45, + json: { + float: Math.PI, + int64: Number.MIN_SAFE_INTEGER, + timestamp: new Date( 0 ), + custom: "custom" + } + } + }); + }); });