Skip to content

Commit 02d8ae6

Browse files
committed
Call toJSON() on non-ext objects when it exists
1 parent 9770004 commit 02d8ae6

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

src/Encoder.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import type { ExtData } from "./ExtData";
77
export const DEFAULT_MAX_DEPTH = 100;
88
export const DEFAULT_INITIAL_BUFFER_SIZE = 2048;
99

10+
const hastoJSON = (value: unknown): value is { toJSON: unknown } => {
11+
return typeof value === 'object' && value !== null && 'toJSON' in value;
12+
};
13+
1014
export class Encoder<ContextType = undefined> {
1115
private pos = 0;
1216
private view = new DataView(new ArrayBuffer(this.initialBufferSize));
@@ -187,14 +191,19 @@ export class Encoder<ContextType = undefined> {
187191
private encodeObject(object: unknown, depth: number) {
188192
// try to encode objects with custom codec first of non-primitives
189193
const ext = this.extensionCodec.tryToEncode(object, this.context);
194+
190195
if (ext != null) {
191196
this.encodeExtension(ext);
192197
} else if (Array.isArray(object)) {
193198
this.encodeArray(object, depth);
194199
} else if (ArrayBuffer.isView(object)) {
195200
this.encodeBinary(object);
196201
} else if (typeof object === "object") {
197-
this.encodeMap(object as Record<string, unknown>, depth);
202+
if (hastoJSON(object) && typeof object.toJSON === "function") {
203+
this.doEncode(object.toJSON(), depth);
204+
} else {
205+
this.encodeMap(object as Record<string, unknown>, depth);
206+
}
198207
} else {
199208
// symbol, function and other special object come here unless extensionCodec handles them.
200209
throw new Error(`Unrecognized object: ${Object.prototype.toString.apply(object)}`);

test/decodeAsync.test.ts

+39
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,43 @@ describe("decodeAsync", () => {
120120
const object = await decodeAsync(createStream());
121121
assert.deepStrictEqual(object, { "foo": "bar" });
122122
});
123+
124+
it("decodes objects with toJSON methods", async () => {
125+
const object = {
126+
string: "Hello, world!",
127+
nested: {
128+
int: -45,
129+
json: {
130+
toJSON() {
131+
return {
132+
float: Math.PI,
133+
int64: Number.MIN_SAFE_INTEGER,
134+
timestamp: new Date( 0 ),
135+
custom: {
136+
toJSON: () => "custom"
137+
}
138+
}
139+
}
140+
}
141+
}
142+
};
143+
144+
const createStream = async function* () {
145+
for (const byte of encode(object)) {
146+
yield [byte];
147+
}
148+
};
149+
assert.deepStrictEqual(await decodeAsync(createStream()), {
150+
string: "Hello, world!",
151+
nested: {
152+
int: -45,
153+
json: {
154+
float: Math.PI,
155+
int64: Number.MIN_SAFE_INTEGER,
156+
timestamp: new Date( 0 ),
157+
custom: "custom"
158+
}
159+
}
160+
});
161+
});
123162
});

0 commit comments

Comments
 (0)