bson 4.7.0 → 5.0.0-alpha.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/bson.d.ts +207 -259
- package/lib/bson.bundle.js +4034 -0
- package/lib/bson.bundle.js.map +1 -0
- package/lib/bson.cjs +4029 -0
- package/lib/bson.cjs.map +1 -0
- package/lib/bson.mjs +4003 -0
- package/lib/bson.mjs.map +1 -0
- package/package.json +49 -62
- package/src/binary.ts +64 -53
- package/src/bson.ts +27 -108
- package/src/code.ts +25 -14
- package/src/constants.ts +33 -0
- package/src/db_ref.ts +14 -8
- package/src/decimal128.ts +32 -25
- package/src/double.ts +8 -5
- package/src/error.ts +0 -2
- package/src/extended_json.ts +148 -148
- package/src/index.ts +19 -0
- package/src/int_32.ts +8 -5
- package/src/long.ts +17 -16
- package/src/max_key.ts +8 -6
- package/src/min_key.ts +8 -6
- package/src/objectid.ts +42 -74
- package/src/parser/calculate_size.ts +39 -63
- package/src/parser/deserializer.ts +41 -112
- package/src/parser/serializer.ts +234 -341
- package/src/parser/utils.ts +1 -99
- package/src/regexp.ts +17 -5
- package/src/symbol.ts +9 -5
- package/src/timestamp.ts +63 -27
- package/src/utils/byte_utils.ts +61 -0
- package/src/utils/node_byte_utils.ts +141 -0
- package/src/utils/web_byte_utils.ts +190 -0
- package/src/uuid_utils.ts +15 -15
- package/bower.json +0 -26
- package/dist/bson.browser.esm.js +0 -7470
- package/dist/bson.browser.esm.js.map +0 -1
- package/dist/bson.browser.umd.js +0 -7537
- package/dist/bson.browser.umd.js.map +0 -1
- package/dist/bson.bundle.js +0 -7536
- package/dist/bson.bundle.js.map +0 -1
- package/dist/bson.esm.js +0 -5436
- package/dist/bson.esm.js.map +0 -1
- package/lib/binary.js +0 -426
- package/lib/binary.js.map +0 -1
- package/lib/bson.js +0 -251
- package/lib/bson.js.map +0 -1
- package/lib/code.js +0 -46
- package/lib/code.js.map +0 -1
- package/lib/constants.js +0 -82
- package/lib/constants.js.map +0 -1
- package/lib/db_ref.js +0 -97
- package/lib/db_ref.js.map +0 -1
- package/lib/decimal128.js +0 -669
- package/lib/decimal128.js.map +0 -1
- package/lib/double.js +0 -76
- package/lib/double.js.map +0 -1
- package/lib/ensure_buffer.js +0 -25
- package/lib/ensure_buffer.js.map +0 -1
- package/lib/error.js +0 -55
- package/lib/error.js.map +0 -1
- package/lib/extended_json.js +0 -390
- package/lib/extended_json.js.map +0 -1
- package/lib/int_32.js +0 -58
- package/lib/int_32.js.map +0 -1
- package/lib/long.js +0 -900
- package/lib/long.js.map +0 -1
- package/lib/map.js +0 -123
- package/lib/map.js.map +0 -1
- package/lib/max_key.js +0 -33
- package/lib/max_key.js.map +0 -1
- package/lib/min_key.js +0 -33
- package/lib/min_key.js.map +0 -1
- package/lib/objectid.js +0 -299
- package/lib/objectid.js.map +0 -1
- package/lib/parser/calculate_size.js +0 -194
- package/lib/parser/calculate_size.js.map +0 -1
- package/lib/parser/deserializer.js +0 -665
- package/lib/parser/deserializer.js.map +0 -1
- package/lib/parser/serializer.js +0 -867
- package/lib/parser/serializer.js.map +0 -1
- package/lib/parser/utils.js +0 -115
- package/lib/parser/utils.js.map +0 -1
- package/lib/regexp.js +0 -74
- package/lib/regexp.js.map +0 -1
- package/lib/symbol.js +0 -48
- package/lib/symbol.js.map +0 -1
- package/lib/timestamp.js +0 -102
- package/lib/timestamp.js.map +0 -1
- package/lib/utils/global.js +0 -18
- package/lib/utils/global.js.map +0 -1
- package/lib/uuid_utils.js +0 -35
- package/lib/uuid_utils.js.map +0 -1
- package/lib/validate_utf8.js +0 -47
- package/lib/validate_utf8.js.map +0 -1
- package/src/ensure_buffer.ts +0 -27
- package/src/map.ts +0 -119
- package/src/utils/global.ts +0 -22
package/src/db_ref.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Document } from './bson';
|
|
2
|
+
import { BSON_MAJOR_VERSION } from './constants';
|
|
2
3
|
import type { EJSONOptions } from './extended_json';
|
|
3
4
|
import type { ObjectId } from './objectid';
|
|
4
|
-
import { isObjectLike } from './parser/utils';
|
|
5
5
|
|
|
6
6
|
/** @public */
|
|
7
7
|
export interface DBRefLike {
|
|
@@ -13,10 +13,14 @@ export interface DBRefLike {
|
|
|
13
13
|
/** @internal */
|
|
14
14
|
export function isDBRefLike(value: unknown): value is DBRefLike {
|
|
15
15
|
return (
|
|
16
|
-
|
|
16
|
+
value != null &&
|
|
17
|
+
typeof value === 'object' &&
|
|
18
|
+
'$id' in value &&
|
|
17
19
|
value.$id != null &&
|
|
20
|
+
'$ref' in value &&
|
|
18
21
|
typeof value.$ref === 'string' &&
|
|
19
|
-
|
|
22
|
+
// If '$db' is defined it MUST be a string, otherwise it should be absent
|
|
23
|
+
(!('$db' in value) || ('$db' in value && typeof value.$db === 'string'))
|
|
20
24
|
);
|
|
21
25
|
}
|
|
22
26
|
|
|
@@ -26,7 +30,13 @@ export function isDBRefLike(value: unknown): value is DBRefLike {
|
|
|
26
30
|
* @category BSONType
|
|
27
31
|
*/
|
|
28
32
|
export class DBRef {
|
|
29
|
-
_bsontype
|
|
33
|
+
get _bsontype(): 'DBRef' {
|
|
34
|
+
return 'DBRef';
|
|
35
|
+
}
|
|
36
|
+
/** @internal */
|
|
37
|
+
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
38
|
+
return BSON_MAJOR_VERSION;
|
|
39
|
+
}
|
|
30
40
|
|
|
31
41
|
collection!: string;
|
|
32
42
|
oid!: ObjectId;
|
|
@@ -39,8 +49,6 @@ export class DBRef {
|
|
|
39
49
|
* @param db - optional db name, if omitted the reference is local to the current db.
|
|
40
50
|
*/
|
|
41
51
|
constructor(collection: string, oid: ObjectId, db?: string, fields?: Document) {
|
|
42
|
-
if (!(this instanceof DBRef)) return new DBRef(collection, oid, db, fields);
|
|
43
|
-
|
|
44
52
|
// check if namespace has been provided
|
|
45
53
|
const parts = collection.split('.');
|
|
46
54
|
if (parts.length === 2) {
|
|
@@ -120,5 +128,3 @@ export class DBRef {
|
|
|
120
128
|
})`;
|
|
121
129
|
}
|
|
122
130
|
}
|
|
123
|
-
|
|
124
|
-
Object.defineProperty(DBRef.prototype, '_bsontype', { value: 'DBRef' });
|
package/src/decimal128.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BSON_MAJOR_VERSION } from './constants';
|
|
2
2
|
import { BSONTypeError } from './error';
|
|
3
3
|
import { Long } from './long';
|
|
4
4
|
import { isUint8Array } from './parser/utils';
|
|
5
|
+
import { ByteUtils } from './utils/byte_utils';
|
|
5
6
|
|
|
6
7
|
const PARSE_STRING_REGEXP = /^(\+|-)?(\d+|(\d*\.\d*))?(E|e)?([-+])?(\d+)?$/;
|
|
7
8
|
const PARSE_INF_REGEXP = /^(\+|-)?(Infinity|inf)$/i;
|
|
@@ -13,16 +14,22 @@ const EXPONENT_BIAS = 6176;
|
|
|
13
14
|
const MAX_DIGITS = 34;
|
|
14
15
|
|
|
15
16
|
// Nan value bits as 32 bit values (due to lack of longs)
|
|
16
|
-
const NAN_BUFFER =
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
const NAN_BUFFER = ByteUtils.fromNumberArray(
|
|
18
|
+
[
|
|
19
|
+
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
20
|
+
].reverse()
|
|
21
|
+
);
|
|
19
22
|
// Infinity value bits 32 bit values (due to lack of longs)
|
|
20
|
-
const INF_NEGATIVE_BUFFER =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const INF_NEGATIVE_BUFFER = ByteUtils.fromNumberArray(
|
|
24
|
+
[
|
|
25
|
+
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
26
|
+
].reverse()
|
|
27
|
+
);
|
|
28
|
+
const INF_POSITIVE_BUFFER = ByteUtils.fromNumberArray(
|
|
29
|
+
[
|
|
30
|
+
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
31
|
+
].reverse()
|
|
32
|
+
);
|
|
26
33
|
|
|
27
34
|
const EXPONENT_REGEX = /^([-+])?(\d+)?$/;
|
|
28
35
|
|
|
@@ -121,17 +128,21 @@ export interface Decimal128Extended {
|
|
|
121
128
|
* @category BSONType
|
|
122
129
|
*/
|
|
123
130
|
export class Decimal128 {
|
|
124
|
-
_bsontype
|
|
131
|
+
get _bsontype(): 'Decimal128' {
|
|
132
|
+
return 'Decimal128';
|
|
133
|
+
}
|
|
134
|
+
/** @internal */
|
|
135
|
+
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
136
|
+
return BSON_MAJOR_VERSION;
|
|
137
|
+
}
|
|
125
138
|
|
|
126
|
-
readonly bytes!:
|
|
139
|
+
readonly bytes!: Uint8Array;
|
|
127
140
|
|
|
128
141
|
/**
|
|
129
142
|
* @param bytes - a buffer containing the raw Decimal128 bytes in little endian order,
|
|
130
143
|
* or a string representation as returned by .toString()
|
|
131
144
|
*/
|
|
132
|
-
constructor(bytes:
|
|
133
|
-
if (!(this instanceof Decimal128)) return new Decimal128(bytes);
|
|
134
|
-
|
|
145
|
+
constructor(bytes: Uint8Array | string) {
|
|
135
146
|
if (typeof bytes === 'string') {
|
|
136
147
|
this.bytes = Decimal128.fromString(bytes).bytes;
|
|
137
148
|
} else if (isUint8Array(bytes)) {
|
|
@@ -239,9 +250,9 @@ export class Decimal128 {
|
|
|
239
250
|
// Check if user passed Infinity or NaN
|
|
240
251
|
if (!isDigit(representation[index]) && representation[index] !== '.') {
|
|
241
252
|
if (representation[index] === 'i' || representation[index] === 'I') {
|
|
242
|
-
return new Decimal128(
|
|
253
|
+
return new Decimal128(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER);
|
|
243
254
|
} else if (representation[index] === 'N') {
|
|
244
|
-
return new Decimal128(
|
|
255
|
+
return new Decimal128(NAN_BUFFER);
|
|
245
256
|
}
|
|
246
257
|
}
|
|
247
258
|
|
|
@@ -285,7 +296,7 @@ export class Decimal128 {
|
|
|
285
296
|
const match = representation.substr(++index).match(EXPONENT_REGEX);
|
|
286
297
|
|
|
287
298
|
// No digits read
|
|
288
|
-
if (!match || !match[2]) return new Decimal128(
|
|
299
|
+
if (!match || !match[2]) return new Decimal128(NAN_BUFFER);
|
|
289
300
|
|
|
290
301
|
// Get exponent
|
|
291
302
|
exponent = parseInt(match[0], 10);
|
|
@@ -295,7 +306,7 @@ export class Decimal128 {
|
|
|
295
306
|
}
|
|
296
307
|
|
|
297
308
|
// Return not a number
|
|
298
|
-
if (representation[index]) return new Decimal128(
|
|
309
|
+
if (representation[index]) return new Decimal128(NAN_BUFFER);
|
|
299
310
|
|
|
300
311
|
// Done reading input
|
|
301
312
|
// Find first non-zero digit in digits
|
|
@@ -423,9 +434,7 @@ export class Decimal128 {
|
|
|
423
434
|
exponent = exponent + 1;
|
|
424
435
|
digits[dIdx] = 1;
|
|
425
436
|
} else {
|
|
426
|
-
return new Decimal128(
|
|
427
|
-
Buffer.from(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)
|
|
428
|
-
);
|
|
437
|
+
return new Decimal128(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER);
|
|
429
438
|
}
|
|
430
439
|
}
|
|
431
440
|
}
|
|
@@ -503,7 +512,7 @@ export class Decimal128 {
|
|
|
503
512
|
}
|
|
504
513
|
|
|
505
514
|
// Encode into a buffer
|
|
506
|
-
const buffer =
|
|
515
|
+
const buffer = ByteUtils.allocate(16);
|
|
507
516
|
index = 0;
|
|
508
517
|
|
|
509
518
|
// Encode the low 64 bits of the decimal
|
|
@@ -769,5 +778,3 @@ export class Decimal128 {
|
|
|
769
778
|
return `new Decimal128("${this.toString()}")`;
|
|
770
779
|
}
|
|
771
780
|
}
|
|
772
|
-
|
|
773
|
-
Object.defineProperty(Decimal128.prototype, '_bsontype', { value: 'Decimal128' });
|
package/src/double.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BSON_MAJOR_VERSION } from './constants';
|
|
1
2
|
import type { EJSONOptions } from './extended_json';
|
|
2
3
|
|
|
3
4
|
/** @public */
|
|
@@ -11,7 +12,13 @@ export interface DoubleExtended {
|
|
|
11
12
|
* @category BSONType
|
|
12
13
|
*/
|
|
13
14
|
export class Double {
|
|
14
|
-
_bsontype
|
|
15
|
+
get _bsontype(): 'Double' {
|
|
16
|
+
return 'Double';
|
|
17
|
+
}
|
|
18
|
+
/** @internal */
|
|
19
|
+
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
20
|
+
return BSON_MAJOR_VERSION;
|
|
21
|
+
}
|
|
15
22
|
|
|
16
23
|
value!: number;
|
|
17
24
|
/**
|
|
@@ -20,8 +27,6 @@ export class Double {
|
|
|
20
27
|
* @param value - the number we want to represent as a double.
|
|
21
28
|
*/
|
|
22
29
|
constructor(value: number) {
|
|
23
|
-
if (!(this instanceof Double)) return new Double(value);
|
|
24
|
-
|
|
25
30
|
if ((value as unknown) instanceof Number) {
|
|
26
31
|
value = value.valueOf();
|
|
27
32
|
}
|
|
@@ -87,5 +92,3 @@ export class Double {
|
|
|
87
92
|
return `new Double(${eJSON.$numberDouble})`;
|
|
88
93
|
}
|
|
89
94
|
}
|
|
90
|
-
|
|
91
|
-
Object.defineProperty(Double.prototype, '_bsontype', { value: 'Double' });
|
package/src/error.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
export class BSONError extends Error {
|
|
3
3
|
constructor(message: string) {
|
|
4
4
|
super(message);
|
|
5
|
-
Object.setPrototypeOf(this, BSONError.prototype);
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
get name(): string {
|
|
@@ -14,7 +13,6 @@ export class BSONError extends Error {
|
|
|
14
13
|
export class BSONTypeError extends TypeError {
|
|
15
14
|
constructor(message: string) {
|
|
16
15
|
super(message);
|
|
17
|
-
Object.setPrototypeOf(this, BSONTypeError.prototype);
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
get name(): string {
|
package/src/extended_json.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Binary } from './binary';
|
|
2
2
|
import type { Document } from './bson';
|
|
3
3
|
import { Code } from './code';
|
|
4
|
+
import { BSON_INT32_MAX, BSON_INT32_MIN, BSON_INT64_MAX, BSON_INT64_MIN } from './constants';
|
|
4
5
|
import { DBRef, isDBRefLike } from './db_ref';
|
|
5
6
|
import { Decimal128 } from './decimal128';
|
|
6
7
|
import { Double } from './double';
|
|
@@ -10,13 +11,18 @@ import { Long } from './long';
|
|
|
10
11
|
import { MaxKey } from './max_key';
|
|
11
12
|
import { MinKey } from './min_key';
|
|
12
13
|
import { ObjectId } from './objectid';
|
|
13
|
-
import { isDate,
|
|
14
|
+
import { isDate, isRegExp } from './parser/utils';
|
|
14
15
|
import { BSONRegExp } from './regexp';
|
|
15
16
|
import { BSONSymbol } from './symbol';
|
|
16
17
|
import { Timestamp } from './timestamp';
|
|
17
18
|
|
|
18
19
|
/** @public */
|
|
19
|
-
export type EJSONOptions =
|
|
20
|
+
export type EJSONOptions = {
|
|
21
|
+
/** Output using the Extended JSON v1 spec */
|
|
22
|
+
legacy?: boolean;
|
|
23
|
+
/** Enable Extended JSON's `relaxed` mode, which attempts to return native JS types where possible, rather than BSON types */
|
|
24
|
+
relaxed?: boolean;
|
|
25
|
+
};
|
|
20
26
|
|
|
21
27
|
/** @internal */
|
|
22
28
|
type BSONType =
|
|
@@ -34,20 +40,15 @@ type BSONType =
|
|
|
34
40
|
| BSONSymbol
|
|
35
41
|
| Timestamp;
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
function isBSONType(value: unknown): value is BSONType {
|
|
38
44
|
return (
|
|
39
|
-
|
|
45
|
+
value != null &&
|
|
46
|
+
typeof value === 'object' &&
|
|
47
|
+
'_bsontype' in value &&
|
|
48
|
+
typeof value._bsontype === 'string'
|
|
40
49
|
);
|
|
41
50
|
}
|
|
42
51
|
|
|
43
|
-
// INT32 boundaries
|
|
44
|
-
const BSON_INT32_MAX = 0x7fffffff;
|
|
45
|
-
const BSON_INT32_MIN = -0x80000000;
|
|
46
|
-
// INT64 boundaries
|
|
47
|
-
// const BSON_INT64_MAX = 0x7fffffffffffffff; // TODO(NODE-4377): This number cannot be precisely represented in JS
|
|
48
|
-
const BSON_INT64_MAX = 0x8000000000000000;
|
|
49
|
-
const BSON_INT64_MIN = -0x8000000000000000;
|
|
50
|
-
|
|
51
52
|
// all the types where we don't need to do any special processing and can just pass the EJSON
|
|
52
53
|
//straight to type.fromExtendedJSON
|
|
53
54
|
const keysToCodecs = {
|
|
@@ -67,17 +68,21 @@ const keysToCodecs = {
|
|
|
67
68
|
} as const;
|
|
68
69
|
|
|
69
70
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
-
function deserializeValue(value: any, options:
|
|
71
|
+
function deserializeValue(value: any, options: EJSONOptions = {}) {
|
|
71
72
|
if (typeof value === 'number') {
|
|
72
73
|
if (options.relaxed || options.legacy) {
|
|
73
74
|
return value;
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
if (Number.isInteger(value) && !Object.is(value, -0)) {
|
|
78
|
+
// interpret as being of the smallest BSON integer type that can represent the number exactly
|
|
79
|
+
if (value >= BSON_INT32_MIN && value <= BSON_INT32_MAX) {
|
|
80
|
+
return new Int32(value);
|
|
81
|
+
}
|
|
82
|
+
if (value >= BSON_INT64_MIN && value <= BSON_INT64_MAX) {
|
|
83
|
+
// TODO(NODE-4377): EJSON js number handling diverges from BSON
|
|
84
|
+
return Long.fromNumber(value);
|
|
85
|
+
}
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
// If the number is a non-integer or out of integer range, should interpret as BSON Double.
|
|
@@ -142,7 +147,7 @@ function deserializeValue(value: any, options: EJSON.Options = {}) {
|
|
|
142
147
|
return value;
|
|
143
148
|
}
|
|
144
149
|
|
|
145
|
-
type EJSONSerializeOptions =
|
|
150
|
+
type EJSONSerializeOptions = EJSONOptions & {
|
|
146
151
|
seenObjects: { obj: unknown; propertyName: string }[];
|
|
147
152
|
};
|
|
148
153
|
|
|
@@ -216,16 +221,17 @@ function serializeValue(value: any, options: EJSONSerializeOptions): any {
|
|
|
216
221
|
}
|
|
217
222
|
|
|
218
223
|
if (typeof value === 'number' && (!options.relaxed || !isFinite(value))) {
|
|
219
|
-
|
|
220
|
-
if (Math.floor(value) === value) {
|
|
221
|
-
const int32Range = value >= BSON_INT32_MIN && value <= BSON_INT32_MAX,
|
|
222
|
-
int64Range = value >= BSON_INT64_MIN && value <= BSON_INT64_MAX;
|
|
223
|
-
|
|
224
|
+
if (Number.isInteger(value) && !Object.is(value, -0)) {
|
|
224
225
|
// interpret as being of the smallest BSON integer type that can represent the number exactly
|
|
225
|
-
if (
|
|
226
|
-
|
|
226
|
+
if (value >= BSON_INT32_MIN && value <= BSON_INT32_MAX) {
|
|
227
|
+
return { $numberInt: value.toString() };
|
|
228
|
+
}
|
|
229
|
+
if (value >= BSON_INT64_MIN && value <= BSON_INT64_MAX) {
|
|
230
|
+
// TODO(NODE-4377): EJSON js number handling diverges from BSON
|
|
231
|
+
return { $numberLong: value.toString() };
|
|
232
|
+
}
|
|
227
233
|
}
|
|
228
|
-
return { $numberDouble: value.toString() };
|
|
234
|
+
return { $numberDouble: Object.is(value, -0) ? '-0.0' : value.toString() };
|
|
229
235
|
}
|
|
230
236
|
|
|
231
237
|
if (value instanceof RegExp || isRegExp(value)) {
|
|
@@ -267,10 +273,9 @@ const BSON_TYPE_MAPPINGS = {
|
|
|
267
273
|
),
|
|
268
274
|
MaxKey: () => new MaxKey(),
|
|
269
275
|
MinKey: () => new MinKey(),
|
|
270
|
-
|
|
271
|
-
ObjectId: (o: ObjectId) => new ObjectId(o), // support 4.0.0/4.0.1 before _bsontype was reverted back to ObjectID
|
|
276
|
+
ObjectId: (o: ObjectId) => new ObjectId(o),
|
|
272
277
|
BSONRegExp: (o: BSONRegExp) => new BSONRegExp(o.pattern, o.options),
|
|
273
|
-
|
|
278
|
+
BSONSymbol: (o: BSONSymbol) => new BSONSymbol(o.value),
|
|
274
279
|
Timestamp: (o: Timestamp) => Timestamp.fromBits(o.low, o.high)
|
|
275
280
|
} as const;
|
|
276
281
|
|
|
@@ -282,7 +287,7 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
|
|
|
282
287
|
if (typeof bsontype === 'undefined') {
|
|
283
288
|
// It's a regular object. Recursively serialize its property values.
|
|
284
289
|
const _doc: Document = {};
|
|
285
|
-
for (const name
|
|
290
|
+
for (const name of Object.keys(doc)) {
|
|
286
291
|
options.seenObjects.push({ propertyName: name, obj: null });
|
|
287
292
|
try {
|
|
288
293
|
const value = serializeValue(doc[name], options);
|
|
@@ -301,6 +306,13 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
|
|
|
301
306
|
}
|
|
302
307
|
}
|
|
303
308
|
return _doc;
|
|
309
|
+
} else if (
|
|
310
|
+
doc != null &&
|
|
311
|
+
typeof doc === 'object' &&
|
|
312
|
+
typeof doc._bsontype === 'string' &&
|
|
313
|
+
doc[Symbol.for('@@mdb.bson.version')] == null
|
|
314
|
+
) {
|
|
315
|
+
throw new BSONError('Unsupported BSON version, bson types must be from bson 5.0 or later');
|
|
304
316
|
} else if (isBSONType(doc)) {
|
|
305
317
|
// the "document" is really just a BSON type object
|
|
306
318
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -336,127 +348,115 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
|
|
|
336
348
|
}
|
|
337
349
|
|
|
338
350
|
/**
|
|
339
|
-
*
|
|
340
|
-
*
|
|
351
|
+
* Parse an Extended JSON string, constructing the JavaScript value or object described by that
|
|
352
|
+
* string.
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* ```js
|
|
356
|
+
* const { EJSON } = require('bson');
|
|
357
|
+
* const text = '{ "int32": { "$numberInt": "10" } }';
|
|
358
|
+
*
|
|
359
|
+
* // prints { int32: { [String: '10'] _bsontype: 'Int32', value: '10' } }
|
|
360
|
+
* console.log(EJSON.parse(text, { relaxed: false }));
|
|
361
|
+
*
|
|
362
|
+
* // prints { int32: 10 }
|
|
363
|
+
* console.log(EJSON.parse(text));
|
|
364
|
+
* ```
|
|
341
365
|
*/
|
|
342
|
-
//
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
/** Enable Extended JSON's `relaxed` mode, which attempts to return native JS types where possible, rather than BSON types */
|
|
350
|
-
relaxed?: boolean;
|
|
351
|
-
/**
|
|
352
|
-
* Disable Extended JSON's `relaxed` mode, which attempts to return BSON types where possible, rather than native JS types
|
|
353
|
-
* @deprecated Please use the relaxed property instead
|
|
354
|
-
*/
|
|
355
|
-
strict?: boolean;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Parse an Extended JSON string, constructing the JavaScript value or object described by that
|
|
360
|
-
* string.
|
|
361
|
-
*
|
|
362
|
-
* @example
|
|
363
|
-
* ```js
|
|
364
|
-
* const { EJSON } = require('bson');
|
|
365
|
-
* const text = '{ "int32": { "$numberInt": "10" } }';
|
|
366
|
-
*
|
|
367
|
-
* // prints { int32: { [String: '10'] _bsontype: 'Int32', value: '10' } }
|
|
368
|
-
* console.log(EJSON.parse(text, { relaxed: false }));
|
|
369
|
-
*
|
|
370
|
-
* // prints { int32: 10 }
|
|
371
|
-
* console.log(EJSON.parse(text));
|
|
372
|
-
* ```
|
|
373
|
-
*/
|
|
374
|
-
export function parse(text: string, options?: EJSON.Options): SerializableTypes {
|
|
375
|
-
const finalOptions = Object.assign({}, { relaxed: true, legacy: false }, options);
|
|
376
|
-
|
|
377
|
-
// relaxed implies not strict
|
|
378
|
-
if (typeof finalOptions.relaxed === 'boolean') finalOptions.strict = !finalOptions.relaxed;
|
|
379
|
-
if (typeof finalOptions.strict === 'boolean') finalOptions.relaxed = !finalOptions.strict;
|
|
380
|
-
|
|
381
|
-
return JSON.parse(text, (key, value) => {
|
|
382
|
-
if (key.indexOf('\x00') !== -1) {
|
|
383
|
-
throw new BSONError(
|
|
384
|
-
`BSON Document field names cannot contain null bytes, found: ${JSON.stringify(key)}`
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
return deserializeValue(value, finalOptions);
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
export type JSONPrimitive = string | number | boolean | null;
|
|
392
|
-
export type SerializableTypes = Document | Array<JSONPrimitive | Document> | JSONPrimitive;
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Converts a BSON document to an Extended JSON string, optionally replacing values if a replacer
|
|
396
|
-
* function is specified or optionally including only the specified properties if a replacer array
|
|
397
|
-
* is specified.
|
|
398
|
-
*
|
|
399
|
-
* @param value - The value to convert to extended JSON
|
|
400
|
-
* @param replacer - A function that alters the behavior of the stringification process, or an array of String and Number objects that serve as a whitelist for selecting/filtering the properties of the value object to be included in the JSON string. If this value is null or not provided, all properties of the object are included in the resulting JSON string
|
|
401
|
-
* @param space - A String or Number object that's used to insert white space into the output JSON string for readability purposes.
|
|
402
|
-
* @param options - Optional settings
|
|
403
|
-
*
|
|
404
|
-
* @example
|
|
405
|
-
* ```js
|
|
406
|
-
* const { EJSON } = require('bson');
|
|
407
|
-
* const Int32 = require('mongodb').Int32;
|
|
408
|
-
* const doc = { int32: new Int32(10) };
|
|
409
|
-
*
|
|
410
|
-
* // prints '{"int32":{"$numberInt":"10"}}'
|
|
411
|
-
* console.log(EJSON.stringify(doc, { relaxed: false }));
|
|
412
|
-
*
|
|
413
|
-
* // prints '{"int32":10}'
|
|
414
|
-
* console.log(EJSON.stringify(doc));
|
|
415
|
-
* ```
|
|
416
|
-
*/
|
|
417
|
-
export function stringify(
|
|
418
|
-
value: SerializableTypes,
|
|
419
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
420
|
-
replacer?: (number | string)[] | ((this: any, key: string, value: any) => any) | EJSON.Options,
|
|
421
|
-
space?: string | number,
|
|
422
|
-
options?: EJSON.Options
|
|
423
|
-
): string {
|
|
424
|
-
if (space != null && typeof space === 'object') {
|
|
425
|
-
options = space;
|
|
426
|
-
space = 0;
|
|
427
|
-
}
|
|
428
|
-
if (replacer != null && typeof replacer === 'object' && !Array.isArray(replacer)) {
|
|
429
|
-
options = replacer;
|
|
430
|
-
replacer = undefined;
|
|
431
|
-
space = 0;
|
|
366
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
367
|
+
function parse(text: string, options?: EJSONOptions): any {
|
|
368
|
+
return JSON.parse(text, (key, value) => {
|
|
369
|
+
if (key.indexOf('\x00') !== -1) {
|
|
370
|
+
throw new BSONError(
|
|
371
|
+
`BSON Document field names cannot contain null bytes, found: ${JSON.stringify(key)}`
|
|
372
|
+
);
|
|
432
373
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
374
|
+
return deserializeValue(value, { relaxed: true, legacy: false, ...options });
|
|
375
|
+
});
|
|
376
|
+
}
|
|
436
377
|
|
|
437
|
-
|
|
438
|
-
|
|
378
|
+
/**
|
|
379
|
+
* Converts a BSON document to an Extended JSON string, optionally replacing values if a replacer
|
|
380
|
+
* function is specified or optionally including only the specified properties if a replacer array
|
|
381
|
+
* is specified.
|
|
382
|
+
*
|
|
383
|
+
* @param value - The value to convert to extended JSON
|
|
384
|
+
* @param replacer - A function that alters the behavior of the stringification process, or an array of String and Number objects that serve as a whitelist for selecting/filtering the properties of the value object to be included in the JSON string. If this value is null or not provided, all properties of the object are included in the resulting JSON string
|
|
385
|
+
* @param space - A String or Number object that's used to insert white space into the output JSON string for readability purposes.
|
|
386
|
+
* @param options - Optional settings
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```js
|
|
390
|
+
* const { EJSON } = require('bson');
|
|
391
|
+
* const Int32 = require('mongodb').Int32;
|
|
392
|
+
* const doc = { int32: new Int32(10) };
|
|
393
|
+
*
|
|
394
|
+
* // prints '{"int32":{"$numberInt":"10"}}'
|
|
395
|
+
* console.log(EJSON.stringify(doc, { relaxed: false }));
|
|
396
|
+
*
|
|
397
|
+
* // prints '{"int32":10}'
|
|
398
|
+
* console.log(EJSON.stringify(doc));
|
|
399
|
+
* ```
|
|
400
|
+
*/
|
|
401
|
+
function stringify(
|
|
402
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
403
|
+
value: any,
|
|
404
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
405
|
+
replacer?: (number | string)[] | ((this: any, key: string, value: any) => any) | EJSONOptions,
|
|
406
|
+
space?: string | number,
|
|
407
|
+
options?: EJSONOptions
|
|
408
|
+
): string {
|
|
409
|
+
if (space != null && typeof space === 'object') {
|
|
410
|
+
options = space;
|
|
411
|
+
space = 0;
|
|
439
412
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
* @param value - The object to serialize
|
|
445
|
-
* @param options - Optional settings passed to the `stringify` function
|
|
446
|
-
*/
|
|
447
|
-
export function serialize(value: SerializableTypes, options?: EJSON.Options): Document {
|
|
448
|
-
options = options || {};
|
|
449
|
-
return JSON.parse(stringify(value, options));
|
|
413
|
+
if (replacer != null && typeof replacer === 'object' && !Array.isArray(replacer)) {
|
|
414
|
+
options = replacer;
|
|
415
|
+
replacer = undefined;
|
|
416
|
+
space = 0;
|
|
450
417
|
}
|
|
418
|
+
const serializeOptions = Object.assign({ relaxed: true, legacy: false }, options, {
|
|
419
|
+
seenObjects: [{ propertyName: '(root)', obj: null }]
|
|
420
|
+
});
|
|
451
421
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
*
|
|
455
|
-
* @param ejson - The Extended JSON object to deserialize
|
|
456
|
-
* @param options - Optional settings passed to the parse method
|
|
457
|
-
*/
|
|
458
|
-
export function deserialize(ejson: Document, options?: EJSON.Options): SerializableTypes {
|
|
459
|
-
options = options || {};
|
|
460
|
-
return parse(JSON.stringify(ejson), options);
|
|
461
|
-
}
|
|
422
|
+
const doc = serializeValue(value, serializeOptions);
|
|
423
|
+
return JSON.stringify(doc, replacer as Parameters<JSON['stringify']>[1], space);
|
|
462
424
|
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Serializes an object to an Extended JSON string, and reparse it as a JavaScript object.
|
|
428
|
+
*
|
|
429
|
+
* @param value - The object to serialize
|
|
430
|
+
* @param options - Optional settings passed to the `stringify` function
|
|
431
|
+
*/
|
|
432
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
433
|
+
function EJSONserialize(value: any, options?: EJSONOptions): Document {
|
|
434
|
+
options = options || {};
|
|
435
|
+
return JSON.parse(stringify(value, options));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Deserializes an Extended JSON object into a plain JavaScript object with native/BSON types
|
|
440
|
+
*
|
|
441
|
+
* @param ejson - The Extended JSON object to deserialize
|
|
442
|
+
* @param options - Optional settings passed to the parse method
|
|
443
|
+
*/
|
|
444
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
445
|
+
function EJSONdeserialize(ejson: Document, options?: EJSONOptions): any {
|
|
446
|
+
options = options || {};
|
|
447
|
+
return parse(JSON.stringify(ejson), options);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/** @public */
|
|
451
|
+
const EJSON: {
|
|
452
|
+
parse: typeof parse;
|
|
453
|
+
stringify: typeof stringify;
|
|
454
|
+
serialize: typeof EJSONserialize;
|
|
455
|
+
deserialize: typeof EJSONdeserialize;
|
|
456
|
+
} = Object.create(null);
|
|
457
|
+
EJSON.parse = parse;
|
|
458
|
+
EJSON.stringify = stringify;
|
|
459
|
+
EJSON.serialize = EJSONserialize;
|
|
460
|
+
EJSON.deserialize = EJSONdeserialize;
|
|
461
|
+
Object.freeze(EJSON);
|
|
462
|
+
export { EJSON };
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as BSON from './bson';
|
|
2
|
+
|
|
3
|
+
// Export all named properties from BSON to support
|
|
4
|
+
// import { ObjectId, serialize } from 'bson';
|
|
5
|
+
// const { ObjectId, serialize } = require('bson');
|
|
6
|
+
export * from './bson';
|
|
7
|
+
|
|
8
|
+
// Export BSON as a namespace to support:
|
|
9
|
+
// import { BSON } from 'bson';
|
|
10
|
+
// const { BSON } = require('bson');
|
|
11
|
+
export { BSON };
|
|
12
|
+
|
|
13
|
+
// BSON does **NOT** have a default export
|
|
14
|
+
|
|
15
|
+
// The following will crash in es module environments
|
|
16
|
+
// import BSON from 'bson';
|
|
17
|
+
|
|
18
|
+
// The following will work as expected, BSON as a namespace of all the APIs (BSON.ObjectId, BSON.serialize)
|
|
19
|
+
// const BSON = require('bson');
|
package/src/int_32.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BSON_MAJOR_VERSION } from './constants';
|
|
1
2
|
import type { EJSONOptions } from './extended_json';
|
|
2
3
|
|
|
3
4
|
/** @public */
|
|
@@ -11,7 +12,13 @@ export interface Int32Extended {
|
|
|
11
12
|
* @category BSONType
|
|
12
13
|
*/
|
|
13
14
|
export class Int32 {
|
|
14
|
-
_bsontype
|
|
15
|
+
get _bsontype(): 'Int32' {
|
|
16
|
+
return 'Int32';
|
|
17
|
+
}
|
|
18
|
+
/** @internal */
|
|
19
|
+
get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
|
|
20
|
+
return BSON_MAJOR_VERSION;
|
|
21
|
+
}
|
|
15
22
|
|
|
16
23
|
value!: number;
|
|
17
24
|
/**
|
|
@@ -20,8 +27,6 @@ export class Int32 {
|
|
|
20
27
|
* @param value - the number we want to represent as an int32.
|
|
21
28
|
*/
|
|
22
29
|
constructor(value: number | string) {
|
|
23
|
-
if (!(this instanceof Int32)) return new Int32(value);
|
|
24
|
-
|
|
25
30
|
if ((value as unknown) instanceof Number) {
|
|
26
31
|
value = value.valueOf();
|
|
27
32
|
}
|
|
@@ -66,5 +71,3 @@ export class Int32 {
|
|
|
66
71
|
return `new Int32(${this.valueOf()})`;
|
|
67
72
|
}
|
|
68
73
|
}
|
|
69
|
-
|
|
70
|
-
Object.defineProperty(Int32.prototype, '_bsontype', { value: 'Int32' });
|