UNPKG

27.3 kBJavaScriptView Raw
1"use strict";
2/**
3 * Utility constants and functions
4 */
5var __assign = (this && this.__assign) || function () {
6 __assign = Object.assign || function(t) {
7 for (var s, i = 1, n = arguments.length; i < n; i++) {
8 s = arguments[i];
9 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
10 t[p] = s[p];
11 }
12 return t;
13 };
14 return __assign.apply(this, arguments);
15};
16Object.defineProperty(exports, "__esModule", { value: true });
17exports.normalize = exports.isOperator = exports.removeValue = exports.setValue = exports.traverse = exports.filterMissing = exports.resolveGraph = exports.resolve = exports.memoize = exports.into = exports.groupBy = exports.sortBy = exports.compare = exports.hashCode = exports.unique = exports.isEqual = exports.flatten = exports.union = exports.intersection = exports.merge = exports.objectMap = exports.has = exports.ensureArray = exports.isEmpty = exports.truthy = exports.notInArray = exports.inArray = exports.isUndefined = exports.isNull = exports.isNil = exports.isFunction = exports.isRegExp = exports.isDate = exports.isObjectLike = exports.isObject = exports.isArray = exports.isNumber = exports.isString = exports.isBoolean = exports.getType = exports.cloneDeep = exports.assert = exports.BsonType = exports.JsType = exports.MIN_LONG = exports.MAX_LONG = exports.MIN_INT = exports.MAX_INT = void 0;
18exports.MAX_INT = 2147483647;
19exports.MIN_INT = -2147483648;
20exports.MAX_LONG = Number.MAX_SAFE_INTEGER;
21exports.MIN_LONG = Number.MIN_SAFE_INTEGER;
22// special value to identify missing items. treated differently from undefined
23var MISSING = {};
24var DEFAULT_HASH_FUNC = function (value) {
25 var s = encode(value);
26 var hash = 0;
27 var i = s.length;
28 while (i)
29 hash = ((hash << 5) - hash) ^ s.charCodeAt(--i);
30 var code = hash >>> 0;
31 return code.toString();
32};
33// Javascript native types
34var JsType;
35(function (JsType) {
36 JsType["NULL"] = "null";
37 JsType["UNDEFINED"] = "undefined";
38 JsType["BOOLEAN"] = "boolean";
39 JsType["NUMBER"] = "number";
40 JsType["STRING"] = "string";
41 JsType["DATE"] = "date";
42 JsType["REGEXP"] = "regexp";
43 JsType["ARRAY"] = "array";
44 JsType["OBJECT"] = "object";
45 JsType["FUNCTION"] = "function";
46})(JsType = exports.JsType || (exports.JsType = {}));
47// MongoDB BSON types
48var BsonType;
49(function (BsonType) {
50 BsonType["BOOL"] = "bool";
51 BsonType["INT"] = "int";
52 BsonType["LONG"] = "long";
53 BsonType["DOUBLE"] = "double";
54 BsonType["DECIMAL"] = "decimal";
55 BsonType["REGEX"] = "regex";
56})(BsonType = exports.BsonType || (exports.BsonType = {}));
57// no array, object, or function types
58var JS_SIMPLE_TYPES = [
59 JsType.NULL,
60 JsType.UNDEFINED,
61 JsType.BOOLEAN,
62 JsType.NUMBER,
63 JsType.STRING,
64 JsType.DATE,
65 JsType.REGEXP,
66];
67var OBJECT_PROTOTYPE = Object.getPrototypeOf({});
68var OBJECT_TAG = "[object Object]";
69var OBJECT_TYPE_RE = /^\[object ([a-zA-Z0-9]+)\]$/;
70function assert(condition, message) {
71 if (!condition)
72 throw new Error(message);
73}
74exports.assert = assert;
75/**
76 * Deep clone an object
77 */
78function cloneDeep(obj) {
79 if (obj instanceof Array)
80 return obj.map(cloneDeep);
81 if (obj instanceof Date)
82 return new Date(obj);
83 if (isObject(obj))
84 return objectMap(obj, cloneDeep);
85 return obj;
86}
87exports.cloneDeep = cloneDeep;
88/**
89 * Returns the name of type as specified in the tag returned by a call to Object.prototype.toString
90 * @param v A value
91 */
92function getType(v) {
93 return OBJECT_TYPE_RE.exec(Object.prototype.toString.call(v))[1];
94}
95exports.getType = getType;
96function isBoolean(v) {
97 return typeof v === JsType.BOOLEAN;
98}
99exports.isBoolean = isBoolean;
100function isString(v) {
101 return typeof v === JsType.STRING;
102}
103exports.isString = isString;
104function isNumber(v) {
105 return !isNaN(v) && typeof v === JsType.NUMBER;
106}
107exports.isNumber = isNumber;
108exports.isArray = Array.isArray;
109function isObject(v) {
110 if (!v)
111 return false;
112 var proto = Object.getPrototypeOf(v);
113 return ((proto === OBJECT_PROTOTYPE || proto === null) &&
114 OBJECT_TAG === Object.prototype.toString.call(v));
115}
116exports.isObject = isObject;
117function isObjectLike(v) {
118 return v === Object(v);
119} // objects, arrays, functions, date, custom object
120exports.isObjectLike = isObjectLike;
121function isDate(v) {
122 return v instanceof Date;
123}
124exports.isDate = isDate;
125function isRegExp(v) {
126 return v instanceof RegExp;
127}
128exports.isRegExp = isRegExp;
129function isFunction(v) {
130 return typeof v === JsType.FUNCTION;
131}
132exports.isFunction = isFunction;
133function isNil(v) {
134 return v === null || v === undefined;
135}
136exports.isNil = isNil;
137function isNull(v) {
138 return v === null;
139}
140exports.isNull = isNull;
141function isUndefined(v) {
142 return v === undefined;
143}
144exports.isUndefined = isUndefined;
145exports.inArray = (function () {
146 // if Array.includes is not supported
147 if (!Array.prototype.includes) {
148 return function (arr, item) {
149 return isNaN(item) && !isString(item)
150 ? arr.some(function (v) { return isNaN(v) && !isString(v); })
151 : arr.indexOf(item) > -1;
152 };
153 }
154 // default
155 return function (arr, item) { return arr.includes(item); };
156})();
157function notInArray(arr, item) {
158 return !(0, exports.inArray)(arr, item);
159}
160exports.notInArray = notInArray;
161function truthy(arg) {
162 return !!arg;
163}
164exports.truthy = truthy;
165function isEmpty(x) {
166 return (isNil(x) ||
167 (isString(x) && !x) ||
168 (x instanceof Array && x.length === 0) ||
169 (isObject(x) && Object.keys(x).length === 0));
170}
171exports.isEmpty = isEmpty;
172// ensure a value is an array or wrapped within one
173function ensureArray(x) {
174 return x instanceof Array ? x : [x];
175}
176exports.ensureArray = ensureArray;
177function has(obj, prop) {
178 return !!obj && Object.prototype.hasOwnProperty.call(obj, prop);
179}
180exports.has = has;
181/**
182 * Transform values in an object
183 *
184 * @param {Object} obj An object whose values to transform
185 * @param {Function} fn The transform function
186 * @return {Array|Object} Result object after applying the transform
187 */
188function objectMap(obj, fn) {
189 var o = {};
190 var objKeys = Object.keys(obj);
191 for (var i = 0; i < objKeys.length; i++) {
192 var k = objKeys[i];
193 o[k] = fn(obj[k], k);
194 }
195 return o;
196}
197exports.objectMap = objectMap;
198/**
199 * Deep merge objects or arrays.
200 * When the inputs have unmergeable types, the source value (right hand side) is returned.
201 * If inputs are arrays of same length and all elements are mergable, elements in the same position are merged together.
202 * If AnyVal of the elements are unmergeable, elements in the source are appended to the target.
203 * @param target {Object|Array} the target to merge into
204 * @param obj {Object|Array} the source object
205 */
206function merge(target, obj, options) {
207 // take care of missing inputs
208 if (target === MISSING)
209 return obj;
210 if (obj === MISSING)
211 return target;
212 var inputs = [target, obj];
213 if (!(inputs.every(isObject) || inputs.every(exports.isArray))) {
214 throw Error("mismatched types. must both be array or object");
215 }
216 // default options
217 options = options || { flatten: false };
218 if ((0, exports.isArray)(target)) {
219 var result = target;
220 var input = obj;
221 if (options.flatten) {
222 var i = 0;
223 var j = 0;
224 while (i < result.length && j < input.length) {
225 result[i] = merge(result[i++], input[j++], options);
226 }
227 while (j < input.length) {
228 result.push(obj[j++]);
229 }
230 }
231 else {
232 Array.prototype.push.apply(result, input);
233 }
234 }
235 else {
236 Object.keys(obj).forEach(function (k) {
237 if (has(obj, k)) {
238 if (has(target, k)) {
239 target[k] = merge(target[k], obj[k], options);
240 }
241 else {
242 target[k] = obj[k];
243 }
244 }
245 });
246 }
247 return target;
248}
249exports.merge = merge;
250/**
251 * Returns the intersection between two arrays
252 *
253 * @param {Array} a The first array
254 * @param {Array} b The second array
255 * @param {Function} hashFunction Custom function to hash values, default the hashCode method
256 * @return {Array} Result array
257 */
258function intersection(a, b, hashFunction) {
259 var flipped = false;
260 // we ensure the left array is always smallest
261 if (a.length > b.length) {
262 var t = a;
263 a = b;
264 b = t;
265 flipped = true;
266 }
267 var maxSize = Math.max(a.length, b.length);
268 var maxResult = Math.min(a.length, b.length);
269 var lookup = a.reduce(function (memo, v, i) {
270 memo[hashCode(v, hashFunction)] = i;
271 return memo;
272 }, {});
273 var indexes = new Array();
274 for (var i = 0, j = 0; i < maxSize && j < maxResult; i++) {
275 var k = lookup[hashCode(b[i], hashFunction)];
276 if (k !== undefined) {
277 indexes.push(k);
278 j++;
279 }
280 }
281 // unless we flipped the arguments we must sort the indexes to keep stability
282 if (!flipped)
283 indexes.sort();
284 return indexes.map(function (i) { return a[i]; });
285}
286exports.intersection = intersection;
287/**
288 * Returns the union of two arrays
289 *
290 * @param {Array} xs The first array
291 * @param {Array} ys The second array
292 * @return {Array} The result array
293 */
294function union(xs, ys, hashFunction) {
295 var hash = {};
296 xs.concat(ys).forEach(function (e, i) {
297 var k = hashCode(e, hashFunction);
298 if (!hash[k])
299 hash[k] = [e, i];
300 });
301 var result = Object.values(hash)
302 .sort(function (a, b) { return (a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0); })
303 .map(function (e) { return e[0]; });
304 return result;
305}
306exports.union = union;
307/**
308 * Flatten the array
309 *
310 * @param {Array} xs The array to flatten
311 * @param {Number} depth The number of nested lists to iterate
312 */
313function flatten(xs, depth) {
314 var arr = [];
315 function flatten2(ys, n) {
316 for (var i = 0, len = ys.length; i < len; i++) {
317 if ((0, exports.isArray)(ys[i]) && (n > 0 || n < 0)) {
318 flatten2(ys[i], Math.max(-1, n - 1));
319 }
320 else {
321 arr.push(ys[i]);
322 }
323 }
324 }
325 flatten2(xs, depth);
326 return arr;
327}
328exports.flatten = flatten;
329/**
330 * Determine whether two values are the same or strictly equivalent
331 *
332 * @param {*} a The first value
333 * @param {*} b The second value
334 * @return {Boolean} Result of comparison
335 */
336function isEqual(a, b) {
337 var lhs = [a];
338 var rhs = [b];
339 while (lhs.length > 0) {
340 a = lhs.pop();
341 b = rhs.pop();
342 // strictly equal must be equal.
343 if (a === b)
344 continue;
345 // unequal types and functions cannot be equal.
346 var nativeType = getType(a).toLowerCase();
347 if (nativeType !== getType(b).toLowerCase() ||
348 nativeType === JsType.FUNCTION) {
349 return false;
350 }
351 // leverage toString for Date and RegExp types
352 if (nativeType === JsType.ARRAY) {
353 var xs = a;
354 var ys = b;
355 if (xs.length !== ys.length)
356 return false;
357 if (xs.length === ys.length && xs.length === 0)
358 continue;
359 into(lhs, xs);
360 into(rhs, ys);
361 }
362 else if (nativeType === JsType.OBJECT) {
363 // deep compare objects
364 var ka = Object.keys(a);
365 var kb = Object.keys(b);
366 // check length of keys early
367 if (ka.length !== kb.length)
368 return false;
369 // we know keys are strings so we sort before comparing
370 ka.sort();
371 kb.sort();
372 // compare keys
373 for (var i = 0, len = ka.length; i < len; i++) {
374 var tempKey = ka[i];
375 if (tempKey !== kb[i]) {
376 return false;
377 }
378 else {
379 // save later work
380 lhs.push(a[tempKey]);
381 rhs.push(b[tempKey]);
382 }
383 }
384 }
385 else {
386 // compare encoded values
387 if (encode(a) !== encode(b))
388 return false;
389 }
390 }
391 return lhs.length === 0;
392}
393exports.isEqual = isEqual;
394/**
395 * Return a new unique version of the collection
396 * @param {Array} xs The input collection
397 * @return {Array} A new collection with unique values
398 */
399function unique(xs, hashFunction) {
400 var h = {};
401 var arr = [];
402 for (var _i = 0, xs_1 = xs; _i < xs_1.length; _i++) {
403 var item = xs_1[_i];
404 var k = hashCode(item, hashFunction);
405 if (!has(h, k)) {
406 arr.push(item);
407 h[k] = 0;
408 }
409 }
410 return arr;
411}
412exports.unique = unique;
413/**
414 * Encode value to string using a simple non-colliding stable scheme.
415 *
416 * @param value
417 * @returns {*}
418 */
419function encode(value) {
420 var type = getType(value).toLowerCase();
421 switch (type) {
422 case JsType.BOOLEAN:
423 case JsType.NUMBER:
424 case JsType.REGEXP:
425 return value.toString();
426 case JsType.STRING:
427 return JSON.stringify(value);
428 case JsType.DATE:
429 return value.toISOString();
430 case JsType.NULL:
431 case JsType.UNDEFINED:
432 return type;
433 case JsType.ARRAY:
434 return "[" + value.map(encode).join(",") + "]";
435 default:
436 break;
437 }
438 // default case
439 var prefix = type === JsType.OBJECT ? "" : "" + getType(value);
440 var objKeys = Object.keys(value);
441 objKeys.sort();
442 return (prefix + "{" +
443 objKeys.map(function (k) { return encode(k) + ":" + encode(value[k]); }).join(",") +
444 "}");
445}
446/**
447 * Generate hash code
448 * This selected function is the result of benchmarking various hash functions.
449 * This version performs well and can hash 10^6 documents in ~3s with on average 100 collisions.
450 *
451 * @param value
452 * @returns {number|null}
453 */
454function hashCode(value, hashFunction) {
455 if (hashFunction === void 0) { hashFunction = DEFAULT_HASH_FUNC; }
456 if (isNil(value))
457 return null;
458 return hashFunction(value);
459}
460exports.hashCode = hashCode;
461/**
462 * Default compare function
463 * @param {*} a
464 * @param {*} b
465 */
466function compare(a, b) {
467 if (a < b)
468 return -1;
469 if (a > b)
470 return 1;
471 return 0;
472}
473exports.compare = compare;
474/**
475 * Returns a (stably) sorted copy of list, ranked in ascending order by the results of running each value through iteratee
476 *
477 * This implementation treats null/undefined sort keys as less than every other type
478 *
479 * @param {Array} collection
480 * @param {Function} keyFn The sort key function used to resolve sort keys
481 * @param {Function} comparator The comparator function to use for comparing keys. Defaults to standard comparison via `compare(...)`
482 * @return {Array} Returns a new sorted array by the given key and comparator function
483 */
484function sortBy(collection, keyFn, comparator) {
485 var sorted = new Array();
486 var result = new Array();
487 var hash = {};
488 comparator = comparator || compare;
489 if (isEmpty(collection))
490 return collection;
491 for (var i = 0; i < collection.length; i++) {
492 var obj = collection[i];
493 var key = keyFn(obj, i);
494 // objects with nil keys will go in first
495 if (isNil(key)) {
496 result.push(obj);
497 }
498 else {
499 // null suffix to differentiate string keys from native object properties
500 if (isString(key))
501 key += "\0";
502 if (hash[key]) {
503 hash[key].push(obj);
504 }
505 else {
506 hash[key] = [obj];
507 }
508 sorted.push(key);
509 }
510 }
511 // use native array sorting but enforce stableness
512 sorted.sort(comparator);
513 for (var i = 0; i < sorted.length; i++) {
514 into(result, hash[sorted[i]]);
515 }
516 return result;
517}
518exports.sortBy = sortBy;
519/**
520 * Groups the collection into sets by the returned key
521 *
522 * @param collection
523 * @param keyFn {Function} to compute the group key of an item in the collection
524 * @returns {{keys: Array, groups: Array}}
525 */
526function groupBy(collection, keyFn, hashFunction) {
527 var result = {
528 keys: new Array(),
529 groups: new Array(),
530 };
531 var lookup = {};
532 for (var _i = 0, collection_1 = collection; _i < collection_1.length; _i++) {
533 var obj = collection_1[_i];
534 var key = keyFn(obj);
535 var hash = hashCode(key, hashFunction);
536 var index = -1;
537 if (lookup[hash] === undefined) {
538 index = result.keys.length;
539 lookup[hash] = index;
540 result.keys.push(key);
541 result.groups.push([]);
542 }
543 index = lookup[hash];
544 result.groups[index].push(obj);
545 }
546 return result;
547}
548exports.groupBy = groupBy;
549// max elements to push.
550// See argument limit https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
551var MAX_ARRAY_PUSH = 50000;
552/**
553 * Merge elements into the dest
554 *
555 * @param {*} target The target object
556 * @param {*} rest The array of elements to merge into dest
557 */
558function into(target) {
559 var rest = [];
560 for (var _i = 1; _i < arguments.length; _i++) {
561 rest[_i - 1] = arguments[_i];
562 }
563 if (target instanceof Array) {
564 return rest.reduce(function (acc, arr) {
565 // push arrary in batches to handle large inputs
566 var i = Math.ceil(arr.length / MAX_ARRAY_PUSH);
567 var begin = 0;
568 while (i-- > 0) {
569 Array.prototype.push.apply(acc, arr.slice(begin, begin + MAX_ARRAY_PUSH));
570 begin += MAX_ARRAY_PUSH;
571 }
572 return acc;
573 }, target);
574 }
575 else if (isObject(target)) {
576 // merge objects. same behaviour as Object.assign
577 return rest.filter(isObjectLike).reduce(function (acc, item) {
578 Object.assign(acc, item);
579 return acc;
580 }, target);
581 }
582 return null;
583}
584exports.into = into;
585/**
586 * This is a generic memoization function
587 *
588 * This implementation uses a cache independent of the function being memoized
589 * to allow old values to be garbage collected when the memoized function goes out of scope.
590 *
591 * @param {*} fn The function object to memoize
592 */
593function memoize(fn, hashFunction) {
594 var _this = this;
595 return (function (memo) {
596 return function () {
597 var args = [];
598 for (var _i = 0; _i < arguments.length; _i++) {
599 args[_i] = arguments[_i];
600 }
601 var key = hashCode(args, hashFunction);
602 if (!has(memo, key)) {
603 memo[key] = fn.apply(_this, args);
604 }
605 return memo[key];
606 };
607 })({
608 /* storage */
609 });
610}
611exports.memoize = memoize;
612// mingo internal
613/**
614 * Retrieve the value of a given key on an object
615 * @param obj
616 * @param key
617 * @returns {*}
618 * @private
619 */
620function getValue(obj, key) {
621 return isObjectLike(obj) ? obj[key] : undefined;
622}
623/**
624 * Unwrap a single element array to specified depth
625 * @param {Array} arr
626 * @param {Number} depth
627 */
628function unwrap(arr, depth) {
629 if (depth < 1)
630 return arr;
631 while (depth-- && arr.length === 1)
632 arr = arr[0];
633 return arr;
634}
635/**
636 * Resolve the value of the field (dot separated) on the given object
637 * @param obj {Object} the object context
638 * @param selector {String} dot separated path to field
639 * @returns {*}
640 */
641function resolve(obj, selector, options) {
642 var depth = 0;
643 // options
644 options = options || { unwrapArray: false };
645 function resolve2(o, path) {
646 var value = o;
647 var _loop_1 = function (i) {
648 var field = path[i];
649 var isText = /^\d+$/.exec(field) === null;
650 // using instanceof to aid typescript compiler
651 if (isText && value instanceof Array) {
652 // On the first iteration, we check if we received a stop flag.
653 // If so, we stop to prevent iterating over a nested array value
654 // on consecutive object keys in the selector.
655 if (i === 0 && depth > 0)
656 return "break";
657 depth += 1;
658 // only look at the rest of the path
659 var subpath_1 = path.slice(i);
660 value = value.reduce(function (acc, item) {
661 var v = resolve2(item, subpath_1);
662 if (v !== undefined)
663 acc.push(v);
664 return acc;
665 }, []);
666 return "break";
667 }
668 else {
669 value = getValue(value, field);
670 }
671 if (value === undefined)
672 return "break";
673 };
674 for (var i = 0; i < path.length; i++) {
675 var state_1 = _loop_1(i);
676 if (state_1 === "break")
677 break;
678 }
679 return value;
680 }
681 var result = (0, exports.inArray)(JS_SIMPLE_TYPES, getType(obj).toLowerCase())
682 ? obj
683 : resolve2(obj, selector.split("."));
684 return result instanceof Array && options.unwrapArray
685 ? unwrap(result, depth)
686 : result;
687}
688exports.resolve = resolve;
689/**
690 * Returns the full object to the resolved value given by the selector.
691 * This function excludes empty values as they aren't practically useful.
692 *
693 * @param obj {Object} the object context
694 * @param selector {String} dot separated path to field
695 */
696function resolveGraph(obj, selector, options) {
697 // options
698 if (options === undefined) {
699 options = { preserveMissing: false };
700 }
701 var names = selector.split(".");
702 var key = names[0];
703 // get the next part of the selector
704 var next = names.slice(1).join(".");
705 var isIndex = /^\d+$/.exec(key) !== null;
706 var hasNext = names.length > 1;
707 var result;
708 var value;
709 if (obj instanceof Array) {
710 if (isIndex) {
711 result = getValue(obj, Number(key));
712 if (hasNext) {
713 result = resolveGraph(result, next, options);
714 }
715 result = [result];
716 }
717 else {
718 result = [];
719 for (var _i = 0, obj_1 = obj; _i < obj_1.length; _i++) {
720 var item = obj_1[_i];
721 value = resolveGraph(item, selector, options);
722 if (options.preserveMissing) {
723 if (value === undefined) {
724 value = MISSING;
725 }
726 result.push(value);
727 }
728 else if (value !== undefined) {
729 result.push(value);
730 }
731 }
732 }
733 }
734 else {
735 value = getValue(obj, key);
736 if (hasNext) {
737 value = resolveGraph(value, next, options);
738 }
739 if (value === undefined)
740 return undefined;
741 result = options.preserveKeys ? __assign({}, obj) : {};
742 result[key] = value;
743 }
744 return result;
745}
746exports.resolveGraph = resolveGraph;
747/**
748 * Filter out all MISSING values from the object in-place
749 *
750 * @param obj The object to filter
751 */
752function filterMissing(obj) {
753 if (obj instanceof Array) {
754 for (var i = obj.length - 1; i >= 0; i--) {
755 if (obj[i] === MISSING) {
756 obj.splice(i, 1);
757 }
758 else {
759 filterMissing(obj[i]);
760 }
761 }
762 }
763 else if (isObject(obj)) {
764 for (var k in obj) {
765 if (has(obj, k)) {
766 filterMissing(obj[k]);
767 }
768 }
769 }
770}
771exports.filterMissing = filterMissing;
772/**
773 * Walk the object graph and execute the given transform function
774 *
775 * @param {Object|Array} obj The object to traverse
776 * @param {String} selector The selector
777 * @param {Function} fn Function to execute for value at the end the traversal
778 * @param {Boolean} force Force generating missing parts of object graph
779 * @return {*}
780 */
781function traverse(obj, selector, fn, force) {
782 var names = selector.split(".");
783 var key = names[0];
784 var next = names.slice(1).join(".");
785 if (names.length === 1) {
786 fn(obj, key);
787 }
788 else {
789 // force the rest of the graph while traversing
790 if (force === true && isNil(obj[key])) {
791 obj[key] = {};
792 }
793 traverse(obj[key], next, fn, force);
794 }
795}
796exports.traverse = traverse;
797/**
798 * Set the value of the given object field
799 *
800 * @param obj {Object|Array} the object context
801 * @param selector {String} path to field
802 * @param value {*} the value to set
803 */
804function setValue(obj, selector, value) {
805 traverse(obj, selector, function (item, key) {
806 item[key] = value;
807 }, true);
808}
809exports.setValue = setValue;
810/**
811 * Removes an element from the container.
812 * If the selector resolves to an array and the leaf is a non-numeric key,
813 * the remove operation will be performed on objects of the array.
814 *
815 * @param obj {ArrayOrObject} object or array
816 * @param selector {String} dot separated path to element to remove
817 */
818function removeValue(obj, selector) {
819 traverse(obj, selector, function (item, key) {
820 if (item instanceof Array) {
821 if (/^\d+$/.test(key)) {
822 item.splice(parseInt(key), 1);
823 }
824 else {
825 for (var _i = 0, item_1 = item; _i < item_1.length; _i++) {
826 var elem = item_1[_i];
827 if (isObject(elem)) {
828 delete elem[key];
829 }
830 }
831 }
832 }
833 else if (isObject(item)) {
834 delete item[key];
835 }
836 });
837}
838exports.removeValue = removeValue;
839var OPERATOR_NAME_PATTERN = /^\$[a-zA-Z0-9_]+$/;
840/**
841 * Check whether the given name passes for an operator. We assume AnyVal field name starting with '$' is an operator.
842 * This is cheap and safe to do since keys beginning with '$' should be reserved for internal use.
843 * @param {String} name
844 */
845function isOperator(name) {
846 return OPERATOR_NAME_PATTERN.test(name);
847}
848exports.isOperator = isOperator;
849/**
850 * Simplify expression for easy evaluation with query operators map
851 * @param expr
852 * @returns {*}
853 */
854function normalize(expr) {
855 // normalized primitives
856 if ((0, exports.inArray)(JS_SIMPLE_TYPES, getType(expr).toLowerCase())) {
857 return isRegExp(expr) ? { $regex: expr } : { $eq: expr };
858 }
859 // normalize object expression. using ObjectLike handles custom types
860 if (isObjectLike(expr)) {
861 // no valid query operator found, so we do simple comparison
862 if (!Object.keys(expr).some(isOperator)) {
863 return { $eq: expr };
864 }
865 // ensure valid regex
866 if (has(expr, "$regex")) {
867 return {
868 $regex: new RegExp(expr["$regex"], expr["$options"]),
869 };
870 }
871 }
872 return expr;
873}
874exports.normalize = normalize;