bson 7.2.0 → 7.3.1
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 +453 -453
- package/lib/bson.bundle.js.map +1 -1
- package/lib/bson.cjs +453 -453
- package/lib/bson.cjs.map +1 -1
- package/lib/bson.mjs +453 -453
- package/lib/bson.mjs.map +1 -1
- package/lib/bson.node.mjs +453 -453
- package/lib/bson.node.mjs.map +1 -1
- package/lib/bson.rn.cjs +454 -456
- package/lib/bson.rn.cjs.map +1 -1
- package/package.json +4 -4
- package/src/binary.ts +2 -2
- package/src/bson.ts +0 -2
- package/src/extended_json.ts +33 -12
- package/src/long.ts +1 -1
- 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 +158 -4
package/lib/bson.rn.cjs
CHANGED
|
@@ -706,7 +706,7 @@ class Binary extends BSONValue {
|
|
|
706
706
|
!Array.isArray(buffer)) {
|
|
707
707
|
throw new BSONError('Binary can only be constructed from Uint8Array or number[]');
|
|
708
708
|
}
|
|
709
|
-
this.sub_type = subType ?? Binary.BSON_BINARY_SUBTYPE_DEFAULT;
|
|
709
|
+
this.sub_type = (subType ?? Binary.BSON_BINARY_SUBTYPE_DEFAULT) & 0xff;
|
|
710
710
|
if (buffer == null) {
|
|
711
711
|
this.buffer = ByteUtils.allocate(Binary.BUFFER_SIZE);
|
|
712
712
|
this.position = 0;
|
|
@@ -812,7 +812,7 @@ class Binary extends BSONValue {
|
|
|
812
812
|
if (this.sub_type === Binary.SUBTYPE_UUID) {
|
|
813
813
|
return new UUID(this.buffer.subarray(0, this.position));
|
|
814
814
|
}
|
|
815
|
-
throw new BSONError(`Binary sub_type "${this.sub_type}" is not supported for converting to UUID. Only
|
|
815
|
+
throw new BSONError(`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.`);
|
|
816
816
|
}
|
|
817
817
|
static createFromHexString(hex, subType) {
|
|
818
818
|
return new Binary(ByteUtils.fromHex(hex), subType);
|
|
@@ -1324,7 +1324,7 @@ class Long extends BSONValue {
|
|
|
1324
1324
|
}
|
|
1325
1325
|
if (value < 0)
|
|
1326
1326
|
return Long.fromNumber(-value, unsigned).neg();
|
|
1327
|
-
return Long.fromBits(value % TWO_PWR_32_DBL | 0, (value / TWO_PWR_32_DBL) | 0, unsigned);
|
|
1327
|
+
return Long.fromBits((value % TWO_PWR_32_DBL) | 0, (value / TWO_PWR_32_DBL) | 0, unsigned);
|
|
1328
1328
|
}
|
|
1329
1329
|
static fromBigInt(value, unsigned) {
|
|
1330
1330
|
const FROM_BIGINT_BIT_MASK = 0xffffffffn;
|
|
@@ -2601,13 +2601,24 @@ class MinKey extends BSONValue {
|
|
|
2601
2601
|
}
|
|
2602
2602
|
}
|
|
2603
2603
|
|
|
2604
|
-
let PROCESS_UNIQUE = null;
|
|
2605
2604
|
const __idCache = new WeakMap();
|
|
2606
2605
|
class ObjectId extends BSONValue {
|
|
2607
2606
|
get _bsontype() {
|
|
2608
2607
|
return 'ObjectId';
|
|
2609
2608
|
}
|
|
2610
|
-
static index =
|
|
2609
|
+
static index = 0;
|
|
2610
|
+
static PROCESS_UNIQUE = null;
|
|
2611
|
+
static resetState = () => {
|
|
2612
|
+
this.index = Math.floor(Math.random() * 0x1000000);
|
|
2613
|
+
this.PROCESS_UNIQUE = ByteUtils.randomBytes(5);
|
|
2614
|
+
};
|
|
2615
|
+
static {
|
|
2616
|
+
this.resetState();
|
|
2617
|
+
const { startupSnapshot } = globalThis?.process?.getBuiltinModule?.('v8') ?? {};
|
|
2618
|
+
if (startupSnapshot?.isBuildingSnapshot?.()) {
|
|
2619
|
+
startupSnapshot?.addDeserializeCallback?.(this.resetState);
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2611
2622
|
static cacheHexString;
|
|
2612
2623
|
buffer;
|
|
2613
2624
|
constructor(inputId) {
|
|
@@ -2684,7 +2695,7 @@ class ObjectId extends BSONValue {
|
|
|
2684
2695
|
return hexString;
|
|
2685
2696
|
}
|
|
2686
2697
|
static getInc() {
|
|
2687
|
-
return (ObjectId.index = (ObjectId.index + 1) %
|
|
2698
|
+
return (ObjectId.index = (ObjectId.index + 1) % 0x1000000);
|
|
2688
2699
|
}
|
|
2689
2700
|
static generate(time) {
|
|
2690
2701
|
if ('number' !== typeof time) {
|
|
@@ -2693,9 +2704,7 @@ class ObjectId extends BSONValue {
|
|
|
2693
2704
|
const inc = ObjectId.getInc();
|
|
2694
2705
|
const buffer = ByteUtils.allocateUnsafe(12);
|
|
2695
2706
|
NumberUtils.setInt32BE(buffer, 0, time);
|
|
2696
|
-
|
|
2697
|
-
PROCESS_UNIQUE = ByteUtils.randomBytes(5);
|
|
2698
|
-
}
|
|
2707
|
+
const PROCESS_UNIQUE = this.PROCESS_UNIQUE;
|
|
2699
2708
|
buffer[4] = PROCESS_UNIQUE[0];
|
|
2700
2709
|
buffer[5] = PROCESS_UNIQUE[1];
|
|
2701
2710
|
buffer[6] = PROCESS_UNIQUE[2];
|
|
@@ -2813,23 +2822,33 @@ class ObjectId extends BSONValue {
|
|
|
2813
2822
|
}
|
|
2814
2823
|
|
|
2815
2824
|
function internalCalculateObjectSize(object, serializeFunctions, ignoreUndefined) {
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
+
const objectStack = [
|
|
2826
|
+
{ obj: object, ignoreUndefined: ignoreUndefined ?? false }
|
|
2827
|
+
];
|
|
2828
|
+
let total = 0;
|
|
2829
|
+
while (objectStack.length > 0) {
|
|
2830
|
+
const { obj, ignoreUndefined: frameIgnoreUndefined } = objectStack.pop();
|
|
2831
|
+
total += 5;
|
|
2832
|
+
const isObjArray = Array.isArray(obj);
|
|
2833
|
+
let target = obj;
|
|
2834
|
+
if (!isObjArray && typeof obj?.toBSON === 'function') {
|
|
2835
|
+
target = obj.toBSON();
|
|
2836
|
+
}
|
|
2837
|
+
if (isObjArray) {
|
|
2838
|
+
const array = target;
|
|
2839
|
+
for (let i = 0; i < array.length; i++) {
|
|
2840
|
+
total += calculateElementSize(i.toString(), array[i], serializeFunctions, true, frameIgnoreUndefined, objectStack);
|
|
2841
|
+
}
|
|
2825
2842
|
}
|
|
2826
|
-
|
|
2827
|
-
|
|
2843
|
+
else {
|
|
2844
|
+
for (const key of Object.keys(target)) {
|
|
2845
|
+
total += calculateElementSize(key, target[key], serializeFunctions, false, frameIgnoreUndefined, objectStack);
|
|
2846
|
+
}
|
|
2828
2847
|
}
|
|
2829
2848
|
}
|
|
2830
|
-
return
|
|
2849
|
+
return total;
|
|
2831
2850
|
}
|
|
2832
|
-
function
|
|
2851
|
+
function calculateElementSize(name, value, serializeFunctions = false, isArray = false, ignoreUndefined = false, objectStack) {
|
|
2833
2852
|
if (typeof value?.toBSON === 'function') {
|
|
2834
2853
|
value = value.toBSON();
|
|
2835
2854
|
}
|
|
@@ -2841,21 +2860,21 @@ function calculateElement(name, value, serializeFunctions = false, isArray = fal
|
|
|
2841
2860
|
value >= JS_INT_MIN &&
|
|
2842
2861
|
value <= JS_INT_MAX) {
|
|
2843
2862
|
if (value >= BSON_INT32_MIN && value <= BSON_INT32_MAX) {
|
|
2844
|
-
return
|
|
2863
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (4 + 1);
|
|
2845
2864
|
}
|
|
2846
2865
|
else {
|
|
2847
|
-
return
|
|
2866
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
|
|
2848
2867
|
}
|
|
2849
2868
|
}
|
|
2850
2869
|
else {
|
|
2851
|
-
return
|
|
2870
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
|
|
2852
2871
|
}
|
|
2853
2872
|
case 'undefined':
|
|
2854
2873
|
if (isArray || !ignoreUndefined)
|
|
2855
|
-
return
|
|
2874
|
+
return ByteUtils.utf8ByteLength(name) + 1 + 1;
|
|
2856
2875
|
return 0;
|
|
2857
2876
|
case 'boolean':
|
|
2858
|
-
return
|
|
2877
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (1 + 1);
|
|
2859
2878
|
case 'object':
|
|
2860
2879
|
if (value != null &&
|
|
2861
2880
|
typeof value._bsontype === 'string' &&
|
|
@@ -2863,39 +2882,41 @@ function calculateElement(name, value, serializeFunctions = false, isArray = fal
|
|
|
2863
2882
|
throw new BSONVersionError();
|
|
2864
2883
|
}
|
|
2865
2884
|
else if (value == null || value._bsontype === 'MinKey' || value._bsontype === 'MaxKey') {
|
|
2866
|
-
return
|
|
2885
|
+
return ByteUtils.utf8ByteLength(name) + 1 + 1;
|
|
2867
2886
|
}
|
|
2868
2887
|
else if (value._bsontype === 'ObjectId') {
|
|
2869
|
-
return
|
|
2888
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (12 + 1);
|
|
2870
2889
|
}
|
|
2871
2890
|
else if (value instanceof Date || isDate(value)) {
|
|
2872
|
-
return
|
|
2891
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
|
|
2873
2892
|
}
|
|
2874
2893
|
else if (ArrayBuffer.isView(value) ||
|
|
2875
2894
|
value instanceof ArrayBuffer ||
|
|
2876
2895
|
isAnyArrayBuffer(value)) {
|
|
2877
|
-
return
|
|
2896
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (1 + 4 + 1) + value.byteLength;
|
|
2878
2897
|
}
|
|
2879
2898
|
else if (value._bsontype === 'Long' ||
|
|
2880
2899
|
value._bsontype === 'Double' ||
|
|
2881
2900
|
value._bsontype === 'Timestamp') {
|
|
2882
|
-
return
|
|
2901
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
|
|
2883
2902
|
}
|
|
2884
2903
|
else if (value._bsontype === 'Decimal128') {
|
|
2885
|
-
return
|
|
2904
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (16 + 1);
|
|
2886
2905
|
}
|
|
2887
2906
|
else if (value._bsontype === 'Code') {
|
|
2888
2907
|
if (value.scope != null && Object.keys(value.scope).length > 0) {
|
|
2889
|
-
|
|
2908
|
+
objectStack.push({ obj: value.scope, ignoreUndefined });
|
|
2909
|
+
return (ByteUtils.utf8ByteLength(name) +
|
|
2910
|
+
1 +
|
|
2890
2911
|
1 +
|
|
2891
2912
|
4 +
|
|
2892
2913
|
4 +
|
|
2893
2914
|
ByteUtils.utf8ByteLength(value.code.toString()) +
|
|
2894
|
-
1
|
|
2895
|
-
internalCalculateObjectSize(value.scope, serializeFunctions, ignoreUndefined));
|
|
2915
|
+
1);
|
|
2896
2916
|
}
|
|
2897
2917
|
else {
|
|
2898
|
-
return (
|
|
2918
|
+
return (ByteUtils.utf8ByteLength(name) +
|
|
2919
|
+
1 +
|
|
2899
2920
|
1 +
|
|
2900
2921
|
4 +
|
|
2901
2922
|
ByteUtils.utf8ByteLength(value.code.toString()) +
|
|
@@ -2905,19 +2926,14 @@ function calculateElement(name, value, serializeFunctions = false, isArray = fal
|
|
|
2905
2926
|
else if (value._bsontype === 'Binary') {
|
|
2906
2927
|
const binary = value;
|
|
2907
2928
|
if (binary.sub_type === Binary.SUBTYPE_BYTE_ARRAY) {
|
|
2908
|
-
return (
|
|
2909
|
-
(binary.position + 1 + 4 + 1 + 4));
|
|
2929
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (binary.position + 1 + 4 + 1 + 4);
|
|
2910
2930
|
}
|
|
2911
2931
|
else {
|
|
2912
|
-
return
|
|
2932
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (binary.position + 1 + 4 + 1);
|
|
2913
2933
|
}
|
|
2914
2934
|
}
|
|
2915
2935
|
else if (value._bsontype === 'Symbol') {
|
|
2916
|
-
return ((name
|
|
2917
|
-
ByteUtils.utf8ByteLength(value.value) +
|
|
2918
|
-
4 +
|
|
2919
|
-
1 +
|
|
2920
|
-
1);
|
|
2936
|
+
return (ByteUtils.utf8ByteLength(name) + 1 + ByteUtils.utf8ByteLength(value.value) + 4 + 1 + 1);
|
|
2921
2937
|
}
|
|
2922
2938
|
else if (value._bsontype === 'DBRef') {
|
|
2923
2939
|
const ordered_values = Object.assign({
|
|
@@ -2927,12 +2943,12 @@ function calculateElement(name, value, serializeFunctions = false, isArray = fal
|
|
|
2927
2943
|
if (value.db != null) {
|
|
2928
2944
|
ordered_values['$db'] = value.db;
|
|
2929
2945
|
}
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
internalCalculateObjectSize(ordered_values, serializeFunctions, ignoreUndefined));
|
|
2946
|
+
objectStack.push({ obj: ordered_values, ignoreUndefined: true });
|
|
2947
|
+
return ByteUtils.utf8ByteLength(name) + 1 + 1;
|
|
2933
2948
|
}
|
|
2934
2949
|
else if (value instanceof RegExp || isRegExp(value)) {
|
|
2935
|
-
return (
|
|
2950
|
+
return (ByteUtils.utf8ByteLength(name) +
|
|
2951
|
+
1 +
|
|
2936
2952
|
1 +
|
|
2937
2953
|
ByteUtils.utf8ByteLength(value.source) +
|
|
2938
2954
|
1 +
|
|
@@ -2942,7 +2958,8 @@ function calculateElement(name, value, serializeFunctions = false, isArray = fal
|
|
|
2942
2958
|
1);
|
|
2943
2959
|
}
|
|
2944
2960
|
else if (value._bsontype === 'BSONRegExp') {
|
|
2945
|
-
return (
|
|
2961
|
+
return (ByteUtils.utf8ByteLength(name) +
|
|
2962
|
+
1 +
|
|
2946
2963
|
1 +
|
|
2947
2964
|
ByteUtils.utf8ByteLength(value.pattern) +
|
|
2948
2965
|
1 +
|
|
@@ -2950,13 +2967,13 @@ function calculateElement(name, value, serializeFunctions = false, isArray = fal
|
|
|
2950
2967
|
1);
|
|
2951
2968
|
}
|
|
2952
2969
|
else {
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
1);
|
|
2970
|
+
objectStack.push({ obj: value, ignoreUndefined });
|
|
2971
|
+
return ByteUtils.utf8ByteLength(name) + 1 + 1;
|
|
2956
2972
|
}
|
|
2957
2973
|
case 'function':
|
|
2958
2974
|
if (serializeFunctions) {
|
|
2959
|
-
return (
|
|
2975
|
+
return (ByteUtils.utf8ByteLength(name) +
|
|
2976
|
+
1 +
|
|
2960
2977
|
1 +
|
|
2961
2978
|
4 +
|
|
2962
2979
|
ByteUtils.utf8ByteLength(value.toString()) +
|
|
@@ -2964,13 +2981,12 @@ function calculateElement(name, value, serializeFunctions = false, isArray = fal
|
|
|
2964
2981
|
}
|
|
2965
2982
|
return 0;
|
|
2966
2983
|
case 'bigint':
|
|
2967
|
-
return
|
|
2984
|
+
return ByteUtils.utf8ByteLength(name) + 1 + (8 + 1);
|
|
2968
2985
|
case 'symbol':
|
|
2969
2986
|
return 0;
|
|
2970
2987
|
default:
|
|
2971
2988
|
throw new BSONError(`Unrecognized JS type: ${typeof value}`);
|
|
2972
2989
|
}
|
|
2973
|
-
return 0;
|
|
2974
2990
|
}
|
|
2975
2991
|
|
|
2976
2992
|
function alphabetize(str) {
|
|
@@ -3181,7 +3197,28 @@ function internalDeserialize(buffer, options, isArray) {
|
|
|
3181
3197
|
return deserializeObject(buffer, index, options, isArray);
|
|
3182
3198
|
}
|
|
3183
3199
|
const allowedDBRefKeys = /^\$ref$|^\$id$|^\$db$/;
|
|
3200
|
+
function assignValue(dest, name, value) {
|
|
3201
|
+
if (name === '__proto__') {
|
|
3202
|
+
Object.defineProperty(dest, name, {
|
|
3203
|
+
value,
|
|
3204
|
+
writable: true,
|
|
3205
|
+
enumerable: true,
|
|
3206
|
+
configurable: true
|
|
3207
|
+
});
|
|
3208
|
+
}
|
|
3209
|
+
else {
|
|
3210
|
+
dest[name] = value;
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
function toPotentialDbRef(doc) {
|
|
3214
|
+
if (isDBRefLike(doc)) {
|
|
3215
|
+
const { $ref, $id, $db, ...fields } = doc;
|
|
3216
|
+
return new DBRef($ref, $id, $db, fields);
|
|
3217
|
+
}
|
|
3218
|
+
return doc;
|
|
3219
|
+
}
|
|
3184
3220
|
function deserializeObject(buffer, index, options, isArray = false) {
|
|
3221
|
+
options = { ...options };
|
|
3185
3222
|
const fieldsAsRaw = options['fieldsAsRaw'] == null ? null : options['fieldsAsRaw'];
|
|
3186
3223
|
const raw = options['raw'] == null ? false : options['raw'];
|
|
3187
3224
|
const bsonRegExp = typeof options['bsonRegExp'] === 'boolean' ? options['bsonRegExp'] : false;
|
|
@@ -3232,32 +3269,87 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
3232
3269
|
index += 4;
|
|
3233
3270
|
if (size < 5 || size > buffer.length)
|
|
3234
3271
|
throw new BSONError('corrupt bson message');
|
|
3235
|
-
const
|
|
3272
|
+
const rootObject = isArray ? [] : {};
|
|
3236
3273
|
let arrayIndex = 0;
|
|
3237
|
-
const done = false;
|
|
3238
3274
|
let isPossibleDBRef = isArray ? false : null;
|
|
3239
|
-
|
|
3275
|
+
let currentFrame = null;
|
|
3276
|
+
let currentDest = rootObject;
|
|
3277
|
+
let currentIsArray = isArray;
|
|
3278
|
+
while (true) {
|
|
3240
3279
|
const elementType = buffer[index++];
|
|
3241
|
-
if (elementType === 0)
|
|
3242
|
-
|
|
3280
|
+
if (elementType === 0) {
|
|
3281
|
+
if (currentFrame) {
|
|
3282
|
+
if (index === currentFrame.lastIndex) {
|
|
3283
|
+
const completedFrame = currentFrame;
|
|
3284
|
+
currentFrame = completedFrame.prev;
|
|
3285
|
+
if (currentFrame === null) {
|
|
3286
|
+
currentDest = rootObject;
|
|
3287
|
+
currentIsArray = isArray;
|
|
3288
|
+
}
|
|
3289
|
+
else {
|
|
3290
|
+
currentDest = currentFrame.holdingDocument;
|
|
3291
|
+
currentIsArray = currentFrame.isArray;
|
|
3292
|
+
}
|
|
3293
|
+
let result = completedFrame.holdingDocument;
|
|
3294
|
+
switch (completedFrame.elementType) {
|
|
3295
|
+
case BSON_DATA_OBJECT:
|
|
3296
|
+
if (completedFrame.isPossibleDBRef) {
|
|
3297
|
+
result = toPotentialDbRef(result);
|
|
3298
|
+
}
|
|
3299
|
+
break;
|
|
3300
|
+
case BSON_DATA_ARRAY:
|
|
3301
|
+
break;
|
|
3302
|
+
case BSON_DATA_CODE_W_SCOPE:
|
|
3303
|
+
result = new Code(completedFrame.functionString, completedFrame.holdingDocument);
|
|
3304
|
+
break;
|
|
3305
|
+
default:
|
|
3306
|
+
throw new BSONError('Unexpected element type in frame stack');
|
|
3307
|
+
}
|
|
3308
|
+
assignValue(currentDest, completedFrame.propertyName, result);
|
|
3309
|
+
continue;
|
|
3310
|
+
}
|
|
3311
|
+
else {
|
|
3312
|
+
if (currentFrame.elementType === BSON_DATA_ARRAY) {
|
|
3313
|
+
throw new BSONError('corrupted array bson');
|
|
3314
|
+
}
|
|
3315
|
+
throw new BSONError('Bad BSON Document: object not properly terminated');
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
else {
|
|
3319
|
+
break;
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3243
3322
|
let i = index;
|
|
3244
3323
|
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
3245
3324
|
i++;
|
|
3246
3325
|
}
|
|
3247
3326
|
if (i >= buffer.byteLength)
|
|
3248
3327
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
3249
|
-
const name =
|
|
3250
|
-
|
|
3251
|
-
|
|
3328
|
+
const name = currentIsArray
|
|
3329
|
+
? currentFrame !== null
|
|
3330
|
+
? currentFrame.arrayIndex++
|
|
3331
|
+
: arrayIndex++
|
|
3332
|
+
: ByteUtils.toUTF8(buffer, index, i, false);
|
|
3333
|
+
let shouldValidateKey;
|
|
3334
|
+
if (currentFrame !== null) {
|
|
3335
|
+
shouldValidateKey = currentFrame.validationSetting;
|
|
3336
|
+
}
|
|
3337
|
+
else if (globalUTFValidation || utf8KeysSet?.has(name)) {
|
|
3252
3338
|
shouldValidateKey = validationSetting;
|
|
3253
3339
|
}
|
|
3254
3340
|
else {
|
|
3255
3341
|
shouldValidateKey = !validationSetting;
|
|
3256
3342
|
}
|
|
3257
|
-
if (
|
|
3343
|
+
if (currentFrame !== null) {
|
|
3344
|
+
if (currentFrame.isPossibleDBRef !== false && typeof name === 'string' && name[0] === '$') {
|
|
3345
|
+
currentFrame.isPossibleDBRef = allowedDBRefKeys.test(name);
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
else if (isPossibleDBRef !== false && name[0] === '$') {
|
|
3258
3349
|
isPossibleDBRef = allowedDBRefKeys.test(name);
|
|
3259
3350
|
}
|
|
3260
3351
|
let value;
|
|
3352
|
+
let isDeferredValue = false;
|
|
3261
3353
|
index = i + 1;
|
|
3262
3354
|
if (elementType === BSON_DATA_STRING) {
|
|
3263
3355
|
const stringSize = NumberUtils.getInt32LE(buffer, index);
|
|
@@ -3303,39 +3395,58 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
3303
3395
|
value = buffer[index++] === 1;
|
|
3304
3396
|
}
|
|
3305
3397
|
else if (elementType === BSON_DATA_OBJECT) {
|
|
3306
|
-
const _index = index;
|
|
3307
3398
|
const objectSize = NumberUtils.getInt32LE(buffer, index);
|
|
3308
|
-
if (objectSize
|
|
3399
|
+
if (objectSize < 5 || objectSize > buffer.length - index)
|
|
3309
3400
|
throw new BSONError('bad embedded document length in bson');
|
|
3310
|
-
if (raw) {
|
|
3401
|
+
if (raw || (currentFrame?.raw ?? false)) {
|
|
3311
3402
|
value = buffer.subarray(index, index + objectSize);
|
|
3403
|
+
index = index + objectSize;
|
|
3312
3404
|
}
|
|
3313
3405
|
else {
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3406
|
+
isDeferredValue = true;
|
|
3407
|
+
const objectFrame = {
|
|
3408
|
+
holdingDocument: {},
|
|
3409
|
+
elementType: BSON_DATA_OBJECT,
|
|
3410
|
+
propertyName: name,
|
|
3411
|
+
functionString: null,
|
|
3412
|
+
lastIndex: index + objectSize,
|
|
3413
|
+
isArray: false,
|
|
3414
|
+
arrayIndex: 0,
|
|
3415
|
+
raw: false,
|
|
3416
|
+
isPossibleDBRef: null,
|
|
3417
|
+
validationSetting: shouldValidateKey,
|
|
3418
|
+
prev: currentFrame
|
|
3419
|
+
};
|
|
3420
|
+
currentFrame = objectFrame;
|
|
3421
|
+
currentDest = objectFrame.holdingDocument;
|
|
3422
|
+
currentIsArray = false;
|
|
3423
|
+
index = index + 4;
|
|
3319
3424
|
}
|
|
3320
|
-
index = index + objectSize;
|
|
3321
3425
|
}
|
|
3322
3426
|
else if (elementType === BSON_DATA_ARRAY) {
|
|
3323
|
-
const _index = index;
|
|
3324
3427
|
const objectSize = NumberUtils.getInt32LE(buffer, index);
|
|
3325
|
-
|
|
3428
|
+
if (objectSize < 5 || objectSize > buffer.length - index)
|
|
3429
|
+
throw new BSONError('bad embedded array length in bson');
|
|
3326
3430
|
const stopIndex = index + objectSize;
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3431
|
+
const arrayRaw = !!(fieldsAsRaw && fieldsAsRaw[name]) || (currentFrame?.raw ?? false);
|
|
3432
|
+
isDeferredValue = true;
|
|
3433
|
+
const arrayFrame = {
|
|
3434
|
+
holdingDocument: [],
|
|
3435
|
+
elementType: BSON_DATA_ARRAY,
|
|
3436
|
+
propertyName: name,
|
|
3437
|
+
functionString: null,
|
|
3438
|
+
lastIndex: stopIndex,
|
|
3439
|
+
isArray: true,
|
|
3440
|
+
arrayIndex: 0,
|
|
3441
|
+
raw: arrayRaw,
|
|
3442
|
+
isPossibleDBRef: false,
|
|
3443
|
+
validationSetting: shouldValidateKey,
|
|
3444
|
+
prev: currentFrame
|
|
3445
|
+
};
|
|
3446
|
+
currentFrame = arrayFrame;
|
|
3447
|
+
currentDest = arrayFrame.holdingDocument;
|
|
3448
|
+
currentIsArray = true;
|
|
3449
|
+
index = index + 4;
|
|
3339
3450
|
}
|
|
3340
3451
|
else if (elementType === BSON_DATA_UNDEFINED) {
|
|
3341
3452
|
value = undefined;
|
|
@@ -3507,15 +3618,32 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
3507
3618
|
index = index + stringSize;
|
|
3508
3619
|
const _index = index;
|
|
3509
3620
|
const objectSize = NumberUtils.getInt32LE(buffer, index);
|
|
3510
|
-
|
|
3511
|
-
|
|
3621
|
+
if (objectSize < 5 || objectSize > buffer.length - index)
|
|
3622
|
+
throw new BSONError('bad scope document size in code_w_scope');
|
|
3512
3623
|
if (totalSize < 4 + 4 + objectSize + stringSize) {
|
|
3513
3624
|
throw new BSONError('code_w_scope total size is too short, truncating scope');
|
|
3514
3625
|
}
|
|
3515
3626
|
if (totalSize > 4 + 4 + objectSize + stringSize) {
|
|
3516
3627
|
throw new BSONError('code_w_scope total size is too long, clips outer document');
|
|
3517
3628
|
}
|
|
3518
|
-
|
|
3629
|
+
isDeferredValue = true;
|
|
3630
|
+
const scopeFrame = {
|
|
3631
|
+
holdingDocument: {},
|
|
3632
|
+
elementType: BSON_DATA_CODE_W_SCOPE,
|
|
3633
|
+
propertyName: name,
|
|
3634
|
+
functionString: functionString,
|
|
3635
|
+
lastIndex: _index + objectSize,
|
|
3636
|
+
isArray: false,
|
|
3637
|
+
arrayIndex: 0,
|
|
3638
|
+
raw: false,
|
|
3639
|
+
isPossibleDBRef: null,
|
|
3640
|
+
validationSetting: shouldValidateKey,
|
|
3641
|
+
prev: currentFrame
|
|
3642
|
+
};
|
|
3643
|
+
currentFrame = scopeFrame;
|
|
3644
|
+
currentDest = scopeFrame.holdingDocument;
|
|
3645
|
+
currentIsArray = false;
|
|
3646
|
+
index = index + 4;
|
|
3519
3647
|
}
|
|
3520
3648
|
else if (elementType === BSON_DATA_DBPOINTER) {
|
|
3521
3649
|
const stringSize = NumberUtils.getInt32LE(buffer, index);
|
|
@@ -3536,18 +3664,14 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
3536
3664
|
else {
|
|
3537
3665
|
throw new BSONError(`Detected unknown BSON type ${elementType.toString(16)} for fieldname "${name}"`);
|
|
3538
3666
|
}
|
|
3539
|
-
if (
|
|
3540
|
-
|
|
3541
|
-
value,
|
|
3542
|
-
writable: true,
|
|
3543
|
-
enumerable: true,
|
|
3544
|
-
configurable: true
|
|
3545
|
-
});
|
|
3546
|
-
}
|
|
3547
|
-
else {
|
|
3548
|
-
object[name] = value;
|
|
3667
|
+
if (!isDeferredValue) {
|
|
3668
|
+
assignValue(currentDest, name, value);
|
|
3549
3669
|
}
|
|
3550
3670
|
}
|
|
3671
|
+
if (currentFrame !== null) {
|
|
3672
|
+
throw new BSONError('corrupted bson, more objects expected based on the current document size');
|
|
3673
|
+
}
|
|
3674
|
+
const object = rootObject;
|
|
3551
3675
|
if (size !== index - startIndex) {
|
|
3552
3676
|
if (isArray)
|
|
3553
3677
|
throw new BSONError('corrupt array bson');
|
|
@@ -3555,14 +3679,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
3555
3679
|
}
|
|
3556
3680
|
if (!isPossibleDBRef)
|
|
3557
3681
|
return object;
|
|
3558
|
-
|
|
3559
|
-
const copy = Object.assign({}, object);
|
|
3560
|
-
delete copy.$ref;
|
|
3561
|
-
delete copy.$id;
|
|
3562
|
-
delete copy.$db;
|
|
3563
|
-
return new DBRef(object.$ref, object.$id, object.$db, copy);
|
|
3564
|
-
}
|
|
3565
|
-
return object;
|
|
3682
|
+
return toPotentialDbRef(object);
|
|
3566
3683
|
}
|
|
3567
3684
|
|
|
3568
3685
|
const regexp = /\x00/;
|
|
@@ -3671,7 +3788,7 @@ function serializeMinMax(buffer, key, value, index) {
|
|
|
3671
3788
|
if (value === null) {
|
|
3672
3789
|
buffer[index++] = BSON_DATA_NULL;
|
|
3673
3790
|
}
|
|
3674
|
-
else if (value
|
|
3791
|
+
else if (value[bsonType] === 'MinKey') {
|
|
3675
3792
|
buffer[index++] = BSON_DATA_MIN_KEY;
|
|
3676
3793
|
}
|
|
3677
3794
|
else {
|
|
@@ -3708,19 +3825,6 @@ function serializeBuffer(buffer, key, value, index) {
|
|
|
3708
3825
|
index = index + size;
|
|
3709
3826
|
return index;
|
|
3710
3827
|
}
|
|
3711
|
-
function serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, path) {
|
|
3712
|
-
if (path.has(value)) {
|
|
3713
|
-
throw new BSONError('Cannot convert circular structure to BSON');
|
|
3714
|
-
}
|
|
3715
|
-
path.add(value);
|
|
3716
|
-
buffer[index++] = Array.isArray(value) ? BSON_DATA_ARRAY : BSON_DATA_OBJECT;
|
|
3717
|
-
const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
|
|
3718
|
-
index = index + numberOfWrittenBytes;
|
|
3719
|
-
buffer[index++] = 0;
|
|
3720
|
-
const endIndex = serializeInto(buffer, value, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined, path);
|
|
3721
|
-
path.delete(value);
|
|
3722
|
-
return endIndex;
|
|
3723
|
-
}
|
|
3724
3828
|
function serializeDecimal128(buffer, key, value, index) {
|
|
3725
3829
|
buffer[index++] = BSON_DATA_DECIMAL128;
|
|
3726
3830
|
const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
|
|
@@ -3732,7 +3836,7 @@ function serializeDecimal128(buffer, key, value, index) {
|
|
|
3732
3836
|
}
|
|
3733
3837
|
function serializeLong(buffer, key, value, index) {
|
|
3734
3838
|
buffer[index++] =
|
|
3735
|
-
value
|
|
3839
|
+
value[bsonType] === 'Long' ? BSON_DATA_LONG : BSON_DATA_TIMESTAMP;
|
|
3736
3840
|
const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
|
|
3737
3841
|
index = index + numberOfWrittenBytes;
|
|
3738
3842
|
buffer[index++] = 0;
|
|
@@ -3771,38 +3875,6 @@ function serializeFunction(buffer, key, value, index) {
|
|
|
3771
3875
|
buffer[index++] = 0;
|
|
3772
3876
|
return index;
|
|
3773
3877
|
}
|
|
3774
|
-
function serializeCode(buffer, key, value, index, checkKeys = false, depth = 0, serializeFunctions = false, ignoreUndefined = true, path) {
|
|
3775
|
-
if (value.scope && typeof value.scope === 'object') {
|
|
3776
|
-
buffer[index++] = BSON_DATA_CODE_W_SCOPE;
|
|
3777
|
-
const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
|
|
3778
|
-
index = index + numberOfWrittenBytes;
|
|
3779
|
-
buffer[index++] = 0;
|
|
3780
|
-
let startIndex = index;
|
|
3781
|
-
const functionString = value.code;
|
|
3782
|
-
index = index + 4;
|
|
3783
|
-
const codeSize = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
|
|
3784
|
-
NumberUtils.setInt32LE(buffer, index, codeSize);
|
|
3785
|
-
buffer[index + 4 + codeSize - 1] = 0;
|
|
3786
|
-
index = index + codeSize + 4;
|
|
3787
|
-
const endIndex = serializeInto(buffer, value.scope, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined, path);
|
|
3788
|
-
index = endIndex - 1;
|
|
3789
|
-
const totalSize = endIndex - startIndex;
|
|
3790
|
-
startIndex += NumberUtils.setInt32LE(buffer, startIndex, totalSize);
|
|
3791
|
-
buffer[index++] = 0;
|
|
3792
|
-
}
|
|
3793
|
-
else {
|
|
3794
|
-
buffer[index++] = BSON_DATA_CODE;
|
|
3795
|
-
const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
|
|
3796
|
-
index = index + numberOfWrittenBytes;
|
|
3797
|
-
buffer[index++] = 0;
|
|
3798
|
-
const functionString = value.code.toString();
|
|
3799
|
-
const size = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
|
|
3800
|
-
NumberUtils.setInt32LE(buffer, index, size);
|
|
3801
|
-
index = index + 4 + size - 1;
|
|
3802
|
-
buffer[index++] = 0;
|
|
3803
|
-
}
|
|
3804
|
-
return index;
|
|
3805
|
-
}
|
|
3806
3878
|
function serializeBinary(buffer, key, value, index) {
|
|
3807
3879
|
buffer[index++] = BSON_DATA_BINARY;
|
|
3808
3880
|
const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
|
|
@@ -3842,26 +3914,59 @@ function serializeSymbol(buffer, key, value, index) {
|
|
|
3842
3914
|
buffer[index++] = 0;
|
|
3843
3915
|
return index;
|
|
3844
3916
|
}
|
|
3845
|
-
function
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3917
|
+
function makeFrame(sourceObject, objectSizeIndex, codeSizeIndex, prev, checkKeys, ignoreUndefined) {
|
|
3918
|
+
if (Array.isArray(sourceObject)) {
|
|
3919
|
+
return {
|
|
3920
|
+
sourceObject,
|
|
3921
|
+
isArray: true,
|
|
3922
|
+
objectSizeIndex,
|
|
3923
|
+
codeSizeIndex,
|
|
3924
|
+
iterTarget: sourceObject,
|
|
3925
|
+
keys: null,
|
|
3926
|
+
keyIndex: 0,
|
|
3927
|
+
mapIterator: null,
|
|
3928
|
+
prev,
|
|
3929
|
+
checkKeys,
|
|
3930
|
+
ignoreUndefined
|
|
3931
|
+
};
|
|
3932
|
+
}
|
|
3933
|
+
if (sourceObject instanceof Map || isMap(sourceObject)) {
|
|
3934
|
+
return {
|
|
3935
|
+
sourceObject,
|
|
3936
|
+
isArray: false,
|
|
3937
|
+
objectSizeIndex,
|
|
3938
|
+
codeSizeIndex,
|
|
3939
|
+
iterTarget: sourceObject,
|
|
3940
|
+
keys: null,
|
|
3941
|
+
keyIndex: 0,
|
|
3942
|
+
mapIterator: sourceObject.entries(),
|
|
3943
|
+
prev,
|
|
3944
|
+
checkKeys,
|
|
3945
|
+
ignoreUndefined
|
|
3946
|
+
};
|
|
3947
|
+
}
|
|
3948
|
+
let target = sourceObject;
|
|
3949
|
+
if (typeof target?.toBSON === 'function') {
|
|
3950
|
+
target = target.toBSON();
|
|
3951
|
+
if (target != null && typeof target !== 'object') {
|
|
3952
|
+
throw new BSONError('toBSON function did not return an object');
|
|
3953
|
+
}
|
|
3954
|
+
}
|
|
3955
|
+
return {
|
|
3956
|
+
sourceObject,
|
|
3957
|
+
isArray: false,
|
|
3958
|
+
objectSizeIndex,
|
|
3959
|
+
codeSizeIndex,
|
|
3960
|
+
iterTarget: target,
|
|
3961
|
+
keys: Object.keys(target),
|
|
3962
|
+
keyIndex: 0,
|
|
3963
|
+
mapIterator: null,
|
|
3964
|
+
prev,
|
|
3965
|
+
checkKeys,
|
|
3966
|
+
ignoreUndefined
|
|
3854
3967
|
};
|
|
3855
|
-
if (value.db != null) {
|
|
3856
|
-
output.$db = value.db;
|
|
3857
|
-
}
|
|
3858
|
-
output = Object.assign(output, value.fields);
|
|
3859
|
-
const endIndex = serializeInto(buffer, output, false, index, depth + 1, serializeFunctions, true, path);
|
|
3860
|
-
const size = endIndex - startIndex;
|
|
3861
|
-
startIndex += NumberUtils.setInt32LE(buffer, index, size);
|
|
3862
|
-
return endIndex;
|
|
3863
3968
|
}
|
|
3864
|
-
function serializeInto(buffer, object, checkKeys, startingIndex,
|
|
3969
|
+
function serializeInto(buffer, object, checkKeys, startingIndex, serializeFunctions, ignoreUndefined, path) {
|
|
3865
3970
|
if (path == null) {
|
|
3866
3971
|
if (object == null) {
|
|
3867
3972
|
buffer[0] = 0x05;
|
|
@@ -3889,308 +3994,200 @@ function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializ
|
|
|
3889
3994
|
path = new Set();
|
|
3890
3995
|
}
|
|
3891
3996
|
path.add(object);
|
|
3997
|
+
let currentFrame = makeFrame(object, startingIndex, null, null, checkKeys, ignoreUndefined);
|
|
3892
3998
|
let index = startingIndex + 4;
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
else if (value === null) {
|
|
3905
|
-
index = serializeNull(buffer, key, value, index);
|
|
3906
|
-
}
|
|
3907
|
-
else if (type === 'string') {
|
|
3908
|
-
index = serializeString(buffer, key, value, index);
|
|
3909
|
-
}
|
|
3910
|
-
else if (type === 'number') {
|
|
3911
|
-
index = serializeNumber(buffer, key, value, index);
|
|
3912
|
-
}
|
|
3913
|
-
else if (type === 'bigint') {
|
|
3914
|
-
index = serializeBigInt(buffer, key, value, index);
|
|
3915
|
-
}
|
|
3916
|
-
else if (type === 'boolean') {
|
|
3917
|
-
index = serializeBoolean(buffer, key, value, index);
|
|
3918
|
-
}
|
|
3919
|
-
else if (type === 'object' && value._bsontype == null) {
|
|
3920
|
-
if (value instanceof Date || isDate(value)) {
|
|
3921
|
-
index = serializeDate(buffer, key, value, index);
|
|
3922
|
-
}
|
|
3923
|
-
else if (value instanceof Uint8Array || isUint8Array(value)) {
|
|
3924
|
-
index = serializeBuffer(buffer, key, value, index);
|
|
3925
|
-
}
|
|
3926
|
-
else if (value instanceof RegExp || isRegExp(value)) {
|
|
3927
|
-
index = serializeRegExp(buffer, key, value, index);
|
|
3928
|
-
}
|
|
3929
|
-
else {
|
|
3930
|
-
index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, path);
|
|
3999
|
+
while (currentFrame !== null) {
|
|
4000
|
+
const frame = currentFrame;
|
|
4001
|
+
let key;
|
|
4002
|
+
let value;
|
|
4003
|
+
if (frame.mapIterator !== null) {
|
|
4004
|
+
const next = frame.mapIterator.next();
|
|
4005
|
+
if (next.done) {
|
|
4006
|
+
buffer[index++] = 0x00;
|
|
4007
|
+
NumberUtils.setInt32LE(buffer, frame.objectSizeIndex, index - frame.objectSizeIndex);
|
|
4008
|
+
if (frame.codeSizeIndex !== null) {
|
|
4009
|
+
NumberUtils.setInt32LE(buffer, frame.codeSizeIndex, index - frame.codeSizeIndex);
|
|
3931
4010
|
}
|
|
4011
|
+
path.delete(frame.sourceObject);
|
|
4012
|
+
currentFrame = frame.prev;
|
|
4013
|
+
continue;
|
|
3932
4014
|
}
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
}
|
|
3943
|
-
else if (value._bsontype === 'Long' || value._bsontype === 'Timestamp') {
|
|
3944
|
-
index = serializeLong(buffer, key, value, index);
|
|
3945
|
-
}
|
|
3946
|
-
else if (value._bsontype === 'Double') {
|
|
3947
|
-
index = serializeDouble(buffer, key, value, index);
|
|
3948
|
-
}
|
|
3949
|
-
else if (value._bsontype === 'Code') {
|
|
3950
|
-
index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, path);
|
|
3951
|
-
}
|
|
3952
|
-
else if (value._bsontype === 'Binary') {
|
|
3953
|
-
index = serializeBinary(buffer, key, value, index);
|
|
3954
|
-
}
|
|
3955
|
-
else if (value._bsontype === 'BSONSymbol') {
|
|
3956
|
-
index = serializeSymbol(buffer, key, value, index);
|
|
3957
|
-
}
|
|
3958
|
-
else if (value._bsontype === 'DBRef') {
|
|
3959
|
-
index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions, path);
|
|
3960
|
-
}
|
|
3961
|
-
else if (value._bsontype === 'BSONRegExp') {
|
|
3962
|
-
index = serializeBSONRegExp(buffer, key, value, index);
|
|
3963
|
-
}
|
|
3964
|
-
else if (value._bsontype === 'Int32') {
|
|
3965
|
-
index = serializeInt32(buffer, key, value, index);
|
|
3966
|
-
}
|
|
3967
|
-
else if (value._bsontype === 'MinKey' || value._bsontype === 'MaxKey') {
|
|
3968
|
-
index = serializeMinMax(buffer, key, value, index);
|
|
3969
|
-
}
|
|
3970
|
-
else if (typeof value._bsontype !== 'undefined') {
|
|
3971
|
-
throw new BSONError(`Unrecognized or invalid _bsontype: ${String(value._bsontype)}`);
|
|
4015
|
+
key = next.value[0];
|
|
4016
|
+
value = next.value[1];
|
|
4017
|
+
}
|
|
4018
|
+
else if (frame.keys !== null) {
|
|
4019
|
+
if (frame.keyIndex >= frame.keys.length) {
|
|
4020
|
+
buffer[index++] = 0x00;
|
|
4021
|
+
NumberUtils.setInt32LE(buffer, frame.objectSizeIndex, index - frame.objectSizeIndex);
|
|
4022
|
+
if (frame.codeSizeIndex !== null) {
|
|
4023
|
+
NumberUtils.setInt32LE(buffer, frame.codeSizeIndex, index - frame.codeSizeIndex);
|
|
3972
4024
|
}
|
|
4025
|
+
path.delete(frame.sourceObject);
|
|
4026
|
+
currentFrame = frame.prev;
|
|
4027
|
+
continue;
|
|
3973
4028
|
}
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
}
|
|
4029
|
+
key = frame.keys[frame.keyIndex++];
|
|
4030
|
+
value = frame.iterTarget[key];
|
|
3977
4031
|
}
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
4032
|
+
else {
|
|
4033
|
+
const arr = frame.iterTarget;
|
|
4034
|
+
if (frame.keyIndex >= arr.length) {
|
|
4035
|
+
buffer[index++] = 0x00;
|
|
4036
|
+
NumberUtils.setInt32LE(buffer, frame.objectSizeIndex, index - frame.objectSizeIndex);
|
|
4037
|
+
if (frame.codeSizeIndex !== null) {
|
|
4038
|
+
NumberUtils.setInt32LE(buffer, frame.codeSizeIndex, index - frame.codeSizeIndex);
|
|
4039
|
+
}
|
|
4040
|
+
path.delete(frame.sourceObject);
|
|
4041
|
+
currentFrame = frame.prev;
|
|
3986
4042
|
continue;
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
4043
|
+
}
|
|
4044
|
+
const i = frame.keyIndex++;
|
|
4045
|
+
key = String(i);
|
|
4046
|
+
value = arr[i];
|
|
4047
|
+
}
|
|
4048
|
+
if (typeof value?.toBSON === 'function') {
|
|
4049
|
+
value = value.toBSON();
|
|
4050
|
+
}
|
|
4051
|
+
if (!frame.isArray && typeof key === 'string' && !(key[0] === '$' && ignoreKeys.has(key))) {
|
|
4052
|
+
if (regexp.test(key)) {
|
|
4053
|
+
throw new BSONError('key ' + key + ' must not contain null bytes');
|
|
4054
|
+
}
|
|
4055
|
+
if (frame.checkKeys) {
|
|
4056
|
+
if ('$' === key[0]) {
|
|
4057
|
+
throw new BSONError('key ' + key + " must not start with '$'");
|
|
3996
4058
|
}
|
|
3997
|
-
if (
|
|
3998
|
-
|
|
3999
|
-
throw new BSONError('key ' + key + " must not start with '$'");
|
|
4000
|
-
}
|
|
4001
|
-
else if (key.includes('.')) {
|
|
4002
|
-
throw new BSONError('key ' + key + " must not contain '.'");
|
|
4003
|
-
}
|
|
4059
|
+
else if (key.includes('.')) {
|
|
4060
|
+
throw new BSONError('key ' + key + " must not contain '.'");
|
|
4004
4061
|
}
|
|
4005
4062
|
}
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
else if (value === null) {
|
|
4063
|
+
}
|
|
4064
|
+
const type = typeof value;
|
|
4065
|
+
if (value === undefined) {
|
|
4066
|
+
if (frame.isArray || frame.ignoreUndefined === false) {
|
|
4011
4067
|
index = serializeNull(buffer, key, value, index);
|
|
4012
4068
|
}
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4069
|
+
}
|
|
4070
|
+
else if (value === null) {
|
|
4071
|
+
index = serializeNull(buffer, key, value, index);
|
|
4072
|
+
}
|
|
4073
|
+
else if (type === 'string') {
|
|
4074
|
+
index = serializeString(buffer, key, value, index);
|
|
4075
|
+
}
|
|
4076
|
+
else if (type === 'number') {
|
|
4077
|
+
index = serializeNumber(buffer, key, value, index);
|
|
4078
|
+
}
|
|
4079
|
+
else if (type === 'bigint') {
|
|
4080
|
+
index = serializeBigInt(buffer, key, value, index);
|
|
4081
|
+
}
|
|
4082
|
+
else if (type === 'boolean') {
|
|
4083
|
+
index = serializeBoolean(buffer, key, value, index);
|
|
4084
|
+
}
|
|
4085
|
+
else if (type === 'object' && value._bsontype == null) {
|
|
4086
|
+
if (value instanceof Date || isDate(value)) {
|
|
4087
|
+
index = serializeDate(buffer, key, value, index);
|
|
4021
4088
|
}
|
|
4022
|
-
else if (
|
|
4023
|
-
index =
|
|
4089
|
+
else if (value instanceof Uint8Array || isUint8Array(value)) {
|
|
4090
|
+
index = serializeBuffer(buffer, key, value, index);
|
|
4024
4091
|
}
|
|
4025
|
-
else if (
|
|
4026
|
-
|
|
4027
|
-
index = serializeDate(buffer, key, value, index);
|
|
4028
|
-
}
|
|
4029
|
-
else if (value instanceof Uint8Array || isUint8Array(value)) {
|
|
4030
|
-
index = serializeBuffer(buffer, key, value, index);
|
|
4031
|
-
}
|
|
4032
|
-
else if (value instanceof RegExp || isRegExp(value)) {
|
|
4033
|
-
index = serializeRegExp(buffer, key, value, index);
|
|
4034
|
-
}
|
|
4035
|
-
else {
|
|
4036
|
-
index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, path);
|
|
4037
|
-
}
|
|
4092
|
+
else if (value instanceof RegExp || isRegExp(value)) {
|
|
4093
|
+
index = serializeRegExp(buffer, key, value, index);
|
|
4038
4094
|
}
|
|
4039
|
-
else
|
|
4040
|
-
if (value
|
|
4041
|
-
throw new
|
|
4042
|
-
}
|
|
4043
|
-
else if (value._bsontype === 'ObjectId') {
|
|
4044
|
-
index = serializeObjectId(buffer, key, value, index);
|
|
4045
|
-
}
|
|
4046
|
-
else if (value._bsontype === 'Decimal128') {
|
|
4047
|
-
index = serializeDecimal128(buffer, key, value, index);
|
|
4048
|
-
}
|
|
4049
|
-
else if (value._bsontype === 'Long' || value._bsontype === 'Timestamp') {
|
|
4050
|
-
index = serializeLong(buffer, key, value, index);
|
|
4051
|
-
}
|
|
4052
|
-
else if (value._bsontype === 'Double') {
|
|
4053
|
-
index = serializeDouble(buffer, key, value, index);
|
|
4054
|
-
}
|
|
4055
|
-
else if (value._bsontype === 'Code') {
|
|
4056
|
-
index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, path);
|
|
4057
|
-
}
|
|
4058
|
-
else if (value._bsontype === 'Binary') {
|
|
4059
|
-
index = serializeBinary(buffer, key, value, index);
|
|
4060
|
-
}
|
|
4061
|
-
else if (value._bsontype === 'BSONSymbol') {
|
|
4062
|
-
index = serializeSymbol(buffer, key, value, index);
|
|
4063
|
-
}
|
|
4064
|
-
else if (value._bsontype === 'DBRef') {
|
|
4065
|
-
index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions, path);
|
|
4066
|
-
}
|
|
4067
|
-
else if (value._bsontype === 'BSONRegExp') {
|
|
4068
|
-
index = serializeBSONRegExp(buffer, key, value, index);
|
|
4069
|
-
}
|
|
4070
|
-
else if (value._bsontype === 'Int32') {
|
|
4071
|
-
index = serializeInt32(buffer, key, value, index);
|
|
4072
|
-
}
|
|
4073
|
-
else if (value._bsontype === 'MinKey' || value._bsontype === 'MaxKey') {
|
|
4074
|
-
index = serializeMinMax(buffer, key, value, index);
|
|
4075
|
-
}
|
|
4076
|
-
else if (typeof value._bsontype !== 'undefined') {
|
|
4077
|
-
throw new BSONError(`Unrecognized or invalid _bsontype: ${String(value._bsontype)}`);
|
|
4095
|
+
else {
|
|
4096
|
+
if (path.has(value)) {
|
|
4097
|
+
throw new BSONError('Cannot convert circular structure to BSON');
|
|
4078
4098
|
}
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
index
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
object = object.toBSON();
|
|
4088
|
-
if (object != null && typeof object !== 'object') {
|
|
4089
|
-
throw new BSONError('toBSON function did not return an object');
|
|
4099
|
+
const nestedIsArray = Array.isArray(value);
|
|
4100
|
+
buffer[index++] = nestedIsArray ? BSON_DATA_ARRAY : BSON_DATA_OBJECT;
|
|
4101
|
+
index += ByteUtils.encodeUTF8Into(buffer, key, index);
|
|
4102
|
+
buffer[index++] = 0x00;
|
|
4103
|
+
const nestedStartIndex = index;
|
|
4104
|
+
path.add(value);
|
|
4105
|
+
currentFrame = makeFrame(value, nestedStartIndex, null, frame, frame.checkKeys, frame.ignoreUndefined);
|
|
4106
|
+
index += 4;
|
|
4090
4107
|
}
|
|
4091
4108
|
}
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
value = value.toBSON();
|
|
4109
|
+
else if (type === 'object') {
|
|
4110
|
+
if (value[BSON_VERSION_SYMBOL] !== BSON_MAJOR_VERSION) {
|
|
4111
|
+
throw new BSONVersionError();
|
|
4096
4112
|
}
|
|
4097
|
-
const
|
|
4098
|
-
if (
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4113
|
+
const tag = value[bsonType];
|
|
4114
|
+
if (tag === 'ObjectId') {
|
|
4115
|
+
index = serializeObjectId(buffer, key, value, index);
|
|
4116
|
+
}
|
|
4117
|
+
else if (tag === 'Decimal128') {
|
|
4118
|
+
index = serializeDecimal128(buffer, key, value, index);
|
|
4119
|
+
}
|
|
4120
|
+
else if (tag === 'Long' || tag === 'Timestamp') {
|
|
4121
|
+
index = serializeLong(buffer, key, value, index);
|
|
4122
|
+
}
|
|
4123
|
+
else if (tag === 'Double') {
|
|
4124
|
+
index = serializeDouble(buffer, key, value, index);
|
|
4125
|
+
}
|
|
4126
|
+
else if (tag === 'Code') {
|
|
4127
|
+
const codeValue = value;
|
|
4128
|
+
if (codeValue.scope && typeof codeValue.scope === 'object') {
|
|
4129
|
+
buffer[index++] = BSON_DATA_CODE_W_SCOPE;
|
|
4130
|
+
index += ByteUtils.encodeUTF8Into(buffer, key, index);
|
|
4131
|
+
buffer[index++] = 0x00;
|
|
4132
|
+
const codeTotalSizeIndex = index;
|
|
4133
|
+
index += 4;
|
|
4134
|
+
const functionString = codeValue.code;
|
|
4135
|
+
const codeSize = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
|
|
4136
|
+
NumberUtils.setInt32LE(buffer, index, codeSize);
|
|
4137
|
+
buffer[index + 4 + codeSize - 1] = 0;
|
|
4138
|
+
index = index + codeSize + 4;
|
|
4139
|
+
const scope = codeValue.scope;
|
|
4140
|
+
if (path.has(scope)) {
|
|
4141
|
+
throw new BSONError('Cannot convert circular structure to BSON');
|
|
4108
4142
|
}
|
|
4143
|
+
path.add(scope);
|
|
4144
|
+
currentFrame = makeFrame(scope, index, codeTotalSizeIndex, frame, frame.checkKeys, frame.ignoreUndefined);
|
|
4145
|
+
index += 4;
|
|
4146
|
+
}
|
|
4147
|
+
else {
|
|
4148
|
+
buffer[index++] = BSON_DATA_CODE;
|
|
4149
|
+
index += ByteUtils.encodeUTF8Into(buffer, key, index);
|
|
4150
|
+
buffer[index++] = 0x00;
|
|
4151
|
+
const functionString = codeValue.code.toString();
|
|
4152
|
+
const size = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
|
|
4153
|
+
NumberUtils.setInt32LE(buffer, index, size);
|
|
4154
|
+
index = index + 4 + size - 1;
|
|
4155
|
+
buffer[index++] = 0;
|
|
4109
4156
|
}
|
|
4110
4157
|
}
|
|
4111
|
-
if (
|
|
4112
|
-
|
|
4113
|
-
index = serializeNull(buffer, key, value, index);
|
|
4114
|
-
}
|
|
4115
|
-
else if (value === null) {
|
|
4116
|
-
index = serializeNull(buffer, key, value, index);
|
|
4117
|
-
}
|
|
4118
|
-
else if (type === 'string') {
|
|
4119
|
-
index = serializeString(buffer, key, value, index);
|
|
4158
|
+
else if (tag === 'Binary') {
|
|
4159
|
+
index = serializeBinary(buffer, key, value, index);
|
|
4120
4160
|
}
|
|
4121
|
-
else if (
|
|
4122
|
-
index =
|
|
4161
|
+
else if (tag === 'BSONSymbol') {
|
|
4162
|
+
index = serializeSymbol(buffer, key, value, index);
|
|
4123
4163
|
}
|
|
4124
|
-
else if (
|
|
4125
|
-
|
|
4164
|
+
else if (tag === 'DBRef') {
|
|
4165
|
+
const dbref = value;
|
|
4166
|
+
const orderedValues = Object.assign({ $ref: dbref.collection, $id: dbref.oid }, dbref.db != null ? { $db: dbref.db } : null, dbref.fields);
|
|
4167
|
+
buffer[index++] = BSON_DATA_OBJECT;
|
|
4168
|
+
index += ByteUtils.encodeUTF8Into(buffer, key, index);
|
|
4169
|
+
buffer[index++] = 0x00;
|
|
4170
|
+
path.add(orderedValues);
|
|
4171
|
+
currentFrame = makeFrame(orderedValues, index, null, frame, false, true);
|
|
4172
|
+
index += 4;
|
|
4126
4173
|
}
|
|
4127
|
-
else if (
|
|
4128
|
-
index =
|
|
4174
|
+
else if (tag === 'BSONRegExp') {
|
|
4175
|
+
index = serializeBSONRegExp(buffer, key, value, index);
|
|
4129
4176
|
}
|
|
4130
|
-
else if (
|
|
4131
|
-
|
|
4132
|
-
index = serializeDate(buffer, key, value, index);
|
|
4133
|
-
}
|
|
4134
|
-
else if (value instanceof Uint8Array || isUint8Array(value)) {
|
|
4135
|
-
index = serializeBuffer(buffer, key, value, index);
|
|
4136
|
-
}
|
|
4137
|
-
else if (value instanceof RegExp || isRegExp(value)) {
|
|
4138
|
-
index = serializeRegExp(buffer, key, value, index);
|
|
4139
|
-
}
|
|
4140
|
-
else {
|
|
4141
|
-
index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, path);
|
|
4142
|
-
}
|
|
4177
|
+
else if (tag === 'Int32') {
|
|
4178
|
+
index = serializeInt32(buffer, key, value, index);
|
|
4143
4179
|
}
|
|
4144
|
-
else if (
|
|
4145
|
-
|
|
4146
|
-
throw new BSONVersionError();
|
|
4147
|
-
}
|
|
4148
|
-
else if (value._bsontype === 'ObjectId') {
|
|
4149
|
-
index = serializeObjectId(buffer, key, value, index);
|
|
4150
|
-
}
|
|
4151
|
-
else if (value._bsontype === 'Decimal128') {
|
|
4152
|
-
index = serializeDecimal128(buffer, key, value, index);
|
|
4153
|
-
}
|
|
4154
|
-
else if (value._bsontype === 'Long' || value._bsontype === 'Timestamp') {
|
|
4155
|
-
index = serializeLong(buffer, key, value, index);
|
|
4156
|
-
}
|
|
4157
|
-
else if (value._bsontype === 'Double') {
|
|
4158
|
-
index = serializeDouble(buffer, key, value, index);
|
|
4159
|
-
}
|
|
4160
|
-
else if (value._bsontype === 'Code') {
|
|
4161
|
-
index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, path);
|
|
4162
|
-
}
|
|
4163
|
-
else if (value._bsontype === 'Binary') {
|
|
4164
|
-
index = serializeBinary(buffer, key, value, index);
|
|
4165
|
-
}
|
|
4166
|
-
else if (value._bsontype === 'BSONSymbol') {
|
|
4167
|
-
index = serializeSymbol(buffer, key, value, index);
|
|
4168
|
-
}
|
|
4169
|
-
else if (value._bsontype === 'DBRef') {
|
|
4170
|
-
index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions, path);
|
|
4171
|
-
}
|
|
4172
|
-
else if (value._bsontype === 'BSONRegExp') {
|
|
4173
|
-
index = serializeBSONRegExp(buffer, key, value, index);
|
|
4174
|
-
}
|
|
4175
|
-
else if (value._bsontype === 'Int32') {
|
|
4176
|
-
index = serializeInt32(buffer, key, value, index);
|
|
4177
|
-
}
|
|
4178
|
-
else if (value._bsontype === 'MinKey' || value._bsontype === 'MaxKey') {
|
|
4179
|
-
index = serializeMinMax(buffer, key, value, index);
|
|
4180
|
-
}
|
|
4181
|
-
else if (typeof value._bsontype !== 'undefined') {
|
|
4182
|
-
throw new BSONError(`Unrecognized or invalid _bsontype: ${String(value._bsontype)}`);
|
|
4183
|
-
}
|
|
4180
|
+
else if (tag === 'MinKey' || tag === 'MaxKey') {
|
|
4181
|
+
index = serializeMinMax(buffer, key, value, index);
|
|
4184
4182
|
}
|
|
4185
|
-
else if (
|
|
4186
|
-
|
|
4183
|
+
else if (typeof value._bsontype !== 'undefined') {
|
|
4184
|
+
throw new BSONError(`Unrecognized or invalid _bsontype: ${String(value._bsontype)}`);
|
|
4187
4185
|
}
|
|
4188
4186
|
}
|
|
4187
|
+
else if (type === 'function' && serializeFunctions) {
|
|
4188
|
+
index = serializeFunction(buffer, key, value, index);
|
|
4189
|
+
}
|
|
4189
4190
|
}
|
|
4190
|
-
path.delete(object);
|
|
4191
|
-
buffer[index++] = 0x00;
|
|
4192
|
-
const size = index - startingIndex;
|
|
4193
|
-
startingIndex += NumberUtils.setInt32LE(buffer, startingIndex, size);
|
|
4194
4191
|
return index;
|
|
4195
4192
|
}
|
|
4196
4193
|
|
|
@@ -4473,21 +4470,22 @@ function parse(text, options) {
|
|
|
4473
4470
|
return deserializeValue(value, ejsonOptions);
|
|
4474
4471
|
});
|
|
4475
4472
|
}
|
|
4476
|
-
function stringify(value,
|
|
4477
|
-
if (
|
|
4478
|
-
options =
|
|
4479
|
-
|
|
4473
|
+
function stringify(value, replacerOrOptions, spaceOrOptions, options) {
|
|
4474
|
+
if (spaceOrOptions != null && typeof spaceOrOptions === 'object') {
|
|
4475
|
+
options = spaceOrOptions;
|
|
4476
|
+
spaceOrOptions = undefined;
|
|
4480
4477
|
}
|
|
4481
|
-
if (
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4478
|
+
if (replacerOrOptions != null &&
|
|
4479
|
+
typeof replacerOrOptions === 'object' &&
|
|
4480
|
+
!Array.isArray(replacerOrOptions)) {
|
|
4481
|
+
options = replacerOrOptions;
|
|
4482
|
+
replacerOrOptions = undefined;
|
|
4485
4483
|
}
|
|
4486
4484
|
const serializeOptions = Object.assign({ relaxed: true, legacy: false }, options, {
|
|
4487
4485
|
seenObjects: [{ propertyName: '(root)', obj: null }]
|
|
4488
4486
|
});
|
|
4489
4487
|
const doc = serializeValue(value, serializeOptions);
|
|
4490
|
-
return JSON.stringify(doc,
|
|
4488
|
+
return JSON.stringify(doc, replacerOrOptions, spaceOrOptions);
|
|
4491
4489
|
}
|
|
4492
4490
|
function EJSONserialize(value, options) {
|
|
4493
4491
|
options = options || {};
|
|
@@ -4649,7 +4647,7 @@ function serialize(object, options = {}) {
|
|
|
4649
4647
|
if (buffer.length < minInternalBufferSize) {
|
|
4650
4648
|
buffer = ByteUtils.allocate(minInternalBufferSize);
|
|
4651
4649
|
}
|
|
4652
|
-
const serializationIndex = serializeInto(buffer, object, checkKeys, 0,
|
|
4650
|
+
const serializationIndex = serializeInto(buffer, object, checkKeys, 0, serializeFunctions, ignoreUndefined, null);
|
|
4653
4651
|
const finishedBuffer = ByteUtils.allocateUnsafe(serializationIndex);
|
|
4654
4652
|
finishedBuffer.set(buffer.subarray(0, serializationIndex), 0);
|
|
4655
4653
|
return finishedBuffer;
|
|
@@ -4659,7 +4657,7 @@ function serializeWithBufferAndIndex(object, finalBuffer, options = {}) {
|
|
|
4659
4657
|
const serializeFunctions = typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
|
|
4660
4658
|
const ignoreUndefined = typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true;
|
|
4661
4659
|
const startIndex = typeof options.index === 'number' ? options.index : 0;
|
|
4662
|
-
const serializationIndex = serializeInto(buffer, object, checkKeys, 0,
|
|
4660
|
+
const serializationIndex = serializeInto(buffer, object, checkKeys, 0, serializeFunctions, ignoreUndefined, null);
|
|
4663
4661
|
finalBuffer.set(buffer.subarray(0, serializationIndex), startIndex);
|
|
4664
4662
|
return startIndex + serializationIndex - 1;
|
|
4665
4663
|
}
|