diff --git a/src/extended_json.ts b/src/extended_json.ts index fd1f0a30..ba05db75 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,18 @@ 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 = Object.create(null); + for (const [k, v] of value) { + 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..f452da09 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,42 @@ describe('Extended JSON', function () { }) ).to.throw(BSONVersionError, /Unsupported BSON version/i); }); + + context('Map objects', function () { + it('serializes an empty Map object', () => { + const input = new Map(); + expect(EJSON.stringify(input)).to.equal('{}'); + }); + + 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('serializes a Map with one string key', () => { + const input = new Map([['a', 100]]); + + 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); + }); + }); });