bson 4.1.0 → 4.2.3

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.
Files changed (90) hide show
  1. package/HISTORY.md +48 -1
  2. package/README.md +7 -9
  3. package/bower.json +1 -1
  4. package/bson.d.ts +986 -0
  5. package/dist/bson.browser.esm.js +7811 -5011
  6. package/dist/bson.browser.esm.js.map +1 -0
  7. package/dist/bson.browser.umd.js +7862 -5099
  8. package/dist/bson.browser.umd.js.map +1 -0
  9. package/dist/bson.bundle.js +8723 -9228
  10. package/dist/bson.bundle.js.map +1 -0
  11. package/dist/bson.esm.js +5728 -4951
  12. package/dist/bson.esm.js.map +1 -0
  13. package/etc/prepare.js +19 -0
  14. package/lib/binary.js +218 -398
  15. package/lib/binary.js.map +1 -0
  16. package/lib/bson.js +201 -240
  17. package/lib/bson.js.map +1 -0
  18. package/lib/code.js +41 -41
  19. package/lib/code.js.map +1 -0
  20. package/lib/constants.js +78 -203
  21. package/lib/constants.js.map +1 -0
  22. package/lib/db_ref.js +88 -81
  23. package/lib/db_ref.js.map +1 -0
  24. package/lib/decimal128.js +667 -777
  25. package/lib/decimal128.js.map +1 -0
  26. package/lib/double.js +68 -70
  27. package/lib/double.js.map +1 -0
  28. package/lib/ensure_buffer.js +22 -18
  29. package/lib/ensure_buffer.js.map +1 -0
  30. package/lib/extended_json.js +310 -321
  31. package/lib/extended_json.js.map +1 -0
  32. package/lib/float_parser.js +98 -104
  33. package/lib/float_parser.js.map +1 -0
  34. package/lib/int_32.js +50 -49
  35. package/lib/int_32.js.map +1 -0
  36. package/lib/long.js +881 -16
  37. package/lib/long.js.map +1 -0
  38. package/lib/map.js +130 -122
  39. package/lib/map.js.map +1 -0
  40. package/lib/max_key.js +28 -25
  41. package/lib/max_key.js.map +1 -0
  42. package/lib/min_key.js +28 -25
  43. package/lib/min_key.js.map +1 -0
  44. package/lib/objectid.js +300 -410
  45. package/lib/objectid.js.map +1 -0
  46. package/lib/parser/calculate_size.js +188 -224
  47. package/lib/parser/calculate_size.js.map +1 -0
  48. package/lib/parser/deserializer.js +545 -621
  49. package/lib/parser/deserializer.js.map +1 -0
  50. package/lib/parser/serializer.js +798 -923
  51. package/lib/parser/serializer.js.map +1 -0
  52. package/lib/parser/utils.js +92 -30
  53. package/lib/parser/utils.js.map +1 -0
  54. package/lib/regexp.js +61 -74
  55. package/lib/regexp.js.map +1 -0
  56. package/lib/symbol.js +45 -58
  57. package/lib/symbol.js.map +1 -0
  58. package/lib/timestamp.js +91 -95
  59. package/lib/timestamp.js.map +1 -0
  60. package/lib/uuid.js +48 -0
  61. package/lib/uuid.js.map +1 -0
  62. package/lib/validate_utf8.js +41 -42
  63. package/lib/validate_utf8.js.map +1 -0
  64. package/package.json +53 -31
  65. package/src/binary.ts +272 -0
  66. package/src/bson.ts +326 -0
  67. package/src/code.ts +61 -0
  68. package/src/constants.ts +104 -0
  69. package/src/db_ref.ts +119 -0
  70. package/src/decimal128.ts +803 -0
  71. package/src/double.ts +87 -0
  72. package/src/ensure_buffer.ts +26 -0
  73. package/src/extended_json.ts +395 -0
  74. package/src/float_parser.ts +152 -0
  75. package/src/int_32.ts +66 -0
  76. package/src/long.ts +1002 -0
  77. package/src/map.ts +139 -0
  78. package/src/max_key.ts +37 -0
  79. package/src/min_key.ts +37 -0
  80. package/src/objectid.ts +379 -0
  81. package/src/parser/calculate_size.ts +230 -0
  82. package/src/parser/deserializer.ts +655 -0
  83. package/src/parser/serializer.ts +1069 -0
  84. package/src/parser/utils.ts +93 -0
  85. package/src/regexp.ts +94 -0
  86. package/src/symbol.ts +59 -0
  87. package/src/timestamp.ts +108 -0
  88. package/src/uuid.ts +57 -0
  89. package/src/validate_utf8.ts +47 -0
  90. package/lib/fnv1a.js +0 -48
@@ -0,0 +1,1069 @@
1
+ import type { Buffer } from 'buffer';
2
+ import { Binary } from '../binary';
3
+ import type { BSONSymbol, DBRef, Document, MaxKey } from '../bson';
4
+ import type { Code } from '../code';
5
+ import * as constants from '../constants';
6
+ import type { DBRefLike } from '../db_ref';
7
+ import type { Decimal128 } from '../decimal128';
8
+ import type { Double } from '../double';
9
+ import { ensureBuffer } from '../ensure_buffer';
10
+ import { isBSONType } from '../extended_json';
11
+ import { writeIEEE754 } from '../float_parser';
12
+ import type { Int32 } from '../int_32';
13
+ import { Long } from '../long';
14
+ import { Map } from '../map';
15
+ import type { MinKey } from '../min_key';
16
+ import type { ObjectId } from '../objectid';
17
+ import type { BSONRegExp } from '../regexp';
18
+ import {
19
+ isBigInt64Array,
20
+ isBigUInt64Array,
21
+ isBuffer,
22
+ isDate,
23
+ isUint8Array,
24
+ normalizedFunctionString
25
+ } from './utils';
26
+
27
+ /** @public */
28
+ export interface SerializeOptions {
29
+ /** the serializer will check if keys are valid. */
30
+ checkKeys?: boolean;
31
+ /** serialize the javascript functions **(default:false)**. */
32
+ serializeFunctions?: boolean;
33
+ /** serialize will not emit undefined fields **(default:true)** */
34
+ ignoreUndefined?: boolean;
35
+ /** @internal Resize internal buffer */
36
+ minInternalBufferSize?: number;
37
+ /** the index in the buffer where we wish to start serializing into */
38
+ index?: number;
39
+ }
40
+
41
+ const regexp = /\x00/; // eslint-disable-line no-control-regex
42
+ const ignoreKeys = new Set(['$db', '$ref', '$id', '$clusterTime']);
43
+
44
+ function isRegExp(d: unknown): d is RegExp {
45
+ return Object.prototype.toString.call(d) === '[object RegExp]';
46
+ }
47
+
48
+ /*
49
+ * isArray indicates if we are writing to a BSON array (type 0x04)
50
+ * which forces the "key" which really an array index as a string to be written as ascii
51
+ * This will catch any errors in index as a string generation
52
+ */
53
+
54
+ function serializeString(
55
+ buffer: Buffer,
56
+ key: string,
57
+ value: string,
58
+ index: number,
59
+ isArray?: boolean
60
+ ) {
61
+ // Encode String type
62
+ buffer[index++] = constants.BSON_DATA_STRING;
63
+ // Number of written bytes
64
+ const numberOfWrittenBytes = !isArray
65
+ ? buffer.write(key, index, undefined, 'utf8')
66
+ : buffer.write(key, index, undefined, 'ascii');
67
+ // Encode the name
68
+ index = index + numberOfWrittenBytes + 1;
69
+ buffer[index - 1] = 0;
70
+ // Write the string
71
+ const size = buffer.write(value, index + 4, undefined, 'utf8');
72
+ // Write the size of the string to buffer
73
+ buffer[index + 3] = ((size + 1) >> 24) & 0xff;
74
+ buffer[index + 2] = ((size + 1) >> 16) & 0xff;
75
+ buffer[index + 1] = ((size + 1) >> 8) & 0xff;
76
+ buffer[index] = (size + 1) & 0xff;
77
+ // Update index
78
+ index = index + 4 + size;
79
+ // Write zero
80
+ buffer[index++] = 0;
81
+ return index;
82
+ }
83
+
84
+ function serializeNumber(
85
+ buffer: Buffer,
86
+ key: string,
87
+ value: number,
88
+ index: number,
89
+ isArray?: boolean
90
+ ) {
91
+ // We have an integer value
92
+ // TODO(NODE-2529): Add support for big int
93
+ if (
94
+ Number.isInteger(value) &&
95
+ value >= constants.BSON_INT32_MIN &&
96
+ value <= constants.BSON_INT32_MAX
97
+ ) {
98
+ // If the value fits in 32 bits encode as int32
99
+ // Set int type 32 bits or less
100
+ buffer[index++] = constants.BSON_DATA_INT;
101
+ // Number of written bytes
102
+ const numberOfWrittenBytes = !isArray
103
+ ? buffer.write(key, index, undefined, 'utf8')
104
+ : buffer.write(key, index, undefined, 'ascii');
105
+ // Encode the name
106
+ index = index + numberOfWrittenBytes;
107
+ buffer[index++] = 0;
108
+ // Write the int value
109
+ buffer[index++] = value & 0xff;
110
+ buffer[index++] = (value >> 8) & 0xff;
111
+ buffer[index++] = (value >> 16) & 0xff;
112
+ buffer[index++] = (value >> 24) & 0xff;
113
+ } else {
114
+ // Encode as double
115
+ buffer[index++] = constants.BSON_DATA_NUMBER;
116
+ // Number of written bytes
117
+ const numberOfWrittenBytes = !isArray
118
+ ? buffer.write(key, index, undefined, 'utf8')
119
+ : buffer.write(key, index, undefined, 'ascii');
120
+ // Encode the name
121
+ index = index + numberOfWrittenBytes;
122
+ buffer[index++] = 0;
123
+ // Write float
124
+ writeIEEE754(buffer, value, index, 'little', 52, 8);
125
+ // Adjust index
126
+ index = index + 8;
127
+ }
128
+
129
+ return index;
130
+ }
131
+
132
+ function serializeNull(buffer: Buffer, key: string, _: unknown, index: number, isArray?: boolean) {
133
+ // Set long type
134
+ buffer[index++] = constants.BSON_DATA_NULL;
135
+
136
+ // Number of written bytes
137
+ const numberOfWrittenBytes = !isArray
138
+ ? buffer.write(key, index, undefined, 'utf8')
139
+ : buffer.write(key, index, undefined, 'ascii');
140
+
141
+ // Encode the name
142
+ index = index + numberOfWrittenBytes;
143
+ buffer[index++] = 0;
144
+ return index;
145
+ }
146
+
147
+ function serializeBoolean(
148
+ buffer: Buffer,
149
+ key: string,
150
+ value: boolean,
151
+ index: number,
152
+ isArray?: boolean
153
+ ) {
154
+ // Write the type
155
+ buffer[index++] = constants.BSON_DATA_BOOLEAN;
156
+ // Number of written bytes
157
+ const numberOfWrittenBytes = !isArray
158
+ ? buffer.write(key, index, undefined, 'utf8')
159
+ : buffer.write(key, index, undefined, 'ascii');
160
+ // Encode the name
161
+ index = index + numberOfWrittenBytes;
162
+ buffer[index++] = 0;
163
+ // Encode the boolean value
164
+ buffer[index++] = value ? 1 : 0;
165
+ return index;
166
+ }
167
+
168
+ function serializeDate(buffer: Buffer, key: string, value: Date, index: number, isArray?: boolean) {
169
+ // Write the type
170
+ buffer[index++] = constants.BSON_DATA_DATE;
171
+ // Number of written bytes
172
+ const numberOfWrittenBytes = !isArray
173
+ ? buffer.write(key, index, undefined, 'utf8')
174
+ : buffer.write(key, index, undefined, 'ascii');
175
+ // Encode the name
176
+ index = index + numberOfWrittenBytes;
177
+ buffer[index++] = 0;
178
+
179
+ // Write the date
180
+ const dateInMilis = Long.fromNumber(value.getTime());
181
+ const lowBits = dateInMilis.getLowBits();
182
+ const highBits = dateInMilis.getHighBits();
183
+ // Encode low bits
184
+ buffer[index++] = lowBits & 0xff;
185
+ buffer[index++] = (lowBits >> 8) & 0xff;
186
+ buffer[index++] = (lowBits >> 16) & 0xff;
187
+ buffer[index++] = (lowBits >> 24) & 0xff;
188
+ // Encode high bits
189
+ buffer[index++] = highBits & 0xff;
190
+ buffer[index++] = (highBits >> 8) & 0xff;
191
+ buffer[index++] = (highBits >> 16) & 0xff;
192
+ buffer[index++] = (highBits >> 24) & 0xff;
193
+ return index;
194
+ }
195
+
196
+ function serializeRegExp(
197
+ buffer: Buffer,
198
+ key: string,
199
+ value: RegExp,
200
+ index: number,
201
+ isArray?: boolean
202
+ ) {
203
+ // Write the type
204
+ buffer[index++] = constants.BSON_DATA_REGEXP;
205
+ // Number of written bytes
206
+ const numberOfWrittenBytes = !isArray
207
+ ? buffer.write(key, index, undefined, 'utf8')
208
+ : buffer.write(key, index, undefined, 'ascii');
209
+
210
+ // Encode the name
211
+ index = index + numberOfWrittenBytes;
212
+ buffer[index++] = 0;
213
+ if (value.source && value.source.match(regexp) != null) {
214
+ throw Error('value ' + value.source + ' must not contain null bytes');
215
+ }
216
+ // Adjust the index
217
+ index = index + buffer.write(value.source, index, undefined, 'utf8');
218
+ // Write zero
219
+ buffer[index++] = 0x00;
220
+ // Write the parameters
221
+ if (value.ignoreCase) buffer[index++] = 0x69; // i
222
+ if (value.global) buffer[index++] = 0x73; // s
223
+ if (value.multiline) buffer[index++] = 0x6d; // m
224
+
225
+ // Add ending zero
226
+ buffer[index++] = 0x00;
227
+ return index;
228
+ }
229
+
230
+ function serializeBSONRegExp(
231
+ buffer: Buffer,
232
+ key: string,
233
+ value: BSONRegExp,
234
+ index: number,
235
+ isArray?: boolean
236
+ ) {
237
+ // Write the type
238
+ buffer[index++] = constants.BSON_DATA_REGEXP;
239
+ // Number of written bytes
240
+ const numberOfWrittenBytes = !isArray
241
+ ? buffer.write(key, index, undefined, 'utf8')
242
+ : buffer.write(key, index, undefined, 'ascii');
243
+ // Encode the name
244
+ index = index + numberOfWrittenBytes;
245
+ buffer[index++] = 0;
246
+
247
+ // Check the pattern for 0 bytes
248
+ if (value.pattern.match(regexp) != null) {
249
+ // The BSON spec doesn't allow keys with null bytes because keys are
250
+ // null-terminated.
251
+ throw Error('pattern ' + value.pattern + ' must not contain null bytes');
252
+ }
253
+
254
+ // Adjust the index
255
+ index = index + buffer.write(value.pattern, index, undefined, 'utf8');
256
+ // Write zero
257
+ buffer[index++] = 0x00;
258
+ // Write the options
259
+ index = index + buffer.write(value.options.split('').sort().join(''), index, undefined, 'utf8');
260
+ // Add ending zero
261
+ buffer[index++] = 0x00;
262
+ return index;
263
+ }
264
+
265
+ function serializeMinMax(
266
+ buffer: Buffer,
267
+ key: string,
268
+ value: MinKey | MaxKey,
269
+ index: number,
270
+ isArray?: boolean
271
+ ) {
272
+ // Write the type of either min or max key
273
+ if (value === null) {
274
+ buffer[index++] = constants.BSON_DATA_NULL;
275
+ } else if (value._bsontype === 'MinKey') {
276
+ buffer[index++] = constants.BSON_DATA_MIN_KEY;
277
+ } else {
278
+ buffer[index++] = constants.BSON_DATA_MAX_KEY;
279
+ }
280
+
281
+ // Number of written bytes
282
+ const numberOfWrittenBytes = !isArray
283
+ ? buffer.write(key, index, undefined, 'utf8')
284
+ : buffer.write(key, index, undefined, 'ascii');
285
+ // Encode the name
286
+ index = index + numberOfWrittenBytes;
287
+ buffer[index++] = 0;
288
+ return index;
289
+ }
290
+
291
+ function serializeObjectId(
292
+ buffer: Buffer,
293
+ key: string,
294
+ value: ObjectId,
295
+ index: number,
296
+ isArray?: boolean
297
+ ) {
298
+ // Write the type
299
+ buffer[index++] = constants.BSON_DATA_OID;
300
+ // Number of written bytes
301
+ const numberOfWrittenBytes = !isArray
302
+ ? buffer.write(key, index, undefined, 'utf8')
303
+ : buffer.write(key, index, undefined, 'ascii');
304
+
305
+ // Encode the name
306
+ index = index + numberOfWrittenBytes;
307
+ buffer[index++] = 0;
308
+
309
+ // Write the objectId into the shared buffer
310
+ if (typeof value.id === 'string') {
311
+ buffer.write(value.id, index, undefined, 'binary');
312
+ } else if (value.id && value.id.copy) {
313
+ value.id.copy(buffer, index, 0, 12);
314
+ } else {
315
+ throw new TypeError('object [' + JSON.stringify(value) + '] is not a valid ObjectId');
316
+ }
317
+
318
+ // Adjust index
319
+ return index + 12;
320
+ }
321
+
322
+ function serializeBuffer(
323
+ buffer: Buffer,
324
+ key: string,
325
+ value: Buffer | Uint8Array,
326
+ index: number,
327
+ isArray?: boolean
328
+ ) {
329
+ // Write the type
330
+ buffer[index++] = constants.BSON_DATA_BINARY;
331
+ // Number of written bytes
332
+ const numberOfWrittenBytes = !isArray
333
+ ? buffer.write(key, index, undefined, 'utf8')
334
+ : buffer.write(key, index, undefined, 'ascii');
335
+ // Encode the name
336
+ index = index + numberOfWrittenBytes;
337
+ buffer[index++] = 0;
338
+ // Get size of the buffer (current write point)
339
+ const size = value.length;
340
+ // Write the size of the string to buffer
341
+ buffer[index++] = size & 0xff;
342
+ buffer[index++] = (size >> 8) & 0xff;
343
+ buffer[index++] = (size >> 16) & 0xff;
344
+ buffer[index++] = (size >> 24) & 0xff;
345
+ // Write the default subtype
346
+ buffer[index++] = constants.BSON_BINARY_SUBTYPE_DEFAULT;
347
+ // Copy the content form the binary field to the buffer
348
+ buffer.set(ensureBuffer(value), index);
349
+ // Adjust the index
350
+ index = index + size;
351
+ return index;
352
+ }
353
+
354
+ function serializeObject(
355
+ buffer: Buffer,
356
+ key: string,
357
+ value: Document,
358
+ index: number,
359
+ checkKeys = false,
360
+ depth = 0,
361
+ serializeFunctions = false,
362
+ ignoreUndefined = true,
363
+ isArray = false,
364
+ path: Document[] = []
365
+ ) {
366
+ for (let i = 0; i < path.length; i++) {
367
+ if (path[i] === value) throw new Error('cyclic dependency detected');
368
+ }
369
+
370
+ // Push value to stack
371
+ path.push(value);
372
+ // Write the type
373
+ buffer[index++] = Array.isArray(value) ? constants.BSON_DATA_ARRAY : constants.BSON_DATA_OBJECT;
374
+ // Number of written bytes
375
+ const numberOfWrittenBytes = !isArray
376
+ ? buffer.write(key, index, undefined, 'utf8')
377
+ : buffer.write(key, index, undefined, 'ascii');
378
+ // Encode the name
379
+ index = index + numberOfWrittenBytes;
380
+ buffer[index++] = 0;
381
+ const endIndex = serializeInto(
382
+ buffer,
383
+ value,
384
+ checkKeys,
385
+ index,
386
+ depth + 1,
387
+ serializeFunctions,
388
+ ignoreUndefined,
389
+ path
390
+ );
391
+ // Pop stack
392
+ path.pop();
393
+ return endIndex;
394
+ }
395
+
396
+ function serializeDecimal128(
397
+ buffer: Buffer,
398
+ key: string,
399
+ value: Decimal128,
400
+ index: number,
401
+ isArray?: boolean
402
+ ) {
403
+ buffer[index++] = constants.BSON_DATA_DECIMAL128;
404
+ // Number of written bytes
405
+ const numberOfWrittenBytes = !isArray
406
+ ? buffer.write(key, index, undefined, 'utf8')
407
+ : buffer.write(key, index, undefined, 'ascii');
408
+ // Encode the name
409
+ index = index + numberOfWrittenBytes;
410
+ buffer[index++] = 0;
411
+ // Write the data from the value
412
+ value.bytes.copy(buffer, index, 0, 16);
413
+ return index + 16;
414
+ }
415
+
416
+ function serializeLong(buffer: Buffer, key: string, value: Long, index: number, isArray?: boolean) {
417
+ // Write the type
418
+ buffer[index++] =
419
+ value._bsontype === 'Long' ? constants.BSON_DATA_LONG : constants.BSON_DATA_TIMESTAMP;
420
+ // Number of written bytes
421
+ const numberOfWrittenBytes = !isArray
422
+ ? buffer.write(key, index, undefined, 'utf8')
423
+ : buffer.write(key, index, undefined, 'ascii');
424
+ // Encode the name
425
+ index = index + numberOfWrittenBytes;
426
+ buffer[index++] = 0;
427
+ // Write the date
428
+ const lowBits = value.getLowBits();
429
+ const highBits = value.getHighBits();
430
+ // Encode low bits
431
+ buffer[index++] = lowBits & 0xff;
432
+ buffer[index++] = (lowBits >> 8) & 0xff;
433
+ buffer[index++] = (lowBits >> 16) & 0xff;
434
+ buffer[index++] = (lowBits >> 24) & 0xff;
435
+ // Encode high bits
436
+ buffer[index++] = highBits & 0xff;
437
+ buffer[index++] = (highBits >> 8) & 0xff;
438
+ buffer[index++] = (highBits >> 16) & 0xff;
439
+ buffer[index++] = (highBits >> 24) & 0xff;
440
+ return index;
441
+ }
442
+
443
+ function serializeInt32(
444
+ buffer: Buffer,
445
+ key: string,
446
+ value: Int32 | number,
447
+ index: number,
448
+ isArray?: boolean
449
+ ) {
450
+ value = value.valueOf();
451
+ // Set int type 32 bits or less
452
+ buffer[index++] = constants.BSON_DATA_INT;
453
+ // Number of written bytes
454
+ const numberOfWrittenBytes = !isArray
455
+ ? buffer.write(key, index, undefined, 'utf8')
456
+ : buffer.write(key, index, undefined, 'ascii');
457
+ // Encode the name
458
+ index = index + numberOfWrittenBytes;
459
+ buffer[index++] = 0;
460
+ // Write the int value
461
+ buffer[index++] = value & 0xff;
462
+ buffer[index++] = (value >> 8) & 0xff;
463
+ buffer[index++] = (value >> 16) & 0xff;
464
+ buffer[index++] = (value >> 24) & 0xff;
465
+ return index;
466
+ }
467
+
468
+ function serializeDouble(
469
+ buffer: Buffer,
470
+ key: string,
471
+ value: Double,
472
+ index: number,
473
+ isArray?: boolean
474
+ ) {
475
+ // Encode as double
476
+ buffer[index++] = constants.BSON_DATA_NUMBER;
477
+
478
+ // Number of written bytes
479
+ const numberOfWrittenBytes = !isArray
480
+ ? buffer.write(key, index, undefined, 'utf8')
481
+ : buffer.write(key, index, undefined, 'ascii');
482
+
483
+ // Encode the name
484
+ index = index + numberOfWrittenBytes;
485
+ buffer[index++] = 0;
486
+
487
+ // Write float
488
+ writeIEEE754(buffer, value.value, index, 'little', 52, 8);
489
+
490
+ // Adjust index
491
+ index = index + 8;
492
+ return index;
493
+ }
494
+
495
+ function serializeFunction(
496
+ buffer: Buffer,
497
+ key: string,
498
+ value: Function,
499
+ index: number,
500
+ _checkKeys = false,
501
+ _depth = 0,
502
+ isArray?: boolean
503
+ ) {
504
+ buffer[index++] = constants.BSON_DATA_CODE;
505
+ // Number of written bytes
506
+ const numberOfWrittenBytes = !isArray
507
+ ? buffer.write(key, index, undefined, 'utf8')
508
+ : buffer.write(key, index, undefined, 'ascii');
509
+ // Encode the name
510
+ index = index + numberOfWrittenBytes;
511
+ buffer[index++] = 0;
512
+ // Function string
513
+ const functionString = normalizedFunctionString(value);
514
+
515
+ // Write the string
516
+ const size = buffer.write(functionString, index + 4, undefined, 'utf8') + 1;
517
+ // Write the size of the string to buffer
518
+ buffer[index] = size & 0xff;
519
+ buffer[index + 1] = (size >> 8) & 0xff;
520
+ buffer[index + 2] = (size >> 16) & 0xff;
521
+ buffer[index + 3] = (size >> 24) & 0xff;
522
+ // Update index
523
+ index = index + 4 + size - 1;
524
+ // Write zero
525
+ buffer[index++] = 0;
526
+ return index;
527
+ }
528
+
529
+ function serializeCode(
530
+ buffer: Buffer,
531
+ key: string,
532
+ value: Code,
533
+ index: number,
534
+ checkKeys = false,
535
+ depth = 0,
536
+ serializeFunctions = false,
537
+ ignoreUndefined = true,
538
+ isArray = false
539
+ ) {
540
+ if (value.scope && typeof value.scope === 'object') {
541
+ // Write the type
542
+ buffer[index++] = constants.BSON_DATA_CODE_W_SCOPE;
543
+ // Number of written bytes
544
+ const numberOfWrittenBytes = !isArray
545
+ ? buffer.write(key, index, undefined, 'utf8')
546
+ : buffer.write(key, index, undefined, 'ascii');
547
+ // Encode the name
548
+ index = index + numberOfWrittenBytes;
549
+ buffer[index++] = 0;
550
+
551
+ // Starting index
552
+ let startIndex = index;
553
+
554
+ // Serialize the function
555
+ // Get the function string
556
+ const functionString = typeof value.code === 'string' ? value.code : value.code.toString();
557
+ // Index adjustment
558
+ index = index + 4;
559
+ // Write string into buffer
560
+ const codeSize = buffer.write(functionString, index + 4, undefined, 'utf8') + 1;
561
+ // Write the size of the string to buffer
562
+ buffer[index] = codeSize & 0xff;
563
+ buffer[index + 1] = (codeSize >> 8) & 0xff;
564
+ buffer[index + 2] = (codeSize >> 16) & 0xff;
565
+ buffer[index + 3] = (codeSize >> 24) & 0xff;
566
+ // Write end 0
567
+ buffer[index + 4 + codeSize - 1] = 0;
568
+ // Write the
569
+ index = index + codeSize + 4;
570
+
571
+ //
572
+ // Serialize the scope value
573
+ const endIndex = serializeInto(
574
+ buffer,
575
+ value.scope,
576
+ checkKeys,
577
+ index,
578
+ depth + 1,
579
+ serializeFunctions,
580
+ ignoreUndefined
581
+ );
582
+ index = endIndex - 1;
583
+
584
+ // Writ the total
585
+ const totalSize = endIndex - startIndex;
586
+
587
+ // Write the total size of the object
588
+ buffer[startIndex++] = totalSize & 0xff;
589
+ buffer[startIndex++] = (totalSize >> 8) & 0xff;
590
+ buffer[startIndex++] = (totalSize >> 16) & 0xff;
591
+ buffer[startIndex++] = (totalSize >> 24) & 0xff;
592
+ // Write trailing zero
593
+ buffer[index++] = 0;
594
+ } else {
595
+ buffer[index++] = constants.BSON_DATA_CODE;
596
+ // Number of written bytes
597
+ const numberOfWrittenBytes = !isArray
598
+ ? buffer.write(key, index, undefined, 'utf8')
599
+ : buffer.write(key, index, undefined, 'ascii');
600
+ // Encode the name
601
+ index = index + numberOfWrittenBytes;
602
+ buffer[index++] = 0;
603
+ // Function string
604
+ const functionString = value.code.toString();
605
+ // Write the string
606
+ const size = buffer.write(functionString, index + 4, undefined, 'utf8') + 1;
607
+ // Write the size of the string to buffer
608
+ buffer[index] = size & 0xff;
609
+ buffer[index + 1] = (size >> 8) & 0xff;
610
+ buffer[index + 2] = (size >> 16) & 0xff;
611
+ buffer[index + 3] = (size >> 24) & 0xff;
612
+ // Update index
613
+ index = index + 4 + size - 1;
614
+ // Write zero
615
+ buffer[index++] = 0;
616
+ }
617
+
618
+ return index;
619
+ }
620
+
621
+ function serializeBinary(
622
+ buffer: Buffer,
623
+ key: string,
624
+ value: Binary,
625
+ index: number,
626
+ isArray?: boolean
627
+ ) {
628
+ // Write the type
629
+ buffer[index++] = constants.BSON_DATA_BINARY;
630
+ // Number of written bytes
631
+ const numberOfWrittenBytes = !isArray
632
+ ? buffer.write(key, index, undefined, 'utf8')
633
+ : buffer.write(key, index, undefined, 'ascii');
634
+ // Encode the name
635
+ index = index + numberOfWrittenBytes;
636
+ buffer[index++] = 0;
637
+ // Extract the buffer
638
+ const data = value.value(true) as Buffer | Uint8Array;
639
+ // Calculate size
640
+ let size = value.position;
641
+ // Add the deprecated 02 type 4 bytes of size to total
642
+ if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) size = size + 4;
643
+ // Write the size of the string to buffer
644
+ buffer[index++] = size & 0xff;
645
+ buffer[index++] = (size >> 8) & 0xff;
646
+ buffer[index++] = (size >> 16) & 0xff;
647
+ buffer[index++] = (size >> 24) & 0xff;
648
+ // Write the subtype to the buffer
649
+ buffer[index++] = value.sub_type;
650
+
651
+ // If we have binary type 2 the 4 first bytes are the size
652
+ if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) {
653
+ size = size - 4;
654
+ buffer[index++] = size & 0xff;
655
+ buffer[index++] = (size >> 8) & 0xff;
656
+ buffer[index++] = (size >> 16) & 0xff;
657
+ buffer[index++] = (size >> 24) & 0xff;
658
+ }
659
+
660
+ // Write the data to the object
661
+ buffer.set(data, index);
662
+ // Adjust the index
663
+ index = index + value.position;
664
+ return index;
665
+ }
666
+
667
+ function serializeSymbol(
668
+ buffer: Buffer,
669
+ key: string,
670
+ value: BSONSymbol,
671
+ index: number,
672
+ isArray?: boolean
673
+ ) {
674
+ // Write the type
675
+ buffer[index++] = constants.BSON_DATA_SYMBOL;
676
+ // Number of written bytes
677
+ const numberOfWrittenBytes = !isArray
678
+ ? buffer.write(key, index, undefined, 'utf8')
679
+ : buffer.write(key, index, undefined, 'ascii');
680
+ // Encode the name
681
+ index = index + numberOfWrittenBytes;
682
+ buffer[index++] = 0;
683
+ // Write the string
684
+ const size = buffer.write(value.value, index + 4, undefined, 'utf8') + 1;
685
+ // Write the size of the string to buffer
686
+ buffer[index] = size & 0xff;
687
+ buffer[index + 1] = (size >> 8) & 0xff;
688
+ buffer[index + 2] = (size >> 16) & 0xff;
689
+ buffer[index + 3] = (size >> 24) & 0xff;
690
+ // Update index
691
+ index = index + 4 + size - 1;
692
+ // Write zero
693
+ buffer[index++] = 0x00;
694
+ return index;
695
+ }
696
+
697
+ function serializeDBRef(
698
+ buffer: Buffer,
699
+ key: string,
700
+ value: DBRef,
701
+ index: number,
702
+ depth: number,
703
+ serializeFunctions: boolean,
704
+ isArray?: boolean
705
+ ) {
706
+ // Write the type
707
+ buffer[index++] = constants.BSON_DATA_OBJECT;
708
+ // Number of written bytes
709
+ const numberOfWrittenBytes = !isArray
710
+ ? buffer.write(key, index, undefined, 'utf8')
711
+ : buffer.write(key, index, undefined, 'ascii');
712
+
713
+ // Encode the name
714
+ index = index + numberOfWrittenBytes;
715
+ buffer[index++] = 0;
716
+
717
+ let startIndex = index;
718
+ let output: DBRefLike = {
719
+ $ref: value.collection || value.namespace, // "namespace" was what library 1.x called "collection"
720
+ $id: value.oid
721
+ };
722
+
723
+ if (value.db != null) {
724
+ output.$db = value.db;
725
+ }
726
+
727
+ output = Object.assign(output, value.fields);
728
+ const endIndex = serializeInto(buffer, output, false, index, depth + 1, serializeFunctions);
729
+
730
+ // Calculate object size
731
+ const size = endIndex - startIndex;
732
+ // Write the size
733
+ buffer[startIndex++] = size & 0xff;
734
+ buffer[startIndex++] = (size >> 8) & 0xff;
735
+ buffer[startIndex++] = (size >> 16) & 0xff;
736
+ buffer[startIndex++] = (size >> 24) & 0xff;
737
+ // Set index
738
+ return endIndex;
739
+ }
740
+
741
+ export function serializeInto(
742
+ buffer: Buffer,
743
+ object: Document,
744
+ checkKeys = false,
745
+ startingIndex = 0,
746
+ depth = 0,
747
+ serializeFunctions = false,
748
+ ignoreUndefined = true,
749
+ path: Document[] = []
750
+ ): number {
751
+ startingIndex = startingIndex || 0;
752
+ path = path || [];
753
+
754
+ // Push the object to the path
755
+ path.push(object);
756
+
757
+ // Start place to serialize into
758
+ let index = startingIndex + 4;
759
+
760
+ // Special case isArray
761
+ if (Array.isArray(object)) {
762
+ // Get object keys
763
+ for (let i = 0; i < object.length; i++) {
764
+ const key = '' + i;
765
+ let value = object[i];
766
+
767
+ // Is there an override value
768
+ if (value && value.toBSON) {
769
+ if (typeof value.toBSON !== 'function') throw new TypeError('toBSON is not a function');
770
+ value = value.toBSON();
771
+ }
772
+
773
+ if (typeof value === 'string') {
774
+ index = serializeString(buffer, key, value, index, true);
775
+ } else if (typeof value === 'number') {
776
+ index = serializeNumber(buffer, key, value, index, true);
777
+ } else if (typeof value === 'bigint') {
778
+ throw new TypeError('Unsupported type BigInt, please use Decimal128');
779
+ } else if (typeof value === 'boolean') {
780
+ index = serializeBoolean(buffer, key, value, index, true);
781
+ } else if (value instanceof Date || isDate(value)) {
782
+ index = serializeDate(buffer, key, value, index, true);
783
+ } else if (value === undefined) {
784
+ index = serializeNull(buffer, key, value, index, true);
785
+ } else if (value === null) {
786
+ index = serializeNull(buffer, key, value, index, true);
787
+ } else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
788
+ index = serializeObjectId(buffer, key, value, index, true);
789
+ } else if (isBuffer(value) || isUint8Array(value)) {
790
+ index = serializeBuffer(buffer, key, value, index, true);
791
+ } else if (value instanceof RegExp || isRegExp(value)) {
792
+ index = serializeRegExp(buffer, key, value, index, true);
793
+ } else if (typeof value === 'object' && value['_bsontype'] == null) {
794
+ index = serializeObject(
795
+ buffer,
796
+ key,
797
+ value,
798
+ index,
799
+ checkKeys,
800
+ depth,
801
+ serializeFunctions,
802
+ ignoreUndefined,
803
+ true,
804
+ path
805
+ );
806
+ } else if (
807
+ typeof value === 'object' &&
808
+ isBSONType(value) &&
809
+ value._bsontype === 'Decimal128'
810
+ ) {
811
+ index = serializeDecimal128(buffer, key, value, index, true);
812
+ } else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') {
813
+ index = serializeLong(buffer, key, value, index, true);
814
+ } else if (value['_bsontype'] === 'Double') {
815
+ index = serializeDouble(buffer, key, value, index, true);
816
+ } else if (typeof value === 'function' && serializeFunctions) {
817
+ index = serializeFunction(buffer, key, value, index, checkKeys, depth, true);
818
+ } else if (value['_bsontype'] === 'Code') {
819
+ index = serializeCode(
820
+ buffer,
821
+ key,
822
+ value,
823
+ index,
824
+ checkKeys,
825
+ depth,
826
+ serializeFunctions,
827
+ ignoreUndefined,
828
+ true
829
+ );
830
+ } else if (value['_bsontype'] === 'Binary') {
831
+ index = serializeBinary(buffer, key, value, index, true);
832
+ } else if (value['_bsontype'] === 'Symbol') {
833
+ index = serializeSymbol(buffer, key, value, index, true);
834
+ } else if (value['_bsontype'] === 'DBRef') {
835
+ index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions, true);
836
+ } else if (value['_bsontype'] === 'BSONRegExp') {
837
+ index = serializeBSONRegExp(buffer, key, value, index, true);
838
+ } else if (value['_bsontype'] === 'Int32') {
839
+ index = serializeInt32(buffer, key, value, index, true);
840
+ } else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') {
841
+ index = serializeMinMax(buffer, key, value, index, true);
842
+ } else if (typeof value['_bsontype'] !== 'undefined') {
843
+ throw new TypeError('Unrecognized or invalid _bsontype: ' + value['_bsontype']);
844
+ }
845
+ }
846
+ } else if (object instanceof Map) {
847
+ const iterator = object.entries();
848
+ let done = false;
849
+
850
+ while (!done) {
851
+ // Unpack the next entry
852
+ const entry = iterator.next();
853
+ done = !!entry.done;
854
+ // Are we done, then skip and terminate
855
+ if (done) continue;
856
+
857
+ // Get the entry values
858
+ const key = entry.value[0];
859
+ const value = entry.value[1];
860
+
861
+ // Check the type of the value
862
+ const type = typeof value;
863
+
864
+ // Check the key and throw error if it's illegal
865
+ if (typeof key === 'string' && !ignoreKeys.has(key)) {
866
+ if (key.match(regexp) != null) {
867
+ // The BSON spec doesn't allow keys with null bytes because keys are
868
+ // null-terminated.
869
+ throw Error('key ' + key + ' must not contain null bytes');
870
+ }
871
+
872
+ if (checkKeys) {
873
+ if ('$' === key[0]) {
874
+ throw Error('key ' + key + " must not start with '$'");
875
+ } else if (~key.indexOf('.')) {
876
+ throw Error('key ' + key + " must not contain '.'");
877
+ }
878
+ }
879
+ }
880
+
881
+ if (type === 'string') {
882
+ index = serializeString(buffer, key, value, index);
883
+ } else if (type === 'number') {
884
+ index = serializeNumber(buffer, key, value, index);
885
+ } else if (type === 'bigint' || isBigInt64Array(value) || isBigUInt64Array(value)) {
886
+ throw new TypeError('Unsupported type BigInt, please use Decimal128');
887
+ } else if (type === 'boolean') {
888
+ index = serializeBoolean(buffer, key, value, index);
889
+ } else if (value instanceof Date || isDate(value)) {
890
+ index = serializeDate(buffer, key, value, index);
891
+ } else if (value === null || (value === undefined && ignoreUndefined === false)) {
892
+ index = serializeNull(buffer, key, value, index);
893
+ } else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
894
+ index = serializeObjectId(buffer, key, value, index);
895
+ } else if (isBuffer(value) || isUint8Array(value)) {
896
+ index = serializeBuffer(buffer, key, value, index);
897
+ } else if (value instanceof RegExp || isRegExp(value)) {
898
+ index = serializeRegExp(buffer, key, value, index);
899
+ } else if (type === 'object' && value['_bsontype'] == null) {
900
+ index = serializeObject(
901
+ buffer,
902
+ key,
903
+ value,
904
+ index,
905
+ checkKeys,
906
+ depth,
907
+ serializeFunctions,
908
+ ignoreUndefined,
909
+ false,
910
+ path
911
+ );
912
+ } else if (type === 'object' && value['_bsontype'] === 'Decimal128') {
913
+ index = serializeDecimal128(buffer, key, value, index);
914
+ } else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') {
915
+ index = serializeLong(buffer, key, value, index);
916
+ } else if (value['_bsontype'] === 'Double') {
917
+ index = serializeDouble(buffer, key, value, index);
918
+ } else if (value['_bsontype'] === 'Code') {
919
+ index = serializeCode(
920
+ buffer,
921
+ key,
922
+ value,
923
+ index,
924
+ checkKeys,
925
+ depth,
926
+ serializeFunctions,
927
+ ignoreUndefined
928
+ );
929
+ } else if (typeof value === 'function' && serializeFunctions) {
930
+ index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions);
931
+ } else if (value['_bsontype'] === 'Binary') {
932
+ index = serializeBinary(buffer, key, value, index);
933
+ } else if (value['_bsontype'] === 'Symbol') {
934
+ index = serializeSymbol(buffer, key, value, index);
935
+ } else if (value['_bsontype'] === 'DBRef') {
936
+ index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions);
937
+ } else if (value['_bsontype'] === 'BSONRegExp') {
938
+ index = serializeBSONRegExp(buffer, key, value, index);
939
+ } else if (value['_bsontype'] === 'Int32') {
940
+ index = serializeInt32(buffer, key, value, index);
941
+ } else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') {
942
+ index = serializeMinMax(buffer, key, value, index);
943
+ } else if (typeof value['_bsontype'] !== 'undefined') {
944
+ throw new TypeError('Unrecognized or invalid _bsontype: ' + value['_bsontype']);
945
+ }
946
+ }
947
+ } else {
948
+ // Did we provide a custom serialization method
949
+ if (object.toBSON) {
950
+ if (typeof object.toBSON !== 'function') throw new TypeError('toBSON is not a function');
951
+ object = object.toBSON();
952
+ if (object != null && typeof object !== 'object')
953
+ throw new TypeError('toBSON function did not return an object');
954
+ }
955
+
956
+ // Iterate over all the keys
957
+ for (const key in object) {
958
+ let value = object[key];
959
+ // Is there an override value
960
+ if (value && value.toBSON) {
961
+ if (typeof value.toBSON !== 'function') throw new TypeError('toBSON is not a function');
962
+ value = value.toBSON();
963
+ }
964
+
965
+ // Check the type of the value
966
+ const type = typeof value;
967
+
968
+ // Check the key and throw error if it's illegal
969
+ if (typeof key === 'string' && !ignoreKeys.has(key)) {
970
+ if (key.match(regexp) != null) {
971
+ // The BSON spec doesn't allow keys with null bytes because keys are
972
+ // null-terminated.
973
+ throw Error('key ' + key + ' must not contain null bytes');
974
+ }
975
+
976
+ if (checkKeys) {
977
+ if ('$' === key[0]) {
978
+ throw Error('key ' + key + " must not start with '$'");
979
+ } else if (~key.indexOf('.')) {
980
+ throw Error('key ' + key + " must not contain '.'");
981
+ }
982
+ }
983
+ }
984
+
985
+ if (type === 'string') {
986
+ index = serializeString(buffer, key, value, index);
987
+ } else if (type === 'number') {
988
+ index = serializeNumber(buffer, key, value, index);
989
+ } else if (type === 'bigint') {
990
+ throw new TypeError('Unsupported type BigInt, please use Decimal128');
991
+ } else if (type === 'boolean') {
992
+ index = serializeBoolean(buffer, key, value, index);
993
+ } else if (value instanceof Date || isDate(value)) {
994
+ index = serializeDate(buffer, key, value, index);
995
+ } else if (value === undefined) {
996
+ if (ignoreUndefined === false) index = serializeNull(buffer, key, value, index);
997
+ } else if (value === null) {
998
+ index = serializeNull(buffer, key, value, index);
999
+ } else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
1000
+ index = serializeObjectId(buffer, key, value, index);
1001
+ } else if (isBuffer(value) || isUint8Array(value)) {
1002
+ index = serializeBuffer(buffer, key, value, index);
1003
+ } else if (value instanceof RegExp || isRegExp(value)) {
1004
+ index = serializeRegExp(buffer, key, value, index);
1005
+ } else if (type === 'object' && value['_bsontype'] == null) {
1006
+ index = serializeObject(
1007
+ buffer,
1008
+ key,
1009
+ value,
1010
+ index,
1011
+ checkKeys,
1012
+ depth,
1013
+ serializeFunctions,
1014
+ ignoreUndefined,
1015
+ false,
1016
+ path
1017
+ );
1018
+ } else if (type === 'object' && value['_bsontype'] === 'Decimal128') {
1019
+ index = serializeDecimal128(buffer, key, value, index);
1020
+ } else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') {
1021
+ index = serializeLong(buffer, key, value, index);
1022
+ } else if (value['_bsontype'] === 'Double') {
1023
+ index = serializeDouble(buffer, key, value, index);
1024
+ } else if (value['_bsontype'] === 'Code') {
1025
+ index = serializeCode(
1026
+ buffer,
1027
+ key,
1028
+ value,
1029
+ index,
1030
+ checkKeys,
1031
+ depth,
1032
+ serializeFunctions,
1033
+ ignoreUndefined
1034
+ );
1035
+ } else if (typeof value === 'function' && serializeFunctions) {
1036
+ index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions);
1037
+ } else if (value['_bsontype'] === 'Binary') {
1038
+ index = serializeBinary(buffer, key, value, index);
1039
+ } else if (value['_bsontype'] === 'Symbol') {
1040
+ index = serializeSymbol(buffer, key, value, index);
1041
+ } else if (value['_bsontype'] === 'DBRef') {
1042
+ index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions);
1043
+ } else if (value['_bsontype'] === 'BSONRegExp') {
1044
+ index = serializeBSONRegExp(buffer, key, value, index);
1045
+ } else if (value['_bsontype'] === 'Int32') {
1046
+ index = serializeInt32(buffer, key, value, index);
1047
+ } else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') {
1048
+ index = serializeMinMax(buffer, key, value, index);
1049
+ } else if (typeof value['_bsontype'] !== 'undefined') {
1050
+ throw new TypeError('Unrecognized or invalid _bsontype: ' + value['_bsontype']);
1051
+ }
1052
+ }
1053
+ }
1054
+
1055
+ // Remove the path
1056
+ path.pop();
1057
+
1058
+ // Final padding byte for object
1059
+ buffer[index++] = 0x00;
1060
+
1061
+ // Final size
1062
+ const size = index - startingIndex;
1063
+ // Write the size of the object
1064
+ buffer[startingIndex++] = size & 0xff;
1065
+ buffer[startingIndex++] = (size >> 8) & 0xff;
1066
+ buffer[startingIndex++] = (size >> 16) & 0xff;
1067
+ buffer[startingIndex++] = (size >> 24) & 0xff;
1068
+ return index;
1069
+ }