bson 4.0.4 → 4.2.2
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/HISTORY.md +56 -1
- package/README.md +7 -9
- package/bower.json +1 -1
- package/bson.d.ts +983 -0
- package/dist/bson.browser.esm.js +7261 -5004
- package/dist/bson.browser.esm.js.map +1 -0
- package/dist/bson.browser.umd.js +7319 -5099
- package/dist/bson.browser.umd.js.map +1 -0
- package/dist/bson.bundle.js +8168 -9216
- package/dist/bson.bundle.js.map +1 -0
- package/dist/bson.esm.js +5643 -5409
- package/dist/bson.esm.js.map +1 -0
- package/etc/prepare.js +19 -0
- package/lib/binary.js +194 -377
- package/lib/binary.js.map +1 -0
- package/lib/bson.js +200 -243
- package/lib/bson.js.map +1 -0
- package/lib/code.js +36 -39
- package/lib/code.js.map +1 -0
- package/lib/constants.js +78 -203
- package/lib/constants.js.map +1 -0
- package/lib/db_ref.js +79 -79
- package/lib/db_ref.js.map +1 -0
- package/lib/decimal128.js +647 -760
- package/lib/decimal128.js.map +1 -0
- package/lib/double.js +61 -58
- package/lib/double.js.map +1 -0
- package/lib/ensure_buffer.js +22 -18
- package/lib/ensure_buffer.js.map +1 -0
- package/lib/extended_json.js +305 -322
- package/lib/extended_json.js.map +1 -0
- package/lib/float_parser.js +98 -104
- package/lib/float_parser.js.map +1 -0
- package/lib/int_32.js +45 -47
- package/lib/int_32.js.map +1 -0
- package/lib/long.js +876 -16
- package/lib/long.js.map +1 -0
- package/lib/map.js +123 -124
- package/lib/map.js.map +1 -0
- package/lib/max_key.js +21 -23
- package/lib/max_key.js.map +1 -0
- package/lib/min_key.js +21 -23
- package/lib/min_key.js.map +1 -0
- package/lib/objectid.js +264 -382
- package/lib/objectid.js.map +1 -0
- package/lib/parser/calculate_size.js +185 -224
- package/lib/parser/calculate_size.js.map +1 -0
- package/lib/parser/deserializer.js +543 -620
- package/lib/parser/deserializer.js.map +1 -0
- package/lib/parser/serializer.js +774 -918
- package/lib/parser/serializer.js.map +1 -0
- package/lib/parser/utils.js +81 -30
- package/lib/parser/utils.js.map +1 -0
- package/lib/regexp.js +54 -70
- package/lib/regexp.js.map +1 -0
- package/lib/symbol.js +40 -56
- package/lib/symbol.js.map +1 -0
- package/lib/timestamp.js +70 -95
- package/lib/timestamp.js.map +1 -0
- package/lib/uuid.js +48 -0
- package/lib/uuid.js.map +1 -0
- package/lib/validate_utf8.js +32 -33
- package/lib/validate_utf8.js.map +1 -0
- package/package.json +53 -31
- package/src/binary.ts +270 -0
- package/src/bson.ts +326 -0
- package/src/code.ts +57 -0
- package/src/constants.ts +104 -0
- package/src/db_ref.ts +115 -0
- package/src/decimal128.ts +801 -0
- package/src/double.ts +85 -0
- package/src/ensure_buffer.ts +26 -0
- package/src/extended_json.ts +395 -0
- package/src/float_parser.ts +152 -0
- package/src/int_32.ts +64 -0
- package/src/long.ts +1000 -0
- package/src/map.ts +139 -0
- package/src/max_key.ts +33 -0
- package/src/min_key.ts +33 -0
- package/src/objectid.ts +377 -0
- package/src/parser/calculate_size.ts +230 -0
- package/src/parser/deserializer.ts +655 -0
- package/src/parser/serializer.ts +1069 -0
- package/src/parser/utils.ts +93 -0
- package/src/regexp.ts +92 -0
- package/src/symbol.ts +57 -0
- package/src/timestamp.ts +103 -0
- package/src/uuid.ts +57 -0
- package/src/validate_utf8.ts +47 -0
- package/lib/fnv1a.js +0 -48
package/lib/extended_json.js
CHANGED
|
@@ -1,347 +1,330 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EJSON = exports.isBSONType = void 0;
|
|
4
|
+
const binary_1 = require("./binary");
|
|
5
|
+
const code_1 = require("./code");
|
|
6
|
+
const db_ref_1 = require("./db_ref");
|
|
7
|
+
const decimal128_1 = require("./decimal128");
|
|
8
|
+
const double_1 = require("./double");
|
|
9
|
+
const int_32_1 = require("./int_32");
|
|
10
|
+
const long_1 = require("./long");
|
|
11
|
+
const max_key_1 = require("./max_key");
|
|
12
|
+
const min_key_1 = require("./min_key");
|
|
13
|
+
const objectid_1 = require("./objectid");
|
|
14
|
+
const utils_1 = require("./parser/utils");
|
|
15
|
+
const regexp_1 = require("./regexp");
|
|
16
|
+
const symbol_1 = require("./symbol");
|
|
17
|
+
const timestamp_1 = require("./timestamp");
|
|
18
|
+
function isBSONType(value) {
|
|
19
|
+
return (utils_1.isObjectLike(value) && Reflect.has(value, '_bsontype') && typeof value._bsontype === 'string');
|
|
20
|
+
}
|
|
21
|
+
exports.isBSONType = isBSONType;
|
|
22
|
+
// INT32 boundaries
|
|
23
|
+
const BSON_INT32_MAX = 0x7fffffff;
|
|
24
|
+
const BSON_INT32_MIN = -0x80000000;
|
|
25
|
+
// INT64 boundaries
|
|
26
|
+
const BSON_INT64_MAX = 0x7fffffffffffffff;
|
|
27
|
+
const BSON_INT64_MIN = -0x8000000000000000;
|
|
23
28
|
// all the types where we don't need to do any special processing and can just pass the EJSON
|
|
24
29
|
//straight to type.fromExtendedJSON
|
|
25
30
|
const keysToCodecs = {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
$oid: objectid_1.ObjectId,
|
|
32
|
+
$binary: binary_1.Binary,
|
|
33
|
+
$uuid: binary_1.Binary,
|
|
34
|
+
$symbol: symbol_1.BSONSymbol,
|
|
35
|
+
$numberInt: int_32_1.Int32,
|
|
36
|
+
$numberDecimal: decimal128_1.Decimal128,
|
|
37
|
+
$numberDouble: double_1.Double,
|
|
38
|
+
$numberLong: long_1.Long,
|
|
39
|
+
$minKey: min_key_1.MinKey,
|
|
40
|
+
$maxKey: max_key_1.MaxKey,
|
|
41
|
+
$regex: regexp_1.BSONRegExp,
|
|
42
|
+
$regularExpression: regexp_1.BSONRegExp,
|
|
43
|
+
$timestamp: timestamp_1.Timestamp
|
|
38
44
|
};
|
|
39
|
-
|
|
40
|
-
function deserializeValue(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
+
function deserializeValue(value, options = {}) {
|
|
47
|
+
if (typeof value === 'number') {
|
|
48
|
+
if (options.relaxed || options.legacy) {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
// if it's an integer, should interpret as smallest BSON integer
|
|
52
|
+
// that can represent it exactly. (if out of range, interpret as double.)
|
|
53
|
+
if (Math.floor(value) === value) {
|
|
54
|
+
if (value >= BSON_INT32_MIN && value <= BSON_INT32_MAX)
|
|
55
|
+
return new int_32_1.Int32(value);
|
|
56
|
+
if (value >= BSON_INT64_MIN && value <= BSON_INT64_MAX)
|
|
57
|
+
return long_1.Long.fromNumber(value);
|
|
58
|
+
}
|
|
59
|
+
// If the number is a non-integer or out of integer range, should interpret as BSON Double.
|
|
60
|
+
return new double_1.Double(value);
|
|
44
61
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
62
|
+
// from here on out we're looking for bson types, so bail if its not an object
|
|
63
|
+
if (value == null || typeof value !== 'object')
|
|
64
|
+
return value;
|
|
65
|
+
// upgrade deprecated undefined to null
|
|
66
|
+
if (value.$undefined)
|
|
67
|
+
return null;
|
|
68
|
+
const keys = Object.keys(value).filter(k => k.startsWith('$') && value[k] != null);
|
|
69
|
+
for (let i = 0; i < keys.length; i++) {
|
|
70
|
+
const c = keysToCodecs[keys[i]];
|
|
71
|
+
if (c)
|
|
72
|
+
return c.fromExtendedJSON(value, options);
|
|
51
73
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const d = value.$date;
|
|
71
|
-
const date = new Date();
|
|
72
|
-
|
|
73
|
-
if (options.legacy) {
|
|
74
|
-
if (typeof d === 'number') date.setTime(d);
|
|
75
|
-
else if (typeof d === 'string') date.setTime(Date.parse(d));
|
|
76
|
-
} else {
|
|
77
|
-
if (typeof d === 'string') date.setTime(Date.parse(d));
|
|
78
|
-
else if (Long.isLong(d)) date.setTime(d.toNumber());
|
|
79
|
-
else if (typeof d === 'number' && options.relaxed) date.setTime(d);
|
|
74
|
+
if (value.$date != null) {
|
|
75
|
+
const d = value.$date;
|
|
76
|
+
const date = new Date();
|
|
77
|
+
if (options.legacy) {
|
|
78
|
+
if (typeof d === 'number')
|
|
79
|
+
date.setTime(d);
|
|
80
|
+
else if (typeof d === 'string')
|
|
81
|
+
date.setTime(Date.parse(d));
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
if (typeof d === 'string')
|
|
85
|
+
date.setTime(Date.parse(d));
|
|
86
|
+
else if (long_1.Long.isLong(d))
|
|
87
|
+
date.setTime(d.toNumber());
|
|
88
|
+
else if (typeof d === 'number' && options.relaxed)
|
|
89
|
+
date.setTime(d);
|
|
90
|
+
}
|
|
91
|
+
return date;
|
|
80
92
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
copy.$scope = deserializeValue(self, null, value.$scope);
|
|
93
|
+
if (value.$code != null) {
|
|
94
|
+
const copy = Object.assign({}, value);
|
|
95
|
+
if (value.$scope) {
|
|
96
|
+
copy.$scope = deserializeValue(value.$scope);
|
|
97
|
+
}
|
|
98
|
+
return code_1.Code.fromExtendedJSON(value);
|
|
88
99
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// only make DBRef if $ keys are all valid
|
|
107
|
-
if (valid) return DBRef.fromExtendedJSON(v);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return value;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Parse an Extended JSON string, constructing the JavaScript value or object described by that
|
|
115
|
-
* string.
|
|
116
|
-
*
|
|
117
|
-
* @memberof EJSON
|
|
118
|
-
* @param {string} text
|
|
119
|
-
* @param {object} [options] Optional settings
|
|
120
|
-
* @param {boolean} [options.relaxed=true] Attempt to return native JS types where possible, rather than BSON types (if true)
|
|
121
|
-
* @return {object}
|
|
122
|
-
*
|
|
123
|
-
* @example
|
|
124
|
-
* const { EJSON } = require('bson');
|
|
125
|
-
* const text = '{ "int32": { "$numberInt": "10" } }';
|
|
126
|
-
*
|
|
127
|
-
* // prints { int32: { [String: '10'] _bsontype: 'Int32', value: '10' } }
|
|
128
|
-
* console.log(EJSON.parse(text, { relaxed: false }));
|
|
129
|
-
*
|
|
130
|
-
* // prints { int32: 10 }
|
|
131
|
-
* console.log(EJSON.parse(text));
|
|
132
|
-
*/
|
|
133
|
-
function parse(text, options) {
|
|
134
|
-
options = Object.assign({}, { relaxed: true, legacy: false }, options);
|
|
135
|
-
|
|
136
|
-
// relaxed implies not strict
|
|
137
|
-
if (typeof options.relaxed === 'boolean') options.strict = !options.relaxed;
|
|
138
|
-
if (typeof options.strict === 'boolean') options.relaxed = !options.strict;
|
|
139
|
-
|
|
140
|
-
return JSON.parse(text, (key, value) => deserializeValue(this, key, value, options));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
//
|
|
144
|
-
// Serializer
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
// MAX INT32 boundaries
|
|
148
|
-
const BSON_INT32_MAX = 0x7fffffff,
|
|
149
|
-
BSON_INT32_MIN = -0x80000000,
|
|
150
|
-
BSON_INT64_MAX = 0x7fffffffffffffff,
|
|
151
|
-
BSON_INT64_MIN = -0x8000000000000000;
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Converts a BSON document to an Extended JSON string, optionally replacing values if a replacer
|
|
155
|
-
* function is specified or optionally including only the specified properties if a replacer array
|
|
156
|
-
* is specified.
|
|
157
|
-
*
|
|
158
|
-
* @memberof EJSON
|
|
159
|
-
* @param {object} value The value to convert to extended JSON
|
|
160
|
-
* @param {function|array} [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
|
|
161
|
-
* @param {string|number} [space] A String or Number object that's used to insert white space into the output JSON string for readability purposes.
|
|
162
|
-
* @param {object} [options] Optional settings
|
|
163
|
-
* @param {boolean} [options.relaxed=true] Enabled Extended JSON's `relaxed` mode
|
|
164
|
-
* @param {boolean} [options.legacy=false] Output using the Extended JSON v1 spec
|
|
165
|
-
* @returns {string}
|
|
166
|
-
*
|
|
167
|
-
* @example
|
|
168
|
-
* const { EJSON } = require('bson');
|
|
169
|
-
* const Int32 = require('mongodb').Int32;
|
|
170
|
-
* const doc = { int32: new Int32(10) };
|
|
171
|
-
*
|
|
172
|
-
* // prints '{"int32":{"$numberInt":"10"}}'
|
|
173
|
-
* console.log(EJSON.stringify(doc, { relaxed: false }));
|
|
174
|
-
*
|
|
175
|
-
* // prints '{"int32":10}'
|
|
176
|
-
* console.log(EJSON.stringify(doc));
|
|
177
|
-
*/
|
|
178
|
-
function stringify(value, replacer, space, options) {
|
|
179
|
-
if (space != null && typeof space === 'object') {
|
|
180
|
-
options = space;
|
|
181
|
-
space = 0;
|
|
182
|
-
}
|
|
183
|
-
if (replacer != null && typeof replacer === 'object' && !Array.isArray(replacer)) {
|
|
184
|
-
options = replacer;
|
|
185
|
-
replacer = null;
|
|
186
|
-
space = 0;
|
|
187
|
-
}
|
|
188
|
-
options = Object.assign({}, { relaxed: true, legacy: false }, options);
|
|
189
|
-
|
|
190
|
-
const doc = Array.isArray(value)
|
|
191
|
-
? serializeArray(value, options)
|
|
192
|
-
: serializeDocument(value, options);
|
|
193
|
-
|
|
194
|
-
return JSON.stringify(doc, replacer, space);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Serializes an object to an Extended JSON string, and reparse it as a JavaScript object.
|
|
199
|
-
*
|
|
200
|
-
* @memberof EJSON
|
|
201
|
-
* @param {object} bson The object to serialize
|
|
202
|
-
* @param {object} [options] Optional settings passed to the `stringify` function
|
|
203
|
-
* @return {object}
|
|
204
|
-
*/
|
|
205
|
-
function serialize(bson, options) {
|
|
206
|
-
options = options || {};
|
|
207
|
-
return JSON.parse(stringify(bson, options));
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Deserializes an Extended JSON object into a plain JavaScript object with native/BSON types
|
|
212
|
-
*
|
|
213
|
-
* @memberof EJSON
|
|
214
|
-
* @param {object} ejson The Extended JSON object to deserialize
|
|
215
|
-
* @param {object} [options] Optional settings passed to the parse method
|
|
216
|
-
* @return {object}
|
|
217
|
-
*/
|
|
218
|
-
function deserialize(ejson, options) {
|
|
219
|
-
options = options || {};
|
|
220
|
-
return parse(JSON.stringify(ejson), options);
|
|
100
|
+
if (value.$ref != null || value.$dbPointer != null) {
|
|
101
|
+
const v = value.$ref ? value : value.$dbPointer;
|
|
102
|
+
// we run into this in a "degenerate EJSON" case (with $id and $ref order flipped)
|
|
103
|
+
// because of the order JSON.parse goes through the document
|
|
104
|
+
if (v instanceof db_ref_1.DBRef)
|
|
105
|
+
return v;
|
|
106
|
+
const dollarKeys = Object.keys(v).filter(k => k.startsWith('$'));
|
|
107
|
+
let valid = true;
|
|
108
|
+
dollarKeys.forEach(k => {
|
|
109
|
+
if (['$ref', '$id', '$db'].indexOf(k) === -1)
|
|
110
|
+
valid = false;
|
|
111
|
+
});
|
|
112
|
+
// only make DBRef if $ keys are all valid
|
|
113
|
+
if (valid)
|
|
114
|
+
return db_ref_1.DBRef.fromExtendedJSON(v);
|
|
115
|
+
}
|
|
116
|
+
return value;
|
|
221
117
|
}
|
|
222
|
-
|
|
118
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
223
119
|
function serializeArray(array, options) {
|
|
224
|
-
|
|
120
|
+
return array.map((v) => serializeValue(v, options));
|
|
225
121
|
}
|
|
226
|
-
|
|
227
122
|
function getISOString(date) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
123
|
+
const isoStr = date.toISOString();
|
|
124
|
+
// we should only show milliseconds in timestamp if they're non-zero
|
|
125
|
+
return date.getUTCMilliseconds() !== 0 ? isoStr : isoStr.slice(0, -5) + 'Z';
|
|
231
126
|
}
|
|
232
|
-
|
|
127
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
233
128
|
function serializeValue(value, options) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
129
|
+
if (Array.isArray(value))
|
|
130
|
+
return serializeArray(value, options);
|
|
131
|
+
if (value === undefined)
|
|
132
|
+
return null;
|
|
133
|
+
if (value instanceof Date) {
|
|
134
|
+
const dateNum = value.getTime(),
|
|
135
|
+
// is it in year range 1970-9999?
|
|
136
|
+
inRange = dateNum > -1 && dateNum < 253402318800000;
|
|
137
|
+
if (options.legacy) {
|
|
138
|
+
return options.relaxed && inRange
|
|
139
|
+
? { $date: value.getTime() }
|
|
140
|
+
: { $date: getISOString(value) };
|
|
141
|
+
}
|
|
142
|
+
return options.relaxed && inRange
|
|
143
|
+
? { $date: getISOString(value) }
|
|
144
|
+
: { $date: { $numberLong: value.getTime().toString() } };
|
|
247
145
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// interpret as being of the smallest BSON integer type that can represent the number exactly
|
|
260
|
-
if (int32Range) return { $numberInt: value.toString() };
|
|
261
|
-
if (int64Range) return { $numberLong: value.toString() };
|
|
146
|
+
if (typeof value === 'number' && !options.relaxed) {
|
|
147
|
+
// it's an integer
|
|
148
|
+
if (Math.floor(value) === value) {
|
|
149
|
+
const int32Range = value >= BSON_INT32_MIN && value <= BSON_INT32_MAX, int64Range = value >= BSON_INT64_MIN && value <= BSON_INT64_MAX;
|
|
150
|
+
// interpret as being of the smallest BSON integer type that can represent the number exactly
|
|
151
|
+
if (int32Range)
|
|
152
|
+
return { $numberInt: value.toString() };
|
|
153
|
+
if (int64Range)
|
|
154
|
+
return { $numberLong: value.toString() };
|
|
155
|
+
}
|
|
156
|
+
return { $numberDouble: value.toString() };
|
|
262
157
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
158
|
+
if (value instanceof RegExp) {
|
|
159
|
+
let flags = value.flags;
|
|
160
|
+
if (flags === undefined) {
|
|
161
|
+
const match = value.toString().match(/[gimuy]*$/);
|
|
162
|
+
if (match) {
|
|
163
|
+
flags = match[0];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const rx = new regexp_1.BSONRegExp(value.source, flags);
|
|
167
|
+
return rx.toExtendedJSON(options);
|
|
270
168
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
return
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (value != null && typeof value === 'object') return serializeDocument(value, options);
|
|
277
|
-
return value;
|
|
169
|
+
if (value != null && typeof value === 'object')
|
|
170
|
+
return serializeDocument(value, options);
|
|
171
|
+
return value;
|
|
278
172
|
}
|
|
279
|
-
|
|
280
173
|
const BSON_TYPE_MAPPINGS = {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
),
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
ObjectId: o => new ObjectId(o), // support 4.0.0/4.0.1 before _bsontype was reverted back to ObjectID
|
|
298
|
-
BSONRegExp: o => new BSONRegExp(o.pattern, o.options),
|
|
299
|
-
Symbol: o => new Symbol(o.value),
|
|
300
|
-
Timestamp: o => Timestamp.fromBits(o.low, o.high)
|
|
174
|
+
Binary: (o) => new binary_1.Binary(o.value(), o.sub_type),
|
|
175
|
+
Code: (o) => new code_1.Code(o.code, o.scope),
|
|
176
|
+
DBRef: (o) => new db_ref_1.DBRef(o.collection || o.namespace, o.oid, o.db, o.fields),
|
|
177
|
+
Decimal128: (o) => new decimal128_1.Decimal128(o.bytes),
|
|
178
|
+
Double: (o) => new double_1.Double(o.value),
|
|
179
|
+
Int32: (o) => new int_32_1.Int32(o.value),
|
|
180
|
+
Long: (o) => long_1.Long.fromBits(
|
|
181
|
+
// underscore variants for 1.x backwards compatibility
|
|
182
|
+
o.low != null ? o.low : o.low_, o.low != null ? o.high : o.high_, o.low != null ? o.unsigned : o.unsigned_),
|
|
183
|
+
MaxKey: () => new max_key_1.MaxKey(),
|
|
184
|
+
MinKey: () => new min_key_1.MinKey(),
|
|
185
|
+
ObjectID: (o) => new objectid_1.ObjectId(o),
|
|
186
|
+
ObjectId: (o) => new objectid_1.ObjectId(o),
|
|
187
|
+
BSONRegExp: (o) => new regexp_1.BSONRegExp(o.pattern, o.options),
|
|
188
|
+
Symbol: (o) => new symbol_1.BSONSymbol(o.value),
|
|
189
|
+
Timestamp: (o) => timestamp_1.Timestamp.fromBits(o.low, o.high)
|
|
301
190
|
};
|
|
302
|
-
|
|
191
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
303
192
|
function serializeDocument(doc, options) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
193
|
+
if (doc == null || typeof doc !== 'object')
|
|
194
|
+
throw new Error('not an object instance');
|
|
195
|
+
const bsontype = doc._bsontype;
|
|
196
|
+
if (typeof bsontype === 'undefined') {
|
|
197
|
+
// It's a regular object. Recursively serialize its property values.
|
|
198
|
+
const _doc = {};
|
|
199
|
+
for (const name in doc) {
|
|
200
|
+
_doc[name] = serializeValue(doc[name], options);
|
|
201
|
+
}
|
|
202
|
+
return _doc;
|
|
312
203
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
204
|
+
else if (isBSONType(doc)) {
|
|
205
|
+
// the "document" is really just a BSON type object
|
|
206
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
207
|
+
let outDoc = doc;
|
|
208
|
+
if (typeof outDoc.toExtendedJSON !== 'function') {
|
|
209
|
+
// There's no EJSON serialization function on the object. It's probably an
|
|
210
|
+
// object created by a previous version of this library (or another library)
|
|
211
|
+
// that's duck-typing objects to look like they were generated by this library).
|
|
212
|
+
// Copy the object into this library's version of that type.
|
|
213
|
+
const mapper = BSON_TYPE_MAPPINGS[doc._bsontype];
|
|
214
|
+
if (!mapper) {
|
|
215
|
+
throw new TypeError('Unrecognized or invalid _bsontype: ' + doc._bsontype);
|
|
216
|
+
}
|
|
217
|
+
outDoc = mapper(outDoc);
|
|
218
|
+
}
|
|
219
|
+
// Two BSON types may have nested objects that may need to be serialized too
|
|
220
|
+
if (bsontype === 'Code' && outDoc.scope) {
|
|
221
|
+
outDoc = new code_1.Code(outDoc.code, serializeValue(outDoc.scope, options));
|
|
222
|
+
}
|
|
223
|
+
else if (bsontype === 'DBRef' && outDoc.oid) {
|
|
224
|
+
outDoc = new db_ref_1.DBRef(outDoc.collection, serializeValue(outDoc.oid, options), outDoc.db, outDoc.fields);
|
|
225
|
+
}
|
|
226
|
+
return outDoc.toExtendedJSON(options);
|
|
327
227
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if (bsontype === 'Code' && _doc.scope) {
|
|
331
|
-
_doc = new Code(_doc.code, serializeValue(_doc.scope, options));
|
|
332
|
-
} else if (bsontype === 'DBRef' && _doc.oid) {
|
|
333
|
-
_doc = new DBRef(_doc.collection, serializeValue(_doc.oid, options), _doc.db, _doc.fields);
|
|
228
|
+
else {
|
|
229
|
+
throw new Error('_bsontype must be a string, but was: ' + typeof bsontype);
|
|
334
230
|
}
|
|
335
|
-
|
|
336
|
-
return _doc.toExtendedJSON(options);
|
|
337
|
-
} else {
|
|
338
|
-
throw new Error('_bsontype must be a string, but was: ' + typeof bsontype);
|
|
339
|
-
}
|
|
340
231
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
232
|
+
/**
|
|
233
|
+
* EJSON parse / stringify API
|
|
234
|
+
* @public
|
|
235
|
+
*/
|
|
236
|
+
// the namespace here is used to emulate `export * as EJSON from '...'`
|
|
237
|
+
// which as of now (sept 2020) api-extractor does not support
|
|
238
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
239
|
+
var EJSON;
|
|
240
|
+
(function (EJSON) {
|
|
241
|
+
/**
|
|
242
|
+
* Parse an Extended JSON string, constructing the JavaScript value or object described by that
|
|
243
|
+
* string.
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```js
|
|
247
|
+
* const { EJSON } = require('bson');
|
|
248
|
+
* const text = '{ "int32": { "$numberInt": "10" } }';
|
|
249
|
+
*
|
|
250
|
+
* // prints { int32: { [String: '10'] _bsontype: 'Int32', value: '10' } }
|
|
251
|
+
* console.log(EJSON.parse(text, { relaxed: false }));
|
|
252
|
+
*
|
|
253
|
+
* // prints { int32: 10 }
|
|
254
|
+
* console.log(EJSON.parse(text));
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
function parse(text, options) {
|
|
258
|
+
const finalOptions = Object.assign({}, { relaxed: true, legacy: false }, options);
|
|
259
|
+
// relaxed implies not strict
|
|
260
|
+
if (typeof finalOptions.relaxed === 'boolean')
|
|
261
|
+
finalOptions.strict = !finalOptions.relaxed;
|
|
262
|
+
if (typeof finalOptions.strict === 'boolean')
|
|
263
|
+
finalOptions.relaxed = !finalOptions.strict;
|
|
264
|
+
return JSON.parse(text, (_key, value) => deserializeValue(value, finalOptions));
|
|
265
|
+
}
|
|
266
|
+
EJSON.parse = parse;
|
|
267
|
+
/**
|
|
268
|
+
* Converts a BSON document to an Extended JSON string, optionally replacing values if a replacer
|
|
269
|
+
* function is specified or optionally including only the specified properties if a replacer array
|
|
270
|
+
* is specified.
|
|
271
|
+
*
|
|
272
|
+
* @param value - The value to convert to extended JSON
|
|
273
|
+
* @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
|
|
274
|
+
* @param space - A String or Number object that's used to insert white space into the output JSON string for readability purposes.
|
|
275
|
+
* @param options - Optional settings
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```js
|
|
279
|
+
* const { EJSON } = require('bson');
|
|
280
|
+
* const Int32 = require('mongodb').Int32;
|
|
281
|
+
* const doc = { int32: new Int32(10) };
|
|
282
|
+
*
|
|
283
|
+
* // prints '{"int32":{"$numberInt":"10"}}'
|
|
284
|
+
* console.log(EJSON.stringify(doc, { relaxed: false }));
|
|
285
|
+
*
|
|
286
|
+
* // prints '{"int32":10}'
|
|
287
|
+
* console.log(EJSON.stringify(doc));
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
function stringify(value,
|
|
291
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
292
|
+
replacer, space, options) {
|
|
293
|
+
if (space != null && typeof space === 'object') {
|
|
294
|
+
options = space;
|
|
295
|
+
space = 0;
|
|
296
|
+
}
|
|
297
|
+
if (replacer != null && typeof replacer === 'object' && !Array.isArray(replacer)) {
|
|
298
|
+
options = replacer;
|
|
299
|
+
replacer = undefined;
|
|
300
|
+
space = 0;
|
|
301
|
+
}
|
|
302
|
+
options = Object.assign({}, { relaxed: true, legacy: false }, options);
|
|
303
|
+
const doc = serializeValue(value, options);
|
|
304
|
+
return JSON.stringify(doc, replacer, space);
|
|
305
|
+
}
|
|
306
|
+
EJSON.stringify = stringify;
|
|
307
|
+
/**
|
|
308
|
+
* Serializes an object to an Extended JSON string, and reparse it as a JavaScript object.
|
|
309
|
+
*
|
|
310
|
+
* @param value - The object to serialize
|
|
311
|
+
* @param options - Optional settings passed to the `stringify` function
|
|
312
|
+
*/
|
|
313
|
+
function serialize(value, options) {
|
|
314
|
+
options = options || {};
|
|
315
|
+
return JSON.parse(stringify(value, options));
|
|
316
|
+
}
|
|
317
|
+
EJSON.serialize = serialize;
|
|
318
|
+
/**
|
|
319
|
+
* Deserializes an Extended JSON object into a plain JavaScript object with native/BSON types
|
|
320
|
+
*
|
|
321
|
+
* @param ejson - The Extended JSON object to deserialize
|
|
322
|
+
* @param options - Optional settings passed to the parse method
|
|
323
|
+
*/
|
|
324
|
+
function deserialize(ejson, options) {
|
|
325
|
+
options = options || {};
|
|
326
|
+
return parse(JSON.stringify(ejson), options);
|
|
327
|
+
}
|
|
328
|
+
EJSON.deserialize = deserialize;
|
|
329
|
+
})(EJSON = exports.EJSON || (exports.EJSON = {}));
|
|
330
|
+
//# sourceMappingURL=extended_json.js.map
|