UNPKG

47.6 kBJavaScriptView Raw
1
2// array skipped
3// object skipped
4
5module.exports.$not = function $not($offset, $len) {
6 this.processValue(this.$expressions[++$offset])
7 const arg0 = this.$stack.pop();
8 this.$stack.push(!(arg0));
9}
10// trace skipped
11
12module.exports.$get = function $get($offset, $len) {
13 this.processValue(this.$expressions[++$offset])
14 const arg0 = this.$stack.pop();
15 this.processValue(this.$expressions[++$offset])
16 const arg1 = this.$stack.pop();
17 this.$stack.push(arg1[arg0]);
18}
19// mapValues skipped
20// map skipped
21// recursiveMapValues skipped
22// recursiveMap skipped
23// any skipped
24// keyBy skipped
25// filter skipped
26// anyValues skipped
27// filterBy skipped
28// mapKeys skipped
29// groupBy skipped
30// values skipped
31// keys skipped
32// flatten skipped
33// size skipped
34// sum skipped
35// range skipped
36// assign skipped
37// defaults skipped
38// recur skipped
39// func skipped
40// invoke skipped
41
42module.exports.$eq = function $eq($offset, $len) {
43 this.processValue(this.$expressions[++$offset])
44 const arg0 = this.$stack.pop();
45 this.processValue(this.$expressions[++$offset])
46 const arg1 = this.$stack.pop();
47 this.$stack.push((arg0) === (arg1));
48}
49
50module.exports.$gt = function $gt($offset, $len) {
51 this.processValue(this.$expressions[++$offset])
52 const arg0 = this.$stack.pop();
53 this.processValue(this.$expressions[++$offset])
54 const arg1 = this.$stack.pop();
55 this.$stack.push((arg0) > (arg1));
56}
57
58module.exports.$lt = function $lt($offset, $len) {
59 this.processValue(this.$expressions[++$offset])
60 const arg0 = this.$stack.pop();
61 this.processValue(this.$expressions[++$offset])
62 const arg1 = this.$stack.pop();
63 this.$stack.push((arg0) < (arg1));
64}
65
66module.exports.$gte = function $gte($offset, $len) {
67 this.processValue(this.$expressions[++$offset])
68 const arg0 = this.$stack.pop();
69 this.processValue(this.$expressions[++$offset])
70 const arg1 = this.$stack.pop();
71 this.$stack.push((arg0) >= (arg1));
72}
73
74module.exports.$lte = function $lte($offset, $len) {
75 this.processValue(this.$expressions[++$offset])
76 const arg0 = this.$stack.pop();
77 this.processValue(this.$expressions[++$offset])
78 const arg1 = this.$stack.pop();
79 this.$stack.push((arg0) <= (arg1));
80}
81
82module.exports.$plus = function $plus($offset, $len) {
83 this.processValue(this.$expressions[++$offset])
84 const arg0 = this.$stack.pop();
85 this.processValue(this.$expressions[++$offset])
86 const arg1 = this.$stack.pop();
87 this.$stack.push((arg0) + (arg1));
88}
89
90module.exports.$minus = function $minus($offset, $len) {
91 this.processValue(this.$expressions[++$offset])
92 const arg0 = this.$stack.pop();
93 this.processValue(this.$expressions[++$offset])
94 const arg1 = this.$stack.pop();
95 this.$stack.push((arg0) - (arg1));
96}
97
98module.exports.$mult = function $mult($offset, $len) {
99 this.processValue(this.$expressions[++$offset])
100 const arg0 = this.$stack.pop();
101 this.processValue(this.$expressions[++$offset])
102 const arg1 = this.$stack.pop();
103 this.$stack.push((arg0) * (arg1));
104}
105
106module.exports.$div = function $div($offset, $len) {
107 this.processValue(this.$expressions[++$offset])
108 const arg0 = this.$stack.pop();
109 this.processValue(this.$expressions[++$offset])
110 const arg1 = this.$stack.pop();
111 this.$stack.push((arg0) / (arg1));
112}
113
114module.exports.$mod = function $mod($offset, $len) {
115 this.processValue(this.$expressions[++$offset])
116 const arg0 = this.$stack.pop();
117 this.processValue(this.$expressions[++$offset])
118 const arg1 = this.$stack.pop();
119 this.$stack.push((arg0) % (arg1));
120}
121
122module.exports.$breakpoint = function $breakpoint($offset, $len) {
123 this.processValue(this.$expressions[++$offset])
124 const arg0 = this.$stack.pop();
125 this.$stack.push(((() => {debugger; return arg0}) ()));
126}
127// call skipped
128// bind skipped
129// effect skipped
130
131module.exports.$startsWith = function $startsWith($offset, $len) {
132 this.processValue(this.$expressions[++$offset])
133 const arg0 = this.$stack.pop();
134 this.processValue(this.$expressions[++$offset])
135 const arg1 = this.$stack.pop();
136 this.$stack.push((String.prototype.startsWith).call(arg0, arg1));
137}
138
139module.exports.$endsWith = function $endsWith($offset, $len) {
140 this.processValue(this.$expressions[++$offset])
141 const arg0 = this.$stack.pop();
142 this.processValue(this.$expressions[++$offset])
143 const arg1 = this.$stack.pop();
144 this.$stack.push((String.prototype.endsWith).call(arg0, arg1));
145}
146
147module.exports.$toUpperCase = function $toUpperCase($offset, $len) {
148 this.processValue(this.$expressions[++$offset])
149 const arg0 = this.$stack.pop();
150 this.$stack.push((String.prototype.toUpperCase).call(arg0));
151}
152
153module.exports.$toLowerCase = function $toLowerCase($offset, $len) {
154 this.processValue(this.$expressions[++$offset])
155 const arg0 = this.$stack.pop();
156 this.$stack.push((String.prototype.toLowerCase).call(arg0));
157}
158
159module.exports.$stringLength = function $stringLength($offset, $len) {
160 this.processValue(this.$expressions[++$offset])
161 const arg0 = this.$stack.pop();
162 this.$stack.push((arg0).length);
163}
164
165module.exports.$floor = function $floor($offset, $len) {
166 this.processValue(this.$expressions[++$offset])
167 const arg0 = this.$stack.pop();
168 this.$stack.push((Math.floor)(arg0));
169}
170
171module.exports.$ceil = function $ceil($offset, $len) {
172 this.processValue(this.$expressions[++$offset])
173 const arg0 = this.$stack.pop();
174 this.$stack.push((Math.ceil)(arg0));
175}
176
177module.exports.$round = function $round($offset, $len) {
178 this.processValue(this.$expressions[++$offset])
179 const arg0 = this.$stack.pop();
180 this.$stack.push((Math.round)(arg0));
181}
182// parseInt skipped
183
184module.exports.$substring = function $substring($offset, $len) {
185 this.processValue(this.$expressions[++$offset])
186 const arg0 = this.$stack.pop();
187 this.processValue(this.$expressions[++$offset])
188 const arg1 = this.$stack.pop();
189 this.processValue(this.$expressions[++$offset])
190 const arg2 = this.$stack.pop();
191 this.$stack.push((String.prototype.substring).call(arg0, arg1, arg2));
192}
193
194module.exports.$split = function $split($offset, $len) {
195 this.processValue(this.$expressions[++$offset])
196 const arg0 = this.$stack.pop();
197 this.processValue(this.$expressions[++$offset])
198 const arg1 = this.$stack.pop();
199 this.$stack.push((String.prototype.split).call(arg0, arg1));
200}
201
202module.exports.$isUndefined = function $isUndefined($offset, $len) {
203 this.processValue(this.$expressions[++$offset])
204 const arg0 = this.$stack.pop();
205 this.$stack.push((typeof (arg0) === 'undefined'));
206}
207
208module.exports.$isBoolean = function $isBoolean($offset, $len) {
209 this.processValue(this.$expressions[++$offset])
210 const arg0 = this.$stack.pop();
211 this.$stack.push((typeof (arg0) === 'boolean'));
212}
213
214module.exports.$isString = function $isString($offset, $len) {
215 this.processValue(this.$expressions[++$offset])
216 const arg0 = this.$stack.pop();
217 this.$stack.push((typeof (arg0) === 'string'));
218}
219
220module.exports.$isNumber = function $isNumber($offset, $len) {
221 this.processValue(this.$expressions[++$offset])
222 const arg0 = this.$stack.pop();
223 this.$stack.push((typeof (arg0) === 'number'));
224}
225
226module.exports.$isArray = function $isArray($offset, $len) {
227 this.processValue(this.$expressions[++$offset])
228 const arg0 = this.$stack.pop();
229 this.$stack.push(Array.isArray(arg0));
230}
231
232module.exports.$quote = function $quote($offset, $len) {
233 this.processValue(this.$expressions[++$offset])
234 const arg0 = this.$stack.pop();
235 this.$stack.push(arg0);
236}
237// trackPath skipped
238const emptyObj = () => ({});
239const emptyArr = () => [];
240const nullFunc = () => null;
241const filterCacheFunc = () => [0];
242const valuesOrKeysCacheFunc = () => ({
243 $keyToIdx: {},
244 $idxToKey: []
245});
246module.exports.$trackPath = function trackPath($offset, $length) {
247 const $end = $path.length - 2;
248 let $current = $path[0];
249
250 for (let i = 0; i <= $end; i++) {
251 this.track($target, $current, $path[i + 1], i !== $end);
252 $current = $current[$path[i + 1]];
253 }
254};
255module.exports.$mapValues = function mapValues($offset, $length) {
256 const func = this.$expressions[++$offset];
257 this.processValue(this.$expressions[++$offset]);
258
259 if ($length === 3) {
260 this.$stack.push(null);
261 } else {
262 this.processValue(this.$expressions[++$offset]);
263 }
264
265 if ($length === 3) {
266 this.$contexts.push(this.$stack.pop());
267 } else {
268 const contextArray = this.getEmptyArray(~$offset);
269
270 if (contextArray.length) {
271 this.setOnArray(contextArray, 0, this.$stack.pop(), false);
272 } else {
273 contextArray[0] = this.$stack.pop();
274 }
275
276 this.$contexts.push(contextArray);
277 }
278
279 let src = this.$stack.pop();
280 this.$collections.push(src);
281 // eslint-disable-next-line no-undef
282 this.$functions.push(func);
283 const $storage = this.initOutput($offset - $length, emptyObj, nullFunc);
284 const $out = $storage[1];
285 const $invalidatedKeys = $storage[2];
286 const $new = $storage[3];
287 ($new && Object.keys(src) || $invalidatedKeys).forEach(key => {
288 if (!src.hasOwnProperty(key)) {
289 if ($out.hasOwnProperty(key)) {
290 this.deleteOnObject($out, key, $new);
291 }
292 } else {
293 this.$keys.push(key);
294 this.collectionFunction();
295 const res = this.$stack.pop();
296 this.setOnObject($out, key, res, $new);
297 }
298 });
299 $invalidatedKeys.clear();
300 this.$stack.push($out)
301 this.$functions.pop();
302 this.$collections.pop();
303 this.$currentSets.pop();
304 this.$contexts.pop();
305};
306module.exports.$filterBy = function filterBy($offset, $length) {
307 const func = this.$expressions[++$offset];
308 this.processValue(this.$expressions[++$offset]);
309
310 if ($length === 3) {
311 this.$stack.push(null);
312 } else {
313 this.processValue(this.$expressions[++$offset]);
314 }
315
316 if ($length === 3) {
317 this.$contexts.push(this.$stack.pop());
318 } else {
319 const contextArray = this.getEmptyArray(~$offset);
320
321 if (contextArray.length) {
322 this.setOnArray(contextArray, 0, this.$stack.pop(), false);
323 } else {
324 contextArray[0] = this.$stack.pop();
325 }
326
327 this.$contexts.push(contextArray);
328 }
329
330 let src = this.$stack.pop();
331 this.$collections.push(src);
332 // eslint-disable-next-line no-undef
333 this.$functions.push(func);
334 const $storage = this.initOutput($offset - $length, emptyObj, nullFunc);
335 const $out = $storage[1];
336 const $invalidatedKeys = $storage[2];
337 const $new = $storage[3];
338 ($new && Object.keys(src) || $invalidatedKeys).forEach(key => {
339 if (!src.hasOwnProperty(key)) {
340 if ($out.hasOwnProperty(key)) {
341 this.deleteOnObject($out, key, $new);
342 }
343 } else {
344 this.$keys.push(key);
345 this.collectionFunction();
346 const res = this.$stack.pop();
347
348 if (res) {
349 this.setOnObject($out, key, src[key], $new);
350 } else if ($out.hasOwnProperty(key)) {
351 this.deleteOnObject($out, key, $new);
352 }
353 }
354 });
355 $invalidatedKeys.clear();
356 this.$stack.push($out)
357 this.$functions.pop();
358 this.$collections.pop();
359 this.$currentSets.pop();
360 this.$contexts.pop();
361};
362module.exports.$map = function map($offset, $length) {
363 const func = this.$expressions[++$offset];
364 this.processValue(this.$expressions[++$offset]);
365
366 if ($length === 3) {
367 this.$stack.push(null);
368 } else {
369 this.processValue(this.$expressions[++$offset]);
370 }
371
372 if ($length === 3) {
373 this.$contexts.push(this.$stack.pop());
374 } else {
375 const contextArray = this.getEmptyArray(~$offset);
376
377 if (contextArray.length) {
378 this.setOnArray(contextArray, 0, this.$stack.pop(), false);
379 } else {
380 contextArray[0] = this.$stack.pop();
381 }
382
383 this.$contexts.push(contextArray);
384 }
385
386 let src = this.$stack.pop();
387 this.$collections.push(src);
388 // eslint-disable-next-line no-undef
389 this.$functions.push(func);
390 const $storage = this.initOutput($offset - $length, emptyArr, nullFunc);
391 const $out = $storage[1];
392 const $invalidatedKeys = $storage[2];
393 const $new = $storage[3];
394
395 if ($new) {
396 for (let key = 0; key < src.length; key++) {
397 this.$keys.push(key);
398 this.collectionFunction();
399 const res = this.$stack.pop();
400 this.setOnArray($out, key, res, $new);
401 }
402 } else {
403 $invalidatedKeys.forEach(key => {
404 if (key < src.length) {
405 this.$keys.push(key);
406 this.collectionFunction();
407 const res = this.$stack.pop();
408 this.setOnArray($out, key, res, $new);
409 }
410 });
411
412 if ($out.length > src.length) {
413 this.truncateArray($out, src.length);
414 }
415 }
416
417 $invalidatedKeys.clear();
418 this.$stack.push($out)
419 this.$functions.pop();
420 this.$collections.pop();
421 this.$currentSets.pop();
422 this.$contexts.pop();
423};
424// recursiveMap skipped from optimizing
425// recursiveMapValues skipped from optimizing
426module.exports.$keyBy = function keyBy($offset, $length) {
427 const func = this.$expressions[++$offset];
428 this.processValue(this.$expressions[++$offset]);
429
430 if ($length === 3) {
431 this.$stack.push(null);
432 } else {
433 this.processValue(this.$expressions[++$offset]);
434 }
435
436 if ($length === 3) {
437 this.$contexts.push(this.$stack.pop());
438 } else {
439 const contextArray = this.getEmptyArray(~$offset);
440
441 if (contextArray.length) {
442 this.setOnArray(contextArray, 0, this.$stack.pop(), false);
443 } else {
444 contextArray[0] = this.$stack.pop();
445 }
446
447 this.$contexts.push(contextArray);
448 }
449
450 let src = this.$stack.pop();
451 this.$collections.push(src);
452 // eslint-disable-next-line no-undef
453 this.$functions.push(func);
454 const $storage = this.initOutput($offset - $length, emptyObj, emptyArr);
455 const $out = $storage[1];
456 const $invalidatedKeys = $storage[2];
457 const $new = $storage[3];
458 const $cache = $storage[4];
459
460 if ($new) {
461 $cache.indexToKey = [];
462 $cache.keyToIndices = {};
463
464 for (let index = 0; index < src.length; index++) {
465 this.$keys.push(index);
466 this.collectionFunction();
467 const key = '' + this.$stack.pop();
468 $cache.indexToKey[index] = key;
469 $cache.keyToIndices[key] = $cache.keyToIndices[key] || new Set();
470 $cache.keyToIndices[key].add(index);
471 this.setOnObject($out, key, src[index], $new);
472 }
473 } else {
474 const keysPendingDelete = new Set();
475 $invalidatedKeys.forEach(index => {
476 if (index < $cache.indexToKey.length) {
477 const key = $cache.indexToKey[index];
478 $cache.keyToIndices[key].delete(index);
479
480 if ($cache.keyToIndices[key].size === 0) {
481 delete $cache.keyToIndices[key];
482 keysPendingDelete.add(key);
483 }
484 }
485 });
486 $invalidatedKeys.forEach(index => {
487 if (index < src.length) {
488 this.$keys.push(index);
489 this.collectionFunction();
490 const key = '' + this.$stack.pop();
491 $cache.indexToKey[index] = key;
492 keysPendingDelete.delete(key);
493 $cache.keyToIndices[key] = $cache.keyToIndices[key] || new Set();
494 $cache.keyToIndices[key].add(index);
495 this.setOnObject($out, key, src[index], $new);
496 }
497 });
498 keysPendingDelete.forEach(key => {
499 this.deleteOnObject($out, key, $new);
500 });
501 }
502
503 $cache.indexToKey.length = src.length;
504 $invalidatedKeys.clear();
505 this.$stack.push($out)
506 this.$functions.pop();
507 this.$collections.pop();
508 this.$currentSets.pop();
509 this.$contexts.pop();
510};
511module.exports.$mapKeys = function mapKeys($offset, $length) {
512 const func = this.$expressions[++$offset];
513 this.processValue(this.$expressions[++$offset]);
514
515 if ($length === 3) {
516 this.$stack.push(null);
517 } else {
518 this.processValue(this.$expressions[++$offset]);
519 }
520
521 if ($length === 3) {
522 this.$contexts.push(this.$stack.pop());
523 } else {
524 const contextArray = this.getEmptyArray(~$offset);
525
526 if (contextArray.length) {
527 this.setOnArray(contextArray, 0, this.$stack.pop(), false);
528 } else {
529 contextArray[0] = this.$stack.pop();
530 }
531
532 this.$contexts.push(contextArray);
533 }
534
535 let src = this.$stack.pop();
536 this.$collections.push(src);
537 // eslint-disable-next-line no-undef
538 this.$functions.push(func);
539 const $storage = this.initOutput($offset - $length, emptyObj, emptyObj);
540 const $out = $storage[1];
541 const $invalidatedKeys = $storage[2];
542 const $new = $storage[3];
543 const $keyToKey = $storage[4];
544
545 if ($new) {
546 Object.keys(src).forEach(key => {
547 this.$keys.push(key);
548 this.collectionFunction();
549 const newKey = this.$stack.pop();
550 this.setOnObject($out, newKey, src[key], $new);
551 $keyToKey[key] = newKey;
552 });
553 } else {
554 const keysPendingDelete = new Set();
555 $invalidatedKeys.forEach(key => {
556 if ($keyToKey.hasOwnProperty(key)) {
557 keysPendingDelete.add($keyToKey[key]);
558 delete $keyToKey[key];
559 }
560 });
561 $invalidatedKeys.forEach(key => {
562 if (src.hasOwnProperty(key)) {
563 this.$keys.push(key);
564 this.collectionFunction();
565 const newKey = this.$stack.pop();
566 this.setOnObject($out, newKey, src[key], $new);
567 $keyToKey[key] = newKey;
568 keysPendingDelete.delete(newKey);
569 }
570 });
571 keysPendingDelete.forEach(key => {
572 this.deleteOnObject($out, key, $new);
573 });
574 }
575
576 $invalidatedKeys.clear();
577 this.$stack.push($out)
578 this.$functions.pop();
579 this.$collections.pop();
580 this.$currentSets.pop();
581 this.$contexts.pop();
582};
583module.exports.$filter = function filter($offset, $length) {
584 const func = this.$expressions[++$offset];
585 this.processValue(this.$expressions[++$offset]);
586
587 if ($length === 3) {
588 this.$stack.push(null);
589 } else {
590 this.processValue(this.$expressions[++$offset]);
591 }
592
593 if ($length === 3) {
594 this.$contexts.push(this.$stack.pop());
595 } else {
596 const contextArray = this.getEmptyArray(~$offset);
597
598 if (contextArray.length) {
599 this.setOnArray(contextArray, 0, this.$stack.pop(), false);
600 } else {
601 contextArray[0] = this.$stack.pop();
602 }
603
604 this.$contexts.push(contextArray);
605 }
606
607 let src = this.$stack.pop();
608 this.$collections.push(src);
609 // eslint-disable-next-line no-undef
610 this.$functions.push(func);
611 const $storage = this.initOutput($offset - $length, emptyArr, filterCacheFunc);
612 const $out = $storage[1];
613 const $invalidatedKeys = $storage[2];
614 const $new = $storage[3];
615 const $idxToIdx = $storage[4];
616
617 if ($new) {
618 for (let key = 0; key < src.length; key++) {
619 this.$keys.push(key);
620 this.collectionFunction();
621 const passed = !!this.$stack.pop();
622 const prevItemIdx = $idxToIdx[key];
623 const nextItemIdx = passed ? prevItemIdx + 1 : prevItemIdx;
624 $idxToIdx[key + 1] = nextItemIdx;
625
626 if (nextItemIdx !== prevItemIdx) {
627 this.setOnArray($out, prevItemIdx, src[key], $new);
628 }
629 }
630 } else {
631 let firstIndex = Number.MAX_SAFE_INTEGER;
632 $invalidatedKeys.forEach(key => firstIndex = Math.min(firstIndex, key));
633
634 for (let key = firstIndex; key < src.length; key++) {
635 this.$keys.push(key);
636 this.collectionFunction();
637 const passed = !!this.$stack.pop();
638 const prevItemIdx = $idxToIdx[key];
639 const nextItemIdx = passed ? prevItemIdx + 1 : prevItemIdx;
640 $idxToIdx[key + 1] = nextItemIdx;
641
642 if (nextItemIdx !== prevItemIdx) {
643 this.setOnArray($out, prevItemIdx, src[key], $new);
644 }
645 }
646
647 $idxToIdx.length = src.length + 1;
648 this.truncateArray($out, $idxToIdx[$idxToIdx.length - 1]);
649 }
650
651 $invalidatedKeys.clear();
652 this.$stack.push($out)
653 this.$functions.pop();
654 this.$collections.pop();
655 this.$currentSets.pop();
656 this.$contexts.pop();
657};
658module.exports.$any = function any($offset, $length) {
659 const func = this.$expressions[++$offset];
660 this.processValue(this.$expressions[++$offset]);
661
662 if ($length === 3) {
663 this.$stack.push(null);
664 } else {
665 this.processValue(this.$expressions[++$offset]);
666 }
667
668 if ($length === 3) {
669 this.$contexts.push(this.$stack.pop());
670 } else {
671 const contextArray = this.getEmptyArray(~$offset);
672
673 if (contextArray.length) {
674 this.setOnArray(contextArray, 0, this.$stack.pop(), false);
675 } else {
676 contextArray[0] = this.$stack.pop();
677 }
678
679 this.$contexts.push(contextArray);
680 }
681
682 let src = this.$stack.pop();
683 this.$collections.push(src);
684 // eslint-disable-next-line no-undef
685 this.$functions.push(func);
686 const $storage = this.initOutput($offset - $length, emptyArr, nullFunc);
687 const $out = $storage[1];
688 const $invalidatedKeys = $storage[2];
689 const $new = $storage[3]; // $out has at most 1 key - the one that stopped the previous run because it was truthy
690
691 if ($new) {
692 for (let key = 0; key < src.length; key++) {
693 $invalidatedKeys.add(key);
694 }
695 }
696
697 const $prevStop = $out.length > 0 ? $out[0] : -1;
698
699 if ($prevStop >= 0 && $prevStop < src.length) {
700 if ($invalidatedKeys.has($prevStop)) {
701 $invalidatedKeys.delete($prevStop);
702 this.$keys.push($prevStop);
703 this.collectionFunction();
704 const passedTest = this.$stack.pop();
705
706 if (!passedTest) {
707 $out.length = 0;
708 }
709 }
710 } else {
711 $out.length = 0;
712 }
713
714 if ($out.length === 0) {
715 for (let key of $invalidatedKeys) {
716 $invalidatedKeys.delete(key);
717
718 if (key >= 0 && key < src.length) {
719 this.$keys.push(key);
720 this.collectionFunction();
721 const match = this.$stack.pop();
722
723 if (match) {
724 $out[0] = key;
725 break;
726 }
727 }
728 }
729 }
730
731 this.$stack.push($out.length === 1)
732 this.$functions.pop();
733 this.$collections.pop();
734 this.$currentSets.pop();
735 this.$contexts.pop();
736};
737module.exports.$anyValues = function anyValues($offset, $length) {
738 const func = this.$expressions[++$offset];
739 this.processValue(this.$expressions[++$offset]);
740
741 if ($length === 3) {
742 this.$stack.push(null);
743 } else {
744 this.processValue(this.$expressions[++$offset]);
745 }
746
747 if ($length === 3) {
748 this.$contexts.push(this.$stack.pop());
749 } else {
750 const contextArray = this.getEmptyArray(~$offset);
751
752 if (contextArray.length) {
753 this.setOnArray(contextArray, 0, this.$stack.pop(), false);
754 } else {
755 contextArray[0] = this.$stack.pop();
756 }
757
758 this.$contexts.push(contextArray);
759 }
760
761 let src = this.$stack.pop();
762 this.$collections.push(src);
763 // eslint-disable-next-line no-undef
764 this.$functions.push(func);
765 const $storage = this.initOutput($offset - $length, emptyArr, nullFunc);
766 const $out = $storage[1];
767 const $invalidatedKeys = $storage[2];
768 const $new = $storage[3]; // $out has at most 1 key - the one that stopped the previous run because it was truthy
769
770 if ($new) {
771 Object.keys(src).forEach(key => $invalidatedKeys.add(key));
772 }
773
774 const $prevStop = $out.length > 0 ? $out[0] : null;
775
776 if ($prevStop !== null && src.hasOwnProperty($prevStop)) {
777 if ($invalidatedKeys.has($prevStop)) {
778 $invalidatedKeys.delete($prevStop);
779 this.$keys.push($prevStop);
780 this.collectionFunction();
781 const passedTest = this.$stack.pop();
782
783 if (!passedTest) {
784 $out.length = 0;
785 }
786 }
787 } else {
788 $out.length = 0;
789 }
790
791 if ($out.length === 0) {
792 for (let key of $invalidatedKeys) {
793 $invalidatedKeys.delete(key);
794
795 if (src.hasOwnProperty(key)) {
796 this.$keys.push(key);
797 this.collectionFunction();
798 const match = this.$stack.pop();
799
800 if (match) {
801 $out[0] = key;
802 break;
803 }
804 }
805 }
806 }
807
808 this.$stack.push($out.length === 1)
809 this.$functions.pop();
810 this.$collections.pop();
811 this.$currentSets.pop();
812 this.$contexts.pop();
813};
814module.exports.$groupBy = function groupBy($offset, $length) {
815 const func = this.$expressions[++$offset];
816 this.processValue(this.$expressions[++$offset]);
817
818 if ($length === 3) {
819 this.$stack.push(null);
820 } else {
821 this.processValue(this.$expressions[++$offset]);
822 }
823
824 if ($length === 3) {
825 this.$contexts.push(this.$stack.pop());
826 } else {
827 const contextArray = this.getEmptyArray(~$offset);
828
829 if (contextArray.length) {
830 this.setOnArray(contextArray, 0, this.$stack.pop(), false);
831 } else {
832 contextArray[0] = this.$stack.pop();
833 }
834
835 this.$contexts.push(contextArray);
836 }
837
838 let src = this.$stack.pop();
839 this.$collections.push(src);
840 // eslint-disable-next-line no-undef
841 this.$functions.push(func);
842 const $storage = this.initOutput($offset - $length, emptyObj, emptyObj);
843 const $out = $storage[1];
844 const $invalidatedKeys = $storage[2];
845 const $new = $storage[3];
846 const $keyToKey = $storage[4];
847
848 if (Array.isArray(src)) {
849 throw new Error('groupBy only works on objects');
850 }
851
852 if ($new) {
853 Object.keys(src).forEach(key => {
854 this.$keys.push(key);
855 this.collectionFunction();
856 const res = '' + this.$stack.pop();
857 $keyToKey[key] = res;
858
859 if (!$out[res]) {
860 this.setOnObject($out, res, {}, $new);
861 }
862
863 this.setOnObject($out[res], key, src[key], $new);
864 });
865 } else {
866 const keysPendingDelete = {};
867 $invalidatedKeys.forEach(key => {
868 if ($keyToKey[key]) {
869 keysPendingDelete[$keyToKey[key]] = keysPendingDelete[$keyToKey[key]] || new Set();
870 keysPendingDelete[$keyToKey[key]].add(key);
871 }
872 });
873 $invalidatedKeys.forEach(key => {
874 if (!src.hasOwnProperty(key)) {
875 delete $keyToKey[key];
876 return;
877 }
878
879 this.$keys.push(key);
880 this.collectionFunction();
881 const res = '' + this.$stack.pop();
882 $keyToKey[key] = res;
883
884 if (!$out[res]) {
885 $out[res] = {};
886 }
887
888 this.setOnObject($out[res], key, src[key], $new);
889 this.setOnObject($out, res, $out[res], $new);
890
891 if (keysPendingDelete.hasOwnProperty(res)) {
892 keysPendingDelete[res].delete(key);
893 }
894 });
895 Object.keys(keysPendingDelete).forEach(res => {
896 if (keysPendingDelete[res].size > 0) {
897 keysPendingDelete[res].forEach(key => {
898 this.deleteOnObject($out[res], key, $new);
899 });
900
901 if (Object.keys($out[res]).length === 0) {
902 this.deleteOnObject($out, res, $new);
903 } else {
904 this.setOnObject($out, res, $out[res], $new);
905 }
906 }
907 });
908 }
909
910 $invalidatedKeys.clear();
911 this.$stack.push($out)
912 this.$functions.pop();
913 this.$collections.pop();
914 this.$currentSets.pop();
915 this.$contexts.pop();
916};
917module.exports.$values = function values($offset, $length) {
918 this.processValue(this.$expressions[++$offset]);
919 let src = this.$stack.pop();
920 this.$collections.push(src);
921 const $storage = this.initOutput($offset - $length, emptyArr, valuesOrKeysCacheFunc);
922 const $out = $storage[1];
923 const $invalidatedKeys = $storage[2];
924 const $new = $storage[3];
925 const {
926 $keyToIdx,
927 $idxToKey
928 } = $storage[4];
929
930 if ($new) {
931 Object.keys(src).forEach((key, idx) => {
932 $out[idx] = src[key];
933 $idxToKey[idx] = key;
934 $keyToIdx[key] = idx;
935 });
936 } else {
937 const $deletedKeys = [];
938 const $addedKeys = [];
939 const $touchedKeys = [];
940 $invalidatedKeys.forEach(key => {
941 if (src.hasOwnProperty(key) && !$keyToIdx.hasOwnProperty(key)) {
942 $addedKeys.push(key);
943 } else if (!src.hasOwnProperty(key) && $keyToIdx.hasOwnProperty(key)) {
944 $deletedKeys.push(key);
945 } else {
946 if ($keyToIdx.hasOwnProperty(key)) {
947 this.setOnObject($out, $keyToIdx[key], src[key], $new);
948 }
949 }
950 });
951
952 if ($addedKeys.length < $deletedKeys.length) {
953 $deletedKeys.sort((a, b) => $keyToIdx[a] - $keyToIdx[b]);
954 }
955
956 const $finalOutLength = $out.length - $deletedKeys.length + $addedKeys.length; // keys both deleted and added fill created holes first
957
958 for (let i = 0; i < $addedKeys.length && i < $deletedKeys.length; i++) {
959 const $addedKey = $addedKeys[i];
960 const $deletedKey = $deletedKeys[i];
961 const $newIdx = $keyToIdx[$deletedKey];
962 delete $keyToIdx[$deletedKey];
963 $keyToIdx[$addedKey] = $newIdx;
964 $idxToKey[$newIdx] = $addedKey;
965 this.setOnArray($out, $newIdx, src[$addedKey], $new);
966 } // more keys added - append to end
967
968
969 for (let i = $deletedKeys.length; i < $addedKeys.length; i++) {
970 const $addedKey = $addedKeys[i];
971 const $newIdx = $out.length;
972 $keyToIdx[$addedKey] = $newIdx;
973 $idxToKey[$newIdx] = $addedKey;
974 this.setOnArray($out, $newIdx, src[$addedKey], $new);
975 } // more keys deleted - move non deleted items at the tail to the location of deleted
976
977
978 const $deletedNotMoved = $deletedKeys.slice($addedKeys.length);
979 const $deletedNotMovedSet = new Set($deletedKeys.slice($addedKeys.length));
980 const $keysToMoveInside = new Set($idxToKey.slice($finalOutLength).filter(key => !$deletedNotMovedSet.has(key)));
981 let $savedCount = 0;
982
983 for (let $tailIdx = $finalOutLength; $tailIdx < $out.length; $tailIdx++) {
984 const $currentKey = $idxToKey[$tailIdx];
985
986 if ($keysToMoveInside.has($currentKey)) {
987 // need to move this key to one of the pending delete
988 const $switchedWithDeletedKey = $deletedNotMoved[$savedCount];
989 const $newIdx = $keyToIdx[$switchedWithDeletedKey];
990 this.setOnArray($out, $newIdx, src[$currentKey], $new);
991 $keyToIdx[$currentKey] = $newIdx;
992 $idxToKey[$newIdx] = $currentKey;
993 delete $keyToIdx[$switchedWithDeletedKey];
994 $savedCount++;
995 } else {
996 delete $keyToIdx[$currentKey];
997 }
998 }
999
1000 this.truncateArray($out, $finalOutLength);
1001 $idxToKey.length = $out.length;
1002 $invalidatedKeys.clear();
1003 }
1004
1005 this.$stack.push($out)
1006 this.$collections.pop();
1007 this.$currentSets.pop();
1008};
1009module.exports.$keys = function keys($offset, $length) {
1010 this.processValue(this.$expressions[++$offset]);
1011 let src = this.$stack.pop();
1012 this.$collections.push(src);
1013 const $storage = this.initOutput($offset - $length, emptyArr, valuesOrKeysCacheFunc);
1014 const $out = $storage[1];
1015 const $invalidatedKeys = $storage[2];
1016 const $new = $storage[3];
1017 const {
1018 $keyToIdx,
1019 $idxToKey
1020 } = $storage[4];
1021
1022 if ($new) {
1023 Object.keys(src).forEach((key, idx) => {
1024 $out[idx] = key;
1025 $idxToKey[idx] = key;
1026 $keyToIdx[key] = idx;
1027 });
1028 } else {
1029 const $deletedKeys = [];
1030 const $addedKeys = [];
1031 const $touchedKeys = [];
1032 $invalidatedKeys.forEach(key => {
1033 if (src.hasOwnProperty(key) && !$keyToIdx.hasOwnProperty(key)) {
1034 $addedKeys.push(key);
1035 } else if (!src.hasOwnProperty(key) && $keyToIdx.hasOwnProperty(key)) {
1036 $deletedKeys.push(key);
1037 } else {
1038 if ($keyToIdx.hasOwnProperty(key)) {
1039 this.setOnObject($out, $keyToIdx[key], key, $new);
1040 }
1041 }
1042 });
1043
1044 if ($addedKeys.length < $deletedKeys.length) {
1045 $deletedKeys.sort((a, b) => $keyToIdx[a] - $keyToIdx[b]);
1046 }
1047
1048 const $finalOutLength = $out.length - $deletedKeys.length + $addedKeys.length; // keys both deleted and added fill created holes first
1049
1050 for (let i = 0; i < $addedKeys.length && i < $deletedKeys.length; i++) {
1051 const $addedKey = $addedKeys[i];
1052 const $deletedKey = $deletedKeys[i];
1053 const $newIdx = $keyToIdx[$deletedKey];
1054 delete $keyToIdx[$deletedKey];
1055 $keyToIdx[$addedKey] = $newIdx;
1056 $idxToKey[$newIdx] = $addedKey;
1057 this.setOnArray($out, $newIdx, $addedKey, $new);
1058 } // more keys added - append to end
1059
1060
1061 for (let i = $deletedKeys.length; i < $addedKeys.length; i++) {
1062 const $addedKey = $addedKeys[i];
1063 const $newIdx = $out.length;
1064 $keyToIdx[$addedKey] = $newIdx;
1065 $idxToKey[$newIdx] = $addedKey;
1066 this.setOnArray($out, $newIdx, $addedKey, $new);
1067 } // more keys deleted - move non deleted items at the tail to the location of deleted
1068
1069
1070 const $deletedNotMoved = $deletedKeys.slice($addedKeys.length);
1071 const $deletedNotMovedSet = new Set($deletedKeys.slice($addedKeys.length));
1072 const $keysToMoveInside = new Set($idxToKey.slice($finalOutLength).filter(key => !$deletedNotMovedSet.has(key)));
1073 let $savedCount = 0;
1074
1075 for (let $tailIdx = $finalOutLength; $tailIdx < $out.length; $tailIdx++) {
1076 const $currentKey = $idxToKey[$tailIdx];
1077
1078 if ($keysToMoveInside.has($currentKey)) {
1079 // need to move this key to one of the pending delete
1080 const $switchedWithDeletedKey = $deletedNotMoved[$savedCount];
1081 const $newIdx = $keyToIdx[$switchedWithDeletedKey];
1082 this.setOnArray($out, $newIdx, $currentKey, $new);
1083 $keyToIdx[$currentKey] = $newIdx;
1084 $idxToKey[$newIdx] = $currentKey;
1085 delete $keyToIdx[$switchedWithDeletedKey];
1086 $savedCount++;
1087 } else {
1088 delete $keyToIdx[$currentKey];
1089 }
1090 }
1091
1092 this.truncateArray($out, $finalOutLength);
1093 $idxToKey.length = $out.length;
1094 $invalidatedKeys.clear();
1095 }
1096
1097 this.$stack.push($out)
1098 this.$collections.pop();
1099 this.$currentSets.pop();
1100};
1101module.exports.$array = function array($offset, $length) {
1102 const newVal = [];
1103
1104 for (let i = 1; i < $length; i++) {
1105 this.processValue(this.$expressions[++$offset]);
1106 newVal.push(this.$stack.pop());
1107 }
1108
1109 const len = $length - 1;
1110 const res = this.getEmptyArray(-$offset);
1111 const $new = res.length === 0;
1112
1113 for (let i = 0; i < len; i++) {
1114 this.setOnArray(res, i, newVal[i], $new);
1115 }
1116
1117 this.$stack.push(res)
1118};
1119module.exports.$object = function object($offset, $length) {
1120 const valsList = [];
1121
1122 for (let i = 2; i < $length; i += 2) {
1123 this.processValue(this.$expressions[$offset + i]);
1124 valsList.push(this.$stack.pop());
1125 }
1126
1127 let keysList = this.$globals.get($offset);
1128
1129 if (!keysList) {
1130 keysList = [];
1131
1132 for (let i = 1; i < $length; i += 2) {
1133 this.processValue(this.$expressions[$offset + i]);
1134 keysList.push(this.$stack.pop());
1135 }
1136
1137 this.$globals.set($offset, keysList);
1138 }
1139
1140 const res = this.getEmptyObject(-$offset);
1141 const $new = keysList.length && !res.hasOwnProperty(keysList[0]);
1142
1143 for (let i = 0; i < keysList.length; i++) {
1144 const name = keysList[i];
1145 this.setOnObject(res, name, valsList[i], $new);
1146 }
1147
1148 this.$stack.push(res)
1149};
1150module.exports.$call = function call($offset, $length) {
1151 const newVal = [];
1152
1153 for (let i = 1; i < $length; i++) {
1154 this.processValue(this.$expressions[++$offset]);
1155 newVal.push(this.$stack.pop());
1156 }
1157
1158 const len = $length - 1;
1159 const arr = this.getEmptyArray(-$offset);
1160 const $new = arr.length === 0;
1161
1162 if ($new) {
1163 arr.push([]);
1164 }
1165
1166 const args = arr[0];
1167
1168 for (let i = 0; i < len; i++) {
1169 this.setOnArray(args, i, newVal[i], $new);
1170 }
1171
1172 if (arr.length === 1 || this.$tainted.has(args)) {
1173 arr[1] = this.$funcLib[args[0]].apply(this.$res, args.slice(1));
1174 }
1175
1176 this.$stack.push(arr[1])
1177};
1178module.exports.$bind = function bind($offset, $length) {
1179 const newVal = [];
1180
1181 for (let i = 1; i < $length; i++) {
1182 this.processValue(this.$expressions[++$offset]);
1183 newVal.push(this.$stack.pop());
1184 }
1185
1186 const len = $length - 1;
1187 const arr = this.getEmptyArray(-$offset);
1188
1189 if (arr.length === 0) {
1190 arr.push([]);
1191 }
1192
1193 const args = arr[0];
1194
1195 for (let i = 0; i < len; i++) {
1196 args[i] = newVal[i];
1197 }
1198
1199 if (arr.length === 1) {
1200 arr[1] = (...extraArgs) => {
1201 const fn = this.$funcLibRaw[args[0]] || this.$res[args[0]];
1202 return fn.apply(this.$res, args.slice(1).concat(extraArgs));
1203 };
1204 }
1205
1206 this.$stack.push(arr[1])
1207};
1208module.exports.$assign = function assign($offset, $length) {
1209 this.processValue(this.$expressions[++$offset]);
1210 let src = this.$stack.pop();
1211 this.$collections.push(src);
1212 const $storage = this.initOutput($offset - $length, emptyObj, nullFunc);
1213 const $out = $storage[1];
1214 const $invalidatedKeys = $storage[2];
1215 const $new = $storage[3];
1216
1217 if ($new) {
1218 Object.assign($out, ...src);
1219 } else {
1220 const res = Object.assign({}, ...src);
1221 Object.keys(res).forEach(key => {
1222 this.setOnObject($out, key, res[key], $new);
1223 });
1224 Object.keys($out).forEach(key => {
1225 if (!res.hasOwnProperty(key)) {
1226 this.deleteOnObject($out, key, $new);
1227 }
1228 });
1229 $invalidatedKeys.clear();
1230 }
1231
1232 this.$stack.push($out)
1233 this.$collections.pop();
1234 this.$currentSets.pop();
1235};
1236module.exports.$defaults = function defaults($offset, $length) {
1237 this.processValue(this.$expressions[++$offset]);
1238 let src = this.$stack.pop();
1239 this.$collections.push(src);
1240 const $storage = this.initOutput($offset - $length, emptyObj, nullFunc);
1241 const $out = $storage[1];
1242 const $invalidatedKeys = $storage[2];
1243 const $new = $storage[3];
1244 src = [...src].reverse();
1245
1246 if ($new) {
1247 Object.assign($out, ...src);
1248 } else {
1249 const res = Object.assign({}, ...src);
1250 Object.keys(res).forEach(key => {
1251 this.setOnObject($out, key, res[key], $new);
1252 });
1253 Object.keys($out).forEach(key => {
1254 if (!res.hasOwnProperty(key)) {
1255 this.deleteOnObject($out, key, $new);
1256 }
1257 });
1258 $invalidatedKeys.clear();
1259 }
1260
1261 this.$stack.push($out)
1262 this.$collections.pop();
1263 this.$currentSets.pop();
1264};
1265module.exports.$flatten = function flatten($offset, $length) {
1266 this.processValue(this.$expressions[++$offset]);
1267 let src = this.$stack.pop();
1268 this.$collections.push(src);
1269 const $storage = this.initOutput($offset - $length, emptyArr, emptyArr);
1270 const $out = $storage[1];
1271 const $invalidatedKeys = $storage[2];
1272 const $new = $storage[3];
1273 const $cache = $storage[4];
1274 const length = src.length;
1275 const initialLength = $out.length;
1276
1277 if ($new) {
1278 for (let pos = 0, i = 0; i < length; i += 1) {
1279 $cache[i] = src[i].length;
1280
1281 for (let j = 0; j < $cache[i]; j += 1) {
1282 $out[pos + j] = src[i][j];
1283 }
1284
1285 pos += $cache[i];
1286 }
1287 } else {
1288 let pos = 0;
1289
1290 for (let key = 0; key < length; key += 1) {
1291 let partLen = src[key].length;
1292
1293 if ($invalidatedKeys.has(key)) {
1294 if ($cache[key] && $cache[key] === partLen) {
1295 src[key].forEach((value, index) => this.setOnArray($out, pos + index, value, $new));
1296 pos += $cache[key];
1297 } else {
1298 for (; key < length; key += 1) {
1299 partLen = src[key].length;
1300 src[key].forEach((value, index) => this.setOnArray($out, pos + index, value, $new));
1301 $cache[key] = partLen;
1302 pos += partLen;
1303 }
1304 }
1305 } else {
1306 pos += partLen;
1307 }
1308 }
1309
1310 $invalidatedKeys.clear();
1311 initialLength !== pos && this.truncateArray($out, pos);
1312 }
1313
1314 this.$stack.push($out)
1315 this.$collections.pop();
1316 this.$currentSets.pop();
1317};
1318module.exports.$size = function size($offset, $length) {
1319 this.processValue(this.$expressions[++$offset]);
1320 let src = this.$stack.pop();
1321 this.$collections.push(src);
1322 const $storage = this.initOutput($offset - $length, emptyArr, nullFunc);
1323 const $out = $storage[1];
1324 const $invalidatedKeys = $storage[2];
1325 const $new = $storage[3];
1326
1327 if ($new) {
1328 $out[0] = Array.isArray(src) ? src.length : Object.keys(src).length;
1329 }
1330
1331 if (!$new) {
1332 $out[0] = Array.isArray(src) ? src.length : Object.keys(src).length;
1333 $invalidatedKeys.clear();
1334 }
1335
1336 this.$stack.push($out[0])
1337 this.$collections.pop();
1338 this.$currentSets.pop();
1339};
1340module.exports.$sum = function sum($offset, $length) {
1341 this.processValue(this.$expressions[++$offset]);
1342 let src = this.$stack.pop();
1343 this.$collections.push(src);
1344 const $storage = this.initOutput($offset - $length, emptyArr, emptyArr);
1345 const $out = $storage[1];
1346 const $invalidatedKeys = $storage[2];
1347 const $new = $storage[3];
1348 const $cache = $storage[4];
1349 const length = src.length;
1350
1351 if ($new) {
1352 $cache[0] = 0;
1353 $cache[1] = [];
1354
1355 for (let i = 0; i < length; i++) {
1356 $cache[0] += src[i];
1357 $cache[1][i] = src[i];
1358 }
1359 } else {
1360 $invalidatedKeys.forEach(key => {
1361 const cached = $cache[1][key] || 0;
1362 const live = src[key] || 0;
1363 $cache[0] = $cache[0] - cached + live;
1364 $cache[1][key] = live;
1365 });
1366 $cache[1].length = length;
1367 $invalidatedKeys.clear();
1368 }
1369
1370 $out[0] = $cache[0];
1371 this.$stack.push($out[0])
1372 this.$collections.pop();
1373 this.$currentSets.pop();
1374};
1375module.exports.$range = function range($offset, $length) {
1376 this.processValue(this.$expressions[++$offset]);
1377
1378 if ($length > 2) {
1379 this.processValue(this.$expressions[++$offset]);
1380 } else {
1381 this.$stack.push(0);
1382 }
1383
1384 if ($length > 3) {
1385 this.processValue(this.$expressions[++$offset]);
1386 } else {
1387 this.$stack.push(1);
1388 }
1389
1390 const step = this.$stack.pop();
1391 const start = this.$stack.pop();
1392 const end = this.$stack.pop();
1393 const $out = this.getEmptyArray(-$offset);
1394 let res;
1395
1396 if ($out.length === 0) {
1397 res = [];
1398 $out.push(res);
1399
1400 for (let val = start; step > 0 && val < end || step < 0 && val > end; val += step) {
1401 res.push(val);
1402 }
1403 } else {
1404 let len = 0;
1405 res = $out[0];
1406
1407 for (let val = start; step > 0 && val < end || step < 0 && val > end; val += step) {
1408 this.setOnArray(res, len, val, false);
1409 len++;
1410 }
1411
1412 if (res.length > len) {
1413 this.truncateArray(res, len);
1414 }
1415 }
1416
1417 this.$stack.push(res)
1418};
1419
1420/*
1421// constantValues
1422this.$trackingMap = new WeakMap();
1423this.$trackingWildcards = new WeakMap();
1424this.$invalidatedMap = new WeakMap();
1425this.$invalidatedRoots = new Set();
1426this.$first = true;
1427this.$tainted = new WeakSet();
1428untrack($targetKeySet, $targetKey) {
1429 const $tracked = $targetKeySet.$tracked;
1430
1431 if (!$tracked || !$tracked[$targetKey]) {
1432 return;
1433 }
1434
1435 const $trackedByKey = $tracked[$targetKey];
1436
1437 for (let i = 0; i < $trackedByKey.length; i += 3) {
1438 const $trackingSource = this.$trackingMap.get($trackedByKey[i]);
1439 $trackingSource[$trackedByKey[i + 1]].delete($trackedByKey[i + 2]);
1440 }
1441
1442 delete $tracked[$targetKey];
1443}
1444invalidate($targetKeySet, $targetKey) {
1445 if ($targetKeySet.has($targetKey)) {
1446 return;
1447 }
1448
1449 $targetKeySet.add($targetKey);
1450 this.untrack($targetKeySet, $targetKey);
1451
1452 if ($targetKeySet.$parent) {
1453 this.invalidate($targetKeySet.$parent, $targetKeySet.$parentKey);
1454 }
1455}
1456setOnObject($target, $key, $val, $new) {
1457 let $changed = false;
1458 let $hard = false;
1459
1460 if (!$new) {
1461 if (typeof $target[$key] === 'object' && $target[$key] && $target[$key] !== $val) {
1462 $hard = true;
1463 }
1464
1465 if ($hard || $target[$key] !== $val || $val && typeof $val === 'object' && this.$tainted.has($val) || !$target.hasOwnProperty($key) && $target[$key] === undefined) {
1466 $changed = true;
1467 this.triggerInvalidations($target, $key, $hard);
1468 }
1469 }
1470
1471 $target[$key] = $val;
1472}
1473deleteOnObject($target, $key, $new) {
1474 let $hard = false;
1475
1476 if (!$new) {
1477 if (typeof $target[$key] === 'object' && $target[$key]) {
1478 $hard = true;
1479 }
1480
1481 this.triggerInvalidations($target, $key, $hard);
1482 const $invalidatedKeys = this.$invalidatedMap.get($target);
1483
1484 if ($invalidatedKeys) {
1485 delete $invalidatedKeys.$subKeys[$key];
1486 }
1487 }
1488
1489 delete $target[$key];
1490}
1491setOnArray($target, $key, $val, $new) {
1492 let $hard = false;
1493
1494 if (!$new) {
1495 if (typeof $target[$key] === 'object' && $target[$key] && $target[$key] !== $val) {
1496 $hard = true;
1497 }
1498
1499 if ($hard || $key >= $target.length || $target[$key] !== $val || $val && typeof $target[$key] === 'object' && this.$tainted.has($val)) {
1500 this.triggerInvalidations($target, $key, $hard);
1501 }
1502 }
1503
1504 $target[$key] = $val;
1505}
1506truncateArray($target, newLen) {
1507 for (let i = newLen; i < $target.length; i++) {
1508 this.triggerInvalidations($target, i, true);
1509 }
1510
1511 $target.length = newLen;
1512}
1513track($target, $sourceObj, $sourceKey, $soft) {
1514 if (!this.$trackingMap.has($sourceObj)) {
1515 this.$trackingMap.set($sourceObj, {});
1516 }
1517
1518 const $track = this.$trackingMap.get($sourceObj);
1519 $track[$sourceKey] = $track[$sourceKey] || new Map();
1520 $track[$sourceKey].set($target, $soft);
1521 const $tracked = $target[0].$tracked;
1522 $tracked[$target[1]] = $tracked[$target[1]] || [];
1523 $tracked[$target[1]].push($sourceObj, $sourceKey, $target);
1524}
1525trackPath($offset, $length) {
1526 const $end = $path.length - 2;
1527 let $current = $path[0];
1528
1529 for (let i = 0; i <= $end; i++) {
1530 this.track($target, $current, $path[i + 1], i !== $end);
1531 $current = $current[$path[i + 1]];
1532 }
1533}
1534triggerInvalidations($sourceObj, $sourceKey, $hard) {
1535 this.$tainted.add($sourceObj);
1536 const $track = this.$trackingMap.get($sourceObj);
1537
1538 if ($track && $track.hasOwnProperty($sourceKey)) {
1539 $track[$sourceKey].forEach(($soft, $target) => {
1540 if (!$soft || $hard) {
1541 this.invalidate($target[0], $target[1]);
1542 }
1543 });
1544 }
1545
1546 if (this.$trackingWildcards.has($sourceObj)) {
1547 this.$trackingWildcards.get($sourceObj).forEach($targetInvalidatedKeys => {
1548 this.invalidate($targetInvalidatedKeys, $sourceKey);
1549 });
1550 }
1551}
1552initOutput($tracked, src, func, createDefaultValue, createCacheValue) {
1553 const subKeys = $tracked[0].$subKeys;
1554 const $cachePerTargetKey = subKeys[$tracked[1]] = subKeys[$tracked[1]] || new Map();
1555 let $cachedByFunc = $cachePerTargetKey.get(func);
1556
1557 if (!$cachedByFunc) {
1558 const $resultObj = createDefaultValue();
1559 const $cacheValue = createCacheValue();
1560 const $invalidatedKeys = new Set();
1561 $invalidatedKeys.$subKeys = {};
1562 $invalidatedKeys.$parentKey = $tracked[1];
1563 $invalidatedKeys.$parent = $tracked[0];
1564 $invalidatedKeys.$tracked = {};
1565 this.$invalidatedMap.set($resultObj, $invalidatedKeys);
1566 $cachedByFunc = [null, $resultObj, $invalidatedKeys, true, $cacheValue];
1567 $cachePerTargetKey.set(func, $cachedByFunc);
1568 } else {
1569 $cachedByFunc[3] = false;
1570 }
1571
1572 const $invalidatedKeys = $cachedByFunc[2];
1573 const $prevSrc = $cachedByFunc[0];
1574
1575 if ($prevSrc !== src) {
1576 if ($prevSrc) {
1577 // prev mapped to a different collection
1578 this.$trackingWildcards.get($prevSrc).delete($invalidatedKeys);
1579
1580 if (Array.isArray($prevSrc)) {
1581 $prevSrc.forEach((_item, index) => $invalidatedKeys.add(index));
1582 } else {
1583 Object.keys($prevSrc).forEach(key => $invalidatedKeys.add(key));
1584 }
1585
1586 if (Array.isArray(src)) {
1587 src.forEach((_item, index) => $invalidatedKeys.add(index));
1588 } else {
1589 Object.keys(src).forEach(key => $invalidatedKeys.add(key));
1590 }
1591 }
1592
1593 if (!this.$trackingWildcards.has(src)) {
1594 this.$trackingWildcards.set(src, new Set());
1595 }
1596
1597 this.$trackingWildcards.get(src).add($invalidatedKeys);
1598 $cachedByFunc[0] = src;
1599 }
1600
1601 return $cachedByFunc;
1602}
1603getEmptyArray($tracked, token) {
1604 const subKeys = $tracked[0].$subKeys;
1605 const $cachePerTargetKey = subKeys[$tracked[1]] = subKeys[$tracked[1]] || new Map();
1606
1607 if (!$cachePerTargetKey.has(token)) {
1608 $cachePerTargetKey.set(token, []);
1609 }
1610
1611 return $cachePerTargetKey.get(token);
1612}
1613getEmptyObject($tracked, token) {
1614 const subKeys = $tracked[0].$subKeys;
1615 const $cachePerTargetKey = subKeys[$tracked[1]] = subKeys[$tracked[1]] || new Map();
1616
1617 if (!$cachePerTargetKey.has(token)) {
1618 $cachePerTargetKey.set(token, {});
1619 }
1620
1621 return $cachePerTargetKey.get(token);
1622}
1623invalidatePath(path) {
1624 path.forEach((part, index) => {
1625 this.triggerInvalidations(getAssignableObject(path, index), part, index === path.length - 1);
1626 });
1627}
1628set(path, value) {
1629 ensurePath(path);
1630 this.invalidatePath(path);
1631 applySetter(getAssignableObject(path, path.length - 1), path[path.length - 1], value);
1632}
1633splice(pathWithKey, len, ...newItems) {
1634 ensurePath(pathWithKey);
1635 const key = pathWithKey[pathWithKey.length - 1];
1636 const path = pathWithKey.slice(0, pathWithKey.length - 1);
1637 const arr = getAssignableObject(path, path.length);
1638 const origLength = arr.length;
1639 const end = len === newItems.length ? key + len : Math.max(origLength, origLength + newItems.length - len);
1640
1641 for (let i = key; i < end; i++) {
1642 this.triggerInvalidations(arr, i, true);
1643 }
1644
1645 this.invalidatePath(pathWithKey);
1646 arr.splice(key, len, ...newItems);
1647}
1648*/
1649