UNPKG

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