UNPKG

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