UNPKG

248 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('react-dom')) :
3 typeof define === 'function' && define.amd ? define(['exports', 'react', 'react-dom'], factory) :
4 (global = global || self, factory(global.Recoil = {}, global.React, global.ReactDOM));
5}(this, (function (exports, react, reactDom) { 'use strict';
6
7 react = react && Object.prototype.hasOwnProperty.call(react, 'default') ? react['default'] : react;
8 reactDom = reactDom && Object.prototype.hasOwnProperty.call(reactDom, 'default') ? reactDom['default'] : reactDom;
9
10 /**
11 * Copyright (c) Facebook, Inc. and its affiliates.
12 *
13 * This source code is licensed under the MIT license found in the
14 * LICENSE file in the root directory of this source tree.
15 *
16 * @emails oncall+recoil
17 *
18 * @format
19 */
20
21 // Split declaration and implementation to allow this function to pretend to
22 // check for actual instance of Promise instead of something with a `then`
23 // method.
24 // eslint-disable-next-line no-redeclare
25 function isPromise(p) {
26 return !!p && typeof p.then === 'function';
27 }
28
29 var Recoil_isPromise = isPromise;
30
31 /**
32 * Copyright (c) Facebook, Inc. and its affiliates.
33 *
34 * This source code is licensed under the MIT license found in the
35 * LICENSE file in the root directory of this source tree.
36 *
37 * @emails oncall+recoil
38 *
39 * @format
40 */
41
42 function nullthrows(x, message) {
43 if (x != null) {
44 return x;
45 }
46
47 throw new Error(message !== null && message !== void 0 ? message : 'Got unexpected null or undefined');
48 }
49
50 var Recoil_nullthrows = nullthrows;
51
52 // TODO Convert Loadable to a Class to allow for runtime type detection.
53 // Containing static factories of withValue(), withError(), withPromise(), and all()
54
55
56 class Canceled {}
57
58 const CANCELED = new Canceled();
59 const loadableAccessors = {
60 valueMaybe() {
61 return undefined;
62 },
63
64 valueOrThrow() {
65 const error = new Error( // $FlowFixMe[object-this-reference]
66 `Loadable expected value, but in "${this.state}" state`); // V8 keeps closures alive until stack is accessed, this prevents a memory leak
67 throw error;
68 },
69
70 errorMaybe() {
71 return undefined;
72 },
73
74 errorOrThrow() {
75 const error = new Error( // $FlowFixMe[object-this-reference]
76 `Loadable expected error, but in "${this.state}" state`); // V8 keeps closures alive until stack is accessed, this prevents a memory leak
77 throw error;
78 },
79
80 promiseMaybe() {
81 return undefined;
82 },
83
84 promiseOrThrow() {
85 const error = new Error( // $FlowFixMe[object-this-reference]
86 `Loadable expected promise, but in "${this.state}" state`); // V8 keeps closures alive until stack is accessed, this prevents a memory leak
87 throw error;
88 },
89
90 is(other) {
91 // $FlowFixMe[object-this-reference]
92 return other.state === this.state && other.contents === this.contents;
93 },
94
95 // TODO Unit tests
96 // TODO Convert Loadable to a Class to better support chaining
97 // by returning a Loadable from a map function
98 map(map) {
99 // $FlowFixMe[object-this-reference]
100 if (this.state === 'hasError') {
101 // $FlowFixMe[object-this-reference]
102 return this;
103 } // $FlowFixMe[object-this-reference]
104
105
106 if (this.state === 'hasValue') {
107 try {
108 // $FlowFixMe[object-this-reference]
109 const next = map(this.contents); // TODO if next instanceof Loadable, then return next
110
111 return Recoil_isPromise(next) ? loadableWithPromise(next) : loadableWithValue(next);
112 } catch (e) {
113 return Recoil_isPromise(e) ? // If we "suspended", then try again.
114 // errors and subsequent retries will be handled in 'loading' case
115 // $FlowFixMe[object-this-reference]
116 loadableWithPromise(e.next(() => map(this.contents))) : loadableWithError(e);
117 }
118 } // $FlowFixMe[object-this-reference]
119
120
121 if (this.state === 'loading') {
122 return loadableWithPromise( // $FlowFixMe[object-this-reference]
123 this.contents // TODO if map returns a loadable, then return the value or promise or throw the error
124 .then(map).catch(e => {
125 if (Recoil_isPromise(e)) {
126 // we were "suspended," try again
127 // $FlowFixMe[object-this-reference]
128 return e.then(() => map(this.contents));
129 }
130
131 throw e;
132 }));
133 }
134
135 const error = new Error('Invalid Loadable state'); // V8 keeps closures alive until stack is accessed, this prevents a memory leak
136 throw error;
137 }
138
139 };
140
141 function loadableWithValue(value) {
142 // Build objects this way since Flow doesn't support disjoint unions for class properties
143 return Object.freeze({
144 state: 'hasValue',
145 contents: value,
146 ...loadableAccessors,
147
148 getValue() {
149 return this.contents;
150 },
151
152 toPromise() {
153 return Promise.resolve(this.contents);
154 },
155
156 valueMaybe() {
157 return this.contents;
158 },
159
160 valueOrThrow() {
161 return this.contents;
162 }
163
164 });
165 }
166
167 function loadableWithError(error) {
168 return Object.freeze({
169 state: 'hasError',
170 contents: error,
171 ...loadableAccessors,
172
173 getValue() {
174 throw this.contents;
175 },
176
177 toPromise() {
178 return Promise.reject(this.contents);
179 },
180
181 errorMaybe() {
182 return this.contents;
183 },
184
185 errorOrThrow() {
186 return this.contents;
187 }
188
189 });
190 }
191
192 function loadableWithPromise(promise) {
193 return Object.freeze({
194 state: 'loading',
195 contents: promise,
196 ...loadableAccessors,
197
198 getValue() {
199 throw this.contents.then(({
200 __value
201 }) => __value);
202 },
203
204 toPromise() {
205 return this.contents.then(({
206 __value
207 }) => __value);
208 },
209
210 promiseMaybe() {
211 return this.contents.then(({
212 __value
213 }) => __value);
214 },
215
216 promiseOrThrow() {
217 return this.contents.then(({
218 __value
219 }) => __value);
220 }
221
222 });
223 }
224
225 function loadableLoading() {
226 return loadableWithPromise(new Promise(() => {}));
227 }
228
229 function loadableAll(inputs) {
230 return inputs.every(i => i.state === 'hasValue') ? loadableWithValue(inputs.map(i => i.contents)) : inputs.some(i => i.state === 'hasError') ? loadableWithError(Recoil_nullthrows(inputs.find(i => i.state === 'hasError'), 'Invalid loadable passed to loadableAll').contents) : loadableWithPromise(Promise.all(inputs.map(i => i.contents)).then(value => ({
231 __value: value
232 })));
233 }
234
235 var Recoil_Loadable = {
236 loadableWithValue,
237 loadableWithError,
238 loadableWithPromise,
239 loadableLoading,
240 loadableAll,
241 Canceled,
242 CANCELED
243 };
244
245 var _useMutableSource;
246
247 // FIXME T2710559282599660
248
249
250 const useMutableSource = // flowlint-line unclear-type:off
251 (_useMutableSource = react.useMutableSource) !== null && _useMutableSource !== void 0 ? _useMutableSource : react.unstable_useMutableSource; // flowlint-line unclear-type:off
252
253 function mutableSourceExists() {
254 return useMutableSource && !(typeof window !== 'undefined' && window.$disableRecoilValueMutableSource_TEMP_HACK_DO_NOT_USE);
255 }
256
257 var Recoil_mutableSource = {
258 mutableSourceExists,
259 useMutableSource
260 };
261
262 const {
263 mutableSourceExists: mutableSourceExists$1
264 } = Recoil_mutableSource;
265
266 const gks = new Map().set('recoil_hamt_2020', true).set('recoil_memory_managament_2020', true);
267
268 function Recoil_gkx(gk) {
269 var _gks$get;
270
271 if (gk === 'recoil_early_rendering_2021' && !mutableSourceExists$1()) {
272 return false;
273 }
274
275 return (_gks$get = gks.get(gk)) !== null && _gks$get !== void 0 ? _gks$get : false;
276 }
277
278 Recoil_gkx.setPass = gk => {
279 gks.set(gk, true);
280 };
281
282 Recoil_gkx.setFail = gk => {
283 gks.set(gk, false);
284 };
285
286 var Recoil_gkx_1 = Recoil_gkx; // @oss-only
287
288 /**
289 * Copyright (c) Facebook, Inc. and its affiliates.
290 *
291 * This source code is licensed under the MIT license found in the
292 * LICENSE file in the root directory of this source tree.
293 *
294 * @emails oncall+recoil
295 *
296 * @format
297 */
298
299 function recoverableViolation(message, projectName, {
300 error
301 } = {}) {
302 {
303 console.error(message, error);
304 }
305
306 return null;
307 }
308
309 var recoverableViolation_1 = recoverableViolation;
310
311 // @oss-only
312
313
314 var Recoil_recoverableViolation = recoverableViolation_1;
315
316 /**
317 * Copyright (c) Facebook, Inc. and its affiliates.
318 *
319 * This source code is licensed under the MIT license found in the
320 * LICENSE file in the root directory of this source tree.
321 *
322 * Utilities for working with built-in Maps and Sets without mutating them.
323 *
324 * @emails oncall+recoil
325 *
326 * @format
327 */
328
329 function setByAddingToSet(set, v) {
330 const next = new Set(set);
331 next.add(v);
332 return next;
333 }
334
335 function setByDeletingFromSet(set, v) {
336 const next = new Set(set);
337 next.delete(v);
338 return next;
339 }
340
341 function mapBySettingInMap(map, k, v) {
342 const next = new Map(map);
343 next.set(k, v);
344 return next;
345 }
346
347 function mapByUpdatingInMap(map, k, updater) {
348 const next = new Map(map);
349 next.set(k, updater(next.get(k)));
350 return next;
351 }
352
353 function mapByDeletingFromMap(map, k) {
354 const next = new Map(map);
355 next.delete(k);
356 return next;
357 }
358
359 function mapByDeletingMultipleFromMap(map, ks) {
360 const next = new Map(map);
361 ks.forEach(k => next.delete(k));
362 return next;
363 }
364
365 var Recoil_CopyOnWrite = {
366 setByAddingToSet,
367 setByDeletingFromSet,
368 mapBySettingInMap,
369 mapByUpdatingInMap,
370 mapByDeletingFromMap,
371 mapByDeletingMultipleFromMap
372 };
373
374 /**
375 * Copyright (c) Facebook, Inc. and its affiliates.
376 *
377 * This source code is licensed under the MIT license found in the
378 * LICENSE file in the root directory of this source tree.
379 *
380 * @emails oncall+recoil
381 *
382 * @format
383 */
384 /**
385 * Creates a new iterable whose output is generated by passing the input
386 * iterable's values through the filter function.
387 */
388
389 function* filterIterable(iterable, predicate) {
390 // Use generator to create iterable/iterator
391 let index = 0;
392
393 for (const value of iterable) {
394 if (predicate(value, index++)) {
395 yield value;
396 }
397 }
398 }
399
400 var Recoil_filterIterable = filterIterable;
401
402 /**
403 * Copyright (c) Facebook, Inc. and its affiliates.
404 *
405 * This source code is licensed under the MIT license found in the
406 * LICENSE file in the root directory of this source tree.
407 *
408 * @emails oncall+recoil
409 *
410 * @format
411 */
412 /**
413 * Creates a new iterable whose output is generated by passing the input
414 * iterable's values through the mapper function.
415 */
416
417 function mapIterable(iterable, callback) {
418 // Use generator to create iterable/iterator
419 return function* () {
420 let index = 0;
421
422 for (const value of iterable) {
423 yield callback(value, index++);
424 }
425 }();
426 }
427
428 var Recoil_mapIterable = mapIterable;
429
430 /**
431 * Copyright (c) Facebook, Inc. and its affiliates.
432 *
433 * This source code is licensed under the MIT license found in the
434 * LICENSE file in the root directory of this source tree.
435 *
436 * @emails oncall+recoil
437 *
438 * @format
439 */
440
441 function sprintf(format, ...args) {
442 let index = 0;
443 return format.replace(/%s/g, () => String(args[index++]));
444 }
445
446 var sprintf_1 = sprintf;
447
448 function expectationViolation(format, ...args) {
449 {
450 const message = sprintf_1.call(null, format, ...args);
451 const error = new Error(message);
452 error.name = 'Expectation Violation';
453 console.error(error);
454 }
455 }
456
457 var expectationViolation_1 = expectationViolation;
458
459 // @oss-only
460
461
462 var Recoil_expectationViolation = expectationViolation_1;
463
464 function _defineProperty(obj, key, value) {
465 if (key in obj) {
466 Object.defineProperty(obj, key, {
467 value: value,
468 enumerable: true,
469 configurable: true,
470 writable: true
471 });
472 } else {
473 obj[key] = value;
474 }
475
476 return obj;
477 }
478
479 /**
480 * Copyright (c) Facebook, Inc. and its affiliates.
481 *
482 * This source code is licensed under the MIT license found in the
483 * LICENSE file in the root directory of this source tree.
484 *
485 * @emails oncall+recoil
486 *
487 * @format
488 */
489
490 // eslint-disable-next-line no-unused-vars
491 class AbstractRecoilValue {
492 constructor(newKey) {
493 _defineProperty(this, "key", void 0);
494
495 this.key = newKey;
496 }
497
498 }
499
500 class RecoilState extends AbstractRecoilValue {}
501
502 class RecoilValueReadOnly extends AbstractRecoilValue {}
503
504 function isRecoilValue(x) {
505 return x instanceof RecoilState || x instanceof RecoilValueReadOnly;
506 }
507
508 var Recoil_RecoilValue = {
509 AbstractRecoilValue,
510 RecoilState,
511 RecoilValueReadOnly,
512 isRecoilValue
513 };
514
515 var Recoil_RecoilValue_1 = Recoil_RecoilValue.AbstractRecoilValue;
516 var Recoil_RecoilValue_2 = Recoil_RecoilValue.RecoilState;
517 var Recoil_RecoilValue_3 = Recoil_RecoilValue.RecoilValueReadOnly;
518 var Recoil_RecoilValue_4 = Recoil_RecoilValue.isRecoilValue;
519
520 var Recoil_RecoilValue$1 = /*#__PURE__*/Object.freeze({
521 __proto__: null,
522 AbstractRecoilValue: Recoil_RecoilValue_1,
523 RecoilState: Recoil_RecoilValue_2,
524 RecoilValueReadOnly: Recoil_RecoilValue_3,
525 isRecoilValue: Recoil_RecoilValue_4
526 });
527
528 class DefaultValue {}
529
530 const DEFAULT_VALUE = new DefaultValue();
531
532 class RecoilValueNotReady extends Error {
533 constructor(key) {
534 super(`Tried to set the value of Recoil selector ${key} using an updater function, but it is an async selector in a pending or error state; this is not supported.`);
535 }
536
537 }
538
539 // flowlint-next-line unclear-type:off
540 const nodes = new Map(); // flowlint-next-line unclear-type:off
541
542 const recoilValues = new Map();
543 /* eslint-disable no-redeclare */
544
545 function recoilValuesForKeys(keys) {
546 return Recoil_mapIterable(keys, key => Recoil_nullthrows(recoilValues.get(key)));
547 }
548
549 function registerNode(node) {
550 if (nodes.has(node.key)) {
551 const message = `Duplicate atom key "${node.key}". This is a FATAL ERROR in
552 production. But it is safe to ignore this warning if it occurred because of
553 hot module replacement.`; // TODO Need to figure out if there is a standard/open-source equivalent to see if hot module replacement is happening:
554 // prettier-ignore
555 // @fb-only: if (__DEV__) {
556 // @fb-only: const isAcceptingUpdate = require('__debug').isAcceptingUpdate;
557 // prettier-ignore
558 // @fb-only: if (typeof isAcceptingUpdate !== 'function' || !isAcceptingUpdate()) {
559 // @fb-only: expectationViolation(message, 'recoil');
560 // @fb-only: }
561 // prettier-ignore
562 // @fb-only: } else {
563 // @fb-only: recoverableViolation(message, 'recoil');
564 // @fb-only: }
565
566 console.warn(message); // @oss-only
567 }
568
569 nodes.set(node.key, node);
570 const recoilValue = node.set == null ? new Recoil_RecoilValue$1.RecoilValueReadOnly(node.key) : new Recoil_RecoilValue$1.RecoilState(node.key);
571 recoilValues.set(node.key, recoilValue);
572 return recoilValue;
573 }
574 /* eslint-enable no-redeclare */
575
576
577 class NodeMissingError extends Error {} // flowlint-next-line unclear-type:off
578
579
580 function getNode(key) {
581 const node = nodes.get(key);
582
583 if (node == null) {
584 throw new NodeMissingError(`Missing definition for RecoilValue: "${key}""`);
585 }
586
587 return node;
588 } // flowlint-next-line unclear-type:off
589
590
591 function getNodeMaybe(key) {
592 return nodes.get(key);
593 }
594
595 const configDeletionHandlers = new Map();
596
597 function deleteNodeConfigIfPossible(key) {
598 var _node$shouldDeleteCon;
599
600 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
601 return;
602 }
603
604 const node = nodes.get(key);
605
606 if (node === null || node === void 0 ? void 0 : (_node$shouldDeleteCon = node.shouldDeleteConfigOnRelease) === null || _node$shouldDeleteCon === void 0 ? void 0 : _node$shouldDeleteCon.call(node)) {
607 var _getConfigDeletionHan;
608
609 nodes.delete(key);
610 (_getConfigDeletionHan = getConfigDeletionHandler(key)) === null || _getConfigDeletionHan === void 0 ? void 0 : _getConfigDeletionHan();
611 configDeletionHandlers.delete(key);
612 }
613 }
614
615 function setConfigDeletionHandler(key, fn) {
616 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
617 return;
618 }
619
620 if (fn === undefined) {
621 configDeletionHandlers.delete(key);
622 } else {
623 configDeletionHandlers.set(key, fn);
624 }
625 }
626
627 function getConfigDeletionHandler(key) {
628 return configDeletionHandlers.get(key);
629 }
630
631 var Recoil_Node = {
632 nodes,
633 recoilValues,
634 registerNode,
635 getNode,
636 getNodeMaybe,
637 deleteNodeConfigIfPossible,
638 setConfigDeletionHandler,
639 getConfigDeletionHandler,
640 recoilValuesForKeys,
641 NodeMissingError,
642 DefaultValue,
643 DEFAULT_VALUE,
644 RecoilValueNotReady
645 };
646
647 /**
648 * Copyright (c) Facebook, Inc. and its affiliates.
649 *
650 * This source code is licensed under the MIT license found in the
651 * LICENSE file in the root directory of this source tree.
652 *
653 * @emails oncall+recoil
654 *
655 * @format
656 */
657
658 class RetentionZone {}
659
660 function retentionZone() {
661 return new RetentionZone();
662 }
663
664 var Recoil_RetentionZone = {
665 RetentionZone,
666 retentionZone
667 };
668
669 const {
670 setByAddingToSet: setByAddingToSet$1
671 } = Recoil_CopyOnWrite;
672
673
674
675
676
677
678
679 const {
680 getNode: getNode$1,
681 getNodeMaybe: getNodeMaybe$1,
682 recoilValuesForKeys: recoilValuesForKeys$1
683 } = Recoil_Node;
684
685 const {
686 RetentionZone: RetentionZone$1
687 } = Recoil_RetentionZone; // flowlint-next-line unclear-type:off
688
689
690 const emptySet = Object.freeze(new Set());
691
692 class ReadOnlyRecoilValueError extends Error {}
693
694 function initializeRetentionForNode(store, nodeKey, retainedBy) {
695 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
696 return () => undefined;
697 }
698
699 const {
700 nodesRetainedByZone
701 } = store.getState().retention;
702
703 function addToZone(zone) {
704 let set = nodesRetainedByZone.get(zone);
705
706 if (!set) {
707 nodesRetainedByZone.set(zone, set = new Set());
708 }
709
710 set.add(nodeKey);
711 }
712
713 if (retainedBy instanceof RetentionZone$1) {
714 addToZone(retainedBy);
715 } else if (Array.isArray(retainedBy)) {
716 for (const zone of retainedBy) {
717 addToZone(zone);
718 }
719 }
720
721 return () => {
722 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
723 return;
724 }
725
726 const nodesRetainedByZone = store.getState().retention.nodesRetainedByZone;
727
728 function deleteFromZone(zone) {
729 const set = nodesRetainedByZone.get(zone);
730
731 if (set) {
732 set.delete(nodeKey);
733 }
734
735 if (set && set.size === 0) {
736 nodesRetainedByZone.delete(zone);
737 }
738 }
739
740 if (retainedBy instanceof RetentionZone$1) {
741 deleteFromZone(retainedBy);
742 } else if (Array.isArray(retainedBy)) {
743 for (const zone of retainedBy) {
744 deleteFromZone(zone);
745 }
746 }
747 };
748 }
749
750 function initializeNodeIfNewToStore(store, treeState, key, trigger) {
751 const storeState = store.getState();
752
753 if (storeState.nodeCleanupFunctions.has(key)) {
754 return;
755 }
756
757 const config = getNode$1(key);
758 const retentionCleanup = initializeRetentionForNode(store, key, config.retainedBy);
759 const nodeCleanup = config.init(store, treeState, trigger);
760 storeState.nodeCleanupFunctions.set(key, () => {
761 nodeCleanup();
762 retentionCleanup();
763 });
764 }
765
766 function cleanUpNode(store, key) {
767 var _state$nodeCleanupFun;
768
769 const state = store.getState();
770 (_state$nodeCleanupFun = state.nodeCleanupFunctions.get(key)) === null || _state$nodeCleanupFun === void 0 ? void 0 : _state$nodeCleanupFun();
771 state.nodeCleanupFunctions.delete(key);
772 } // Get the current value loadable of a node and update the state.
773 // Update dependencies and subscriptions for selectors.
774 // Update saved value validation for atoms.
775
776
777 function getNodeLoadable(store, state, key) {
778 initializeNodeIfNewToStore(store, state, key, 'get');
779 return getNode$1(key).get(store, state);
780 } // Peek at the current value loadable for a node without any evaluation or state change
781
782
783 function peekNodeLoadable(store, state, key) {
784 return getNode$1(key).peek(store, state);
785 } // Write value directly to state bypassing the Node interface as the node
786 // definitions may not have been loaded yet when processing the initial snapshot.
787
788
789 function setUnvalidatedAtomValue_DEPRECATED(state, key, newValue) {
790 var _node$invalidate;
791
792 const node = getNodeMaybe$1(key);
793 node === null || node === void 0 ? void 0 : (_node$invalidate = node.invalidate) === null || _node$invalidate === void 0 ? void 0 : _node$invalidate.call(node, state);
794 return { ...state,
795 atomValues: state.atomValues.clone().delete(key),
796 nonvalidatedAtoms: state.nonvalidatedAtoms.clone().set(key, newValue),
797 dirtyAtoms: setByAddingToSet$1(state.dirtyAtoms, key)
798 };
799 } // Return the discovered dependencies and values to be written by setting
800 // a node value. (Multiple values may be written due to selectors getting to
801 // set upstreams; deps may be discovered because of reads in updater functions.)
802
803
804 function setNodeValue(store, state, key, newValue) {
805 const node = getNode$1(key);
806
807 if (node.set == null) {
808 throw new ReadOnlyRecoilValueError(`Attempt to set read-only RecoilValue: ${key}`);
809 }
810
811 const set = node.set; // so flow doesn't lose the above refinement.
812
813 initializeNodeIfNewToStore(store, state, key, 'set');
814 return set(store, state, newValue);
815 }
816
817 function peekNodeInfo(store, state, key) {
818 var _graph$nodeDeps$get, _storeState$nodeToCom, _storeState$nodeToCom2;
819
820 const storeState = store.getState();
821 const graph = store.getGraph(state.version);
822 const type = storeState.knownAtoms.has(key) ? 'atom' : storeState.knownSelectors.has(key) ? 'selector' : undefined;
823 const downstreamNodes = Recoil_filterIterable(getDownstreamNodes(store, state, new Set([key])), nodeKey => nodeKey !== key);
824 return {
825 loadable: peekNodeLoadable(store, state, key),
826 isActive: storeState.knownAtoms.has(key) || storeState.knownSelectors.has(key),
827 isSet: type === 'selector' ? false : state.atomValues.has(key),
828 isModified: state.dirtyAtoms.has(key),
829 type,
830 // Report current dependencies. If the node hasn't been evaluated, then
831 // dependencies may be missing based on the current state.
832 deps: recoilValuesForKeys$1((_graph$nodeDeps$get = graph.nodeDeps.get(key)) !== null && _graph$nodeDeps$get !== void 0 ? _graph$nodeDeps$get : []),
833 // Reportsall "current" subscribers. Evaluating other nodes or
834 // previous in-progress async evaluations may introduce new subscribers.
835 subscribers: {
836 nodes: recoilValuesForKeys$1(downstreamNodes),
837 components: Recoil_mapIterable((_storeState$nodeToCom = (_storeState$nodeToCom2 = storeState.nodeToComponentSubscriptions.get(key)) === null || _storeState$nodeToCom2 === void 0 ? void 0 : _storeState$nodeToCom2.values()) !== null && _storeState$nodeToCom !== void 0 ? _storeState$nodeToCom : [], ([name]) => ({
838 name
839 }))
840 }
841 };
842 } // Find all of the recursively dependent nodes
843
844
845 function getDownstreamNodes(store, state, keys) {
846 const visitedNodes = new Set();
847 const visitingNodes = Array.from(keys);
848 const graph = store.getGraph(state.version);
849
850 for (let key = visitingNodes.pop(); key; key = visitingNodes.pop()) {
851 var _graph$nodeToNodeSubs;
852
853 visitedNodes.add(key);
854 const subscribedNodes = (_graph$nodeToNodeSubs = graph.nodeToNodeSubscriptions.get(key)) !== null && _graph$nodeToNodeSubs !== void 0 ? _graph$nodeToNodeSubs : emptySet;
855
856 for (const downstreamNode of subscribedNodes) {
857 if (!visitedNodes.has(downstreamNode)) {
858 visitingNodes.push(downstreamNode);
859 }
860 }
861 }
862
863 return visitedNodes;
864 }
865
866 var Recoil_FunctionalCore = {
867 getNodeLoadable,
868 peekNodeLoadable,
869 setNodeValue,
870 cleanUpNode,
871 setUnvalidatedAtomValue_DEPRECATED,
872 peekNodeInfo,
873 getDownstreamNodes,
874 initializeNodeIfNewToStore
875 };
876
877 const {
878 CANCELED: CANCELED$1
879 } = Recoil_Loadable;
880
881
882
883
884
885
886
887 const {
888 getDownstreamNodes: getDownstreamNodes$1,
889 getNodeLoadable: getNodeLoadable$1,
890 setNodeValue: setNodeValue$1
891 } = Recoil_FunctionalCore;
892
893 const {
894 getNodeMaybe: getNodeMaybe$2
895 } = Recoil_Node;
896
897 const {
898 DefaultValue: DefaultValue$1,
899 RecoilValueNotReady: RecoilValueNotReady$1
900 } = Recoil_Node;
901
902 const {
903 AbstractRecoilValue: AbstractRecoilValue$1,
904 RecoilState: RecoilState$1,
905 RecoilValueReadOnly: RecoilValueReadOnly$1,
906 isRecoilValue: isRecoilValue$1
907 } = Recoil_RecoilValue$1;
908
909 function getRecoilValueAsLoadable(store, {
910 key
911 }, treeState = store.getState().currentTree) {
912 var _storeState$nextTree, _storeState$previousT;
913
914 // Reading from an older tree can cause bugs because the dependencies that we
915 // discover during the read are lost.
916 const storeState = store.getState();
917
918 if (!(treeState.version === storeState.currentTree.version || treeState.version === ((_storeState$nextTree = storeState.nextTree) === null || _storeState$nextTree === void 0 ? void 0 : _storeState$nextTree.version) || treeState.version === ((_storeState$previousT = storeState.previousTree) === null || _storeState$previousT === void 0 ? void 0 : _storeState$previousT.version))) {
919 Recoil_recoverableViolation('Tried to read from a discarded tree');
920 }
921
922 const loadable = getNodeLoadable$1(store, treeState, key);
923
924 if (loadable.state === 'loading') {
925 loadable.contents.catch(() => {
926 /**
927 * HACK: intercept thrown error here to prevent an uncaught promise exception. Ideally this would happen closer to selector
928 * execution (perhaps introducing a new ERROR class to be resolved by async selectors that are in an error state)
929 */
930 return CANCELED$1;
931 });
932 }
933
934 return loadable;
935 }
936
937 function applyAtomValueWrites(atomValues, writes) {
938 const result = atomValues.clone();
939 writes.forEach((v, k) => {
940 if (v.state === 'hasValue' && v.contents instanceof DefaultValue$1) {
941 result.delete(k);
942 } else {
943 result.set(k, v);
944 }
945 });
946 return result;
947 }
948
949 function valueFromValueOrUpdater(store, state, {
950 key
951 }, valueOrUpdater) {
952 if (typeof valueOrUpdater === 'function') {
953 // Updater form: pass in the current value. Throw if the current value
954 // is unavailable (namely when updating an async selector that's
955 // pending or errored):
956 const current = getNodeLoadable$1(store, state, key);
957
958 if (current.state === 'loading') {
959 throw new RecoilValueNotReady$1(key);
960 } else if (current.state === 'hasError') {
961 throw current.contents;
962 } // T itself may be a function, so our refinement is not sufficient:
963
964
965 return valueOrUpdater(current.contents); // flowlint-line unclear-type:off
966 } else {
967 return valueOrUpdater;
968 }
969 }
970
971 function applyAction(store, state, action) {
972 if (action.type === 'set') {
973 const {
974 recoilValue,
975 valueOrUpdater
976 } = action;
977 const newValue = valueFromValueOrUpdater(store, state, recoilValue, valueOrUpdater);
978 const writes = setNodeValue$1(store, state, recoilValue.key, newValue);
979
980 for (const [key, loadable] of writes.entries()) {
981 writeLoadableToTreeState(state, key, loadable);
982 }
983 } else if (action.type === 'setLoadable') {
984 const {
985 recoilValue: {
986 key
987 },
988 loadable
989 } = action;
990 writeLoadableToTreeState(state, key, loadable);
991 } else if (action.type === 'markModified') {
992 const {
993 recoilValue: {
994 key
995 }
996 } = action;
997 state.dirtyAtoms.add(key);
998 } else if (action.type === 'setUnvalidated') {
999 var _node$invalidate;
1000
1001 // Write value directly to state bypassing the Node interface as the node
1002 // definitions may not have been loaded yet when processing the initial snapshot.
1003 const {
1004 recoilValue: {
1005 key
1006 },
1007 unvalidatedValue
1008 } = action;
1009 const node = getNodeMaybe$2(key);
1010 node === null || node === void 0 ? void 0 : (_node$invalidate = node.invalidate) === null || _node$invalidate === void 0 ? void 0 : _node$invalidate.call(node, state);
1011 state.atomValues.delete(key);
1012 state.nonvalidatedAtoms.set(key, unvalidatedValue);
1013 state.dirtyAtoms.add(key);
1014 } else {
1015 Recoil_recoverableViolation(`Unknown action ${action.type}`);
1016 }
1017 }
1018
1019 function writeLoadableToTreeState(state, key, loadable) {
1020 if (loadable.state === 'hasValue' && loadable.contents instanceof DefaultValue$1) {
1021 state.atomValues.delete(key);
1022 } else {
1023 state.atomValues.set(key, loadable);
1024 }
1025
1026 state.dirtyAtoms.add(key);
1027 state.nonvalidatedAtoms.delete(key);
1028 }
1029
1030 function applyActionsToStore(store, actions) {
1031 store.replaceState(state => {
1032 const newState = copyTreeState(state);
1033
1034 for (const action of actions) {
1035 applyAction(store, newState, action);
1036 }
1037
1038 invalidateDownstreams(store, newState);
1039 return newState;
1040 });
1041 }
1042
1043 function queueOrPerformStateUpdate(store, action) {
1044 if (batchStack.length) {
1045 const actionsByStore = batchStack[batchStack.length - 1];
1046 let actions = actionsByStore.get(store);
1047
1048 if (!actions) {
1049 actionsByStore.set(store, actions = []);
1050 }
1051
1052 actions.push(action);
1053 } else {
1054 applyActionsToStore(store, [action]);
1055 }
1056 }
1057
1058 const batchStack = [];
1059
1060 function batchStart() {
1061 const actionsByStore = new Map();
1062 batchStack.push(actionsByStore);
1063 return () => {
1064 for (const [store, actions] of actionsByStore) {
1065 applyActionsToStore(store, actions);
1066 }
1067
1068 const popped = batchStack.pop();
1069
1070 if (popped !== actionsByStore) {
1071 Recoil_recoverableViolation('Incorrect order of batch popping');
1072 }
1073 };
1074 }
1075
1076 function copyTreeState(state) {
1077 return { ...state,
1078 atomValues: state.atomValues.clone(),
1079 nonvalidatedAtoms: state.nonvalidatedAtoms.clone(),
1080 dirtyAtoms: new Set(state.dirtyAtoms)
1081 };
1082 }
1083
1084 function invalidateDownstreams(store, state) {
1085 // Inform any nodes that were changed or downstream of changes so that they
1086 // can clear out any caches as needed due to the update:
1087 const downstreams = getDownstreamNodes$1(store, state, state.dirtyAtoms);
1088
1089 for (const key of downstreams) {
1090 var _getNodeMaybe, _getNodeMaybe$invalid;
1091
1092 (_getNodeMaybe = getNodeMaybe$2(key)) === null || _getNodeMaybe === void 0 ? void 0 : (_getNodeMaybe$invalid = _getNodeMaybe.invalidate) === null || _getNodeMaybe$invalid === void 0 ? void 0 : _getNodeMaybe$invalid.call(_getNodeMaybe, state);
1093 }
1094 }
1095
1096 function setRecoilValue(store, recoilValue, valueOrUpdater) {
1097 queueOrPerformStateUpdate(store, {
1098 type: 'set',
1099 recoilValue,
1100 valueOrUpdater
1101 });
1102 }
1103
1104 function setRecoilValueLoadable(store, recoilValue, loadable) {
1105 if (loadable instanceof DefaultValue$1) {
1106 return setRecoilValue(store, recoilValue, loadable);
1107 }
1108
1109 queueOrPerformStateUpdate(store, {
1110 type: 'setLoadable',
1111 recoilValue,
1112 loadable
1113 });
1114 }
1115
1116 function markRecoilValueModified(store, recoilValue) {
1117 queueOrPerformStateUpdate(store, {
1118 type: 'markModified',
1119 recoilValue
1120 });
1121 }
1122
1123 function setUnvalidatedRecoilValue(store, recoilValue, unvalidatedValue) {
1124 queueOrPerformStateUpdate(store, {
1125 type: 'setUnvalidated',
1126 recoilValue,
1127 unvalidatedValue
1128 });
1129 }
1130
1131 let subscriptionID = 0;
1132
1133 function subscribeToRecoilValue(store, {
1134 key
1135 }, callback, componentDebugName = null) {
1136 const subID = subscriptionID++;
1137 const storeState = store.getState();
1138
1139 if (!storeState.nodeToComponentSubscriptions.has(key)) {
1140 storeState.nodeToComponentSubscriptions.set(key, new Map());
1141 }
1142
1143 Recoil_nullthrows(storeState.nodeToComponentSubscriptions.get(key)).set(subID, [componentDebugName !== null && componentDebugName !== void 0 ? componentDebugName : '<not captured>', callback]); // Handle the case that, during the same tick that we are subscribing, an atom
1144 // has been updated by some effect handler. Otherwise we will miss the update.
1145
1146 if (Recoil_gkx_1('recoil_early_rendering_2021')) {
1147 const nextTree = store.getState().nextTree;
1148
1149 if (nextTree && nextTree.dirtyAtoms.has(key)) {
1150 callback(nextTree);
1151 }
1152 }
1153
1154 return {
1155 release: () => {
1156 const storeState = store.getState();
1157 const subs = storeState.nodeToComponentSubscriptions.get(key);
1158
1159 if (subs === undefined || !subs.has(subID)) {
1160 Recoil_recoverableViolation(`Subscription missing at release time for atom ${key}. This is a bug in Recoil.`);
1161 return;
1162 }
1163
1164 subs.delete(subID);
1165
1166 if (subs.size === 0) {
1167 storeState.nodeToComponentSubscriptions.delete(key);
1168 }
1169 }
1170 };
1171 }
1172
1173 var Recoil_RecoilValueInterface = {
1174 RecoilValueReadOnly: RecoilValueReadOnly$1,
1175 AbstractRecoilValue: AbstractRecoilValue$1,
1176 RecoilState: RecoilState$1,
1177 getRecoilValueAsLoadable,
1178 setRecoilValue,
1179 setRecoilValueLoadable,
1180 markRecoilValueModified,
1181 setUnvalidatedRecoilValue,
1182 subscribeToRecoilValue,
1183 isRecoilValue: isRecoilValue$1,
1184 applyAtomValueWrites,
1185 // TODO Remove export when deprecating initialStoreState_DEPRECATED in RecoilRoot
1186 batchStart,
1187 writeLoadableToTreeState,
1188 invalidateDownstreams,
1189 copyTreeState,
1190 invalidateDownstreams_FOR_TESTING: invalidateDownstreams
1191 };
1192
1193 /**
1194 * Copyright (c) Facebook, Inc. and its affiliates.
1195 *
1196 * This source code is licensed under the MIT license found in the
1197 * LICENSE file in the root directory of this source tree.
1198 *
1199 * @emails oncall+recoil
1200 *
1201 * @format
1202 *
1203 * This is to export esstiential functions from react-dom
1204 * for our web build
1205 */
1206 const {
1207 unstable_batchedUpdates
1208 } = reactDom;
1209
1210 var ReactBatchedUpdates = {
1211 unstable_batchedUpdates
1212 };
1213
1214 /**
1215 * Copyright (c) Facebook, Inc. and its affiliates.
1216 *
1217 * This source code is licensed under the MIT license found in the
1218 * LICENSE file in the root directory of this source tree.
1219 *
1220 * @emails oncall+recoil
1221 *
1222 * @format
1223 *
1224 * This is to export esstiential functions from react-dom
1225 * for our web build
1226 */
1227 // @fb-only: const {unstable_batchedUpdates} = require('ReactDOMComet');
1228 const {
1229 unstable_batchedUpdates: unstable_batchedUpdates$1
1230 } = ReactBatchedUpdates; // @oss-only
1231
1232
1233 var Recoil_ReactBatchedUpdates = {
1234 unstable_batchedUpdates: unstable_batchedUpdates$1
1235 };
1236
1237 /**
1238 * Copyright (c) Facebook, Inc. and its affiliates.
1239 *
1240 * This source code is licensed under the MIT license found in the
1241 * LICENSE file in the root directory of this source tree.
1242 *
1243 * @emails oncall+recoil
1244 *
1245 * @format
1246 */
1247 const {
1248 batchStart: batchStart$1
1249 } = Recoil_RecoilValueInterface;
1250
1251 const {
1252 unstable_batchedUpdates: unstable_batchedUpdates$2
1253 } = Recoil_ReactBatchedUpdates;
1254
1255 let batcher = unstable_batchedUpdates$2; // flowlint-next-line unclear-type:off
1256
1257 /**
1258 * Sets the provided batcher function as the batcher function used by Recoil.
1259 *
1260 * Set the batcher to a custom batcher for your renderer,
1261 * if you use a renderer other than React DOM or React Native.
1262 */
1263 const setBatcher = newBatcher => {
1264 batcher = newBatcher;
1265 };
1266 /**
1267 * Returns the current batcher function.
1268 */
1269
1270
1271 const getBatcher = () => batcher;
1272 /**
1273 * Calls the current batcher function and passes the
1274 * provided callback function.
1275 */
1276
1277
1278 const batchUpdates = callback => {
1279 batcher(() => {
1280 let batchEnd = () => undefined;
1281
1282 try {
1283 batchEnd = batchStart$1();
1284 callback();
1285 } finally {
1286 batchEnd();
1287 }
1288 });
1289 };
1290
1291 var Recoil_Batching = {
1292 getBatcher,
1293 setBatcher,
1294 batchUpdates
1295 };
1296
1297 /**
1298 * Copyright (c) Facebook, Inc. and its affiliates.
1299 *
1300 * This source code is licensed under the MIT license found in the
1301 * LICENSE file in the root directory of this source tree.
1302 *
1303 * @emails oncall+recoil
1304 *
1305 * @format
1306 */
1307
1308 function enqueueExecution(s, f) {
1309 f();
1310 }
1311
1312 var Recoil_Queue = {
1313 enqueueExecution
1314 };
1315
1316 /**
1317 * Copyright (c) Facebook, Inc. and its affiliates.
1318 *
1319 * This source code is licensed under the MIT license found in the
1320 * LICENSE file in the root directory of this source tree.
1321 *
1322 * @emails oncall+recoil
1323 *
1324 * @format
1325 */
1326 /**
1327 * Returns a set containing all of the values from the first set that are not
1328 * present in any of the subsequent sets.
1329 *
1330 * Note: this is written procedurally (i.e., without filterSet) for performant
1331 * use in tight loops.
1332 */
1333
1334 function differenceSets(set, ...setsWithValuesToRemove) {
1335 const ret = new Set();
1336
1337 FIRST: for (const value of set) {
1338 for (const otherSet of setsWithValuesToRemove) {
1339 if (otherSet.has(value)) {
1340 continue FIRST;
1341 }
1342 }
1343
1344 ret.add(value);
1345 }
1346
1347 return ret;
1348 }
1349
1350 var Recoil_differenceSets = differenceSets;
1351
1352 /**
1353 * Copyright (c) Facebook, Inc. and its affiliates.
1354 *
1355 * This source code is licensed under the MIT license found in the
1356 * LICENSE file in the root directory of this source tree.
1357 *
1358 * @emails oncall+recoil
1359 *
1360 * @format
1361 */
1362 /**
1363 * Returns a new Map object with the same keys as the original, but with the
1364 * values replaced with the output of the given callback function.
1365 */
1366
1367 function mapMap(map, callback) {
1368 const result = new Map();
1369 map.forEach((value, key) => {
1370 result.set(key, callback(value, key));
1371 });
1372 return result;
1373 }
1374
1375 var Recoil_mapMap = mapMap;
1376
1377 function graph() {
1378 return {
1379 nodeDeps: new Map(),
1380 nodeToNodeSubscriptions: new Map()
1381 };
1382 }
1383
1384 function cloneGraph(graph) {
1385 return {
1386 nodeDeps: Recoil_mapMap(graph.nodeDeps, s => new Set(s)),
1387 nodeToNodeSubscriptions: Recoil_mapMap(graph.nodeToNodeSubscriptions, s => new Set(s))
1388 };
1389 } // Note that this overwrites the deps of existing nodes, rather than unioning
1390 // the new deps with the old deps.
1391
1392
1393 function mergeDependencyMapIntoGraph(deps, graph, // If olderGraph is given then we will not overwrite changes made to the given
1394 // graph compared with olderGraph:
1395 olderGraph) {
1396 const {
1397 nodeDeps,
1398 nodeToNodeSubscriptions
1399 } = graph;
1400 deps.forEach((upstreams, downstream) => {
1401 const existingUpstreams = nodeDeps.get(downstream);
1402
1403 if (existingUpstreams && olderGraph && existingUpstreams !== olderGraph.nodeDeps.get(downstream)) {
1404 return;
1405 } // Update nodeDeps:
1406
1407
1408 nodeDeps.set(downstream, new Set(upstreams)); // Add new deps to nodeToNodeSubscriptions:
1409
1410 const addedUpstreams = existingUpstreams == null ? upstreams : Recoil_differenceSets(upstreams, existingUpstreams);
1411 addedUpstreams.forEach(upstream => {
1412 if (!nodeToNodeSubscriptions.has(upstream)) {
1413 nodeToNodeSubscriptions.set(upstream, new Set());
1414 }
1415
1416 const existing = Recoil_nullthrows(nodeToNodeSubscriptions.get(upstream));
1417 existing.add(downstream);
1418 }); // Remove removed deps from nodeToNodeSubscriptions:
1419
1420 if (existingUpstreams) {
1421 const removedUpstreams = Recoil_differenceSets(existingUpstreams, upstreams);
1422 removedUpstreams.forEach(upstream => {
1423 if (!nodeToNodeSubscriptions.has(upstream)) {
1424 return;
1425 }
1426
1427 const existing = Recoil_nullthrows(nodeToNodeSubscriptions.get(upstream));
1428 existing.delete(downstream);
1429
1430 if (existing.size === 0) {
1431 nodeToNodeSubscriptions.delete(upstream);
1432 }
1433 });
1434 }
1435 });
1436 }
1437
1438 function saveDependencyMapToStore(dependencyMap, store, version) {
1439 var _storeState$nextTree, _storeState$previousT, _storeState$previousT2, _storeState$previousT3;
1440
1441 const storeState = store.getState();
1442
1443 if (!(version === storeState.currentTree.version || version === ((_storeState$nextTree = storeState.nextTree) === null || _storeState$nextTree === void 0 ? void 0 : _storeState$nextTree.version) || version === ((_storeState$previousT = storeState.previousTree) === null || _storeState$previousT === void 0 ? void 0 : _storeState$previousT.version))) {
1444 Recoil_recoverableViolation('Tried to save dependencies to a discarded tree');
1445 } // Merge the dependencies discovered into the store's dependency map
1446 // for the version that was read:
1447
1448
1449 const graph = store.getGraph(version);
1450 mergeDependencyMapIntoGraph(dependencyMap, graph); // If this version is not the latest version, also write these dependencies
1451 // into later versions if they don't already have their own:
1452
1453 if (version === ((_storeState$previousT2 = storeState.previousTree) === null || _storeState$previousT2 === void 0 ? void 0 : _storeState$previousT2.version)) {
1454 const currentGraph = store.getGraph(storeState.currentTree.version);
1455 mergeDependencyMapIntoGraph(dependencyMap, currentGraph, graph);
1456 }
1457
1458 if (version === ((_storeState$previousT3 = storeState.previousTree) === null || _storeState$previousT3 === void 0 ? void 0 : _storeState$previousT3.version) || version === storeState.currentTree.version) {
1459 var _storeState$nextTree2;
1460
1461 const nextVersion = (_storeState$nextTree2 = storeState.nextTree) === null || _storeState$nextTree2 === void 0 ? void 0 : _storeState$nextTree2.version;
1462
1463 if (nextVersion !== undefined) {
1464 const nextGraph = store.getGraph(nextVersion);
1465 mergeDependencyMapIntoGraph(dependencyMap, nextGraph, graph);
1466 }
1467 }
1468 }
1469
1470 function mergeDepsIntoDependencyMap(from, into) {
1471 from.forEach((upstreamDeps, downstreamNode) => {
1472 if (!into.has(downstreamNode)) {
1473 into.set(downstreamNode, new Set());
1474 }
1475
1476 const deps = Recoil_nullthrows(into.get(downstreamNode));
1477 upstreamDeps.forEach(dep => deps.add(dep));
1478 });
1479 }
1480
1481 function addToDependencyMap(downstream, upstream, dependencyMap) {
1482 if (!dependencyMap.has(downstream)) {
1483 dependencyMap.set(downstream, new Set());
1484 }
1485
1486 Recoil_nullthrows(dependencyMap.get(downstream)).add(upstream);
1487 }
1488
1489 var Recoil_Graph = {
1490 addToDependencyMap,
1491 cloneGraph,
1492 graph,
1493 mergeDepsIntoDependencyMap,
1494 saveDependencyMapToStore
1495 };
1496
1497 function createCommonjsModule(fn, module) {
1498 return module = { exports: {} }, fn(module, module.exports), module.exports;
1499 }
1500
1501 var hamt_1 = createCommonjsModule(function (module) {
1502
1503 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
1504 return typeof obj;
1505 } : function (obj) {
1506 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
1507 };
1508 /**
1509 @fileOverview Hash Array Mapped Trie.
1510
1511 Code based on: https://github.com/exclipy/pdata
1512 */
1513
1514
1515 var hamt = {}; // export
1516
1517 /* Configuration
1518 ******************************************************************************/
1519
1520 var SIZE = 5;
1521 var BUCKET_SIZE = Math.pow(2, SIZE);
1522 var MASK = BUCKET_SIZE - 1;
1523 var MAX_INDEX_NODE = BUCKET_SIZE / 2;
1524 var MIN_ARRAY_NODE = BUCKET_SIZE / 4;
1525 /*
1526 ******************************************************************************/
1527
1528 var nothing = {};
1529
1530 var constant = function constant(x) {
1531 return function () {
1532 return x;
1533 };
1534 };
1535 /**
1536 Get 32 bit hash of string.
1537
1538 Based on:
1539 http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery
1540 */
1541
1542
1543 var hash = hamt.hash = function (str) {
1544 var type = typeof str === 'undefined' ? 'undefined' : _typeof(str);
1545 if (type === 'number') return str;
1546 if (type !== 'string') str += '';
1547 var hash = 0;
1548
1549 for (var i = 0, len = str.length; i < len; ++i) {
1550 var c = str.charCodeAt(i);
1551 hash = (hash << 5) - hash + c | 0;
1552 }
1553
1554 return hash;
1555 };
1556 /* Bit Ops
1557 ******************************************************************************/
1558
1559 /**
1560 Hamming weight.
1561
1562 Taken from: http://jsperf.com/hamming-weight
1563 */
1564
1565
1566 var popcount = function popcount(x) {
1567 x -= x >> 1 & 0x55555555;
1568 x = (x & 0x33333333) + (x >> 2 & 0x33333333);
1569 x = x + (x >> 4) & 0x0f0f0f0f;
1570 x += x >> 8;
1571 x += x >> 16;
1572 return x & 0x7f;
1573 };
1574
1575 var hashFragment = function hashFragment(shift, h) {
1576 return h >>> shift & MASK;
1577 };
1578
1579 var toBitmap = function toBitmap(x) {
1580 return 1 << x;
1581 };
1582
1583 var fromBitmap = function fromBitmap(bitmap, bit) {
1584 return popcount(bitmap & bit - 1);
1585 };
1586 /* Array Ops
1587 ******************************************************************************/
1588
1589 /**
1590 Set a value in an array.
1591
1592 @param mutate Should the input array be mutated?
1593 @param at Index to change.
1594 @param v New value
1595 @param arr Array.
1596 */
1597
1598
1599 var arrayUpdate = function arrayUpdate(mutate, at, v, arr) {
1600 var out = arr;
1601
1602 if (!mutate) {
1603 var len = arr.length;
1604 out = new Array(len);
1605
1606 for (var i = 0; i < len; ++i) {
1607 out[i] = arr[i];
1608 }
1609 }
1610
1611 out[at] = v;
1612 return out;
1613 };
1614 /**
1615 Remove a value from an array.
1616
1617 @param mutate Should the input array be mutated?
1618 @param at Index to remove.
1619 @param arr Array.
1620 */
1621
1622
1623 var arraySpliceOut = function arraySpliceOut(mutate, at, arr) {
1624 var newLen = arr.length - 1;
1625 var i = 0;
1626 var g = 0;
1627 var out = arr;
1628
1629 if (mutate) {
1630 i = g = at;
1631 } else {
1632 out = new Array(newLen);
1633
1634 while (i < at) {
1635 out[g++] = arr[i++];
1636 }
1637 }
1638
1639 ++i;
1640
1641 while (i <= newLen) {
1642 out[g++] = arr[i++];
1643 }
1644
1645 if (mutate) {
1646 out.length = newLen;
1647 }
1648
1649 return out;
1650 };
1651 /**
1652 Insert a value into an array.
1653
1654 @param mutate Should the input array be mutated?
1655 @param at Index to insert at.
1656 @param v Value to insert,
1657 @param arr Array.
1658 */
1659
1660
1661 var arraySpliceIn = function arraySpliceIn(mutate, at, v, arr) {
1662 var len = arr.length;
1663
1664 if (mutate) {
1665 var _i = len;
1666
1667 while (_i >= at) {
1668 arr[_i--] = arr[_i];
1669 }
1670
1671 arr[at] = v;
1672 return arr;
1673 }
1674
1675 var i = 0,
1676 g = 0;
1677 var out = new Array(len + 1);
1678
1679 while (i < at) {
1680 out[g++] = arr[i++];
1681 }
1682
1683 out[at] = v;
1684
1685 while (i < len) {
1686 out[++g] = arr[i++];
1687 }
1688
1689 return out;
1690 };
1691 /* Node Structures
1692 ******************************************************************************/
1693
1694
1695 var LEAF = 1;
1696 var COLLISION = 2;
1697 var INDEX = 3;
1698 var ARRAY = 4;
1699 /**
1700 Empty node.
1701 */
1702
1703 var empty = {
1704 __hamt_isEmpty: true
1705 };
1706
1707 var isEmptyNode = function isEmptyNode(x) {
1708 return x === empty || x && x.__hamt_isEmpty;
1709 };
1710 /**
1711 Leaf holding a value.
1712
1713 @member edit Edit of the node.
1714 @member hash Hash of key.
1715 @member key Key.
1716 @member value Value stored.
1717 */
1718
1719
1720 var Leaf = function Leaf(edit, hash, key, value) {
1721 return {
1722 type: LEAF,
1723 edit: edit,
1724 hash: hash,
1725 key: key,
1726 value: value,
1727 _modify: Leaf__modify
1728 };
1729 };
1730 /**
1731 Leaf holding multiple values with the same hash but different keys.
1732
1733 @member edit Edit of the node.
1734 @member hash Hash of key.
1735 @member children Array of collision children node.
1736 */
1737
1738
1739 var Collision = function Collision(edit, hash, children) {
1740 return {
1741 type: COLLISION,
1742 edit: edit,
1743 hash: hash,
1744 children: children,
1745 _modify: Collision__modify
1746 };
1747 };
1748 /**
1749 Internal node with a sparse set of children.
1750
1751 Uses a bitmap and array to pack children.
1752
1753 @member edit Edit of the node.
1754 @member mask Bitmap that encode the positions of children in the array.
1755 @member children Array of child nodes.
1756 */
1757
1758
1759 var IndexedNode = function IndexedNode(edit, mask, children) {
1760 return {
1761 type: INDEX,
1762 edit: edit,
1763 mask: mask,
1764 children: children,
1765 _modify: IndexedNode__modify
1766 };
1767 };
1768 /**
1769 Internal node with many children.
1770
1771 @member edit Edit of the node.
1772 @member size Number of children.
1773 @member children Array of child nodes.
1774 */
1775
1776
1777 var ArrayNode = function ArrayNode(edit, size, children) {
1778 return {
1779 type: ARRAY,
1780 edit: edit,
1781 size: size,
1782 children: children,
1783 _modify: ArrayNode__modify
1784 };
1785 };
1786 /**
1787 Is `node` a leaf node?
1788 */
1789
1790
1791 var isLeaf = function isLeaf(node) {
1792 return node === empty || node.type === LEAF || node.type === COLLISION;
1793 };
1794 /* Internal node operations.
1795 ******************************************************************************/
1796
1797 /**
1798 Expand an indexed node into an array node.
1799
1800 @param edit Current edit.
1801 @param frag Index of added child.
1802 @param child Added child.
1803 @param mask Index node mask before child added.
1804 @param subNodes Index node children before child added.
1805 */
1806
1807
1808 var expand = function expand(edit, frag, child, bitmap, subNodes) {
1809 var arr = [];
1810 var bit = bitmap;
1811 var count = 0;
1812
1813 for (var i = 0; bit; ++i) {
1814 if (bit & 1) arr[i] = subNodes[count++];
1815 bit >>>= 1;
1816 }
1817
1818 arr[frag] = child;
1819 return ArrayNode(edit, count + 1, arr);
1820 };
1821 /**
1822 Collapse an array node into a indexed node.
1823
1824 @param edit Current edit.
1825 @param count Number of elements in new array.
1826 @param removed Index of removed element.
1827 @param elements Array node children before remove.
1828 */
1829
1830
1831 var pack = function pack(edit, count, removed, elements) {
1832 var children = new Array(count - 1);
1833 var g = 0;
1834 var bitmap = 0;
1835
1836 for (var i = 0, len = elements.length; i < len; ++i) {
1837 if (i !== removed) {
1838 var elem = elements[i];
1839
1840 if (elem && !isEmptyNode(elem)) {
1841 children[g++] = elem;
1842 bitmap |= 1 << i;
1843 }
1844 }
1845 }
1846
1847 return IndexedNode(edit, bitmap, children);
1848 };
1849 /**
1850 Merge two leaf nodes.
1851
1852 @param shift Current shift.
1853 @param h1 Node 1 hash.
1854 @param n1 Node 1.
1855 @param h2 Node 2 hash.
1856 @param n2 Node 2.
1857 */
1858
1859
1860 var mergeLeaves = function mergeLeaves(edit, shift, h1, n1, h2, n2) {
1861 if (h1 === h2) return Collision(edit, h1, [n2, n1]);
1862 var subH1 = hashFragment(shift, h1);
1863 var subH2 = hashFragment(shift, h2);
1864 return IndexedNode(edit, toBitmap(subH1) | toBitmap(subH2), subH1 === subH2 ? [mergeLeaves(edit, shift + SIZE, h1, n1, h2, n2)] : subH1 < subH2 ? [n1, n2] : [n2, n1]);
1865 };
1866 /**
1867 Update an entry in a collision list.
1868
1869 @param mutate Should mutation be used?
1870 @param edit Current edit.
1871 @param keyEq Key compare function.
1872 @param hash Hash of collision.
1873 @param list Collision list.
1874 @param f Update function.
1875 @param k Key to update.
1876 @param size Size ref.
1877 */
1878
1879
1880 var updateCollisionList = function updateCollisionList(mutate, edit, keyEq, h, list, f, k, size) {
1881 var len = list.length;
1882
1883 for (var i = 0; i < len; ++i) {
1884 var child = list[i];
1885
1886 if (keyEq(k, child.key)) {
1887 var value = child.value;
1888
1889 var _newValue = f(value);
1890
1891 if (_newValue === value) return list;
1892
1893 if (_newValue === nothing) {
1894 --size.value;
1895 return arraySpliceOut(mutate, i, list);
1896 }
1897
1898 return arrayUpdate(mutate, i, Leaf(edit, h, k, _newValue), list);
1899 }
1900 }
1901
1902 var newValue = f();
1903 if (newValue === nothing) return list;
1904 ++size.value;
1905 return arrayUpdate(mutate, len, Leaf(edit, h, k, newValue), list);
1906 };
1907
1908 var canEditNode = function canEditNode(edit, node) {
1909 return edit === node.edit;
1910 };
1911 /* Editing
1912 ******************************************************************************/
1913
1914
1915 var Leaf__modify = function Leaf__modify(edit, keyEq, shift, f, h, k, size) {
1916 if (keyEq(k, this.key)) {
1917 var _v = f(this.value);
1918
1919 if (_v === this.value) return this;else if (_v === nothing) {
1920 --size.value;
1921 return empty;
1922 }
1923
1924 if (canEditNode(edit, this)) {
1925 this.value = _v;
1926 return this;
1927 }
1928
1929 return Leaf(edit, h, k, _v);
1930 }
1931
1932 var v = f();
1933 if (v === nothing) return this;
1934 ++size.value;
1935 return mergeLeaves(edit, shift, this.hash, this, h, Leaf(edit, h, k, v));
1936 };
1937
1938 var Collision__modify = function Collision__modify(edit, keyEq, shift, f, h, k, size) {
1939 if (h === this.hash) {
1940 var canEdit = canEditNode(edit, this);
1941 var list = updateCollisionList(canEdit, edit, keyEq, this.hash, this.children, f, k, size);
1942 if (list === this.children) return this;
1943 return list.length > 1 ? Collision(edit, this.hash, list) : list[0]; // collapse single element collision list
1944 }
1945
1946 var v = f();
1947 if (v === nothing) return this;
1948 ++size.value;
1949 return mergeLeaves(edit, shift, this.hash, this, h, Leaf(edit, h, k, v));
1950 };
1951
1952 var IndexedNode__modify = function IndexedNode__modify(edit, keyEq, shift, f, h, k, size) {
1953 var mask = this.mask;
1954 var children = this.children;
1955 var frag = hashFragment(shift, h);
1956 var bit = toBitmap(frag);
1957 var indx = fromBitmap(mask, bit);
1958 var exists = mask & bit;
1959 var current = exists ? children[indx] : empty;
1960
1961 var child = current._modify(edit, keyEq, shift + SIZE, f, h, k, size);
1962
1963 if (current === child) return this;
1964 var canEdit = canEditNode(edit, this);
1965 var bitmap = mask;
1966 var newChildren = void 0;
1967
1968 if (exists && isEmptyNode(child)) {
1969 // remove
1970 bitmap &= ~bit;
1971 if (!bitmap) return empty;
1972 if (children.length <= 2 && isLeaf(children[indx ^ 1])) return children[indx ^ 1]; // collapse
1973
1974 newChildren = arraySpliceOut(canEdit, indx, children);
1975 } else if (!exists && !isEmptyNode(child)) {
1976 // add
1977 if (children.length >= MAX_INDEX_NODE) return expand(edit, frag, child, mask, children);
1978 bitmap |= bit;
1979 newChildren = arraySpliceIn(canEdit, indx, child, children);
1980 } else {
1981 // modify
1982 newChildren = arrayUpdate(canEdit, indx, child, children);
1983 }
1984
1985 if (canEdit) {
1986 this.mask = bitmap;
1987 this.children = newChildren;
1988 return this;
1989 }
1990
1991 return IndexedNode(edit, bitmap, newChildren);
1992 };
1993
1994 var ArrayNode__modify = function ArrayNode__modify(edit, keyEq, shift, f, h, k, size) {
1995 var count = this.size;
1996 var children = this.children;
1997 var frag = hashFragment(shift, h);
1998 var child = children[frag];
1999
2000 var newChild = (child || empty)._modify(edit, keyEq, shift + SIZE, f, h, k, size);
2001
2002 if (child === newChild) return this;
2003 var canEdit = canEditNode(edit, this);
2004 var newChildren = void 0;
2005
2006 if (isEmptyNode(child) && !isEmptyNode(newChild)) {
2007 // add
2008 ++count;
2009 newChildren = arrayUpdate(canEdit, frag, newChild, children);
2010 } else if (!isEmptyNode(child) && isEmptyNode(newChild)) {
2011 // remove
2012 --count;
2013 if (count <= MIN_ARRAY_NODE) return pack(edit, count, frag, children);
2014 newChildren = arrayUpdate(canEdit, frag, empty, children);
2015 } else {
2016 // modify
2017 newChildren = arrayUpdate(canEdit, frag, newChild, children);
2018 }
2019
2020 if (canEdit) {
2021 this.size = count;
2022 this.children = newChildren;
2023 return this;
2024 }
2025
2026 return ArrayNode(edit, count, newChildren);
2027 };
2028
2029 empty._modify = function (edit, keyEq, shift, f, h, k, size) {
2030 var v = f();
2031 if (v === nothing) return empty;
2032 ++size.value;
2033 return Leaf(edit, h, k, v);
2034 };
2035 /*
2036 ******************************************************************************/
2037
2038
2039 function Map(editable, edit, config, root, size) {
2040 this._editable = editable;
2041 this._edit = edit;
2042 this._config = config;
2043 this._root = root;
2044 this._size = size;
2045 }
2046
2047 Map.prototype.setTree = function (newRoot, newSize) {
2048 if (this._editable) {
2049 this._root = newRoot;
2050 this._size = newSize;
2051 return this;
2052 }
2053
2054 return newRoot === this._root ? this : new Map(this._editable, this._edit, this._config, newRoot, newSize);
2055 };
2056 /* Queries
2057 ******************************************************************************/
2058
2059 /**
2060 Lookup the value for `key` in `map` using a custom `hash`.
2061
2062 Returns the value or `alt` if none.
2063 */
2064
2065
2066 var tryGetHash = hamt.tryGetHash = function (alt, hash, key, map) {
2067 var node = map._root;
2068 var shift = 0;
2069 var keyEq = map._config.keyEq;
2070
2071 while (true) {
2072 switch (node.type) {
2073 case LEAF:
2074 {
2075 return keyEq(key, node.key) ? node.value : alt;
2076 }
2077
2078 case COLLISION:
2079 {
2080 if (hash === node.hash) {
2081 var children = node.children;
2082
2083 for (var i = 0, len = children.length; i < len; ++i) {
2084 var child = children[i];
2085 if (keyEq(key, child.key)) return child.value;
2086 }
2087 }
2088
2089 return alt;
2090 }
2091
2092 case INDEX:
2093 {
2094 var frag = hashFragment(shift, hash);
2095 var bit = toBitmap(frag);
2096
2097 if (node.mask & bit) {
2098 node = node.children[fromBitmap(node.mask, bit)];
2099 shift += SIZE;
2100 break;
2101 }
2102
2103 return alt;
2104 }
2105
2106 case ARRAY:
2107 {
2108 node = node.children[hashFragment(shift, hash)];
2109
2110 if (node) {
2111 shift += SIZE;
2112 break;
2113 }
2114
2115 return alt;
2116 }
2117
2118 default:
2119 return alt;
2120 }
2121 }
2122 };
2123
2124 Map.prototype.tryGetHash = function (alt, hash, key) {
2125 return tryGetHash(alt, hash, key, this);
2126 };
2127 /**
2128 Lookup the value for `key` in `map` using internal hash function.
2129
2130 @see `tryGetHash`
2131 */
2132
2133
2134 var tryGet = hamt.tryGet = function (alt, key, map) {
2135 return tryGetHash(alt, map._config.hash(key), key, map);
2136 };
2137
2138 Map.prototype.tryGet = function (alt, key) {
2139 return tryGet(alt, key, this);
2140 };
2141 /**
2142 Lookup the value for `key` in `map` using a custom `hash`.
2143
2144 Returns the value or `undefined` if none.
2145 */
2146
2147
2148 var getHash = hamt.getHash = function (hash, key, map) {
2149 return tryGetHash(undefined, hash, key, map);
2150 };
2151
2152 Map.prototype.getHash = function (hash, key) {
2153 return getHash(hash, key, this);
2154 };
2155 /**
2156 Lookup the value for `key` in `map` using internal hash function.
2157
2158 @see `get`
2159 */
2160
2161
2162 var get = hamt.get = function (key, map) {
2163 return tryGetHash(undefined, map._config.hash(key), key, map);
2164 };
2165
2166 Map.prototype.get = function (key, alt) {
2167 return tryGet(alt, key, this);
2168 };
2169 /**
2170 Does an entry exist for `key` in `map`? Uses custom `hash`.
2171 */
2172
2173
2174 var hasHash = hamt.has = function (hash, key, map) {
2175 return tryGetHash(nothing, hash, key, map) !== nothing;
2176 };
2177
2178 Map.prototype.hasHash = function (hash, key) {
2179 return hasHash(hash, key, this);
2180 };
2181 /**
2182 Does an entry exist for `key` in `map`? Uses internal hash function.
2183 */
2184
2185
2186 var has = hamt.has = function (key, map) {
2187 return hasHash(map._config.hash(key), key, map);
2188 };
2189
2190 Map.prototype.has = function (key) {
2191 return has(key, this);
2192 };
2193
2194 var defKeyCompare = function defKeyCompare(x, y) {
2195 return x === y;
2196 };
2197 /**
2198 Create an empty map.
2199
2200 @param config Configuration.
2201 */
2202
2203
2204 hamt.make = function (config) {
2205 return new Map(0, 0, {
2206 keyEq: config && config.keyEq || defKeyCompare,
2207 hash: config && config.hash || hash
2208 }, empty, 0);
2209 };
2210 /**
2211 Empty map.
2212 */
2213
2214
2215 hamt.empty = hamt.make();
2216 /**
2217 Does `map` contain any elements?
2218 */
2219
2220 var isEmpty = hamt.isEmpty = function (map) {
2221 return map && !!isEmptyNode(map._root);
2222 };
2223
2224 Map.prototype.isEmpty = function () {
2225 return isEmpty(this);
2226 };
2227 /* Updates
2228 ******************************************************************************/
2229
2230 /**
2231 Alter the value stored for `key` in `map` using function `f` using
2232 custom hash.
2233
2234 `f` is invoked with the current value for `k` if it exists,
2235 or no arguments if no such value exists. `modify` will always either
2236 update or insert a value into the map.
2237
2238 Returns a map with the modified value. Does not alter `map`.
2239 */
2240
2241
2242 var modifyHash = hamt.modifyHash = function (f, hash, key, map) {
2243 var size = {
2244 value: map._size
2245 };
2246
2247 var newRoot = map._root._modify(map._editable ? map._edit : NaN, map._config.keyEq, 0, f, hash, key, size);
2248
2249 return map.setTree(newRoot, size.value);
2250 };
2251
2252 Map.prototype.modifyHash = function (hash, key, f) {
2253 return modifyHash(f, hash, key, this);
2254 };
2255 /**
2256 Alter the value stored for `key` in `map` using function `f` using
2257 internal hash function.
2258
2259 @see `modifyHash`
2260 */
2261
2262
2263 var modify = hamt.modify = function (f, key, map) {
2264 return modifyHash(f, map._config.hash(key), key, map);
2265 };
2266
2267 Map.prototype.modify = function (key, f) {
2268 return modify(f, key, this);
2269 };
2270 /**
2271 Store `value` for `key` in `map` using custom `hash`.
2272
2273 Returns a map with the modified value. Does not alter `map`.
2274 */
2275
2276
2277 var setHash = hamt.setHash = function (hash, key, value, map) {
2278 return modifyHash(constant(value), hash, key, map);
2279 };
2280
2281 Map.prototype.setHash = function (hash, key, value) {
2282 return setHash(hash, key, value, this);
2283 };
2284 /**
2285 Store `value` for `key` in `map` using internal hash function.
2286
2287 @see `setHash`
2288 */
2289
2290
2291 var set = hamt.set = function (key, value, map) {
2292 return setHash(map._config.hash(key), key, value, map);
2293 };
2294
2295 Map.prototype.set = function (key, value) {
2296 return set(key, value, this);
2297 };
2298 /**
2299 Remove the entry for `key` in `map`.
2300
2301 Returns a map with the value removed. Does not alter `map`.
2302 */
2303
2304
2305 var del = constant(nothing);
2306
2307 var removeHash = hamt.removeHash = function (hash, key, map) {
2308 return modifyHash(del, hash, key, map);
2309 };
2310
2311 Map.prototype.removeHash = Map.prototype.deleteHash = function (hash, key) {
2312 return removeHash(hash, key, this);
2313 };
2314 /**
2315 Remove the entry for `key` in `map` using internal hash function.
2316
2317 @see `removeHash`
2318 */
2319
2320
2321 var remove = hamt.remove = function (key, map) {
2322 return removeHash(map._config.hash(key), key, map);
2323 };
2324
2325 Map.prototype.remove = Map.prototype.delete = function (key) {
2326 return remove(key, this);
2327 };
2328 /* Mutation
2329 ******************************************************************************/
2330
2331 /**
2332 Mark `map` as mutable.
2333 */
2334
2335
2336 var beginMutation = hamt.beginMutation = function (map) {
2337 return new Map(map._editable + 1, map._edit + 1, map._config, map._root, map._size);
2338 };
2339
2340 Map.prototype.beginMutation = function () {
2341 return beginMutation(this);
2342 };
2343 /**
2344 Mark `map` as immutable.
2345 */
2346
2347
2348 var endMutation = hamt.endMutation = function (map) {
2349 map._editable = map._editable && map._editable - 1;
2350 return map;
2351 };
2352
2353 Map.prototype.endMutation = function () {
2354 return endMutation(this);
2355 };
2356 /**
2357 Mutate `map` within the context of `f`.
2358 @param f
2359 @param map HAMT
2360 */
2361
2362
2363 var mutate = hamt.mutate = function (f, map) {
2364 var transient = beginMutation(map);
2365 f(transient);
2366 return endMutation(transient);
2367 };
2368
2369 Map.prototype.mutate = function (f) {
2370 return mutate(f, this);
2371 };
2372 /* Traversal
2373 ******************************************************************************/
2374
2375 /**
2376 Apply a continuation.
2377 */
2378
2379
2380 var appk = function appk(k) {
2381 return k && lazyVisitChildren(k[0], k[1], k[2], k[3], k[4]);
2382 };
2383 /**
2384 Recursively visit all values stored in an array of nodes lazily.
2385 */
2386
2387
2388 var lazyVisitChildren = function lazyVisitChildren(len, children, i, f, k) {
2389 while (i < len) {
2390 var child = children[i++];
2391 if (child && !isEmptyNode(child)) return lazyVisit(child, f, [len, children, i, f, k]);
2392 }
2393
2394 return appk(k);
2395 };
2396 /**
2397 Recursively visit all values stored in `node` lazily.
2398 */
2399
2400
2401 var lazyVisit = function lazyVisit(node, f, k) {
2402 switch (node.type) {
2403 case LEAF:
2404 return {
2405 value: f(node),
2406 rest: k
2407 };
2408
2409 case COLLISION:
2410 case ARRAY:
2411 case INDEX:
2412 var children = node.children;
2413 return lazyVisitChildren(children.length, children, 0, f, k);
2414
2415 default:
2416 return appk(k);
2417 }
2418 };
2419
2420 var DONE = {
2421 done: true
2422 };
2423 /**
2424 Javascript iterator over a map.
2425 */
2426
2427 function MapIterator(v) {
2428 this.v = v;
2429 }
2430
2431 MapIterator.prototype.next = function () {
2432 if (!this.v) return DONE;
2433 var v0 = this.v;
2434 this.v = appk(v0.rest);
2435 return v0;
2436 };
2437
2438 MapIterator.prototype[Symbol.iterator] = function () {
2439 return this;
2440 };
2441 /**
2442 Lazily visit each value in map with function `f`.
2443 */
2444
2445
2446 var visit = function visit(map, f) {
2447 return new MapIterator(lazyVisit(map._root, f));
2448 };
2449 /**
2450 Get a Javascsript iterator of `map`.
2451
2452 Iterates over `[key, value]` arrays.
2453 */
2454
2455
2456 var buildPairs = function buildPairs(x) {
2457 return [x.key, x.value];
2458 };
2459
2460 var entries = hamt.entries = function (map) {
2461 return visit(map, buildPairs);
2462 };
2463
2464 Map.prototype.entries = Map.prototype[Symbol.iterator] = function () {
2465 return entries(this);
2466 };
2467 /**
2468 Get array of all keys in `map`.
2469
2470 Order is not guaranteed.
2471 */
2472
2473
2474 var buildKeys = function buildKeys(x) {
2475 return x.key;
2476 };
2477
2478 var keys = hamt.keys = function (map) {
2479 return visit(map, buildKeys);
2480 };
2481
2482 Map.prototype.keys = function () {
2483 return keys(this);
2484 };
2485 /**
2486 Get array of all values in `map`.
2487
2488 Order is not guaranteed, duplicates are preserved.
2489 */
2490
2491
2492 var buildValues = function buildValues(x) {
2493 return x.value;
2494 };
2495
2496 var values = hamt.values = Map.prototype.values = function (map) {
2497 return visit(map, buildValues);
2498 };
2499
2500 Map.prototype.values = function () {
2501 return values(this);
2502 };
2503 /* Fold
2504 ******************************************************************************/
2505
2506 /**
2507 Visit every entry in the map, aggregating data.
2508
2509 Order of nodes is not guaranteed.
2510
2511 @param f Function mapping accumulated value, value, and key to new value.
2512 @param z Starting value.
2513 @param m HAMT
2514 */
2515
2516
2517 var fold = hamt.fold = function (f, z, m) {
2518 var root = m._root;
2519 if (root.type === LEAF) return f(z, root.value, root.key);
2520 var toVisit = [root.children];
2521 var children = void 0;
2522
2523 while (children = toVisit.pop()) {
2524 for (var i = 0, len = children.length; i < len;) {
2525 var child = children[i++];
2526
2527 if (child && child.type) {
2528 if (child.type === LEAF) z = f(z, child.value, child.key);else toVisit.push(child.children);
2529 }
2530 }
2531 }
2532
2533 return z;
2534 };
2535
2536 Map.prototype.fold = function (f, z) {
2537 return fold(f, z, this);
2538 };
2539 /**
2540 Visit every entry in the map, aggregating data.
2541
2542 Order of nodes is not guaranteed.
2543
2544 @param f Function invoked with value and key
2545 @param map HAMT
2546 */
2547
2548
2549 var forEach = hamt.forEach = function (f, map) {
2550 return fold(function (_, value, key) {
2551 return f(value, key, map);
2552 }, null, map);
2553 };
2554
2555 Map.prototype.forEach = function (f) {
2556 return forEach(f, this);
2557 };
2558 /* Aggregate
2559 ******************************************************************************/
2560
2561 /**
2562 Get the number of entries in `map`.
2563 */
2564
2565
2566 var count = hamt.count = function (map) {
2567 return map._size;
2568 };
2569
2570 Map.prototype.count = function () {
2571 return count(this);
2572 };
2573
2574 Object.defineProperty(Map.prototype, 'size', {
2575 get: Map.prototype.count
2576 });
2577 /* Export
2578 ******************************************************************************/
2579
2580 if ( module.exports) {
2581 module.exports = hamt;
2582 } else {
2583 undefined.hamt = hamt;
2584 }
2585 });
2586
2587 class BuiltInMap {
2588 constructor(existing) {
2589 _defineProperty(this, "_map", void 0);
2590
2591 this._map = new Map(existing === null || existing === void 0 ? void 0 : existing.entries());
2592 }
2593
2594 keys() {
2595 return this._map.keys();
2596 }
2597
2598 entries() {
2599 return this._map.entries();
2600 }
2601
2602 get(k) {
2603 return this._map.get(k);
2604 }
2605
2606 has(k) {
2607 return this._map.has(k);
2608 }
2609
2610 set(k, v) {
2611 this._map.set(k, v);
2612
2613 return this;
2614 }
2615
2616 delete(k) {
2617 this._map.delete(k);
2618
2619 return this;
2620 }
2621
2622 clone() {
2623 return persistentMap(this);
2624 }
2625
2626 toMap() {
2627 return new Map(this._map);
2628 }
2629
2630 }
2631
2632 class HashArrayMappedTrieMap {
2633 // Because hamt.empty is not a function there is no way to introduce type
2634 // parameters on it, so empty is typed as HAMTPlusMap<string, mixed>.
2635 // flowlint-next-line unclear-type:off
2636 constructor(existing) {
2637 _defineProperty(this, "_hamt", hamt_1.empty.beginMutation());
2638
2639 if (existing instanceof HashArrayMappedTrieMap) {
2640 const h = existing._hamt.endMutation();
2641
2642 existing._hamt = h.beginMutation();
2643 this._hamt = h.beginMutation();
2644 } else if (existing) {
2645 for (const [k, v] of existing.entries()) {
2646 this._hamt.set(k, v);
2647 }
2648 }
2649 }
2650
2651 keys() {
2652 return this._hamt.keys();
2653 }
2654
2655 entries() {
2656 return this._hamt.entries();
2657 }
2658
2659 get(k) {
2660 return this._hamt.get(k);
2661 }
2662
2663 has(k) {
2664 return this._hamt.has(k);
2665 }
2666
2667 set(k, v) {
2668 this._hamt.set(k, v);
2669
2670 return this;
2671 }
2672
2673 delete(k) {
2674 this._hamt.delete(k);
2675
2676 return this;
2677 }
2678
2679 clone() {
2680 return persistentMap(this);
2681 }
2682
2683 toMap() {
2684 return new Map(this._hamt);
2685 }
2686
2687 }
2688
2689 function persistentMap(existing) {
2690 if (Recoil_gkx_1('recoil_hamt_2020')) {
2691 return new HashArrayMappedTrieMap(existing);
2692 } else {
2693 return new BuiltInMap(existing);
2694 }
2695 }
2696
2697 var Recoil_PersistentMap = {
2698 persistentMap
2699 };
2700
2701 var Recoil_PersistentMap_1 = Recoil_PersistentMap.persistentMap;
2702
2703 var Recoil_PersistentMap$1 = /*#__PURE__*/Object.freeze({
2704 __proto__: null,
2705 persistentMap: Recoil_PersistentMap_1
2706 });
2707
2708 const {
2709 graph: graph$1
2710 } = Recoil_Graph;
2711
2712 const {
2713 persistentMap: persistentMap$1
2714 } = Recoil_PersistentMap$1; // flowlint-next-line unclear-type:off
2715
2716
2717 let nextTreeStateVersion = 0;
2718
2719 const getNextTreeStateVersion = () => nextTreeStateVersion++;
2720
2721 function makeEmptyTreeState() {
2722 const version = getNextTreeStateVersion();
2723 return {
2724 version,
2725 stateID: version,
2726 transactionMetadata: {},
2727 dirtyAtoms: new Set(),
2728 atomValues: persistentMap$1(),
2729 nonvalidatedAtoms: persistentMap$1()
2730 };
2731 }
2732
2733 function makeEmptyStoreState() {
2734 const currentTree = makeEmptyTreeState();
2735 return {
2736 currentTree,
2737 nextTree: null,
2738 previousTree: null,
2739 commitDepth: 0,
2740 knownAtoms: new Set(),
2741 knownSelectors: new Set(),
2742 transactionSubscriptions: new Map(),
2743 nodeTransactionSubscriptions: new Map(),
2744 nodeToComponentSubscriptions: new Map(),
2745 queuedComponentCallbacks_DEPRECATED: [],
2746 suspendedComponentResolvers: new Set(),
2747 graphsByVersion: new Map().set(currentTree.version, graph$1()),
2748 versionsUsedByComponent: new Map(),
2749 retention: {
2750 referenceCounts: new Map(),
2751 nodesRetainedByZone: new Map(),
2752 retainablesToCheckForRelease: new Set()
2753 },
2754 nodeCleanupFunctions: new Map()
2755 };
2756 }
2757
2758 var Recoil_State = {
2759 makeEmptyTreeState,
2760 makeEmptyStoreState,
2761 getNextTreeStateVersion
2762 };
2763
2764 /**
2765 * Copyright (c) Facebook, Inc. and its affiliates.
2766 *
2767 * This source code is licensed under the MIT license found in the
2768 * LICENSE file in the root directory of this source tree.
2769 *
2770 * @emails oncall+recoil
2771 *
2772 * @format
2773 */
2774
2775 function unionSets(...sets) {
2776 const result = new Set();
2777
2778 for (const set of sets) {
2779 for (const value of set) {
2780 result.add(value);
2781 }
2782 }
2783
2784 return result;
2785 }
2786
2787 var Recoil_unionSets = unionSets;
2788
2789 /**
2790 * Copyright (c) Facebook, Inc. and its affiliates.
2791 *
2792 * This source code is licensed under the MIT license found in the
2793 * LICENSE file in the root directory of this source tree.
2794 *
2795 * @emails oncall+recoil
2796 *
2797 * @format
2798 */
2799 /**
2800 * The someSet() method tests whether some elements in the given Set pass the
2801 * test implemented by the provided function.
2802 */
2803
2804 function someSet(set, callback, context) {
2805 const iterator = set.entries();
2806 let current = iterator.next();
2807
2808 while (!current.done) {
2809 const entry = current.value;
2810
2811 if (callback.call(context, entry[1], entry[0], set)) {
2812 return true;
2813 }
2814
2815 current = iterator.next();
2816 }
2817
2818 return false;
2819 }
2820
2821 var Recoil_someSet = someSet;
2822
2823 const {
2824 cleanUpNode: cleanUpNode$1
2825 } = Recoil_FunctionalCore;
2826
2827 const {
2828 deleteNodeConfigIfPossible: deleteNodeConfigIfPossible$1,
2829 getNode: getNode$2
2830 } = Recoil_Node;
2831
2832 const {
2833 RetentionZone: RetentionZone$2
2834 } = Recoil_RetentionZone;
2835
2836 const emptySet$1 = new Set();
2837
2838 function releaseRetainablesNowOnCurrentTree(store, retainables) {
2839 const storeState = store.getState();
2840 const treeState = storeState.currentTree;
2841
2842 if (storeState.nextTree) {
2843 Recoil_recoverableViolation('releaseNodesNowOnCurrentTree should only be called at the end of a batch');
2844 return; // leak memory rather than erase something that's about to be used.
2845 }
2846
2847 const nodes = new Set();
2848
2849 for (const r of retainables) {
2850 if (r instanceof RetentionZone$2) {
2851 for (const n of nodesRetainedByZone(storeState, r)) {
2852 nodes.add(n);
2853 }
2854 } else {
2855 nodes.add(r);
2856 }
2857 }
2858
2859 const releasableNodes = findReleasableNodes(store, nodes);
2860
2861 for (const node of releasableNodes) {
2862 releaseNode(store, treeState, node);
2863 }
2864 }
2865
2866 function findReleasableNodes(store, searchFromNodes) {
2867 const storeState = store.getState();
2868 const treeState = storeState.currentTree;
2869 const graph = store.getGraph(treeState.version);
2870 const releasableNodes = new Set(); // mutated to collect answer
2871
2872 const nonReleasableNodes = new Set();
2873 findReleasableNodesInner(searchFromNodes);
2874 return releasableNodes;
2875
2876 function findReleasableNodesInner(searchFromNodes) {
2877 const releasableNodesFoundThisIteration = new Set();
2878 const downstreams = getDownstreamNodesInTopologicalOrder(store, treeState, searchFromNodes, releasableNodes, // don't descend into these
2879 nonReleasableNodes // don't descend into these
2880 ); // Find which of the downstream nodes are releasable and which are not:
2881
2882 for (const node of downstreams) {
2883 var _storeState$retention;
2884
2885 // Not releasable if configured to be retained forever:
2886 if (getNode$2(node).retainedBy === 'recoilRoot') {
2887 nonReleasableNodes.add(node);
2888 continue;
2889 } // Not releasable if retained directly by a component:
2890
2891
2892 if (((_storeState$retention = storeState.retention.referenceCounts.get(node)) !== null && _storeState$retention !== void 0 ? _storeState$retention : 0) > 0) {
2893 nonReleasableNodes.add(node);
2894 continue;
2895 } // Not releasable if retained by a zone:
2896
2897
2898 if (zonesThatCouldRetainNode(node).some(z => storeState.retention.referenceCounts.get(z))) {
2899 nonReleasableNodes.add(node);
2900 continue;
2901 } // Not releasable if it has a non-releasable child (which will already be in
2902 // nonReleasableNodes because we are going in topological order):
2903
2904
2905 const nodeChildren = graph.nodeToNodeSubscriptions.get(node);
2906
2907 if (nodeChildren && Recoil_someSet(nodeChildren, child => nonReleasableNodes.has(child))) {
2908 nonReleasableNodes.add(node);
2909 continue;
2910 }
2911
2912 releasableNodes.add(node);
2913 releasableNodesFoundThisIteration.add(node);
2914 } // If we found any releasable nodes, we need to walk UP from those nodes to
2915 // find whether their parents can now be released as well:
2916
2917
2918 const parents = new Set();
2919
2920 for (const node of releasableNodesFoundThisIteration) {
2921 for (const parent of (_graph$nodeDeps$get = graph.nodeDeps.get(node)) !== null && _graph$nodeDeps$get !== void 0 ? _graph$nodeDeps$get : emptySet$1) {
2922 var _graph$nodeDeps$get;
2923
2924 if (!releasableNodes.has(parent)) {
2925 parents.add(parent);
2926 }
2927 }
2928 }
2929
2930 if (parents.size) {
2931 findReleasableNodesInner(parents);
2932 }
2933 }
2934 } // Children before parents
2935
2936
2937 function getDownstreamNodesInTopologicalOrder(store, treeState, nodes, // Mutable set is destroyed in place
2938 doNotDescendInto1, doNotDescendInto2) {
2939 const graph = store.getGraph(treeState.version);
2940 const answer = [];
2941 const visited = new Set();
2942
2943 while (nodes.size > 0) {
2944 visit(Recoil_nullthrows(nodes.values().next().value));
2945 }
2946
2947 return answer;
2948
2949 function visit(node) {
2950 if (doNotDescendInto1.has(node) || doNotDescendInto2.has(node)) {
2951 nodes.delete(node);
2952 return;
2953 }
2954
2955 if (visited.has(node)) {
2956 return;
2957 }
2958
2959 const children = graph.nodeToNodeSubscriptions.get(node);
2960
2961 if (children) {
2962 for (const child of children) {
2963 visit(child);
2964 }
2965 }
2966
2967 visited.add(node);
2968 nodes.delete(node);
2969 answer.push(node);
2970 }
2971 }
2972
2973 function releaseNode(store, treeState, node) {
2974 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
2975 return;
2976 } // Atom effects, in-closure caches, etc.:
2977
2978
2979 cleanUpNode$1(store, node); // Delete from store state:
2980
2981 const storeState = store.getState();
2982 storeState.knownAtoms.delete(node);
2983 storeState.knownSelectors.delete(node);
2984 storeState.nodeTransactionSubscriptions.delete(node);
2985 storeState.retention.referenceCounts.delete(node);
2986 const zones = zonesThatCouldRetainNode(node);
2987
2988 for (const zone of zones) {
2989 var _storeState$retention2;
2990
2991 (_storeState$retention2 = storeState.retention.nodesRetainedByZone.get(zone)) === null || _storeState$retention2 === void 0 ? void 0 : _storeState$retention2.delete(node);
2992 } // Note that we DO NOT delete from nodeToComponentSubscriptions because this
2993 // already happens when the last component that was retaining the node unmounts,
2994 // and this could happen either before or after that.
2995 // Delete from TreeState and dep graph:
2996
2997
2998 treeState.atomValues.delete(node);
2999 treeState.dirtyAtoms.delete(node);
3000 treeState.nonvalidatedAtoms.delete(node);
3001 const graph = storeState.graphsByVersion.get(treeState.version);
3002
3003 if (graph) {
3004 const deps = graph.nodeDeps.get(node);
3005
3006 if (deps !== undefined) {
3007 graph.nodeDeps.delete(node);
3008
3009 for (const dep of deps) {
3010 var _graph$nodeToNodeSubs;
3011
3012 (_graph$nodeToNodeSubs = graph.nodeToNodeSubscriptions.get(dep)) === null || _graph$nodeToNodeSubs === void 0 ? void 0 : _graph$nodeToNodeSubs.delete(node);
3013 }
3014 } // No need to delete sub's deps as there should be no subs at this point.
3015 // But an invariant would require deleting nodes in topological order.
3016
3017
3018 graph.nodeToNodeSubscriptions.delete(node);
3019 } // Node config (for family members only as their configs can be recreated, and
3020 // only if they are not retained within any other Stores):
3021
3022
3023 deleteNodeConfigIfPossible$1(node);
3024 }
3025
3026 function nodesRetainedByZone(storeState, zone) {
3027 var _storeState$retention3;
3028
3029 return (_storeState$retention3 = storeState.retention.nodesRetainedByZone.get(zone)) !== null && _storeState$retention3 !== void 0 ? _storeState$retention3 : emptySet$1;
3030 }
3031
3032 function zonesThatCouldRetainNode(node) {
3033 const retainedBy = getNode$2(node).retainedBy;
3034
3035 if (retainedBy === undefined || retainedBy === 'components' || retainedBy === 'recoilRoot') {
3036 return [];
3037 } else if (retainedBy instanceof RetentionZone$2) {
3038 return [retainedBy];
3039 } else {
3040 return retainedBy; // it's an array of zones
3041 }
3042 }
3043
3044 function scheduleOrPerformPossibleReleaseOfRetainable(store, retainable) {
3045 const state = store.getState();
3046
3047 if (state.nextTree) {
3048 state.retention.retainablesToCheckForRelease.add(retainable);
3049 } else {
3050 releaseRetainablesNowOnCurrentTree(store, new Set([retainable]));
3051 }
3052 }
3053
3054 function updateRetainCount(store, retainable, delta) {
3055 var _map$get;
3056
3057 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
3058 return;
3059 }
3060
3061 const map = store.getState().retention.referenceCounts;
3062 const newCount = ((_map$get = map.get(retainable)) !== null && _map$get !== void 0 ? _map$get : 0) + delta;
3063
3064 if (newCount === 0) {
3065 updateRetainCountToZero(store, retainable);
3066 } else {
3067 map.set(retainable, newCount);
3068 }
3069 }
3070
3071 function updateRetainCountToZero(store, retainable) {
3072 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
3073 return;
3074 }
3075
3076 const map = store.getState().retention.referenceCounts;
3077 map.delete(retainable);
3078 scheduleOrPerformPossibleReleaseOfRetainable(store, retainable);
3079 }
3080
3081 function releaseScheduledRetainablesNow(store) {
3082 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
3083 return;
3084 }
3085
3086 const state = store.getState();
3087 releaseRetainablesNowOnCurrentTree(store, state.retention.retainablesToCheckForRelease);
3088 state.retention.retainablesToCheckForRelease.clear();
3089 }
3090
3091 function retainedByOptionWithDefault(r) {
3092 // The default will change from 'recoilRoot' to 'components' in the future.
3093 return r === undefined ? 'recoilRoot' : r;
3094 }
3095
3096 var Recoil_Retention = {
3097 updateRetainCount,
3098 updateRetainCountToZero,
3099 releaseScheduledRetainablesNow,
3100 retainedByOptionWithDefault
3101 };
3102
3103 /**
3104 * Copyright (c) Facebook, Inc. and its affiliates.
3105 *
3106 * This source code is licensed under the MIT license found in the
3107 * LICENSE file in the root directory of this source tree.
3108 *
3109 * @emails oncall+recoil
3110 *
3111 * @format
3112 */
3113 /**
3114 * Combines multiple Iterables into a single Iterable.
3115 * Traverses the input Iterables in the order provided and maintains the order
3116 * of their elements.
3117 *
3118 * Example:
3119 * ```
3120 * const r = Array.from(concatIterables(['a', 'b'], ['c'], ['d', 'e', 'f']));
3121 * r == ['a', 'b', 'c', 'd', 'e', 'f'];
3122 * ```
3123 */
3124
3125 function* concatIterables(iters) {
3126 for (const iter of iters) {
3127 for (const val of iter) {
3128 yield val;
3129 }
3130 }
3131 }
3132
3133 var Recoil_concatIterables = concatIterables;
3134
3135 /**
3136 * Copyright (c) Facebook, Inc. and its affiliates.
3137 *
3138 * This source code is licensed under the MIT license found in the
3139 * LICENSE file in the root directory of this source tree.
3140 *
3141 * @emails oncall+recoil
3142 *
3143 * @format
3144 */
3145
3146 const isSSR = typeof window === 'undefined';
3147 const isReactNative = typeof navigator !== 'undefined' && navigator.product === 'ReactNative'; // eslint-disable-line fb-www/typeof-undefined
3148
3149 var Recoil_Environment = {
3150 isSSR,
3151 isReactNative
3152 };
3153
3154 const {
3155 isSSR: isSSR$1
3156 } = Recoil_Environment;
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166 const {
3167 batchUpdates: batchUpdates$1
3168 } = Recoil_Batching;
3169
3170 const {
3171 initializeNodeIfNewToStore: initializeNodeIfNewToStore$1,
3172 peekNodeInfo: peekNodeInfo$1
3173 } = Recoil_FunctionalCore;
3174
3175 const {
3176 graph: graph$2
3177 } = Recoil_Graph;
3178
3179 const {
3180 DEFAULT_VALUE: DEFAULT_VALUE$1,
3181 recoilValues: recoilValues$1,
3182 recoilValuesForKeys: recoilValuesForKeys$2
3183 } = Recoil_Node;
3184
3185 const {
3186 AbstractRecoilValue: AbstractRecoilValue$2,
3187 getRecoilValueAsLoadable: getRecoilValueAsLoadable$1,
3188 setRecoilValue: setRecoilValue$1,
3189 setUnvalidatedRecoilValue: setUnvalidatedRecoilValue$1
3190 } = Recoil_RecoilValueInterface;
3191
3192 const {
3193 updateRetainCount: updateRetainCount$1
3194 } = Recoil_Retention;
3195
3196 const {
3197 getNextTreeStateVersion: getNextTreeStateVersion$1,
3198 makeEmptyStoreState: makeEmptyStoreState$1
3199 } = Recoil_State; // Opaque at this surface because it's part of the public API from here.
3200
3201
3202 const retainWarning = `
3203Recoil Snapshots only last for the duration of the callback they are provided to. To keep a Snapshot longer, do this:
3204
3205 const release = snapshot.retain();
3206 try {
3207 await useTheSnapshotAsynchronously(snapshot);
3208 } finally {
3209 release();
3210 }
3211
3212This is currently a DEV-only warning but will become a thrown exception in the next release of Recoil.
3213`; // A "Snapshot" is "read-only" and captures a specific set of values of atoms.
3214 // However, the data-flow-graph and selector values may evolve as selector
3215 // evaluation functions are executed and async selectors resolve.
3216
3217 class Snapshot {
3218 constructor(storeState) {
3219 _defineProperty(this, "_store", void 0);
3220
3221 _defineProperty(this, "_refCount", 0);
3222
3223 _defineProperty(this, "getLoadable", recoilValue => {
3224 this.checkRefCount_INTERNAL();
3225 return getRecoilValueAsLoadable$1(this._store, recoilValue);
3226 });
3227
3228 _defineProperty(this, "getPromise", recoilValue => {
3229 this.checkRefCount_INTERNAL();
3230 return this.getLoadable(recoilValue).toPromise();
3231 });
3232
3233 _defineProperty(this, "getNodes_UNSTABLE", opt => {
3234 this.checkRefCount_INTERNAL(); // TODO Deal with modified selectors
3235
3236 if ((opt === null || opt === void 0 ? void 0 : opt.isModified) === true) {
3237 if ((opt === null || opt === void 0 ? void 0 : opt.isInitialized) === false) {
3238 return [];
3239 }
3240
3241 const state = this._store.getState().currentTree;
3242
3243 return recoilValuesForKeys$2(state.dirtyAtoms);
3244 }
3245
3246 const knownAtoms = this._store.getState().knownAtoms;
3247
3248 const knownSelectors = this._store.getState().knownSelectors;
3249
3250 return (opt === null || opt === void 0 ? void 0 : opt.isInitialized) == null ? recoilValues$1.values() : opt.isInitialized === true ? recoilValuesForKeys$2(Recoil_concatIterables([this._store.getState().knownAtoms, this._store.getState().knownSelectors])) : Recoil_filterIterable(recoilValues$1.values(), ({
3251 key
3252 }) => !knownAtoms.has(key) && !knownSelectors.has(key));
3253 });
3254
3255 _defineProperty(this, "getInfo_UNSTABLE", ({
3256 key
3257 }) => {
3258 this.checkRefCount_INTERNAL();
3259 return peekNodeInfo$1(this._store, this._store.getState().currentTree, key);
3260 });
3261
3262 _defineProperty(this, "map", mapper => {
3263 this.checkRefCount_INTERNAL();
3264 const mutableSnapshot = new MutableSnapshot(this, batchUpdates$1);
3265 mapper(mutableSnapshot); // if removing batchUpdates from `set` add it here
3266
3267 return cloneSnapshot(mutableSnapshot.getStore_INTERNAL());
3268 });
3269
3270 _defineProperty(this, "mapBatched_UNSTABLE", mapper => {
3271 this.checkRefCount_INTERNAL();
3272 const mutableSnapshot = new MutableSnapshot(this, cb => cb());
3273 batchUpdates$1(() => {
3274 mapper(mutableSnapshot);
3275 });
3276 return cloneSnapshot(mutableSnapshot.getStore_INTERNAL());
3277 });
3278
3279 _defineProperty(this, "asyncMap", async mapper => {
3280 this.checkRefCount_INTERNAL();
3281 const mutableSnapshot = new MutableSnapshot(this, batchUpdates$1);
3282 await mapper(mutableSnapshot);
3283 return cloneSnapshot(mutableSnapshot.getStore_INTERNAL());
3284 });
3285
3286 this._store = {
3287 getState: () => storeState,
3288 replaceState: replacer => {
3289 storeState.currentTree = replacer(storeState.currentTree); // no batching so nextTree is never active
3290 },
3291 getGraph: version => {
3292 const graphs = storeState.graphsByVersion;
3293
3294 if (graphs.has(version)) {
3295 return Recoil_nullthrows(graphs.get(version));
3296 }
3297
3298 const newGraph = graph$2();
3299 graphs.set(version, newGraph);
3300 return newGraph;
3301 },
3302 subscribeToTransactions: () => ({
3303 release: () => {}
3304 }),
3305 addTransactionMetadata: () => {
3306 throw new Error('Cannot subscribe to Snapshots');
3307 }
3308 }; // Initialize any nodes that are live in the parent store (primarily so that this
3309 // snapshot gets counted towards the node's live stores count).
3310
3311 for (const nodeKey of this._store.getState().nodeCleanupFunctions.keys()) {
3312 initializeNodeIfNewToStore$1(this._store, storeState.currentTree, nodeKey, 'get');
3313 updateRetainCount$1(this._store, nodeKey, 1);
3314 }
3315
3316 this.retain();
3317 this.autorelease_INTERNAL();
3318 }
3319
3320 retain() {
3321 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
3322 return () => undefined;
3323 }
3324
3325 this._refCount++;
3326 let released = false;
3327 return () => {
3328 if (!released) {
3329 released = true;
3330 this.release_INTERNAL();
3331 }
3332 };
3333 }
3334
3335 autorelease_INTERNAL() {
3336 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
3337 return;
3338 }
3339
3340 if (!isSSR$1) {
3341 window.setTimeout(() => this.release_INTERNAL(), 0);
3342 }
3343 }
3344
3345 release_INTERNAL() {
3346 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
3347 return;
3348 }
3349
3350 this._refCount--;
3351
3352 if (this._refCount === 0) ;
3353 }
3354
3355 checkRefCount_INTERNAL() {
3356 if (Recoil_gkx_1('recoil_memory_managament_2020') && this._refCount <= 0) {
3357 {
3358 Recoil_recoverableViolation(retainWarning);
3359 } // What we will ship later:
3360 // throw new Error(retainWarning);
3361
3362 }
3363 }
3364
3365 getStore_INTERNAL() {
3366 this.checkRefCount_INTERNAL();
3367 return this._store;
3368 }
3369
3370 getID() {
3371 this.checkRefCount_INTERNAL();
3372 return this.getID_INTERNAL();
3373 }
3374
3375 getID_INTERNAL() {
3376 this.checkRefCount_INTERNAL();
3377 return this._store.getState().currentTree.stateID;
3378 } // We want to allow the methods to be destructured and used as accessors
3379 // eslint-disable-next-line fb-www/extra-arrow-initializer
3380
3381
3382 }
3383
3384 function cloneStoreState(store, treeState, bumpVersion = false) {
3385 const storeState = store.getState();
3386 const version = bumpVersion ? getNextTreeStateVersion$1() : treeState.version;
3387 return {
3388 currentTree: bumpVersion ? {
3389 // TODO snapshots shouldn't really have versions because a new version number
3390 // is always assigned when the snapshot is gone to.
3391 version,
3392 stateID: version,
3393 transactionMetadata: { ...treeState.transactionMetadata
3394 },
3395 dirtyAtoms: new Set(treeState.dirtyAtoms),
3396 atomValues: treeState.atomValues.clone(),
3397 nonvalidatedAtoms: treeState.nonvalidatedAtoms.clone()
3398 } : treeState,
3399 commitDepth: 0,
3400 nextTree: null,
3401 previousTree: null,
3402 knownAtoms: new Set(storeState.knownAtoms),
3403 // FIXME here's a copy
3404 knownSelectors: new Set(storeState.knownSelectors),
3405 // FIXME here's a copy
3406 transactionSubscriptions: new Map(),
3407 nodeTransactionSubscriptions: new Map(),
3408 nodeToComponentSubscriptions: new Map(),
3409 queuedComponentCallbacks_DEPRECATED: [],
3410 suspendedComponentResolvers: new Set(),
3411 graphsByVersion: new Map().set(version, store.getGraph(treeState.version)),
3412 versionsUsedByComponent: new Map(),
3413 retention: {
3414 referenceCounts: new Map(),
3415 nodesRetainedByZone: new Map(),
3416 retainablesToCheckForRelease: new Set()
3417 },
3418 nodeCleanupFunctions: new Map()
3419 };
3420 } // Factory to build a fresh snapshot
3421
3422
3423 function freshSnapshot(initializeState) {
3424 const snapshot = new Snapshot(makeEmptyStoreState$1());
3425 return initializeState != null ? snapshot.map(initializeState) : snapshot;
3426 } // Factory to clone a snapahot state
3427
3428
3429 function cloneSnapshot(store, version = 'current') {
3430 const storeState = store.getState();
3431 const treeState = version === 'current' ? storeState.currentTree : Recoil_nullthrows(storeState.previousTree);
3432 return new Snapshot(cloneStoreState(store, treeState));
3433 }
3434
3435 class MutableSnapshot extends Snapshot {
3436 constructor(snapshot, batch) {
3437 super(cloneStoreState(snapshot.getStore_INTERNAL(), snapshot.getStore_INTERNAL().getState().currentTree, true));
3438
3439 _defineProperty(this, "_batch", void 0);
3440
3441 _defineProperty(this, "set", (recoilState, newValueOrUpdater) => {
3442 this.checkRefCount_INTERNAL();
3443 const store = this.getStore_INTERNAL(); // This batchUpdates ensures this `set` is applied immediately and you can
3444 // read the written value after calling `set`. I would like to remove this
3445 // behavior and only batch in `Snapshot.map`, but this would be a breaking
3446 // change potentially.
3447
3448 this._batch(() => {
3449 updateRetainCount$1(store, recoilState.key, 1);
3450 setRecoilValue$1(this.getStore_INTERNAL(), recoilState, newValueOrUpdater);
3451 });
3452 });
3453
3454 _defineProperty(this, "reset", recoilState => {
3455 this.checkRefCount_INTERNAL();
3456 const store = this.getStore_INTERNAL(); // See note at `set` about batched updates.
3457
3458 this._batch(() => {
3459 updateRetainCount$1(store, recoilState.key, 1);
3460 setRecoilValue$1(this.getStore_INTERNAL(), recoilState, DEFAULT_VALUE$1);
3461 });
3462 });
3463
3464 _defineProperty(this, "setUnvalidatedAtomValues_DEPRECATED", values => {
3465 this.checkRefCount_INTERNAL();
3466 const store = this.getStore_INTERNAL(); // See note at `set` about batched updates.
3467
3468 batchUpdates$1(() => {
3469 for (const [k, v] of values.entries()) {
3470 updateRetainCount$1(store, k, 1);
3471 setUnvalidatedRecoilValue$1(store, new AbstractRecoilValue$2(k), v);
3472 }
3473 });
3474 });
3475
3476 this._batch = batch;
3477 } // We want to allow the methods to be destructured and used as accessors
3478 // eslint-disable-next-line fb-www/extra-arrow-initializer
3479
3480
3481 }
3482
3483 var Recoil_Snapshot = {
3484 Snapshot,
3485 MutableSnapshot,
3486 freshSnapshot,
3487 cloneSnapshot
3488 };
3489
3490 var Recoil_Snapshot_1 = Recoil_Snapshot.Snapshot;
3491 var Recoil_Snapshot_2 = Recoil_Snapshot.MutableSnapshot;
3492 var Recoil_Snapshot_3 = Recoil_Snapshot.freshSnapshot;
3493 var Recoil_Snapshot_4 = Recoil_Snapshot.cloneSnapshot;
3494
3495 var Recoil_Snapshot$1 = /*#__PURE__*/Object.freeze({
3496 __proto__: null,
3497 Snapshot: Recoil_Snapshot_1,
3498 MutableSnapshot: Recoil_Snapshot_2,
3499 freshSnapshot: Recoil_Snapshot_3,
3500 cloneSnapshot: Recoil_Snapshot_4
3501 });
3502
3503 // @fb-only: const RecoilusagelogEvent = require('RecoilusagelogEvent');
3504 // @fb-only: const RecoilUsageLogFalcoEvent = require('RecoilUsageLogFalcoEvent');
3505 // @fb-only: const URI = require('URI');
3506
3507
3508 const {
3509 getNextTreeStateVersion: getNextTreeStateVersion$2,
3510 makeEmptyStoreState: makeEmptyStoreState$2
3511 } = Recoil_State;
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523 const {
3524 cleanUpNode: cleanUpNode$2,
3525 getDownstreamNodes: getDownstreamNodes$2,
3526 setNodeValue: setNodeValue$2,
3527 setUnvalidatedAtomValue_DEPRECATED: setUnvalidatedAtomValue_DEPRECATED$1
3528 } = Recoil_FunctionalCore;
3529
3530 const {
3531 graph: graph$3
3532 } = Recoil_Graph;
3533
3534 const {
3535 cloneGraph: cloneGraph$1
3536 } = Recoil_Graph;
3537
3538 const {
3539 applyAtomValueWrites: applyAtomValueWrites$1
3540 } = Recoil_RecoilValueInterface;
3541
3542 const {
3543 releaseScheduledRetainablesNow: releaseScheduledRetainablesNow$1
3544 } = Recoil_Retention;
3545
3546 const {
3547 freshSnapshot: freshSnapshot$1
3548 } = Recoil_Snapshot$1;
3549
3550
3551
3552 const {
3553 useCallback,
3554 useContext,
3555 useEffect,
3556 useMemo,
3557 useRef,
3558 useState
3559 } = react;
3560
3561 function notInAContext() {
3562 throw new Error('This component must be used inside a <RecoilRoot> component.');
3563 }
3564
3565 const defaultStore = Object.freeze({
3566 getState: notInAContext,
3567 replaceState: notInAContext,
3568 getGraph: notInAContext,
3569 subscribeToTransactions: notInAContext,
3570 addTransactionMetadata: notInAContext
3571 });
3572 let stateReplacerIsBeingExecuted = false;
3573
3574 function startNextTreeIfNeeded(store) {
3575 if (stateReplacerIsBeingExecuted) {
3576 throw new Error('An atom update was triggered within the execution of a state updater function. State updater functions provided to Recoil must be pure functions.');
3577 }
3578
3579 const storeState = store.getState();
3580
3581 if (storeState.nextTree === null) {
3582 if (Recoil_gkx_1('recoil_memory_managament_2020') && Recoil_gkx_1('recoil_release_on_cascading_update_killswitch_2021')) {
3583 // If this is a cascading update (that is, rendering due to one state change
3584 // invokes a second state change), we won't have cleaned up retainables yet
3585 // because this normally happens after notifying components. Do it before
3586 // proceeding with the cascading update so that it remains predictable:
3587 if (storeState.commitDepth > 0) {
3588 releaseScheduledRetainablesNow$1(store);
3589 }
3590 }
3591
3592 const version = storeState.currentTree.version;
3593 const nextVersion = getNextTreeStateVersion$2();
3594 storeState.nextTree = { ...storeState.currentTree,
3595 version: nextVersion,
3596 stateID: nextVersion,
3597 dirtyAtoms: new Set(),
3598 transactionMetadata: {}
3599 };
3600 storeState.graphsByVersion.set(nextVersion, cloneGraph$1(Recoil_nullthrows(storeState.graphsByVersion.get(version))));
3601 }
3602 }
3603
3604 const AppContext = react.createContext({
3605 current: defaultStore
3606 });
3607
3608 const useStoreRef = () => useContext(AppContext);
3609
3610 const MutableSourceContext = react.createContext(null); // TODO T2710559282599660
3611
3612 function useRecoilMutableSource() {
3613 const mutableSource = useContext(MutableSourceContext);
3614
3615 if (mutableSource == null) {
3616 Recoil_expectationViolation('Attempted to use a Recoil hook outside of a <RecoilRoot>. ' + '<RecoilRoot> must be an ancestor of any component that uses ' + 'Recoil hooks.');
3617 }
3618
3619 return mutableSource;
3620 }
3621
3622 function notifyComponents(store, storeState, treeState) {
3623 const dependentNodes = getDownstreamNodes$2(store, treeState, treeState.dirtyAtoms);
3624
3625 for (const key of dependentNodes) {
3626 const comps = storeState.nodeToComponentSubscriptions.get(key);
3627
3628 if (comps) {
3629 for (const [_subID, [_debugName, callback]] of comps) {
3630 callback(treeState);
3631 }
3632 }
3633 }
3634 }
3635
3636 function sendEndOfBatchNotifications(store) {
3637 const storeState = store.getState();
3638 const treeState = storeState.currentTree; // Inform transaction subscribers of the transaction:
3639
3640 const dirtyAtoms = treeState.dirtyAtoms;
3641
3642 if (dirtyAtoms.size) {
3643 // Execute Node-specific subscribers before global subscribers
3644 for (const [key, subscriptions] of storeState.nodeTransactionSubscriptions) {
3645 if (dirtyAtoms.has(key)) {
3646 for (const [_, subscription] of subscriptions) {
3647 subscription(store);
3648 }
3649 }
3650 }
3651
3652 for (const [_, subscription] of storeState.transactionSubscriptions) {
3653 subscription(store);
3654 }
3655
3656 if (!Recoil_gkx_1('recoil_early_rendering_2021') || storeState.suspendedComponentResolvers.size) {
3657 // Notifying components is needed to wake from suspense, even when using
3658 // early rendering.
3659 notifyComponents(store, storeState, treeState); // Wake all suspended components so the right one(s) can try to re-render.
3660 // We need to wake up components not just when some asynchronous selector
3661 // resolved, but also when changing synchronous values because this may cause
3662 // a selector to change from asynchronous to synchronous, in which case there
3663 // would be no follow-up asynchronous resolution to wake us up.
3664 // TODO OPTIMIZATION Only wake up related downstream components
3665
3666 storeState.suspendedComponentResolvers.forEach(cb => cb());
3667 storeState.suspendedComponentResolvers.clear();
3668 }
3669 } // Special behavior ONLY invoked by useInterface.
3670 // FIXME delete queuedComponentCallbacks_DEPRECATED when deleting useInterface.
3671
3672
3673 storeState.queuedComponentCallbacks_DEPRECATED.forEach(cb => cb(treeState));
3674 storeState.queuedComponentCallbacks_DEPRECATED.splice(0, storeState.queuedComponentCallbacks_DEPRECATED.length);
3675 }
3676
3677 function endBatch(storeRef) {
3678 const storeState = storeRef.current.getState();
3679 storeState.commitDepth++;
3680
3681 try {
3682 const {
3683 nextTree
3684 } = storeState; // Ignore commits that are not because of Recoil transactions -- namely,
3685 // because something above RecoilRoot re-rendered:
3686
3687 if (nextTree === null) {
3688 return;
3689 } // nextTree is now committed -- note that copying and reset occurs when
3690 // a transaction begins, in startNextTreeIfNeeded:
3691
3692
3693 storeState.previousTree = storeState.currentTree;
3694 storeState.currentTree = nextTree;
3695 storeState.nextTree = null;
3696 sendEndOfBatchNotifications(storeRef.current);
3697
3698 if (storeState.previousTree != null) {
3699 storeState.graphsByVersion.delete(storeState.previousTree.version);
3700 } else {
3701 Recoil_recoverableViolation('Ended batch with no previous state, which is unexpected', 'recoil');
3702 }
3703
3704 storeState.previousTree = null;
3705
3706 if (Recoil_gkx_1('recoil_memory_managament_2020')) {
3707 releaseScheduledRetainablesNow$1(storeRef.current);
3708 }
3709 } finally {
3710 storeState.commitDepth--;
3711 }
3712 }
3713 /*
3714 * The purpose of the Batcher is to observe when React batches end so that
3715 * Recoil state changes can be batched. Whenever Recoil state changes, we call
3716 * setState on the batcher. Then we wait for that change to be committed, which
3717 * signifies the end of the batch. That's when we respond to the Recoil change.
3718 */
3719
3720
3721 function Batcher({
3722 setNotifyBatcherOfChange
3723 }) {
3724 const storeRef = useStoreRef();
3725 const [_, setState] = useState([]);
3726 setNotifyBatcherOfChange(() => setState({}));
3727 useEffect(() => {
3728 // enqueueExecution runs this function immediately; it is only used to
3729 // manipulate the order of useEffects during tests, since React seems to
3730 // call useEffect in an unpredictable order sometimes.
3731 Recoil_Queue.enqueueExecution('Batcher', () => {
3732 endBatch(storeRef);
3733 });
3734 }); // If an asynchronous selector resolves after the Batcher is unmounted,
3735 // notifyBatcherOfChange will still be called. An error gets thrown whenever
3736 // setState is called after a component is already unmounted, so this sets
3737 // notifyBatcherOfChange to be a no-op.
3738
3739 useEffect(() => {
3740 return () => {
3741 setNotifyBatcherOfChange(() => {});
3742 };
3743 }, [setNotifyBatcherOfChange]);
3744 return null;
3745 }
3746
3747 {
3748 if (typeof window !== 'undefined' && !window.$recoilDebugStates) {
3749 window.$recoilDebugStates = [];
3750 }
3751 } // When removing this deprecated function, remove stateBySettingRecoilValue
3752 // which will no longer be needed.
3753
3754
3755 function initialStoreState_DEPRECATED(store, initializeState) {
3756 const initial = makeEmptyStoreState$2();
3757 initializeState({
3758 // $FlowFixMe[escaped-generic]
3759 set: (atom, value) => {
3760 const state = initial.currentTree;
3761 const writes = setNodeValue$2(store, state, atom.key, value);
3762 const writtenNodes = new Set(writes.keys());
3763 const nonvalidatedAtoms = state.nonvalidatedAtoms.clone();
3764
3765 for (const n of writtenNodes) {
3766 nonvalidatedAtoms.delete(n);
3767 }
3768
3769 initial.currentTree = { ...state,
3770 dirtyAtoms: Recoil_unionSets(state.dirtyAtoms, writtenNodes),
3771 atomValues: applyAtomValueWrites$1(state.atomValues, writes),
3772 // NB: PLEASE un-export applyAtomValueWrites when deleting this code
3773 nonvalidatedAtoms
3774 };
3775 },
3776 setUnvalidatedAtomValues: atomValues => {
3777 // FIXME replace this with a mutative loop
3778 atomValues.forEach((v, k) => {
3779 initial.currentTree = setUnvalidatedAtomValue_DEPRECATED$1(initial.currentTree, k, v);
3780 });
3781 }
3782 });
3783 return initial;
3784 }
3785
3786 function initialStoreState(initializeState) {
3787 const snapshot = freshSnapshot$1().map(initializeState);
3788 return snapshot.getStore_INTERNAL().getState();
3789 }
3790
3791 let nextID = 0;
3792
3793 function RecoilRoot_INTERNAL({
3794 initializeState_DEPRECATED,
3795 initializeState,
3796 store_INTERNAL: storeProp,
3797 // For use with React "context bridging"
3798 children
3799 }) {
3800 var _createMutableSource;
3801
3802 // prettier-ignore
3803 // @fb-only: useEffect(() => {
3804 // @fb-only: if (gkx('recoil_usage_logging')) {
3805 // @fb-only: try {
3806 // @fb-only: RecoilUsageLogFalcoEvent.log(() => ({
3807 // @fb-only: type: RecoilusagelogEvent.RECOIL_ROOT_MOUNTED,
3808 // @fb-only: path: URI.getRequestURI().getPath(),
3809 // @fb-only: }));
3810 // @fb-only: } catch {
3811 // @fb-only: recoverableViolation(
3812 // @fb-only: 'Error when logging Recoil Usage event',
3813 // @fb-only: 'recoil',
3814 // @fb-only: );
3815 // @fb-only: }
3816 // @fb-only: }
3817 // @fb-only: }, []);
3818 let storeState; // eslint-disable-line prefer-const
3819
3820 const getGraph = version => {
3821 const graphs = storeState.current.graphsByVersion;
3822
3823 if (graphs.has(version)) {
3824 return Recoil_nullthrows(graphs.get(version));
3825 }
3826
3827 const newGraph = graph$3();
3828 graphs.set(version, newGraph);
3829 return newGraph;
3830 };
3831
3832 const subscribeToTransactions = (callback, key) => {
3833 if (key == null) {
3834 // Global transaction subscriptions
3835 const {
3836 transactionSubscriptions
3837 } = storeRef.current.getState();
3838 const id = nextID++;
3839 transactionSubscriptions.set(id, callback);
3840 return {
3841 release: () => {
3842 transactionSubscriptions.delete(id);
3843 }
3844 };
3845 } else {
3846 // Node-specific transaction subscriptions:
3847 const {
3848 nodeTransactionSubscriptions
3849 } = storeRef.current.getState();
3850
3851 if (!nodeTransactionSubscriptions.has(key)) {
3852 nodeTransactionSubscriptions.set(key, new Map());
3853 }
3854
3855 const id = nextID++;
3856 Recoil_nullthrows(nodeTransactionSubscriptions.get(key)).set(id, callback);
3857 return {
3858 release: () => {
3859 const subs = nodeTransactionSubscriptions.get(key);
3860
3861 if (subs) {
3862 subs.delete(id);
3863
3864 if (subs.size === 0) {
3865 nodeTransactionSubscriptions.delete(key);
3866 }
3867 }
3868 }
3869 };
3870 }
3871 };
3872
3873 const addTransactionMetadata = metadata => {
3874 startNextTreeIfNeeded(storeRef.current);
3875
3876 for (const k of Object.keys(metadata)) {
3877 Recoil_nullthrows(storeRef.current.getState().nextTree).transactionMetadata[k] = metadata[k];
3878 }
3879 };
3880
3881 const replaceState = replacer => {
3882 const storeState = storeRef.current.getState();
3883 startNextTreeIfNeeded(storeRef.current); // Use replacer to get the next state:
3884
3885 const nextTree = Recoil_nullthrows(storeState.nextTree);
3886 let replaced;
3887
3888 try {
3889 stateReplacerIsBeingExecuted = true;
3890 replaced = replacer(nextTree);
3891 } finally {
3892 stateReplacerIsBeingExecuted = false;
3893 }
3894
3895 if (replaced === nextTree) {
3896 return;
3897 }
3898
3899 {
3900 if (typeof window !== 'undefined') {
3901 window.$recoilDebugStates.push(replaced); // TODO this shouldn't happen here because it's not batched
3902 }
3903 } // Save changes to nextTree and schedule a React update:
3904
3905
3906 storeState.nextTree = replaced;
3907
3908 if (Recoil_gkx_1('recoil_early_rendering_2021')) {
3909 notifyComponents(store, storeState, replaced);
3910 }
3911
3912 Recoil_nullthrows(notifyBatcherOfChange.current)();
3913 };
3914
3915 const notifyBatcherOfChange = useRef(null);
3916 const setNotifyBatcherOfChange = useCallback(x => {
3917 notifyBatcherOfChange.current = x;
3918 }, [notifyBatcherOfChange]); // FIXME T2710559282599660
3919
3920 const createMutableSource = (_createMutableSource = react.createMutableSource) !== null && _createMutableSource !== void 0 ? _createMutableSource : // flowlint-line unclear-type:off
3921 react.unstable_createMutableSource; // flowlint-line unclear-type:off
3922
3923 const store = storeProp !== null && storeProp !== void 0 ? storeProp : {
3924 getState: () => storeState.current,
3925 replaceState,
3926 getGraph,
3927 subscribeToTransactions,
3928 addTransactionMetadata
3929 };
3930 const storeRef = useRef(store);
3931 storeState = useRef(initializeState_DEPRECATED != null ? initialStoreState_DEPRECATED(store, initializeState_DEPRECATED) : initializeState != null ? initialStoreState(initializeState) : makeEmptyStoreState$2());
3932 const mutableSource = useMemo(() => createMutableSource ? createMutableSource(storeState, () => storeState.current.currentTree.version) : null, [createMutableSource, storeState]); // Cleanup when the <RecoilRoot> is unmounted
3933
3934 useEffect(() => () => {
3935 for (const atomKey of storeRef.current.getState().knownAtoms) {
3936 cleanUpNode$2(storeRef.current, atomKey);
3937 }
3938 }, []);
3939 return /*#__PURE__*/react.createElement(AppContext.Provider, {
3940 value: storeRef
3941 }, /*#__PURE__*/react.createElement(MutableSourceContext.Provider, {
3942 value: mutableSource
3943 }, /*#__PURE__*/react.createElement(Batcher, {
3944 setNotifyBatcherOfChange: setNotifyBatcherOfChange
3945 }), children));
3946 }
3947
3948 function RecoilRoot(props) {
3949 const {
3950 override,
3951 ...propsExceptOverride
3952 } = props;
3953 const ancestorStoreRef = useStoreRef();
3954
3955 if (override === false && ancestorStoreRef.current !== defaultStore) {
3956 // If ancestorStoreRef.current !== defaultStore, it means that this
3957 // RecoilRoot is not nested within another.
3958 return props.children;
3959 }
3960
3961 return /*#__PURE__*/react.createElement(RecoilRoot_INTERNAL, propsExceptOverride);
3962 }
3963
3964 var Recoil_RecoilRoot_react = {
3965 useStoreRef,
3966 useRecoilMutableSource,
3967 RecoilRoot,
3968 notifyComponents_FOR_TESTING: notifyComponents,
3969 sendEndOfBatchNotifications_FOR_TESTING: sendEndOfBatchNotifications
3970 };
3971
3972 const {
3973 loadableWithValue: loadableWithValue$1
3974 } = Recoil_Loadable;
3975
3976 const {
3977 DEFAULT_VALUE: DEFAULT_VALUE$2,
3978 getNode: getNode$3
3979 } = Recoil_Node;
3980
3981 const {
3982 copyTreeState: copyTreeState$1,
3983 getRecoilValueAsLoadable: getRecoilValueAsLoadable$2,
3984 invalidateDownstreams: invalidateDownstreams$1,
3985 writeLoadableToTreeState: writeLoadableToTreeState$1
3986 } = Recoil_RecoilValueInterface;
3987
3988 function isAtom(recoilValue) {
3989 return getNode$3(recoilValue.key).nodeType === 'atom';
3990 }
3991
3992 class TransactionInterfaceImpl {
3993 constructor(store, treeState) {
3994 _defineProperty(this, "_store", void 0);
3995
3996 _defineProperty(this, "_treeState", void 0);
3997
3998 _defineProperty(this, "_changes", void 0);
3999
4000 _defineProperty(this, "get", recoilValue => {
4001 if (this._changes.has(recoilValue.key)) {
4002 // $FlowFixMe[incompatible-return]
4003 return this._changes.get(recoilValue.key);
4004 }
4005
4006 if (!isAtom(recoilValue)) {
4007 throw new Error('Reading selectors within atomicUpdate is not supported');
4008 }
4009
4010 const loadable = getRecoilValueAsLoadable$2(this._store, recoilValue, this._treeState);
4011
4012 if (loadable.state === 'hasValue') {
4013 return loadable.contents;
4014 } else if (loadable.state === 'hasError') {
4015 throw loadable.contents;
4016 } else {
4017 throw new Error(`Expected Recoil atom ${recoilValue.key} to have a value, but it is in a loading state.`);
4018 }
4019 });
4020
4021 _defineProperty(this, "set", (recoilState, valueOrUpdater) => {
4022 if (!isAtom(recoilState)) {
4023 throw new Error('Setting selectors within atomicUpdate is not supported');
4024 }
4025
4026 if (typeof valueOrUpdater === 'function') {
4027 const current = this.get(recoilState);
4028
4029 this._changes.set(recoilState.key, valueOrUpdater(current)); // flowlint-line unclear-type:off
4030
4031 } else {
4032 this._changes.set(recoilState.key, valueOrUpdater);
4033 }
4034 });
4035
4036 _defineProperty(this, "reset", recoilState => {
4037 this.set(recoilState, DEFAULT_VALUE$2);
4038 });
4039
4040 this._store = store;
4041 this._treeState = treeState;
4042 this._changes = new Map();
4043 } // Allow destructing
4044 // eslint-disable-next-line fb-www/extra-arrow-initializer
4045
4046
4047 newTreeState_INTERNAL() {
4048 if (this._changes.size === 0) {
4049 return this._treeState;
4050 }
4051
4052 const newState = copyTreeState$1(this._treeState);
4053
4054 for (const [k, v] of this._changes) {
4055 writeLoadableToTreeState$1(newState, k, loadableWithValue$1(v));
4056 }
4057
4058 invalidateDownstreams$1(this._store, newState);
4059 return newState;
4060 }
4061
4062 }
4063
4064 function atomicUpdater(store) {
4065 return fn => {
4066 store.replaceState(treeState => {
4067 const changeset = new TransactionInterfaceImpl(store, treeState);
4068 fn(changeset);
4069 return changeset.newTreeState_INTERNAL();
4070 });
4071 };
4072 }
4073
4074 var Recoil_AtomicUpdates = {
4075 atomicUpdater
4076 };
4077
4078 var Recoil_AtomicUpdates_1 = Recoil_AtomicUpdates.atomicUpdater;
4079
4080 var Recoil_AtomicUpdates$1 = /*#__PURE__*/Object.freeze({
4081 __proto__: null,
4082 atomicUpdater: Recoil_AtomicUpdates_1
4083 });
4084
4085 /**
4086 * Copyright (c) Facebook, Inc. and its affiliates.
4087 *
4088 * This source code is licensed under the MIT license found in the
4089 * LICENSE file in the root directory of this source tree.
4090 *
4091 * @emails oncall+recoil
4092 *
4093 * @format
4094 */
4095 /**
4096 * Returns a map containing all of the keys + values from the original map where
4097 * the given callback returned true.
4098 */
4099
4100 function filterMap(map, callback) {
4101 const result = new Map();
4102
4103 for (const [key, value] of map) {
4104 if (callback(value, key)) {
4105 result.set(key, value);
4106 }
4107 }
4108
4109 return result;
4110 }
4111
4112 var Recoil_filterMap = filterMap;
4113
4114 /**
4115 * Copyright (c) Facebook, Inc. and its affiliates.
4116 *
4117 * This source code is licensed under the MIT license found in the
4118 * LICENSE file in the root directory of this source tree.
4119 *
4120 * @emails oncall+recoil
4121 *
4122 * @format
4123 */
4124 /**
4125 * Returns a set containing all of the values from the original set where
4126 * the given callback returned true.
4127 */
4128
4129 function filterSet(set, callback) {
4130 const result = new Set();
4131
4132 for (const value of set) {
4133 if (callback(value)) {
4134 result.add(value);
4135 }
4136 }
4137
4138 return result;
4139 }
4140
4141 var Recoil_filterSet = filterSet;
4142
4143 /**
4144 * Copyright (c) Facebook, Inc. and its affiliates.
4145 *
4146 * This source code is licensed under the MIT license found in the
4147 * LICENSE file in the root directory of this source tree.
4148 *
4149 * @emails oncall+recoil
4150 *
4151 * @format
4152 */
4153
4154 function invariant(condition, message) {
4155 if (!condition) {
4156 throw new Error(message);
4157 }
4158 }
4159
4160 var invariant_1 = invariant;
4161
4162 // @oss-only
4163
4164
4165 var Recoil_invariant = invariant_1;
4166
4167 /**
4168 * Copyright (c) Facebook, Inc. and its affiliates.
4169 *
4170 * This source code is licensed under the MIT license found in the
4171 * LICENSE file in the root directory of this source tree.
4172 *
4173 * @emails oncall+recoil
4174 *
4175 * @format
4176 */
4177
4178 function mergeMaps(...maps) {
4179 const result = new Map();
4180
4181 for (let i = 0; i < maps.length; i++) {
4182 const iterator = maps[i].keys();
4183 let nextKey;
4184
4185 while (!(nextKey = iterator.next()).done) {
4186 // $FlowFixMe[incompatible-call] - map/iterator knows nothing about flow types
4187 result.set(nextKey.value, maps[i].get(nextKey.value));
4188 }
4189 }
4190 /* $FlowFixMe[incompatible-return] (>=0.66.0 site=www,mobile) This comment
4191 * suppresses an error found when Flow v0.66 was deployed. To see the error
4192 * delete this comment and run Flow. */
4193
4194
4195 return result;
4196 }
4197
4198 var Recoil_mergeMaps = mergeMaps;
4199
4200 /**
4201 * Copyright (c) Facebook, Inc. and its affiliates.
4202 *
4203 * This source code is licensed under the MIT license found in the
4204 * LICENSE file in the root directory of this source tree.
4205 *
4206 * @emails oncall+recoil
4207 *
4208 * @format
4209 */
4210
4211 function shallowArrayEqual(a, b) {
4212 if (a === b) {
4213 return true;
4214 }
4215
4216 if (a.length !== b.length) {
4217 return false;
4218 }
4219
4220 for (let i = 0, l = a.length; i < l; i++) {
4221 if (a[i] !== b[i]) {
4222 return false;
4223 }
4224 }
4225
4226 return true;
4227 }
4228
4229 var Recoil_shallowArrayEqual = shallowArrayEqual;
4230
4231 /**
4232 * Copyright (c) Facebook, Inc. and its affiliates.
4233 *
4234 * MIT License
4235 *
4236 * Copyright (c) 2014-2019 Georg Tavonius
4237 *
4238 * Permission is hereby granted, free of charge, to any person obtaining a copy
4239 * of this software and associated documentation files (the "Software"), to deal
4240 * in the Software without restriction, including without limitation the rights
4241 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4242 * copies of the Software, and to permit persons to whom the Software is
4243 * furnished to do so, subject to the following conditions:
4244 *
4245 * The above copyright notice and this permission notice shall be included in all
4246 * copies or substantial portions of the Software.
4247 *
4248 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4249 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4250 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4251 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4252 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4253 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4254 * SOFTWARE.
4255 *
4256 * @emails oncall+recoil
4257 *
4258 * @format
4259 */
4260
4261 const UNKNOWN_FUNCTION = '<unknown>';
4262 /**
4263 * This parses the different stack traces and puts them into one format
4264 * This borrows heavily from TraceKit (https://github.com/csnover/TraceKit)
4265 */
4266
4267 function stackTraceParser(stackString) {
4268 const lines = stackString.split('\n');
4269 return lines.reduce((stack, line) => {
4270 const parseResult = parseChrome(line) || parseWinjs(line) || parseGecko(line) || parseNode(line) || parseJSC(line);
4271
4272 if (parseResult) {
4273 stack.push(parseResult);
4274 }
4275
4276 return stack;
4277 }, []);
4278 }
4279
4280 const chromeRe = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\/|[a-z]:\\|\\\\).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
4281 const chromeEvalRe = /\((\S*)(?::(\d+))(?::(\d+))\)/;
4282
4283 function parseChrome(line) {
4284 const parts = chromeRe.exec(line);
4285
4286 if (!parts) {
4287 return null;
4288 }
4289
4290 const isNative = parts[2] && parts[2].indexOf('native') === 0; // start of line
4291
4292 const isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
4293
4294 const submatch = chromeEvalRe.exec(parts[2]);
4295
4296 if (isEval && submatch != null) {
4297 // throw out eval line/column and use top-most line/column number
4298 parts[2] = submatch[1]; // url
4299
4300 parts[3] = submatch[2]; // line
4301
4302 parts[4] = submatch[3]; // column
4303 }
4304
4305 return {
4306 file: !isNative ? parts[2] : null,
4307 methodName: parts[1] || UNKNOWN_FUNCTION,
4308 arguments: isNative ? [parts[2]] : [],
4309 lineNumber: parts[3] ? +parts[3] : null,
4310 column: parts[4] ? +parts[4] : null
4311 };
4312 }
4313
4314 const winjsRe = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
4315
4316 function parseWinjs(line) {
4317 const parts = winjsRe.exec(line);
4318
4319 if (!parts) {
4320 return null;
4321 }
4322
4323 return {
4324 file: parts[2],
4325 methodName: parts[1] || UNKNOWN_FUNCTION,
4326 arguments: [],
4327 lineNumber: +parts[3],
4328 column: parts[4] ? +parts[4] : null
4329 };
4330 }
4331
4332 const geckoRe = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i;
4333 const geckoEvalRe = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
4334
4335 function parseGecko(line) {
4336 const parts = geckoRe.exec(line);
4337
4338 if (!parts) {
4339 return null;
4340 }
4341
4342 const isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
4343 const submatch = geckoEvalRe.exec(parts[3]);
4344
4345 if (isEval && submatch != null) {
4346 // throw out eval line/column and use top-most line number
4347 parts[3] = submatch[1];
4348 parts[4] = submatch[2];
4349 parts[5] = null; // no column when eval
4350 }
4351
4352 return {
4353 file: parts[3],
4354 methodName: parts[1] || UNKNOWN_FUNCTION,
4355 arguments: parts[2] ? parts[2].split(',') : [],
4356 lineNumber: parts[4] ? +parts[4] : null,
4357 column: parts[5] ? +parts[5] : null
4358 };
4359 }
4360
4361 const javaScriptCoreRe = /^\s*(?:([^@]*)(?:\((.*?)\))?@)?(\S.*?):(\d+)(?::(\d+))?\s*$/i;
4362
4363 function parseJSC(line) {
4364 const parts = javaScriptCoreRe.exec(line);
4365
4366 if (!parts) {
4367 return null;
4368 }
4369
4370 return {
4371 file: parts[3],
4372 methodName: parts[1] || UNKNOWN_FUNCTION,
4373 arguments: [],
4374 lineNumber: +parts[4],
4375 column: parts[5] ? +parts[5] : null
4376 };
4377 }
4378
4379 const nodeRe = /^\s*at (?:((?:\[object object\])?[^\\/]+(?: \[as \S+\])?) )?\(?(.*?):(\d+)(?::(\d+))?\)?\s*$/i;
4380
4381 function parseNode(line) {
4382 const parts = nodeRe.exec(line);
4383
4384 if (!parts) {
4385 return null;
4386 }
4387
4388 return {
4389 file: parts[2],
4390 methodName: parts[1] || UNKNOWN_FUNCTION,
4391 arguments: [],
4392 lineNumber: +parts[3],
4393 column: parts[4] ? +parts[4] : null
4394 };
4395 }
4396
4397 var Recoil_stackTraceParser = stackTraceParser;
4398
4399 const {
4400 useRef: useRef$1
4401 } = react;
4402
4403 function useComponentName() {
4404 const nameRef = useRef$1();
4405
4406 {
4407 if (Recoil_gkx_1('recoil_infer_component_names')) {
4408 var _nameRef$current;
4409
4410 if (nameRef.current === undefined) {
4411 // There is no blessed way to determine the calling React component from
4412 // within a hook. This hack uses the fact that hooks must start with 'use'
4413 // and that hooks are either called by React Components or other hooks. It
4414 // follows therefore, that to find the calling component, you simply need
4415 // to look down the stack and find the first function which doesn't start
4416 // with 'use'. We are only enabling this in dev for now, since once the
4417 // codebase is minified, the naming assumptions no longer hold true.
4418 const frames = Recoil_stackTraceParser(new Error().stack);
4419
4420 for (const {
4421 methodName
4422 } of frames) {
4423 // I observed cases where the frame was of the form 'Object.useXXX'
4424 // hence why I'm searching for hooks following a word boundary
4425 if (!methodName.match(/\buse[^\b]+$/)) {
4426 return nameRef.current = methodName;
4427 }
4428 }
4429
4430 nameRef.current = null;
4431 }
4432
4433 return (_nameRef$current = nameRef.current) !== null && _nameRef$current !== void 0 ? _nameRef$current : '<unable to determine component name>';
4434 }
4435 } // @fb-only: return "<component name only available when both in dev mode and when passing GK 'recoil_infer_component_names'>";
4436
4437
4438 return '<component name not available>'; // @oss-only
4439 }
4440
4441 var Recoil_useComponentName = useComponentName;
4442
4443 const {
4444 atomicUpdater: atomicUpdater$1
4445 } = Recoil_AtomicUpdates$1;
4446
4447 const {
4448 batchUpdates: batchUpdates$2
4449 } = Recoil_Batching;
4450
4451 const {
4452 DEFAULT_VALUE: DEFAULT_VALUE$3,
4453 getNode: getNode$4,
4454 nodes: nodes$1
4455 } = Recoil_Node;
4456
4457 const {
4458 useRecoilMutableSource: useRecoilMutableSource$1,
4459 useStoreRef: useStoreRef$1
4460 } = Recoil_RecoilRoot_react;
4461
4462 const {
4463 isRecoilValue: isRecoilValue$2
4464 } = Recoil_RecoilValue$1;
4465
4466 const {
4467 AbstractRecoilValue: AbstractRecoilValue$3,
4468 getRecoilValueAsLoadable: getRecoilValueAsLoadable$3,
4469 setRecoilValue: setRecoilValue$2,
4470 setRecoilValueLoadable: setRecoilValueLoadable$1,
4471 setUnvalidatedRecoilValue: setUnvalidatedRecoilValue$2,
4472 subscribeToRecoilValue: subscribeToRecoilValue$1
4473 } = Recoil_RecoilValueInterface;
4474
4475 const {
4476 updateRetainCount: updateRetainCount$2
4477 } = Recoil_Retention;
4478
4479 const {
4480 RetentionZone: RetentionZone$3
4481 } = Recoil_RetentionZone;
4482
4483 const {
4484 Snapshot: Snapshot$1,
4485 cloneSnapshot: cloneSnapshot$1
4486 } = Recoil_Snapshot$1;
4487
4488 const {
4489 setByAddingToSet: setByAddingToSet$2
4490 } = Recoil_CopyOnWrite;
4491
4492
4493
4494 const {
4495 isSSR: isSSR$2
4496 } = Recoil_Environment;
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512 const {
4513 mutableSourceExists: mutableSourceExists$2,
4514 useMutableSource: useMutableSource$1
4515 } = Recoil_mutableSource;
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525 const {
4526 useCallback: useCallback$1,
4527 useEffect: useEffect$1,
4528 useMemo: useMemo$1,
4529 useRef: useRef$2,
4530 useState: useState$1
4531 } = react; // Components that aren't mounted after suspending for this long will be assumed
4532 // to be discarded and their resources released.
4533
4534
4535 const SUSPENSE_TIMEOUT_MS = 120000;
4536
4537 function handleLoadable(loadable, recoilValue, storeRef) {
4538 // We can't just throw the promise we are waiting on to Suspense. If the
4539 // upstream dependencies change it may produce a state in which the component
4540 // can render, but it would still be suspended on a Promise that may never resolve.
4541 if (loadable.state === 'hasValue') {
4542 return loadable.contents;
4543 } else if (loadable.state === 'loading') {
4544 const promise = new Promise(resolve => {
4545 storeRef.current.getState().suspendedComponentResolvers.add(resolve);
4546 }); // $FlowFixMe Flow(prop-missing) for integrating with tools that inspect thrown promises @fb-only
4547 // @fb-only: promise.displayName = `Recoil State: ${recoilValue.key}`;
4548
4549 throw promise;
4550 } else if (loadable.state === 'hasError') {
4551 throw loadable.contents;
4552 } else {
4553 const err = new Error(`Invalid value of loadable atom "${recoilValue.key}"`);
4554
4555 throw err;
4556 }
4557 }
4558
4559 function validateRecoilValue(recoilValue, hookName) {
4560 if (!isRecoilValue$2(recoilValue)) {
4561 throw new Error(`Invalid argument to ${hookName}: expected an atom or selector but got ${String(recoilValue)}`);
4562 }
4563 }
4564
4565 /**
4566 * Various things are broken with useRecoilInterface, particularly concurrent mode
4567 * and memory management. They will not be fixed.
4568 * */
4569 function useRecoilInterface_DEPRECATED() {
4570 const storeRef = useStoreRef$1();
4571 const [_, forceUpdate] = useState$1([]);
4572 const recoilValuesUsed = useRef$2(new Set());
4573 recoilValuesUsed.current = new Set(); // Track the RecoilValues used just during this render
4574
4575 const previousSubscriptions = useRef$2(new Set());
4576 const subscriptions = useRef$2(new Map());
4577 const unsubscribeFrom = useCallback$1(key => {
4578 const sub = subscriptions.current.get(key);
4579
4580 if (sub) {
4581 sub.release();
4582 subscriptions.current.delete(key);
4583 }
4584 }, [subscriptions]);
4585 const componentName = Recoil_useComponentName();
4586 useEffect$1(() => {
4587 const store = storeRef.current;
4588
4589 function updateState(_state, key) {
4590 if (!subscriptions.current.has(key)) {
4591 return;
4592 }
4593
4594 forceUpdate([]);
4595 }
4596
4597 Recoil_differenceSets(recoilValuesUsed.current, previousSubscriptions.current).forEach(key => {
4598 if (subscriptions.current.has(key)) {
4599 Recoil_expectationViolation(`Double subscription to RecoilValue "${key}"`);
4600 return;
4601 }
4602
4603 const sub = subscribeToRecoilValue$1(store, new AbstractRecoilValue$3(key), state => {
4604 updateState(state, key);
4605 }, componentName);
4606 subscriptions.current.set(key, sub);
4607 /**
4608 * Since we're subscribing in an effect we need to update to the latest
4609 * value of the atom since it may have changed since we rendered. We can
4610 * go ahead and do that now, unless we're in the middle of a batch --
4611 * in which case we should do it at the end of the batch, due to the
4612 * following edge case: Suppose an atom is updated in another useEffect
4613 * of this same component. Then the following sequence of events occur:
4614 * 1. Atom is updated and subs fired (but we may not be subscribed
4615 * yet depending on order of effects, so we miss this) Updated value
4616 * is now in nextTree, but not currentTree.
4617 * 2. This effect happens. We subscribe and update.
4618 * 3. From the update we re-render and read currentTree, with old value.
4619 * 4. Batcher's effect sets currentTree to nextTree.
4620 * In this sequence we miss the update. To avoid that, add the update
4621 * to queuedComponentCallback if a batch is in progress.
4622 */
4623 // FIXME delete queuedComponentCallbacks_DEPRECATED when deleting useInterface.
4624
4625 const state = store.getState();
4626
4627 if (state.nextTree) {
4628 store.getState().queuedComponentCallbacks_DEPRECATED.push(() => {
4629 updateState(store.getState(), key);
4630 });
4631 } else {
4632 updateState(store.getState(), key);
4633 }
4634 });
4635 Recoil_differenceSets(previousSubscriptions.current, recoilValuesUsed.current).forEach(key => {
4636 unsubscribeFrom(key);
4637 });
4638 previousSubscriptions.current = recoilValuesUsed.current;
4639 });
4640 useEffect$1(() => {
4641 const subs = subscriptions.current;
4642 return () => subs.forEach((_, key) => unsubscribeFrom(key));
4643 }, [unsubscribeFrom]);
4644 return useMemo$1(() => {
4645 function useSetRecoilState(recoilState) {
4646 {
4647 // $FlowFixMe[escaped-generic]
4648 validateRecoilValue(recoilState, 'useSetRecoilState');
4649 }
4650
4651 return newValueOrUpdater => {
4652 setRecoilValue$2(storeRef.current, recoilState, newValueOrUpdater);
4653 };
4654 }
4655
4656 function useResetRecoilState(recoilState) {
4657 {
4658 // $FlowFixMe[escaped-generic]
4659 validateRecoilValue(recoilState, 'useResetRecoilState');
4660 }
4661
4662 return () => setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$3);
4663 }
4664
4665 function useRecoilValueLoadable(recoilValue) {
4666 var _storeState$nextTree;
4667
4668 {
4669 // $FlowFixMe[escaped-generic]
4670 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
4671 }
4672
4673 if (!recoilValuesUsed.current.has(recoilValue.key)) {
4674 recoilValuesUsed.current = setByAddingToSet$2(recoilValuesUsed.current, recoilValue.key);
4675 } // TODO Restore optimization to memoize lookup
4676
4677
4678 const storeState = storeRef.current.getState();
4679 return getRecoilValueAsLoadable$3(storeRef.current, recoilValue, Recoil_gkx_1('recoil_early_rendering_2021') ? (_storeState$nextTree = storeState.nextTree) !== null && _storeState$nextTree !== void 0 ? _storeState$nextTree : storeState.currentTree : storeState.currentTree);
4680 }
4681
4682 function useRecoilValue(recoilValue) {
4683 {
4684 // $FlowFixMe[escaped-generic]
4685 validateRecoilValue(recoilValue, 'useRecoilValue');
4686 }
4687
4688 const loadable = useRecoilValueLoadable(recoilValue);
4689 return handleLoadable(loadable, recoilValue, storeRef);
4690 }
4691
4692 function useRecoilState(recoilState) {
4693 {
4694 // $FlowFixMe[escaped-generic]
4695 validateRecoilValue(recoilState, 'useRecoilState');
4696 }
4697
4698 return [useRecoilValue(recoilState), useSetRecoilState(recoilState)];
4699 }
4700
4701 function useRecoilStateLoadable(recoilState) {
4702 {
4703 // $FlowFixMe[escaped-generic]
4704 validateRecoilValue(recoilState, 'useRecoilStateLoadable');
4705 }
4706
4707 return [useRecoilValueLoadable(recoilState), useSetRecoilState(recoilState)];
4708 }
4709
4710 return {
4711 getRecoilValue: useRecoilValue,
4712 getRecoilValueLoadable: useRecoilValueLoadable,
4713 getRecoilState: useRecoilState,
4714 getRecoilStateLoadable: useRecoilStateLoadable,
4715 getSetRecoilState: useSetRecoilState,
4716 getResetRecoilState: useResetRecoilState
4717 };
4718 }, [recoilValuesUsed, storeRef]);
4719 }
4720
4721 const recoilComponentGetRecoilValueCount_FOR_TESTING = {
4722 current: 0
4723 };
4724
4725 function useRecoilValueLoadable_MUTABLESOURCE(recoilValue) {
4726 {
4727 // $FlowFixMe[escaped-generic]
4728 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
4729 }
4730
4731 const storeRef = useStoreRef$1();
4732 const getLoadable = useCallback$1(() => {
4733 var _storeState$nextTree2;
4734
4735 const store = storeRef.current;
4736 const storeState = store.getState();
4737 const treeState = Recoil_gkx_1('recoil_early_rendering_2021') ? (_storeState$nextTree2 = storeState.nextTree) !== null && _storeState$nextTree2 !== void 0 ? _storeState$nextTree2 : storeState.currentTree : storeState.currentTree;
4738 return getRecoilValueAsLoadable$3(store, recoilValue, treeState);
4739 }, [storeRef, recoilValue]);
4740 const getLoadableWithTesting = useCallback$1(() => {
4741 {
4742 recoilComponentGetRecoilValueCount_FOR_TESTING.current++;
4743 }
4744
4745 return getLoadable();
4746 }, [getLoadable]);
4747 const componentName = Recoil_useComponentName();
4748 const subscribe = useCallback$1((_storeState, callback) => {
4749 const store = storeRef.current;
4750 const subscription = subscribeToRecoilValue$1(store, recoilValue, () => {
4751 if (!Recoil_gkx_1('recoil_suppress_rerender_in_callback')) {
4752 return callback();
4753 } // Only re-render if the value has changed.
4754 // This will evaluate the atom/selector now as well as when the
4755 // component renders, but that may help with prefetching.
4756
4757
4758 const newLoadable = getLoadable();
4759
4760 if (!prevLoadableRef.current.is(newLoadable)) {
4761 callback();
4762 } // If the component is suspended then the effect setting prevLoadableRef
4763 // will not run. So, set the previous value here when its subscription
4764 // is fired to wake it up. We can't just rely on this, though, because
4765 // this only executes when an atom/selector is dirty and the atom/selector
4766 // passed to the hook can dynamically change.
4767
4768
4769 prevLoadableRef.current = newLoadable;
4770 }, componentName);
4771 return subscription.release;
4772 }, [storeRef, recoilValue, componentName, getLoadable]);
4773 const source = useRecoilMutableSource$1();
4774 const loadable = useMutableSource$1(source, getLoadableWithTesting, subscribe);
4775 const prevLoadableRef = useRef$2(loadable);
4776 useEffect$1(() => {
4777 prevLoadableRef.current = loadable;
4778 });
4779 return loadable;
4780 }
4781
4782 function useRecoilValueLoadable_LEGACY(recoilValue) {
4783 {
4784 // $FlowFixMe[escaped-generic]
4785 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
4786 }
4787
4788 const storeRef = useStoreRef$1();
4789 const [_, forceUpdate] = useState$1([]);
4790 const componentName = Recoil_useComponentName();
4791 useEffect$1(() => {
4792 const store = storeRef.current;
4793 const storeState = store.getState();
4794 const subscription = subscribeToRecoilValue$1(store, recoilValue, _state => {
4795 var _prevLoadableRef$curr;
4796
4797 if (!Recoil_gkx_1('recoil_suppress_rerender_in_callback')) {
4798 return forceUpdate([]);
4799 }
4800
4801 const newLoadable = getRecoilValueAsLoadable$3(store, recoilValue, store.getState().currentTree);
4802
4803 if (!((_prevLoadableRef$curr = prevLoadableRef.current) === null || _prevLoadableRef$curr === void 0 ? void 0 : _prevLoadableRef$curr.is(newLoadable))) {
4804 forceUpdate(newLoadable);
4805 }
4806
4807 prevLoadableRef.current = newLoadable;
4808 }, componentName);
4809 /**
4810 * Since we're subscribing in an effect we need to update to the latest
4811 * value of the atom since it may have changed since we rendered. We can
4812 * go ahead and do that now, unless we're in the middle of a batch --
4813 * in which case we should do it at the end of the batch, due to the
4814 * following edge case: Suppose an atom is updated in another useEffect
4815 * of this same component. Then the following sequence of events occur:
4816 * 1. Atom is updated and subs fired (but we may not be subscribed
4817 * yet depending on order of effects, so we miss this) Updated value
4818 * is now in nextTree, but not currentTree.
4819 * 2. This effect happens. We subscribe and update.
4820 * 3. From the update we re-render and read currentTree, with old value.
4821 * 4. Batcher's effect sets currentTree to nextTree.
4822 * In this sequence we miss the update. To avoid that, add the update
4823 * to queuedComponentCallback if a batch is in progress.
4824 */
4825
4826 if (storeState.nextTree) {
4827 store.getState().queuedComponentCallbacks_DEPRECATED.push(() => {
4828 prevLoadableRef.current = null;
4829 forceUpdate([]);
4830 });
4831 } else {
4832 var _prevLoadableRef$curr2;
4833
4834 if (!Recoil_gkx_1('recoil_suppress_rerender_in_callback')) {
4835 return forceUpdate([]);
4836 }
4837
4838 const newLoadable = getRecoilValueAsLoadable$3(store, recoilValue, store.getState().currentTree);
4839
4840 if (!((_prevLoadableRef$curr2 = prevLoadableRef.current) === null || _prevLoadableRef$curr2 === void 0 ? void 0 : _prevLoadableRef$curr2.is(newLoadable))) {
4841 forceUpdate(newLoadable);
4842 }
4843
4844 prevLoadableRef.current = newLoadable;
4845 }
4846
4847 return subscription.release;
4848 }, [componentName, recoilValue, storeRef]);
4849 const loadable = getRecoilValueAsLoadable$3(storeRef.current, recoilValue);
4850 const prevLoadableRef = useRef$2(loadable);
4851 useEffect$1(() => {
4852 prevLoadableRef.current = loadable;
4853 });
4854 return loadable;
4855 }
4856 /**
4857 Like useRecoilValue(), but either returns the value if available or
4858 just undefined if not available for any reason, such as pending or error.
4859 */
4860
4861
4862 function useRecoilValueLoadable(recoilValue) {
4863 if (Recoil_gkx_1('recoil_memory_managament_2020')) {
4864 // eslint-disable-next-line fb-www/react-hooks
4865 useRetain(recoilValue);
4866 }
4867
4868 if (mutableSourceExists$2()) {
4869 // eslint-disable-next-line fb-www/react-hooks
4870 return useRecoilValueLoadable_MUTABLESOURCE(recoilValue);
4871 } else {
4872 // eslint-disable-next-line fb-www/react-hooks
4873 return useRecoilValueLoadable_LEGACY(recoilValue);
4874 }
4875 }
4876 /**
4877 Returns the value represented by the RecoilValue.
4878 If the value is pending, it will throw a Promise to suspend the component,
4879 if the value is an error it will throw it for the nearest React error boundary.
4880 This will also subscribe the component for any updates in the value.
4881 */
4882
4883
4884 function useRecoilValue(recoilValue) {
4885 {
4886 // $FlowFixMe[escaped-generic]
4887 validateRecoilValue(recoilValue, 'useRecoilValue');
4888 }
4889
4890 const storeRef = useStoreRef$1();
4891 const loadable = useRecoilValueLoadable(recoilValue);
4892 return handleLoadable(loadable, recoilValue, storeRef);
4893 }
4894 /**
4895 Returns a function that allows the value of a RecoilState to be updated, but does
4896 not subscribe the component to changes to that RecoilState.
4897 */
4898
4899
4900 function useSetRecoilState(recoilState) {
4901 {
4902 // $FlowFixMe[escaped-generic]
4903 validateRecoilValue(recoilState, 'useSetRecoilState');
4904 }
4905
4906 const storeRef = useStoreRef$1();
4907 return useCallback$1(newValueOrUpdater => {
4908 setRecoilValue$2(storeRef.current, recoilState, newValueOrUpdater);
4909 }, [storeRef, recoilState]);
4910 }
4911 /**
4912 Returns a function that will reset the value of a RecoilState to its default
4913 */
4914
4915
4916 function useResetRecoilState(recoilState) {
4917 {
4918 // $FlowFixMe[escaped-generic]
4919 validateRecoilValue(recoilState, 'useResetRecoilState');
4920 }
4921
4922 const storeRef = useStoreRef$1();
4923 return useCallback$1(() => {
4924 setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$3);
4925 }, [storeRef, recoilState]);
4926 }
4927 /**
4928 Equivalent to useState(). Allows the value of the RecoilState to be read and written.
4929 Subsequent updates to the RecoilState will cause the component to re-render. If the
4930 RecoilState is pending, this will suspend the component and initiate the
4931 retrieval of the value. If evaluating the RecoilState resulted in an error, this will
4932 throw the error so that the nearest React error boundary can catch it.
4933 */
4934
4935
4936 function useRecoilState(recoilState) {
4937 {
4938 // $FlowFixMe[escaped-generic]
4939 validateRecoilValue(recoilState, 'useRecoilState');
4940 }
4941
4942 return [useRecoilValue(recoilState), useSetRecoilState(recoilState)];
4943 }
4944 /**
4945 Like useRecoilState(), but does not cause Suspense or React error handling. Returns
4946 an object that indicates whether the RecoilState is available, pending, or
4947 unavailable due to an error.
4948 */
4949
4950
4951 function useRecoilStateLoadable(recoilState) {
4952 {
4953 // $FlowFixMe[escaped-generic]
4954 validateRecoilValue(recoilState, 'useRecoilStateLoadable');
4955 }
4956
4957 return [useRecoilValueLoadable(recoilState), useSetRecoilState(recoilState)];
4958 }
4959
4960 function useTransactionSubscription(callback) {
4961 const storeRef = useStoreRef$1();
4962 useEffect$1(() => {
4963 const sub = storeRef.current.subscribeToTransactions(callback);
4964 return sub.release;
4965 }, [callback, storeRef]);
4966 }
4967
4968 function externallyVisibleAtomValuesInState(state) {
4969 const atomValues = state.atomValues.toMap();
4970 const persistedAtomContentsValues = Recoil_mapMap(Recoil_filterMap(atomValues, (v, k) => {
4971 const node = getNode$4(k);
4972 const persistence = node.persistence_UNSTABLE;
4973 return persistence != null && persistence.type !== 'none' && v.state === 'hasValue';
4974 }), v => v.contents); // Merge in nonvalidated atoms; we may not have defs for them but they will
4975 // all have persistence on or they wouldn't be there in the first place.
4976
4977 return Recoil_mergeMaps(state.nonvalidatedAtoms.toMap(), persistedAtomContentsValues);
4978 }
4979
4980 /**
4981 Calls the given callback after any atoms have been modified and the consequent
4982 component re-renders have been committed. This is intended for persisting
4983 the values of the atoms to storage. The stored values can then be restored
4984 using the useSetUnvalidatedAtomValues hook.
4985
4986 The callback receives the following info:
4987
4988 atomValues: The current value of every atom that is both persistable (persistence
4989 type not set to 'none') and whose value is available (not in an
4990 error or loading state).
4991
4992 previousAtomValues: The value of every persistable and available atom before
4993 the transaction began.
4994
4995 atomInfo: A map containing the persistence settings for each atom. Every key
4996 that exists in atomValues will also exist in atomInfo.
4997
4998 modifiedAtoms: The set of atoms that were written to during the transaction.
4999
5000 transactionMetadata: Arbitrary information that was added via the
5001 useSetUnvalidatedAtomValues hook. Useful for ignoring the useSetUnvalidatedAtomValues
5002 transaction, to avoid loops.
5003 */
5004 function useTransactionObservation_DEPRECATED(callback) {
5005 useTransactionSubscription(useCallback$1(store => {
5006 let previousTree = store.getState().previousTree;
5007 const currentTree = store.getState().currentTree;
5008
5009 if (!previousTree) {
5010 Recoil_recoverableViolation('Transaction subscribers notified without a previous tree being present -- this is a bug in Recoil');
5011 previousTree = store.getState().currentTree; // attempt to trundle on
5012 }
5013
5014 const atomValues = externallyVisibleAtomValuesInState(currentTree);
5015 const previousAtomValues = externallyVisibleAtomValuesInState(previousTree);
5016 const atomInfo = Recoil_mapMap(nodes$1, node => {
5017 var _node$persistence_UNS, _node$persistence_UNS2, _node$persistence_UNS3, _node$persistence_UNS4;
5018
5019 return {
5020 persistence_UNSTABLE: {
5021 type: (_node$persistence_UNS = (_node$persistence_UNS2 = node.persistence_UNSTABLE) === null || _node$persistence_UNS2 === void 0 ? void 0 : _node$persistence_UNS2.type) !== null && _node$persistence_UNS !== void 0 ? _node$persistence_UNS : 'none',
5022 backButton: (_node$persistence_UNS3 = (_node$persistence_UNS4 = node.persistence_UNSTABLE) === null || _node$persistence_UNS4 === void 0 ? void 0 : _node$persistence_UNS4.backButton) !== null && _node$persistence_UNS3 !== void 0 ? _node$persistence_UNS3 : false
5023 }
5024 };
5025 }); // Filter on existance in atomValues so that externally-visible rules
5026 // are also applied to modified atoms (specifically exclude selectors):
5027
5028 const modifiedAtoms = Recoil_filterSet(currentTree.dirtyAtoms, k => atomValues.has(k) || previousAtomValues.has(k));
5029 callback({
5030 atomValues,
5031 previousAtomValues,
5032 atomInfo,
5033 modifiedAtoms,
5034 transactionMetadata: { ...currentTree.transactionMetadata
5035 }
5036 });
5037 }, [callback]));
5038 }
5039
5040 function useRecoilTransactionObserver(callback) {
5041 useTransactionSubscription(useCallback$1(store => {
5042 const snapshot = cloneSnapshot$1(store, 'current');
5043 const previousSnapshot = cloneSnapshot$1(store, 'previous');
5044 callback({
5045 snapshot,
5046 previousSnapshot
5047 });
5048 }, [callback]));
5049 }
5050
5051 function usePrevious(value) {
5052 const ref = useRef$2();
5053 useEffect$1(() => {
5054 ref.current = value;
5055 });
5056 return ref.current;
5057 } // Return a snapshot of the current state and subscribe to all state changes
5058
5059
5060 function useRecoilSnapshot() {
5061 const storeRef = useStoreRef$1();
5062 const [snapshot, setSnapshot] = useState$1(() => cloneSnapshot$1(storeRef.current));
5063 const previousSnapshot = usePrevious(snapshot);
5064 const timeoutID = useRef$2();
5065 useEffect$1(() => {
5066 if (timeoutID.current && !isSSR$2) {
5067 window.clearTimeout(timeoutID.current);
5068 }
5069
5070 return snapshot.retain();
5071 }, [snapshot]);
5072 useTransactionSubscription(useCallback$1(store => setSnapshot(cloneSnapshot$1(store)), []));
5073
5074 if (previousSnapshot !== snapshot && !isSSR$2) {
5075 if (timeoutID.current) {
5076 previousSnapshot === null || previousSnapshot === void 0 ? void 0 : previousSnapshot.release_INTERNAL();
5077 window.clearTimeout(timeoutID.current);
5078 }
5079
5080 snapshot.retain();
5081 timeoutID.current = window.setTimeout(() => {
5082 snapshot.release_INTERNAL();
5083 timeoutID.current = null;
5084 }, SUSPENSE_TIMEOUT_MS);
5085 }
5086
5087 return snapshot;
5088 }
5089
5090 function useGotoRecoilSnapshot() {
5091 const storeRef = useStoreRef$1();
5092 return useCallback$1(snapshot => {
5093 var _storeState$nextTree3;
5094
5095 const storeState = storeRef.current.getState();
5096 const prev = (_storeState$nextTree3 = storeState.nextTree) !== null && _storeState$nextTree3 !== void 0 ? _storeState$nextTree3 : storeState.currentTree;
5097 const next = snapshot.getStore_INTERNAL().getState().currentTree;
5098 batchUpdates$2(() => {
5099 const keysToUpdate = new Set();
5100
5101 for (const keys of [prev.atomValues.keys(), next.atomValues.keys()]) {
5102 for (const key of keys) {
5103 var _prev$atomValues$get, _next$atomValues$get;
5104
5105 if (((_prev$atomValues$get = prev.atomValues.get(key)) === null || _prev$atomValues$get === void 0 ? void 0 : _prev$atomValues$get.contents) !== ((_next$atomValues$get = next.atomValues.get(key)) === null || _next$atomValues$get === void 0 ? void 0 : _next$atomValues$get.contents) && getNode$4(key).shouldRestoreFromSnapshots) {
5106 keysToUpdate.add(key);
5107 }
5108 }
5109 }
5110
5111 keysToUpdate.forEach(key => {
5112 setRecoilValueLoadable$1(storeRef.current, new AbstractRecoilValue$3(key), next.atomValues.has(key) ? Recoil_nullthrows(next.atomValues.get(key)) : DEFAULT_VALUE$3);
5113 });
5114 storeRef.current.replaceState(state => {
5115 return { ...state,
5116 stateID: snapshot.getID_INTERNAL()
5117 };
5118 });
5119 });
5120 }, [storeRef]);
5121 }
5122
5123 function useSetUnvalidatedAtomValues() {
5124 const storeRef = useStoreRef$1();
5125 return (values, transactionMetadata = {}) => {
5126 batchUpdates$2(() => {
5127 storeRef.current.addTransactionMetadata(transactionMetadata);
5128 values.forEach((value, key) => setUnvalidatedRecoilValue$2(storeRef.current, new AbstractRecoilValue$3(key), value));
5129 });
5130 };
5131 }
5132
5133 class Sentinel {}
5134
5135 const SENTINEL = new Sentinel();
5136
5137 function useRecoilCallback(fn, deps) {
5138 const storeRef = useStoreRef$1();
5139 const gotoSnapshot = useGotoRecoilSnapshot();
5140 return useCallback$1((...args) => {
5141 function set(recoilState, newValueOrUpdater) {
5142 setRecoilValue$2(storeRef.current, recoilState, newValueOrUpdater);
5143 }
5144
5145 function reset(recoilState) {
5146 setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$3);
5147 } // Use currentTree for the snapshot to show the currently committed state
5148
5149
5150 const snapshot = cloneSnapshot$1(storeRef.current); // FIXME massive gains from doing this lazily
5151
5152 const atomicUpdate = atomicUpdater$1(storeRef.current);
5153 let ret = SENTINEL;
5154 batchUpdates$2(() => {
5155 const errMsg = 'useRecoilCallback expects a function that returns a function: ' + 'it accepts a function of the type (RecoilInterface) => T = R ' + 'and returns a callback function T => R, where RecoilInterface is an ' + 'object {snapshot, set, ...} and T and R are the argument and return ' + 'types of the callback you want to create. Please see the docs ' + 'at recoiljs.org for details.';
5156
5157 if (typeof fn !== 'function') {
5158 throw new Error(errMsg);
5159 } // flowlint-next-line unclear-type:off
5160
5161
5162 const cb = fn({
5163 set,
5164 reset,
5165 snapshot,
5166 gotoSnapshot,
5167 transact_UNSTABLE: atomicUpdate
5168 });
5169
5170 if (typeof cb !== 'function') {
5171 throw new Error(errMsg);
5172 }
5173
5174 ret = cb(...args);
5175 });
5176 !!(ret instanceof Sentinel) ? Recoil_invariant(false, 'batchUpdates should return immediately') : void 0;
5177 return ret;
5178 }, deps != null ? [...deps, storeRef] : undefined // eslint-disable-line fb-www/react-hooks-deps
5179 );
5180 } // I don't see a way to avoid the any type here because we want to accept readable
5181 // and writable values with any type parameter, but normally with writable ones
5182 // RecoilState<SomeT> is not a subtype of RecoilState<mixed>.
5183
5184
5185 // flowlint-line unclear-type:off
5186 function useRetain(toRetain) {
5187 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
5188 return;
5189 } // eslint-disable-next-line fb-www/react-hooks
5190
5191
5192 return useRetain_ACTUAL(toRetain);
5193 }
5194
5195 function useRetain_ACTUAL(toRetain) {
5196 const array = Array.isArray(toRetain) ? toRetain : [toRetain];
5197 const retainables = array.map(a => a instanceof RetentionZone$3 ? a : a.key);
5198 const storeRef = useStoreRef$1();
5199 useEffect$1(() => {
5200 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
5201 return;
5202 }
5203
5204 const store = storeRef.current;
5205
5206 if (timeoutID.current && !isSSR$2) {
5207 // Already performed a temporary retain on render, simply cancel the release
5208 // of that temporary retain.
5209 window.clearTimeout(timeoutID.current);
5210 timeoutID.current = null;
5211 } else {
5212 for (const r of retainables) {
5213 updateRetainCount$2(store, r, 1);
5214 }
5215 }
5216
5217 return () => {
5218 for (const r of retainables) {
5219 updateRetainCount$2(store, r, -1);
5220 }
5221 }; // eslint-disable-next-line fb-www/react-hooks-deps
5222 }, [storeRef, ...retainables]); // We want to retain if the component suspends. This is terrible but the Suspense
5223 // API affords us no better option. If we suspend and never commit after some
5224 // seconds, then release. The 'actual' retain/release in the effect above
5225 // cancels this.
5226
5227 const timeoutID = useRef$2();
5228 const previousRetainables = usePrevious(retainables);
5229
5230 if (!isSSR$2 && (previousRetainables === undefined || !Recoil_shallowArrayEqual(previousRetainables, retainables))) {
5231 const store = storeRef.current;
5232
5233 for (const r of retainables) {
5234 updateRetainCount$2(store, r, 1);
5235 }
5236
5237 if (previousRetainables) {
5238 for (const r of previousRetainables) {
5239 updateRetainCount$2(store, r, -1);
5240 }
5241 }
5242
5243 if (timeoutID.current) {
5244 window.clearTimeout(timeoutID.current);
5245 }
5246
5247 timeoutID.current = window.setTimeout(() => {
5248 timeoutID.current = null;
5249
5250 for (const r of retainables) {
5251 updateRetainCount$2(store, r, -1);
5252 }
5253 }, SUSPENSE_TIMEOUT_MS);
5254 }
5255 }
5256
5257 function useRecoilTransaction(fn, deps) {
5258 const storeRef = useStoreRef$1();
5259 return useMemo$1(() => (...args) => {
5260 const atomicUpdate = atomicUpdater$1(storeRef.current);
5261 atomicUpdate(transactionInterface => {
5262 fn(transactionInterface)(...args);
5263 });
5264 }, deps != null ? [...deps, storeRef] : undefined // eslint-disable-line fb-www/react-hooks-deps
5265 );
5266 }
5267
5268 var Recoil_Hooks = {
5269 recoilComponentGetRecoilValueCount_FOR_TESTING,
5270 useGotoRecoilSnapshot,
5271 useRecoilCallback,
5272 useRecoilInterface: useRecoilInterface_DEPRECATED,
5273 useRecoilSnapshot,
5274 useRecoilState,
5275 useRecoilStateLoadable,
5276 useRecoilTransaction,
5277 useRecoilTransactionObserver,
5278 useRecoilValue,
5279 useRecoilValueLoadable,
5280 useRetain,
5281 useResetRecoilState,
5282 useSetRecoilState,
5283 useSetUnvalidatedAtomValues,
5284 useTransactionObservation_DEPRECATED,
5285 useTransactionSubscription_DEPRECATED: useTransactionSubscription
5286 };
5287
5288 const {
5289 peekNodeInfo: peekNodeInfo$2
5290 } = Recoil_FunctionalCore;
5291
5292 const {
5293 useStoreRef: useStoreRef$2
5294 } = Recoil_RecoilRoot_react;
5295
5296 function useGetRecoilValueInfo() {
5297 const storeRef = useStoreRef$2();
5298 return ({
5299 key
5300 }) => peekNodeInfo$2(storeRef.current, storeRef.current.getState().currentTree, key);
5301 }
5302
5303 var Recoil_useGetRecoilValueInfo = useGetRecoilValueInfo;
5304
5305 const {
5306 RecoilRoot: RecoilRoot$1,
5307 useStoreRef: useStoreRef$3
5308 } = Recoil_RecoilRoot_react;
5309
5310
5311
5312 const {
5313 useMemo: useMemo$2
5314 } = react;
5315
5316 function useRecoilBridgeAcrossReactRoots() {
5317 const store = useStoreRef$3().current;
5318 return useMemo$2(() => {
5319 function RecoilBridge({
5320 children
5321 }) {
5322 return /*#__PURE__*/react.createElement(RecoilRoot$1, {
5323 store_INTERNAL: store
5324 }, children);
5325 }
5326
5327 return RecoilBridge;
5328 }, [store]);
5329 }
5330
5331 var Recoil_useRecoilBridgeAcrossReactRoots = useRecoilBridgeAcrossReactRoots;
5332
5333 /**
5334 * Copyright (c) Facebook, Inc. and its affiliates.
5335 *
5336 * This source code is licensed under the MIT license found in the
5337 * LICENSE file in the root directory of this source tree.
5338 *
5339 * @emails oncall+recoil
5340 *
5341 * @format
5342 */
5343
5344 function isNode(object) {
5345 var _ownerDocument, _doc$defaultView;
5346
5347 if (typeof window === 'undefined') {
5348 return false;
5349 }
5350
5351 const doc = object != null ? (_ownerDocument = object.ownerDocument) !== null && _ownerDocument !== void 0 ? _ownerDocument : object : document;
5352 const defaultView = (_doc$defaultView = doc.defaultView) !== null && _doc$defaultView !== void 0 ? _doc$defaultView : window;
5353 return !!(object != null && (typeof defaultView.Node === 'function' ? object instanceof defaultView.Node : typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string'));
5354 }
5355
5356 var Recoil_isNode = isNode;
5357
5358 const {
5359 isReactNative: isReactNative$1,
5360 isSSR: isSSR$3
5361 } = Recoil_Environment;
5362
5363
5364
5365
5366
5367 function shouldNotBeFrozen(value) {
5368 // Primitives and functions:
5369 if (value === null || typeof value !== 'object') {
5370 return true;
5371 } // React elements:
5372
5373
5374 switch (typeof value.$$typeof) {
5375 case 'symbol':
5376 return true;
5377
5378 case 'number':
5379 return true;
5380 } // Immutable structures:
5381
5382
5383 if (value['@@__IMMUTABLE_ITERABLE__@@'] != null || value['@@__IMMUTABLE_KEYED__@@'] != null || value['@@__IMMUTABLE_INDEXED__@@'] != null || value['@@__IMMUTABLE_ORDERED__@@'] != null || value['@@__IMMUTABLE_RECORD__@@'] != null) {
5384 return true;
5385 } // DOM nodes:
5386
5387
5388 if (Recoil_isNode(value)) {
5389 return true;
5390 }
5391
5392 if (Recoil_isPromise(value)) {
5393 return true;
5394 }
5395
5396 if (value instanceof Error) {
5397 return true;
5398 }
5399
5400 if (ArrayBuffer.isView(value)) {
5401 return true;
5402 } // Some environments, just as Jest, don't work with the instanceof check
5403
5404
5405 if (!isSSR$3 && !isReactNative$1 && ( // $FlowFixMe(site=recoil) Window does not have a FlowType definition https://github.com/facebook/flow/issues/6709
5406 value === window || value instanceof Window)) {
5407 return true;
5408 }
5409
5410 return false;
5411 } // Recursively freeze a value to enforce it is read-only.
5412 // This may also have minimal performance improvements for enumerating
5413 // objects (based on browser implementations, of course)
5414
5415
5416 function deepFreezeValue(value) {
5417 if (typeof value !== 'object' || shouldNotBeFrozen(value)) {
5418 return;
5419 }
5420
5421 Object.freeze(value); // Make all properties read-only
5422
5423 for (const key in value) {
5424 // $FlowFixMe[method-unbinding] added when improving typing for this parameters
5425 if (Object.prototype.hasOwnProperty.call(value, key)) {
5426 const prop = value[key]; // Prevent infinite recurssion for circular references.
5427
5428 if (typeof prop === 'object' && prop != null && !Object.isFrozen(prop)) {
5429 deepFreezeValue(prop);
5430 }
5431 }
5432 }
5433
5434 Object.seal(value); // This also makes existing properties non-configurable.
5435 }
5436
5437 var Recoil_deepFreezeValue = deepFreezeValue;
5438
5439 const TIME_WARNING_THRESHOLD_MS = 15;
5440
5441 function stringify(x, opt, key) {
5442 // A optimization to avoid the more expensive JSON.stringify() for simple strings
5443 // This may lose protection for u2028 and u2029, though.
5444 if (typeof x === 'string' && !x.includes('"') && !x.includes('\\')) {
5445 return `"${x}"`;
5446 } // Handle primitive types
5447
5448
5449 switch (typeof x) {
5450 case 'undefined':
5451 return '';
5452 // JSON.stringify(undefined) returns undefined, but we always want to return a string
5453
5454 case 'boolean':
5455 return x ? 'true' : 'false';
5456
5457 case 'number':
5458 case 'symbol':
5459 // case 'bigint': // BigInt is not supported in www
5460 return String(x);
5461
5462 case 'string':
5463 // Add surrounding quotes and escape internal quotes
5464 return JSON.stringify(x);
5465
5466 case 'function':
5467 if ((opt === null || opt === void 0 ? void 0 : opt.allowFunctions) !== true) {
5468 throw new Error('Attempt to serialize function in a Recoil cache key');
5469 }
5470
5471 return `__FUNCTION(${x.name})__`;
5472 }
5473
5474 if (x === null) {
5475 return 'null';
5476 } // Fallback case for unknown types
5477
5478
5479 if (typeof x !== 'object') {
5480 var _JSON$stringify;
5481
5482 return (_JSON$stringify = JSON.stringify(x)) !== null && _JSON$stringify !== void 0 ? _JSON$stringify : '';
5483 } // Deal with all promises as equivalent for now.
5484
5485
5486 if (Recoil_isPromise(x)) {
5487 return '__PROMISE__';
5488 } // Arrays handle recursive stringification
5489
5490
5491 if (Array.isArray(x)) {
5492 return `[${x.map((v, i) => stringify(v, opt, i.toString()))}]`;
5493 } // If an object defines a toJSON() method, then use that to override the
5494 // serialization. This matches the behavior of JSON.stringify().
5495 // Pass the key for compatibility.
5496 // Immutable.js collections define this method to allow us to serialize them.
5497
5498
5499 if (typeof x.toJSON === 'function') {
5500 // flowlint-next-line unclear-type: off
5501 return stringify(x.toJSON(key), opt, key);
5502 } // For built-in Maps, sort the keys in a stable order instead of the
5503 // default insertion order. Support non-string keys.
5504
5505
5506 if (x instanceof Map) {
5507 const obj = {};
5508
5509 for (const [k, v] of x) {
5510 // Stringify will escape any nested quotes
5511 obj[typeof k === 'string' ? k : stringify(k, opt)] = v;
5512 }
5513
5514 return stringify(obj, opt, key);
5515 } // For built-in Sets, sort the keys in a stable order instead of the
5516 // default insertion order.
5517
5518
5519 if (x instanceof Set) {
5520 return stringify(Array.from(x).sort((a, b) => stringify(a, opt).localeCompare(stringify(b, opt))), opt, key);
5521 } // Anything else that is iterable serialize as an Array.
5522
5523
5524 if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === 'function') {
5525 // flowlint-next-line unclear-type: off
5526 return stringify(Array.from(x), opt, key);
5527 } // For all other Objects, sort the keys in a stable order.
5528
5529
5530 return `{${Object.keys(x).filter(key => x[key] !== undefined).sort() // stringify the key to add quotes and escape any nested slashes or quotes.
5531 .map(key => `${stringify(key, opt)}:${stringify(x[key], opt, key)}`).join(',')}}`;
5532 } // Utility similar to JSON.stringify() except:
5533 // * Serialize built-in Sets as an Array
5534 // * Serialize built-in Maps as an Object. Supports non-string keys.
5535 // * Serialize other iterables as arrays
5536 // * Sort the keys of Objects and Maps to have a stable order based on string conversion.
5537 // This overrides their default insertion order.
5538 // * Still uses toJSON() of any object to override serialization
5539 // * Support Symbols (though don't guarantee uniqueness)
5540 // * We could support BigInt, but Flow doesn't seem to like it.
5541 // See Recoil_stableStringify-test.js for examples
5542
5543
5544 function stableStringify(x, opt = {
5545 allowFunctions: false
5546 }) {
5547 {
5548 if (typeof window !== 'undefined') {
5549 const startTime = window.performance ? window.performance.now() : 0;
5550 const str = stringify(x, opt);
5551 const endTime = window.performance ? window.performance.now() : 0;
5552
5553 if (endTime - startTime > TIME_WARNING_THRESHOLD_MS) {
5554 /* eslint-disable fb-www/no-console */
5555 console.groupCollapsed(`Recoil: Spent ${endTime - startTime}ms computing a cache key`);
5556 console.warn(x, str);
5557 console.groupEnd();
5558 /* eslint-enable fb-www/no-console */
5559 }
5560
5561 return str;
5562 }
5563 }
5564
5565 return stringify(x, opt);
5566 }
5567
5568 var Recoil_stableStringify = stableStringify;
5569
5570 class TreeCache {
5571 constructor(options) {
5572 var _options$onHit, _options$onSet, _options$mapNodeValue;
5573
5574 _defineProperty(this, "_numLeafs", void 0);
5575
5576 _defineProperty(this, "_root", void 0);
5577
5578 _defineProperty(this, "_onHit", void 0);
5579
5580 _defineProperty(this, "_onSet", void 0);
5581
5582 _defineProperty(this, "_mapNodeValue", void 0);
5583
5584 this._numLeafs = 0;
5585 this._root = null;
5586 this._onHit = (_options$onHit = options === null || options === void 0 ? void 0 : options.onHit) !== null && _options$onHit !== void 0 ? _options$onHit : () => {};
5587 this._onSet = (_options$onSet = options === null || options === void 0 ? void 0 : options.onSet) !== null && _options$onSet !== void 0 ? _options$onSet : () => {};
5588 this._mapNodeValue = (_options$mapNodeValue = options === null || options === void 0 ? void 0 : options.mapNodeValue) !== null && _options$mapNodeValue !== void 0 ? _options$mapNodeValue : val => val;
5589 }
5590
5591 size() {
5592 return this._numLeafs;
5593 } // TODO: nodeCount(): number
5594
5595
5596 root() {
5597 return this._root;
5598 }
5599
5600 get(getNodeValue, handlers) {
5601 var _this$getLeafNode;
5602
5603 return (_this$getLeafNode = this.getLeafNode(getNodeValue, handlers)) === null || _this$getLeafNode === void 0 ? void 0 : _this$getLeafNode.value;
5604 }
5605
5606 getLeafNode(getNodeValue, handlers) {
5607 return findLeaf(this.root(), nodeKey => this._mapNodeValue(getNodeValue(nodeKey)), {
5608 onNodeVisit: node => {
5609 handlers === null || handlers === void 0 ? void 0 : handlers.onNodeVisit(node);
5610
5611 if (node.type === 'leaf') {
5612 this._onHit(node);
5613 }
5614 }
5615 });
5616 }
5617
5618 set(route, value, handlers) {
5619 let leafNode;
5620 const newRoot = addLeaf(this.root(), route.map(([nodeKey, nodeValue]) => [nodeKey, this._mapNodeValue(nodeValue)]), null, value, null, {
5621 onNodeVisit: node => {
5622 handlers === null || handlers === void 0 ? void 0 : handlers.onNodeVisit(node);
5623
5624 if (node.type === 'leaf') {
5625 leafNode = node;
5626 }
5627 }
5628 });
5629
5630 if (!this.root()) {
5631 this._root = newRoot;
5632 }
5633
5634 this._numLeafs++;
5635
5636 this._onSet(Recoil_nullthrows(leafNode));
5637 }
5638
5639 delete(node) {
5640 if (!this.root()) {
5641 return false;
5642 }
5643
5644 const root = Recoil_nullthrows(this.root());
5645 const existsInTree = pruneNodeFromTree(root, node, node.parent);
5646
5647 if (!existsInTree) {
5648 return false;
5649 }
5650
5651 if (node === root || root.type === 'branch' && !root.branches.size) {
5652 this._root = null;
5653 this._numLeafs = 0;
5654 return true;
5655 }
5656
5657 this._numLeafs -= countDownstreamLeaves(node);
5658 return true;
5659 }
5660
5661 clear() {
5662 this._numLeafs = 0;
5663 this._root = null;
5664 }
5665
5666 }
5667
5668 const findLeaf = (root, getNodeValue, handlers) => {
5669 var _handlers$onNodeVisit;
5670
5671 if (root == null) {
5672 return undefined;
5673 }
5674
5675 handlers === null || handlers === void 0 ? void 0 : (_handlers$onNodeVisit = handlers.onNodeVisit) === null || _handlers$onNodeVisit === void 0 ? void 0 : _handlers$onNodeVisit.call(handlers, root);
5676
5677 if (root.type === 'leaf') {
5678 return root;
5679 }
5680
5681 const nodeValue = getNodeValue(root.nodeKey);
5682 return findLeaf(root.branches.get(nodeValue), getNodeValue, handlers);
5683 };
5684
5685 const addLeaf = (root, route, parent, value, branchKey, handlers) => {
5686 var _handlers$onNodeVisit2;
5687
5688 let node;
5689
5690 if (root == null) {
5691 if (route.length === 0) {
5692 node = {
5693 type: 'leaf',
5694 value,
5695 parent,
5696 branchKey
5697 };
5698 } else {
5699 const [path, ...rest] = route;
5700 const [nodeKey, nodeValue] = path;
5701 node = {
5702 type: 'branch',
5703 nodeKey,
5704 parent,
5705 branches: new Map(),
5706 branchKey
5707 };
5708 node.branches.set(nodeValue, addLeaf(null, rest, node, value, nodeValue, handlers));
5709 }
5710 } else {
5711 node = root;
5712
5713 if (route.length) {
5714 const [path, ...rest] = route;
5715 const [nodeKey, nodeValue] = path;
5716 !(root.type === 'branch' && root.nodeKey === nodeKey) ? Recoil_invariant(false, 'Existing cache must have a branch midway through the route with matching node key') : void 0;
5717 root.branches.set(nodeValue, addLeaf(root.branches.get(nodeValue), rest, root, value, nodeValue, handlers));
5718 }
5719 }
5720
5721 handlers === null || handlers === void 0 ? void 0 : (_handlers$onNodeVisit2 = handlers.onNodeVisit) === null || _handlers$onNodeVisit2 === void 0 ? void 0 : _handlers$onNodeVisit2.call(handlers, node);
5722 return node;
5723 };
5724
5725 const pruneNodeFromTree = (root, node, parent) => {
5726 if (!parent) {
5727 return root === node;
5728 }
5729
5730 parent.branches.delete(node.branchKey);
5731 return pruneUpstreamBranches(root, parent, parent.parent);
5732 };
5733
5734 const pruneUpstreamBranches = (root, branchNode, parent) => {
5735 if (!parent) {
5736 return root === branchNode;
5737 }
5738
5739 if (branchNode.branches.size === 0) {
5740 parent.branches.delete(branchNode.branchKey);
5741 }
5742
5743 return pruneUpstreamBranches(root, parent, parent.parent);
5744 };
5745
5746 const countDownstreamLeaves = node => node.type === 'leaf' ? 1 : Array.from(node.branches.values()).reduce((sum, currNode) => sum + countDownstreamLeaves(currNode), 0);
5747
5748 var Recoil_TreeCache = {
5749 TreeCache
5750 };
5751
5752 var Recoil_TreeCache_1 = Recoil_TreeCache.TreeCache;
5753
5754 var Recoil_TreeCache$1 = /*#__PURE__*/Object.freeze({
5755 __proto__: null,
5756 TreeCache: Recoil_TreeCache_1
5757 });
5758
5759 class LRUCache {
5760 constructor(options) {
5761 var _options$mapKey;
5762
5763 _defineProperty(this, "_maxSize", void 0);
5764
5765 _defineProperty(this, "_size", void 0);
5766
5767 _defineProperty(this, "_head", void 0);
5768
5769 _defineProperty(this, "_tail", void 0);
5770
5771 _defineProperty(this, "_map", void 0);
5772
5773 _defineProperty(this, "_keyMapper", void 0);
5774
5775 this._maxSize = options.maxSize;
5776 this._size = 0;
5777 this._head = null;
5778 this._tail = null;
5779 this._map = new Map();
5780 this._keyMapper = (_options$mapKey = options.mapKey) !== null && _options$mapKey !== void 0 ? _options$mapKey : v => v;
5781 }
5782
5783 head() {
5784 return this._head;
5785 }
5786
5787 tail() {
5788 return this._tail;
5789 }
5790
5791 size() {
5792 return this._size;
5793 }
5794
5795 maxSize() {
5796 return this._maxSize;
5797 }
5798
5799 has(key) {
5800 return this._map.has(this._keyMapper(key));
5801 }
5802
5803 get(key) {
5804 const mappedKey = this._keyMapper(key);
5805
5806 const node = this._map.get(mappedKey);
5807
5808 if (!node) {
5809 return undefined;
5810 }
5811
5812 this.set(key, node.value);
5813 return node.value;
5814 }
5815
5816 set(key, val) {
5817 const mappedKey = this._keyMapper(key);
5818
5819 const existingNode = this._map.get(mappedKey);
5820
5821 if (existingNode) {
5822 this.delete(key);
5823 }
5824
5825 const head = this.head();
5826 const node = {
5827 key,
5828 right: head,
5829 left: null,
5830 value: val
5831 };
5832
5833 if (head) {
5834 head.left = node;
5835 } else {
5836 this._tail = node;
5837 }
5838
5839 this._map.set(mappedKey, node);
5840
5841 this._head = node;
5842 this._size++;
5843
5844 this._maybeDeleteLRU();
5845 }
5846
5847 _maybeDeleteLRU() {
5848 if (this.size() > this.maxSize()) {
5849 this.deleteLru();
5850 }
5851 }
5852
5853 deleteLru() {
5854 const tail = this.tail();
5855
5856 if (tail) {
5857 this.delete(tail.key);
5858 }
5859 }
5860
5861 delete(key) {
5862 const mappedKey = this._keyMapper(key);
5863
5864 if (!this._size || !this._map.has(mappedKey)) {
5865 return;
5866 }
5867
5868 const node = Recoil_nullthrows(this._map.get(mappedKey));
5869 const right = node.right;
5870 const left = node.left;
5871
5872 if (right) {
5873 right.left = node.left;
5874 }
5875
5876 if (left) {
5877 left.right = node.right;
5878 }
5879
5880 if (node === this.head()) {
5881 this._head = right;
5882 }
5883
5884 if (node === this.tail()) {
5885 this._tail = left;
5886 }
5887
5888 this._map.delete(mappedKey);
5889
5890 this._size--;
5891 }
5892
5893 clear() {
5894 this._size = 0;
5895 this._head = null;
5896 this._tail = null;
5897 this._map = new Map();
5898 }
5899
5900 }
5901
5902 var Recoil_LRUCache = {
5903 LRUCache
5904 };
5905
5906 var Recoil_LRUCache_1 = Recoil_LRUCache.LRUCache;
5907
5908 var Recoil_LRUCache$1 = /*#__PURE__*/Object.freeze({
5909 __proto__: null,
5910 LRUCache: Recoil_LRUCache_1
5911 });
5912
5913 const {
5914 LRUCache: LRUCache$1
5915 } = Recoil_LRUCache$1;
5916
5917 const {
5918 TreeCache: TreeCache$1
5919 } = Recoil_TreeCache$1;
5920
5921 function treeCacheLRU(maxSize, mapNodeValue = v => v) {
5922 const lruCache = new LRUCache$1({
5923 maxSize
5924 });
5925 const cache = new TreeCache$1({
5926 mapNodeValue,
5927 onHit: node => {
5928 lruCache.set(node, true);
5929 },
5930 onSet: node => {
5931 const lruNode = lruCache.tail();
5932 lruCache.set(node, true);
5933
5934 if (lruNode && cache.size() > maxSize) {
5935 cache.delete(lruNode.key);
5936 }
5937 }
5938 }); // $FlowFixMe[method-unbinding]
5939
5940 return cache;
5941 }
5942
5943 var Recoil_treeCacheLRU = treeCacheLRU;
5944
5945 const {
5946 TreeCache: TreeCache$2
5947 } = Recoil_TreeCache$1;
5948
5949
5950
5951 const defaultPolicy = {
5952 equality: 'reference',
5953 eviction: 'keep-all',
5954 maxSize: Infinity
5955 };
5956
5957 function treeCacheFromPolicy({
5958 equality = defaultPolicy.equality,
5959 eviction = defaultPolicy.eviction,
5960 maxSize = defaultPolicy.maxSize
5961 } = defaultPolicy) {
5962 const valueMapper = getValueMapper(equality);
5963 const treeCache = getTreeCache(eviction, maxSize, valueMapper);
5964 return treeCache;
5965 }
5966
5967 function getValueMapper(equality) {
5968 switch (equality) {
5969 case 'reference':
5970 return val => val;
5971
5972 case 'value':
5973 return val => Recoil_stableStringify(val);
5974 }
5975
5976 throw new Error(`Unrecognized equality policy ${equality}`);
5977 }
5978
5979 function getTreeCache(eviction, maxSize, mapNodeValue) {
5980 switch (eviction) {
5981 case 'keep-all':
5982 // $FlowFixMe[method-unbinding]
5983 return new TreeCache$2({
5984 mapNodeValue
5985 });
5986
5987 case 'lru':
5988 return Recoil_treeCacheLRU(Recoil_nullthrows(maxSize), mapNodeValue);
5989
5990 case 'most-recent':
5991 return Recoil_treeCacheLRU(1, mapNodeValue);
5992 }
5993
5994 throw new Error(`Unrecognized eviction policy ${eviction}`);
5995 }
5996
5997 var Recoil_treeCacheFromPolicy = treeCacheFromPolicy;
5998
5999 /**
6000 * Copyright (c) Facebook, Inc. and its affiliates.
6001 *
6002 * This source code is licensed under the MIT license found in the
6003 * LICENSE file in the root directory of this source tree.
6004 *
6005 * @emails oncall+recoil
6006 *
6007 * @format
6008 *
6009 * This is a stub for some integration into FB internal stuff
6010 */
6011 function startPerfBlock(_id) {
6012 return () => null;
6013 }
6014
6015 var Recoil_PerformanceTimings = {
6016 startPerfBlock
6017 };
6018
6019 const {
6020 CANCELED: CANCELED$2,
6021 Canceled: Canceled$1,
6022 loadableWithError: loadableWithError$1,
6023 loadableWithPromise: loadableWithPromise$1,
6024 loadableWithValue: loadableWithValue$2
6025 } = Recoil_Loadable;
6026
6027
6028
6029 const {
6030 getNodeLoadable: getNodeLoadable$2,
6031 peekNodeLoadable: peekNodeLoadable$1,
6032 setNodeValue: setNodeValue$3
6033 } = Recoil_FunctionalCore;
6034
6035 const {
6036 saveDependencyMapToStore: saveDependencyMapToStore$1
6037 } = Recoil_Graph;
6038
6039 const {
6040 DEFAULT_VALUE: DEFAULT_VALUE$4,
6041 RecoilValueNotReady: RecoilValueNotReady$2,
6042 getConfigDeletionHandler: getConfigDeletionHandler$1,
6043 registerNode: registerNode$1
6044 } = Recoil_Node;
6045
6046 const {
6047 isRecoilValue: isRecoilValue$3
6048 } = Recoil_RecoilValue$1;
6049
6050 const {
6051 AbstractRecoilValue: AbstractRecoilValue$4
6052 } = Recoil_RecoilValue$1;
6053
6054 const {
6055 setRecoilValueLoadable: setRecoilValueLoadable$2
6056 } = Recoil_RecoilValueInterface;
6057
6058 const {
6059 retainedByOptionWithDefault: retainedByOptionWithDefault$1
6060 } = Recoil_Retention;
6061
6062 const {
6063 cloneSnapshot: cloneSnapshot$2
6064 } = Recoil_Snapshot$1;
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076 const {
6077 startPerfBlock: startPerfBlock$1
6078 } = Recoil_PerformanceTimings;
6079
6080
6081
6082 const dependencyStack = []; // for detecting circular dependencies.
6083
6084 const waitingStores = new Map();
6085 /* eslint-disable no-redeclare */
6086
6087 const getNewExecutionId = (() => {
6088 let executionId = 0;
6089 return () => executionId++;
6090 })();
6091
6092 function getInitialExecutionInfo() {
6093 return {
6094 depValuesDiscoveredSoFarDuringAsyncWork: null,
6095 latestLoadable: null,
6096 latestExecutionId: null,
6097 stateVersion: null
6098 };
6099 }
6100
6101 function selector(options) {
6102 const {
6103 key,
6104 get,
6105 cachePolicy_UNSTABLE: cachePolicy
6106 } = options;
6107 const set = options.set != null ? options.set : undefined; // flow
6108
6109 const cache = Recoil_treeCacheFromPolicy(cachePolicy !== null && cachePolicy !== void 0 ? cachePolicy : {
6110 equality: 'reference',
6111 eviction: 'keep-all'
6112 });
6113 const retainedBy = retainedByOptionWithDefault$1(options.retainedBy_UNSTABLE);
6114 const executionInfoMap = new Map();
6115 let liveStoresCount = 0;
6116
6117 function selectorIsLive() {
6118 return !Recoil_gkx_1('recoil_memory_managament_2020') || liveStoresCount > 0;
6119 }
6120
6121 function getExecutionInfo(store) {
6122 if (!executionInfoMap.has(store)) {
6123 executionInfoMap.set(store, getInitialExecutionInfo());
6124 }
6125
6126 return Recoil_nullthrows(executionInfoMap.get(store));
6127 }
6128
6129 function selectorInit(store) {
6130 liveStoresCount++;
6131 store.getState().knownSelectors.add(key); // FIXME remove knownSelectors?
6132
6133 return () => {
6134 liveStoresCount--;
6135 store.getState().knownSelectors.delete(key);
6136 executionInfoMap.delete(store);
6137 };
6138 }
6139
6140 function selectorShouldDeleteConfigOnRelease() {
6141 return getConfigDeletionHandler$1(key) !== undefined && !selectorIsLive();
6142 }
6143
6144 function notifyStoreWhenAsyncSettles(store, loadable, executionId) {
6145 if (loadable.state === 'loading') {
6146 let stores = waitingStores.get(executionId);
6147
6148 if (stores == null) {
6149 waitingStores.set(executionId, stores = new Set());
6150 }
6151
6152 stores.add(store);
6153 }
6154 }
6155
6156 function notifyStoresOfSettledAsync(newLoadable, executionId) {
6157 const stores = waitingStores.get(executionId);
6158
6159 if (stores !== undefined) {
6160 for (const store of stores) {
6161 setRecoilValueLoadable$2(store, new AbstractRecoilValue$4(key), newLoadable);
6162 }
6163
6164 waitingStores.delete(executionId);
6165 }
6166 }
6167
6168 function getCachedNodeLoadable(store, state, key) {
6169 const isKeyPointingToSelector = store.getState().knownSelectors.has(key);
6170 /**
6171 * It's important that we don't bypass calling getNodeLoadable for atoms
6172 * as getNodeLoadable has side effects in state
6173 */
6174
6175 if (isKeyPointingToSelector && state.atomValues.has(key)) {
6176 return Recoil_nullthrows(state.atomValues.get(key));
6177 }
6178
6179 const loadable = getNodeLoadable$2(store, state, key);
6180
6181 if (loadable.state !== 'loading' && isKeyPointingToSelector) {
6182 state.atomValues.set(key, loadable);
6183 }
6184
6185 return loadable;
6186 }
6187 /**
6188 * This function attaches a then() and a catch() to a promise that was
6189 * returned from a selector's get() (either explicitly or implicitly by
6190 * running a function that uses the "async" keyword). If a selector's get()
6191 * returns a promise, we have two possibilities:
6192 *
6193 * 1. The promise will resolve, in which case it will have completely finished
6194 * executing without any remaining pending dependencies. No more retries
6195 * are needed and we can proceed with updating the cache and notifying
6196 * subscribers (if it is the latest execution, otherwise only the cache
6197 * will be updated and subscriptions will not be fired). This is the case
6198 * handled by the attached then() handler.
6199 *
6200 * 2. The promise will throw because it either has an error or it came across
6201 * an async dependency that has not yet resolved, in which case we will
6202 * call wrapDepdencyPromise(), whose responsibility is to handle dependency
6203 * promises. This case is handled by the attached catch() handler.
6204 *
6205 * Both branches will eventually resolve to the final result of the selector
6206 * (or an error if a real error occurred).
6207 *
6208 * The execution will run to completion even if it is stale, and its value
6209 * will be cached. But stale executions will not update global state or update
6210 * executionInfo as that is the responsibility of the 'latest' execution.
6211 *
6212 * Note this function should not be passed a promise that was thrown--AKA a
6213 * dependency promise. Dependency promises should be passed to
6214 * wrapPendingDependencyPromise()).
6215 */
6216
6217
6218 function wrapPendingPromise(store, promise, state, depValues, executionId) {
6219 return promise.then(value => {
6220 if (!selectorIsLive()) {
6221 // The selector was released since the request began; ignore the response.
6222 clearExecutionInfo(store, executionId);
6223 return CANCELED$2;
6224 }
6225
6226 const loadable = loadableWithValue$2(value);
6227 maybeFreezeValue(value);
6228 setCache(state, depValuesToDepRoute(depValues), loadable);
6229 setDepsInStore(store, state, new Set(depValues.keys()), executionId);
6230 setLoadableInStoreToNotifyDeps(store, loadable, executionId);
6231 return {
6232 __value: value,
6233 __key: key
6234 };
6235 }).catch(errorOrPromise => {
6236 if (!selectorIsLive()) {
6237 // The selector was released since the request began; ignore the response.
6238 clearExecutionInfo(store, executionId);
6239 return CANCELED$2;
6240 }
6241
6242 if (isLatestExecution(store, executionId)) {
6243 updateExecutionInfoDepValues(depValues, store, executionId);
6244 }
6245
6246 if (Recoil_isPromise(errorOrPromise)) {
6247 return wrapPendingDependencyPromise(store, errorOrPromise, state, depValues, executionId);
6248 }
6249
6250 const loadable = loadableWithError$1(errorOrPromise);
6251 maybeFreezeValue(errorOrPromise);
6252 setCache(state, depValuesToDepRoute(depValues), loadable);
6253 setDepsInStore(store, state, new Set(depValues.keys()), executionId);
6254 setLoadableInStoreToNotifyDeps(store, loadable, executionId);
6255 throw errorOrPromise;
6256 });
6257 }
6258 /**
6259 * This function attaches a then() and a catch() to a promise that was
6260 * thrown from a selector's get(). If a selector's get() throws a promise,
6261 * we have two possibilities:
6262 *
6263 * 1. The promise will resolve, meaning one of our selector's dependencies is
6264 * now available and we should "retry" our get() by running it again. This
6265 * is the case handled by the attached then() handler.
6266 *
6267 * 2. The promise will throw because something went wrong with the dependency
6268 * promise (in other words a real error occurred). This case is handled by
6269 * the attached catch() handler. If the dependency promise throws, it is
6270 * _always_ a real error and not another dependency promise (any dependency
6271 * promises would have been handled upstream).
6272 *
6273 * The then() branch will eventually resolve to the final result of the
6274 * selector (or an error if a real error occurs), and the catch() will always
6275 * resolve to an error because the dependency promise is a promise that was
6276 * wrapped upstream, meaning it will only resolve to its real value or to a
6277 * real error.
6278 *
6279 * The execution will run to completion even if it is stale, and its value
6280 * will be cached. But stale executions will not update global state or update
6281 * executionInfo as that is the responsibility of the 'latest' execution.
6282 *
6283 * Note this function should not be passed a promise that was returned from
6284 * get(). The intention is that this function is only passed promises that
6285 * were thrown due to a pending dependency. Promises returned by get() should
6286 * be passed to wrapPendingPromise() instead.
6287 */
6288
6289
6290 function wrapPendingDependencyPromise(store, promise, state, existingDeps, executionId) {
6291 return promise.then(resolvedDep => {
6292 if (!selectorIsLive()) {
6293 // The selector was released since the request began; ignore the response.
6294 clearExecutionInfo(store, executionId);
6295 return CANCELED$2;
6296 }
6297
6298 if (resolvedDep instanceof Canceled$1) {
6299 Recoil_recoverableViolation('Selector was released while it had dependencies');
6300 return CANCELED$2;
6301 }
6302
6303 const {
6304 __key: resolvedDepKey,
6305 __value: depValue
6306 } = resolvedDep !== null && resolvedDep !== void 0 ? resolvedDep : {};
6307 /**
6308 * We need to bypass the selector dep cache if the resolved dep was a
6309 * user-thrown promise because the selector dep cache will contain the
6310 * stale values of dependencies, causing an infinite evaluation loop.
6311 */
6312
6313 let bypassSelectorDepCacheOnReevaluation = true;
6314
6315 if (resolvedDepKey != null) {
6316 /**
6317 * Note for async atoms, this means we are changing the atom's value
6318 * in the store for the given version. This should be alright because
6319 * the version of state is now stale and a new version will have
6320 * already been triggered by the atom being resolved (see this logic
6321 * in Recoil_atom.js)
6322 */
6323 state.atomValues.set(resolvedDepKey, loadableWithValue$2(depValue));
6324 /**
6325 * We've added the resolved dependency to the selector dep cache, so
6326 * there's no need to bypass the cache
6327 */
6328
6329 bypassSelectorDepCacheOnReevaluation = false;
6330 }
6331 /**
6332 * Optimization: Now that the dependency has resolved, let's try hitting
6333 * the cache in case the dep resolved to a value we have previously seen.
6334 *
6335 * TODO:
6336 * Note this optimization is not perfect because it only prevents re-executions
6337 * _after_ the point where an async dependency is found. Any code leading
6338 * up to the async dependency may have run unnecessarily. The ideal case
6339 * would be to wait for the async dependency to resolve first, check the
6340 * cache, and prevent _any_ execution of the selector if the resulting
6341 * value of the dependency leads to a path that is found in the cache.
6342 * The ideal case is more difficult to implement as it would require that
6343 * we capture and wait for the the async dependency right after checking
6344 * the cache. The current approach takes advantage of the fact that running
6345 * the selector already has a code path that lets use exit early when
6346 * an async dep resolves.
6347 */
6348
6349
6350 const cachedLoadable = getValFromCacheAndUpdatedDownstreamDeps(store, state);
6351
6352 if (cachedLoadable && cachedLoadable.state === 'hasValue') {
6353 setExecutionInfo(cachedLoadable, store);
6354 return {
6355 __value: cachedLoadable.contents,
6356 __key: key
6357 };
6358 }
6359
6360 const [loadable, depValues] = evaluateSelectorGetter(store, state, executionId, bypassSelectorDepCacheOnReevaluation);
6361
6362 if (isLatestExecution(store, executionId)) {
6363 updateExecutionInfoDepValues(depValues, store, executionId);
6364 }
6365
6366 maybeFreezeLoadableContents(loadable);
6367
6368 if (loadable.state !== 'loading') {
6369 setCache(state, depValuesToDepRoute(depValues), loadable);
6370 setDepsInStore(store, state, new Set(depValues.keys()), executionId);
6371 setLoadableInStoreToNotifyDeps(store, loadable, executionId);
6372 }
6373
6374 if (loadable.state === 'hasError') {
6375 throw loadable.contents;
6376 }
6377
6378 if (loadable.state === 'hasValue') {
6379 return {
6380 __value: loadable.contents,
6381 __key: key
6382 };
6383 }
6384 /**
6385 * Returning promise here without wrapping as the wrapepr logic was
6386 * already done when we called evaluateSelectorGetter() to get this
6387 * loadable
6388 */
6389
6390
6391 return loadable.contents;
6392 }).catch(error => {
6393 if (!selectorIsLive()) {
6394 // The selector was released since the request began; ignore the response.
6395 clearExecutionInfo(store, executionId);
6396 return CANCELED$2;
6397 }
6398
6399 const loadable = loadableWithError$1(error);
6400 maybeFreezeValue(error);
6401 setCache(state, depValuesToDepRoute(existingDeps), loadableWithError$1(error));
6402 setDepsInStore(store, state, new Set(existingDeps.keys()), executionId);
6403 setLoadableInStoreToNotifyDeps(store, loadable, executionId);
6404 throw error;
6405 });
6406 }
6407
6408 function setLoadableInStoreToNotifyDeps(store, loadable, executionId) {
6409 if (isLatestExecution(store, executionId)) {
6410 setExecutionInfo(loadable, store);
6411 notifyStoresOfSettledAsync(loadable, executionId);
6412 }
6413 }
6414
6415 function setDepsInStore(store, state, deps, executionId) {
6416 var _store$getState, _store$getState$curre, _store$getState2, _store$getState2$next;
6417
6418 if (isLatestExecution(store, executionId) || state.version === ((_store$getState = store.getState()) === null || _store$getState === void 0 ? void 0 : (_store$getState$curre = _store$getState.currentTree) === null || _store$getState$curre === void 0 ? void 0 : _store$getState$curre.version) || state.version === ((_store$getState2 = store.getState()) === null || _store$getState2 === void 0 ? void 0 : (_store$getState2$next = _store$getState2.nextTree) === null || _store$getState2$next === void 0 ? void 0 : _store$getState2$next.version)) {
6419 var _store$getState$nextT, _store$getState3, _store$getState3$next;
6420
6421 saveDependencyMapToStore$1(new Map([[key, deps]]), store, (_store$getState$nextT = (_store$getState3 = store.getState()) === null || _store$getState3 === void 0 ? void 0 : (_store$getState3$next = _store$getState3.nextTree) === null || _store$getState3$next === void 0 ? void 0 : _store$getState3$next.version) !== null && _store$getState$nextT !== void 0 ? _store$getState$nextT : store.getState().currentTree.version);
6422 }
6423 }
6424
6425 function setNewDepInStore(store, state, deps, newDepKey, executionId) {
6426 deps.add(newDepKey);
6427 setDepsInStore(store, state, deps, executionId);
6428 }
6429
6430 function evaluateSelectorGetter(store, state, executionId, bypassSelectorDepCache = false) {
6431 const endPerfBlock = startPerfBlock$1(key); // TODO T63965866: use execution ID here
6432
6433 let result;
6434 let resultIsError = false;
6435 let loadable;
6436 const depValues = new Map();
6437 /**
6438 * Starting a fresh set of deps that we'll be using to update state. We're
6439 * starting a new set versus adding it in existing state deps because
6440 * the version of state that we update deps for may be a more recent version
6441 * than the version the selector was called with. This is because the latest
6442 * execution will update the deps of the current/latest version of state (
6443 * this is safe to do because the fact that the selector is the latest
6444 * execution means the deps we discover below are our best guess at the
6445 * deps for the current/latest state in the store)
6446 */
6447
6448 const deps = new Set();
6449 setDepsInStore(store, state, deps, executionId);
6450
6451 function getRecoilValue(recoilValue) {
6452 const {
6453 key: depKey
6454 } = recoilValue;
6455 setNewDepInStore(store, state, deps, depKey, executionId);
6456 const depLoadable = bypassSelectorDepCache ? getNodeLoadable$2(store, state, depKey) : getCachedNodeLoadable(store, state, depKey);
6457 maybeFreezeLoadableContents(depLoadable);
6458 depValues.set(depKey, depLoadable);
6459
6460 if (depLoadable.state === 'hasValue') {
6461 return depLoadable.contents;
6462 }
6463
6464 throw depLoadable.contents;
6465 }
6466
6467 let gateCallback = false;
6468
6469 const getCallback = fn => {
6470 return (...args) => {
6471 if (!gateCallback) {
6472 throw new Error('getCallback() should only be called asynchronously after the selector is evalutated. It can be used for selectors to return objects with callbacks that can obtain the current Recoil state without a subscription.');
6473 }
6474
6475 const snapshot = cloneSnapshot$2(store);
6476 const cb = fn({
6477 snapshot
6478 });
6479
6480 if (typeof cb !== 'function') {
6481 throw new Error('getCallback() expects a function that returns a function.');
6482 }
6483
6484 return cb(...args);
6485 };
6486 };
6487
6488 try {
6489 result = get({
6490 get: getRecoilValue,
6491 getCallback
6492 });
6493 result = isRecoilValue$3(result) ? getRecoilValue(result) : result;
6494 gateCallback = true;
6495
6496 if (Recoil_isPromise(result)) {
6497 result = wrapPendingPromise(store, result, state, depValues, executionId).finally(endPerfBlock);
6498 } else {
6499 endPerfBlock();
6500 }
6501 } catch (errorOrDepPromise) {
6502 result = errorOrDepPromise;
6503
6504 if (Recoil_isPromise(result)) {
6505 result = wrapPendingDependencyPromise(store, result, state, depValues, executionId).finally(endPerfBlock);
6506 } else {
6507 resultIsError = true;
6508 endPerfBlock();
6509 }
6510 }
6511
6512 if (resultIsError) {
6513 loadable = loadableWithError$1(result);
6514 } else if (Recoil_isPromise(result)) {
6515 loadable = loadableWithPromise$1(result);
6516 } else {
6517 loadable = loadableWithValue$2(result);
6518 }
6519
6520 maybeFreezeLoadableContents(loadable);
6521 return [loadable, depValues];
6522 }
6523
6524 function getValFromCacheAndUpdatedDownstreamDeps(store, state) {
6525 const depsAfterCacheDone = new Set();
6526 const executionInfo = getExecutionInfo(store);
6527 const cachedVal = cache.get(nodeKey => {
6528 !(typeof nodeKey === 'string') ? Recoil_invariant(false, 'Cache nodeKey is type string') : void 0;
6529 const loadable = getCachedNodeLoadable(store, state, nodeKey);
6530 return loadable.contents;
6531 }, {
6532 onNodeVisit: node => {
6533 if (node.type === 'branch' && node.nodeKey !== key && typeof node.nodeKey === 'string') {
6534 depsAfterCacheDone.add(node.nodeKey);
6535 }
6536 }
6537 });
6538 /**
6539 * Ensure store contains correct dependencies if we hit the cache so that
6540 * the store deps and cache are in sync for a given state. This is important
6541 * because store deps are normally updated when new executions are created,
6542 * but cache hits don't trigger new executions but they still _may_ signifiy
6543 * a change in deps in the store if the store deps for this state are empty
6544 * or stale.
6545 */
6546
6547 if (cachedVal) {
6548 setDepsInStore(store, state, depsAfterCacheDone, executionInfo.latestExecutionId);
6549 }
6550
6551 return cachedVal;
6552 }
6553 /**
6554 * FIXME: dep keys should take into account the state of the loadable to
6555 * prevent the edge case where a loadable with an error and a loadable with
6556 * an error as a value are treated as the same thing incorrectly. For example
6557 * these two should be treated differently:
6558 *
6559 * selector({key: '', get: () => new Error('hi')});
6560 * selector({key: '', get () => {throw new Error('hi')}});
6561 *
6562 * With current implementation they are treated the same
6563 */
6564
6565
6566 function depValuesToDepRoute(depValues) {
6567 return Array.from(depValues.entries()).map(([key, valLoadable]) => [key, valLoadable.contents]);
6568 }
6569
6570 function getValFromRunningNewExecutionAndUpdatedDeps(store, state) {
6571 const newExecutionId = getNewExecutionId();
6572 const [loadable, newDepValues] = evaluateSelectorGetter(store, state, newExecutionId);
6573 setExecutionInfo(loadable, store, newDepValues, newExecutionId, state);
6574 maybeSetCacheWithLoadable(state, depValuesToDepRoute(newDepValues), loadable);
6575 notifyStoreWhenAsyncSettles(store, loadable, newExecutionId);
6576 return loadable;
6577 }
6578 /**
6579 * Given a tree state, this function returns the "selector result", which is
6580 * defined as a size-2 tuple of [DependencyMap, Loadable<T>].
6581 *
6582 * The selector's get() function will only be re-evaluated if _both_ of the
6583 * following statements are true:
6584 *
6585 * 1. The current dep values from the given state produced a cache key that
6586 * was not found in the cache.
6587 * 2. There is no currently running async execution OR there is an
6588 * async execution that is running, but after comparing the dep values in
6589 * the given state with the dep values that the execution has discovered so
6590 * far we find that at least one dep value has changed, in which case we
6591 * start a new execution (the previously running execution will continue to
6592 * run to completion, but only the new execution will be deemed the
6593 * 'latest' execution, meaning it will be the only execution that will
6594 * update global state when it is finished. Any non-latest executions will
6595 * run to completion and update the selector cache but not global state).
6596 */
6597
6598
6599 function getSelectorValAndUpdatedDeps(store, state) {
6600 const cachedVal = getValFromCacheAndUpdatedDownstreamDeps(store, state);
6601
6602 if (cachedVal != null) {
6603 setExecutionInfo(cachedVal, store);
6604 return cachedVal;
6605 }
6606
6607 const inProgressExecutionInfo = getExecutionInfoOfInProgressExecution(store, state); // FIXME: this won't work with custom caching b/c it uses separate cache
6608
6609 if (inProgressExecutionInfo) {
6610 const executionInfo = inProgressExecutionInfo;
6611 notifyStoreWhenAsyncSettles(store, Recoil_nullthrows(executionInfo.latestLoadable), Recoil_nullthrows(executionInfo.latestExecutionId)); // FIXME: check after the fact to see if we made the right choice by waiting
6612
6613 return Recoil_nullthrows(executionInfo.latestLoadable);
6614 }
6615
6616 return getValFromRunningNewExecutionAndUpdatedDeps(store, state);
6617 }
6618 /**
6619 * Searches execution info across all stores to see if there is an in-progress
6620 * execution whose dependency values match the values of the requesting store.
6621 */
6622
6623
6624 function getExecutionInfoOfInProgressExecution(store, state) {
6625 var _Array$from$find;
6626
6627 const [, executionInfo] = (_Array$from$find = Array.from(executionInfoMap.entries()).find(([, executionInfo]) => {
6628 return executionInfo.latestLoadable != null && executionInfo.latestExecutionId != null && !haveAsyncDepsChanged(store, state);
6629 })) !== null && _Array$from$find !== void 0 ? _Array$from$find : [];
6630 return executionInfo;
6631 }
6632
6633 const mapOfCheckedVersions = new Map();
6634
6635 function haveAsyncDepsChanged(store, state) {
6636 var _executionInfo$depVal, _mapOfCheckedVersions;
6637
6638 const executionInfo = getExecutionInfo(store);
6639 const oldDepValues = (_executionInfo$depVal = executionInfo.depValuesDiscoveredSoFarDuringAsyncWork) !== null && _executionInfo$depVal !== void 0 ? _executionInfo$depVal : new Map();
6640 const cachedDepValuesCheckedForThisVersion = Array(((_mapOfCheckedVersions = mapOfCheckedVersions.get(state.version)) !== null && _mapOfCheckedVersions !== void 0 ? _mapOfCheckedVersions : new Map()).entries());
6641 const isCachedVersionSame = mapOfCheckedVersions.has(state.version) && cachedDepValuesCheckedForThisVersion.length === oldDepValues.size && cachedDepValuesCheckedForThisVersion.every(([nodeKey, nodeVal]) => {
6642 return oldDepValues.get(nodeKey) === nodeVal;
6643 });
6644
6645 if (oldDepValues == null || state.version === executionInfo.stateVersion || isCachedVersionSame) {
6646 return false;
6647 }
6648
6649 mapOfCheckedVersions.set(state.version, new Map(oldDepValues));
6650 return Array.from(oldDepValues).some(([nodeKey, oldVal]) => {
6651 const loadable = getCachedNodeLoadable(store, state, nodeKey);
6652 return loadable.contents !== oldVal.contents &&
6653 /**
6654 * FIXME: in the condition below we're making the assumption that a
6655 * dependency that goes from loading to having a value is always because
6656 * the dependency resolved to that value, so we don't count it as a dep
6657 * change as the normal retry loop will handle retrying in response to a
6658 * resolved async dep. This is an incorrect assumption for the edge case
6659 * where there is an async selector that is loading, and while it is
6660 * loading one of its dependencies changes, triggering a new execution,
6661 * and that new execution produces a value synchronously (we don't make
6662 * that assumption for asynchronous work b/c it's guaranteed that a
6663 * loadable that goes from 'loading' to 'loading' in a new loadable is
6664 * a dep change).
6665 */
6666 !(oldVal.state === 'loading' && loadable.state !== 'loading');
6667 });
6668 }
6669 /**
6670 * This function will update the selector's execution info when the selector
6671 * has either finished running an execution or has started a new execution. If
6672 * the given loadable is in a 'loading' state, the intention is that a new
6673 * execution has started. Otherwise, the intention is that an execution has
6674 * just finished.
6675 */
6676
6677
6678 function setExecutionInfo(loadable, store, depValues, newExecutionId, state) {
6679 const executionInfo = getExecutionInfo(store);
6680
6681 if (loadable.state === 'loading') {
6682 executionInfo.depValuesDiscoveredSoFarDuringAsyncWork = depValues;
6683 executionInfo.latestExecutionId = newExecutionId;
6684 executionInfo.latestLoadable = loadable;
6685 executionInfo.stateVersion = state === null || state === void 0 ? void 0 : state.version;
6686 } else {
6687 executionInfo.depValuesDiscoveredSoFarDuringAsyncWork = null;
6688 executionInfo.latestExecutionId = null;
6689 executionInfo.latestLoadable = null;
6690 executionInfo.stateVersion = null;
6691 }
6692 }
6693 /**
6694 * Conditionally updates the cache with a given loadable.
6695 *
6696 * We only cache loadables that are not loading because our cache keys are
6697 * based on dep values, which are in an unfinished state for loadables that
6698 * have a 'loading' state (new deps may be discovered while the selector
6699 * runs its async code). We never want to cache partial dependencies b/c it
6700 * could lead to errors, such as prematurely returning the result based on a
6701 * partial list of deps-- we need the full list of deps to ensure that we
6702 * are returning the correct result from cache.
6703 */
6704
6705
6706 function maybeSetCacheWithLoadable(state, depRoute, loadable) {
6707 if (loadable.state !== 'loading') {
6708 setCache(state, depRoute, loadable);
6709 }
6710 }
6711
6712 function updateExecutionInfoDepValues(depValues, store, executionId) {
6713 const executionInfo = getExecutionInfo(store);
6714
6715 if (isLatestExecution(store, executionId)) {
6716 executionInfo.depValuesDiscoveredSoFarDuringAsyncWork = depValues;
6717 }
6718 }
6719
6720 function clearExecutionInfo(store, executionId) {
6721 if (isLatestExecution(store, executionId)) {
6722 executionInfoMap.delete(store);
6723 }
6724 }
6725
6726 function isLatestExecution(store, executionId) {
6727 const executionInfo = getExecutionInfo(store);
6728 return executionId === executionInfo.latestExecutionId;
6729 }
6730
6731 function maybeFreezeLoadableContents(loadable) {
6732 if (loadable.state !== 'loading') {
6733 maybeFreezeValue(loadable.contents);
6734 }
6735 }
6736
6737 function maybeFreezeValue(val) {
6738 {
6739 if (Boolean(options.dangerouslyAllowMutability) === false) {
6740 Recoil_deepFreezeValue(val);
6741 }
6742 }
6743 }
6744
6745 function setCache(state, cacheRoute, loadable) {
6746 state.atomValues.set(key, loadable);
6747 cache.set(cacheRoute, loadable);
6748 }
6749
6750 function detectCircularDependencies(fn) {
6751 if (dependencyStack.includes(key)) {
6752 const message = `Recoil selector has circular dependencies: ${dependencyStack.slice(dependencyStack.indexOf(key)).join(' \u2192 ')}`;
6753 return loadableWithError$1(new Error(message));
6754 }
6755
6756 dependencyStack.push(key);
6757
6758 try {
6759 return fn();
6760 } finally {
6761 dependencyStack.pop();
6762 }
6763 }
6764
6765 function selectorPeek(store, state) {
6766 const cacheVal = cache.get(nodeKey => {
6767 !(typeof nodeKey === 'string') ? Recoil_invariant(false, 'Cache nodeKey is type string') : void 0;
6768 const peek = peekNodeLoadable$1(store, state, nodeKey);
6769 return peek === null || peek === void 0 ? void 0 : peek.contents;
6770 });
6771 return cacheVal;
6772 }
6773
6774 function selectorGet(store, state) {
6775 return detectCircularDependencies(() => getSelectorValAndUpdatedDeps(store, state));
6776 }
6777
6778 function invalidateSelector(state) {
6779 state.atomValues.delete(key);
6780 }
6781
6782 if (set != null) {
6783 /**
6784 * ES5 strict mode prohibits defining non-top-level function declarations,
6785 * so don't use function declaration syntax here
6786 */
6787 const selectorSet = (store, state, newValue) => {
6788 let syncSelectorSetFinished = false;
6789 const writes = new Map();
6790
6791 function getRecoilValue({
6792 key
6793 }) {
6794 if (syncSelectorSetFinished) {
6795 throw new Error('Recoil: Async selector sets are not currently supported.');
6796 }
6797
6798 const loadable = getCachedNodeLoadable(store, state, key);
6799 maybeFreezeLoadableContents(loadable);
6800
6801 if (loadable.state === 'hasValue') {
6802 return loadable.contents;
6803 } else if (loadable.state === 'loading') {
6804 throw new RecoilValueNotReady$2(key);
6805 } else {
6806 throw loadable.contents;
6807 }
6808 }
6809
6810 function setRecoilState(recoilState, valueOrUpdater) {
6811 if (syncSelectorSetFinished) {
6812 throw new Error('Recoil: Async selector sets are not currently supported.');
6813 }
6814
6815 const newValue = typeof valueOrUpdater === 'function' ? // cast to any because we can't restrict type S from being a function itself without losing support for opaque types
6816 // flowlint-next-line unclear-type:off
6817 valueOrUpdater(getRecoilValue(recoilState)) : valueOrUpdater;
6818 const upstreamWrites = setNodeValue$3(store, state, recoilState.key, newValue);
6819 upstreamWrites.forEach((v, k) => writes.set(k, v));
6820 }
6821
6822 function resetRecoilState(recoilState) {
6823 setRecoilState(recoilState, DEFAULT_VALUE$4);
6824 }
6825
6826 const ret = set({
6827 set: setRecoilState,
6828 get: getRecoilValue,
6829 reset: resetRecoilState
6830 }, newValue); // set should be a void method, but if the user makes it `async`, then it
6831 // will return a Promise, which we don't currently support.
6832
6833 if (ret !== undefined) {
6834 throw Recoil_isPromise(ret) ? new Error('Recoil: Async selector sets are not currently supported.') : new Error('Recoil: selector set should be a void function.');
6835 }
6836
6837 syncSelectorSetFinished = true;
6838 return writes;
6839 };
6840
6841 return registerNode$1({
6842 key,
6843 nodeType: 'selector',
6844 peek: selectorPeek,
6845 get: selectorGet,
6846 set: selectorSet,
6847 init: selectorInit,
6848 invalidate: invalidateSelector,
6849 shouldDeleteConfigOnRelease: selectorShouldDeleteConfigOnRelease,
6850 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
6851 shouldRestoreFromSnapshots: false,
6852 retainedBy
6853 });
6854 } else {
6855 return registerNode$1({
6856 key,
6857 nodeType: 'selector',
6858 peek: selectorPeek,
6859 get: selectorGet,
6860 init: selectorInit,
6861 invalidate: invalidateSelector,
6862 shouldDeleteConfigOnRelease: selectorShouldDeleteConfigOnRelease,
6863 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
6864 shouldRestoreFromSnapshots: false,
6865 retainedBy
6866 });
6867 }
6868 }
6869 /* eslint-enable no-redeclare */
6870
6871
6872 var Recoil_selector = selector;
6873
6874 // @fb-only: const {scopedAtom} = require('Recoil_ScopedAtom');
6875 const {
6876 loadableWithError: loadableWithError$2,
6877 loadableWithPromise: loadableWithPromise$2,
6878 loadableWithValue: loadableWithValue$3
6879 } = Recoil_Loadable;
6880
6881 const {
6882 DEFAULT_VALUE: DEFAULT_VALUE$5,
6883 DefaultValue: DefaultValue$2,
6884 getConfigDeletionHandler: getConfigDeletionHandler$2,
6885 registerNode: registerNode$2,
6886 setConfigDeletionHandler: setConfigDeletionHandler$1
6887 } = Recoil_Node;
6888
6889 const {
6890 isRecoilValue: isRecoilValue$4
6891 } = Recoil_RecoilValue$1;
6892
6893 const {
6894 markRecoilValueModified: markRecoilValueModified$1,
6895 setRecoilValue: setRecoilValue$3,
6896 setRecoilValueLoadable: setRecoilValueLoadable$3
6897 } = Recoil_RecoilValueInterface;
6898
6899 const {
6900 retainedByOptionWithDefault: retainedByOptionWithDefault$2
6901 } = Recoil_Retention;
6902
6903
6904
6905
6906
6907
6908
6909
6910
6911
6912
6913
6914
6915 function baseAtom(options) {
6916 const {
6917 key,
6918 persistence_UNSTABLE: persistence
6919 } = options;
6920 const retainedBy = retainedByOptionWithDefault$2(options.retainedBy_UNSTABLE);
6921 let liveStoresCount = 0;
6922 let defaultLoadable = Recoil_isPromise(options.default) ? loadableWithPromise$2(options.default.then(value => {
6923 defaultLoadable = loadableWithValue$3(value); // TODO Temporary disable Flow due to pending selector_NEW refactor
6924
6925 const promiseInfo = {
6926 __key: key,
6927 __value: value
6928 };
6929 return promiseInfo;
6930 }).catch(error => {
6931 defaultLoadable = loadableWithError$2(error);
6932 throw error;
6933 })) : loadableWithValue$3(options.default);
6934 let cachedAnswerForUnvalidatedValue = undefined; // Cleanup handlers for this atom
6935 // Rely on stable reference equality of the store to use it as a key per <RecoilRoot>
6936
6937 const cleanupEffectsByStore = new Map();
6938
6939 function wrapPendingPromise(store, promise) {
6940 const wrappedPromise = promise.then(value => {
6941 var _store$getState$nextT, _state$atomValues$get;
6942
6943 const state = (_store$getState$nextT = store.getState().nextTree) !== null && _store$getState$nextT !== void 0 ? _store$getState$nextT : store.getState().currentTree;
6944
6945 if (((_state$atomValues$get = state.atomValues.get(key)) === null || _state$atomValues$get === void 0 ? void 0 : _state$atomValues$get.contents) === wrappedPromise) {
6946 setRecoilValue$3(store, node, value);
6947 }
6948
6949 return {
6950 __key: key,
6951 __value: value
6952 };
6953 }).catch(error => {
6954 var _store$getState$nextT2, _state$atomValues$get2;
6955
6956 const state = (_store$getState$nextT2 = store.getState().nextTree) !== null && _store$getState$nextT2 !== void 0 ? _store$getState$nextT2 : store.getState().currentTree;
6957
6958 if (((_state$atomValues$get2 = state.atomValues.get(key)) === null || _state$atomValues$get2 === void 0 ? void 0 : _state$atomValues$get2.contents) === wrappedPromise) {
6959 setRecoilValueLoadable$3(store, node, loadableWithError$2(error));
6960 }
6961
6962 throw error;
6963 });
6964 return wrappedPromise;
6965 }
6966
6967 function initAtom(store, initState, trigger) {
6968 liveStoresCount++;
6969 const alreadyKnown = store.getState().knownAtoms.has(key);
6970 store.getState().knownAtoms.add(key); // Setup async defaults to notify subscribers when they resolve
6971
6972 if (defaultLoadable.state === 'loading') {
6973 const notifyDefaultSubscribers = () => {
6974 var _store$getState$nextT3;
6975
6976 const state = (_store$getState$nextT3 = store.getState().nextTree) !== null && _store$getState$nextT3 !== void 0 ? _store$getState$nextT3 : store.getState().currentTree;
6977
6978 if (!state.atomValues.has(key)) {
6979 markRecoilValueModified$1(store, node);
6980 }
6981 };
6982
6983 defaultLoadable.contents.then(notifyDefaultSubscribers).catch(notifyDefaultSubscribers);
6984 } // Run Atom Effects
6985 // This state is scoped by Store, since this is in the initAtom() closure
6986
6987
6988 let initValue = DEFAULT_VALUE$5;
6989 let pendingSetSelf = null;
6990
6991 if (options.effects_UNSTABLE != null && !alreadyKnown) {
6992 let duringInit = true;
6993
6994 const setSelf = effect => valueOrUpdater => {
6995 if (duringInit) {
6996 const currentValue = initValue instanceof DefaultValue$2 || Recoil_isPromise(initValue) ? defaultLoadable.state === 'hasValue' ? defaultLoadable.contents : DEFAULT_VALUE$5 : initValue;
6997 initValue = typeof valueOrUpdater === 'function' ? // cast to any because we can't restrict T from being a function without losing support for opaque types
6998 valueOrUpdater(currentValue) // flowlint-line unclear-type:off
6999 : valueOrUpdater; // Avoid calling onSet() when setSelf() initializes with a Promise
7000
7001 if (Recoil_isPromise(initValue)) {
7002 initValue = initValue.then(value => {
7003 pendingSetSelf = {
7004 effect,
7005 value
7006 };
7007 return value;
7008 });
7009 }
7010 } else {
7011 if (Recoil_isPromise(valueOrUpdater)) {
7012 throw new Error('Setting atoms to async values is not implemented.');
7013 }
7014
7015 if (typeof valueOrUpdater !== 'function') {
7016 pendingSetSelf = {
7017 effect,
7018 value: valueOrUpdater
7019 };
7020 }
7021
7022 setRecoilValue$3(store, node, typeof valueOrUpdater === 'function' ? currentValue => {
7023 const newValue = // cast to any because we can't restrict T from being a function without losing support for opaque types
7024 valueOrUpdater(currentValue); // flowlint-line unclear-type:off
7025
7026 pendingSetSelf = {
7027 effect,
7028 value: newValue
7029 };
7030 return newValue;
7031 } : valueOrUpdater);
7032 }
7033 };
7034
7035 const resetSelf = effect => () => setSelf(effect)(DEFAULT_VALUE$5);
7036
7037 const onSet = effect => handler => {
7038 store.subscribeToTransactions(currentStore => {
7039 var _currentTree$atomValu;
7040
7041 // eslint-disable-next-line prefer-const
7042 let {
7043 currentTree,
7044 previousTree
7045 } = currentStore.getState();
7046
7047 if (!previousTree) {
7048 Recoil_recoverableViolation('Transaction subscribers notified without a next tree being present -- this is a bug in Recoil');
7049 previousTree = currentTree; // attempt to trundle on
7050 }
7051
7052 const newLoadable = (_currentTree$atomValu = currentTree.atomValues.get(key)) !== null && _currentTree$atomValu !== void 0 ? _currentTree$atomValu : defaultLoadable;
7053
7054 if (newLoadable.state === 'hasValue') {
7055 var _previousTree$atomVal, _pendingSetSelf, _pendingSetSelf2, _pendingSetSelf3;
7056
7057 const newValue = newLoadable.contents;
7058 const oldLoadable = (_previousTree$atomVal = previousTree.atomValues.get(key)) !== null && _previousTree$atomVal !== void 0 ? _previousTree$atomVal : defaultLoadable;
7059 const oldValue = oldLoadable.state === 'hasValue' ? oldLoadable.contents : DEFAULT_VALUE$5; // TODO This isn't actually valid, use as a placeholder for now.
7060 // Ignore atom value changes that were set via setSelf() in the same effect.
7061 // We will still properly call the handler if there was a subsequent
7062 // set from something other than an atom effect which was batched
7063 // with the `setSelf()` call. However, we may incorrectly ignore
7064 // the handler if the subsequent batched call happens to set the
7065 // atom to the exact same value as the `setSelf()`. But, in that
7066 // case, it was kind of a noop, so the semantics are debatable..
7067
7068 if (((_pendingSetSelf = pendingSetSelf) === null || _pendingSetSelf === void 0 ? void 0 : _pendingSetSelf.effect) !== effect || ((_pendingSetSelf2 = pendingSetSelf) === null || _pendingSetSelf2 === void 0 ? void 0 : _pendingSetSelf2.value) !== newValue) {
7069 handler(newValue, oldValue);
7070 } else if (((_pendingSetSelf3 = pendingSetSelf) === null || _pendingSetSelf3 === void 0 ? void 0 : _pendingSetSelf3.effect) === effect) {
7071 pendingSetSelf = null;
7072 }
7073 }
7074 }, key);
7075 };
7076
7077 for (const effect of (_options$effects_UNST = options.effects_UNSTABLE) !== null && _options$effects_UNST !== void 0 ? _options$effects_UNST : []) {
7078 var _options$effects_UNST;
7079
7080 const cleanup = effect({
7081 node,
7082 trigger,
7083 setSelf: setSelf(effect),
7084 resetSelf: resetSelf(effect),
7085 onSet: onSet(effect)
7086 });
7087
7088 if (cleanup != null) {
7089 var _cleanupEffectsByStor;
7090
7091 cleanupEffectsByStore.set(store, [...((_cleanupEffectsByStor = cleanupEffectsByStore.get(store)) !== null && _cleanupEffectsByStor !== void 0 ? _cleanupEffectsByStor : []), cleanup]);
7092 }
7093 }
7094
7095 duringInit = false;
7096 } // Mutate initial state in place since we know there are no other subscribers
7097 // since we are the ones initializing on first use.
7098
7099
7100 if (!(initValue instanceof DefaultValue$2)) {
7101 var _store$getState$nextT4;
7102
7103 const initLoadable = Recoil_isPromise(initValue) ? loadableWithPromise$2(wrapPendingPromise(store, initValue)) : loadableWithValue$3(initValue);
7104 initState.atomValues.set(key, initLoadable); // If there is a pending transaction, then also mutate the next state tree.
7105 // This could happen if the atom was first initialized in an action that
7106 // also updated some other atom's state.
7107
7108 (_store$getState$nextT4 = store.getState().nextTree) === null || _store$getState$nextT4 === void 0 ? void 0 : _store$getState$nextT4.atomValues.set(key, initLoadable);
7109 }
7110
7111 return () => {
7112 var _cleanupEffectsByStor2;
7113
7114 liveStoresCount--;
7115 (_cleanupEffectsByStor2 = cleanupEffectsByStore.get(store)) === null || _cleanupEffectsByStor2 === void 0 ? void 0 : _cleanupEffectsByStor2.forEach(cleanup => cleanup());
7116 cleanupEffectsByStore.delete(store);
7117 store.getState().knownAtoms.delete(key); // FIXME remove knownAtoms?
7118 };
7119 }
7120
7121 function peekAtom(_store, state) {
7122 var _ref, _state$atomValues$get3, _cachedAnswerForUnval;
7123
7124 return (_ref = (_state$atomValues$get3 = state.atomValues.get(key)) !== null && _state$atomValues$get3 !== void 0 ? _state$atomValues$get3 : (_cachedAnswerForUnval = cachedAnswerForUnvalidatedValue) === null || _cachedAnswerForUnval === void 0 ? void 0 : _cachedAnswerForUnval[1]) !== null && _ref !== void 0 ? _ref : defaultLoadable;
7125 }
7126
7127 function getAtom(_store, state) {
7128 if (state.atomValues.has(key)) {
7129 // Atom value is stored in state:
7130 return Recoil_nullthrows(state.atomValues.get(key));
7131 } else if (state.nonvalidatedAtoms.has(key)) {
7132 // Atom value is stored but needs validation before use.
7133 // We might have already validated it and have a cached validated value:
7134 if (cachedAnswerForUnvalidatedValue != null) {
7135 return cachedAnswerForUnvalidatedValue;
7136 }
7137
7138 if (persistence == null) {
7139 Recoil_expectationViolation(`Tried to restore a persisted value for atom ${key} but it has no persistence settings.`);
7140 return defaultLoadable;
7141 }
7142
7143 const nonvalidatedValue = state.nonvalidatedAtoms.get(key);
7144 const validatorResult = persistence.validator(nonvalidatedValue, DEFAULT_VALUE$5);
7145 const validatedValueLoadable = validatorResult instanceof DefaultValue$2 ? defaultLoadable : loadableWithValue$3(validatorResult);
7146 cachedAnswerForUnvalidatedValue = validatedValueLoadable;
7147 return cachedAnswerForUnvalidatedValue;
7148 } else {
7149 return defaultLoadable;
7150 }
7151 }
7152
7153 function invalidateAtom() {
7154 cachedAnswerForUnvalidatedValue = undefined;
7155 }
7156
7157 function setAtom(_store, state, newValue) {
7158 // Bail out if we're being set to the existing value, or if we're being
7159 // reset but have no stored value (validated or unvalidated) to reset from:
7160 if (state.atomValues.has(key)) {
7161 const existing = Recoil_nullthrows(state.atomValues.get(key));
7162
7163 if (existing.state === 'hasValue' && newValue === existing.contents) {
7164 return new Map();
7165 }
7166 } else if (!state.nonvalidatedAtoms.has(key) && newValue instanceof DefaultValue$2) {
7167 return new Map();
7168 }
7169
7170 {
7171 if (options.dangerouslyAllowMutability !== true) {
7172 Recoil_deepFreezeValue(newValue);
7173 }
7174 }
7175
7176 cachedAnswerForUnvalidatedValue = undefined; // can be released now if it was previously in use
7177
7178 return new Map().set(key, loadableWithValue$3(newValue));
7179 }
7180
7181 function shouldDeleteConfigOnReleaseAtom() {
7182 return getConfigDeletionHandler$2(key) !== undefined && liveStoresCount <= 0;
7183 }
7184
7185 const node = registerNode$2({
7186 key,
7187 nodeType: 'atom',
7188 peek: peekAtom,
7189 get: getAtom,
7190 set: setAtom,
7191 init: initAtom,
7192 invalidate: invalidateAtom,
7193 shouldDeleteConfigOnRelease: shouldDeleteConfigOnReleaseAtom,
7194 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
7195 persistence_UNSTABLE: options.persistence_UNSTABLE ? {
7196 type: options.persistence_UNSTABLE.type,
7197 backButton: options.persistence_UNSTABLE.backButton
7198 } : undefined,
7199 shouldRestoreFromSnapshots: true,
7200 retainedBy
7201 });
7202 return node;
7203 } // prettier-ignore
7204
7205
7206 function atom(options) {
7207 const {
7208 default: optionsDefault,
7209 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
7210 ...restOptions
7211 } = options;
7212
7213 if (isRecoilValue$4(optionsDefault) // Continue to use atomWithFallback for promise defaults for scoped atoms
7214 // for now, since scoped atoms don't support async defaults
7215 // @fb-only: || (isPromise(optionsDefault) && scopeRules_APPEND_ONLY_READ_THE_DOCS)
7216 ) {
7217 return atomWithFallback({ ...restOptions,
7218 default: optionsDefault // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
7219
7220 }); // @fb-only: } else if (scopeRules_APPEND_ONLY_READ_THE_DOCS && !isPromise(optionsDefault)) {
7221 // @fb-only: return scopedAtom<T>({
7222 // @fb-only: ...restOptions,
7223 // @fb-only: default: optionsDefault,
7224 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
7225 // @fb-only: });
7226 } else {
7227 return baseAtom({ ...restOptions,
7228 default: optionsDefault
7229 });
7230 }
7231 }
7232
7233 function atomWithFallback(options) {
7234 const base = atom({ ...options,
7235 default: DEFAULT_VALUE$5,
7236 persistence_UNSTABLE: options.persistence_UNSTABLE === undefined ? undefined : { ...options.persistence_UNSTABLE,
7237 validator: storedValue => storedValue instanceof DefaultValue$2 ? storedValue : Recoil_nullthrows(options.persistence_UNSTABLE).validator(storedValue, DEFAULT_VALUE$5)
7238 },
7239 // TODO Hack for now.
7240 // flowlint-next-line unclear-type: off
7241 effects_UNSTABLE: options.effects_UNSTABLE
7242 });
7243 const sel = Recoil_selector({
7244 key: `${options.key}__withFallback`,
7245 get: ({
7246 get
7247 }) => {
7248 const baseValue = get(base);
7249 return baseValue instanceof DefaultValue$2 ? options.default : baseValue;
7250 },
7251 set: ({
7252 set
7253 }, newValue) => set(base, newValue),
7254 dangerouslyAllowMutability: options.dangerouslyAllowMutability
7255 });
7256 setConfigDeletionHandler$1(sel.key, getConfigDeletionHandler$2(options.key));
7257 return sel;
7258 }
7259
7260 var Recoil_atom = atom;
7261
7262 /**
7263 * (c) Facebook, Inc. and its affiliates. Confidential and proprietary.
7264 *
7265 * @emails oncall+recoil
7266 *
7267 * @format
7268 */
7269
7270 class MapCache {
7271 constructor(options) {
7272 var _options$mapKey;
7273
7274 _defineProperty(this, "_map", void 0);
7275
7276 _defineProperty(this, "_keyMapper", void 0);
7277
7278 this._map = new Map();
7279 this._keyMapper = (_options$mapKey = options === null || options === void 0 ? void 0 : options.mapKey) !== null && _options$mapKey !== void 0 ? _options$mapKey : v => v;
7280 }
7281
7282 size() {
7283 return this._map.size;
7284 }
7285
7286 has(key) {
7287 return this._map.has(this._keyMapper(key));
7288 }
7289
7290 get(key) {
7291 return this._map.get(this._keyMapper(key));
7292 }
7293
7294 set(key, val) {
7295 this._map.set(this._keyMapper(key), val);
7296 }
7297
7298 delete(key) {
7299 this._map.delete(this._keyMapper(key));
7300 }
7301
7302 clear() {
7303 this._map.clear();
7304 }
7305
7306 }
7307
7308 var Recoil_MapCache = {
7309 MapCache
7310 };
7311
7312 var Recoil_MapCache_1 = Recoil_MapCache.MapCache;
7313
7314 var Recoil_MapCache$1 = /*#__PURE__*/Object.freeze({
7315 __proto__: null,
7316 MapCache: Recoil_MapCache_1
7317 });
7318
7319 const {
7320 LRUCache: LRUCache$2
7321 } = Recoil_LRUCache$1;
7322
7323 const {
7324 MapCache: MapCache$1
7325 } = Recoil_MapCache$1;
7326
7327 const defaultPolicy$1 = {
7328 equality: 'reference',
7329 eviction: 'none',
7330 maxSize: Infinity
7331 };
7332
7333 function cacheFromPolicy({
7334 equality = defaultPolicy$1.equality,
7335 eviction = defaultPolicy$1.eviction,
7336 maxSize = defaultPolicy$1.maxSize
7337 } = defaultPolicy$1) {
7338 const valueMapper = getValueMapper$1(equality);
7339 const cache = getCache(eviction, maxSize, valueMapper);
7340 return cache;
7341 }
7342
7343 function getValueMapper$1(equality) {
7344 switch (equality) {
7345 case 'reference':
7346 return val => val;
7347
7348 case 'value':
7349 return val => Recoil_stableStringify(val);
7350 }
7351
7352 throw new Error(`Unrecognized equality policy ${equality}`);
7353 }
7354
7355 function getCache(eviction, maxSize, mapKey) {
7356 switch (eviction) {
7357 case 'keep-all':
7358 // $FlowFixMe[method-unbinding]
7359 return new MapCache$1({
7360 mapKey
7361 });
7362
7363 case 'lru':
7364 // $FlowFixMe[method-unbinding]
7365 return new LRUCache$2({
7366 mapKey,
7367 maxSize: Recoil_nullthrows(maxSize)
7368 });
7369
7370 case 'most-recent':
7371 // $FlowFixMe[method-unbinding]
7372 return new LRUCache$2({
7373 mapKey,
7374 maxSize: 1
7375 });
7376 }
7377
7378 throw new Error(`Unrecognized eviction policy ${eviction}`);
7379 }
7380
7381 var Recoil_cacheFromPolicy = cacheFromPolicy;
7382
7383 const {
7384 setConfigDeletionHandler: setConfigDeletionHandler$2
7385 } = Recoil_Node;
7386 /*
7387 A function which returns an atom based on the input parameter.
7388
7389 Each unique parameter returns a unique atom. E.g.,
7390
7391 const f = atomFamily(...);
7392 f({a: 1}) => an atom
7393 f({a: 2}) => a different atom
7394
7395 This allows components to persist local, private state using atoms. Each
7396 instance of the component may have a different key, which it uses as the
7397 parameter for a family of atoms; in this way, each component will have
7398 its own atom not shared by other instances. These state keys may be composed
7399 into children's state keys as well.
7400 */
7401
7402
7403 function atomFamily(options) {
7404 var _options$cachePolicyF, _options$cachePolicyF2;
7405
7406 const atomCache = Recoil_cacheFromPolicy({
7407 equality: (_options$cachePolicyF = (_options$cachePolicyF2 = options.cachePolicyForParams_UNSTABLE) === null || _options$cachePolicyF2 === void 0 ? void 0 : _options$cachePolicyF2.equality) !== null && _options$cachePolicyF !== void 0 ? _options$cachePolicyF : 'value',
7408 eviction: 'keep-all'
7409 }); // Simple atomFamily implementation to cache individual atoms based
7410 // on the parameter value equality.
7411
7412 return params => {
7413 var _stableStringify;
7414
7415 const cachedAtom = atomCache.get(params);
7416
7417 if (cachedAtom != null) {
7418 return cachedAtom;
7419 }
7420
7421 const {
7422 cachePolicyForParams_UNSTABLE,
7423 ...atomOptions
7424 } = options;
7425 const newAtom = Recoil_atom({ ...atomOptions,
7426 key: `${options.key}__${(_stableStringify = Recoil_stableStringify(params)) !== null && _stableStringify !== void 0 ? _stableStringify : 'void'}`,
7427 default: typeof options.default === 'function' ? // The default was parameterized
7428 // Flow doesn't know that T isn't a function, so we need to case to any
7429 options.default(params) // flowlint-line unclear-type:off
7430 : // Default may be a static value, promise, or RecoilValue
7431 options.default,
7432 retainedBy_UNSTABLE: typeof options.retainedBy_UNSTABLE === 'function' ? options.retainedBy_UNSTABLE(params) : options.retainedBy_UNSTABLE,
7433 effects_UNSTABLE: typeof options.effects_UNSTABLE === 'function' ? options.effects_UNSTABLE(params) : options.effects_UNSTABLE // prettier-ignore
7434 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS: mapScopeRules(
7435 // @fb-only: options.scopeRules_APPEND_ONLY_READ_THE_DOCS,
7436 // @fb-only: params,
7437 // @fb-only: ),
7438
7439 });
7440 atomCache.set(params, newAtom);
7441 setConfigDeletionHandler$2(newAtom.key, () => {
7442 atomCache.delete(params);
7443 });
7444 return newAtom;
7445 };
7446 }
7447
7448 var Recoil_atomFamily = atomFamily;
7449
7450 const {
7451 setConfigDeletionHandler: setConfigDeletionHandler$3
7452 } = Recoil_Node;
7453
7454
7455
7456 // Keep in mind the parameter needs to be serializable as a cahche key
7457 // using Recoil_stableStringify
7458
7459
7460 // Add a unique index to each selector in case the cache implementation allows
7461 // duplicate keys based on equivalent stringified parameters
7462 let nextIndex = 0;
7463 /* eslint-disable no-redeclare */
7464
7465 // Return a function that returns members of a family of selectors of the same type
7466 // E.g.,
7467 //
7468 // const s = selectorFamily(...);
7469 // s({a: 1}) => a selector
7470 // s({a: 2}) => a different selector
7471 //
7472 // By default, the selectors are distinguished by distinct values of the
7473 // parameter based on value equality, not reference equality. This allows using
7474 // object literals or other equivalent objects at callsites to not create
7475 // duplicate cache entries. This behavior may be overridden with the
7476 // cacheImplementationForParams option.
7477 function selectorFamily(options) {
7478 var _options$cachePolicyF, _options$cachePolicyF2;
7479
7480 const selectorCache = Recoil_cacheFromPolicy({
7481 equality: (_options$cachePolicyF = (_options$cachePolicyF2 = options.cachePolicyForParams_UNSTABLE) === null || _options$cachePolicyF2 === void 0 ? void 0 : _options$cachePolicyF2.equality) !== null && _options$cachePolicyF !== void 0 ? _options$cachePolicyF : 'value',
7482 eviction: 'keep-all'
7483 });
7484 return params => {
7485 var _stableStringify;
7486
7487 const cachedSelector = selectorCache.get(params);
7488
7489 if (cachedSelector != null) {
7490 return cachedSelector;
7491 }
7492
7493 const myKey = `${options.key}__selectorFamily/${(_stableStringify = Recoil_stableStringify(params, {
7494 // It is possible to use functions in parameters if the user uses
7495 // a cache with reference equality thanks to the incrementing index.
7496 allowFunctions: true
7497 })) !== null && _stableStringify !== void 0 ? _stableStringify : 'void'}/${nextIndex++}`; // Append index in case values serialize to the same key string
7498
7499 const myGet = callbacks => options.get(params)(callbacks);
7500
7501 const myCachePolicy = options.cachePolicy_UNSTABLE;
7502 const retainedBy = typeof options.retainedBy_UNSTABLE === 'function' ? options.retainedBy_UNSTABLE(params) : options.retainedBy_UNSTABLE;
7503 let newSelector;
7504
7505 if (options.set != null) {
7506 const set = options.set;
7507
7508 const mySet = (callbacks, newValue) => set(params)(callbacks, newValue);
7509
7510 newSelector = Recoil_selector({
7511 key: myKey,
7512 get: myGet,
7513 set: mySet,
7514 cachePolicy_UNSTABLE: myCachePolicy,
7515 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
7516 retainedBy_UNSTABLE: retainedBy
7517 });
7518 } else {
7519 newSelector = Recoil_selector({
7520 key: myKey,
7521 get: myGet,
7522 cachePolicy_UNSTABLE: myCachePolicy,
7523 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
7524 retainedBy_UNSTABLE: retainedBy
7525 });
7526 }
7527
7528 selectorCache.set(params, newSelector);
7529 setConfigDeletionHandler$3(newSelector.key, () => {
7530 selectorCache.delete(params);
7531 });
7532 return newSelector;
7533 };
7534 }
7535 /* eslint-enable no-redeclare */
7536
7537
7538 var Recoil_selectorFamily = selectorFamily;
7539
7540 // flowlint-next-line unclear-type:off
7541
7542
7543 const constantSelector = Recoil_selectorFamily({
7544 key: '__constant',
7545 get: constant => () => constant,
7546 cachePolicyForParams_UNSTABLE: {
7547 equality: 'reference'
7548 }
7549 }); // Function that returns a selector which always produces the
7550 // same constant value. It may be called multiple times with the
7551 // same value, based on reference equality, and will provide the
7552 // same selector.
7553
7554 function constSelector(constant) {
7555 return constantSelector(constant);
7556 }
7557
7558 var Recoil_constSelector = constSelector;
7559
7560 // flowlint-next-line unclear-type:off
7561
7562
7563 const throwingSelector = Recoil_selectorFamily({
7564 key: '__error',
7565 get: message => () => {
7566 throw new Error(message);
7567 },
7568 cachePolicyForParams_UNSTABLE: {
7569 equality: 'reference'
7570 }
7571 }); // Function that returns a selector which always throws an error
7572 // with the provided message.
7573
7574 function errorSelector(message) {
7575 return throwingSelector(message);
7576 }
7577
7578 var Recoil_errorSelector = errorSelector;
7579
7580 /**
7581 * Copyright (c) Facebook, Inc. and its affiliates.
7582 *
7583 * This source code is licensed under the MIT license found in the
7584 * LICENSE file in the root directory of this source tree.
7585 *
7586 * Wraps another recoil value and prevents writing to it.
7587 *
7588 * @emails oncall+recoil
7589 *
7590 * @format
7591 */
7592
7593 function readOnlySelector(atom) {
7594 // flowlint-next-line unclear-type: off
7595 return atom;
7596 }
7597
7598 var Recoil_readOnlySelector = readOnlySelector;
7599
7600 const {
7601 loadableWithError: loadableWithError$3,
7602 loadableWithPromise: loadableWithPromise$3,
7603 loadableWithValue: loadableWithValue$4
7604 } = Recoil_Loadable;
7605
7606
7607
7608 /////////////////
7609 // TRUTH TABLE
7610 /////////////////
7611 // Dependencies waitForNone waitForAny waitForAll waitForAllSettled
7612 // [loading, loading] [Promise, Promise] Promise Promise Promise
7613 // [value, loading] [value, Promise] [value, Promise] Promise Promise
7614 // [value, value] [value, value] [value, value] [value, value] [value, value]
7615 //
7616 // [error, loading] [Error, Promise] [Error, Promise] Error Promise
7617 // [error, error] [Error, Error] [Error, Error] Error [error, error]
7618 // [value, error] [value, Error] [value, Error] Error [value, error]
7619 // Issue parallel requests for all dependencies and return the current
7620 // status if they have results, have some error, or are still pending.
7621
7622
7623 function concurrentRequests(getRecoilValue, deps) {
7624 const results = Array(deps.length).fill(undefined);
7625 const exceptions = Array(deps.length).fill(undefined);
7626
7627 for (const [i, dep] of deps.entries()) {
7628 try {
7629 results[i] = getRecoilValue(dep);
7630 } catch (e) {
7631 // exceptions can either be Promises of pending results or real errors
7632 exceptions[i] = e;
7633 }
7634 }
7635
7636 return [results, exceptions];
7637 }
7638
7639 function isError(exp) {
7640 return exp != null && !Recoil_isPromise(exp);
7641 }
7642
7643 function unwrapDependencies(dependencies) {
7644 return Array.isArray(dependencies) ? dependencies : Object.getOwnPropertyNames(dependencies).map(key => dependencies[key]);
7645 }
7646
7647 function getValueFromLoadablePromiseResult(result) {
7648 if (result != null && typeof result === 'object' && result.hasOwnProperty('__value')) {
7649 return result.__value;
7650 }
7651
7652 return result;
7653 }
7654
7655 function wrapResults(dependencies, results) {
7656 return Array.isArray(dependencies) ? results : // Object.getOwnPropertyNames() has consistent key ordering with ES6
7657 Object.getOwnPropertyNames(dependencies).reduce((out, key, idx) => ({ ...out,
7658 [key]: results[idx]
7659 }), {});
7660 }
7661
7662 function wrapLoadables(dependencies, results, exceptions) {
7663 const output = exceptions.map((exception, idx) => exception == null ? loadableWithValue$4(results[idx]) : Recoil_isPromise(exception) ? loadableWithPromise$3(exception) : loadableWithError$3(exception));
7664 return wrapResults(dependencies, output);
7665 }
7666
7667 function combineAsyncResultsWithSyncResults(syncResults, asyncResults) {
7668 return asyncResults.map((result, idx) =>
7669 /**
7670 * it's important we use === undefined as opposed to == null, because the
7671 * resolved value of the async promise could be `null`, in which case we
7672 * don't want to use syncResults[idx], which would be undefined. If async
7673 * promise resolves to `undefined`, that's ok because `syncResults[idx]`
7674 * will also be `undefined`. That's a little hacky, but it works.
7675 */
7676 result === undefined ? syncResults[idx] : result);
7677 } // Selector that requests all dependencies in parallel and immediately returns
7678 // current results without waiting.
7679
7680
7681 const waitForNone = Recoil_selectorFamily({
7682 key: '__waitForNone',
7683 get: dependencies => ({
7684 get
7685 }) => {
7686 // Issue requests for all dependencies in parallel.
7687 const deps = unwrapDependencies(dependencies);
7688 const [results, exceptions] = concurrentRequests(get, deps); // Always return the current status of the results; never block.
7689
7690 return wrapLoadables(dependencies, results, exceptions);
7691 },
7692 dangerouslyAllowMutability: true
7693 }); // Selector that requests all dependencies in parallel and waits for at least
7694 // one to be available before returning results. It will only error if all
7695 // dependencies have errors.
7696
7697 const waitForAny = Recoil_selectorFamily({
7698 key: '__waitForAny',
7699 get: dependencies => ({
7700 get
7701 }) => {
7702 // Issue requests for all dependencies in parallel.
7703 // Exceptions can either be Promises of pending results or real errors
7704 const deps = unwrapDependencies(dependencies);
7705 const [results, exceptions] = concurrentRequests(get, deps); // If any results are available, value or error, return the current status
7706
7707 if (exceptions.some(exp => !Recoil_isPromise(exp))) {
7708 return wrapLoadables(dependencies, results, exceptions);
7709 } // Otherwise, return a promise that will resolve when the next result is
7710 // available, whichever one happens to be next. But, if all pending
7711 // dependencies end up with errors, then reject the promise.
7712
7713
7714 return new Promise(resolve => {
7715 for (const [i, exp] of exceptions.entries()) {
7716 if (Recoil_isPromise(exp)) {
7717 exp.then(result => {
7718 results[i] = getValueFromLoadablePromiseResult(result);
7719 exceptions[i] = undefined;
7720 resolve(wrapLoadables(dependencies, results, exceptions));
7721 }).catch(error => {
7722 exceptions[i] = error;
7723 resolve(wrapLoadables(dependencies, results, exceptions));
7724 });
7725 }
7726 }
7727 });
7728 },
7729 dangerouslyAllowMutability: true
7730 }); // Selector that requests all dependencies in parallel and waits for all to be
7731 // available before returning a value. It will error if any dependencies error.
7732
7733 const waitForAll = Recoil_selectorFamily({
7734 key: '__waitForAll',
7735 get: dependencies => ({
7736 get
7737 }) => {
7738 // Issue requests for all dependencies in parallel.
7739 // Exceptions can either be Promises of pending results or real errors
7740 const deps = unwrapDependencies(dependencies);
7741 const [results, exceptions] = concurrentRequests(get, deps); // If all results are available, return the results
7742
7743 if (exceptions.every(exp => exp == null)) {
7744 return wrapResults(dependencies, results);
7745 } // If we have any errors, throw the first error
7746
7747
7748 const error = exceptions.find(isError);
7749
7750 if (error != null) {
7751 throw error;
7752 } // Otherwise, return a promise that will resolve when all results are available
7753
7754
7755 return Promise.all(exceptions).then(exceptionResults => wrapResults(dependencies, combineAsyncResultsWithSyncResults(results, exceptionResults).map(getValueFromLoadablePromiseResult)));
7756 },
7757 dangerouslyAllowMutability: true
7758 });
7759 const waitForAllSettled = Recoil_selectorFamily({
7760 key: '__waitForAllSettled',
7761 get: dependencies => ({
7762 get
7763 }) => {
7764 // Issue requests for all dependencies in parallel.
7765 // Exceptions can either be Promises of pending results or real errors
7766 const deps = unwrapDependencies(dependencies);
7767 const [results, exceptions] = concurrentRequests(get, deps); // If all results are available, return the results
7768
7769 if (exceptions.every(exp => !Recoil_isPromise(exp))) {
7770 return wrapLoadables(dependencies, results, exceptions);
7771 } // Wait for all results to settle
7772
7773
7774 return Promise.all(exceptions.map((exp, i) => Recoil_isPromise(exp) ? exp.then(result => {
7775 results[i] = getValueFromLoadablePromiseResult(result);
7776 exceptions[i] = undefined;
7777 }).catch(error => {
7778 results[i] = undefined;
7779 exceptions[i] = error;
7780 }) : null)) // Then wrap them as loadables
7781 .then(() => wrapLoadables(dependencies, results, exceptions));
7782 },
7783 dangerouslyAllowMutability: true
7784 });
7785 const noWait = Recoil_selectorFamily({
7786 key: '__noWait',
7787 get: dependency => ({
7788 get
7789 }) => {
7790 try {
7791 return loadableWithValue$4(get(dependency));
7792 } catch (exception) {
7793 return Recoil_isPromise(exception) ? loadableWithPromise$3(exception) : loadableWithError$3(exception);
7794 }
7795 },
7796 dangerouslyAllowMutability: true
7797 });
7798 var Recoil_WaitFor = {
7799 waitForNone,
7800 waitForAny,
7801 waitForAll,
7802 waitForAllSettled,
7803 noWait
7804 };
7805
7806 const {
7807 batchUpdates: batchUpdates$3,
7808 setBatcher: setBatcher$1
7809 } = Recoil_Batching;
7810
7811 const {
7812 DefaultValue: DefaultValue$3
7813 } = Recoil_Node;
7814
7815 const {
7816 RecoilRoot: RecoilRoot$2
7817 } = Recoil_RecoilRoot_react;
7818
7819 const {
7820 isRecoilValue: isRecoilValue$5
7821 } = Recoil_RecoilValue$1;
7822
7823 const {
7824 retentionZone: retentionZone$1
7825 } = Recoil_RetentionZone;
7826
7827 const {
7828 freshSnapshot: freshSnapshot$2
7829 } = Recoil_Snapshot$1;
7830
7831 const {
7832 useGotoRecoilSnapshot: useGotoRecoilSnapshot$1,
7833 useRecoilCallback: useRecoilCallback$1,
7834 useRecoilSnapshot: useRecoilSnapshot$1,
7835 useRecoilState: useRecoilState$1,
7836 useRecoilStateLoadable: useRecoilStateLoadable$1,
7837 useRecoilTransaction: useRecoilTransaction$1,
7838 useRecoilTransactionObserver: useRecoilTransactionObserver$1,
7839 useRecoilValue: useRecoilValue$1,
7840 useRecoilValueLoadable: useRecoilValueLoadable$1,
7841 useResetRecoilState: useResetRecoilState$1,
7842 useRetain: useRetain$1,
7843 useSetRecoilState: useSetRecoilState$1,
7844 useSetUnvalidatedAtomValues: useSetUnvalidatedAtomValues$1,
7845 useTransactionObservation_DEPRECATED: useTransactionObservation_DEPRECATED$1
7846 } = Recoil_Hooks;
7847
7848
7849
7850
7851
7852
7853
7854
7855
7856
7857
7858
7859
7860
7861
7862
7863
7864
7865
7866 const {
7867 noWait: noWait$1,
7868 waitForAll: waitForAll$1,
7869 waitForAllSettled: waitForAllSettled$1,
7870 waitForAny: waitForAny$1,
7871 waitForNone: waitForNone$1
7872 } = Recoil_WaitFor;
7873
7874 var Recoil_index = {
7875 // Types
7876 DefaultValue: DefaultValue$3,
7877 // Components
7878 RecoilRoot: RecoilRoot$2,
7879 useRecoilBridgeAcrossReactRoots_UNSTABLE: Recoil_useRecoilBridgeAcrossReactRoots,
7880 // RecoilValues
7881 atom: Recoil_atom,
7882 selector: Recoil_selector,
7883 // Other factories
7884 retentionZone: retentionZone$1,
7885 // Convenience RecoilValues
7886 atomFamily: Recoil_atomFamily,
7887 selectorFamily: Recoil_selectorFamily,
7888 constSelector: Recoil_constSelector,
7889 errorSelector: Recoil_errorSelector,
7890 readOnlySelector: Recoil_readOnlySelector,
7891 // Hooks that accept RecoilValues
7892 useRecoilValue: useRecoilValue$1,
7893 useRecoilValueLoadable: useRecoilValueLoadable$1,
7894 useRecoilState: useRecoilState$1,
7895 useRecoilStateLoadable: useRecoilStateLoadable$1,
7896 useSetRecoilState: useSetRecoilState$1,
7897 useResetRecoilState: useResetRecoilState$1,
7898 useGetRecoilValueInfo_UNSTABLE: Recoil_useGetRecoilValueInfo,
7899 useRetain: useRetain$1,
7900 // Hooks for complex operations with RecoilValues
7901 useRecoilCallback: useRecoilCallback$1,
7902 useRecoilTransaction_UNSTABLE: useRecoilTransaction$1,
7903 // Hooks for Snapshots
7904 useGotoRecoilSnapshot: useGotoRecoilSnapshot$1,
7905 useRecoilSnapshot: useRecoilSnapshot$1,
7906 useRecoilTransactionObserver_UNSTABLE: useRecoilTransactionObserver$1,
7907 useTransactionObservation_UNSTABLE: useTransactionObservation_DEPRECATED$1,
7908 useSetUnvalidatedAtomValues_UNSTABLE: useSetUnvalidatedAtomValues$1,
7909 // Concurrency Helpers
7910 noWait: noWait$1,
7911 waitForNone: waitForNone$1,
7912 waitForAny: waitForAny$1,
7913 waitForAll: waitForAll$1,
7914 waitForAllSettled: waitForAllSettled$1,
7915 // Other functions
7916 isRecoilValue: isRecoilValue$5,
7917 // Batching
7918 batchUpdates: batchUpdates$3,
7919 setBatcher: setBatcher$1,
7920 // Snapshot Utils
7921 snapshot_UNSTABLE: freshSnapshot$2
7922 };
7923 var Recoil_index_1 = Recoil_index.DefaultValue;
7924 var Recoil_index_2 = Recoil_index.RecoilRoot;
7925 var Recoil_index_3 = Recoil_index.useRecoilBridgeAcrossReactRoots_UNSTABLE;
7926 var Recoil_index_4 = Recoil_index.atom;
7927 var Recoil_index_5 = Recoil_index.selector;
7928 var Recoil_index_6 = Recoil_index.retentionZone;
7929 var Recoil_index_7 = Recoil_index.atomFamily;
7930 var Recoil_index_8 = Recoil_index.selectorFamily;
7931 var Recoil_index_9 = Recoil_index.constSelector;
7932 var Recoil_index_10 = Recoil_index.errorSelector;
7933 var Recoil_index_11 = Recoil_index.readOnlySelector;
7934 var Recoil_index_12 = Recoil_index.useRecoilValue;
7935 var Recoil_index_13 = Recoil_index.useRecoilValueLoadable;
7936 var Recoil_index_14 = Recoil_index.useRecoilState;
7937 var Recoil_index_15 = Recoil_index.useRecoilStateLoadable;
7938 var Recoil_index_16 = Recoil_index.useSetRecoilState;
7939 var Recoil_index_17 = Recoil_index.useResetRecoilState;
7940 var Recoil_index_18 = Recoil_index.useGetRecoilValueInfo_UNSTABLE;
7941 var Recoil_index_19 = Recoil_index.useRetain;
7942 var Recoil_index_20 = Recoil_index.useRecoilCallback;
7943 var Recoil_index_21 = Recoil_index.useRecoilTransaction_UNSTABLE;
7944 var Recoil_index_22 = Recoil_index.useGotoRecoilSnapshot;
7945 var Recoil_index_23 = Recoil_index.useRecoilSnapshot;
7946 var Recoil_index_24 = Recoil_index.useRecoilTransactionObserver_UNSTABLE;
7947 var Recoil_index_25 = Recoil_index.useTransactionObservation_UNSTABLE;
7948 var Recoil_index_26 = Recoil_index.useSetUnvalidatedAtomValues_UNSTABLE;
7949 var Recoil_index_27 = Recoil_index.noWait;
7950 var Recoil_index_28 = Recoil_index.waitForNone;
7951 var Recoil_index_29 = Recoil_index.waitForAny;
7952 var Recoil_index_30 = Recoil_index.waitForAll;
7953 var Recoil_index_31 = Recoil_index.waitForAllSettled;
7954 var Recoil_index_32 = Recoil_index.isRecoilValue;
7955 var Recoil_index_33 = Recoil_index.batchUpdates;
7956 var Recoil_index_34 = Recoil_index.setBatcher;
7957 var Recoil_index_35 = Recoil_index.snapshot_UNSTABLE;
7958
7959 exports.DefaultValue = Recoil_index_1;
7960 exports.RecoilRoot = Recoil_index_2;
7961 exports.atom = Recoil_index_4;
7962 exports.atomFamily = Recoil_index_7;
7963 exports.batchUpdates = Recoil_index_33;
7964 exports.constSelector = Recoil_index_9;
7965 exports.default = Recoil_index;
7966 exports.errorSelector = Recoil_index_10;
7967 exports.isRecoilValue = Recoil_index_32;
7968 exports.noWait = Recoil_index_27;
7969 exports.readOnlySelector = Recoil_index_11;
7970 exports.retentionZone = Recoil_index_6;
7971 exports.selector = Recoil_index_5;
7972 exports.selectorFamily = Recoil_index_8;
7973 exports.setBatcher = Recoil_index_34;
7974 exports.snapshot_UNSTABLE = Recoil_index_35;
7975 exports.useGetRecoilValueInfo_UNSTABLE = Recoil_index_18;
7976 exports.useGotoRecoilSnapshot = Recoil_index_22;
7977 exports.useRecoilBridgeAcrossReactRoots_UNSTABLE = Recoil_index_3;
7978 exports.useRecoilCallback = Recoil_index_20;
7979 exports.useRecoilSnapshot = Recoil_index_23;
7980 exports.useRecoilState = Recoil_index_14;
7981 exports.useRecoilStateLoadable = Recoil_index_15;
7982 exports.useRecoilTransactionObserver_UNSTABLE = Recoil_index_24;
7983 exports.useRecoilTransaction_UNSTABLE = Recoil_index_21;
7984 exports.useRecoilValue = Recoil_index_12;
7985 exports.useRecoilValueLoadable = Recoil_index_13;
7986 exports.useResetRecoilState = Recoil_index_17;
7987 exports.useRetain = Recoil_index_19;
7988 exports.useSetRecoilState = Recoil_index_16;
7989 exports.useSetUnvalidatedAtomValues_UNSTABLE = Recoil_index_26;
7990 exports.useTransactionObservation_UNSTABLE = Recoil_index_25;
7991 exports.waitForAll = Recoil_index_30;
7992 exports.waitForAllSettled = Recoil_index_31;
7993 exports.waitForAny = Recoil_index_29;
7994 exports.waitForNone = Recoil_index_28;
7995
7996 Object.defineProperty(exports, '__esModule', { value: true });
7997
7998})));