bson 5.0.0-alpha.1 → 5.0.0-alpha.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.
- package/README.md +85 -93
- package/bson.d.ts +50 -22
- package/lib/bson.bundle.js +242 -204
- package/lib/bson.bundle.js.map +1 -1
- package/lib/bson.cjs +242 -204
- package/lib/bson.cjs.map +1 -1
- package/lib/bson.mjs +241 -204
- package/lib/bson.mjs.map +1 -1
- package/package.json +4 -4
- package/src/binary.ts +11 -18
- package/src/bson.ts +2 -1
- package/src/bson_value.ts +18 -0
- package/src/code.ts +3 -6
- package/src/constants.ts +1 -3
- package/src/db_ref.ts +3 -6
- package/src/decimal128.ts +10 -13
- package/src/double.ts +9 -20
- package/src/error.ts +47 -8
- package/src/extended_json.ts +36 -10
- package/src/int_32.ts +3 -6
- package/src/long.ts +37 -14
- package/src/max_key.ts +2 -6
- package/src/min_key.ts +2 -6
- package/src/objectid.ts +9 -14
- package/src/parser/calculate_size.ts +18 -11
- package/src/parser/deserializer.ts +24 -9
- package/src/parser/serializer.ts +53 -34
- package/src/regexp.ts +5 -8
- package/src/symbol.ts +3 -7
- package/src/timestamp.ts +0 -5
- package/src/uuid_utils.ts +2 -2
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"etc/prepare.js"
|
|
14
14
|
],
|
|
15
15
|
"types": "bson.d.ts",
|
|
16
|
-
"version": "5.0.0-alpha.
|
|
16
|
+
"version": "5.0.0-alpha.3",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "The MongoDB NodeJS Team",
|
|
19
19
|
"email": "dbx-node@mongodb.com"
|
|
@@ -75,11 +75,11 @@
|
|
|
75
75
|
},
|
|
76
76
|
"main": "./lib/bson.cjs",
|
|
77
77
|
"module": "./lib/bson.mjs",
|
|
78
|
-
"browser": "./lib/bson.mjs",
|
|
79
78
|
"exports": {
|
|
80
|
-
"browser": "./lib/bson.mjs",
|
|
81
79
|
"import": "./lib/bson.mjs",
|
|
82
|
-
"require": "./lib/bson.cjs"
|
|
80
|
+
"require": "./lib/bson.cjs",
|
|
81
|
+
"react-native": "./lib/bson.cjs",
|
|
82
|
+
"browser": "./lib/bson.mjs"
|
|
83
83
|
},
|
|
84
84
|
"engines": {
|
|
85
85
|
"node": ">=14.20.1"
|
package/src/binary.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { bufferToUuidHexString, uuidHexStringToBuffer, uuidValidateString } from './uuid_utils';
|
|
2
2
|
import { isUint8Array } from './parser/utils';
|
|
3
3
|
import type { EJSONOptions } from './extended_json';
|
|
4
|
-
import { BSONError
|
|
5
|
-
import { BSON_BINARY_SUBTYPE_UUID_NEW
|
|
4
|
+
import { BSONError } from './error';
|
|
5
|
+
import { BSON_BINARY_SUBTYPE_UUID_NEW } from './constants';
|
|
6
6
|
import { ByteUtils } from './utils/byte_utils';
|
|
7
|
+
import { BSONValue } from './bson_value';
|
|
7
8
|
|
|
8
9
|
/** @public */
|
|
9
10
|
export type BinarySequence = Uint8Array | number[];
|
|
@@ -27,14 +28,10 @@ export interface BinaryExtended {
|
|
|
27
28
|
* @public
|
|
28
29
|
* @category BSONType
|
|
29
30
|
*/
|
|
30
|
-
export class Binary {
|
|
31
|
+
export class Binary extends BSONValue {
|
|
31
32
|
get _bsontype(): 'Binary' {
|
|
32
33
|
return 'Binary';
|
|
33
34
|
}
|
|
34
|
-
/** @internal */
|
|
35
|
-
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
36
|
-
return BSON_MAJOR_VERSION;
|
|
37
|
-
}
|
|
38
35
|
|
|
39
36
|
/**
|
|
40
37
|
* Binary default subtype
|
|
@@ -79,6 +76,7 @@ export class Binary {
|
|
|
79
76
|
* @param subType - the option binary type.
|
|
80
77
|
*/
|
|
81
78
|
constructor(buffer?: string | BinarySequence, subType?: number) {
|
|
79
|
+
super();
|
|
82
80
|
if (
|
|
83
81
|
!(buffer == null) &&
|
|
84
82
|
!(typeof buffer === 'string') &&
|
|
@@ -86,7 +84,7 @@ export class Binary {
|
|
|
86
84
|
!(buffer instanceof ArrayBuffer) &&
|
|
87
85
|
!Array.isArray(buffer)
|
|
88
86
|
) {
|
|
89
|
-
throw new
|
|
87
|
+
throw new BSONError(
|
|
90
88
|
'Binary can only be constructed from string, Buffer, TypedArray, or Array<number>'
|
|
91
89
|
);
|
|
92
90
|
}
|
|
@@ -121,9 +119,9 @@ export class Binary {
|
|
|
121
119
|
put(byteValue: string | number | Uint8Array | number[]): void {
|
|
122
120
|
// If it's a string and a has more than one character throw an error
|
|
123
121
|
if (typeof byteValue === 'string' && byteValue.length !== 1) {
|
|
124
|
-
throw new
|
|
122
|
+
throw new BSONError('only accepts single character String');
|
|
125
123
|
} else if (typeof byteValue !== 'number' && byteValue.length !== 1)
|
|
126
|
-
throw new
|
|
124
|
+
throw new BSONError('only accepts single character Uint8Array or Array');
|
|
127
125
|
|
|
128
126
|
// Decode the byte value once
|
|
129
127
|
let decodedByte: number;
|
|
@@ -136,7 +134,7 @@ export class Binary {
|
|
|
136
134
|
}
|
|
137
135
|
|
|
138
136
|
if (decodedByte < 0 || decodedByte > 255) {
|
|
139
|
-
throw new
|
|
137
|
+
throw new BSONError('only accepts number in a valid unsigned byte range 0-255');
|
|
140
138
|
}
|
|
141
139
|
|
|
142
140
|
if (this.buffer.byteLength > this.position) {
|
|
@@ -283,7 +281,7 @@ export class Binary {
|
|
|
283
281
|
data = uuidHexStringToBuffer(doc.$uuid);
|
|
284
282
|
}
|
|
285
283
|
if (!data) {
|
|
286
|
-
throw new
|
|
284
|
+
throw new BSONError(`Unexpected Binary Extended JSON format ${JSON.stringify(doc)}`);
|
|
287
285
|
}
|
|
288
286
|
return type === BSON_BINARY_SUBTYPE_UUID_NEW ? new UUID(data) : new Binary(data, type);
|
|
289
287
|
}
|
|
@@ -309,11 +307,6 @@ const UUID_BYTE_LENGTH = 16;
|
|
|
309
307
|
* @public
|
|
310
308
|
*/
|
|
311
309
|
export class UUID extends Binary {
|
|
312
|
-
/** @internal */
|
|
313
|
-
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
314
|
-
return BSON_MAJOR_VERSION;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
310
|
static cacheHexString: boolean;
|
|
318
311
|
|
|
319
312
|
/** UUID hexString cache @internal */
|
|
@@ -337,7 +330,7 @@ export class UUID extends Binary {
|
|
|
337
330
|
} else if (typeof input === 'string') {
|
|
338
331
|
bytes = uuidHexStringToBuffer(input);
|
|
339
332
|
} else {
|
|
340
|
-
throw new
|
|
333
|
+
throw new BSONError(
|
|
341
334
|
'Argument passed in UUID constructor must be a UUID, a 16 byte Buffer or a 32/36 character hex string (dashes excluded/included, format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).'
|
|
342
335
|
);
|
|
343
336
|
}
|
package/src/bson.ts
CHANGED
|
@@ -49,7 +49,8 @@ export {
|
|
|
49
49
|
BSONRegExp,
|
|
50
50
|
Decimal128
|
|
51
51
|
};
|
|
52
|
-
export {
|
|
52
|
+
export { BSONValue } from './bson_value';
|
|
53
|
+
export { BSONError, BSONVersionError } from './error';
|
|
53
54
|
export { BSONType } from './constants';
|
|
54
55
|
export { EJSON } from './extended_json';
|
|
55
56
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BSON_MAJOR_VERSION } from './constants';
|
|
2
|
+
|
|
3
|
+
/** @public */
|
|
4
|
+
export abstract class BSONValue {
|
|
5
|
+
/** @public */
|
|
6
|
+
public abstract get _bsontype(): string;
|
|
7
|
+
|
|
8
|
+
/** @internal */
|
|
9
|
+
get [Symbol.for('@@mdb.bson.version')](): typeof BSON_MAJOR_VERSION {
|
|
10
|
+
return BSON_MAJOR_VERSION;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** @public */
|
|
14
|
+
public abstract inspect(): string;
|
|
15
|
+
|
|
16
|
+
/** @internal */
|
|
17
|
+
abstract toExtendedJSON(): unknown;
|
|
18
|
+
}
|
package/src/code.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Document } from './bson';
|
|
2
|
-
import {
|
|
2
|
+
import { BSONValue } from './bson_value';
|
|
3
3
|
|
|
4
4
|
/** @public */
|
|
5
5
|
export interface CodeExtended {
|
|
@@ -12,14 +12,10 @@ export interface CodeExtended {
|
|
|
12
12
|
* @public
|
|
13
13
|
* @category BSONType
|
|
14
14
|
*/
|
|
15
|
-
export class Code {
|
|
15
|
+
export class Code extends BSONValue {
|
|
16
16
|
get _bsontype(): 'Code' {
|
|
17
17
|
return 'Code';
|
|
18
18
|
}
|
|
19
|
-
/** @internal */
|
|
20
|
-
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
21
|
-
return BSON_MAJOR_VERSION;
|
|
22
|
-
}
|
|
23
19
|
|
|
24
20
|
code: string;
|
|
25
21
|
|
|
@@ -32,6 +28,7 @@ export class Code {
|
|
|
32
28
|
* @param scope - an optional scope for the function.
|
|
33
29
|
*/
|
|
34
30
|
constructor(code: string | Function, scope?: Document | null) {
|
|
31
|
+
super();
|
|
35
32
|
this.code = code.toString();
|
|
36
33
|
this.scope = scope ?? null;
|
|
37
34
|
}
|
package/src/constants.ts
CHANGED
package/src/db_ref.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Document } from './bson';
|
|
2
|
-
import {
|
|
2
|
+
import { BSONValue } from './bson_value';
|
|
3
3
|
import type { EJSONOptions } from './extended_json';
|
|
4
4
|
import type { ObjectId } from './objectid';
|
|
5
5
|
|
|
@@ -29,14 +29,10 @@ export function isDBRefLike(value: unknown): value is DBRefLike {
|
|
|
29
29
|
* @public
|
|
30
30
|
* @category BSONType
|
|
31
31
|
*/
|
|
32
|
-
export class DBRef {
|
|
32
|
+
export class DBRef extends BSONValue {
|
|
33
33
|
get _bsontype(): 'DBRef' {
|
|
34
34
|
return 'DBRef';
|
|
35
35
|
}
|
|
36
|
-
/** @internal */
|
|
37
|
-
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
38
|
-
return BSON_MAJOR_VERSION;
|
|
39
|
-
}
|
|
40
36
|
|
|
41
37
|
collection!: string;
|
|
42
38
|
oid!: ObjectId;
|
|
@@ -49,6 +45,7 @@ export class DBRef {
|
|
|
49
45
|
* @param db - optional db name, if omitted the reference is local to the current db.
|
|
50
46
|
*/
|
|
51
47
|
constructor(collection: string, oid: ObjectId, db?: string, fields?: Document) {
|
|
48
|
+
super();
|
|
52
49
|
// check if namespace has been provided
|
|
53
50
|
const parts = collection.split('.');
|
|
54
51
|
if (parts.length === 2) {
|
package/src/decimal128.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { BSONValue } from './bson_value';
|
|
2
|
+
import { BSONError } from './error';
|
|
3
3
|
import { Long } from './long';
|
|
4
4
|
import { isUint8Array } from './parser/utils';
|
|
5
5
|
import { ByteUtils } from './utils/byte_utils';
|
|
@@ -114,7 +114,7 @@ function lessThan(left: Long, right: Long): boolean {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
function invalidErr(string: string, message: string) {
|
|
117
|
-
throw new
|
|
117
|
+
throw new BSONError(`"${string}" is not a valid Decimal128 string - ${message}`);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
/** @public */
|
|
@@ -127,14 +127,10 @@ export interface Decimal128Extended {
|
|
|
127
127
|
* @public
|
|
128
128
|
* @category BSONType
|
|
129
129
|
*/
|
|
130
|
-
export class Decimal128 {
|
|
130
|
+
export class Decimal128 extends BSONValue {
|
|
131
131
|
get _bsontype(): 'Decimal128' {
|
|
132
132
|
return 'Decimal128';
|
|
133
133
|
}
|
|
134
|
-
/** @internal */
|
|
135
|
-
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
136
|
-
return BSON_MAJOR_VERSION;
|
|
137
|
-
}
|
|
138
134
|
|
|
139
135
|
readonly bytes!: Uint8Array;
|
|
140
136
|
|
|
@@ -143,15 +139,16 @@ export class Decimal128 {
|
|
|
143
139
|
* or a string representation as returned by .toString()
|
|
144
140
|
*/
|
|
145
141
|
constructor(bytes: Uint8Array | string) {
|
|
142
|
+
super();
|
|
146
143
|
if (typeof bytes === 'string') {
|
|
147
144
|
this.bytes = Decimal128.fromString(bytes).bytes;
|
|
148
145
|
} else if (isUint8Array(bytes)) {
|
|
149
146
|
if (bytes.byteLength !== 16) {
|
|
150
|
-
throw new
|
|
147
|
+
throw new BSONError('Decimal128 must take a Buffer of 16 bytes');
|
|
151
148
|
}
|
|
152
149
|
this.bytes = bytes;
|
|
153
150
|
} else {
|
|
154
|
-
throw new
|
|
151
|
+
throw new BSONError('Decimal128 must take a Buffer or string');
|
|
155
152
|
}
|
|
156
153
|
}
|
|
157
154
|
|
|
@@ -206,7 +203,7 @@ export class Decimal128 {
|
|
|
206
203
|
// TODO: implementing a custom parsing for this, or refactoring the regex would yield
|
|
207
204
|
// further gains.
|
|
208
205
|
if (representation.length >= 7000) {
|
|
209
|
-
throw new
|
|
206
|
+
throw new BSONError('' + representation + ' not a valid Decimal128 string');
|
|
210
207
|
}
|
|
211
208
|
|
|
212
209
|
// Results
|
|
@@ -216,7 +213,7 @@ export class Decimal128 {
|
|
|
216
213
|
|
|
217
214
|
// Validate the string
|
|
218
215
|
if ((!stringMatch && !infMatch && !nanMatch) || representation.length === 0) {
|
|
219
|
-
throw new
|
|
216
|
+
throw new BSONError('' + representation + ' not a valid Decimal128 string');
|
|
220
217
|
}
|
|
221
218
|
|
|
222
219
|
if (stringMatch) {
|
|
@@ -288,7 +285,7 @@ export class Decimal128 {
|
|
|
288
285
|
}
|
|
289
286
|
|
|
290
287
|
if (sawRadix && !nDigitsRead)
|
|
291
|
-
throw new
|
|
288
|
+
throw new BSONError('' + representation + ' not a valid Decimal128 string');
|
|
292
289
|
|
|
293
290
|
// Read exponent if exists
|
|
294
291
|
if (representation[index] === 'e' || representation[index] === 'E') {
|
package/src/double.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BSONValue } from './bson_value';
|
|
2
2
|
import type { EJSONOptions } from './extended_json';
|
|
3
3
|
|
|
4
4
|
/** @public */
|
|
@@ -11,14 +11,10 @@ export interface DoubleExtended {
|
|
|
11
11
|
* @public
|
|
12
12
|
* @category BSONType
|
|
13
13
|
*/
|
|
14
|
-
export class Double {
|
|
14
|
+
export class Double extends BSONValue {
|
|
15
15
|
get _bsontype(): 'Double' {
|
|
16
16
|
return 'Double';
|
|
17
17
|
}
|
|
18
|
-
/** @internal */
|
|
19
|
-
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
20
|
-
return BSON_MAJOR_VERSION;
|
|
21
|
-
}
|
|
22
18
|
|
|
23
19
|
value!: number;
|
|
24
20
|
/**
|
|
@@ -27,6 +23,7 @@ export class Double {
|
|
|
27
23
|
* @param value - the number we want to represent as a double.
|
|
28
24
|
*/
|
|
29
25
|
constructor(value: number) {
|
|
26
|
+
super();
|
|
30
27
|
if ((value as unknown) instanceof Number) {
|
|
31
28
|
value = value.valueOf();
|
|
32
29
|
}
|
|
@@ -57,23 +54,15 @@ export class Double {
|
|
|
57
54
|
return this.value;
|
|
58
55
|
}
|
|
59
56
|
|
|
60
|
-
// NOTE: JavaScript has +0 and -0, apparently to model limit calculations. If a user
|
|
61
|
-
// explicitly provided `-0` then we need to ensure the sign makes it into the output
|
|
62
57
|
if (Object.is(Math.sign(this.value), -0)) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
let $numberDouble: string;
|
|
67
|
-
if (Number.isInteger(this.value)) {
|
|
68
|
-
$numberDouble = this.value.toFixed(1);
|
|
69
|
-
if ($numberDouble.length >= 13) {
|
|
70
|
-
$numberDouble = this.value.toExponential(13).toUpperCase();
|
|
71
|
-
}
|
|
72
|
-
} else {
|
|
73
|
-
$numberDouble = this.value.toString();
|
|
58
|
+
// NOTE: JavaScript has +0 and -0, apparently to model limit calculations. If a user
|
|
59
|
+
// explicitly provided `-0` then we need to ensure the sign makes it into the output
|
|
60
|
+
return { $numberDouble: '-0.0' };
|
|
74
61
|
}
|
|
75
62
|
|
|
76
|
-
return {
|
|
63
|
+
return {
|
|
64
|
+
$numberDouble: Number.isInteger(this.value) ? this.value.toFixed(1) : this.value.toString()
|
|
65
|
+
};
|
|
77
66
|
}
|
|
78
67
|
|
|
79
68
|
/** @internal */
|
package/src/error.ts
CHANGED
|
@@ -1,21 +1,60 @@
|
|
|
1
|
-
|
|
1
|
+
import { BSON_MAJOR_VERSION } from './constants';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @public
|
|
5
|
+
* `BSONError` objects are thrown when runtime errors occur.
|
|
6
|
+
*/
|
|
2
7
|
export class BSONError extends Error {
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
* The underlying algorithm for isBSONError may change to improve how strict it is
|
|
11
|
+
* about determining if an input is a BSONError. But it must remain backwards compatible
|
|
12
|
+
* with previous minors & patches of the current major version.
|
|
13
|
+
*/
|
|
14
|
+
protected get bsonError(): true {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override get name(): string {
|
|
19
|
+
return 'BSONError';
|
|
20
|
+
}
|
|
21
|
+
|
|
3
22
|
constructor(message: string) {
|
|
4
23
|
super(message);
|
|
5
24
|
}
|
|
6
25
|
|
|
7
|
-
|
|
8
|
-
|
|
26
|
+
/**
|
|
27
|
+
* @public
|
|
28
|
+
*
|
|
29
|
+
* All errors thrown from the BSON library inherit from `BSONError`.
|
|
30
|
+
* This method can assist with determining if an error originates from the BSON library
|
|
31
|
+
* even if it does not pass an `instanceof` check against this class' constructor.
|
|
32
|
+
*
|
|
33
|
+
* @param value - any javascript value that needs type checking
|
|
34
|
+
*/
|
|
35
|
+
public static isBSONError(value: unknown): value is BSONError {
|
|
36
|
+
return (
|
|
37
|
+
value != null &&
|
|
38
|
+
typeof value === 'object' &&
|
|
39
|
+
'bsonError' in value &&
|
|
40
|
+
value.bsonError === true &&
|
|
41
|
+
// Do not access the following properties, just check existence
|
|
42
|
+
'name' in value &&
|
|
43
|
+
'message' in value &&
|
|
44
|
+
'stack' in value
|
|
45
|
+
);
|
|
9
46
|
}
|
|
10
47
|
}
|
|
11
48
|
|
|
12
49
|
/** @public */
|
|
13
|
-
export class
|
|
14
|
-
|
|
15
|
-
|
|
50
|
+
export class BSONVersionError extends BSONError {
|
|
51
|
+
get name(): 'BSONVersionError' {
|
|
52
|
+
return 'BSONVersionError';
|
|
16
53
|
}
|
|
17
54
|
|
|
18
|
-
|
|
19
|
-
|
|
55
|
+
constructor() {
|
|
56
|
+
super(
|
|
57
|
+
`Unsupported BSON version, bson types must be from bson ${BSON_MAJOR_VERSION}.0 or later`
|
|
58
|
+
);
|
|
20
59
|
}
|
|
21
60
|
}
|
package/src/extended_json.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { Binary } from './binary';
|
|
2
2
|
import type { Document } from './bson';
|
|
3
3
|
import { Code } from './code';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
BSON_INT32_MAX,
|
|
6
|
+
BSON_INT32_MIN,
|
|
7
|
+
BSON_INT64_MAX,
|
|
8
|
+
BSON_INT64_MIN,
|
|
9
|
+
BSON_MAJOR_VERSION
|
|
10
|
+
} from './constants';
|
|
5
11
|
import { DBRef, isDBRefLike } from './db_ref';
|
|
6
12
|
import { Decimal128 } from './decimal128';
|
|
7
13
|
import { Double } from './double';
|
|
8
|
-
import { BSONError,
|
|
14
|
+
import { BSONError, BSONVersionError } from './error';
|
|
9
15
|
import { Int32 } from './int_32';
|
|
10
16
|
import { Long } from './long';
|
|
11
17
|
import { MaxKey } from './max_key';
|
|
@@ -22,6 +28,8 @@ export type EJSONOptions = {
|
|
|
22
28
|
legacy?: boolean;
|
|
23
29
|
/** Enable Extended JSON's `relaxed` mode, which attempts to return native JS types where possible, rather than BSON types */
|
|
24
30
|
relaxed?: boolean;
|
|
31
|
+
/** Enable native bigint support */
|
|
32
|
+
useBigInt64?: boolean;
|
|
25
33
|
};
|
|
26
34
|
|
|
27
35
|
/** @internal */
|
|
@@ -70,17 +78,23 @@ const keysToCodecs = {
|
|
|
70
78
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
79
|
function deserializeValue(value: any, options: EJSONOptions = {}) {
|
|
72
80
|
if (typeof value === 'number') {
|
|
81
|
+
// TODO(NODE-4377): EJSON js number handling diverges from BSON
|
|
82
|
+
const in32BitRange = value <= BSON_INT32_MAX && value >= BSON_INT32_MIN;
|
|
83
|
+
const in64BitRange = value <= BSON_INT64_MAX && value >= BSON_INT64_MIN;
|
|
84
|
+
|
|
73
85
|
if (options.relaxed || options.legacy) {
|
|
74
86
|
return value;
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
if (Number.isInteger(value) && !Object.is(value, -0)) {
|
|
78
90
|
// interpret as being of the smallest BSON integer type that can represent the number exactly
|
|
79
|
-
if (
|
|
91
|
+
if (in32BitRange) {
|
|
80
92
|
return new Int32(value);
|
|
81
93
|
}
|
|
82
|
-
if (
|
|
83
|
-
|
|
94
|
+
if (in64BitRange) {
|
|
95
|
+
if (options.useBigInt64) {
|
|
96
|
+
return BigInt(value);
|
|
97
|
+
}
|
|
84
98
|
return Long.fromNumber(value);
|
|
85
99
|
}
|
|
86
100
|
}
|
|
@@ -192,7 +206,7 @@ function serializeValue(value: any, options: EJSONSerializeOptions): any {
|
|
|
192
206
|
circularPart.length + (alreadySeen.length + current.length) / 2 - 1
|
|
193
207
|
);
|
|
194
208
|
|
|
195
|
-
throw new
|
|
209
|
+
throw new BSONError(
|
|
196
210
|
'Converting circular structure to EJSON:\n' +
|
|
197
211
|
` ${leadingPart}${alreadySeen}${circularPart}${current}\n` +
|
|
198
212
|
` ${leadingSpace}\\${dashes}/`
|
|
@@ -234,6 +248,13 @@ function serializeValue(value: any, options: EJSONSerializeOptions): any {
|
|
|
234
248
|
return { $numberDouble: Object.is(value, -0) ? '-0.0' : value.toString() };
|
|
235
249
|
}
|
|
236
250
|
|
|
251
|
+
if (typeof value === 'bigint') {
|
|
252
|
+
if (!options.relaxed) {
|
|
253
|
+
return { $numberLong: BigInt.asIntN(64, value).toString() };
|
|
254
|
+
}
|
|
255
|
+
return Number(BigInt.asIntN(64, value));
|
|
256
|
+
}
|
|
257
|
+
|
|
237
258
|
if (value instanceof RegExp || isRegExp(value)) {
|
|
238
259
|
let flags = value.flags;
|
|
239
260
|
if (flags === undefined) {
|
|
@@ -310,9 +331,9 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
|
|
|
310
331
|
doc != null &&
|
|
311
332
|
typeof doc === 'object' &&
|
|
312
333
|
typeof doc._bsontype === 'string' &&
|
|
313
|
-
doc[Symbol.for('@@mdb.bson.version')]
|
|
334
|
+
doc[Symbol.for('@@mdb.bson.version')] !== BSON_MAJOR_VERSION
|
|
314
335
|
) {
|
|
315
|
-
throw new
|
|
336
|
+
throw new BSONVersionError();
|
|
316
337
|
} else if (isBSONType(doc)) {
|
|
317
338
|
// the "document" is really just a BSON type object
|
|
318
339
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -324,7 +345,7 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
|
|
|
324
345
|
// Copy the object into this library's version of that type.
|
|
325
346
|
const mapper = BSON_TYPE_MAPPINGS[doc._bsontype];
|
|
326
347
|
if (!mapper) {
|
|
327
|
-
throw new
|
|
348
|
+
throw new BSONError('Unrecognized or invalid _bsontype: ' + doc._bsontype);
|
|
328
349
|
}
|
|
329
350
|
outDoc = mapper(outDoc);
|
|
330
351
|
}
|
|
@@ -365,13 +386,18 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
|
|
|
365
386
|
*/
|
|
366
387
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
367
388
|
function parse(text: string, options?: EJSONOptions): any {
|
|
389
|
+
const ejsonOptions = {
|
|
390
|
+
useBigInt64: options?.useBigInt64 ?? false,
|
|
391
|
+
relaxed: options?.relaxed ?? true,
|
|
392
|
+
legacy: options?.legacy ?? false
|
|
393
|
+
};
|
|
368
394
|
return JSON.parse(text, (key, value) => {
|
|
369
395
|
if (key.indexOf('\x00') !== -1) {
|
|
370
396
|
throw new BSONError(
|
|
371
397
|
`BSON Document field names cannot contain null bytes, found: ${JSON.stringify(key)}`
|
|
372
398
|
);
|
|
373
399
|
}
|
|
374
|
-
return deserializeValue(value,
|
|
400
|
+
return deserializeValue(value, ejsonOptions);
|
|
375
401
|
});
|
|
376
402
|
}
|
|
377
403
|
|
package/src/int_32.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BSONValue } from './bson_value';
|
|
2
2
|
import type { EJSONOptions } from './extended_json';
|
|
3
3
|
|
|
4
4
|
/** @public */
|
|
@@ -11,14 +11,10 @@ export interface Int32Extended {
|
|
|
11
11
|
* @public
|
|
12
12
|
* @category BSONType
|
|
13
13
|
*/
|
|
14
|
-
export class Int32 {
|
|
14
|
+
export class Int32 extends BSONValue {
|
|
15
15
|
get _bsontype(): 'Int32' {
|
|
16
16
|
return 'Int32';
|
|
17
17
|
}
|
|
18
|
-
/** @internal */
|
|
19
|
-
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
20
|
-
return BSON_MAJOR_VERSION;
|
|
21
|
-
}
|
|
22
18
|
|
|
23
19
|
value!: number;
|
|
24
20
|
/**
|
|
@@ -27,6 +23,7 @@ export class Int32 {
|
|
|
27
23
|
* @param value - the number we want to represent as an int32.
|
|
28
24
|
*/
|
|
29
25
|
constructor(value: number | string) {
|
|
26
|
+
super();
|
|
30
27
|
if ((value as unknown) instanceof Number) {
|
|
31
28
|
value = value.valueOf();
|
|
32
29
|
}
|