From aa3fdff86d4c5b0db8a3c710e120824a5e9e8532 Mon Sep 17 00:00:00 2001 From: Warren James Date: Tue, 14 Mar 2023 16:28:08 -0400 Subject: [PATCH 1/5] fix(NODE-4789): Add fix --- src/extended_json.ts | 13 ++++++++++++- test/node/extended_json.test.ts | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/extended_json.ts b/src/extended_json.ts index fd1f0a30..43a64364 100644 --- a/src/extended_json.ts +++ b/src/extended_json.ts @@ -17,7 +17,7 @@ import { Long } from './long'; import { MaxKey } from './max_key'; import { MinKey } from './min_key'; import { ObjectId } from './objectid'; -import { isDate, isRegExp } from './parser/utils'; +import { isDate, isRegExp, isMap } from './parser/utils'; import { BSONRegExp } from './regexp'; import { BSONSymbol } from './symbol'; import { Timestamp } from './timestamp'; @@ -190,6 +190,17 @@ function getISOString(date: Date) { // eslint-disable-next-line @typescript-eslint/no-explicit-any function serializeValue(value: any, options: EJSONSerializeOptions): any { + if (value instanceof Map || isMap(value)) { + const obj: Record = {}; + for (const [k, v] of value.entries()) { + if (typeof k !== 'string') { + throw new BSONError('Can only serialize maps with string keys'); + } + obj[k] = v; + } + + return serializeValue(obj, options); + } if ((typeof value === 'object' || typeof value === 'function') && value !== null) { const index = options.seenObjects.findIndex(entry => entry.obj === value); if (index !== -1) { diff --git a/test/node/extended_json.test.ts b/test/node/extended_json.test.ts index c1f14f2d..64347091 100644 --- a/test/node/extended_json.test.ts +++ b/test/node/extended_json.test.ts @@ -3,6 +3,7 @@ const EJSON = BSON.EJSON; import * as vm from 'node:vm'; import { expect } from 'chai'; import { BSONVersionError, BSONRuntimeError } from '../../src'; +import { BSONError } from '../register-bson'; // BSON types const Binary = BSON.Binary; @@ -583,4 +584,21 @@ describe('Extended JSON', function () { }) ).to.throw(BSONVersionError, /Unsupported BSON version/i); }); + + it('serializes a Map object with string keys', () => { + const input: Map = new Map(); + input.set('a', { a: 100, b: 200 }); + input.set('b', 100.0); + + const str = EJSON.stringify(input); + expect(str).to.equal('{"a":{"a":100,"b":200},"b":100}'); + }); + + it('throws BSONError when passed Map object with non-string keys', () => { + const input: Map = new Map(); + input.set(1, 100); + input.set(2, 100.0); + + expect(() => EJSON.stringify(input)).to.throw(BSONError); + }); }); From 4638db0acd143a61ec3c759cd8ba423de4eb5e82 Mon Sep 17 00:00:00 2001 From: Warren James Date: Tue, 14 Mar 2023 16:46:33 -0400 Subject: [PATCH 2/5] test(NODE-4789): Update tests --- test/node/extended_json.test.ts | 45 ++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/test/node/extended_json.test.ts b/test/node/extended_json.test.ts index 64347091..f452da09 100644 --- a/test/node/extended_json.test.ts +++ b/test/node/extended_json.test.ts @@ -585,20 +585,41 @@ describe('Extended JSON', function () { ).to.throw(BSONVersionError, /Unsupported BSON version/i); }); - it('serializes a Map object with string keys', () => { - const input: Map = new Map(); - input.set('a', { a: 100, b: 200 }); - input.set('b', 100.0); + context('Map objects', function () { + it('serializes an empty Map object', () => { + const input = new Map(); + expect(EJSON.stringify(input)).to.equal('{}'); + }); - const str = EJSON.stringify(input); - expect(str).to.equal('{"a":{"a":100,"b":200},"b":100}'); - }); + it('serializes a nested Map object', () => { + const input = new Map([ + [ + 'a', + new Map([ + ['a', 100], + ['b', 200] + ]) + ] + ]); + + const str = EJSON.stringify(input); + expect(str).to.equal('{"a":{"a":100,"b":200}}'); + }); - it('throws BSONError when passed Map object with non-string keys', () => { - const input: Map = new Map(); - input.set(1, 100); - input.set(2, 100.0); + it('serializes a Map with one string key', () => { + const input = new Map([['a', 100]]); - expect(() => EJSON.stringify(input)).to.throw(BSONError); + const str = EJSON.stringify(input); + expect(str).to.equal('{"a":100}'); + }); + + it('throws BSONError when passed Map object with non-string keys', () => { + const input: Map = new Map([ + [1, 100], + [2, 200] + ]); + + expect(() => EJSON.stringify(input)).to.throw(BSONError); + }); }); }); From c5e6cf5dd5564fddf5fc8af08e35f562bc9b4f05 Mon Sep 17 00:00:00 2001 From: Warren James Date: Wed, 15 Mar 2023 11:04:44 -0400 Subject: [PATCH 3/5] Update src/extended_json.ts Co-authored-by: Anna Henningsen --- src/extended_json.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extended_json.ts b/src/extended_json.ts index 43a64364..923aeba4 100644 --- a/src/extended_json.ts +++ b/src/extended_json.ts @@ -191,7 +191,7 @@ function getISOString(date: Date) { // eslint-disable-next-line @typescript-eslint/no-explicit-any function serializeValue(value: any, options: EJSONSerializeOptions): any { if (value instanceof Map || isMap(value)) { - const obj: Record = {}; + const obj: Record = Object.create(null); for (const [k, v] of value.entries()) { if (typeof k !== 'string') { throw new BSONError('Can only serialize maps with string keys'); From bb0aa215036fcbc4bc3b084b4066c87c516f6753 Mon Sep 17 00:00:00 2001 From: Warren James Date: Wed, 15 Mar 2023 16:45:55 -0400 Subject: [PATCH 4/5] Update src/extended_json.ts Co-authored-by: Neal Beeken --- src/extended_json.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extended_json.ts b/src/extended_json.ts index 923aeba4..0c978ab2 100644 --- a/src/extended_json.ts +++ b/src/extended_json.ts @@ -192,7 +192,7 @@ function getISOString(date: Date) { function serializeValue(value: any, options: EJSONSerializeOptions): any { if (value instanceof Map || isMap(value)) { const obj: Record = Object.create(null); - for (const [k, v] of value.entries()) { + for (const [k, v] of value) { if (typeof k !== 'string') { throw new BSONError('Can only serialize maps with string keys'); } From b947b5bde2f3df73cdb8d37d6b2b833080a04433 Mon Sep 17 00:00:00 2001 From: Warren James Date: Wed, 15 Mar 2023 16:47:03 -0400 Subject: [PATCH 5/5] style(NODE-4789): add newline --- src/extended_json.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/extended_json.ts b/src/extended_json.ts index 0c978ab2..ba05db75 100644 --- a/src/extended_json.ts +++ b/src/extended_json.ts @@ -201,6 +201,7 @@ function serializeValue(value: any, options: EJSONSerializeOptions): any { return serializeValue(obj, options); } + if ((typeof value === 'object' || typeof value === 'function') && value !== null) { const index = options.seenObjects.findIndex(entry => entry.obj === value); if (index !== -1) {