bson 7.2.0 → 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/README.md +8 -2
- package/bson.d.ts +129 -5
- package/lib/bson.bundle.js +452 -452
- package/lib/bson.bundle.js.map +1 -1
- package/lib/bson.cjs +452 -452
- package/lib/bson.cjs.map +1 -1
- package/lib/bson.mjs +452 -452
- package/lib/bson.mjs.map +1 -1
- package/lib/bson.node.mjs +452 -452
- package/lib/bson.node.mjs.map +1 -1
- package/lib/bson.rn.cjs +453 -455
- package/lib/bson.rn.cjs.map +1 -1
- package/package.json +1 -1
- package/src/binary.ts +2 -2
- package/src/bson.ts +0 -2
- package/src/extended_json.ts +33 -12
- package/src/objectid.ts +24 -10
- package/src/parser/calculate_size.ts +75 -68
- package/src/parser/deserializer.ts +227 -61
- package/src/parser/serializer.ts +272 -478
- package/src/timestamp.ts +157 -4
package/package.json
CHANGED
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
|
|
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
|
@@ -117,7 +117,6 @@ export function serialize(object: Document, options: SerializeOptions = {}): Uin
|
|
|
117
117
|
object,
|
|
118
118
|
checkKeys,
|
|
119
119
|
0,
|
|
120
|
-
0,
|
|
121
120
|
serializeFunctions,
|
|
122
121
|
ignoreUndefined,
|
|
123
122
|
null
|
|
@@ -161,7 +160,6 @@ export function serializeWithBufferAndIndex(
|
|
|
161
160
|
object,
|
|
162
161
|
checkKeys,
|
|
163
162
|
0,
|
|
164
|
-
0,
|
|
165
163
|
serializeFunctions,
|
|
166
164
|
ignoreUndefined,
|
|
167
165
|
null
|
package/src/extended_json.ts
CHANGED
|
@@ -443,6 +443,7 @@ function parse(text: string, options?: EJSONParseOptions): any {
|
|
|
443
443
|
});
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
446
447
|
/**
|
|
447
448
|
* Converts a BSON document to an Extended JSON string, optionally replacing values if a replacer
|
|
448
449
|
* function is specified or optionally including only the specified properties if a replacer array
|
|
@@ -464,34 +465,54 @@ function parse(text: string, options?: EJSONParseOptions): any {
|
|
|
464
465
|
*
|
|
465
466
|
* // prints '{"int32":10}'
|
|
466
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));
|
|
467
471
|
* ```
|
|
468
472
|
*/
|
|
469
473
|
function stringify(
|
|
470
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
471
474
|
value: any,
|
|
472
|
-
replacer?:
|
|
475
|
+
replacer?: (number | string)[] | ((this: any, key: string, value: any) => any) | null,
|
|
476
|
+
space?: string | number,
|
|
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?:
|
|
473
488
|
| (number | string)[]
|
|
474
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
475
489
|
| ((this: any, key: string, value: any) => any)
|
|
490
|
+
| null
|
|
476
491
|
| EJSONSerializeOptions,
|
|
477
|
-
|
|
492
|
+
spaceOrOptions?: string | number | EJSONSerializeOptions,
|
|
478
493
|
options?: EJSONSerializeOptions
|
|
479
494
|
): string {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
495
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
496
|
+
|
|
497
|
+
if (spaceOrOptions != null && typeof spaceOrOptions === 'object') {
|
|
498
|
+
options = spaceOrOptions;
|
|
499
|
+
spaceOrOptions = undefined;
|
|
483
500
|
}
|
|
484
|
-
if (
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
501
|
+
if (
|
|
502
|
+
replacerOrOptions != null &&
|
|
503
|
+
typeof replacerOrOptions === 'object' &&
|
|
504
|
+
!Array.isArray(replacerOrOptions)
|
|
505
|
+
) {
|
|
506
|
+
options = replacerOrOptions;
|
|
507
|
+
replacerOrOptions = undefined;
|
|
488
508
|
}
|
|
509
|
+
|
|
489
510
|
const serializeOptions = Object.assign({ relaxed: true, legacy: false }, options, {
|
|
490
511
|
seenObjects: [{ propertyName: '(root)', obj: null }]
|
|
491
512
|
});
|
|
492
513
|
|
|
493
514
|
const doc = serializeValue(value, serializeOptions);
|
|
494
|
-
return JSON.stringify(doc,
|
|
515
|
+
return JSON.stringify(doc, replacerOrOptions as Parameters<JSON['stringify']>[1], spaceOrOptions);
|
|
495
516
|
}
|
|
496
517
|
|
|
497
518
|
/**
|
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 =
|
|
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) %
|
|
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
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
58
|
+
return total;
|
|
39
59
|
}
|
|
40
60
|
|
|
41
61
|
/** @internal */
|
|
42
|
-
function
|
|
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
|
|
87
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (4 + 1);
|
|
67
88
|
} else {
|
|
68
|
-
return
|
|
89
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
|
|
69
90
|
}
|
|
70
91
|
} else {
|
|
71
92
|
// 64 bit
|
|
72
|
-
return
|
|
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
|
|
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
|
|
108
|
+
return ByteUtils.utf8ByteLength(name) + 1 + 1;
|
|
89
109
|
} else if (value._bsontype === 'ObjectId') {
|
|
90
|
-
return
|
|
110
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (12 + 1);
|
|
91
111
|
} else if (value instanceof Date || isDate(value)) {
|
|
92
|
-
return
|
|
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
|
|
124
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
|
|
107
125
|
} else if (value._bsontype === 'Decimal128') {
|
|
108
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
193
|
-
|
|
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
|
-
|
|
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
|
|
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
|
}
|