bson 7.1.1 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "vendor"
15
15
  ],
16
16
  "types": "bson.d.ts",
17
- "version": "7.1.1",
17
+ "version": "7.3.0",
18
18
  "author": {
19
19
  "name": "The MongoDB NodeJS Team",
20
20
  "email": "dbx-node@mongodb.com"
package/src/binary.ts CHANGED
@@ -134,7 +134,7 @@ export class Binary extends BSONValue {
134
134
  throw new BSONError('Binary can only be constructed from Uint8Array or number[]');
135
135
  }
136
136
 
137
- this.sub_type = subType ?? Binary.BSON_BINARY_SUBTYPE_DEFAULT;
137
+ this.sub_type = (subType ?? Binary.BSON_BINARY_SUBTYPE_DEFAULT) & 0xff;
138
138
 
139
139
  if (buffer == null) {
140
140
  // create an empty binary buffer
@@ -279,7 +279,7 @@ export class Binary extends BSONValue {
279
279
  }
280
280
 
281
281
  throw new BSONError(
282
- `Binary sub_type "${this.sub_type}" is not supported for converting to UUID. Only "${Binary.SUBTYPE_UUID}" is currently supported.`
282
+ `Binary sub_type "${this.sub_type}" (${typeof this.sub_type}) is not supported for converting to UUID. Only 0x${Binary.SUBTYPE_UUID.toString(16).padStart(2, '0')} is currently supported.`
283
283
  );
284
284
  }
285
285
 
package/src/bson.ts CHANGED
@@ -22,7 +22,12 @@ export type { CodeExtended } from './code';
22
22
  export type { DBRefLike } from './db_ref';
23
23
  export type { Decimal128Extended } from './decimal128';
24
24
  export type { DoubleExtended } from './double';
25
- export type { EJSONOptions } from './extended_json';
25
+ export type {
26
+ EJSONOptions,
27
+ EJSONOptionsBase,
28
+ EJSONSerializeOptions,
29
+ EJSONParseOptions
30
+ } from './extended_json';
26
31
  export type { Int32Extended } from './int_32';
27
32
  export type { LongExtended } from './long';
28
33
  export type { MaxKeyExtended } from './max_key';
@@ -112,7 +117,6 @@ export function serialize(object: Document, options: SerializeOptions = {}): Uin
112
117
  object,
113
118
  checkKeys,
114
119
  0,
115
- 0,
116
120
  serializeFunctions,
117
121
  ignoreUndefined,
118
122
  null
@@ -156,7 +160,6 @@ export function serializeWithBufferAndIndex(
156
160
  object,
157
161
  checkKeys,
158
162
  0,
159
- 0,
160
163
  serializeFunctions,
161
164
  ignoreUndefined,
162
165
  null
@@ -24,7 +24,7 @@ import { BSONSymbol } from './symbol';
24
24
  import { Timestamp } from './timestamp';
25
25
 
26
26
  /** @public */
27
- export type EJSONOptions = {
27
+ export type EJSONOptionsBase = {
28
28
  /**
29
29
  * Output using the Extended JSON v1 spec
30
30
  * @defaultValue `false`
@@ -32,8 +32,22 @@ export type EJSONOptions = {
32
32
  legacy?: boolean;
33
33
  /**
34
34
  * Enable Extended JSON's `relaxed` mode, which attempts to return native JS types where possible, rather than BSON types
35
- * @defaultValue `false` */
35
+ * @defaultValue `false`
36
+ */
36
37
  relaxed?: boolean;
38
+ };
39
+
40
+ /** @public */
41
+ export type EJSONSerializeOptions = EJSONOptionsBase & {
42
+ /**
43
+ * Omits undefined values from the output instead of converting them to null
44
+ * @defaultValue `false`
45
+ */
46
+ ignoreUndefined?: boolean;
47
+ };
48
+
49
+ /** @public */
50
+ export type EJSONParseOptions = EJSONOptionsBase & {
37
51
  /**
38
52
  * Enable native bigint support
39
53
  * @defaultValue `false`
@@ -41,6 +55,9 @@ export type EJSONOptions = {
41
55
  useBigInt64?: boolean;
42
56
  };
43
57
 
58
+ /** @public */
59
+ export type EJSONOptions = EJSONSerializeOptions & EJSONParseOptions;
60
+
44
61
  /** @internal */
45
62
  type BSONType =
46
63
  | Binary
@@ -174,12 +191,12 @@ function deserializeValue(value: any, options: EJSONOptions = {}) {
174
191
  return value;
175
192
  }
176
193
 
177
- type EJSONSerializeOptions = EJSONOptions & {
194
+ type EJSONSerializeInternalOptions = EJSONSerializeOptions & {
178
195
  seenObjects: { obj: unknown; propertyName: string }[];
179
196
  };
180
197
 
181
198
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
- function serializeArray(array: any[], options: EJSONSerializeOptions): any[] {
199
+ function serializeArray(array: any[], options: EJSONSerializeInternalOptions): any[] {
183
200
  return array.map((v: unknown, index: number) => {
184
201
  options.seenObjects.push({ propertyName: `index ${index}`, obj: null });
185
202
  try {
@@ -197,7 +214,7 @@ function getISOString(date: Date) {
197
214
  }
198
215
 
199
216
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
200
- function serializeValue(value: any, options: EJSONSerializeOptions): any {
217
+ function serializeValue(value: any, options: EJSONSerializeInternalOptions): any {
201
218
  if (value instanceof Map || isMap(value)) {
202
219
  const obj: Record<string, unknown> = Object.create(null);
203
220
  for (const [k, v] of value) {
@@ -242,7 +259,7 @@ function serializeValue(value: any, options: EJSONSerializeOptions): any {
242
259
 
243
260
  if (Array.isArray(value)) return serializeArray(value, options);
244
261
 
245
- if (value === undefined) return null;
262
+ if (value === undefined) return options.ignoreUndefined ? undefined : null;
246
263
 
247
264
  if (value instanceof Date || isDate(value)) {
248
265
  const dateNum = value.getTime(),
@@ -326,7 +343,7 @@ const BSON_TYPE_MAPPINGS = {
326
343
  } as const;
327
344
 
328
345
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
329
- function serializeDocument(doc: any, options: EJSONSerializeOptions) {
346
+ function serializeDocument(doc: any, options: EJSONSerializeInternalOptions) {
330
347
  if (doc == null || typeof doc !== 'object') throw new BSONError('not an object instance');
331
348
 
332
349
  const bsontype: BSONType['_bsontype'] = doc._bsontype;
@@ -410,7 +427,7 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
410
427
  * ```
411
428
  */
412
429
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
413
- function parse(text: string, options?: EJSONOptions): any {
430
+ function parse(text: string, options?: EJSONParseOptions): any {
414
431
  const ejsonOptions = {
415
432
  useBigInt64: options?.useBigInt64 ?? false,
416
433
  relaxed: options?.relaxed ?? true,
@@ -426,6 +443,7 @@ function parse(text: string, options?: EJSONOptions): any {
426
443
  });
427
444
  }
428
445
 
446
+ /* eslint-disable @typescript-eslint/no-explicit-any */
429
447
  /**
430
448
  * Converts a BSON document to an Extended JSON string, optionally replacing values if a replacer
431
449
  * function is specified or optionally including only the specified properties if a replacer array
@@ -447,31 +465,54 @@ function parse(text: string, options?: EJSONOptions): any {
447
465
  *
448
466
  * // prints '{"int32":10}'
449
467
  * console.log(EJSON.stringify(doc));
468
+ *
469
+ * // prints '{"int32":{"$numberInt":"10"}}' with 2 space indentation
470
+ * console.log(EJSON.stringify(doc, { relaxed: false }, 2));
450
471
  * ```
451
472
  */
452
473
  function stringify(
453
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
454
474
  value: any,
455
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
456
- replacer?: (number | string)[] | ((this: any, key: string, value: any) => any) | EJSONOptions,
475
+ replacer?: (number | string)[] | ((this: any, key: string, value: any) => any) | null,
457
476
  space?: string | number,
458
- options?: EJSONOptions
477
+ options?: EJSONSerializeOptions
478
+ ): string;
479
+ function stringify(
480
+ value: any,
481
+ replacer?: (number | string)[] | ((this: any, key: string, value: any) => any) | null,
482
+ options?: EJSONSerializeOptions
483
+ ): string;
484
+ function stringify(value: any, options?: EJSONSerializeOptions, space?: string | number): string;
485
+ function stringify(
486
+ value: any,
487
+ replacerOrOptions?:
488
+ | (number | string)[]
489
+ | ((this: any, key: string, value: any) => any)
490
+ | null
491
+ | EJSONSerializeOptions,
492
+ spaceOrOptions?: string | number | EJSONSerializeOptions,
493
+ options?: EJSONSerializeOptions
459
494
  ): string {
460
- if (space != null && typeof space === 'object') {
461
- options = space;
462
- space = 0;
495
+ /* eslint-enable @typescript-eslint/no-explicit-any */
496
+
497
+ if (spaceOrOptions != null && typeof spaceOrOptions === 'object') {
498
+ options = spaceOrOptions;
499
+ spaceOrOptions = undefined;
463
500
  }
464
- if (replacer != null && typeof replacer === 'object' && !Array.isArray(replacer)) {
465
- options = replacer;
466
- replacer = undefined;
467
- space = 0;
501
+ if (
502
+ replacerOrOptions != null &&
503
+ typeof replacerOrOptions === 'object' &&
504
+ !Array.isArray(replacerOrOptions)
505
+ ) {
506
+ options = replacerOrOptions;
507
+ replacerOrOptions = undefined;
468
508
  }
509
+
469
510
  const serializeOptions = Object.assign({ relaxed: true, legacy: false }, options, {
470
511
  seenObjects: [{ propertyName: '(root)', obj: null }]
471
512
  });
472
513
 
473
514
  const doc = serializeValue(value, serializeOptions);
474
- return JSON.stringify(doc, replacer as Parameters<JSON['stringify']>[1], space);
515
+ return JSON.stringify(doc, replacerOrOptions as Parameters<JSON['stringify']>[1], spaceOrOptions);
475
516
  }
476
517
 
477
518
  /**
@@ -481,7 +522,7 @@ function stringify(
481
522
  * @param options - Optional settings passed to the `stringify` function
482
523
  */
483
524
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
484
- function EJSONserialize(value: any, options?: EJSONOptions): Document {
525
+ function EJSONserialize(value: any, options?: EJSONSerializeOptions): Document {
485
526
  options = options || {};
486
527
  return JSON.parse(stringify(value, options));
487
528
  }
@@ -493,7 +534,7 @@ function EJSONserialize(value: any, options?: EJSONOptions): Document {
493
534
  * @param options - Optional settings passed to the parse method
494
535
  */
495
536
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
496
- function EJSONdeserialize(ejson: Document, options?: EJSONOptions): any {
537
+ function EJSONdeserialize(ejson: Document, options?: EJSONParseOptions): any {
497
538
  options = options || {};
498
539
  return parse(JSON.stringify(ejson), options);
499
540
  }
package/src/objectid.ts CHANGED
@@ -4,9 +4,6 @@ import { type InspectFn, defaultInspect } from './parser/utils';
4
4
  import { ByteUtils } from './utils/byte_utils';
5
5
  import { NumberUtils } from './utils/number_utils';
6
6
 
7
- // Unique sequence for the current process (initialized on first use)
8
- let PROCESS_UNIQUE: Uint8Array | null = null;
9
-
10
7
  /** ObjectId hexString cache @internal */
11
8
  const __idCache = new WeakMap(); // TODO(NODE-6549): convert this to #__id private field when target updated to ES2022
12
9
 
@@ -33,7 +30,28 @@ export class ObjectId extends BSONValue {
33
30
  }
34
31
 
35
32
  /** @internal */
36
- private static index = Math.floor(Math.random() * 0xffffff);
33
+ private static index = 0;
34
+
35
+ /** Unique sequence for the current process (initialized on first use)
36
+ * @internal
37
+ */
38
+ private static PROCESS_UNIQUE: Uint8Array | null = null;
39
+
40
+ /** @internal */
41
+ private static resetState = (): void => {
42
+ this.index = Math.floor(Math.random() * 0x1000000);
43
+ this.PROCESS_UNIQUE = ByteUtils.randomBytes(5);
44
+ };
45
+
46
+ static {
47
+ this.resetState();
48
+ // https://nodejs.org/api/v8.html#startup-snapshot-api
49
+ // @ts-expect-error Node.js types not present since this is an optional API
50
+ const { startupSnapshot } = globalThis?.process?.getBuiltinModule('v8') ?? {};
51
+ if (startupSnapshot?.isBuildingSnapshot()) {
52
+ startupSnapshot?.addDeserializeCallback(this.resetState);
53
+ }
54
+ }
37
55
 
38
56
  static cacheHexString: boolean;
39
57
 
@@ -178,7 +196,7 @@ export class ObjectId extends BSONValue {
178
196
  * @internal
179
197
  */
180
198
  private static getInc(): number {
181
- return (ObjectId.index = (ObjectId.index + 1) % 0xffffff);
199
+ return (ObjectId.index = (ObjectId.index + 1) % 0x1000000);
182
200
  }
183
201
 
184
202
  /**
@@ -197,12 +215,8 @@ export class ObjectId extends BSONValue {
197
215
  // 4-byte timestamp
198
216
  NumberUtils.setInt32BE(buffer, 0, time);
199
217
 
200
- // set PROCESS_UNIQUE if yet not initialized
201
- if (PROCESS_UNIQUE === null) {
202
- PROCESS_UNIQUE = ByteUtils.randomBytes(5);
203
- }
204
-
205
218
  // 5-byte process unique
219
+ const PROCESS_UNIQUE = this.PROCESS_UNIQUE!;
206
220
  buffer[4] = PROCESS_UNIQUE[0];
207
221
  buffer[5] = PROCESS_UNIQUE[1];
208
222
  buffer[6] = PROCESS_UNIQUE[2];
@@ -10,43 +10,64 @@ export function internalCalculateObjectSize(
10
10
  serializeFunctions?: boolean,
11
11
  ignoreUndefined?: boolean
12
12
  ): number {
13
- let totalLength = 4 + 1;
13
+ // Each stack entry carries its own ignoreUndefined so DBRef fields can force ignoreUndefined=true
14
+ // regardless of the caller's setting, matching the behavior of serializeInto.
15
+ const objectStack: Array<{ obj: Document; ignoreUndefined: boolean }> = [
16
+ { obj: object, ignoreUndefined: ignoreUndefined ?? false }
17
+ ];
18
+ let total = 0;
14
19
 
15
- if (Array.isArray(object)) {
16
- for (let i = 0; i < object.length; i++) {
17
- totalLength += calculateElement(
18
- i.toString(),
19
- object[i],
20
- serializeFunctions,
21
- true,
22
- ignoreUndefined
23
- );
24
- }
25
- } else {
26
- // If we have toBSON defined, override the current object
20
+ while (objectStack.length > 0) {
21
+ const { obj, ignoreUndefined: frameIgnoreUndefined } = objectStack.pop()!;
22
+ total += 5; // 4-byte size field + null terminator
27
23
 
28
- if (typeof object?.toBSON === 'function') {
29
- object = object.toBSON();
24
+ const isObjArray = Array.isArray(obj);
25
+ let target = obj;
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ if (!isObjArray && typeof (obj as any)?.toBSON === 'function') {
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
+ target = (obj as any).toBSON();
30
30
  }
31
31
 
32
- // Calculate size
33
- for (const key of Object.keys(object)) {
34
- totalLength += calculateElement(key, object[key], serializeFunctions, false, ignoreUndefined);
32
+ if (isObjArray) {
33
+ const array = target as unknown[];
34
+ for (let i = 0; i < array.length; i++) {
35
+ total += calculateElementSize(
36
+ i.toString(),
37
+ array[i],
38
+ serializeFunctions,
39
+ true,
40
+ frameIgnoreUndefined,
41
+ objectStack
42
+ );
43
+ }
44
+ } else {
45
+ for (const key of Object.keys(target)) {
46
+ total += calculateElementSize(
47
+ key,
48
+ target[key],
49
+ serializeFunctions,
50
+ false,
51
+ frameIgnoreUndefined,
52
+ objectStack
53
+ );
54
+ }
35
55
  }
36
56
  }
37
57
 
38
- return totalLength;
58
+ return total;
39
59
  }
40
60
 
41
61
  /** @internal */
42
- function calculateElement(
62
+ function calculateElementSize(
43
63
  name: string,
44
64
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
65
  value: any,
46
66
  serializeFunctions = false,
47
67
  isArray = false,
48
- ignoreUndefined = false
49
- ) {
68
+ ignoreUndefined = false,
69
+ objectStack: Array<{ obj: Document; ignoreUndefined: boolean }>
70
+ ): number {
50
71
  // If we have toBSON defined, override the current object
51
72
  if (typeof value?.toBSON === 'function') {
52
73
  value = value.toBSON();
@@ -63,20 +84,19 @@ function calculateElement(
63
84
  ) {
64
85
  if (value >= constants.BSON_INT32_MIN && value <= constants.BSON_INT32_MAX) {
65
86
  // 32 bit
66
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (4 + 1);
87
+ return ByteUtils.utf8ByteLength(name) + 1 + (4 + 1);
67
88
  } else {
68
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (8 + 1);
89
+ return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
69
90
  }
70
91
  } else {
71
92
  // 64 bit
72
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (8 + 1);
93
+ return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
73
94
  }
74
95
  case 'undefined':
75
- if (isArray || !ignoreUndefined)
76
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + 1;
96
+ if (isArray || !ignoreUndefined) return ByteUtils.utf8ByteLength(name) + 1 + 1;
77
97
  return 0;
78
98
  case 'boolean':
79
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (1 + 1);
99
+ return ByteUtils.utf8ByteLength(name) + 1 + (1 + 1);
80
100
  case 'object':
81
101
  if (
82
102
  value != null &&
@@ -85,42 +105,42 @@ function calculateElement(
85
105
  ) {
86
106
  throw new BSONVersionError();
87
107
  } else if (value == null || value._bsontype === 'MinKey' || value._bsontype === 'MaxKey') {
88
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + 1;
108
+ return ByteUtils.utf8ByteLength(name) + 1 + 1;
89
109
  } else if (value._bsontype === 'ObjectId') {
90
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (12 + 1);
110
+ return ByteUtils.utf8ByteLength(name) + 1 + (12 + 1);
91
111
  } else if (value instanceof Date || isDate(value)) {
92
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (8 + 1);
112
+ return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
93
113
  } else if (
94
114
  ArrayBuffer.isView(value) ||
95
115
  value instanceof ArrayBuffer ||
96
116
  isAnyArrayBuffer(value)
97
117
  ) {
98
- return (
99
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (1 + 4 + 1) + value.byteLength
100
- );
118
+ return ByteUtils.utf8ByteLength(name) + 1 + (1 + 4 + 1) + value.byteLength;
101
119
  } else if (
102
120
  value._bsontype === 'Long' ||
103
121
  value._bsontype === 'Double' ||
104
122
  value._bsontype === 'Timestamp'
105
123
  ) {
106
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (8 + 1);
124
+ return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
107
125
  } else if (value._bsontype === 'Decimal128') {
108
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (16 + 1);
126
+ return ByteUtils.utf8ByteLength(name) + 1 + (16 + 1);
109
127
  } else if (value._bsontype === 'Code') {
110
128
  // Calculate size depending on the availability of a scope
111
129
  if (value.scope != null && Object.keys(value.scope).length > 0) {
130
+ objectStack.push({ obj: value.scope, ignoreUndefined });
112
131
  return (
113
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +
132
+ ByteUtils.utf8ByteLength(name) +
133
+ 1 +
114
134
  1 +
115
135
  4 +
116
136
  4 +
117
137
  ByteUtils.utf8ByteLength(value.code.toString()) +
118
- 1 +
119
- internalCalculateObjectSize(value.scope, serializeFunctions, ignoreUndefined)
138
+ 1
120
139
  );
121
140
  } else {
122
141
  return (
123
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +
142
+ ByteUtils.utf8ByteLength(name) +
143
+ 1 +
124
144
  1 +
125
145
  4 +
126
146
  ByteUtils.utf8ByteLength(value.code.toString()) +
@@ -131,22 +151,13 @@ function calculateElement(
131
151
  const binary: Binary = value;
132
152
  // Check what kind of subtype we have
133
153
  if (binary.sub_type === Binary.SUBTYPE_BYTE_ARRAY) {
134
- return (
135
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +
136
- (binary.position + 1 + 4 + 1 + 4)
137
- );
154
+ return ByteUtils.utf8ByteLength(name) + 1 + (binary.position + 1 + 4 + 1 + 4);
138
155
  } else {
139
- return (
140
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (binary.position + 1 + 4 + 1)
141
- );
156
+ return ByteUtils.utf8ByteLength(name) + 1 + (binary.position + 1 + 4 + 1);
142
157
  }
143
158
  } else if (value._bsontype === 'Symbol') {
144
159
  return (
145
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +
146
- ByteUtils.utf8ByteLength(value.value) +
147
- 4 +
148
- 1 +
149
- 1
160
+ ByteUtils.utf8ByteLength(name) + 1 + ByteUtils.utf8ByteLength(value.value) + 4 + 1 + 1
150
161
  );
151
162
  } else if (value._bsontype === 'DBRef') {
152
163
  // Set up correct object for serialization
@@ -163,14 +174,13 @@ function calculateElement(
163
174
  ordered_values['$db'] = value.db;
164
175
  }
165
176
 
166
- return (
167
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +
168
- 1 +
169
- internalCalculateObjectSize(ordered_values, serializeFunctions, ignoreUndefined)
170
- );
177
+ // DBRef fields always use ignoreUndefined=true to match serializeInto behavior.
178
+ objectStack.push({ obj: ordered_values, ignoreUndefined: true });
179
+ return ByteUtils.utf8ByteLength(name) + 1 + 1;
171
180
  } else if (value instanceof RegExp || isRegExp(value)) {
172
181
  return (
173
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +
182
+ ByteUtils.utf8ByteLength(name) +
183
+ 1 +
174
184
  1 +
175
185
  ByteUtils.utf8ByteLength(value.source) +
176
186
  1 +
@@ -181,7 +191,8 @@ function calculateElement(
181
191
  );
182
192
  } else if (value._bsontype === 'BSONRegExp') {
183
193
  return (
184
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +
194
+ ByteUtils.utf8ByteLength(name) +
195
+ 1 +
185
196
  1 +
186
197
  ByteUtils.utf8ByteLength(value.pattern) +
187
198
  1 +
@@ -189,16 +200,14 @@ function calculateElement(
189
200
  1
190
201
  );
191
202
  } else {
192
- return (
193
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +
194
- internalCalculateObjectSize(value, serializeFunctions, ignoreUndefined) +
195
- 1
196
- );
203
+ objectStack.push({ obj: value, ignoreUndefined });
204
+ return ByteUtils.utf8ByteLength(name) + 1 + 1;
197
205
  }
198
206
  case 'function':
199
207
  if (serializeFunctions) {
200
208
  return (
201
- (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +
209
+ ByteUtils.utf8ByteLength(name) +
210
+ 1 +
202
211
  1 +
203
212
  4 +
204
213
  ByteUtils.utf8ByteLength(value.toString()) +
@@ -207,12 +216,10 @@ function calculateElement(
207
216
  }
208
217
  return 0;
209
218
  case 'bigint':
210
- return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (8 + 1);
219
+ return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
211
220
  case 'symbol':
212
221
  return 0;
213
222
  default:
214
223
  throw new BSONError(`Unrecognized JS type: ${typeof value}`);
215
224
  }
216
-
217
- return 0;
218
225
  }