mongodb-livedata-server 0.0.4 → 0.0.6
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/{livedata_server.ts → dist/livedata_server.d.ts} +1 -1
- package/dist/livedata_server.js +3 -1
- package/dist/meteor/binary-heap/max_heap.d.ts +31 -0
- package/dist/meteor/binary-heap/min_heap.d.ts +6 -0
- package/dist/meteor/binary-heap/min_max_heap.d.ts +11 -0
- package/dist/meteor/callback-hook/hook.d.ts +11 -0
- package/dist/meteor/ddp/crossbar.d.ts +15 -0
- package/dist/meteor/ddp/heartbeat.d.ts +19 -0
- package/dist/meteor/ddp/livedata_server.d.ts +141 -0
- package/dist/meteor/ddp/method-invocation.d.ts +25 -0
- package/dist/meteor/ddp/random-stream.d.ts +8 -0
- package/dist/meteor/ddp/session-collection-view.d.ts +27 -0
- package/dist/meteor/ddp/session-document-view.d.ts +8 -0
- package/dist/meteor/ddp/session.d.ts +69 -0
- package/dist/meteor/ddp/stream_server.d.ts +21 -0
- package/dist/meteor/ddp/subscription.d.ts +89 -0
- package/dist/meteor/ddp/utils.d.ts +8 -0
- package/dist/meteor/ddp/writefence.d.ts +20 -0
- package/dist/meteor/diff-sequence/diff.d.ts +13 -0
- package/dist/meteor/ejson/ejson.d.ts +82 -0
- package/dist/meteor/ejson/stringify.d.ts +2 -0
- package/dist/meteor/ejson/utils.d.ts +12 -0
- package/dist/meteor/id-map/id_map.d.ts +16 -0
- package/dist/meteor/mongo/caching_change_observer.d.ts +16 -0
- package/dist/meteor/mongo/doc_fetcher.d.ts +7 -0
- package/dist/meteor/mongo/geojson_utils.d.ts +3 -0
- package/dist/meteor/mongo/live_connection.d.ts +27 -0
- package/dist/meteor/mongo/live_cursor.d.ts +25 -0
- package/dist/meteor/mongo/minimongo_common.d.ts +84 -0
- package/dist/meteor/mongo/minimongo_matcher.d.ts +22 -0
- package/dist/meteor/mongo/minimongo_sorter.d.ts +16 -0
- package/dist/meteor/mongo/observe_driver_utils.d.ts +9 -0
- package/dist/meteor/mongo/observe_multiplexer.d.ts +36 -0
- package/dist/meteor/mongo/oplog-observe-driver.d.ts +67 -0
- package/dist/meteor/mongo/oplog_tailing.d.ts +35 -0
- package/dist/meteor/mongo/oplog_v2_converter.d.ts +1 -0
- package/dist/meteor/mongo/polling_observe_driver.d.ts +30 -0
- package/dist/meteor/mongo/synchronous-cursor.d.ts +17 -0
- package/dist/meteor/mongo/synchronous-queue.d.ts +14 -0
- package/dist/meteor/ordered-dict/ordered_dict.d.ts +31 -0
- package/dist/meteor/random/AbstractRandomGenerator.d.ts +42 -0
- package/dist/meteor/random/AleaRandomGenerator.d.ts +13 -0
- package/dist/meteor/random/NodeRandomGenerator.d.ts +16 -0
- package/dist/meteor/random/createAleaGenerator.d.ts +2 -0
- package/dist/meteor/random/createRandom.d.ts +1 -0
- package/dist/meteor/random/main.d.ts +1 -0
- package/package.json +2 -2
- package/meteor/LICENSE +0 -28
- package/meteor/binary-heap/max_heap.ts +0 -225
- package/meteor/binary-heap/min_heap.ts +0 -15
- package/meteor/binary-heap/min_max_heap.ts +0 -53
- package/meteor/callback-hook/hook.ts +0 -85
- package/meteor/ddp/crossbar.ts +0 -148
- package/meteor/ddp/heartbeat.ts +0 -97
- package/meteor/ddp/livedata_server.ts +0 -474
- package/meteor/ddp/method-invocation.ts +0 -86
- package/meteor/ddp/random-stream.ts +0 -102
- package/meteor/ddp/session-collection-view.ts +0 -119
- package/meteor/ddp/session-document-view.ts +0 -92
- package/meteor/ddp/session.ts +0 -708
- package/meteor/ddp/stream_server.ts +0 -204
- package/meteor/ddp/subscription.ts +0 -392
- package/meteor/ddp/utils.ts +0 -119
- package/meteor/ddp/writefence.ts +0 -130
- package/meteor/diff-sequence/diff.ts +0 -295
- package/meteor/ejson/ejson.ts +0 -601
- package/meteor/ejson/stringify.ts +0 -122
- package/meteor/ejson/utils.ts +0 -38
- package/meteor/id-map/id_map.ts +0 -84
- package/meteor/mongo/caching_change_observer.ts +0 -120
- package/meteor/mongo/doc_fetcher.ts +0 -52
- package/meteor/mongo/geojson_utils.ts +0 -42
- package/meteor/mongo/live_connection.ts +0 -302
- package/meteor/mongo/live_cursor.ts +0 -79
- package/meteor/mongo/minimongo_common.ts +0 -2440
- package/meteor/mongo/minimongo_matcher.ts +0 -275
- package/meteor/mongo/minimongo_sorter.ts +0 -331
- package/meteor/mongo/observe_driver_utils.ts +0 -79
- package/meteor/mongo/observe_multiplexer.ts +0 -256
- package/meteor/mongo/oplog-observe-driver.ts +0 -1049
- package/meteor/mongo/oplog_tailing.ts +0 -414
- package/meteor/mongo/oplog_v2_converter.ts +0 -124
- package/meteor/mongo/polling_observe_driver.ts +0 -247
- package/meteor/mongo/synchronous-cursor.ts +0 -293
- package/meteor/mongo/synchronous-queue.ts +0 -119
- package/meteor/ordered-dict/ordered_dict.ts +0 -229
- package/meteor/random/AbstractRandomGenerator.ts +0 -99
- package/meteor/random/AleaRandomGenerator.ts +0 -96
- package/meteor/random/NodeRandomGenerator.ts +0 -37
- package/meteor/random/createAleaGenerator.ts +0 -31
- package/meteor/random/createRandom.ts +0 -19
- package/meteor/random/main.ts +0 -8
- package/tsconfig.json +0 -10
package/meteor/ejson/ejson.ts
DELETED
|
@@ -1,601 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
isFunction,
|
|
3
|
-
isObject,
|
|
4
|
-
keysOf,
|
|
5
|
-
lengthOf,
|
|
6
|
-
hasOwn,
|
|
7
|
-
convertMapToObject,
|
|
8
|
-
isArguments,
|
|
9
|
-
isInfOrNaN,
|
|
10
|
-
handleError,
|
|
11
|
-
} from './utils';
|
|
12
|
-
import canonicalStringify from './stringify';
|
|
13
|
-
|
|
14
|
-
// Custom type interface definition
|
|
15
|
-
/**
|
|
16
|
-
* @class CustomType
|
|
17
|
-
* @instanceName customType
|
|
18
|
-
* @memberOf EJSON
|
|
19
|
-
* @summary The interface that a class must satisfy to be able to become an
|
|
20
|
-
* EJSON custom type via EJSON.addType.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @function typeName
|
|
25
|
-
* @memberOf EJSON.CustomType
|
|
26
|
-
* @summary Return the tag used to identify this type. This must match the
|
|
27
|
-
* tag used to register this type with
|
|
28
|
-
* [`EJSON.addType`](#ejson_add_type).
|
|
29
|
-
* @locus Anywhere
|
|
30
|
-
* @instance
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @function toJSONValue
|
|
35
|
-
* @memberOf EJSON.CustomType
|
|
36
|
-
* @summary Serialize this instance into a JSON-compatible value.
|
|
37
|
-
* @locus Anywhere
|
|
38
|
-
* @instance
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @function clone
|
|
43
|
-
* @memberOf EJSON.CustomType
|
|
44
|
-
* @summary Return a value `r` such that `this.equals(r)` is true, and
|
|
45
|
-
* modifications to `r` do not affect `this` and vice versa.
|
|
46
|
-
* @locus Anywhere
|
|
47
|
-
* @instance
|
|
48
|
-
*/
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* @function equals
|
|
52
|
-
* @memberOf EJSON.CustomType
|
|
53
|
-
* @summary Return `true` if `other` has a value equal to `this`; `false`
|
|
54
|
-
* otherwise.
|
|
55
|
-
* @locus Anywhere
|
|
56
|
-
* @param {Object} other Another object to compare this to.
|
|
57
|
-
* @instance
|
|
58
|
-
*/
|
|
59
|
-
|
|
60
|
-
const customTypes = new Map();
|
|
61
|
-
|
|
62
|
-
// Add a custom type, using a method of your choice to get to and
|
|
63
|
-
// from a basic JSON-able representation. The factory argument
|
|
64
|
-
// is a function of JSON-able --> your object
|
|
65
|
-
// The type you add must have:
|
|
66
|
-
// - A toJSONValue() method, so that Meteor can serialize it
|
|
67
|
-
// - a typeName() method, to show how to look it up in our type table.
|
|
68
|
-
// It is okay if these methods are monkey-patched on.
|
|
69
|
-
// EJSON.clone will use toJSONValue and the given factory to produce
|
|
70
|
-
// a clone, but you may specify a method clone() that will be
|
|
71
|
-
// used instead.
|
|
72
|
-
// Similarly, EJSON.equals will use toJSONValue to make comparisons,
|
|
73
|
-
// but you may provide a method equals() instead.
|
|
74
|
-
/**
|
|
75
|
-
* @summary Add a custom datatype to EJSON.
|
|
76
|
-
* @locus Anywhere
|
|
77
|
-
* @param {String} name A tag for your custom type; must be unique among
|
|
78
|
-
* custom data types defined in your project, and must
|
|
79
|
-
* match the result of your type's `typeName` method.
|
|
80
|
-
* @param {Function} factory A function that deserializes a JSON-compatible
|
|
81
|
-
* value into an instance of your type. This should
|
|
82
|
-
* match the serialization performed by your
|
|
83
|
-
* type's `toJSONValue` method.
|
|
84
|
-
*/
|
|
85
|
-
export function addType(name, factory) {
|
|
86
|
-
if (customTypes.has(name)) {
|
|
87
|
-
throw new Error(`Type ${name} already present`);
|
|
88
|
-
}
|
|
89
|
-
customTypes.set(name, factory);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const builtinConverters = [
|
|
93
|
-
{ // Date
|
|
94
|
-
matchJSONValue(obj) {
|
|
95
|
-
return hasOwn(obj, '$date') && lengthOf(obj) === 1;
|
|
96
|
-
},
|
|
97
|
-
matchObject(obj) {
|
|
98
|
-
return obj instanceof Date;
|
|
99
|
-
},
|
|
100
|
-
toJSONValue(obj) {
|
|
101
|
-
return { $date: obj.getTime() };
|
|
102
|
-
},
|
|
103
|
-
fromJSONValue(obj) {
|
|
104
|
-
return new Date(obj.$date);
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
{ // RegExp
|
|
108
|
-
matchJSONValue(obj) {
|
|
109
|
-
return hasOwn(obj, '$regexp')
|
|
110
|
-
&& hasOwn(obj, '$flags')
|
|
111
|
-
&& lengthOf(obj) === 2;
|
|
112
|
-
},
|
|
113
|
-
matchObject(obj) {
|
|
114
|
-
return obj instanceof RegExp;
|
|
115
|
-
},
|
|
116
|
-
toJSONValue(regexp) {
|
|
117
|
-
return {
|
|
118
|
-
$regexp: regexp.source,
|
|
119
|
-
$flags: regexp.flags
|
|
120
|
-
};
|
|
121
|
-
},
|
|
122
|
-
fromJSONValue(obj) {
|
|
123
|
-
// Replaces duplicate / invalid flags.
|
|
124
|
-
return new RegExp(
|
|
125
|
-
obj.$regexp,
|
|
126
|
-
obj.$flags
|
|
127
|
-
// Cut off flags at 50 chars to avoid abusing RegExp for DOS.
|
|
128
|
-
.slice(0, 50)
|
|
129
|
-
.replace(/[^gimuy]/g, '')
|
|
130
|
-
.replace(/(.)(?=.*\1)/g, '')
|
|
131
|
-
);
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
{ // NaN, Inf, -Inf. (These are the only objects with typeof !== 'object'
|
|
135
|
-
// which we match.)
|
|
136
|
-
matchJSONValue(obj) {
|
|
137
|
-
return hasOwn(obj, '$InfNaN') && lengthOf(obj) === 1;
|
|
138
|
-
},
|
|
139
|
-
matchObject: isInfOrNaN,
|
|
140
|
-
toJSONValue(obj) {
|
|
141
|
-
let sign;
|
|
142
|
-
if (Number.isNaN(obj)) {
|
|
143
|
-
sign = 0;
|
|
144
|
-
} else if (obj === Infinity) {
|
|
145
|
-
sign = 1;
|
|
146
|
-
} else {
|
|
147
|
-
sign = -1;
|
|
148
|
-
}
|
|
149
|
-
return { $InfNaN: sign };
|
|
150
|
-
},
|
|
151
|
-
fromJSONValue(obj) {
|
|
152
|
-
return obj.$InfNaN / 0;
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
{ // Binary
|
|
156
|
-
matchJSONValue(obj) {
|
|
157
|
-
return hasOwn(obj, '$binary') && lengthOf(obj) === 1;
|
|
158
|
-
},
|
|
159
|
-
matchObject(obj) {
|
|
160
|
-
return typeof Uint8Array !== 'undefined' && obj instanceof Uint8Array
|
|
161
|
-
|| (obj && hasOwn(obj, '$Uint8ArrayPolyfill'));
|
|
162
|
-
},
|
|
163
|
-
toJSONValue(obj) {
|
|
164
|
-
return { $binary: Buffer.from(obj).toString("base64") };
|
|
165
|
-
},
|
|
166
|
-
fromJSONValue(obj) {
|
|
167
|
-
return Buffer.from(obj.$binary, "base64").toString();
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
{ // Escaping one level
|
|
171
|
-
matchJSONValue(obj) {
|
|
172
|
-
return hasOwn(obj, '$escape') && lengthOf(obj) === 1;
|
|
173
|
-
},
|
|
174
|
-
matchObject(obj) {
|
|
175
|
-
let match = false;
|
|
176
|
-
if (obj) {
|
|
177
|
-
const keyCount = lengthOf(obj);
|
|
178
|
-
if (keyCount === 1 || keyCount === 2) {
|
|
179
|
-
match =
|
|
180
|
-
builtinConverters.some(converter => converter.matchJSONValue(obj));
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return match;
|
|
184
|
-
},
|
|
185
|
-
toJSONValue(obj) {
|
|
186
|
-
const newObj = {};
|
|
187
|
-
keysOf(obj).forEach(key => {
|
|
188
|
-
newObj[key] = toJSONValue(obj[key]);
|
|
189
|
-
});
|
|
190
|
-
return { $escape: newObj };
|
|
191
|
-
},
|
|
192
|
-
fromJSONValue(obj) {
|
|
193
|
-
const newObj = {};
|
|
194
|
-
keysOf(obj.$escape).forEach(key => {
|
|
195
|
-
newObj[key] = fromJSONValue(obj.$escape[key]);
|
|
196
|
-
});
|
|
197
|
-
return newObj;
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
{ // Custom
|
|
201
|
-
matchJSONValue(obj) {
|
|
202
|
-
return hasOwn(obj, '$type')
|
|
203
|
-
&& hasOwn(obj, '$value') && lengthOf(obj) === 2;
|
|
204
|
-
},
|
|
205
|
-
matchObject(obj) {
|
|
206
|
-
return _isCustomType(obj);
|
|
207
|
-
},
|
|
208
|
-
toJSONValue(obj) {
|
|
209
|
-
const jsonValue = obj.toJSONValue();
|
|
210
|
-
return { $type: obj.typeName(), $value: jsonValue };
|
|
211
|
-
},
|
|
212
|
-
fromJSONValue(obj) {
|
|
213
|
-
const typeName = obj.$type;
|
|
214
|
-
if (!customTypes.has(typeName)) {
|
|
215
|
-
throw new Error(`Custom EJSON type ${typeName} is not defined`);
|
|
216
|
-
}
|
|
217
|
-
const converter = customTypes.get(typeName);
|
|
218
|
-
return converter(obj.$value);
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
];
|
|
222
|
-
|
|
223
|
-
export function _isCustomType(obj) {
|
|
224
|
-
return obj &&
|
|
225
|
-
isFunction(obj.toJSONValue) &&
|
|
226
|
-
isFunction(obj.typeName) &&
|
|
227
|
-
customTypes.has(obj.typeName())
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export function _getTypes(isOriginal = false) { return (isOriginal ? customTypes : convertMapToObject(customTypes)); }
|
|
231
|
-
|
|
232
|
-
export function _getConverters() { return builtinConverters; }
|
|
233
|
-
|
|
234
|
-
// Either return the JSON-compatible version of the argument, or undefined (if
|
|
235
|
-
// the item isn't itself replaceable, but maybe some fields in it are)
|
|
236
|
-
const toJSONValueHelper = item => {
|
|
237
|
-
for (let i = 0; i < builtinConverters.length; i++) {
|
|
238
|
-
const converter = builtinConverters[i];
|
|
239
|
-
if (converter.matchObject(item)) {
|
|
240
|
-
return converter.toJSONValue(item);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return undefined;
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
// for both arrays and objects, in-place modification.
|
|
247
|
-
export function _adjustTypesToJSONValue(obj) {
|
|
248
|
-
// Is it an atom that we need to adjust?
|
|
249
|
-
if (obj === null) {
|
|
250
|
-
return null;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const maybeChanged = toJSONValueHelper(obj);
|
|
254
|
-
if (maybeChanged !== undefined) {
|
|
255
|
-
return maybeChanged;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Other atoms are unchanged.
|
|
259
|
-
if (!isObject(obj)) {
|
|
260
|
-
return obj;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Iterate over array or object structure.
|
|
264
|
-
keysOf(obj).forEach(key => {
|
|
265
|
-
const value = obj[key];
|
|
266
|
-
if (!isObject(value) && value !== undefined &&
|
|
267
|
-
!isInfOrNaN(value)) {
|
|
268
|
-
return; // continue
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const changed = toJSONValueHelper(value);
|
|
272
|
-
if (changed) {
|
|
273
|
-
obj[key] = changed;
|
|
274
|
-
return; // on to the next key
|
|
275
|
-
}
|
|
276
|
-
// if we get here, value is an object but not adjustable
|
|
277
|
-
// at this level. recurse.
|
|
278
|
-
_adjustTypesToJSONValue(value);
|
|
279
|
-
});
|
|
280
|
-
return obj;
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* @summary Serialize an EJSON-compatible value into its plain JSON
|
|
285
|
-
* representation.
|
|
286
|
-
* @locus Anywhere
|
|
287
|
-
* @param {EJSON} val A value to serialize to plain JSON.
|
|
288
|
-
*/
|
|
289
|
-
export function toJSONValue(item) {
|
|
290
|
-
const changed = toJSONValueHelper(item);
|
|
291
|
-
if (changed !== undefined) {
|
|
292
|
-
return changed;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
let newItem = item;
|
|
296
|
-
if (isObject(item)) {
|
|
297
|
-
newItem = clone(item);
|
|
298
|
-
_adjustTypesToJSONValue(newItem);
|
|
299
|
-
}
|
|
300
|
-
return newItem;
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
// Either return the argument changed to have the non-json
|
|
304
|
-
// rep of itself (the Object version) or the argument itself.
|
|
305
|
-
// DOES NOT RECURSE. For actually getting the fully-changed value, use
|
|
306
|
-
// EJSON.fromJSONValue
|
|
307
|
-
const fromJSONValueHelper = value => {
|
|
308
|
-
if (isObject(value) && value !== null) {
|
|
309
|
-
const keys = keysOf(value);
|
|
310
|
-
if (keys.length <= 2
|
|
311
|
-
&& keys.every(k => typeof k === 'string' && k.substr(0, 1) === '$')) {
|
|
312
|
-
for (let i = 0; i < builtinConverters.length; i++) {
|
|
313
|
-
const converter = builtinConverters[i];
|
|
314
|
-
if (converter.matchJSONValue(value)) {
|
|
315
|
-
return converter.fromJSONValue(value);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
return value;
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
// for both arrays and objects. Tries its best to just
|
|
324
|
-
// use the object you hand it, but may return something
|
|
325
|
-
// different if the object you hand it itself needs changing.
|
|
326
|
-
export function _adjustTypesFromJSONValue (obj) {
|
|
327
|
-
if (obj === null) {
|
|
328
|
-
return null;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const maybeChanged = fromJSONValueHelper(obj);
|
|
332
|
-
if (maybeChanged !== obj) {
|
|
333
|
-
return maybeChanged;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Other atoms are unchanged.
|
|
337
|
-
if (!isObject(obj)) {
|
|
338
|
-
return obj;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
keysOf(obj).forEach(key => {
|
|
342
|
-
const value = obj[key];
|
|
343
|
-
if (isObject(value)) {
|
|
344
|
-
const changed = fromJSONValueHelper(value);
|
|
345
|
-
if (value !== changed) {
|
|
346
|
-
obj[key] = changed;
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
// if we get here, value is an object but not adjustable
|
|
350
|
-
// at this level. recurse.
|
|
351
|
-
_adjustTypesFromJSONValue(value);
|
|
352
|
-
}
|
|
353
|
-
});
|
|
354
|
-
return obj;
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* @summary Deserialize an EJSON value from its plain JSON representation.
|
|
359
|
-
* @locus Anywhere
|
|
360
|
-
* @param {JSONCompatible} val A value to deserialize into EJSON.
|
|
361
|
-
*/
|
|
362
|
-
export function fromJSONValue(item) {
|
|
363
|
-
let changed = fromJSONValueHelper(item);
|
|
364
|
-
if (changed === item && isObject(item)) {
|
|
365
|
-
changed = clone(item);
|
|
366
|
-
_adjustTypesFromJSONValue(changed);
|
|
367
|
-
}
|
|
368
|
-
return changed;
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* @summary Serialize a value to a string. For EJSON values, the serialization
|
|
373
|
-
* fully represents the value. For non-EJSON values, serializes the
|
|
374
|
-
* same way as `JSON.stringify`.
|
|
375
|
-
* @locus Anywhere
|
|
376
|
-
* @param {EJSON} val A value to stringify.
|
|
377
|
-
* @param {Object} [options]
|
|
378
|
-
* @param {Boolean | Integer | String} options.indent Indents objects and
|
|
379
|
-
* arrays for easy readability. When `true`, indents by 2 spaces; when an
|
|
380
|
-
* integer, indents by that number of spaces; and when a string, uses the
|
|
381
|
-
* string as the indentation pattern.
|
|
382
|
-
* @param {Boolean} options.canonical When `true`, stringifies keys in an
|
|
383
|
-
* object in sorted order.
|
|
384
|
-
*/
|
|
385
|
-
export function stringify(val: any, opts?: { canonical?: boolean, indent?: boolean | number | string }) {
|
|
386
|
-
return handleError((item: any, options: { canonical?: boolean, indent?: boolean | number | string }) => {
|
|
387
|
-
let serialized: string;
|
|
388
|
-
const json = toJSONValue(item);
|
|
389
|
-
if (options && (options.canonical || options.indent)) {
|
|
390
|
-
serialized = canonicalStringify(json, options);
|
|
391
|
-
} else {
|
|
392
|
-
serialized = JSON.stringify(json);
|
|
393
|
-
}
|
|
394
|
-
return serialized;
|
|
395
|
-
}, val, opts);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* @summary Parse a string into an EJSON value. Throws an error if the string
|
|
400
|
-
* is not valid EJSON.
|
|
401
|
-
* @locus Anywhere
|
|
402
|
-
* @param {String} str A string to parse into an EJSON value.
|
|
403
|
-
*/
|
|
404
|
-
export function parse(item) {
|
|
405
|
-
if (typeof item !== 'string') {
|
|
406
|
-
throw new Error('EJSON.parse argument should be a string');
|
|
407
|
-
}
|
|
408
|
-
return fromJSONValue(JSON.parse(item));
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* @summary Returns true if `x` is a buffer of binary data, as returned from
|
|
413
|
-
* [`EJSON.newBinary`](#ejson_new_binary).
|
|
414
|
-
* @param {Object} x The variable to check.
|
|
415
|
-
* @locus Anywhere
|
|
416
|
-
*/
|
|
417
|
-
export function isBinary(obj): obj is Uint8Array {
|
|
418
|
-
return !!((typeof Uint8Array !== 'undefined' && obj instanceof Uint8Array) ||
|
|
419
|
-
(obj && obj.$Uint8ArrayPolyfill));
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
/**
|
|
423
|
-
* @summary Return true if `a` and `b` are equal to each other. Return false
|
|
424
|
-
* otherwise. Uses the `equals` method on `a` if present, otherwise
|
|
425
|
-
* performs a deep comparison.
|
|
426
|
-
* @locus Anywhere
|
|
427
|
-
* @param {EJSON} a
|
|
428
|
-
* @param {EJSON} b
|
|
429
|
-
* @param {Object} [options]
|
|
430
|
-
* @param {Boolean} options.keyOrderSensitive Compare in key sensitive order,
|
|
431
|
-
* if supported by the JavaScript implementation. For example, `{a: 1, b: 2}`
|
|
432
|
-
* is equal to `{b: 2, a: 1}` only when `keyOrderSensitive` is `false`. The
|
|
433
|
-
* default is `false`.
|
|
434
|
-
*/
|
|
435
|
-
export function equals(a, b, options?) {
|
|
436
|
-
let i;
|
|
437
|
-
const keyOrderSensitive = !!(options && options.keyOrderSensitive);
|
|
438
|
-
if (a === b) {
|
|
439
|
-
return true;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// This differs from the IEEE spec for NaN equality, b/c we don't want
|
|
443
|
-
// anything ever with a NaN to be poisoned from becoming equal to anything.
|
|
444
|
-
if (Number.isNaN(a) && Number.isNaN(b)) {
|
|
445
|
-
return true;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// if either one is falsy, they'd have to be === to be equal
|
|
449
|
-
if (!a || !b) {
|
|
450
|
-
return false;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (!(isObject(a) && isObject(b))) {
|
|
454
|
-
return false;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
if (a instanceof Date && b instanceof Date) {
|
|
458
|
-
return a.valueOf() === b.valueOf();
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
if (isBinary(a) && isBinary(b)) {
|
|
462
|
-
if (a.length !== b.length) {
|
|
463
|
-
return false;
|
|
464
|
-
}
|
|
465
|
-
for (i = 0; i < a.length; i++) {
|
|
466
|
-
if (a[i] !== b[i]) {
|
|
467
|
-
return false;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
return true;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
if (isFunction(a.equals)) {
|
|
474
|
-
return a.equals(b, options);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
if (isFunction(b.equals)) {
|
|
478
|
-
return b.equals(a, options);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// Array.isArray works across iframes while instanceof won't
|
|
482
|
-
const aIsArray = Array.isArray(a);
|
|
483
|
-
const bIsArray = Array.isArray(b);
|
|
484
|
-
|
|
485
|
-
// if not both or none are array they are not equal
|
|
486
|
-
if (aIsArray !== bIsArray) {
|
|
487
|
-
return false;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
if (aIsArray && bIsArray) {
|
|
491
|
-
if (a.length !== b.length) {
|
|
492
|
-
return false;
|
|
493
|
-
}
|
|
494
|
-
for (i = 0; i < a.length; i++) {
|
|
495
|
-
if (!equals(a[i], b[i], options)) {
|
|
496
|
-
return false;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
return true;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// fallback for custom types that don't implement their own equals
|
|
503
|
-
switch (+_isCustomType(a) + +_isCustomType(b)) {
|
|
504
|
-
case 1: return false;
|
|
505
|
-
case 2: return equals(toJSONValue(a), toJSONValue(b));
|
|
506
|
-
default: // Do nothing
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
// fall back to structural equality of objects
|
|
510
|
-
let ret;
|
|
511
|
-
const aKeys = keysOf(a);
|
|
512
|
-
const bKeys = keysOf(b);
|
|
513
|
-
if (keyOrderSensitive) {
|
|
514
|
-
i = 0;
|
|
515
|
-
ret = aKeys.every(key => {
|
|
516
|
-
if (i >= bKeys.length) {
|
|
517
|
-
return false;
|
|
518
|
-
}
|
|
519
|
-
if (key !== bKeys[i]) {
|
|
520
|
-
return false;
|
|
521
|
-
}
|
|
522
|
-
if (!equals(a[key], b[bKeys[i]], options)) {
|
|
523
|
-
return false;
|
|
524
|
-
}
|
|
525
|
-
i++;
|
|
526
|
-
return true;
|
|
527
|
-
});
|
|
528
|
-
} else {
|
|
529
|
-
i = 0;
|
|
530
|
-
ret = aKeys.every(key => {
|
|
531
|
-
if (!hasOwn(b, key)) {
|
|
532
|
-
return false;
|
|
533
|
-
}
|
|
534
|
-
if (!equals(a[key], b[key], options)) {
|
|
535
|
-
return false;
|
|
536
|
-
}
|
|
537
|
-
i++;
|
|
538
|
-
return true;
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
return ret && i === bKeys.length;
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
/**
|
|
545
|
-
* @summary Return a deep copy of `val`.
|
|
546
|
-
* @locus Anywhere
|
|
547
|
-
* @param {EJSON} val A value to copy.
|
|
548
|
-
*/
|
|
549
|
-
export function clone<T>(v:T): T {
|
|
550
|
-
let ret;
|
|
551
|
-
if (!isObject(v)) {
|
|
552
|
-
return v;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
if (v === null) {
|
|
556
|
-
return null; // null has typeof "object"
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
if (v instanceof Date) {
|
|
560
|
-
return new Date(v.getTime()) as unknown as T;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// RegExps are not really EJSON elements (eg we don't define a serialization
|
|
564
|
-
// for them), but they're immutable anyway, so we can support them in clone.
|
|
565
|
-
if (v instanceof RegExp) {
|
|
566
|
-
return v;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
if (isBinary(v)) {
|
|
570
|
-
ret = new Uint8Array(v.length);
|
|
571
|
-
for (let i = 0; i < v.length; i++) {
|
|
572
|
-
ret[i] = v[i];
|
|
573
|
-
}
|
|
574
|
-
return ret;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
if (Array.isArray(v)) {
|
|
578
|
-
return v.map(clone) as unknown as T;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
if (isArguments(v)) {
|
|
582
|
-
return Array.from(v).map(clone) as unknown as T;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
// handle general user-defined typed Objects if they have a clone method
|
|
586
|
-
if ("clone" in v && isFunction((v as any).clone)) {
|
|
587
|
-
return (v as any).clone();
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// handle other custom types
|
|
591
|
-
if (_isCustomType(v)) {
|
|
592
|
-
return fromJSONValue(clone(toJSONValue(v)));
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
// handle other objects
|
|
596
|
-
ret = {};
|
|
597
|
-
keysOf(v).forEach((key) => {
|
|
598
|
-
ret[key] = clone(v[key]);
|
|
599
|
-
});
|
|
600
|
-
return ret;
|
|
601
|
-
};
|