UNPKG

181 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 reactDom = _interopDefault(require('react-dom'));
8var react = _interopDefault(require('react'));
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
21const gks = new Map();
22
23function Recoil_gkx(gk) {
24 var _gks$get;
25
26 return (_gks$get = gks.get(gk)) !== null && _gks$get !== void 0 ? _gks$get : false;
27}
28
29Recoil_gkx.setPass = gk => {
30 gks.set(gk, true);
31};
32
33Recoil_gkx.setFail = gk => {
34 gks.set(gk, false);
35};
36
37var Recoil_gkx_1 = Recoil_gkx; // @oss-only
38
39/**
40 * Copyright (c) Facebook, Inc. and its affiliates.
41 *
42 * This source code is licensed under the MIT license found in the
43 * LICENSE file in the root directory of this source tree.
44 *
45 * @emails oncall+recoil
46 *
47 * @format
48 */
49/**
50 * Returns a new Map object with the same keys as the original, but with the
51 * values replaced with the output of the given callback function.
52 */
53
54function mapMap(map, callback) {
55 const result = new Map();
56 map.forEach((value, key) => {
57 result.set(key, callback(value, key));
58 });
59 return result;
60}
61
62var Recoil_mapMap = mapMap;
63
64/**
65 * Copyright (c) Facebook, Inc. and its affiliates.
66 *
67 * This source code is licensed under the MIT license found in the
68 * LICENSE file in the root directory of this source tree.
69 *
70 * @emails oncall+recoil
71 *
72 * @format
73 */
74
75function nullthrows(x, message) {
76 if (x != null) {
77 return x;
78 }
79
80 throw new Error(message !== null && message !== void 0 ? message : 'Got unexpected null or undefined');
81}
82
83var Recoil_nullthrows = nullthrows;
84
85/**
86 * Copyright (c) Facebook, Inc. and its affiliates.
87 *
88 * This source code is licensed under the MIT license found in the
89 * LICENSE file in the root directory of this source tree.
90 *
91 * @emails oncall+recoil
92 *
93 * @format
94 */
95
96function recoverableViolation(message, projectName, {
97 error
98} = {}) {
99 if (process.env.NODE_ENV !== "production") {
100 console.error(message, error);
101 }
102
103 return null;
104}
105
106var recoverableViolation_1 = recoverableViolation;
107
108// @oss-only
109
110
111var Recoil_recoverableViolation = recoverableViolation_1;
112
113/**
114 * Copyright (c) Facebook, Inc. and its affiliates.
115 *
116 * This source code is licensed under the MIT license found in the
117 * LICENSE file in the root directory of this source tree.
118 *
119 * Interface for `scheduler/tracing` to aid in profiling Recoil and Recoil apps.
120 *
121 * @emails oncall+recoil
122 *
123 * @format
124 */
125
126// flowlint-next-line untyped-import:off
127// @fb-only: const SchedulerTracing = require('SchedulerTracing');
128function trace(message, node, fn) {
129 // prettier-ignore
130 // @fb-only: if (__DEV__) {
131 // prettier-ignore
132 // @fb-only: if (
133 // prettier-ignore
134 // @fb-only: SchedulerTracing.unstable_trace !== undefined &&
135 // prettier-ignore
136 // @fb-only: window.performance !== undefined
137 // prettier-ignore
138 // @fb-only: ) {
139 // prettier-ignore
140 // @fb-only: return SchedulerTracing.unstable_trace(
141 // prettier-ignore
142 // @fb-only: `Recoil: ${message} for node: ${
143 // prettier-ignore
144 // @fb-only: typeof node === 'string' ? node : node.key
145 // prettier-ignore
146 // @fb-only: }`,
147 // prettier-ignore
148 // @fb-only: window.performance.now(),
149 // prettier-ignore
150 // @fb-only: fn,
151 // prettier-ignore
152 // @fb-only: );
153 // prettier-ignore
154 // @fb-only: }
155 // prettier-ignore
156 // @fb-only: }
157 return fn();
158}
159
160function wrap(fn) {
161 // prettier-ignore
162 // @fb-only: if (__DEV__) {
163 // prettier-ignore
164 // @fb-only: if (SchedulerTracing.unstable_wrap !== undefined) {
165 // prettier-ignore
166 // @fb-only: return SchedulerTracing.unstable_wrap(fn);
167 // prettier-ignore
168 // @fb-only: }
169 // prettier-ignore
170 // @fb-only: }
171 return fn;
172}
173
174var Recoil_Tracing = {
175 trace,
176 wrap
177};
178
179/**
180 * Copyright (c) Facebook, Inc. and its affiliates.
181 *
182 * This source code is licensed under the MIT license found in the
183 * LICENSE file in the root directory of this source tree.
184 *
185 * Utilities for working with built-in Maps and Sets without mutating them.
186 *
187 * @emails oncall+recoil
188 *
189 * @format
190 */
191
192function setByAddingToSet(set, v) {
193 const next = new Set(set);
194 next.add(v);
195 return next;
196}
197
198function setByDeletingFromSet(set, v) {
199 const next = new Set(set);
200 next.delete(v);
201 return next;
202}
203
204function mapBySettingInMap(map, k, v) {
205 const next = new Map(map);
206 next.set(k, v);
207 return next;
208}
209
210function mapByUpdatingInMap(map, k, updater) {
211 const next = new Map(map);
212 next.set(k, updater(next.get(k)));
213 return next;
214}
215
216function mapByDeletingFromMap(map, k) {
217 const next = new Map(map);
218 next.delete(k);
219 return next;
220}
221
222function mapByDeletingMultipleFromMap(map, ks) {
223 const next = new Map(map);
224 ks.forEach(k => next.delete(k));
225 return next;
226}
227
228var Recoil_CopyOnWrite = {
229 setByAddingToSet,
230 setByDeletingFromSet,
231 mapBySettingInMap,
232 mapByUpdatingInMap,
233 mapByDeletingFromMap,
234 mapByDeletingMultipleFromMap
235};
236
237/**
238 * Copyright (c) Facebook, Inc. and its affiliates.
239 *
240 * This source code is licensed under the MIT license found in the
241 * LICENSE file in the root directory of this source tree.
242 *
243 * @emails oncall+recoil
244 *
245 * @format
246 */
247
248function sprintf(format, ...args) {
249 let index = 0;
250 return format.replace(/%s/g, () => String(args[index++]));
251}
252
253var sprintf_1 = sprintf;
254
255function expectationViolation(format, ...args) {
256 if (process.env.NODE_ENV !== "production") {
257 const message = sprintf_1.call(null, format, ...args);
258 const error = new Error(message);
259 error.name = 'Expectation Violation';
260 console.error(error);
261 }
262}
263
264var expectationViolation_1 = expectationViolation;
265
266// @oss-only
267
268
269var Recoil_expectationViolation = expectationViolation_1;
270
271function _defineProperty(obj, key, value) {
272 if (key in obj) {
273 Object.defineProperty(obj, key, {
274 value: value,
275 enumerable: true,
276 configurable: true,
277 writable: true
278 });
279 } else {
280 obj[key] = value;
281 }
282
283 return obj;
284}
285
286/**
287 * Copyright (c) Facebook, Inc. and its affiliates.
288 *
289 * This source code is licensed under the MIT license found in the
290 * LICENSE file in the root directory of this source tree.
291 *
292 * @emails oncall+recoil
293 *
294 * @format
295 */
296
297// eslint-disable-next-line no-unused-vars
298class AbstractRecoilValue {
299 constructor(newKey) {
300 _defineProperty(this, "key", void 0);
301
302 this.key = newKey;
303 }
304
305}
306
307class RecoilState extends AbstractRecoilValue {}
308
309class RecoilValueReadOnly extends AbstractRecoilValue {}
310
311function isRecoilValue(x) {
312 return x instanceof RecoilState || x instanceof RecoilValueReadOnly;
313}
314
315var Recoil_RecoilValue = {
316 AbstractRecoilValue,
317 RecoilState,
318 RecoilValueReadOnly,
319 isRecoilValue
320};
321
322var Recoil_RecoilValue_1 = Recoil_RecoilValue.AbstractRecoilValue;
323var Recoil_RecoilValue_2 = Recoil_RecoilValue.RecoilState;
324var Recoil_RecoilValue_3 = Recoil_RecoilValue.RecoilValueReadOnly;
325var Recoil_RecoilValue_4 = Recoil_RecoilValue.isRecoilValue;
326
327var Recoil_RecoilValue$1 = /*#__PURE__*/Object.freeze({
328 __proto__: null,
329 AbstractRecoilValue: Recoil_RecoilValue_1,
330 RecoilState: Recoil_RecoilValue_2,
331 RecoilValueReadOnly: Recoil_RecoilValue_3,
332 isRecoilValue: Recoil_RecoilValue_4
333});
334
335class DefaultValue {}
336
337const DEFAULT_VALUE = new DefaultValue();
338
339class RecoilValueNotReady extends Error {
340 constructor(key) {
341 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.`);
342 }
343
344}
345
346// flowlint-next-line unclear-type:off
347const nodes = new Map(); // flowlint-next-line unclear-type:off
348
349const recoilValues = new Map();
350/* eslint-disable no-redeclare */
351
352function registerNode(node) {
353 if (nodes.has(node.key)) {
354 const message = `Duplicate atom key "${node.key}". This is a FATAL ERROR in
355 production. But it is safe to ignore this warning if it occurred because of
356 hot module replacement.`; // TODO Need to figure out if there is a standard/open-source equivalent to see if hot module replacement is happening:
357 // prettier-ignore
358 // @fb-only: if (__DEV__) {
359 // @fb-only: const isAcceptingUpdate = require('__debug').isAcceptingUpdate;
360 // prettier-ignore
361 // @fb-only: if (typeof isAcceptingUpdate !== 'function' || !isAcceptingUpdate()) {
362 // @fb-only: expectationViolation(message, 'recoil');
363 // @fb-only: }
364 // prettier-ignore
365 // @fb-only: } else {
366 // @fb-only: recoverableViolation(message, 'recoil');
367 // @fb-only: }
368
369 console.warn(message); // @oss-only
370 }
371
372 nodes.set(node.key, node);
373 const recoilValue = node.set == null ? new Recoil_RecoilValue$1.RecoilValueReadOnly(node.key) : new Recoil_RecoilValue$1.RecoilState(node.key);
374 recoilValues.set(node.key, recoilValue);
375 return recoilValue;
376}
377/* eslint-enable no-redeclare */
378
379
380class NodeMissingError extends Error {} // flowlint-next-line unclear-type:off
381
382
383function getNode(key) {
384 const node = nodes.get(key);
385
386 if (node == null) {
387 throw new NodeMissingError(`Missing definition for RecoilValue: "${key}""`);
388 }
389
390 return node;
391} // flowlint-next-line unclear-type:off
392
393
394function getNodeMaybe(key) {
395 return nodes.get(key);
396}
397
398var Recoil_Node = {
399 nodes,
400 recoilValues,
401 registerNode,
402 getNode,
403 getNodeMaybe,
404 NodeMissingError,
405 DefaultValue,
406 DEFAULT_VALUE,
407 RecoilValueNotReady
408};
409
410const {
411 mapByDeletingFromMap: mapByDeletingFromMap$1,
412 mapBySettingInMap: mapBySettingInMap$1,
413 setByAddingToSet: setByAddingToSet$1
414} = Recoil_CopyOnWrite;
415
416const {
417 getNode: getNode$1,
418 getNodeMaybe: getNodeMaybe$1
419} = Recoil_Node; // flowlint-next-line unclear-type:off
420
421
422const emptySet = Object.freeze(new Set());
423
424class ReadOnlyRecoilValueError extends Error {} // Get the current value loadable of a node and update the state.
425// Update dependencies and subscriptions for selectors.
426// Update saved value validation for atoms.
427
428
429function getNodeLoadable(store, state, key) {
430 return getNode$1(key).get(store, state);
431} // Peek at the current value loadable for a node without any evaluation or state change
432
433
434function peekNodeLoadable(store, state, key) {
435 return getNode$1(key).peek(store, state);
436} // Write value directly to state bypassing the Node interface as the node
437// definitions may not have been loaded yet when processing the initial snapshot.
438
439
440function setUnvalidatedAtomValue_DEPRECATED(state, key, newValue) {
441 var _node$invalidate;
442
443 const node = getNodeMaybe$1(key);
444 node === null || node === void 0 ? void 0 : (_node$invalidate = node.invalidate) === null || _node$invalidate === void 0 ? void 0 : _node$invalidate.call(node, state);
445 return { ...state,
446 atomValues: mapByDeletingFromMap$1(state.atomValues, key),
447 nonvalidatedAtoms: mapBySettingInMap$1(state.nonvalidatedAtoms, key, newValue),
448 dirtyAtoms: setByAddingToSet$1(state.dirtyAtoms, key)
449 };
450} // Return the discovered dependencies and values to be written by setting
451// a node value. (Multiple values may be written due to selectors getting to
452// set upstreams; deps may be discovered because of reads in updater functions.)
453
454
455function setNodeValue(store, state, key, newValue) {
456 const node = getNode$1(key);
457
458 if (node.set == null) {
459 throw new ReadOnlyRecoilValueError(`Attempt to set read-only RecoilValue: ${key}`);
460 }
461
462 return node.set(store, state, newValue);
463}
464
465function cleanUpNode(store, key) {
466 const node = getNode$1(key);
467 node.cleanUp(store);
468} // Find all of the recursively dependent nodes
469
470
471function getDownstreamNodes(store, state, keys) {
472 const visitedNodes = new Set();
473 const visitingNodes = Array.from(keys);
474 const graph = store.getGraph(state.version);
475
476 for (let key = visitingNodes.pop(); key; key = visitingNodes.pop()) {
477 var _graph$nodeToNodeSubs;
478
479 visitedNodes.add(key);
480 const subscribedNodes = (_graph$nodeToNodeSubs = graph.nodeToNodeSubscriptions.get(key)) !== null && _graph$nodeToNodeSubs !== void 0 ? _graph$nodeToNodeSubs : emptySet;
481
482 for (const downstreamNode of subscribedNodes) {
483 if (!visitedNodes.has(downstreamNode)) {
484 visitingNodes.push(downstreamNode);
485 }
486 }
487 }
488
489 return visitedNodes;
490}
491
492var Recoil_FunctionalCore = {
493 getNodeLoadable,
494 peekNodeLoadable,
495 setNodeValue,
496 cleanUpNode,
497 setUnvalidatedAtomValue_DEPRECATED,
498 getDownstreamNodes
499};
500
501/**
502 * Copyright (c) Facebook, Inc. and its affiliates.
503 *
504 * This source code is licensed under the MIT license found in the
505 * LICENSE file in the root directory of this source tree.
506 *
507 * @emails oncall+recoil
508 *
509 * @format
510 */
511/**
512 * Returns a set containing all of the values from the first set that are not
513 * present in any of the subsequent sets.
514 *
515 * Note: this is written procedurally (i.e., without filterSet) for performant
516 * use in tight loops.
517 */
518
519function differenceSets(set, ...setsWithValuesToRemove) {
520 const ret = new Set();
521
522 FIRST: for (const value of set) {
523 for (const otherSet of setsWithValuesToRemove) {
524 if (otherSet.has(value)) {
525 continue FIRST;
526 }
527 }
528
529 ret.add(value);
530 }
531
532 return ret;
533}
534
535var Recoil_differenceSets = differenceSets;
536
537function graph() {
538 return {
539 nodeDeps: new Map(),
540 nodeToNodeSubscriptions: new Map()
541 };
542}
543
544function cloneGraph(graph) {
545 return {
546 nodeDeps: Recoil_mapMap(graph.nodeDeps, s => new Set(s)),
547 nodeToNodeSubscriptions: Recoil_mapMap(graph.nodeToNodeSubscriptions, s => new Set(s))
548 };
549} // Note that this overwrites the deps of existing nodes, rather than unioning
550// the new deps with the old deps.
551
552
553function mergeDependencyMapIntoGraph(deps, graph, // If olderGraph is given then we will not overwrite changes made to the given
554// graph compared with olderGraph:
555olderGraph) {
556 const {
557 nodeDeps,
558 nodeToNodeSubscriptions
559 } = graph;
560 deps.forEach((upstreams, downstream) => {
561 const existingUpstreams = nodeDeps.get(downstream);
562
563 if (existingUpstreams && olderGraph && existingUpstreams !== olderGraph.nodeDeps.get(downstream)) {
564 return;
565 } // Update nodeDeps:
566
567
568 nodeDeps.set(downstream, new Set(upstreams)); // Add new deps to nodeToNodeSubscriptions:
569
570 const addedUpstreams = existingUpstreams == null ? upstreams : Recoil_differenceSets(upstreams, existingUpstreams);
571 addedUpstreams.forEach(upstream => {
572 if (!nodeToNodeSubscriptions.has(upstream)) {
573 nodeToNodeSubscriptions.set(upstream, new Set());
574 }
575
576 const existing = Recoil_nullthrows(nodeToNodeSubscriptions.get(upstream));
577 existing.add(downstream);
578 }); // Remove removed deps from nodeToNodeSubscriptions:
579
580 if (existingUpstreams) {
581 const removedUpstreams = Recoil_differenceSets(existingUpstreams, upstreams);
582 removedUpstreams.forEach(upstream => {
583 if (!nodeToNodeSubscriptions.has(upstream)) {
584 return;
585 }
586
587 const existing = Recoil_nullthrows(nodeToNodeSubscriptions.get(upstream));
588 existing.delete(downstream);
589
590 if (existing.size === 0) {
591 nodeToNodeSubscriptions.delete(upstream);
592 }
593 });
594 }
595 });
596}
597
598function saveDependencyMapToStore(dependencyMap, store, version) {
599 var _storeState$nextTree, _storeState$previousT, _storeState$previousT2, _storeState$previousT3;
600
601 const storeState = store.getState();
602
603 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))) {
604 Recoil_recoverableViolation('Tried to save dependencies to a discarded tree');
605 } // Merge the dependencies discovered into the store's dependency map
606 // for the version that was read:
607
608
609 const graph = store.getGraph(version);
610 mergeDependencyMapIntoGraph(dependencyMap, graph); // If this version is not the latest version, also write these dependencies
611 // into later versions if they don't already have their own:
612
613 if (version === ((_storeState$previousT2 = storeState.previousTree) === null || _storeState$previousT2 === void 0 ? void 0 : _storeState$previousT2.version)) {
614 const currentGraph = store.getGraph(storeState.currentTree.version);
615 mergeDependencyMapIntoGraph(dependencyMap, currentGraph, graph);
616 }
617
618 if (version === ((_storeState$previousT3 = storeState.previousTree) === null || _storeState$previousT3 === void 0 ? void 0 : _storeState$previousT3.version) || version === storeState.currentTree.version) {
619 var _storeState$nextTree2;
620
621 const nextVersion = (_storeState$nextTree2 = storeState.nextTree) === null || _storeState$nextTree2 === void 0 ? void 0 : _storeState$nextTree2.version;
622
623 if (nextVersion !== undefined) {
624 const nextGraph = store.getGraph(nextVersion);
625 mergeDependencyMapIntoGraph(dependencyMap, nextGraph, graph);
626 }
627 }
628}
629
630function mergeDepsIntoDependencyMap(from, into) {
631 from.forEach((upstreamDeps, downstreamNode) => {
632 if (!into.has(downstreamNode)) {
633 into.set(downstreamNode, new Set());
634 }
635
636 const deps = Recoil_nullthrows(into.get(downstreamNode));
637 upstreamDeps.forEach(dep => deps.add(dep));
638 });
639}
640
641function addToDependencyMap(downstream, upstream, dependencyMap) {
642 if (!dependencyMap.has(downstream)) {
643 dependencyMap.set(downstream, new Set());
644 }
645
646 Recoil_nullthrows(dependencyMap.get(downstream)).add(upstream);
647}
648
649var Recoil_Graph = {
650 addToDependencyMap,
651 cloneGraph,
652 graph,
653 mergeDepsIntoDependencyMap,
654 saveDependencyMapToStore
655};
656
657const {
658 getDownstreamNodes: getDownstreamNodes$1,
659 getNodeLoadable: getNodeLoadable$1,
660 setNodeValue: setNodeValue$1
661} = Recoil_FunctionalCore;
662
663const {
664 saveDependencyMapToStore: saveDependencyMapToStore$1
665} = Recoil_Graph;
666
667const {
668 getNodeMaybe: getNodeMaybe$2
669} = Recoil_Node;
670
671const {
672 DefaultValue: DefaultValue$1,
673 RecoilValueNotReady: RecoilValueNotReady$1
674} = Recoil_Node;
675
676const {
677 AbstractRecoilValue: AbstractRecoilValue$1,
678 RecoilState: RecoilState$1,
679 RecoilValueReadOnly: RecoilValueReadOnly$1,
680 isRecoilValue: isRecoilValue$1
681} = Recoil_RecoilValue$1;
682
683function getRecoilValueAsLoadable(store, {
684 key
685}, treeState = store.getState().currentTree) {
686 var _storeState$nextTree, _storeState$previousT;
687
688 // Reading from an older tree can cause bugs because the dependencies that we
689 // discover during the read are lost.
690 const storeState = store.getState();
691
692 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))) {
693 Recoil_recoverableViolation('Tried to read from a discarded tree');
694 }
695
696 const [dependencyMap, loadable] = getNodeLoadable$1(store, treeState, key);
697
698 if (!Recoil_gkx_1('recoil_async_selector_refactor')) {
699 /**
700 * In selector_NEW, we take care of updating state deps within the selector
701 */
702 saveDependencyMapToStore$1(dependencyMap, store, treeState.version);
703 }
704
705 return loadable;
706}
707
708function applyAtomValueWrites(atomValues, writes) {
709 const result = Recoil_mapMap(atomValues, v => v);
710 writes.forEach((v, k) => {
711 if (v.state === 'hasValue' && v.contents instanceof DefaultValue$1) {
712 result.delete(k);
713 } else {
714 result.set(k, v);
715 }
716 });
717 return result;
718}
719
720function valueFromValueOrUpdater(store, state, {
721 key
722}, valueOrUpdater) {
723 if (typeof valueOrUpdater === 'function') {
724 // Updater form: pass in the current value. Throw if the current value
725 // is unavailable (namely when updating an async selector that's
726 // pending or errored):
727 // NOTE: This will evaluate node, but not update state with node subscriptions!
728 const current = getNodeLoadable$1(store, state, key)[1];
729
730 if (current.state === 'loading') {
731 throw new RecoilValueNotReady$1(key);
732 } else if (current.state === 'hasError') {
733 throw current.contents;
734 } // T itself may be a function, so our refinement is not sufficient:
735
736
737 return valueOrUpdater(current.contents); // flowlint-line unclear-type:off
738 } else {
739 return valueOrUpdater;
740 }
741}
742
743function applyAction(store, state, action) {
744 if (action.type === 'set') {
745 const {
746 recoilValue,
747 valueOrUpdater
748 } = action;
749 const newValue = valueFromValueOrUpdater(store, state, recoilValue, valueOrUpdater);
750 const [depMap, writes] = setNodeValue$1(store, state, recoilValue.key, newValue);
751 saveDependencyMapToStore$1(depMap, store, state.version);
752
753 for (const [key, loadable] of writes.entries()) {
754 writeLoadableToTreeState(state, key, loadable);
755 }
756 } else if (action.type === 'setLoadable') {
757 const {
758 recoilValue: {
759 key
760 },
761 loadable
762 } = action;
763 writeLoadableToTreeState(state, key, loadable);
764 } else if (action.type === 'markModified') {
765 const {
766 recoilValue: {
767 key
768 }
769 } = action;
770 state.dirtyAtoms.add(key);
771 } else if (action.type === 'setUnvalidated') {
772 var _node$invalidate;
773
774 // Write value directly to state bypassing the Node interface as the node
775 // definitions may not have been loaded yet when processing the initial snapshot.
776 const {
777 recoilValue: {
778 key
779 },
780 unvalidatedValue
781 } = action;
782 const node = getNodeMaybe$2(key);
783 node === null || node === void 0 ? void 0 : (_node$invalidate = node.invalidate) === null || _node$invalidate === void 0 ? void 0 : _node$invalidate.call(node, state);
784 state.atomValues.delete(key);
785 state.nonvalidatedAtoms.set(key, unvalidatedValue);
786 state.dirtyAtoms.add(key);
787 } else {
788 Recoil_recoverableViolation(`Unknown action ${action.type}`);
789 }
790}
791
792function writeLoadableToTreeState(state, key, loadable) {
793 if (loadable.state === 'hasValue' && loadable.contents instanceof DefaultValue$1) {
794 state.atomValues.delete(key);
795 } else {
796 state.atomValues.set(key, loadable);
797 }
798
799 state.dirtyAtoms.add(key);
800 state.nonvalidatedAtoms.delete(key);
801}
802
803function applyActionsToStore(store, actions) {
804 store.replaceState(state => {
805 const newState = copyTreeState(state);
806
807 for (const action of actions) {
808 applyAction(store, newState, action);
809 }
810
811 invalidateDownstreams(store, newState);
812 return newState;
813 });
814}
815
816function queueOrPerformStateUpdate(store, action, key, message) {
817 if (batchStack.length) {
818 const actionsByStore = batchStack[batchStack.length - 1];
819 let actions = actionsByStore.get(store);
820
821 if (!actions) {
822 actionsByStore.set(store, actions = []);
823 }
824
825 actions.push(action);
826 } else {
827 Recoil_Tracing.trace(message, key, () => applyActionsToStore(store, [action]));
828 }
829}
830
831const batchStack = [];
832
833function batchStart() {
834 const actionsByStore = new Map();
835 batchStack.push(actionsByStore);
836 return () => {
837 for (const [store, actions] of actionsByStore) {
838 Recoil_Tracing.trace('Recoil batched updates', '-', () => applyActionsToStore(store, actions));
839 }
840
841 const popped = batchStack.pop();
842
843 if (popped !== actionsByStore) {
844 Recoil_recoverableViolation('Incorrect order of batch popping');
845 }
846 };
847}
848
849function copyTreeState(state) {
850 return { ...state,
851 atomValues: new Map(state.atomValues),
852 nonvalidatedAtoms: new Map(state.nonvalidatedAtoms),
853 dirtyAtoms: new Set(state.dirtyAtoms)
854 };
855}
856
857function invalidateDownstreams(store, state) {
858 // Inform any nodes that were changed or downstream of changes so that they
859 // can clear out any caches as needed due to the update:
860 const downstreams = getDownstreamNodes$1(store, state, state.dirtyAtoms);
861
862 for (const key of downstreams) {
863 var _getNodeMaybe, _getNodeMaybe$invalid;
864
865 (_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);
866 }
867}
868
869function setRecoilValue(store, recoilValue, valueOrUpdater) {
870 queueOrPerformStateUpdate(store, {
871 type: 'set',
872 recoilValue,
873 valueOrUpdater
874 }, recoilValue.key, 'set Recoil value');
875}
876
877function setRecoilValueLoadable(store, recoilValue, loadable) {
878 if (loadable instanceof DefaultValue$1) {
879 return setRecoilValue(store, recoilValue, loadable);
880 }
881
882 queueOrPerformStateUpdate(store, {
883 type: 'setLoadable',
884 recoilValue,
885 loadable
886 }, recoilValue.key, 'set Recoil value');
887}
888
889function markRecoilValueModified(store, recoilValue) {
890 queueOrPerformStateUpdate(store, {
891 type: 'markModified',
892 recoilValue
893 }, recoilValue.key, 'mark RecoilValue modified');
894}
895
896function setUnvalidatedRecoilValue(store, recoilValue, unvalidatedValue) {
897 queueOrPerformStateUpdate(store, {
898 type: 'setUnvalidated',
899 recoilValue,
900 unvalidatedValue
901 }, recoilValue.key, 'set Recoil value');
902}
903
904let subscriptionID = 0;
905
906function subscribeToRecoilValue(store, {
907 key
908}, callback, componentDebugName = null) {
909 const subID = subscriptionID++;
910 const storeState = store.getState();
911
912 if (!storeState.nodeToComponentSubscriptions.has(key)) {
913 storeState.nodeToComponentSubscriptions.set(key, new Map());
914 }
915
916 Recoil_nullthrows(storeState.nodeToComponentSubscriptions.get(key)).set(subID, [componentDebugName !== null && componentDebugName !== void 0 ? componentDebugName : '<not captured>', callback]);
917 return {
918 release: () => {
919 const storeState = store.getState();
920 const subs = storeState.nodeToComponentSubscriptions.get(key);
921
922 if (subs === undefined || !subs.has(subID)) {
923 Recoil_recoverableViolation(`Subscription missing at release time for atom ${key}. This is a bug in Recoil.`);
924 return;
925 }
926
927 subs.delete(subID);
928
929 if (subs.size === 0) {
930 storeState.nodeToComponentSubscriptions.delete(key);
931 }
932 }
933 };
934}
935
936var Recoil_RecoilValueInterface = {
937 RecoilValueReadOnly: RecoilValueReadOnly$1,
938 AbstractRecoilValue: AbstractRecoilValue$1,
939 RecoilState: RecoilState$1,
940 getRecoilValueAsLoadable,
941 setRecoilValue,
942 setRecoilValueLoadable,
943 markRecoilValueModified,
944 setUnvalidatedRecoilValue,
945 subscribeToRecoilValue,
946 isRecoilValue: isRecoilValue$1,
947 applyAtomValueWrites,
948 // TODO Remove export when deprecating initialStoreState_DEPRECATED in RecoilRoot
949 batchStart,
950 invalidateDownstreams_FOR_TESTING: invalidateDownstreams
951};
952
953/**
954 * Copyright (c) Facebook, Inc. and its affiliates.
955 *
956 * This source code is licensed under the MIT license found in the
957 * LICENSE file in the root directory of this source tree.
958 *
959 * @emails oncall+recoil
960 *
961 * @format
962 *
963 * This is to export esstiential functions from react-dom
964 * for our web build
965 */
966const {
967 unstable_batchedUpdates
968} = reactDom; // @oss-only
969// @fb-only: const {unstable_batchedUpdates} = require('ReactDOMComet');
970
971
972var Recoil_ReactBatchedUpdates = {
973 unstable_batchedUpdates
974};
975
976/**
977 * Copyright (c) Facebook, Inc. and its affiliates.
978 *
979 * This source code is licensed under the MIT license found in the
980 * LICENSE file in the root directory of this source tree.
981 *
982 * @emails oncall+recoil
983 *
984 * @format
985 */
986const {
987 batchStart: batchStart$1
988} = Recoil_RecoilValueInterface;
989
990const {
991 unstable_batchedUpdates: unstable_batchedUpdates$1
992} = Recoil_ReactBatchedUpdates;
993
994let batcher = unstable_batchedUpdates$1; // flowlint-next-line unclear-type:off
995
996/**
997 * Sets the provided batcher function as the batcher function used by Recoil.
998 *
999 * Set the batcher to a custom batcher for your renderer,
1000 * if you use a renderer other than React DOM or React Native.
1001 */
1002const setBatcher = newBatcher => {
1003 batcher = newBatcher;
1004};
1005/**
1006 * Returns the current batcher function.
1007 */
1008
1009
1010const getBatcher = () => batcher;
1011/**
1012 * Calls the current batcher function and passes the
1013 * provided callback function.
1014 */
1015
1016
1017const batchUpdates = callback => {
1018 batcher(() => {
1019 let batchEnd = () => undefined;
1020
1021 try {
1022 batchEnd = batchStart$1();
1023 callback();
1024 } finally {
1025 batchEnd();
1026 }
1027 });
1028};
1029
1030var Recoil_Batching = {
1031 getBatcher,
1032 setBatcher,
1033 batchUpdates
1034};
1035
1036/**
1037 * Copyright (c) Facebook, Inc. and its affiliates.
1038 *
1039 * This source code is licensed under the MIT license found in the
1040 * LICENSE file in the root directory of this source tree.
1041 *
1042 * @emails oncall+recoil
1043 *
1044 * @format
1045 */
1046
1047function enqueueExecution(s, f) {
1048 f();
1049}
1050
1051var Recoil_Queue = {
1052 enqueueExecution
1053};
1054
1055/**
1056 * Copyright (c) Facebook, Inc. and its affiliates.
1057 *
1058 * This source code is licensed under the MIT license found in the
1059 * LICENSE file in the root directory of this source tree.
1060 *
1061 * @emails oncall+recoil
1062 *
1063 * @format
1064 */
1065/**
1066 * Combines multiple Iterables into a single Iterable.
1067 * Traverses the input Iterables in the order provided and maintains the order
1068 * of their elements.
1069 *
1070 * Example:
1071 * ```
1072 * const r = Array.from(concatIterables(['a', 'b'], ['c'], ['d', 'e', 'f']));
1073 * r == ['a', 'b', 'c', 'd', 'e', 'f'];
1074 * ```
1075 */
1076
1077function* concatIterables(iters) {
1078 for (const iter of iters) {
1079 for (const val of iter) {
1080 yield val;
1081 }
1082 }
1083}
1084
1085var Recoil_concatIterables = concatIterables;
1086
1087/**
1088 * Copyright (c) Facebook, Inc. and its affiliates.
1089 *
1090 * This source code is licensed under the MIT license found in the
1091 * LICENSE file in the root directory of this source tree.
1092 *
1093 * @emails oncall+recoil
1094 *
1095 * @format
1096 */
1097/**
1098 * Creates a new iterable whose output is generated by passing the input
1099 * iterable's values through the filter function.
1100 */
1101
1102function* filterIterable(iterable, predicate) {
1103 // Use generator to create iterable/iterator
1104 let index = 0;
1105
1106 for (const value of iterable) {
1107 if (predicate(value, index++)) {
1108 yield value;
1109 }
1110 }
1111}
1112
1113var Recoil_filterIterable = filterIterable;
1114
1115/**
1116 * Copyright (c) Facebook, Inc. and its affiliates.
1117 *
1118 * This source code is licensed under the MIT license found in the
1119 * LICENSE file in the root directory of this source tree.
1120 *
1121 * @emails oncall+recoil
1122 *
1123 * @format
1124 */
1125/**
1126 * Creates a new iterable whose output is generated by passing the input
1127 * iterable's values through the mapper function.
1128 */
1129
1130function mapIterable(iterable, callback) {
1131 // Use generator to create iterable/iterator
1132 return function* () {
1133 let index = 0;
1134
1135 for (const value of iterable) {
1136 yield callback(value, index++);
1137 }
1138 }();
1139}
1140
1141var Recoil_mapIterable = mapIterable;
1142
1143const {
1144 graph: graph$1
1145} = Recoil_Graph; // flowlint-next-line unclear-type:off
1146
1147
1148let nextTreeStateVersion = 0;
1149
1150const getNextTreeStateVersion = () => nextTreeStateVersion++;
1151
1152function makeEmptyTreeState() {
1153 const version = getNextTreeStateVersion();
1154 return {
1155 version,
1156 stateID: version,
1157 transactionMetadata: {},
1158 dirtyAtoms: new Set(),
1159 atomValues: new Map(),
1160 nonvalidatedAtoms: new Map()
1161 };
1162}
1163
1164function makeEmptyStoreState() {
1165 const currentTree = makeEmptyTreeState();
1166 return {
1167 currentTree,
1168 nextTree: null,
1169 previousTree: null,
1170 knownAtoms: new Set(),
1171 knownSelectors: new Set(),
1172 transactionSubscriptions: new Map(),
1173 nodeTransactionSubscriptions: new Map(),
1174 nodeToComponentSubscriptions: new Map(),
1175 queuedComponentCallbacks_DEPRECATED: [],
1176 suspendedComponentResolvers: new Set(),
1177 graphsByVersion: new Map().set(currentTree.version, graph$1()),
1178 versionsUsedByComponent: new Map()
1179 };
1180}
1181
1182var Recoil_State = {
1183 makeEmptyTreeState,
1184 makeEmptyStoreState,
1185 getNextTreeStateVersion
1186};
1187
1188const {
1189 batchUpdates: batchUpdates$1
1190} = Recoil_Batching;
1191
1192const {
1193 getDownstreamNodes: getDownstreamNodes$2,
1194 peekNodeLoadable: peekNodeLoadable$1
1195} = Recoil_FunctionalCore;
1196
1197const {
1198 graph: graph$2
1199} = Recoil_Graph;
1200
1201const {
1202 DEFAULT_VALUE: DEFAULT_VALUE$1,
1203 recoilValues: recoilValues$1
1204} = Recoil_Node;
1205
1206const {
1207 getRecoilValueAsLoadable: getRecoilValueAsLoadable$1,
1208 setRecoilValue: setRecoilValue$1
1209} = Recoil_RecoilValueInterface;
1210
1211const {
1212 getNextTreeStateVersion: getNextTreeStateVersion$1,
1213 makeEmptyStoreState: makeEmptyStoreState$1
1214} = Recoil_State; // Opaque at this surface because it's part of the public API from here.
1215
1216
1217function recoilValuesForKeys(keys) {
1218 return Recoil_mapIterable(keys, key => Recoil_nullthrows(recoilValues$1.get(key)));
1219} // A "Snapshot" is "read-only" and captures a specific set of values of atoms.
1220// However, the data-flow-graph and selector values may evolve as selector
1221// evaluation functions are executed and async selectors resolve.
1222
1223
1224class Snapshot {
1225 constructor(storeState) {
1226 _defineProperty(this, "_store", void 0);
1227
1228 _defineProperty(this, "getLoadable", recoilValue => // $FlowFixMe[escaped-generic]
1229 getRecoilValueAsLoadable$1(this._store, recoilValue));
1230
1231 _defineProperty(this, "getPromise", recoilValue => // $FlowFixMe[escaped-generic]
1232 this.getLoadable(recoilValue).toPromise());
1233
1234 _defineProperty(this, "getNodes_UNSTABLE", opt => {
1235 // TODO Deal with modified selectors
1236 if ((opt === null || opt === void 0 ? void 0 : opt.isModified) === true) {
1237 if ((opt === null || opt === void 0 ? void 0 : opt.isInitialized) === false) {
1238 return [];
1239 }
1240
1241 const state = this._store.getState().currentTree;
1242
1243 return recoilValuesForKeys(state.dirtyAtoms);
1244 }
1245
1246 const knownAtoms = this._store.getState().knownAtoms;
1247
1248 const knownSelectors = this._store.getState().knownSelectors;
1249
1250 return (opt === null || opt === void 0 ? void 0 : opt.isInitialized) == null ? recoilValues$1.values() : opt.isInitialized === true ? recoilValuesForKeys(Recoil_concatIterables([this._store.getState().knownAtoms, this._store.getState().knownSelectors])) : Recoil_filterIterable(recoilValues$1.values(), ({
1251 key
1252 }) => !knownAtoms.has(key) && !knownSelectors.has(key));
1253 });
1254
1255 _defineProperty(this, "getDeps_UNSTABLE", recoilValue => {
1256 this.getLoadable(recoilValue); // Evaluate node to ensure deps are up-to-date
1257
1258 const deps = this._store.getGraph(this._store.getState().currentTree.version).nodeDeps.get(recoilValue.key);
1259
1260 return recoilValuesForKeys(deps !== null && deps !== void 0 ? deps : []);
1261 });
1262
1263 _defineProperty(this, "getSubscribers_UNSTABLE", ({
1264 key
1265 }) => {
1266 const state = this._store.getState().currentTree;
1267
1268 const downstreamNodes = Recoil_filterIterable(getDownstreamNodes$2(this._store, state, new Set([key])), nodeKey => nodeKey !== key);
1269 return {
1270 nodes: recoilValuesForKeys(downstreamNodes)
1271 };
1272 });
1273
1274 _defineProperty(this, "getInfo_UNSTABLE", recoilValue => {
1275 var _graph$nodeDeps$get;
1276
1277 const {
1278 key
1279 } = recoilValue;
1280
1281 const state = this._store.getState().currentTree;
1282
1283 const graph = this._store.getGraph(state.version);
1284
1285 const type = this._store.getState().knownAtoms.has(key) ? 'atom' : this._store.getState().knownSelectors.has(key) ? 'selector' : undefined;
1286 return {
1287 loadable: peekNodeLoadable$1(this._store, state, key),
1288 isActive: this._store.getState().knownAtoms.has(key) || this._store.getState().knownSelectors.has(key),
1289 isSet: type === 'selector' ? false : state.atomValues.has(key),
1290 isModified: state.dirtyAtoms.has(key),
1291 type,
1292 // Don't use this.getDeps() as it will evaluate the node and we are only peeking
1293 deps: recoilValuesForKeys((_graph$nodeDeps$get = graph.nodeDeps.get(key)) !== null && _graph$nodeDeps$get !== void 0 ? _graph$nodeDeps$get : []),
1294 subscribers: this.getSubscribers_UNSTABLE(recoilValue)
1295 };
1296 });
1297
1298 _defineProperty(this, "map", mapper => {
1299 const mutableSnapshot = new MutableSnapshot(this);
1300 mapper(mutableSnapshot); // if removing batchUpdates from `set` add it here
1301
1302 return cloneSnapshot(mutableSnapshot.getStore_INTERNAL());
1303 });
1304
1305 _defineProperty(this, "asyncMap", async mapper => {
1306 const mutableSnapshot = new MutableSnapshot(this);
1307 await mapper(mutableSnapshot);
1308 return cloneSnapshot(mutableSnapshot.getStore_INTERNAL());
1309 });
1310
1311 this._store = {
1312 getState: () => storeState,
1313 replaceState: replacer => {
1314 storeState.currentTree = replacer(storeState.currentTree); // no batching so nextTree is never active
1315 },
1316 getGraph: version => {
1317 const graphs = storeState.graphsByVersion;
1318
1319 if (graphs.has(version)) {
1320 return Recoil_nullthrows(graphs.get(version));
1321 }
1322
1323 const newGraph = graph$2();
1324 graphs.set(version, newGraph);
1325 return newGraph;
1326 },
1327 subscribeToTransactions: () => ({
1328 release: () => {}
1329 }),
1330 addTransactionMetadata: () => {
1331 throw new Error('Cannot subscribe to Snapshots');
1332 }
1333 };
1334 }
1335
1336 getStore_INTERNAL() {
1337 return this._store;
1338 }
1339
1340 getID() {
1341 return this.getID_INTERNAL();
1342 }
1343
1344 getID_INTERNAL() {
1345 return this._store.getState().currentTree.stateID;
1346 }
1347
1348}
1349
1350function cloneStoreState(store, treeState, bumpVersion = false) {
1351 const storeState = store.getState();
1352 const version = bumpVersion ? getNextTreeStateVersion$1() : treeState.version;
1353 return {
1354 currentTree: bumpVersion ? {
1355 // TODO snapshots shouldn't really have versions because a new version number
1356 // is always assigned when the snapshot is gone to.
1357 version,
1358 stateID: version,
1359 transactionMetadata: { ...treeState.transactionMetadata
1360 },
1361 dirtyAtoms: new Set(treeState.dirtyAtoms),
1362 atomValues: new Map(treeState.atomValues),
1363 nonvalidatedAtoms: new Map(treeState.nonvalidatedAtoms)
1364 } : treeState,
1365 nextTree: null,
1366 previousTree: null,
1367 knownAtoms: new Set(storeState.knownAtoms),
1368 // FIXME here's a copy
1369 knownSelectors: new Set(storeState.knownSelectors),
1370 // FIXME here's a copy
1371 transactionSubscriptions: new Map(),
1372 nodeTransactionSubscriptions: new Map(),
1373 nodeToComponentSubscriptions: new Map(),
1374 queuedComponentCallbacks_DEPRECATED: [],
1375 suspendedComponentResolvers: new Set(),
1376 graphsByVersion: new Map().set(version, store.getGraph(treeState.version)),
1377 versionsUsedByComponent: new Map()
1378 };
1379} // Factory to build a fresh snapshot
1380
1381
1382function freshSnapshot(initializeState) {
1383 const snapshot = new Snapshot(makeEmptyStoreState$1());
1384 return initializeState != null ? snapshot.map(initializeState) : snapshot;
1385} // Factory to clone a snapahot state
1386
1387
1388function cloneSnapshot(store, version = 'current') {
1389 const storeState = store.getState();
1390 const treeState = version === 'current' ? storeState.currentTree : Recoil_nullthrows(storeState.previousTree);
1391 return new Snapshot(cloneStoreState(store, treeState));
1392}
1393
1394class MutableSnapshot extends Snapshot {
1395 constructor(snapshot) {
1396 super(cloneStoreState(snapshot.getStore_INTERNAL(), snapshot.getStore_INTERNAL().getState().currentTree, true));
1397
1398 _defineProperty(this, "set", (recoilState, newValueOrUpdater) => {
1399 const store = this.getStore_INTERNAL(); // This batchUpdates ensures this `set` is applied immediately and you can
1400 // read the written value after calling `set`. I would like to remove this
1401 // behavior and only batch in `Snapshot.map`, but this would be a breaking
1402 // change potentially.
1403
1404 batchUpdates$1(() => {
1405 setRecoilValue$1(store, recoilState, newValueOrUpdater);
1406 });
1407 });
1408
1409 _defineProperty(this, "reset", recoilState => // See note at `set` about batched updates.
1410 batchUpdates$1(() => setRecoilValue$1(this.getStore_INTERNAL(), recoilState, DEFAULT_VALUE$1)));
1411 } // We want to allow the methods to be destructured and used as accessors
1412 // eslint-disable-next-line fb-www/extra-arrow-initializer
1413
1414
1415}
1416
1417var Recoil_Snapshot = {
1418 Snapshot,
1419 MutableSnapshot,
1420 freshSnapshot,
1421 cloneSnapshot
1422};
1423
1424var Recoil_Snapshot_1 = Recoil_Snapshot.Snapshot;
1425var Recoil_Snapshot_2 = Recoil_Snapshot.MutableSnapshot;
1426var Recoil_Snapshot_3 = Recoil_Snapshot.freshSnapshot;
1427var Recoil_Snapshot_4 = Recoil_Snapshot.cloneSnapshot;
1428
1429var Recoil_Snapshot$1 = /*#__PURE__*/Object.freeze({
1430 __proto__: null,
1431 Snapshot: Recoil_Snapshot_1,
1432 MutableSnapshot: Recoil_Snapshot_2,
1433 freshSnapshot: Recoil_Snapshot_3,
1434 cloneSnapshot: Recoil_Snapshot_4
1435});
1436
1437/**
1438 * Copyright (c) Facebook, Inc. and its affiliates.
1439 *
1440 * This source code is licensed under the MIT license found in the
1441 * LICENSE file in the root directory of this source tree.
1442 *
1443 * @emails oncall+recoil
1444 *
1445 * @format
1446 */
1447
1448function unionSets(...sets) {
1449 const result = new Set();
1450
1451 for (const set of sets) {
1452 for (const value of set) {
1453 result.add(value);
1454 }
1455 }
1456
1457 return result;
1458}
1459
1460var Recoil_unionSets = unionSets;
1461
1462const {
1463 useContext,
1464 useEffect,
1465 useMemo,
1466 useRef,
1467 useState
1468} = react; // @fb-only: const RecoilusagelogEvent = require('RecoilusagelogEvent');
1469// @fb-only: const RecoilUsageLogFalcoEvent = require('RecoilUsageLogFalcoEvent');
1470// @fb-only: const URI = require('URI');
1471
1472
1473
1474
1475const {
1476 cleanUpNode: cleanUpNode$1,
1477 getDownstreamNodes: getDownstreamNodes$3,
1478 setNodeValue: setNodeValue$2,
1479 setUnvalidatedAtomValue_DEPRECATED: setUnvalidatedAtomValue_DEPRECATED$1
1480} = Recoil_FunctionalCore;
1481
1482const {
1483 graph: graph$3,
1484 saveDependencyMapToStore: saveDependencyMapToStore$2
1485} = Recoil_Graph;
1486
1487const {
1488 cloneGraph: cloneGraph$1
1489} = Recoil_Graph;
1490
1491const {
1492 applyAtomValueWrites: applyAtomValueWrites$1
1493} = Recoil_RecoilValueInterface;
1494
1495const {
1496 freshSnapshot: freshSnapshot$1
1497} = Recoil_Snapshot$1;
1498
1499const {
1500 getNextTreeStateVersion: getNextTreeStateVersion$2,
1501 makeEmptyStoreState: makeEmptyStoreState$2
1502} = Recoil_State;
1503
1504const {
1505 mapByDeletingMultipleFromMap: mapByDeletingMultipleFromMap$1
1506} = Recoil_CopyOnWrite;
1507
1508 // @fb-only: const recoverableViolation = require('../util/Recoil_recoverableViolation');
1509
1510
1511
1512
1513 // @fb-only: const gkx = require('gkx');
1514
1515
1516function notInAContext() {
1517 throw new Error('This component must be used inside a <RecoilRoot> component.');
1518}
1519
1520const defaultStore = Object.freeze({
1521 getState: notInAContext,
1522 replaceState: notInAContext,
1523 getGraph: notInAContext,
1524 subscribeToTransactions: notInAContext,
1525 addTransactionMetadata: notInAContext
1526});
1527let stateReplacerIsBeingExecuted = false;
1528
1529function startNextTreeIfNeeded(storeState) {
1530 if (stateReplacerIsBeingExecuted) {
1531 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.');
1532 }
1533
1534 if (storeState.nextTree === null) {
1535 const version = storeState.currentTree.version;
1536 const nextVersion = getNextTreeStateVersion$2();
1537 storeState.nextTree = { ...storeState.currentTree,
1538 version: nextVersion,
1539 stateID: nextVersion,
1540 dirtyAtoms: new Set(),
1541 transactionMetadata: {}
1542 };
1543 storeState.graphsByVersion.set(nextVersion, cloneGraph$1(Recoil_nullthrows(storeState.graphsByVersion.get(version))));
1544 }
1545}
1546
1547const AppContext = react.createContext({
1548 current: defaultStore
1549});
1550
1551const useStoreRef = () => useContext(AppContext);
1552
1553const MutableSourceContext = react.createContext(null); // TODO T2710559282599660
1554
1555const useRecoilMutableSource = () => useContext(MutableSourceContext);
1556
1557function sendEndOfBatchNotifications(store) {
1558 const storeState = store.getState();
1559 const treeState = storeState.currentTree; // Inform transaction subscribers of the transaction:
1560
1561 const dirtyAtoms = treeState.dirtyAtoms;
1562
1563 if (dirtyAtoms.size) {
1564 // Execute Node-specific subscribers before global subscribers
1565 for (const [key, subscriptions] of storeState.nodeTransactionSubscriptions) {
1566 if (dirtyAtoms.has(key)) {
1567 for (const [_, subscription] of subscriptions) {
1568 subscription(store);
1569 }
1570 }
1571 }
1572
1573 for (const [_, subscription] of storeState.transactionSubscriptions) {
1574 subscription(store);
1575 } // Components that are subscribed to the dirty atom:
1576
1577
1578 const dependentNodes = getDownstreamNodes$3(store, treeState, dirtyAtoms);
1579
1580 for (const key of dependentNodes) {
1581 const comps = storeState.nodeToComponentSubscriptions.get(key);
1582
1583 if (comps) {
1584 for (const [_subID, [_debugName, callback]] of comps) {
1585 callback(treeState);
1586 }
1587 }
1588 } // Wake all suspended components so the right one(s) can try to re-render.
1589 // We need to wake up components not just when some asynchronous selector
1590 // resolved, but also when changing synchronous values because this may cause
1591 // a selector to change from asynchronous to synchronous, in which case there
1592 // would be no follow-up asynchronous resolution to wake us up.
1593 // TODO OPTIMIZATION Only wake up related downstream components
1594
1595
1596 let nodeNames = '[available in dev build]';
1597
1598 if (process.env.NODE_ENV !== "production") {
1599 nodeNames = Array.from(dirtyAtoms).join(', ');
1600 }
1601
1602 storeState.suspendedComponentResolvers.forEach(cb => Recoil_Tracing.trace('value became available, waking components', nodeNames, cb));
1603 } // Special behavior ONLY invoked by useInterface.
1604 // FIXME delete queuedComponentCallbacks_DEPRECATED when deleting useInterface.
1605
1606
1607 storeState.queuedComponentCallbacks_DEPRECATED.forEach(cb => cb(treeState));
1608 storeState.queuedComponentCallbacks_DEPRECATED.splice(0, storeState.queuedComponentCallbacks_DEPRECATED.length);
1609}
1610/*
1611 * The purpose of the Batcher is to observe when React batches end so that
1612 * Recoil state changes can be batched. Whenever Recoil state changes, we call
1613 * setState on the batcher. Then we wait for that change to be committed, which
1614 * signifies the end of the batch. That's when we respond to the Recoil change.
1615 */
1616
1617
1618function Batcher(props) {
1619 const storeRef = useStoreRef();
1620 const [_, setState] = useState([]);
1621 props.setNotifyBatcherOfChange(() => setState({}));
1622 useEffect(() => {
1623 // enqueueExecution runs this function immediately; it is only used to
1624 // manipulate the order of useEffects during tests, since React seems to
1625 // call useEffect in an unpredictable order sometimes.
1626 Recoil_Queue.enqueueExecution('Batcher', () => {
1627 const storeState = storeRef.current.getState();
1628 const {
1629 nextTree
1630 } = storeState; // Ignore commits that are not because of Recoil transactions -- namely,
1631 // because something above RecoilRoot re-rendered:
1632
1633 if (nextTree === null) {
1634 return;
1635 } // nextTree is now committed -- note that copying and reset occurs when
1636 // a transaction begins, in startNextTreeIfNeeded:
1637
1638
1639 storeState.previousTree = storeState.currentTree;
1640 storeState.currentTree = nextTree;
1641 storeState.nextTree = null;
1642 sendEndOfBatchNotifications(storeRef.current);
1643 const discardedVersion = Recoil_nullthrows(storeState.previousTree).version;
1644 storeState.graphsByVersion.delete(discardedVersion);
1645 storeState.previousTree = null;
1646 });
1647 });
1648 return null;
1649}
1650
1651if (process.env.NODE_ENV !== "production") {
1652 if (typeof window !== 'undefined' && !window.$recoilDebugStates) {
1653 window.$recoilDebugStates = [];
1654 }
1655} // When removing this deprecated function, remove stateBySettingRecoilValue
1656// which will no longer be needed.
1657
1658
1659function initialStoreState_DEPRECATED(store, initializeState) {
1660 const initial = makeEmptyStoreState$2();
1661 initializeState({
1662 // $FlowFixMe[escaped-generic]
1663 set: (atom, value) => {
1664 const state = initial.currentTree;
1665 const [depMap, writes] = setNodeValue$2(store, state, atom.key, value);
1666 const writtenNodes = new Set(writes.keys());
1667 saveDependencyMapToStore$2(depMap, store, state.version);
1668 const nonvalidatedAtoms = mapByDeletingMultipleFromMap$1(state.nonvalidatedAtoms, writtenNodes);
1669 initial.currentTree = { ...state,
1670 dirtyAtoms: Recoil_unionSets(state.dirtyAtoms, writtenNodes),
1671 atomValues: applyAtomValueWrites$1(state.atomValues, writes),
1672 // NB: PLEASE un-export applyAtomValueWrites when deleting this code
1673 nonvalidatedAtoms
1674 };
1675 },
1676 setUnvalidatedAtomValues: atomValues => {
1677 // FIXME replace this with a mutative loop
1678 atomValues.forEach((v, k) => {
1679 initial.currentTree = setUnvalidatedAtomValue_DEPRECATED$1(initial.currentTree, k, v);
1680 });
1681 }
1682 });
1683 return initial;
1684}
1685
1686function initialStoreState(initializeState) {
1687 const snapshot = freshSnapshot$1().map(initializeState);
1688 return snapshot.getStore_INTERNAL().getState();
1689}
1690
1691let nextID = 0;
1692
1693function RecoilRoot({
1694 initializeState_DEPRECATED,
1695 initializeState,
1696 store_INTERNAL: storeProp,
1697 // For use with React "context bridging"
1698 children
1699}) {
1700 var _createMutableSource;
1701
1702 // prettier-ignore
1703 // @fb-only: useEffect(() => {
1704 // @fb-only: if (gkx('recoil_usage_logging')) {
1705 // @fb-only: try {
1706 // @fb-only: RecoilUsageLogFalcoEvent.log(() => ({
1707 // @fb-only: type: RecoilusagelogEvent.RECOIL_ROOT_MOUNTED,
1708 // @fb-only: path: URI.getRequestURI().getPath(),
1709 // @fb-only: }));
1710 // @fb-only: } catch {
1711 // @fb-only: recoverableViolation(
1712 // @fb-only: 'Error when logging Recoil Usage event',
1713 // @fb-only: 'recoil',
1714 // @fb-only: );
1715 // @fb-only: }
1716 // @fb-only: }
1717 // @fb-only: }, []);
1718 let storeState; // eslint-disable-line prefer-const
1719
1720 const getGraph = version => {
1721 const graphs = storeState.current.graphsByVersion;
1722
1723 if (graphs.has(version)) {
1724 return Recoil_nullthrows(graphs.get(version));
1725 }
1726
1727 const newGraph = graph$3();
1728 graphs.set(version, newGraph);
1729 return newGraph;
1730 };
1731
1732 const subscribeToTransactions = (callback, key) => {
1733 if (key == null) {
1734 // Global transaction subscriptions
1735 const {
1736 transactionSubscriptions
1737 } = storeRef.current.getState();
1738 const id = nextID++;
1739 transactionSubscriptions.set(id, callback);
1740 return {
1741 release: () => {
1742 transactionSubscriptions.delete(id);
1743 }
1744 };
1745 } else {
1746 // Node-specific transaction subscriptions:
1747 const {
1748 nodeTransactionSubscriptions
1749 } = storeRef.current.getState();
1750
1751 if (!nodeTransactionSubscriptions.has(key)) {
1752 nodeTransactionSubscriptions.set(key, new Map());
1753 }
1754
1755 const id = nextID++;
1756 Recoil_nullthrows(nodeTransactionSubscriptions.get(key)).set(id, callback);
1757 return {
1758 release: () => {
1759 const subs = nodeTransactionSubscriptions.get(key);
1760
1761 if (subs) {
1762 subs.delete(id);
1763
1764 if (subs.size === 0) {
1765 nodeTransactionSubscriptions.delete(key);
1766 }
1767 }
1768 }
1769 };
1770 }
1771 };
1772
1773 const addTransactionMetadata = metadata => {
1774 startNextTreeIfNeeded(storeRef.current.getState());
1775
1776 for (const k of Object.keys(metadata)) {
1777 Recoil_nullthrows(storeRef.current.getState().nextTree).transactionMetadata[k] = metadata[k];
1778 }
1779 };
1780
1781 const replaceState = replacer => {
1782 const storeState = storeRef.current.getState();
1783 startNextTreeIfNeeded(storeState); // Use replacer to get the next state:
1784
1785 const nextTree = Recoil_nullthrows(storeState.nextTree);
1786 let replaced;
1787
1788 try {
1789 stateReplacerIsBeingExecuted = true;
1790 replaced = replacer(nextTree);
1791 } finally {
1792 stateReplacerIsBeingExecuted = false;
1793 }
1794
1795 if (replaced === nextTree) {
1796 return;
1797 }
1798
1799 if (process.env.NODE_ENV !== "production") {
1800 if (typeof window !== 'undefined') {
1801 window.$recoilDebugStates.push(replaced); // TODO this shouldn't happen here because it's not batched
1802 }
1803 } // Save changes to nextTree and schedule a React update:
1804
1805
1806 storeState.nextTree = replaced;
1807 Recoil_nullthrows(notifyBatcherOfChange.current)();
1808 };
1809
1810 const notifyBatcherOfChange = useRef(null);
1811
1812 function setNotifyBatcherOfChange(x) {
1813 notifyBatcherOfChange.current = x;
1814 } // FIXME T2710559282599660
1815
1816
1817 const createMutableSource = (_createMutableSource = react.createMutableSource) !== null && _createMutableSource !== void 0 ? _createMutableSource : // flowlint-line unclear-type:off
1818 react.unstable_createMutableSource; // flowlint-line unclear-type:off
1819
1820 const store = storeProp !== null && storeProp !== void 0 ? storeProp : {
1821 getState: () => storeState.current,
1822 replaceState,
1823 getGraph,
1824 subscribeToTransactions,
1825 addTransactionMetadata
1826 };
1827 const storeRef = useRef(store);
1828 storeState = useRef(initializeState_DEPRECATED != null ? initialStoreState_DEPRECATED(store, initializeState_DEPRECATED) : initializeState != null ? initialStoreState(initializeState) : makeEmptyStoreState$2());
1829 const mutableSource = useMemo(() => createMutableSource ? createMutableSource(storeState, () => storeState.current.currentTree.version) : null, [createMutableSource, storeState]); // Cleanup when the <RecoilRoot> is unmounted
1830
1831 useEffect(() => () => {
1832 for (const atomKey of storeRef.current.getState().knownAtoms) {
1833 cleanUpNode$1(storeRef.current, atomKey);
1834 }
1835 }, []);
1836 return /*#__PURE__*/react.createElement(AppContext.Provider, {
1837 value: storeRef
1838 }, /*#__PURE__*/react.createElement(MutableSourceContext.Provider, {
1839 value: mutableSource
1840 }, /*#__PURE__*/react.createElement(Batcher, {
1841 setNotifyBatcherOfChange: setNotifyBatcherOfChange
1842 }), children));
1843}
1844
1845var Recoil_RecoilRoot_react = {
1846 useStoreRef,
1847 useRecoilMutableSource,
1848 RecoilRoot,
1849 sendEndOfBatchNotifications_FOR_TESTING: sendEndOfBatchNotifications
1850};
1851
1852/**
1853 * Copyright (c) Facebook, Inc. and its affiliates.
1854 *
1855 * This source code is licensed under the MIT license found in the
1856 * LICENSE file in the root directory of this source tree.
1857 *
1858 * @emails oncall+recoil
1859 *
1860 * @format
1861 */
1862/**
1863 * Returns a map containing all of the keys + values from the original map where
1864 * the given callback returned true.
1865 */
1866
1867function filterMap(map, callback) {
1868 const result = new Map();
1869
1870 for (const [key, value] of map) {
1871 if (callback(value, key)) {
1872 result.set(key, value);
1873 }
1874 }
1875
1876 return result;
1877}
1878
1879var Recoil_filterMap = filterMap;
1880
1881/**
1882 * Copyright (c) Facebook, Inc. and its affiliates.
1883 *
1884 * This source code is licensed under the MIT license found in the
1885 * LICENSE file in the root directory of this source tree.
1886 *
1887 * @emails oncall+recoil
1888 *
1889 * @format
1890 */
1891/**
1892 * Returns a set containing all of the values from the original set where
1893 * the given callback returned true.
1894 */
1895
1896function filterSet(set, callback) {
1897 const result = new Set();
1898
1899 for (const value of set) {
1900 if (callback(value)) {
1901 result.add(value);
1902 }
1903 }
1904
1905 return result;
1906}
1907
1908var Recoil_filterSet = filterSet;
1909
1910/**
1911 * Copyright (c) Facebook, Inc. and its affiliates.
1912 *
1913 * This source code is licensed under the MIT license found in the
1914 * LICENSE file in the root directory of this source tree.
1915 *
1916 * @emails oncall+recoil
1917 *
1918 * @format
1919 */
1920
1921function invariant(condition, message) {
1922 if (!condition) {
1923 throw new Error(message);
1924 }
1925}
1926
1927var invariant_1 = invariant;
1928
1929// @oss-only
1930
1931
1932var Recoil_invariant = invariant_1;
1933
1934/**
1935 * Copyright (c) Facebook, Inc. and its affiliates.
1936 *
1937 * This source code is licensed under the MIT license found in the
1938 * LICENSE file in the root directory of this source tree.
1939 *
1940 * @emails oncall+recoil
1941 *
1942 * @format
1943 */
1944
1945function mergeMaps(...maps) {
1946 const result = new Map();
1947
1948 for (let i = 0; i < maps.length; i++) {
1949 const iterator = maps[i].keys();
1950 let nextKey;
1951
1952 while (!(nextKey = iterator.next()).done) {
1953 // $FlowFixMe[incompatible-call] - map/iterator knows nothing about flow types
1954 result.set(nextKey.value, maps[i].get(nextKey.value));
1955 }
1956 }
1957 /* $FlowFixMe[incompatible-return] (>=0.66.0 site=www,mobile) This comment
1958 * suppresses an error found when Flow v0.66 was deployed. To see the error
1959 * delete this comment and run Flow. */
1960
1961
1962 return result;
1963}
1964
1965var Recoil_mergeMaps = mergeMaps;
1966
1967var _useMutableSource;
1968
1969 // FIXME T2710559282599660
1970
1971
1972const useMutableSource = // flowlint-line unclear-type:off
1973(_useMutableSource = react.useMutableSource) !== null && _useMutableSource !== void 0 ? _useMutableSource : react.unstable_useMutableSource; // flowlint-line unclear-type:off
1974
1975function mutableSourceExists() {
1976 return useMutableSource && !(typeof window !== 'undefined' && window.$disableRecoilValueMutableSource_TEMP_HACK_DO_NOT_USE);
1977}
1978
1979var Recoil_mutableSource = {
1980 mutableSourceExists,
1981 useMutableSource
1982};
1983
1984/**
1985 * Copyright (c) Facebook, Inc. and its affiliates.
1986 *
1987 * MIT License
1988 *
1989 * Copyright (c) 2014-2019 Georg Tavonius
1990 *
1991 * Permission is hereby granted, free of charge, to any person obtaining a copy
1992 * of this software and associated documentation files (the "Software"), to deal
1993 * in the Software without restriction, including without limitation the rights
1994 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1995 * copies of the Software, and to permit persons to whom the Software is
1996 * furnished to do so, subject to the following conditions:
1997 *
1998 * The above copyright notice and this permission notice shall be included in all
1999 * copies or substantial portions of the Software.
2000 *
2001 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2002 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2003 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2004 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2005 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2006 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2007 * SOFTWARE.
2008 *
2009 * @emails oncall+recoil
2010 *
2011 * @format
2012 */
2013
2014const UNKNOWN_FUNCTION = '<unknown>';
2015/**
2016 * This parses the different stack traces and puts them into one format
2017 * This borrows heavily from TraceKit (https://github.com/csnover/TraceKit)
2018 */
2019
2020function stackTraceParser(stackString) {
2021 const lines = stackString.split('\n');
2022 return lines.reduce((stack, line) => {
2023 const parseResult = parseChrome(line) || parseWinjs(line) || parseGecko(line) || parseNode(line) || parseJSC(line);
2024
2025 if (parseResult) {
2026 stack.push(parseResult);
2027 }
2028
2029 return stack;
2030 }, []);
2031}
2032
2033const chromeRe = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\/|[a-z]:\\|\\\\).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
2034const chromeEvalRe = /\((\S*)(?::(\d+))(?::(\d+))\)/;
2035
2036function parseChrome(line) {
2037 const parts = chromeRe.exec(line);
2038
2039 if (!parts) {
2040 return null;
2041 }
2042
2043 const isNative = parts[2] && parts[2].indexOf('native') === 0; // start of line
2044
2045 const isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
2046
2047 const submatch = chromeEvalRe.exec(parts[2]);
2048
2049 if (isEval && submatch != null) {
2050 // throw out eval line/column and use top-most line/column number
2051 parts[2] = submatch[1]; // url
2052
2053 parts[3] = submatch[2]; // line
2054
2055 parts[4] = submatch[3]; // column
2056 }
2057
2058 return {
2059 file: !isNative ? parts[2] : null,
2060 methodName: parts[1] || UNKNOWN_FUNCTION,
2061 arguments: isNative ? [parts[2]] : [],
2062 lineNumber: parts[3] ? +parts[3] : null,
2063 column: parts[4] ? +parts[4] : null
2064 };
2065}
2066
2067const winjsRe = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
2068
2069function parseWinjs(line) {
2070 const parts = winjsRe.exec(line);
2071
2072 if (!parts) {
2073 return null;
2074 }
2075
2076 return {
2077 file: parts[2],
2078 methodName: parts[1] || UNKNOWN_FUNCTION,
2079 arguments: [],
2080 lineNumber: +parts[3],
2081 column: parts[4] ? +parts[4] : null
2082 };
2083}
2084
2085const geckoRe = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i;
2086const geckoEvalRe = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
2087
2088function parseGecko(line) {
2089 const parts = geckoRe.exec(line);
2090
2091 if (!parts) {
2092 return null;
2093 }
2094
2095 const isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
2096 const submatch = geckoEvalRe.exec(parts[3]);
2097
2098 if (isEval && submatch != null) {
2099 // throw out eval line/column and use top-most line number
2100 parts[3] = submatch[1];
2101 parts[4] = submatch[2];
2102 parts[5] = null; // no column when eval
2103 }
2104
2105 return {
2106 file: parts[3],
2107 methodName: parts[1] || UNKNOWN_FUNCTION,
2108 arguments: parts[2] ? parts[2].split(',') : [],
2109 lineNumber: parts[4] ? +parts[4] : null,
2110 column: parts[5] ? +parts[5] : null
2111 };
2112}
2113
2114const javaScriptCoreRe = /^\s*(?:([^@]*)(?:\((.*?)\))?@)?(\S.*?):(\d+)(?::(\d+))?\s*$/i;
2115
2116function parseJSC(line) {
2117 const parts = javaScriptCoreRe.exec(line);
2118
2119 if (!parts) {
2120 return null;
2121 }
2122
2123 return {
2124 file: parts[3],
2125 methodName: parts[1] || UNKNOWN_FUNCTION,
2126 arguments: [],
2127 lineNumber: +parts[4],
2128 column: parts[5] ? +parts[5] : null
2129 };
2130}
2131
2132const nodeRe = /^\s*at (?:((?:\[object object\])?[^\\/]+(?: \[as \S+\])?) )?\(?(.*?):(\d+)(?::(\d+))?\)?\s*$/i;
2133
2134function parseNode(line) {
2135 const parts = nodeRe.exec(line);
2136
2137 if (!parts) {
2138 return null;
2139 }
2140
2141 return {
2142 file: parts[2],
2143 methodName: parts[1] || UNKNOWN_FUNCTION,
2144 arguments: [],
2145 lineNumber: +parts[3],
2146 column: parts[4] ? +parts[4] : null
2147 };
2148}
2149
2150var Recoil_stackTraceParser = stackTraceParser;
2151
2152const {
2153 useRef: useRef$1
2154} = react;
2155
2156
2157
2158
2159
2160function useComponentName() {
2161 const nameRef = useRef$1();
2162
2163 if (process.env.NODE_ENV !== "production") {
2164 if (Recoil_gkx_1('recoil_infer_component_names')) {
2165 var _nameRef$current;
2166
2167 if (nameRef.current === undefined) {
2168 // There is no blessed way to determine the calling React component from
2169 // within a hook. This hack uses the fact that hooks must start with 'use'
2170 // and that hooks are either called by React Components or other hooks. It
2171 // follows therefore, that to find the calling component, you simply need
2172 // to look down the stack and find the first function which doesn't start
2173 // with 'use'. We are only enabling this in dev for now, since once the
2174 // codebase is minified, the naming assumptions no longer hold true.
2175 // eslint-disable-next-line fb-www/no-new-error
2176 const frames = Recoil_stackTraceParser(new Error().stack);
2177
2178 for (const {
2179 methodName
2180 } of frames) {
2181 // I observed cases where the frame was of the form 'Object.useXXX'
2182 // hence why I'm searching for hooks following a word boundary
2183 if (!methodName.match(/\buse[^\b]+$/)) {
2184 return nameRef.current = methodName;
2185 }
2186 }
2187
2188 nameRef.current = null;
2189 }
2190
2191 return (_nameRef$current = nameRef.current) !== null && _nameRef$current !== void 0 ? _nameRef$current : '<unable to determine component name>';
2192 }
2193 } // @fb-only: return "<component name only available when both in dev mode and when passing GK 'recoil_infer_component_names'>";
2194
2195
2196 return "<component name not available>"; // @oss-only
2197}
2198
2199var Recoil_useComponentName = useComponentName;
2200
2201const {
2202 useCallback,
2203 useEffect: useEffect$1,
2204 useMemo: useMemo$1,
2205 useRef: useRef$2,
2206 useState: useState$1
2207} = react;
2208
2209const {
2210 batchUpdates: batchUpdates$2
2211} = Recoil_Batching;
2212
2213const {
2214 DEFAULT_VALUE: DEFAULT_VALUE$2,
2215 getNode: getNode$2,
2216 nodes: nodes$1
2217} = Recoil_Node;
2218
2219const {
2220 useRecoilMutableSource: useRecoilMutableSource$1,
2221 useStoreRef: useStoreRef$1
2222} = Recoil_RecoilRoot_react;
2223
2224const {
2225 isRecoilValue: isRecoilValue$2
2226} = Recoil_RecoilValue$1;
2227
2228const {
2229 AbstractRecoilValue: AbstractRecoilValue$2,
2230 getRecoilValueAsLoadable: getRecoilValueAsLoadable$2,
2231 setRecoilValue: setRecoilValue$2,
2232 setRecoilValueLoadable: setRecoilValueLoadable$1,
2233 setUnvalidatedRecoilValue: setUnvalidatedRecoilValue$1,
2234 subscribeToRecoilValue: subscribeToRecoilValue$1
2235} = Recoil_RecoilValueInterface;
2236
2237const {
2238 Snapshot: Snapshot$1,
2239 cloneSnapshot: cloneSnapshot$1
2240} = Recoil_Snapshot$1;
2241
2242const {
2243 setByAddingToSet: setByAddingToSet$2
2244} = Recoil_CopyOnWrite;
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260const {
2261 mutableSourceExists: mutableSourceExists$1,
2262 useMutableSource: useMutableSource$1
2263} = Recoil_mutableSource;
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273function handleLoadable(loadable, atom, storeRef) {
2274 // We can't just throw the promise we are waiting on to Suspense. If the
2275 // upstream dependencies change it may produce a state in which the component
2276 // can render, but it would still be suspended on a Promise that may never resolve.
2277 if (loadable.state === 'hasValue') {
2278 return loadable.contents;
2279 } else if (loadable.state === 'loading') {
2280 const promise = new Promise(resolve => {
2281 storeRef.current.getState().suspendedComponentResolvers.add(resolve);
2282 });
2283 throw promise;
2284 } else if (loadable.state === 'hasError') {
2285 throw loadable.contents;
2286 } else {
2287 throw new Error(`Invalid value of loadable atom "${atom.key}"`);
2288 }
2289}
2290
2291function validateRecoilValue(recoilValue, hookName) {
2292 if (!isRecoilValue$2(recoilValue)) {
2293 throw new Error(`Invalid argument to ${hookName}: expected an atom or selector but got ${String(recoilValue)}`);
2294 }
2295}
2296
2297function useRecoilInterface_DEPRECATED() {
2298 const storeRef = useStoreRef$1();
2299 const [_, forceUpdate] = useState$1([]);
2300 const recoilValuesUsed = useRef$2(new Set());
2301 recoilValuesUsed.current = new Set(); // Track the RecoilValues used just during this render
2302
2303 const previousSubscriptions = useRef$2(new Set());
2304 const subscriptions = useRef$2(new Map());
2305 const unsubscribeFrom = useCallback(key => {
2306 const sub = subscriptions.current.get(key);
2307
2308 if (sub) {
2309 sub.release(storeRef.current);
2310 subscriptions.current.delete(key);
2311 }
2312 }, [storeRef, subscriptions]);
2313 const componentName = Recoil_useComponentName();
2314 useEffect$1(() => {
2315 const store = storeRef.current;
2316
2317 function updateState(_state, key) {
2318 if (!subscriptions.current.has(key)) {
2319 return;
2320 }
2321
2322 forceUpdate([]);
2323 }
2324
2325 Recoil_differenceSets(recoilValuesUsed.current, previousSubscriptions.current).forEach(key => {
2326 if (subscriptions.current.has(key)) {
2327 Recoil_expectationViolation(`Double subscription to RecoilValue "${key}"`);
2328 return;
2329 }
2330
2331 const sub = subscribeToRecoilValue$1(store, new AbstractRecoilValue$2(key), state => {
2332 Recoil_Tracing.trace('RecoilValue subscription fired', key, () => {
2333 updateState(state, key);
2334 });
2335 }, componentName);
2336 subscriptions.current.set(key, sub);
2337 Recoil_Tracing.trace('initial update on subscribing', key, () => {
2338 /**
2339 * Since we're subscribing in an effect we need to update to the latest
2340 * value of the atom since it may have changed since we rendered. We can
2341 * go ahead and do that now, unless we're in the middle of a batch --
2342 * in which case we should do it at the end of the batch, due to the
2343 * following edge case: Suppose an atom is updated in another useEffect
2344 * of this same component. Then the following sequence of events occur:
2345 * 1. Atom is updated and subs fired (but we may not be subscribed
2346 * yet depending on order of effects, so we miss this) Updated value
2347 * is now in nextTree, but not currentTree.
2348 * 2. This effect happens. We subscribe and update.
2349 * 3. From the update we re-render and read currentTree, with old value.
2350 * 4. Batcher's effect sets currentTree to nextTree.
2351 * In this sequence we miss the update. To avoid that, add the update
2352 * to queuedComponentCallback if a batch is in progress.
2353 */
2354 // FIXME delete queuedComponentCallbacks_DEPRECATED when deleting useInterface.
2355 const state = store.getState();
2356
2357 if (state.nextTree) {
2358 store.getState().queuedComponentCallbacks_DEPRECATED.push(Recoil_Tracing.wrap(() => {
2359 updateState(store.getState(), key);
2360 }));
2361 } else {
2362 updateState(store.getState(), key);
2363 }
2364 });
2365 });
2366 Recoil_differenceSets(previousSubscriptions.current, recoilValuesUsed.current).forEach(key => {
2367 unsubscribeFrom(key);
2368 });
2369 previousSubscriptions.current = recoilValuesUsed.current;
2370 });
2371 useEffect$1(() => {
2372 const subs = subscriptions.current;
2373 return () => subs.forEach((_, key) => unsubscribeFrom(key));
2374 }, [unsubscribeFrom]);
2375 return useMemo$1(() => {
2376 function useSetRecoilState(recoilState) {
2377 if (process.env.NODE_ENV !== "production") {
2378 // $FlowFixMe[escaped-generic]
2379 validateRecoilValue(recoilState, 'useSetRecoilState');
2380 }
2381
2382 return newValueOrUpdater => {
2383 setRecoilValue$2(storeRef.current, recoilState, newValueOrUpdater);
2384 };
2385 }
2386
2387 function useResetRecoilState(recoilState) {
2388 if (process.env.NODE_ENV !== "production") {
2389 // $FlowFixMe[escaped-generic]
2390 validateRecoilValue(recoilState, 'useResetRecoilState');
2391 }
2392
2393 return () => setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$2);
2394 }
2395
2396 function useRecoilValueLoadable(recoilValue) {
2397 if (process.env.NODE_ENV !== "production") {
2398 // $FlowFixMe[escaped-generic]
2399 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
2400 }
2401
2402 if (!recoilValuesUsed.current.has(recoilValue.key)) {
2403 recoilValuesUsed.current = setByAddingToSet$2(recoilValuesUsed.current, recoilValue.key);
2404 } // TODO Restore optimization to memoize lookup
2405
2406
2407 return getRecoilValueAsLoadable$2(storeRef.current, recoilValue);
2408 }
2409
2410 function useRecoilValue(recoilValue) {
2411 if (process.env.NODE_ENV !== "production") {
2412 // $FlowFixMe[escaped-generic]
2413 validateRecoilValue(recoilValue, 'useRecoilValue');
2414 }
2415
2416 const loadable = useRecoilValueLoadable(recoilValue); // $FlowFixMe[escaped-generic]
2417
2418 return handleLoadable(loadable, recoilValue, storeRef);
2419 }
2420
2421 function useRecoilState(recoilState) {
2422 if (process.env.NODE_ENV !== "production") {
2423 // $FlowFixMe[escaped-generic]
2424 validateRecoilValue(recoilState, 'useRecoilState');
2425 }
2426
2427 return [useRecoilValue(recoilState), useSetRecoilState(recoilState)];
2428 }
2429
2430 function useRecoilStateLoadable(recoilState) {
2431 if (process.env.NODE_ENV !== "production") {
2432 // $FlowFixMe[escaped-generic]
2433 validateRecoilValue(recoilState, 'useRecoilStateLoadable');
2434 }
2435
2436 return [useRecoilValueLoadable(recoilState), useSetRecoilState(recoilState)];
2437 }
2438
2439 return {
2440 getRecoilValue: useRecoilValue,
2441 getRecoilValueLoadable: useRecoilValueLoadable,
2442 getRecoilState: useRecoilState,
2443 getRecoilStateLoadable: useRecoilStateLoadable,
2444 getSetRecoilState: useSetRecoilState,
2445 getResetRecoilState: useResetRecoilState
2446 };
2447 }, [recoilValuesUsed, storeRef]);
2448}
2449
2450const recoilComponentGetRecoilValueCount_FOR_TESTING = {
2451 current: 0
2452};
2453
2454function useRecoilValueLoadable_MUTABLESOURCE(recoilValue) {
2455 if (process.env.NODE_ENV !== "production") {
2456 // $FlowFixMe[escaped-generic]
2457 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
2458 }
2459
2460 const storeRef = useStoreRef$1();
2461 const getValue = useCallback(() => {
2462 if (process.env.NODE_ENV !== "production") {
2463 recoilComponentGetRecoilValueCount_FOR_TESTING.current++;
2464 }
2465
2466 return getRecoilValueAsLoadable$2(storeRef.current, recoilValue, storeRef.current.getState().currentTree);
2467 }, [storeRef, recoilValue]);
2468 const componentName = Recoil_useComponentName();
2469 const subscribe = useCallback((_something, callback) => {
2470 const store = storeRef.current;
2471 const sub = subscribeToRecoilValue$1(store, recoilValue, () => {
2472 Recoil_Tracing.trace('RecoilValue subscription fired', recoilValue.key, () => {
2473 callback();
2474 });
2475 }, componentName);
2476 return () => sub.release(store);
2477 }, [recoilValue, storeRef, componentName]);
2478 return useMutableSource$1(useRecoilMutableSource$1(), getValue, subscribe);
2479}
2480
2481function useRecoilValueLoadable_LEGACY(recoilValue) {
2482 if (process.env.NODE_ENV !== "production") {
2483 // $FlowFixMe[escaped-generic]
2484 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
2485 }
2486
2487 const storeRef = useStoreRef$1();
2488 const [_, forceUpdate] = useState$1([]);
2489 const componentName = Recoil_useComponentName();
2490 useEffect$1(() => {
2491 const store = storeRef.current;
2492 const sub = subscribeToRecoilValue$1(store, recoilValue, _state => {
2493 Recoil_Tracing.trace('RecoilValue subscription fired', recoilValue.key, () => {
2494 forceUpdate([]);
2495 });
2496 }, componentName);
2497 Recoil_Tracing.trace('initial update on subscribing', recoilValue.key, () => {
2498 /**
2499 * Since we're subscribing in an effect we need to update to the latest
2500 * value of the atom since it may have changed since we rendered. We can
2501 * go ahead and do that now, unless we're in the middle of a batch --
2502 * in which case we should do it at the end of the batch, due to the
2503 * following edge case: Suppose an atom is updated in another useEffect
2504 * of this same component. Then the following sequence of events occur:
2505 * 1. Atom is updated and subs fired (but we may not be subscribed
2506 * yet depending on order of effects, so we miss this) Updated value
2507 * is now in nextTree, but not currentTree.
2508 * 2. This effect happens. We subscribe and update.
2509 * 3. From the update we re-render and read currentTree, with old value.
2510 * 4. Batcher's effect sets currentTree to nextTree.
2511 * In this sequence we miss the update. To avoid that, add the update
2512 * to queuedComponentCallback if a batch is in progress.
2513 */
2514 const state = store.getState();
2515
2516 if (state.nextTree) {
2517 store.getState().queuedComponentCallbacks_DEPRECATED.push(Recoil_Tracing.wrap(() => {
2518 forceUpdate([]);
2519 }));
2520 } else {
2521 forceUpdate([]);
2522 }
2523 });
2524 return () => sub.release(store);
2525 }, [recoilValue, storeRef]);
2526 return getRecoilValueAsLoadable$2(storeRef.current, recoilValue);
2527}
2528/**
2529 Like useRecoilValue(), but either returns the value if available or
2530 just undefined if not available for any reason, such as pending or error.
2531*/
2532
2533
2534function useRecoilValueLoadable(recoilValue) {
2535 if (mutableSourceExists$1()) {
2536 // eslint-disable-next-line fb-www/react-hooks
2537 return useRecoilValueLoadable_MUTABLESOURCE(recoilValue);
2538 } else {
2539 // eslint-disable-next-line fb-www/react-hooks
2540 return useRecoilValueLoadable_LEGACY(recoilValue);
2541 }
2542}
2543/**
2544 Returns the value represented by the RecoilValue.
2545 If the value is pending, it will throw a Promise to suspend the component,
2546 if the value is an error it will throw it for the nearest React error boundary.
2547 This will also subscribe the component for any updates in the value.
2548 */
2549
2550
2551function useRecoilValue(recoilValue) {
2552 if (process.env.NODE_ENV !== "production") {
2553 // $FlowFixMe[escaped-generic]
2554 validateRecoilValue(recoilValue, 'useRecoilValue');
2555 }
2556
2557 const storeRef = useStoreRef$1();
2558 const loadable = useRecoilValueLoadable(recoilValue); // $FlowFixMe[escaped-generic]
2559
2560 return handleLoadable(loadable, recoilValue, storeRef);
2561}
2562/**
2563 Returns a function that allows the value of a RecoilState to be updated, but does
2564 not subscribe the component to changes to that RecoilState.
2565*/
2566
2567
2568function useSetRecoilState(recoilState) {
2569 if (process.env.NODE_ENV !== "production") {
2570 // $FlowFixMe[escaped-generic]
2571 validateRecoilValue(recoilState, 'useSetRecoilState');
2572 }
2573
2574 const storeRef = useStoreRef$1();
2575 return useCallback(newValueOrUpdater => {
2576 setRecoilValue$2(storeRef.current, recoilState, newValueOrUpdater);
2577 }, [storeRef, recoilState]);
2578}
2579/**
2580 Returns a function that will reset the value of a RecoilState to its default
2581*/
2582
2583
2584function useResetRecoilState(recoilState) {
2585 if (process.env.NODE_ENV !== "production") {
2586 // $FlowFixMe[escaped-generic]
2587 validateRecoilValue(recoilState, 'useResetRecoilState');
2588 }
2589
2590 const storeRef = useStoreRef$1();
2591 return useCallback(() => {
2592 setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$2);
2593 }, [storeRef, recoilState]);
2594}
2595/**
2596 Equivalent to useState(). Allows the value of the RecoilState to be read and written.
2597 Subsequent updates to the RecoilState will cause the component to re-render. If the
2598 RecoilState is pending, this will suspend the component and initiate the
2599 retrieval of the value. If evaluating the RecoilState resulted in an error, this will
2600 throw the error so that the nearest React error boundary can catch it.
2601*/
2602
2603
2604function useRecoilState(recoilState) {
2605 if (process.env.NODE_ENV !== "production") {
2606 // $FlowFixMe[escaped-generic]
2607 validateRecoilValue(recoilState, 'useRecoilState');
2608 }
2609
2610 return [useRecoilValue(recoilState), useSetRecoilState(recoilState)];
2611}
2612/**
2613 Like useRecoilState(), but does not cause Suspense or React error handling. Returns
2614 an object that indicates whether the RecoilState is available, pending, or
2615 unavailable due to an error.
2616*/
2617
2618
2619function useRecoilStateLoadable(recoilState) {
2620 if (process.env.NODE_ENV !== "production") {
2621 // $FlowFixMe[escaped-generic]
2622 validateRecoilValue(recoilState, 'useRecoilStateLoadable');
2623 }
2624
2625 return [useRecoilValueLoadable(recoilState), useSetRecoilState(recoilState)];
2626}
2627
2628function useTransactionSubscription(callback) {
2629 const storeRef = useStoreRef$1();
2630 useEffect$1(() => {
2631 const sub = storeRef.current.subscribeToTransactions(callback);
2632 return sub.release;
2633 }, [callback, storeRef]);
2634}
2635
2636function externallyVisibleAtomValuesInState(state) {
2637 const atomValues = state.atomValues;
2638 const persistedAtomContentsValues = Recoil_mapMap(Recoil_filterMap(atomValues, (v, k) => {
2639 const node = getNode$2(k);
2640 const persistence = node.persistence_UNSTABLE;
2641 return persistence != null && persistence.type !== 'none' && v.state === 'hasValue';
2642 }), v => v.contents); // Merge in nonvalidated atoms; we may not have defs for them but they will
2643 // all have persistence on or they wouldn't be there in the first place.
2644
2645 return Recoil_mergeMaps(state.nonvalidatedAtoms, persistedAtomContentsValues);
2646}
2647
2648/**
2649 Calls the given callback after any atoms have been modified and the consequent
2650 component re-renders have been committed. This is intended for persisting
2651 the values of the atoms to storage. The stored values can then be restored
2652 using the useSetUnvalidatedAtomValues hook.
2653
2654 The callback receives the following info:
2655
2656 atomValues: The current value of every atom that is both persistable (persistence
2657 type not set to 'none') and whose value is available (not in an
2658 error or loading state).
2659
2660 previousAtomValues: The value of every persistable and available atom before
2661 the transaction began.
2662
2663 atomInfo: A map containing the persistence settings for each atom. Every key
2664 that exists in atomValues will also exist in atomInfo.
2665
2666 modifiedAtoms: The set of atoms that were written to during the transaction.
2667
2668 transactionMetadata: Arbitrary information that was added via the
2669 useSetUnvalidatedAtomValues hook. Useful for ignoring the useSetUnvalidatedAtomValues
2670 transaction, to avoid loops.
2671*/
2672function useTransactionObservation_DEPRECATED(callback) {
2673 useTransactionSubscription(useCallback(store => {
2674 let previousTree = store.getState().previousTree;
2675 const currentTree = store.getState().currentTree;
2676
2677 if (!previousTree) {
2678 Recoil_recoverableViolation('Transaction subscribers notified without a previous tree being present -- this is a bug in Recoil');
2679 previousTree = store.getState().currentTree; // attempt to trundle on
2680 }
2681
2682 const atomValues = externallyVisibleAtomValuesInState(currentTree);
2683 const previousAtomValues = externallyVisibleAtomValuesInState(previousTree);
2684 const atomInfo = Recoil_mapMap(nodes$1, node => {
2685 var _node$persistence_UNS, _node$persistence_UNS2, _node$persistence_UNS3, _node$persistence_UNS4;
2686
2687 return {
2688 persistence_UNSTABLE: {
2689 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',
2690 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
2691 }
2692 };
2693 }); // Filter on existance in atomValues so that externally-visible rules
2694 // are also applied to modified atoms (specifically exclude selectors):
2695
2696 const modifiedAtoms = Recoil_filterSet(currentTree.dirtyAtoms, k => atomValues.has(k) || previousAtomValues.has(k));
2697 callback({
2698 atomValues,
2699 previousAtomValues,
2700 atomInfo,
2701 modifiedAtoms,
2702 transactionMetadata: { ...currentTree.transactionMetadata
2703 }
2704 });
2705 }, [callback]));
2706}
2707
2708function useRecoilTransactionObserver(callback) {
2709 useTransactionSubscription(useCallback(store => {
2710 callback({
2711 snapshot: cloneSnapshot$1(store, 'current'),
2712 previousSnapshot: cloneSnapshot$1(store, 'previous')
2713 });
2714 }, [callback]));
2715} // Return a snapshot of the current state and subscribe to all state changes
2716
2717
2718function useRecoilSnapshot() {
2719 const storeRef = useStoreRef$1();
2720 const [snapshot, setSnapshot] = useState$1(() => cloneSnapshot$1(storeRef.current));
2721 useTransactionSubscription(useCallback(store => setSnapshot(cloneSnapshot$1(store)), []));
2722 return snapshot;
2723}
2724
2725function useGotoRecoilSnapshot() {
2726 const storeRef = useStoreRef$1();
2727 return useCallback(snapshot => {
2728 var _storeState$nextTree;
2729
2730 const storeState = storeRef.current.getState();
2731 const prev = (_storeState$nextTree = storeState.nextTree) !== null && _storeState$nextTree !== void 0 ? _storeState$nextTree : storeState.currentTree;
2732 const next = snapshot.getStore_INTERNAL().getState().currentTree;
2733 batchUpdates$2(() => {
2734 const keysToUpdate = new Set();
2735
2736 for (const keys of [prev.atomValues.keys(), next.atomValues.keys()]) {
2737 for (const key of keys) {
2738 var _prev$atomValues$get, _next$atomValues$get;
2739
2740 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$2(key).shouldRestoreFromSnapshots) {
2741 keysToUpdate.add(key);
2742 }
2743 }
2744 }
2745
2746 keysToUpdate.forEach(key => {
2747 setRecoilValueLoadable$1(storeRef.current, new AbstractRecoilValue$2(key), next.atomValues.has(key) ? Recoil_nullthrows(next.atomValues.get(key)) : DEFAULT_VALUE$2);
2748 });
2749 storeRef.current.replaceState(state => {
2750 return { ...state,
2751 stateID: snapshot.getID_INTERNAL()
2752 };
2753 });
2754 });
2755 }, [storeRef]);
2756}
2757
2758function useSetUnvalidatedAtomValues() {
2759 const storeRef = useStoreRef$1();
2760 return (values, transactionMetadata = {}) => {
2761 batchUpdates$2(() => {
2762 storeRef.current.addTransactionMetadata(transactionMetadata);
2763 values.forEach((value, key) => setUnvalidatedRecoilValue$1(storeRef.current, new AbstractRecoilValue$2(key), value));
2764 });
2765 };
2766}
2767
2768class Sentinel {}
2769
2770const SENTINEL = new Sentinel();
2771
2772function useRecoilCallback(fn, deps) {
2773 const storeRef = useStoreRef$1();
2774 const gotoSnapshot = useGotoRecoilSnapshot();
2775 return useCallback((...args) => {
2776 // Use currentTree for the snapshot to show the currently committed state
2777 const snapshot = cloneSnapshot$1(storeRef.current);
2778
2779 function set(recoilState, newValueOrUpdater) {
2780 setRecoilValue$2(storeRef.current, recoilState, newValueOrUpdater);
2781 }
2782
2783 function reset(recoilState) {
2784 setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$2);
2785 }
2786
2787 let ret = SENTINEL;
2788 batchUpdates$2(() => {
2789 // flowlint-next-line unclear-type:off
2790 ret = fn({
2791 set,
2792 reset,
2793 snapshot,
2794 gotoSnapshot
2795 })(...args);
2796 });
2797 !!(ret instanceof Sentinel) ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'batchUpdates should return immediately') : Recoil_invariant(false) : void 0;
2798 return ret;
2799 }, deps != null ? [...deps, storeRef] : undefined // eslint-disable-line fb-www/react-hooks-deps
2800 );
2801}
2802
2803var Recoil_Hooks = {
2804 recoilComponentGetRecoilValueCount_FOR_TESTING,
2805 useGotoRecoilSnapshot,
2806 useRecoilCallback,
2807 useRecoilInterface: useRecoilInterface_DEPRECATED,
2808 useRecoilSnapshot,
2809 useRecoilState,
2810 useRecoilStateLoadable,
2811 useRecoilTransactionObserver,
2812 useRecoilValue,
2813 useRecoilValueLoadable,
2814 useResetRecoilState,
2815 useSetRecoilState,
2816 useSetUnvalidatedAtomValues,
2817 useTransactionObservation_DEPRECATED,
2818 useTransactionSubscription_DEPRECATED: useTransactionSubscription
2819};
2820
2821const {
2822 useMemo: useMemo$2
2823} = react;
2824
2825const {
2826 RecoilRoot: RecoilRoot$1,
2827 useStoreRef: useStoreRef$2
2828} = Recoil_RecoilRoot_react;
2829
2830function useRecoilBridgeAcrossReactRoots() {
2831 const store = useStoreRef$2().current;
2832 return useMemo$2(() => {
2833 function RecoilBridge({
2834 children
2835 }) {
2836 return /*#__PURE__*/react.createElement(RecoilRoot$1, {
2837 store_INTERNAL: store
2838 }, children);
2839 }
2840
2841 return RecoilBridge;
2842 }, [store]);
2843}
2844
2845var Recoil_useRecoilBridgeAcrossReactRoots = useRecoilBridgeAcrossReactRoots;
2846
2847/**
2848 * Copyright (c) Facebook, Inc. and its affiliates.
2849 *
2850 * This source code is licensed under the MIT license found in the
2851 * LICENSE file in the root directory of this source tree.
2852 *
2853 * @emails oncall+recoil
2854 *
2855 * @format
2856 */
2857
2858// Split declaration and implementation to allow this function to pretend to
2859// check for actual instance of Promise instead of something with a `then`
2860// method.
2861// eslint-disable-next-line no-redeclare
2862function isPromise(p) {
2863 return !!p && typeof p.then === 'function';
2864}
2865
2866var Recoil_isPromise = isPromise;
2867
2868// TODO Convert Loadable to a Class to allow for runtime type detection.
2869// Containing static factories of withValue(), withError(), withPromise(), and all()
2870
2871
2872const loadableAccessors = {
2873 /**
2874 * if loadable has a value (state === 'hasValue'), return that value.
2875 * Otherwise, throw the (unwrapped) promise or the error.
2876 */
2877 getValue() {
2878 if (this.state === 'loading' && Recoil_gkx_1('recoil_async_selector_refactor')) {
2879 throw this.contents.then(({
2880 __value
2881 }) => __value);
2882 }
2883
2884 if (this.state !== 'hasValue') {
2885 throw this.contents;
2886 }
2887
2888 return this.contents;
2889 },
2890
2891 toPromise() {
2892 return this.state === 'hasValue' ? Promise.resolve(this.contents) : this.state === 'hasError' ? Promise.reject(this.contents) : Recoil_gkx_1('recoil_async_selector_refactor') ? this.contents.then(({
2893 __value
2894 }) => __value) : this.contents;
2895 },
2896
2897 valueMaybe() {
2898 return this.state === 'hasValue' ? this.contents : undefined;
2899 },
2900
2901 valueOrThrow() {
2902 if (this.state !== 'hasValue') {
2903 throw new Error(`Loadable expected value, but in "${this.state}" state`);
2904 }
2905
2906 return this.contents;
2907 },
2908
2909 errorMaybe() {
2910 return this.state === 'hasError' ? this.contents : undefined;
2911 },
2912
2913 errorOrThrow() {
2914 if (this.state !== 'hasError') {
2915 throw new Error(`Loadable expected error, but in "${this.state}" state`);
2916 }
2917
2918 return this.contents;
2919 },
2920
2921 promiseMaybe() {
2922 return this.state === 'loading' ? Recoil_gkx_1('recoil_async_selector_refactor') ? this.contents.then(({
2923 __value
2924 }) => __value) : this.contents : undefined;
2925 },
2926
2927 promiseOrThrow() {
2928 if (this.state !== 'loading') {
2929 throw new Error(`Loadable expected promise, but in "${this.state}" state`);
2930 }
2931
2932 return Recoil_gkx_1('recoil_async_selector_refactor') ? this.contents.then(({
2933 __value
2934 }) => __value) : this.contents;
2935 },
2936
2937 // TODO Unit tests
2938 // TODO Convert Loadable to a Class to better support chaining
2939 // by returning a Loadable from a map function
2940 map(map) {
2941 if (this.state === 'hasError') {
2942 return this;
2943 }
2944
2945 if (this.state === 'hasValue') {
2946 try {
2947 const next = map(this.contents); // TODO if next instanceof Loadable, then return next
2948
2949 return Recoil_isPromise(next) ? loadableWithPromise(next) : loadableWithValue(next);
2950 } catch (e) {
2951 return Recoil_isPromise(e) ? // If we "suspended", then try again.
2952 // errors and subsequent retries will be handled in 'loading' case
2953 loadableWithPromise(e.next(() => map(this.contents))) : loadableWithError(e);
2954 }
2955 }
2956
2957 if (this.state === 'loading') {
2958 return loadableWithPromise(this.contents // TODO if map returns a loadable, then return the value or promise or throw the error
2959 .then(map).catch(e => {
2960 if (Recoil_isPromise(e)) {
2961 // we were "suspended," try again
2962 return e.then(() => map(this.contents));
2963 }
2964
2965 throw e;
2966 }));
2967 }
2968
2969 throw new Error('Invalid Loadable state');
2970 }
2971
2972};
2973
2974function loadableWithValue(value) {
2975 // Build objects this way since Flow doesn't support disjoint unions for class properties
2976 return Object.freeze({
2977 state: 'hasValue',
2978 contents: value,
2979 ...loadableAccessors
2980 });
2981}
2982
2983function loadableWithError(error) {
2984 return Object.freeze({
2985 state: 'hasError',
2986 contents: error,
2987 ...loadableAccessors
2988 });
2989}
2990
2991function loadableWithPromise(promise) {
2992 return Object.freeze({
2993 state: 'loading',
2994 contents: promise,
2995 ...loadableAccessors
2996 });
2997}
2998
2999function loadableLoading() {
3000 return loadableWithPromise(new Promise(() => {}));
3001}
3002
3003function loadableAll(inputs) {
3004 return inputs.every(i => i.state === 'hasValue') ? loadableWithValue(inputs.map(i => i.contents)) : inputs.some(i => i.state === 'hasError') ? loadableWithError( // $FlowIssue[incompatible-call] #44070740 Array.find should refine parameter
3005 Recoil_nullthrows(inputs.find(i => i.state === 'hasError'), 'Invalid loadable passed to loadableAll').contents) : loadableWithPromise(Recoil_gkx_1('recoil_async_selector_refactor') ? Promise.all(inputs.map(i => i.contents)).then(value => ({
3006 __value: value
3007 })) : Promise.all(inputs.map(i => i.contents)));
3008}
3009
3010var Recoil_Loadable = {
3011 loadableWithValue,
3012 loadableWithError,
3013 loadableWithPromise,
3014 loadableLoading,
3015 loadableAll
3016};
3017
3018/**
3019 * Copyright (c) Facebook, Inc. and its affiliates.
3020 *
3021 * This source code is licensed under the MIT license found in the
3022 * LICENSE file in the root directory of this source tree.
3023 *
3024 * @emails oncall+recoil
3025 *
3026 * @format
3027 */
3028
3029const ARRAY_BUFFER_VIEW_TYPES = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, DataView];
3030
3031function isArrayBufferView(value) {
3032 for (const type of ARRAY_BUFFER_VIEW_TYPES) {
3033 if (value instanceof type) {
3034 return true;
3035 }
3036 }
3037
3038 return false;
3039}
3040
3041var Recoil_isArrayBufferView = isArrayBufferView;
3042
3043/**
3044 * Copyright (c) Facebook, Inc. and its affiliates.
3045 *
3046 * This source code is licensed under the MIT license found in the
3047 * LICENSE file in the root directory of this source tree.
3048 *
3049 * @emails oncall+recoil
3050 *
3051 * @format
3052 */
3053
3054function isNode(object) {
3055 var _ownerDocument, _doc$defaultView;
3056
3057 if (typeof window === 'undefined') {
3058 return false;
3059 }
3060
3061 const doc = object != null ? (_ownerDocument = object.ownerDocument) !== null && _ownerDocument !== void 0 ? _ownerDocument : object : document;
3062 const defaultView = (_doc$defaultView = doc.defaultView) !== null && _doc$defaultView !== void 0 ? _doc$defaultView : window;
3063 return !!(object != null && (typeof defaultView.Node === 'function' ? object instanceof defaultView.Node : typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string'));
3064}
3065
3066var Recoil_isNode = isNode;
3067
3068const isSSR = typeof window === 'undefined';
3069const isReactNative = typeof navigator !== 'undefined' && navigator.product === 'ReactNative'; // eslint-disable-line fb-www/typeof-undefined
3070
3071function shouldNotBeFrozen(value) {
3072 // Primitives and functions:
3073 if (value === null || typeof value !== 'object') {
3074 return true;
3075 } // React elements:
3076
3077
3078 switch (typeof value.$$typeof) {
3079 case 'symbol':
3080 return true;
3081
3082 case 'number':
3083 return true;
3084 } // Immutable structures:
3085
3086
3087 if (value['@@__IMMUTABLE_ITERABLE__@@'] != null || value['@@__IMMUTABLE_KEYED__@@'] != null || value['@@__IMMUTABLE_INDEXED__@@'] != null || value['@@__IMMUTABLE_ORDERED__@@'] != null || value['@@__IMMUTABLE_RECORD__@@'] != null) {
3088 return true;
3089 } // DOM nodes:
3090
3091
3092 if (Recoil_isNode(value)) {
3093 return true;
3094 }
3095
3096 if (Recoil_isPromise(value)) {
3097 return true;
3098 }
3099
3100 if (Recoil_isArrayBufferView(value)) {
3101 return true;
3102 } // Some environments, just as Jest, don't work with the instanceof check
3103
3104
3105 if (!isSSR && !isReactNative && (value === window || value instanceof Window)) {
3106 return true;
3107 }
3108
3109 return false;
3110} // Recursively freeze a value to enforce it is read-only.
3111// This may also have minimal performance improvements for enumerating
3112// objects (based on browser implementations, of course)
3113
3114
3115function deepFreezeValue(value) {
3116 if (typeof value !== 'object' || shouldNotBeFrozen(value)) {
3117 return;
3118 }
3119
3120 Object.freeze(value); // Make all properties read-only
3121
3122 for (const key in value) {
3123 if (Object.prototype.hasOwnProperty.call(value, key)) {
3124 const prop = value[key]; // Prevent infinite recurssion for circular references.
3125
3126 if (typeof prop === 'object' && prop != null && !Object.isFrozen(prop)) {
3127 deepFreezeValue(prop);
3128 }
3129 }
3130 }
3131
3132 Object.seal(value); // This also makes existing properties non-configurable.
3133}
3134
3135var Recoil_deepFreezeValue = deepFreezeValue;
3136
3137/**
3138 * Copyright (c) Facebook, Inc. and its affiliates.
3139 *
3140 * This source code is licensed under the MIT license found in the
3141 * LICENSE file in the root directory of this source tree.
3142 *
3143 * @emails oncall+recoil
3144 *
3145 * @format
3146 */
3147
3148// cache implementation that only stores the most recent entry
3149// based on key reference equality
3150function cacheMostRecent() {
3151 let mostRecentKey;
3152 let mostRecentValue;
3153 const cache = {
3154 get: key => key === mostRecentKey ? mostRecentValue : undefined,
3155 set: (key, value) => {
3156 mostRecentKey = key;
3157 mostRecentValue = value;
3158 return cache;
3159 }
3160 };
3161 return cache;
3162}
3163
3164var Recoil_cacheMostRecent = cacheMostRecent;
3165
3166/**
3167 * Copyright (c) Facebook, Inc. and its affiliates.
3168 *
3169 * This source code is licensed under the MIT license found in the
3170 * LICENSE file in the root directory of this source tree.
3171 *
3172 * Implements (a subset of) the interface of built-in Map but supports arrays as
3173 * keys. Two keys are equal if corresponding elements are equal according to the
3174 * equality semantics of built-in Map. Operations are at worst O(n*b) where n is
3175 * the array length and b is the complexity of the built-in operation.
3176 *
3177 * @emails oncall+recoil
3178 *
3179 * @format
3180 */
3181
3182const LEAF = Symbol('ArrayKeyedMap');
3183const emptyMap = new Map();
3184
3185class ArrayKeyedMap {
3186 // @fb-only: _base: Map<any, any> = new Map();
3187 constructor(existing) {
3188 this._base = new Map(); // @oss-only
3189
3190 if (existing instanceof ArrayKeyedMap) {
3191 for (const [k, v] of existing.entries()) {
3192 this.set(k, v);
3193 }
3194 } else if (existing) {
3195 for (const [k, v] of existing) {
3196 this.set(k, v);
3197 }
3198 }
3199
3200 return this;
3201 }
3202
3203 get(key) {
3204 const ks = Array.isArray(key) ? key : [key];
3205 let map = this._base;
3206 ks.forEach(k => {
3207 var _map$get;
3208
3209 map = (_map$get = map.get(k)) !== null && _map$get !== void 0 ? _map$get : emptyMap;
3210 });
3211 return map === undefined ? undefined : map.get(LEAF);
3212 }
3213
3214 set(key, value) {
3215 const ks = Array.isArray(key) ? key : [key];
3216 let map = this._base;
3217 let next = map;
3218 ks.forEach(k => {
3219 next = map.get(k);
3220
3221 if (!next) {
3222 next = new Map();
3223 map.set(k, next);
3224 }
3225
3226 map = next;
3227 });
3228 next.set(LEAF, value);
3229 return this;
3230 }
3231
3232 delete(key) {
3233 const ks = Array.isArray(key) ? key : [key];
3234 let map = this._base;
3235 let next = map;
3236 ks.forEach(k => {
3237 next = map.get(k);
3238
3239 if (!next) {
3240 next = new Map();
3241 map.set(k, next);
3242 }
3243
3244 map = next;
3245 });
3246 next.delete(LEAF); // TODO We could cleanup empty maps
3247
3248 return this;
3249 }
3250
3251 entries() {
3252 const answer = [];
3253
3254 function recurse(level, prefix) {
3255 level.forEach((v, k) => {
3256 if (k === LEAF) {
3257 answer.push([prefix, v]);
3258 } else {
3259 recurse(v, prefix.concat(k));
3260 }
3261 });
3262 }
3263
3264 recurse(this._base, []);
3265 return answer.values();
3266 }
3267
3268 toBuiltInMap() {
3269 return new Map(this.entries());
3270 }
3271
3272}
3273
3274var Recoil_ArrayKeyedMap = ArrayKeyedMap;
3275
3276function cacheWithReferenceEquality() {
3277 return new Recoil_ArrayKeyedMap();
3278}
3279
3280var Recoil_cacheWithReferenceEquality = cacheWithReferenceEquality;
3281
3282const TIME_WARNING_THRESHOLD_MS = 15;
3283
3284function stringify(x, opt, key) {
3285 // A optimization to avoid the more expensive JSON.stringify() for simple strings
3286 // This may lose protection for u2028 and u2029, though.
3287 if (typeof x === 'string' && !x.includes('"') && !x.includes('\\')) {
3288 return `"${x}"`;
3289 } // Handle primitive types
3290
3291
3292 switch (typeof x) {
3293 case 'undefined':
3294 return '';
3295 // JSON.stringify(undefined) returns undefined, but we always want to return a string
3296
3297 case 'boolean':
3298 return x ? 'true' : 'false';
3299
3300 case 'number':
3301 case 'symbol':
3302 // case 'bigint': // BigInt is not supported in www
3303 return String(x);
3304
3305 case 'string':
3306 // Add surrounding quotes and escape internal quotes
3307 return JSON.stringify(x);
3308
3309 case 'function':
3310 if ((opt === null || opt === void 0 ? void 0 : opt.allowFunctions) !== true) {
3311 throw new Error('Attempt to serialize function in a Recoil cache key');
3312 }
3313
3314 return `__FUNCTION(${x.name})__`;
3315 }
3316
3317 if (x === null) {
3318 return 'null';
3319 } // Fallback case for unknown types
3320
3321
3322 if (typeof x !== 'object') {
3323 var _JSON$stringify;
3324
3325 return (_JSON$stringify = JSON.stringify(x)) !== null && _JSON$stringify !== void 0 ? _JSON$stringify : '';
3326 } // Deal with all promises as equivalent for now.
3327
3328
3329 if (Recoil_isPromise(x)) {
3330 return '__PROMISE__';
3331 } // Arrays handle recursive stringification
3332
3333
3334 if (Array.isArray(x)) {
3335 return `[${x.map((v, i) => stringify(v, opt, i.toString()))}]`;
3336 } // If an object defines a toJSON() method, then use that to override the
3337 // serialization. This matches the behavior of JSON.stringify().
3338 // Pass the key for compatibility.
3339 // Immutable.js collections define this method to allow us to serialize them.
3340
3341
3342 if (typeof x.toJSON === 'function') {
3343 // flowlint-next-line unclear-type: off
3344 return stringify(x.toJSON(key), opt, key);
3345 } // For built-in Maps, sort the keys in a stable order instead of the
3346 // default insertion order. Support non-string keys.
3347
3348
3349 if (x instanceof Map) {
3350 const obj = {};
3351
3352 for (const [k, v] of x) {
3353 // Stringify will escape any nested quotes
3354 obj[typeof k === 'string' ? k : stringify(k, opt)] = v;
3355 }
3356
3357 return stringify(obj, opt, key);
3358 } // For built-in Sets, sort the keys in a stable order instead of the
3359 // default insertion order.
3360
3361
3362 if (x instanceof Set) {
3363 return stringify(Array.from(x).sort((a, b) => stringify(a, opt).localeCompare(stringify(b, opt))), opt, key);
3364 } // Anything else that is iterable serialize as an Array.
3365
3366
3367 if (x[Symbol.iterator] != null && typeof x[Symbol.iterator] === 'function') {
3368 // flowlint-next-line unclear-type: off
3369 return stringify(Array.from(x), opt, key);
3370 } // For all other Objects, sort the keys in a stable order.
3371
3372
3373 return `{${Object.keys(x).filter(key => x[key] !== undefined).sort() // stringify the key to add quotes and escape any nested slashes or quotes.
3374 .map(key => `${stringify(key, opt)}:${stringify(x[key], opt, key)}`).join(',')}}`;
3375} // Utility similar to JSON.stringify() except:
3376// * Serialize built-in Sets as an Array
3377// * Serialize built-in Maps as an Object. Supports non-string keys.
3378// * Serialize other iterables as arrays
3379// * Sort the keys of Objects and Maps to have a stable order based on string conversion.
3380// This overrides their default insertion order.
3381// * Still uses toJSON() of any object to override serialization
3382// * Support Symbols (though don't guarantee uniqueness)
3383// * We could support BigInt, but Flow doesn't seem to like it.
3384// See Recoil_stableStringify-test.js for examples
3385
3386
3387function stableStringify(x, opt = {
3388 allowFunctions: false
3389}) {
3390 if (process.env.NODE_ENV !== "production") {
3391 if (typeof window !== 'undefined') {
3392 const startTime = window.performance ? window.performance.now() : 0;
3393 const str = stringify(x, opt);
3394 const endTime = window.performance ? window.performance.now() : 0;
3395
3396 if (endTime - startTime > TIME_WARNING_THRESHOLD_MS) {
3397 /* eslint-disable fb-www/no-console */
3398 console.groupCollapsed(`Recoil: Spent ${endTime - startTime}ms computing a cache key`);
3399 console.warn(x, str);
3400 console.groupEnd();
3401 /* eslint-enable fb-www/no-console */
3402 }
3403
3404 return str;
3405 }
3406 }
3407
3408 return stringify(x, opt);
3409}
3410
3411var Recoil_stableStringify = stableStringify;
3412
3413// If we do profile and find the key equality check is expensive,
3414// we could always try to optimize.. Something that comes to mind is having
3415// each check assign an incrementing index to each reference that maps to the
3416// value equivalency. Then, if an object already has an index, the comparison
3417// check/lookup would be trivial and the string serialization would only need
3418// to be done once per object instance. Just a thought..
3419// Cache implementation to use value equality for keys instead of the default
3420// reference equality. This allows different instances of dependency values to
3421// be used. Normally this is not needed, as dependent atoms/selectors will
3422// themselves be cached and always return the same instance. However, if
3423// different params or upstream values for those dependencies could produce
3424// equivalent values or they have a custom cache implementation, then this
3425// implementation may be needed. The downside with this approach is that it
3426// takes longer to compute the value equivalence vs simple reference equality.
3427
3428
3429function cacheWithValueEquality() {
3430 const map = new Map();
3431 const cache = {
3432 get: key => map.get(Recoil_stableStringify(key)),
3433 set: (key, value) => {
3434 map.set(Recoil_stableStringify(key), value);
3435 return cache;
3436 },
3437 map // For debugging
3438
3439 };
3440 return cache;
3441}
3442
3443var Recoil_cacheWithValueEquality = cacheWithValueEquality;
3444
3445/**
3446 * (c) Facebook, Inc. and its affiliates. Confidential and proprietary.
3447 *
3448 * @emails oncall+recoil
3449 *
3450 * @format
3451 */
3452
3453function nodeCacheMostRecent() {
3454 let mostRecent;
3455 return {
3456 get: (getNodeValue, handlers) => {
3457 if (mostRecent === undefined) {
3458 return undefined;
3459 }
3460
3461 for (const [nodeKey, nodeValue] of mostRecent.route) {
3462 var _handlers$onCacheHit;
3463
3464 if (getNodeValue(nodeKey) !== nodeValue) {
3465 return undefined;
3466 }
3467
3468 handlers === null || handlers === void 0 ? void 0 : (_handlers$onCacheHit = handlers.onCacheHit) === null || _handlers$onCacheHit === void 0 ? void 0 : _handlers$onCacheHit.call(handlers, nodeKey);
3469 }
3470
3471 return mostRecent.value;
3472 },
3473 set: (route, value) => {
3474 mostRecent = {
3475 route,
3476 value
3477 };
3478 },
3479 getRoot: () => mostRecent
3480 };
3481}
3482
3483var Recoil_nodeCacheMostRecent = nodeCacheMostRecent;
3484
3485function setInTreeCache(root, route, result) {
3486 if (root == null) {
3487 if (route.length === 0) {
3488 return {
3489 type: 'result',
3490 result
3491 };
3492 } else {
3493 const [path, ...rest] = route;
3494 const [nodeKey, value] = path;
3495 const ret = {
3496 type: 'branch',
3497 nodeKey,
3498 branches: new Map([[value, setInTreeCache(null, rest, result)]])
3499 };
3500 return ret;
3501 }
3502 } else {
3503 if (route.length === 0) {
3504 !(root.type === 'result') ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Existing cache must have a result type node at the end of the route') : Recoil_invariant(false) : void 0;
3505
3506 if (root.result && root.result.state === 'loading') {
3507 const ret = {
3508 type: 'result',
3509 result
3510 };
3511 return ret;
3512 } else {
3513 !(root.result === result) ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Existing cache must have the same result at the end of the route') : Recoil_invariant(false) : void 0;
3514 const ret = root;
3515 return ret;
3516 }
3517 } else {
3518 const [path, ...rest] = route;
3519 const [nodeKey, value] = path;
3520 !(root.type === 'branch') ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Existing cache must have a branch midway through the route') : Recoil_invariant(false) : void 0;
3521 !(root.nodeKey === nodeKey) ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Existing cache must have a branch for the same nodeKey midway through the route') : Recoil_invariant(false) : void 0;
3522 root.branches.set(value, setInTreeCache(root.branches.get(value), rest, result));
3523 return root;
3524 }
3525 }
3526}
3527
3528function getFromTreeCache(root, getNodeValue, handlers) {
3529 var _handlers$onCacheHit;
3530
3531 if (root == null) {
3532 return undefined;
3533 }
3534
3535 if (root.type === 'result') {
3536 return root.result;
3537 }
3538
3539 handlers === null || handlers === void 0 ? void 0 : (_handlers$onCacheHit = handlers.onCacheHit) === null || _handlers$onCacheHit === void 0 ? void 0 : _handlers$onCacheHit.call(handlers, root.nodeKey);
3540 const nodeValue = getNodeValue(root.nodeKey);
3541 return getFromTreeCache(root.branches.get(nodeValue), getNodeValue, handlers);
3542}
3543
3544var Recoil_TreeNodeCache = {
3545 setInTreeCache,
3546 getFromTreeCache
3547};
3548
3549const {
3550 getFromTreeCache: getFromTreeCache$1,
3551 setInTreeCache: setInTreeCache$1
3552} = Recoil_TreeNodeCache;
3553
3554function treeCacheReferenceEquality() {
3555 let treeRoot;
3556 return {
3557 get: (getNodeValue, handlers) => getFromTreeCache$1(treeRoot, getNodeValue, handlers),
3558 set: (route, result) => {
3559 treeRoot = setInTreeCache$1(treeRoot, route, result);
3560 },
3561 getRoot: () => treeRoot
3562 };
3563}
3564
3565var Recoil_treeCacheReferenceEquality = treeCacheReferenceEquality;
3566
3567const {
3568 getFromTreeCache: getFromTreeCache$2,
3569 setInTreeCache: setInTreeCache$2
3570} = Recoil_TreeNodeCache;
3571
3572function treeCacheValueEquality() {
3573 let treeRoot;
3574 return {
3575 get: (getNodeValue, handlers) => getFromTreeCache$2(treeRoot, nodeKey => Recoil_stableStringify(getNodeValue(nodeKey)), handlers),
3576 set: (route, result) => {
3577 treeRoot = setInTreeCache$2(treeRoot, route.map(([nodeKey, nodeValue]) => [nodeKey, Recoil_stableStringify(nodeValue)]), result);
3578 },
3579 getRoot: () => treeRoot
3580 };
3581}
3582
3583var Recoil_treeCacheValueEquality = treeCacheValueEquality;
3584
3585/**
3586 * Copyright (c) Facebook, Inc. and its affiliates.
3587 *
3588 * This source code is licensed under the MIT license found in the
3589 * LICENSE file in the root directory of this source tree.
3590 *
3591 * @emails oncall+recoil
3592 *
3593 * @format
3594 *
3595 * This is a stub for some integration into FB internal stuff
3596 */
3597function startPerfBlock(_id) {
3598 return () => null;
3599}
3600
3601var Recoil_PerformanceTimings = {
3602 startPerfBlock
3603};
3604
3605const {
3606 loadableWithError: loadableWithError$1,
3607 loadableWithPromise: loadableWithPromise$1,
3608 loadableWithValue: loadableWithValue$1
3609} = Recoil_Loadable;
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623const {
3624 getNodeLoadable: getNodeLoadable$2,
3625 peekNodeLoadable: peekNodeLoadable$2,
3626 setNodeValue: setNodeValue$3
3627} = Recoil_FunctionalCore;
3628
3629const {
3630 saveDependencyMapToStore: saveDependencyMapToStore$3
3631} = Recoil_Graph;
3632
3633const {
3634 DEFAULT_VALUE: DEFAULT_VALUE$3,
3635 RecoilValueNotReady: RecoilValueNotReady$2,
3636 registerNode: registerNode$1
3637} = Recoil_Node;
3638
3639const {
3640 isRecoilValue: isRecoilValue$3
3641} = Recoil_RecoilValue$1;
3642
3643const {
3644 AbstractRecoilValue: AbstractRecoilValue$3
3645} = Recoil_RecoilValue$1;
3646
3647const {
3648 setRecoilValueLoadable: setRecoilValueLoadable$2
3649} = Recoil_RecoilValueInterface;
3650
3651
3652
3653
3654
3655
3656
3657const {
3658 startPerfBlock: startPerfBlock$1
3659} = Recoil_PerformanceTimings;
3660
3661// flowlint-next-line unclear-type:off
3662const emptySet$1 = Object.freeze(new Set());
3663const dependencyStack = []; // for detecting circular dependencies.
3664
3665const waitingStores = new Map();
3666/* eslint-disable no-redeclare */
3667
3668const getNewExecutionId = (() => {
3669 let executionId = 0;
3670 return () => executionId++;
3671})();
3672
3673function getInitialExecutionInfo() {
3674 return {
3675 depValuesDiscoveredSoFarDuringAsyncWork: null,
3676 latestLoadable: null,
3677 latestExecutionId: null,
3678 stateVersion: null
3679 };
3680}
3681
3682function selector(options) {
3683 const {
3684 key,
3685 get,
3686 cacheImplementation_UNSTABLE: cacheImplementation
3687 } = options;
3688 const set = options.set != null ? options.set : undefined; // flow
3689
3690 /**
3691 * HACK: doing this as a way to map given cache to corresponding tree cache
3692 */
3693
3694 const cache = cacheImplementation === Recoil_cacheWithReferenceEquality ? Recoil_treeCacheReferenceEquality() : cacheImplementation === Recoil_cacheWithValueEquality ? Recoil_treeCacheValueEquality() : cacheImplementation === Recoil_cacheMostRecent ? Recoil_nodeCacheMostRecent() : Recoil_treeCacheReferenceEquality();
3695 const executionInfo = getInitialExecutionInfo();
3696
3697 function initSelector(store) {
3698 store.getState().knownSelectors.add(key);
3699 }
3700
3701 function notifyStoreWhenAsyncSettles(store, loadable, executionId) {
3702 if (loadable.state === 'loading') {
3703 let stores = waitingStores.get(executionId);
3704
3705 if (stores == null) {
3706 waitingStores.set(executionId, stores = new Set());
3707 }
3708
3709 stores.add(store);
3710 }
3711 }
3712 /**
3713 * FIXME: we should keep track of latest execution id _per store_ and update
3714 * the stores accordingly.
3715 */
3716
3717
3718 function notifyStoresOfSettledAsync(newLoadable, executionId) {
3719 const stores = waitingStores.get(executionId);
3720
3721 if (stores !== undefined) {
3722 for (const store of stores) {
3723 setRecoilValueLoadable$2(store, new AbstractRecoilValue$3(key), newLoadable);
3724 }
3725
3726 waitingStores.delete(executionId);
3727 }
3728 }
3729
3730 function getCachedNodeLoadable(store, state, key) {
3731 if (state.atomValues.has(key)) {
3732 return [new Map(), Recoil_nullthrows(state.atomValues.get(key))];
3733 }
3734
3735 const [, loadable] = getNodeLoadable$2(store, state, key);
3736 const isKeyPointingToSelector = store.getState().knownSelectors.has(key);
3737
3738 if (loadable.state !== 'loading' && isKeyPointingToSelector) {
3739 state.atomValues.set(key, loadable);
3740 }
3741
3742 return [new Map(), loadable];
3743 }
3744 /**
3745 * This function attaches a then() and a catch() to a promise that was
3746 * returned from a selector's get() (either explicitly or implicitly by
3747 * running a function that uses the "async" keyword). If a selector's get()
3748 * returns a promise, we have two possibilities:
3749 *
3750 * 1. The promise will resolve, in which case it will have completely finished
3751 * executing without any remaining pending dependencies. No more retries
3752 * are needed and we can proceed with updating the cache and notifying
3753 * subscribers (if it is the latest execution, otherwise only the cache
3754 * will be updated and subscriptions will not be fired). This is the case
3755 * handled by the attached then() handler.
3756 *
3757 * 2. The promise will throw because it either has an error or it came across
3758 * an async dependency that has not yet resolved, in which case we will
3759 * call wrapDepdencyPromise(), whose responsibility is to handle dependency
3760 * promises. This case is handled by the attached catch() handler.
3761 *
3762 * Both branches will eventually resolve to the final result of the selector
3763 * (or an error if a real error occurred).
3764 *
3765 * The execution will run to completion even if it is stale, and its value
3766 * will be cached. But stale executions will not update global state or update
3767 * executionInfo as that is the responsibility of the 'latest' execution.
3768 *
3769 * Note this function should not be passed a promise that was thrown--AKA a
3770 * dependency promise. Dependency promises should be passed to
3771 * wrapPendingDependencyPromise()).
3772 */
3773
3774
3775 function wrapPendingPromise(store, promise, state, depValues, executionId) {
3776 return promise.then(value => {
3777 const loadable = loadableWithValue$1(value);
3778 maybeFreezeValue(value);
3779 setCache(state, depValuesToDepRoute(depValues), loadable);
3780 setLoadableInStoreToNotifyDeps(loadable, executionId);
3781 return {
3782 __value: value,
3783 __key: key
3784 };
3785 }).catch(errorOrPromise => {
3786 if (isLatestExecution(executionId)) {
3787 updateExecutionInfoDepValues(depValues, executionId);
3788 }
3789
3790 if (Recoil_isPromise(errorOrPromise)) {
3791 return wrapPendingDependencyPromise(store, errorOrPromise, state, depValues, executionId);
3792 }
3793
3794 const loadable = loadableWithError$1(errorOrPromise);
3795 maybeFreezeValue(errorOrPromise);
3796 setCache(state, depValuesToDepRoute(depValues), loadable);
3797 setLoadableInStoreToNotifyDeps(loadable, executionId);
3798 throw errorOrPromise;
3799 });
3800 }
3801 /**
3802 * This function attaches a then() and a catch() to a promise that was
3803 * thrown from a selector's get(). If a selector's get() throws a promise,
3804 * we have two possibilities:
3805 *
3806 * 1. The promise will resolve, meaning one of our selector's dependencies is
3807 * now available and we should "retry" our get() by running it again. This
3808 * is the case handled by the attached then() handler.
3809 *
3810 * 2. The promise will throw because something went wrong with the dependency
3811 * promise (in other words a real error occurred). This case is handled by
3812 * the attached catch() handler. If the dependency promise throws, it is
3813 * _always_ a real error and not another dependency promise (any dependency
3814 * promises would have been handled upstream).
3815 *
3816 * The then() branch will eventually resolve to the final result of the
3817 * selector (or an error if a real error occurs), and the catch() will always
3818 * resolve to an error because the dependency promise is a promise that was
3819 * wrapped upstream, meaning it will only resolve to its real value or to a
3820 * real error.
3821 *
3822 * The execution will run to completion even if it is stale, and its value
3823 * will be cached. But stale executions will not update global state or update
3824 * executionInfo as that is the responsibility of the 'latest' execution.
3825 *
3826 * Note this function should not be passed a promise that was returned from
3827 * get(). The intention is that this function is only passed promises that
3828 * were thrown due to a pending dependency. Promises returned by get() should
3829 * be passed to wrapPendingPromise() instead.
3830 */
3831
3832
3833 function wrapPendingDependencyPromise(store, promise, state, existingDeps, executionId) {
3834 return promise.then(resolvedDep => {
3835 const {
3836 __key: resolvedDepKey,
3837 __value: depValue
3838 } = resolvedDep;
3839
3840 if (resolvedDepKey != null) {
3841 /**
3842 * Note for async atoms, this means we are changing the atom's value
3843 * in the store for the given version. This should be alright because
3844 * the version of state is now stale and a new version will have
3845 * already been triggered by the atom being resolved (see this logic
3846 * in Recoil_atom.js)
3847 */
3848 state.atomValues.set(resolvedDepKey, loadableWithValue$1(depValue));
3849 }
3850
3851 const [loadable, depValues] = evaluateSelectorGetter(store, state, executionId);
3852
3853 if (isLatestExecution(executionId)) {
3854 updateExecutionInfoDepValues(depValues, executionId);
3855 }
3856
3857 maybeFreezeLoadableContents(loadable);
3858
3859 if (loadable.state !== 'loading') {
3860 setCache(state, depValuesToDepRoute(depValues), loadable);
3861 setLoadableInStoreToNotifyDeps(loadable, executionId);
3862 }
3863
3864 if (loadable.state === 'hasError') {
3865 throw loadable.contents;
3866 }
3867
3868 if (loadable.state === 'hasValue') {
3869 return {
3870 __value: loadable.contents,
3871 __key: key
3872 };
3873 }
3874 /**
3875 * Returning promise here without wrapping as the wrapepr logic was
3876 * already done when we called evaluateSelectorGetter() to get this
3877 * loadable
3878 */
3879
3880
3881 return loadable.contents;
3882 }).catch(error => {
3883 const loadable = loadableWithError$1(error);
3884 maybeFreezeValue(error);
3885 setCache(state, depValuesToDepRoute(existingDeps), loadableWithError$1(error));
3886 setLoadableInStoreToNotifyDeps(loadable, executionId);
3887 throw error;
3888 });
3889 }
3890
3891 function setLoadableInStoreToNotifyDeps(loadable, executionId) {
3892 if (isLatestExecution(executionId)) {
3893 setExecutionInfo(loadable);
3894 notifyStoresOfSettledAsync(loadable, executionId);
3895 }
3896 }
3897
3898 function setDepsInStore(store, state, deps, executionId) {
3899 var _store$getState, _store$getState$curre, _store$getState2, _store$getState2$next;
3900
3901 if (isLatestExecution(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)) {
3902 var _store$getState$nextT, _store$getState3, _store$getState3$next;
3903
3904 saveDependencyMapToStore$3(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);
3905 }
3906 }
3907
3908 function setNewDepInStore(store, state, deps, newDepKey, executionId) {
3909 deps.add(newDepKey);
3910 setDepsInStore(store, state, deps, executionId);
3911 }
3912
3913 function evaluateSelectorGetter(store, state, executionId) {
3914 const endPerfBlock = startPerfBlock$1(key); // TODO T63965866: use execution ID here
3915
3916 let result;
3917 let loadable;
3918 const depValues = new Map();
3919 /**
3920 * Starting a fresh set of deps that we'll be using to update state. We're
3921 * starting a new set versus adding it in existing state deps because
3922 * the version of state that we update deps for may be a more recent version
3923 * than the version the selector was called with. This is because the latest
3924 * execution will update the deps of the current/latest version of state (
3925 * this is safe to do because the fact that the selector is the latest
3926 * execution means the deps we discover below are our best guess at the
3927 * deps for the current/latest state in the store)
3928 */
3929
3930 const deps = new Set();
3931 setDepsInStore(store, state, deps, executionId);
3932
3933 function getRecoilValue(recoilValue) {
3934 const {
3935 key: depKey
3936 } = recoilValue;
3937 setNewDepInStore(store, state, deps, depKey, executionId);
3938 const [, depLoadable] = getCachedNodeLoadable(store, state, depKey);
3939 depValues.set(depKey, depLoadable);
3940
3941 if (depLoadable.state === 'hasValue') {
3942 return depLoadable.contents;
3943 }
3944
3945 throw depLoadable.contents;
3946 }
3947
3948 try {
3949 result = get({
3950 get: getRecoilValue
3951 });
3952 result = isRecoilValue$3(result) ? getRecoilValue(result) : result;
3953
3954 if (Recoil_isPromise(result)) {
3955 result = wrapPendingPromise(store, result, state, depValues, executionId).finally(endPerfBlock);
3956 } else {
3957 endPerfBlock();
3958 }
3959 } catch (errorOrDepPromise) {
3960 result = errorOrDepPromise;
3961
3962 if (Recoil_isPromise(result)) {
3963 result = wrapPendingDependencyPromise(store, result, state, depValues, executionId).finally(endPerfBlock);
3964 } else {
3965 endPerfBlock();
3966 }
3967 }
3968
3969 if (result instanceof Error) {
3970 loadable = loadableWithError$1(result);
3971 } else if (Recoil_isPromise(result)) {
3972 loadable = loadableWithPromise$1(result);
3973 } else {
3974 loadable = loadableWithValue$1(result);
3975 }
3976
3977 maybeFreezeLoadableContents(loadable);
3978 return [loadable, depValues];
3979 }
3980
3981 function getValFromCacheAndUpdatedDownstreamDeps(store, state) {
3982 var _store$getGraph$nodeD;
3983
3984 if (state.atomValues.has(key)) {
3985 return state.atomValues.get(key);
3986 }
3987
3988 const deps = new Set((_store$getGraph$nodeD = store.getGraph(state.version).nodeDeps.get(key)) !== null && _store$getGraph$nodeD !== void 0 ? _store$getGraph$nodeD : emptySet$1);
3989 setDepsInStore(store, state, deps, executionInfo.latestExecutionId);
3990 const cachedVal = cache.get(nodeKey => {
3991 const [, loadable] = getCachedNodeLoadable(store, state, nodeKey);
3992 return loadable.contents;
3993 }, {
3994 onCacheHit: nodeKey => {
3995 if (nodeKey !== key) {
3996 setNewDepInStore(store, state, deps, nodeKey, executionInfo.latestExecutionId);
3997 }
3998 }
3999 });
4000 return cachedVal;
4001 }
4002 /**
4003 * FIXME: dep keys should take into account the state of the loadable to
4004 * prevent the edge case where a loadable with an error and a loadable with
4005 * an error as a value are treated as the same thing incorrectly. For example
4006 * these two should be treated differently:
4007 *
4008 * selector({key: '', get: () => new Error('hi')});
4009 * selector({key: '', get () => {throw new Error('hi')}});
4010 *
4011 * With current implementation they are treated the same
4012 */
4013
4014
4015 function depValuesToDepRoute(depValues) {
4016 return Array.from(depValues.entries()).map(([key, valLoadable]) => [key, valLoadable.contents]);
4017 }
4018
4019 function getValFromRunningNewExecutionAndUpdatedDeps(store, state) {
4020 const newExecutionId = getNewExecutionId();
4021 const [loadable, newDepValues] = evaluateSelectorGetter(store, state, newExecutionId);
4022 setExecutionInfo(loadable, newDepValues, newExecutionId, state);
4023 maybeSetCacheWithLoadable(state, depValuesToDepRoute(newDepValues), loadable);
4024 notifyStoreWhenAsyncSettles(store, loadable, newExecutionId);
4025 return loadable;
4026 }
4027 /**
4028 * Given a tree state, this function returns the "selector result", which is
4029 * defined as a size-2 tuple of [DependencyMap, Loadable<T>].
4030 *
4031 * The selector's get() function will only be re-evaluated if _both_ of the
4032 * following statements are true:
4033 *
4034 * 1. The current dep values from the given state produced a cache key that
4035 * was not found in the cache.
4036 * 2. There is no currently running async execution OR there is an
4037 * async execution that is running, but after comparing the dep values in
4038 * the given state with the dep values that the execution has discovered so
4039 * far we find that at least one dep value has changed, in which case we
4040 * start a new execution (the previously running execution will continue to
4041 * run to completion, but only the new execution will be deemed the
4042 * 'latest' execution, meaning it will be the only execution that will
4043 * update global state when it is finished. Any non-latest executions will
4044 * run to completion and update the selector cache but not global state).
4045 */
4046
4047
4048 function getSelectorValAndUpdatedDeps(store, state) {
4049 const cachedVal = getValFromCacheAndUpdatedDownstreamDeps(store, state);
4050
4051 if (cachedVal != null) {
4052 setExecutionInfo(cachedVal);
4053 return cachedVal;
4054 } // FIXME: this won't work with custom caching b/c it uses separate cache
4055
4056
4057 if (asyncWorkIsInProgressAndDepsDiscoveredHaveNotChanged(store, state)) {
4058 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
4059
4060 return Recoil_nullthrows(executionInfo.latestLoadable);
4061 }
4062
4063 return getValFromRunningNewExecutionAndUpdatedDeps(store, state);
4064 }
4065
4066 function asyncWorkIsInProgressAndDepsDiscoveredHaveNotChanged(store, state) {
4067 return executionInfo.latestLoadable != null && executionInfo.latestExecutionId != null && !haveAsyncDepsChanged(store, state);
4068 }
4069
4070 const mapOfCheckedVersions = new Map();
4071
4072 function haveAsyncDepsChanged(store, state) {
4073 var _executionInfo$depVal, _mapOfCheckedVersions;
4074
4075 const oldDepValues = (_executionInfo$depVal = executionInfo.depValuesDiscoveredSoFarDuringAsyncWork) !== null && _executionInfo$depVal !== void 0 ? _executionInfo$depVal : new Map();
4076 const cachedDepValuesCheckedForThisVersion = Array(((_mapOfCheckedVersions = mapOfCheckedVersions.get(state.version)) !== null && _mapOfCheckedVersions !== void 0 ? _mapOfCheckedVersions : new Map()).entries());
4077 const isCachedVersionSame = mapOfCheckedVersions.has(state.version) && cachedDepValuesCheckedForThisVersion.length === oldDepValues.size && cachedDepValuesCheckedForThisVersion.every(([nodeKey, nodeVal]) => {
4078 return oldDepValues.get(nodeKey) === nodeVal;
4079 });
4080
4081 if (oldDepValues == null || state.version === executionInfo.stateVersion || isCachedVersionSame) {
4082 return false;
4083 }
4084
4085 mapOfCheckedVersions.set(state.version, new Map(oldDepValues));
4086 return Array.from(oldDepValues).some(([nodeKey, oldVal]) => {
4087 const [, loadable] = getCachedNodeLoadable(store, state, nodeKey);
4088 return loadable.contents !== oldVal.contents &&
4089 /**
4090 * FIXME: in the condition below we're making the assumption that a
4091 * dependency that goes from loading to having a value is always because
4092 * the dependency resolved to that value, so we don't count it as a dep
4093 * change as the normal retry loop will handle retrying in response to a
4094 * resolved async dep. This is an incorrect assumption for the edge case
4095 * where there is an async selector that is loading, and while it is
4096 * loading one of its dependencies changes, triggering a new execution,
4097 * and that new execution produces a value synchronously (we don't make
4098 * that assumption for asynchronous work b/c it's guaranteed that a
4099 * loadable that goes from 'loading' to 'loading' in a new loadable is
4100 * a dep change).
4101 */
4102 !(oldVal.state === 'loading' && loadable.state !== 'loading');
4103 });
4104 }
4105 /**
4106 * This function will update the selector's execution info when the selector
4107 * has either finished running an execution or has started a new execution. If
4108 * the given loadable is in a 'loading' state, the intention is that a new
4109 * execution has started. Otherwise, the intention is that an execution has
4110 * just finished.
4111 */
4112
4113
4114 function setExecutionInfo(loadable, depValues, newExecutionId, state) {
4115 if (loadable.state === 'loading') {
4116 executionInfo.depValuesDiscoveredSoFarDuringAsyncWork = depValues;
4117 executionInfo.latestExecutionId = newExecutionId;
4118 executionInfo.latestLoadable = loadable;
4119 executionInfo.stateVersion = state === null || state === void 0 ? void 0 : state.version;
4120 } else {
4121 executionInfo.depValuesDiscoveredSoFarDuringAsyncWork = null;
4122 executionInfo.latestExecutionId = null;
4123 executionInfo.latestLoadable = null;
4124 executionInfo.stateVersion = null;
4125 }
4126 }
4127 /**
4128 * Conditionally updates the cache with a given loadable.
4129 *
4130 * We only cache loadables that are not loading because our cache keys are
4131 * based on dep values, which are in an unfinished state for loadables that
4132 * have a 'loading' state (new deps may be discovered while the selector
4133 * runs its async code). We never want to cache partial dependencies b/c it
4134 * could lead to errors, such as prematurely returning the result based on a
4135 * partial list of deps-- we need the full list of deps to ensure that we
4136 * are returning the correct result from cache.
4137 */
4138
4139
4140 function maybeSetCacheWithLoadable(state, depRoute, loadable) {
4141 if (loadable.state !== 'loading') {
4142 setCache(state, depRoute, loadable);
4143 }
4144 }
4145
4146 function updateExecutionInfoDepValues(depValues, executionId) {
4147 if (isLatestExecution(executionId)) {
4148 executionInfo.depValuesDiscoveredSoFarDuringAsyncWork = depValues;
4149 }
4150 }
4151
4152 function isLatestExecution(executionId) {
4153 return executionId === executionInfo.latestExecutionId;
4154 }
4155
4156 function maybeFreezeLoadableContents(loadable) {
4157 if (loadable.state !== 'loading') {
4158 maybeFreezeValue(loadable.contents);
4159 }
4160 }
4161
4162 function maybeFreezeValue(val) {
4163 if (process.env.NODE_ENV !== "production") {
4164 if (Boolean(options.dangerouslyAllowMutability) === false) {
4165 Recoil_deepFreezeValue(val);
4166 }
4167 }
4168 }
4169
4170 function setCache(state, cacheRoute, loadable) {
4171 state.atomValues.set(key, loadable);
4172 cache.set(cacheRoute, loadable);
4173 }
4174
4175 function detectCircularDependencies(fn) {
4176 if (dependencyStack.includes(key)) {
4177 const message = `Recoil selector has circular dependencies: ${dependencyStack.slice(dependencyStack.indexOf(key)).join(' \u2192 ')}`; // eslint-disable-next-line fb-www/no-new-error
4178
4179 return loadableWithError$1(new Error(message));
4180 }
4181
4182 dependencyStack.push(key);
4183
4184 try {
4185 return fn();
4186 } finally {
4187 dependencyStack.pop();
4188 }
4189 }
4190
4191 function myPeek(store, state) {
4192 const cacheVal = cache.get(nodeKey => {
4193 const peek = peekNodeLoadable$2(store, state, nodeKey);
4194 return peek === null || peek === void 0 ? void 0 : peek.contents;
4195 });
4196 return cacheVal;
4197 }
4198
4199 function myGet(store, state) {
4200 initSelector(store);
4201 return [new Map(), detectCircularDependencies(() => getSelectorValAndUpdatedDeps(store, state))];
4202 }
4203
4204 function invalidate(state) {
4205 state.atomValues.delete(key);
4206 }
4207
4208 if (set != null) {
4209 function mySet(store, state, newValue) {
4210 initSelector(store);
4211 const dependencyMap = new Map();
4212 const writes = new Map();
4213
4214 function getRecoilValue({
4215 key
4216 }) {
4217 const [, loadable] = getCachedNodeLoadable(store, state, key);
4218
4219 if (loadable.state === 'hasValue') {
4220 return loadable.contents;
4221 } else if (loadable.state === 'loading') {
4222 throw new RecoilValueNotReady$2(key);
4223 } else {
4224 throw loadable.contents;
4225 }
4226 }
4227
4228 function setRecoilState(recoilState, valueOrUpdater) {
4229 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
4230 // flowlint-next-line unclear-type:off
4231 valueOrUpdater(getRecoilValue(recoilState)) : valueOrUpdater;
4232 const [, upstreamWrites] = setNodeValue$3(store, state, recoilState.key, newValue);
4233 upstreamWrites.forEach((v, k) => writes.set(k, v));
4234 }
4235
4236 function resetRecoilState(recoilState) {
4237 setRecoilState(recoilState, DEFAULT_VALUE$3);
4238 }
4239
4240 set({
4241 set: setRecoilState,
4242 get: getRecoilValue,
4243 reset: resetRecoilState
4244 }, newValue);
4245 return [dependencyMap, writes];
4246 }
4247
4248 return registerNode$1({
4249 key,
4250 peek: myPeek,
4251 get: myGet,
4252 set: mySet,
4253 cleanUp: () => {},
4254 invalidate,
4255 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
4256 shouldRestoreFromSnapshots: false
4257 });
4258 } else {
4259 return registerNode$1({
4260 key,
4261 peek: myPeek,
4262 get: myGet,
4263 cleanUp: () => {},
4264 invalidate,
4265 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
4266 shouldRestoreFromSnapshots: false
4267 });
4268 }
4269}
4270/* eslint-enable no-redeclare */
4271
4272
4273var Recoil_selector_NEW = selector;
4274
4275const {
4276 loadableWithError: loadableWithError$2,
4277 loadableWithPromise: loadableWithPromise$2,
4278 loadableWithValue: loadableWithValue$2
4279} = Recoil_Loadable;
4280
4281
4282
4283const {
4284 getNodeLoadable: getNodeLoadable$3,
4285 peekNodeLoadable: peekNodeLoadable$3,
4286 setNodeValue: setNodeValue$4
4287} = Recoil_FunctionalCore;
4288
4289const {
4290 addToDependencyMap: addToDependencyMap$1,
4291 mergeDepsIntoDependencyMap: mergeDepsIntoDependencyMap$1,
4292 saveDependencyMapToStore: saveDependencyMapToStore$4
4293} = Recoil_Graph;
4294
4295const {
4296 DEFAULT_VALUE: DEFAULT_VALUE$4,
4297 RecoilValueNotReady: RecoilValueNotReady$3,
4298 registerNode: registerNode$2
4299} = Recoil_Node;
4300
4301const {
4302 AbstractRecoilValue: AbstractRecoilValue$4
4303} = Recoil_RecoilValue$1;
4304
4305const {
4306 getRecoilValueAsLoadable: getRecoilValueAsLoadable$3,
4307 isRecoilValue: isRecoilValue$4,
4308 setRecoilValueLoadable: setRecoilValueLoadable$3
4309} = Recoil_RecoilValueInterface;
4310
4311
4312
4313
4314
4315
4316
4317const {
4318 startPerfBlock: startPerfBlock$2
4319} = Recoil_PerformanceTimings;
4320
4321// flowlint-next-line unclear-type:off
4322const emptySet$2 = Object.freeze(new Set());
4323
4324function cacheKeyFromDepValues(depValues) {
4325 const answer = [];
4326
4327 for (const key of Array.from(depValues.keys()).sort()) {
4328 const loadable = Recoil_nullthrows(depValues.get(key));
4329 answer.push(key);
4330 answer.push(loadable.state);
4331 answer.push(loadable.contents);
4332 }
4333
4334 return answer;
4335}
4336
4337const dependencyStack$1 = []; // for detecting circular dependencies.
4338
4339const waitingStores$1 = new Map();
4340/* eslint-disable no-redeclare */
4341
4342function selector$1(options) {
4343 const {
4344 key,
4345 get,
4346 cacheImplementation_UNSTABLE: cacheImplementation
4347 } = options;
4348 const set = options.set != null ? options.set : undefined; // flow
4349
4350 let cache = cacheImplementation !== null && cacheImplementation !== void 0 ? cacheImplementation : Recoil_cacheWithReferenceEquality();
4351
4352 function initSelector(store) {
4353 store.getState().knownSelectors.add(key);
4354 }
4355
4356 function letStoreBeNotifiedWhenAsyncSettles(store, loadable) {
4357 if (loadable.state === 'loading') {
4358 let stores = waitingStores$1.get(loadable);
4359
4360 if (stores === undefined) {
4361 waitingStores$1.set(loadable, stores = new Set());
4362 }
4363
4364 stores.add(store);
4365 }
4366 }
4367
4368 function notifyStoresOfSettledAsync(originalLoadable, newLoadable) {
4369 const stores = waitingStores$1.get(originalLoadable);
4370
4371 if (stores !== undefined) {
4372 for (const store of stores) {
4373 setRecoilValueLoadable$3(store, new AbstractRecoilValue$4(key), newLoadable);
4374 }
4375
4376 waitingStores$1.delete(originalLoadable);
4377 }
4378 }
4379
4380 function putIntoCache(state, cacheKey, loadable) {
4381 if (loadable.state !== 'loading') {
4382 // Synchronous result
4383 if (process.env.NODE_ENV !== "production") {
4384 if (!options.dangerouslyAllowMutability === true) {
4385 Recoil_deepFreezeValue(loadable.contents);
4386 }
4387 }
4388 } else {
4389 // Asynchronous result
4390 // When the promise resolves, we need to replace the loading state in the
4391 // cache and fire any external subscriptions to re-render with the new value.
4392 loadable.contents.then(result => {
4393 if (process.env.NODE_ENV !== "production") {
4394 if (!options.dangerouslyAllowMutability === true) {
4395 Recoil_deepFreezeValue(result);
4396 }
4397 }
4398
4399 const newLoadable = loadableWithValue$2(result); // If the value is now resolved, then update the cache with the new value
4400
4401 cache = cache.set(cacheKey, newLoadable); // TODO Potential optimization: I think this is updating the cache
4402 // with a cacheKey of the dep when it wasn't ready yet. We could also
4403 // theoretically put the result in the cache for a cacheKey with the
4404 // dep resolved. If we had some way of figuring out what that cacheKey was..
4405 // Note that this optimization would change the user visible behavior slightly,
4406 // see the unit test "useRecoilState - selector catching promise 2".
4407 // If the user catches and handles pending async dependencies, then returns
4408 // a promise that resolves when they are available there is a question if
4409 // the result of that promise should be the value of the selector, or if
4410 // the selector should re-evaluate when the dependency is available.
4411 // If the promise returned and the pending dependency resolve at different
4412 // times, then the behaviour is better defined, as in the unit test,
4413 // "useRecoilState - selector catching promise and resolving asynchronously"
4414 // Fire subscriptions to re-render any subscribed components with the new value.
4415 // The store uses the CURRENT state, not the old state from which
4416 // this was called. That state likely doesn't have the subscriptions saved yet.
4417 // Note that we have to set the value for this key, not just notify
4418 // components, so that there will be a new version for useMutableSource.
4419
4420 notifyStoresOfSettledAsync(loadable, newLoadable);
4421 return result;
4422 }).catch(error => {
4423 // TODO Figure out why we are catching promises here versus evaluateSelectorFunction
4424 // OH, I see why. Ok, work on this.
4425 if (Recoil_isPromise(error)) {
4426 return error;
4427 }
4428
4429 if (process.env.NODE_ENV !== "production") {
4430 if (!options.dangerouslyAllowMutability === true) {
4431 Recoil_deepFreezeValue(error);
4432 }
4433 } // The async value was rejected with an error. Update the cache with
4434 // the error and fire subscriptions to re-render.
4435
4436
4437 const newLoadable = loadableWithError$2(error);
4438 cache = cache.set(cacheKey, newLoadable);
4439 notifyStoresOfSettledAsync(loadable, newLoadable);
4440 return error;
4441 });
4442 }
4443
4444 cache = cache.set(cacheKey, loadable);
4445
4446 if (loadable.state !== 'loading') {
4447 state.atomValues.set(key, loadable);
4448 }
4449 }
4450
4451 function getFromCacheOrEvaluate(store, state) {
4452 var _store$getGraph$nodeD;
4453
4454 const dependencyMap = new Map(); // First, get the current deps for this selector
4455
4456 const currentDeps = (_store$getGraph$nodeD = store.getGraph(state.version).nodeDeps.get(key)) !== null && _store$getGraph$nodeD !== void 0 ? _store$getGraph$nodeD : emptySet$2;
4457 const depValues = new Map(Array.from(currentDeps).sort().map(depKey => {
4458 const [deps, loadable] = getNodeLoadable$3(store, state, depKey);
4459 mergeDepsIntoDependencyMap$1(deps, dependencyMap);
4460 saveDependencyMapToStore$4(dependencyMap, store, state.version);
4461 return [depKey, loadable];
4462 })); // Always cache and evaluate a selector
4463 // It may provide a result even when not all deps are available.
4464
4465 const cacheKey = cacheKeyFromDepValues(depValues);
4466 const cached = cache.get(cacheKey);
4467
4468 if (cached != null) {
4469 letStoreBeNotifiedWhenAsyncSettles(store, cached);
4470 return [dependencyMap, cached];
4471 } // Cache miss, compute the value
4472
4473
4474 const [deps, loadable, newDepValues] = evaluateSelectorFunction(store, state);
4475 mergeDepsIntoDependencyMap$1(deps, dependencyMap);
4476 saveDependencyMapToStore$4(dependencyMap, store, state.version); // Save result in cache
4477
4478 const newCacheKey = cacheKeyFromDepValues(newDepValues);
4479 letStoreBeNotifiedWhenAsyncSettles(store, loadable);
4480 putIntoCache(state, newCacheKey, loadable);
4481 return [dependencyMap, loadable];
4482 }
4483
4484 function evaluateSelectorFunction(store, state) {
4485 const endPerfBlock = startPerfBlock$2(key);
4486 const depValues = new Map(); // key -> value for our deps
4487
4488 const dependencyMap = new Map(); // node -> nodes, part of overall dep map.
4489
4490 function getRecoilValue({
4491 key: depKey
4492 }) {
4493 addToDependencyMap$1(key, depKey, dependencyMap);
4494 const [deps, loadable] = getNodeLoadable$3(store, state, depKey);
4495 depValues.set(depKey, loadable);
4496 mergeDepsIntoDependencyMap$1(deps, dependencyMap);
4497 saveDependencyMapToStore$4(dependencyMap, store, state.version);
4498
4499 if (loadable.state === 'hasValue') {
4500 return loadable.contents;
4501 } else {
4502 throw loadable.contents; // Promise or error
4503 }
4504 }
4505
4506 try {
4507 // The big moment!
4508 const output = get({
4509 get: getRecoilValue
4510 }); // TODO Allow user to also return Loadables for improved composability
4511
4512 const result = isRecoilValue$4(output) ? getRecoilValue(output) : output;
4513 let loadable;
4514
4515 if (!Recoil_isPromise(result)) {
4516 // The selector returned a simple synchronous value, so let's use it!
4517 endPerfBlock();
4518 loadable = loadableWithValue$2(result);
4519 } else {
4520 // The user returned a promise for an asynchronous selector. This will
4521 // resolve to the proper value of the selector when available.
4522 loadable = loadableWithPromise$2(result.finally(endPerfBlock));
4523 }
4524
4525 return [dependencyMap, loadable, depValues];
4526 } catch (errorOrDepPromise) {
4527 // XXX why was this changed to not use isPromise?
4528 const isP = errorOrDepPromise.then !== undefined;
4529 let loadable;
4530
4531 if (!isP) {
4532 // There was a synchronous error in the evaluation
4533 endPerfBlock();
4534 loadable = loadableWithError$2(errorOrDepPromise);
4535 } else {
4536 // If an asynchronous dependency was not ready, then return a promise that
4537 // will resolve when we finally do have a real value or error for the selector.
4538 loadable = loadableWithPromise$2(errorOrDepPromise.then(() => {
4539 // Now that its deps are ready, re-evaluate the selector (and
4540 // record any newly-discovered dependencies in the Store):
4541 const loadable = getRecoilValueAsLoadable$3(store, new AbstractRecoilValue$4(key));
4542
4543 if (loadable.state === 'hasError') {
4544 throw loadable.contents;
4545 } // Either the re-try provided a value, which we will use, or it
4546 // got blocked again. In that case this is a promise and we'll try again.
4547
4548
4549 return loadable.contents;
4550 }).finally(endPerfBlock));
4551 }
4552
4553 return [dependencyMap, loadable, depValues];
4554 }
4555 }
4556
4557 function detectCircularDependencies(fn) {
4558 if (dependencyStack$1.includes(key)) {
4559 const message = `Recoil selector has circular dependencies: ${dependencyStack$1.slice(dependencyStack$1.indexOf(key)).join(' \u2192 ')}`;
4560 return [new Map(), loadableWithError$2(new Error(message))];
4561 }
4562
4563 dependencyStack$1.push(key);
4564
4565 try {
4566 return fn();
4567 } finally {
4568 dependencyStack$1.pop();
4569 }
4570 }
4571
4572 function myPeek(store, state) {
4573 var _store$getGraph$nodeD2;
4574
4575 // First, get the current deps for this selector
4576 const currentDeps = (_store$getGraph$nodeD2 = store.getGraph(state.version).nodeDeps.get(key)) !== null && _store$getGraph$nodeD2 !== void 0 ? _store$getGraph$nodeD2 : emptySet$2;
4577 const depValues = new Map(Array.from(currentDeps).sort().map(depKey => [depKey, peekNodeLoadable$3(store, state, depKey)]));
4578 const cacheDepValues = new Map();
4579
4580 for (const [depKey, depValue] of depValues.entries()) {
4581 if (depValue == null) {
4582 return undefined;
4583 }
4584
4585 cacheDepValues.set(depKey, depValue);
4586 } // Always cache and evaluate a selector
4587 // It may provide a result even when not all deps are available.
4588
4589
4590 const cacheKey = cacheKeyFromDepValues(cacheDepValues);
4591 return cache.get(cacheKey);
4592 }
4593
4594 function invalidate(state) {
4595 state.atomValues.delete(key);
4596 }
4597
4598 function myGet(store, state) {
4599 initSelector(store); // First-level cache: Have we already evaluated the selector since being
4600 // invalidated due to a dependency changing?
4601
4602 const cached = state.atomValues.get(key);
4603
4604 if (cached !== undefined) {
4605 return [new Map(), cached];
4606 } // Second-level cache based on looking up current dependencies in a map
4607 // and evaluating selector if missing.
4608
4609
4610 if (process.env.NODE_ENV !== "production") {
4611 return detectCircularDependencies(() => getFromCacheOrEvaluate(store, state));
4612 } else {
4613 return getFromCacheOrEvaluate(store, state);
4614 }
4615 }
4616
4617 if (set != null) {
4618 function mySet(store, state, newValue) {
4619 initSelector(store);
4620 const dependencyMap = new Map();
4621 const writes = new Map();
4622
4623 function getRecoilValue({
4624 key
4625 }) {
4626 const [deps, loadable] = getNodeLoadable$3(store, state, key);
4627 mergeDepsIntoDependencyMap$1(deps, dependencyMap);
4628
4629 if (loadable.state === 'hasValue') {
4630 return loadable.contents;
4631 } else if (loadable.state === 'loading') {
4632 throw new RecoilValueNotReady$3(key);
4633 } else {
4634 throw loadable.contents;
4635 }
4636 }
4637
4638 function setRecoilState(recoilState, valueOrUpdater) {
4639 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
4640 // flowlint-next-line unclear-type:off
4641 valueOrUpdater(getRecoilValue(recoilState)) : valueOrUpdater;
4642 const [deps, upstreamWrites] = setNodeValue$4(store, state, recoilState.key, newValue);
4643 mergeDepsIntoDependencyMap$1(deps, dependencyMap);
4644 upstreamWrites.forEach((v, k) => writes.set(k, v));
4645 }
4646
4647 function resetRecoilState(recoilState) {
4648 setRecoilState(recoilState, DEFAULT_VALUE$4);
4649 }
4650
4651 set({
4652 set: setRecoilState,
4653 get: getRecoilValue,
4654 reset: resetRecoilState
4655 }, newValue);
4656 return [dependencyMap, writes];
4657 }
4658
4659 return registerNode$2({
4660 key,
4661 peek: myPeek,
4662 get: myGet,
4663 set: mySet,
4664 invalidate,
4665 cleanUp: () => {},
4666 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
4667 shouldRestoreFromSnapshots: false
4668 });
4669 } else {
4670 return registerNode$2({
4671 key,
4672 peek: myPeek,
4673 get: myGet,
4674 invalidate,
4675 cleanUp: () => {},
4676 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
4677 shouldRestoreFromSnapshots: false
4678 });
4679 }
4680}
4681/* eslint-enable no-redeclare */
4682
4683
4684var Recoil_selector_OLD = selector$1;
4685
4686const selector$2 = Recoil_gkx_1('recoil_async_selector_refactor') ? Recoil_selector_NEW : Recoil_selector_OLD;
4687var Recoil_selector = selector$2;
4688
4689// @fb-only: const {scopedAtom} = require('Recoil_ScopedAtom');
4690const {
4691 loadableWithError: loadableWithError$3,
4692 loadableWithPromise: loadableWithPromise$3,
4693 loadableWithValue: loadableWithValue$3
4694} = Recoil_Loadable;
4695
4696const {
4697 DEFAULT_VALUE: DEFAULT_VALUE$5,
4698 DefaultValue: DefaultValue$2,
4699 registerNode: registerNode$3
4700} = Recoil_Node;
4701
4702const {
4703 isRecoilValue: isRecoilValue$5
4704} = Recoil_RecoilValue$1;
4705
4706const {
4707 markRecoilValueModified: markRecoilValueModified$1,
4708 setRecoilValue: setRecoilValue$3,
4709 setRecoilValueLoadable: setRecoilValueLoadable$4
4710} = Recoil_RecoilValueInterface;
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724function baseAtom(options) {
4725 const {
4726 key,
4727 persistence_UNSTABLE: persistence
4728 } = options;
4729 let defaultLoadable = Recoil_isPromise(options.default) ? loadableWithPromise$3(options.default.then(value => {
4730 defaultLoadable = loadableWithValue$3(value); // TODO Temporary disable Flow due to pending selector_NEW refactor
4731
4732 const promiseInfo = {
4733 __key: key,
4734 __value: value
4735 };
4736 return promiseInfo;
4737 }).catch(error => {
4738 defaultLoadable = loadableWithError$3(error);
4739 throw error;
4740 })) : loadableWithValue$3(options.default);
4741 let cachedAnswerForUnvalidatedValue = undefined; // Cleanup handlers for this atom
4742 // Rely on stable reference equality of the store to use it as a key per <RecoilRoot>
4743
4744 const cleanupEffectsByStore = new Map();
4745
4746 function wrapPendingPromise(store, promise) {
4747 const wrappedPromise = promise.then(value => {
4748 var _store$getState$nextT, _state$atomValues$get;
4749
4750 const state = (_store$getState$nextT = store.getState().nextTree) !== null && _store$getState$nextT !== void 0 ? _store$getState$nextT : store.getState().currentTree;
4751
4752 if (((_state$atomValues$get = state.atomValues.get(key)) === null || _state$atomValues$get === void 0 ? void 0 : _state$atomValues$get.contents) === wrappedPromise) {
4753 setRecoilValue$3(store, node, value);
4754 }
4755
4756 return {
4757 __key: key,
4758 __value: value
4759 };
4760 }).catch(error => {
4761 var _store$getState$nextT2, _state$atomValues$get2;
4762
4763 const state = (_store$getState$nextT2 = store.getState().nextTree) !== null && _store$getState$nextT2 !== void 0 ? _store$getState$nextT2 : store.getState().currentTree;
4764
4765 if (((_state$atomValues$get2 = state.atomValues.get(key)) === null || _state$atomValues$get2 === void 0 ? void 0 : _state$atomValues$get2.contents) === wrappedPromise) {
4766 setRecoilValueLoadable$4(store, node, loadableWithError$3(error));
4767 }
4768
4769 throw error;
4770 });
4771 return wrappedPromise;
4772 }
4773
4774 function initAtom(store, initState, trigger) {
4775 if (store.getState().knownAtoms.has(key)) {
4776 return;
4777 }
4778
4779 store.getState().knownAtoms.add(key); // Setup async defaults to notify subscribers when they resolve
4780
4781 if (defaultLoadable.state === 'loading') {
4782 function notifyDefaultSubscribers() {
4783 var _store$getState$nextT3;
4784
4785 const state = (_store$getState$nextT3 = store.getState().nextTree) !== null && _store$getState$nextT3 !== void 0 ? _store$getState$nextT3 : store.getState().currentTree;
4786
4787 if (!state.atomValues.has(key)) {
4788 markRecoilValueModified$1(store, node);
4789 }
4790 }
4791
4792 defaultLoadable.contents.then(notifyDefaultSubscribers).catch(notifyDefaultSubscribers);
4793 } // Run Atom Effects
4794 // This state is scoped by Store, since this is in the initAtom() closure
4795
4796
4797 let initValue = DEFAULT_VALUE$5;
4798 let pendingSetSelf = null;
4799
4800 if (options.effects_UNSTABLE != null) {
4801 let duringInit = true;
4802
4803 const setSelf = effect => valueOrUpdater => {
4804 if (duringInit) {
4805 const currentValue = initValue instanceof DefaultValue$2 || Recoil_isPromise(initValue) ? defaultLoadable.state === 'hasValue' ? defaultLoadable.contents : DEFAULT_VALUE$5 : initValue;
4806 initValue = typeof valueOrUpdater === 'function' ? // cast to any because we can't restrict T from being a function without losing support for opaque types
4807 valueOrUpdater(currentValue) // flowlint-line unclear-type:off
4808 : valueOrUpdater;
4809 } else {
4810 if (Recoil_isPromise(valueOrUpdater)) {
4811 throw new Error('Setting atoms to async values is not implemented.');
4812 }
4813
4814 if (typeof valueOrUpdater !== 'function') {
4815 pendingSetSelf = {
4816 effect,
4817 value: valueOrUpdater
4818 };
4819 }
4820
4821 setRecoilValue$3(store, node, typeof valueOrUpdater === 'function' ? currentValue => {
4822 const newValue = // cast to any because we can't restrict T from being a function without losing support for opaque types
4823 valueOrUpdater(currentValue); // flowlint-line unclear-type:off
4824
4825 pendingSetSelf = {
4826 effect,
4827 value: newValue
4828 };
4829 return newValue;
4830 } : valueOrUpdater);
4831 }
4832 };
4833
4834 const resetSelf = effect => () => setSelf(effect)(DEFAULT_VALUE$5);
4835
4836 const onSet = effect => handler => {
4837 store.subscribeToTransactions(currentStore => {
4838 var _pendingSetSelf3;
4839
4840 // eslint-disable-next-line prefer-const
4841 let {
4842 currentTree,
4843 previousTree
4844 } = currentStore.getState();
4845
4846 if (!previousTree) {
4847 Recoil_recoverableViolation('Transaction subscribers notified without a next tree being present -- this is a bug in Recoil');
4848 previousTree = currentTree; // attempt to trundle on
4849 }
4850
4851 const newLoadable = currentTree.atomValues.get(key);
4852
4853 if (newLoadable == null || newLoadable.state === 'hasValue') {
4854 var _previousTree$atomVal, _pendingSetSelf, _pendingSetSelf2;
4855
4856 const newValue = newLoadable != null ? newLoadable.contents : DEFAULT_VALUE$5;
4857 const oldLoadable = (_previousTree$atomVal = previousTree.atomValues.get(key)) !== null && _previousTree$atomVal !== void 0 ? _previousTree$atomVal : defaultLoadable;
4858 const oldValue = oldLoadable.state === 'hasValue' ? oldLoadable.contents : DEFAULT_VALUE$5; // TODO This isn't actually valid, use as a placeholder for now.
4859 // Ignore atom value changes that were set via setSelf() in the same effect.
4860 // We will still properly call the handler if there was a subsequent
4861 // set from something other than an atom effect which was batched
4862 // with the `setSelf()` call. However, we may incorrectly ignore
4863 // the handler if the subsequent batched call happens to set the
4864 // atom to the exact same value as the `setSelf()`. But, in that
4865 // case, it was kind of a noop, so the semantics are debatable..
4866
4867 if (((_pendingSetSelf = pendingSetSelf) === null || _pendingSetSelf === void 0 ? void 0 : _pendingSetSelf.effect) !== effect || ((_pendingSetSelf2 = pendingSetSelf) === null || _pendingSetSelf2 === void 0 ? void 0 : _pendingSetSelf2.value) !== newValue) {
4868 handler(newValue, oldValue);
4869 }
4870 }
4871
4872 if (((_pendingSetSelf3 = pendingSetSelf) === null || _pendingSetSelf3 === void 0 ? void 0 : _pendingSetSelf3.effect) === effect) {
4873 pendingSetSelf = null;
4874 }
4875 }, key);
4876 };
4877
4878 for (const effect of (_options$effects_UNST = options.effects_UNSTABLE) !== null && _options$effects_UNST !== void 0 ? _options$effects_UNST : []) {
4879 var _options$effects_UNST;
4880
4881 const cleanup = effect({
4882 node,
4883 trigger,
4884 setSelf: setSelf(effect),
4885 resetSelf: resetSelf(effect),
4886 onSet: onSet(effect)
4887 });
4888
4889 if (cleanup != null) {
4890 cleanupEffectsByStore.set(store, cleanup);
4891 }
4892 }
4893
4894 duringInit = false;
4895 } // Mutate initial state in place since we know there are no other subscribers
4896 // since we are the ones initializing on first use.
4897
4898
4899 if (!(initValue instanceof DefaultValue$2)) {
4900 initState.atomValues.set(key, Recoil_isPromise(initValue) ? loadableWithPromise$3(wrapPendingPromise(store, initValue)) : loadableWithValue$3(initValue));
4901 }
4902 }
4903
4904 function myPeek(_store, state) {
4905 var _ref, _state$atomValues$get3, _cachedAnswerForUnval;
4906
4907 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;
4908 }
4909
4910 function myGet(store, state) {
4911 initAtom(store, state, 'get');
4912
4913 if (state.atomValues.has(key)) {
4914 // Atom value is stored in state:
4915 return [new Map(), Recoil_nullthrows(state.atomValues.get(key))];
4916 } else if (state.nonvalidatedAtoms.has(key)) {
4917 // Atom value is stored but needs validation before use.
4918 // We might have already validated it and have a cached validated value:
4919 if (cachedAnswerForUnvalidatedValue != null) {
4920 return cachedAnswerForUnvalidatedValue;
4921 }
4922
4923 if (persistence == null) {
4924 Recoil_expectationViolation(`Tried to restore a persisted value for atom ${key} but it has no persistence settings.`);
4925 return [new Map(), defaultLoadable];
4926 }
4927
4928 const nonvalidatedValue = state.nonvalidatedAtoms.get(key);
4929 const validatorResult = persistence.validator(nonvalidatedValue, DEFAULT_VALUE$5);
4930 const validatedValueLoadable = validatorResult instanceof DefaultValue$2 ? defaultLoadable : loadableWithValue$3(validatorResult);
4931 cachedAnswerForUnvalidatedValue = [new Map(), validatedValueLoadable];
4932 return cachedAnswerForUnvalidatedValue;
4933 } else {
4934 return [new Map(), defaultLoadable];
4935 }
4936 }
4937
4938 function myCleanup(store) {
4939 var _cleanupEffectsByStor;
4940
4941 (_cleanupEffectsByStor = cleanupEffectsByStore.get(store)) === null || _cleanupEffectsByStor === void 0 ? void 0 : _cleanupEffectsByStor();
4942 cleanupEffectsByStore.delete(store);
4943 }
4944
4945 function invalidate() {
4946 cachedAnswerForUnvalidatedValue = undefined;
4947 }
4948
4949 function mySet(store, state, newValue) {
4950 initAtom(store, state, 'set'); // Bail out if we're being set to the existing value, or if we're being
4951 // reset but have no stored value (validated or unvalidated) to reset from:
4952
4953 if (state.atomValues.has(key)) {
4954 const existing = Recoil_nullthrows(state.atomValues.get(key));
4955
4956 if (existing.state === 'hasValue' && newValue === existing.contents) {
4957 return [new Map(), new Map()];
4958 }
4959 } else if (!state.nonvalidatedAtoms.has(key) && newValue instanceof DefaultValue$2) {
4960 return [new Map(), new Map()];
4961 }
4962
4963 if (process.env.NODE_ENV !== "production") {
4964 if (options.dangerouslyAllowMutability !== true) {
4965 Recoil_deepFreezeValue(newValue);
4966 }
4967 }
4968
4969 cachedAnswerForUnvalidatedValue = undefined; // can be released now if it was previously in use
4970
4971 return [new Map(), new Map().set(key, loadableWithValue$3(newValue))];
4972 }
4973
4974 const node = registerNode$3({
4975 key,
4976 peek: myPeek,
4977 get: myGet,
4978 set: mySet,
4979 cleanUp: myCleanup,
4980 invalidate,
4981 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
4982 persistence_UNSTABLE: options.persistence_UNSTABLE ? {
4983 type: options.persistence_UNSTABLE.type,
4984 backButton: options.persistence_UNSTABLE.backButton
4985 } : undefined,
4986 shouldRestoreFromSnapshots: true
4987 });
4988 return node;
4989} // prettier-ignore
4990
4991
4992function atom(options) {
4993 const {
4994 default: optionsDefault,
4995 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
4996 ...restOptions
4997 } = options;
4998
4999 if (isRecoilValue$5(optionsDefault) // Continue to use atomWithFallback for promise defaults for scoped atoms
5000 // for now, since scoped atoms don't support async defaults
5001 // @fb-only: || (isPromise(optionsDefault) && scopeRules_APPEND_ONLY_READ_THE_DOCS)
5002 ) {
5003 return atomWithFallback({ ...restOptions,
5004 default: optionsDefault // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
5005
5006 }); // @fb-only: } else if (scopeRules_APPEND_ONLY_READ_THE_DOCS && !isPromise(optionsDefault)) {
5007 // @fb-only: return scopedAtom<T>({
5008 // @fb-only: ...restOptions,
5009 // @fb-only: default: optionsDefault,
5010 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
5011 // @fb-only: });
5012 } else {
5013 return baseAtom({ ...restOptions,
5014 default: optionsDefault
5015 });
5016 }
5017}
5018
5019function atomWithFallback(options) {
5020 const base = atom({ ...options,
5021 default: DEFAULT_VALUE$5,
5022 persistence_UNSTABLE: options.persistence_UNSTABLE === undefined ? undefined : { ...options.persistence_UNSTABLE,
5023 validator: storedValue => storedValue instanceof DefaultValue$2 ? storedValue : Recoil_nullthrows(options.persistence_UNSTABLE).validator(storedValue, DEFAULT_VALUE$5)
5024 },
5025 // TODO Hack for now.
5026 // flowlint-next-line unclear-type: off
5027 effects_UNSTABLE: options.effects_UNSTABLE
5028 });
5029 return Recoil_selector({
5030 key: `${options.key}__withFallback`,
5031 get: ({
5032 get
5033 }) => {
5034 const baseValue = get(base);
5035 return baseValue instanceof DefaultValue$2 ? options.default : baseValue;
5036 },
5037 set: ({
5038 set
5039 }, newValue) => set(base, newValue),
5040 dangerouslyAllowMutability: options.dangerouslyAllowMutability
5041 });
5042}
5043
5044var Recoil_atom = atom;
5045
5046// Keep in mind the parameter needs to be serializable as a cahche key
5047// using Recoil_stableStringify
5048
5049
5050// Add a unique index to each selector in case the cache implementation allows
5051// duplicate keys based on equivalent stringified parameters
5052let nextIndex = 0;
5053/* eslint-disable no-redeclare */
5054
5055// Return a function that returns members of a family of selectors of the same type
5056// E.g.,
5057//
5058// const s = selectorFamily(...);
5059// s({a: 1}) => a selector
5060// s({a: 2}) => a different selector
5061//
5062// By default, the selectors are distinguished by distinct values of the
5063// parameter based on value equality, not reference equality. This allows using
5064// object literals or other equivalent objects at callsites to not create
5065// duplicate cache entries. This behavior may be overridden with the
5066// cacheImplementationForParams option.
5067function selectorFamily(options) {
5068 var _options$cacheImpleme, _options$cacheImpleme2;
5069
5070 let selectorCache = (_options$cacheImpleme = (_options$cacheImpleme2 = options.cacheImplementationForParams_UNSTABLE) === null || _options$cacheImpleme2 === void 0 ? void 0 : _options$cacheImpleme2.call(options)) !== null && _options$cacheImpleme !== void 0 ? _options$cacheImpleme : Recoil_cacheWithValueEquality();
5071 return params => {
5072 var _stableStringify, _options$cacheImpleme3;
5073
5074 const cachedSelector = selectorCache.get(params);
5075
5076 if (cachedSelector != null) {
5077 return cachedSelector;
5078 }
5079
5080 const myKey = `${options.key}__selectorFamily/${(_stableStringify = Recoil_stableStringify(params, {
5081 // It is possible to use functions in parameters if the user uses
5082 // a cache with reference equality thanks to the incrementing index.
5083 allowFunctions: true
5084 })) !== null && _stableStringify !== void 0 ? _stableStringify : 'void'}/${nextIndex++}`; // Append index in case values serialize to the same key string
5085
5086 const myGet = callbacks => options.get(params)(callbacks);
5087
5088 const myCacheImplementation = (_options$cacheImpleme3 = options.cacheImplementation_UNSTABLE) === null || _options$cacheImpleme3 === void 0 ? void 0 : _options$cacheImpleme3.call(options);
5089 let newSelector;
5090
5091 if (options.set != null) {
5092 const set = options.set;
5093
5094 const mySet = (callbacks, newValue) => set(params)(callbacks, newValue);
5095
5096 newSelector = Recoil_selector({
5097 key: myKey,
5098 get: myGet,
5099 set: mySet,
5100 cacheImplementation_UNSTABLE: myCacheImplementation,
5101 dangerouslyAllowMutability: options.dangerouslyAllowMutability
5102 });
5103 } else {
5104 newSelector = Recoil_selector({
5105 key: myKey,
5106 get: myGet,
5107 cacheImplementation_UNSTABLE: myCacheImplementation,
5108 dangerouslyAllowMutability: options.dangerouslyAllowMutability
5109 });
5110 }
5111
5112 selectorCache = selectorCache.set(params, newSelector);
5113 return newSelector;
5114 };
5115}
5116/* eslint-enable no-redeclare */
5117
5118
5119var Recoil_selectorFamily = selectorFamily;
5120
5121// @fb-only: const {parameterizedScopedAtomLegacy} = require('Recoil_ScopedAtom');
5122
5123
5124const {
5125 DEFAULT_VALUE: DEFAULT_VALUE$6,
5126 DefaultValue: DefaultValue$3
5127} = Recoil_Node;
5128/*
5129A function which returns an atom based on the input parameter.
5130
5131Each unique parameter returns a unique atom. E.g.,
5132
5133 const f = atomFamily(...);
5134 f({a: 1}) => an atom
5135 f({a: 2}) => a different atom
5136
5137This allows components to persist local, private state using atoms. Each
5138instance of the component may have a different key, which it uses as the
5139parameter for a family of atoms; in this way, each component will have
5140its own atom not shared by other instances. These state keys may be composed
5141into children's state keys as well.
5142*/
5143
5144
5145function atomFamily(options) {
5146 let atomCache = Recoil_cacheWithValueEquality(); // An atom to represent any legacy atoms that we can upgrade to an atomFamily
5147
5148 const legacyAtomOptions = {
5149 key: options.key,
5150 // Legacy atoms just used the plain key directly
5151 default: DEFAULT_VALUE$6,
5152 persistence_UNSTABLE: options.persistence_UNSTABLE
5153 };
5154 let legacyAtom; // prettier-ignore
5155 // @fb-only: if (
5156 // @fb-only: options.scopeRules_APPEND_ONLY_READ_THE_DOCS
5157 // @fb-only: ) {
5158 // @fb-only: legacyAtom = parameterizedScopedAtomLegacy<T | DefaultValue, P>({
5159 // @fb-only: ...legacyAtomOptions,
5160 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS:
5161 // @fb-only: options.scopeRules_APPEND_ONLY_READ_THE_DOCS,
5162 // @fb-only: });
5163 // @fb-only: } else {
5164
5165 legacyAtom = Recoil_atom(legacyAtomOptions); // @fb-only: }
5166 // Selector to calculate the default value based on any persisted legacy atoms
5167 // that were upgraded to a atomFamily
5168
5169 const atomFamilyDefault = Recoil_selectorFamily({
5170 key: `${options.key}__atomFamily/Default`,
5171 get: param => ({
5172 get
5173 }) => {
5174 const legacyValue = get(typeof legacyAtom === 'function' ? legacyAtom(param) : legacyAtom); // Atom was upgraded from a non-parameterized atom
5175
5176 if (!(legacyValue instanceof DefaultValue$3)) {
5177 return legacyValue;
5178 } // There's no legacy atom value, so use the user-specified default
5179
5180
5181 return typeof options.default === 'function' ? // The default was parameterized
5182 // Flow doesn't know that T isn't a function, so we need to case to any
5183 options.default(param) // flowlint-line unclear-type:off
5184 : // Default may be a static value, promise, or RecoilValue
5185 options.default;
5186 },
5187 dangerouslyAllowMutability: options.dangerouslyAllowMutability
5188 }); // Simple atomFamily implementation to cache individual atoms based
5189 // on the parameter value equality.
5190
5191 return params => {
5192 var _stableStringify;
5193
5194 const cachedAtom = atomCache.get(params);
5195
5196 if (cachedAtom != null) {
5197 return cachedAtom;
5198 }
5199
5200 const newAtom = Recoil_atom({ ...options,
5201 key: `${options.key}__${(_stableStringify = Recoil_stableStringify(params)) !== null && _stableStringify !== void 0 ? _stableStringify : 'void'}`,
5202 default: atomFamilyDefault(params),
5203 effects_UNSTABLE: typeof options.effects_UNSTABLE === 'function' ? options.effects_UNSTABLE(params) : options.effects_UNSTABLE // prettier-ignore
5204 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS: mapScopeRules(
5205 // @fb-only: options.scopeRules_APPEND_ONLY_READ_THE_DOCS,
5206 // @fb-only: params,
5207 // @fb-only: )
5208
5209 });
5210 atomCache = atomCache.set(params, newAtom);
5211 return newAtom;
5212 };
5213}
5214
5215var Recoil_atomFamily = atomFamily;
5216
5217// flowlint-next-line unclear-type:off
5218
5219
5220const constantSelector = Recoil_selectorFamily({
5221 key: '__constant',
5222 get: constant => () => constant,
5223 cacheImplementationForParams_UNSTABLE: Recoil_cacheWithReferenceEquality
5224}); // Function that returns a selector which always produces the
5225// same constant value. It may be called multiple times with the
5226// same value, based on reference equality, and will provide the
5227// same selector.
5228
5229function constSelector(constant) {
5230 return constantSelector(constant);
5231}
5232
5233var Recoil_constSelector = constSelector;
5234
5235// flowlint-next-line unclear-type:off
5236
5237
5238const throwingSelector = Recoil_selectorFamily({
5239 key: '__error',
5240 get: message => () => {
5241 throw new Error(message);
5242 },
5243 cacheImplementationForParams_UNSTABLE: Recoil_cacheWithReferenceEquality
5244}); // Function that returns a selector which always throws an error
5245// with the provided message.
5246
5247function errorSelector(message) {
5248 return throwingSelector(message);
5249}
5250
5251var Recoil_errorSelector = errorSelector;
5252
5253/**
5254 * Copyright (c) Facebook, Inc. and its affiliates.
5255 *
5256 * This source code is licensed under the MIT license found in the
5257 * LICENSE file in the root directory of this source tree.
5258 *
5259 * Wraps another recoil value and prevents writing to it.
5260 *
5261 * @emails oncall+recoil
5262 *
5263 * @format
5264 */
5265
5266function readOnlySelector(atom) {
5267 // flowlint-next-line unclear-type: off
5268 return atom;
5269}
5270
5271var Recoil_readOnlySelector = readOnlySelector;
5272
5273const {
5274 loadableWithError: loadableWithError$4,
5275 loadableWithPromise: loadableWithPromise$4,
5276 loadableWithValue: loadableWithValue$4
5277} = Recoil_Loadable;
5278
5279
5280
5281
5282
5283 /////////////////
5284// TRUTH TABLE
5285/////////////////
5286// Dependencies waitForNone waitForAny waitForAll
5287// [loading, loading] [Promise, Promise] Promise Promise
5288// [value, loading] [value, Promise] [value, Promise] Promise
5289// [value, value] [value, value] [value, value] [value, value]
5290//
5291// [error, loading] [Error, Promise] Promise Error
5292// [error, error] [Error, Error] Error Error
5293// [value, error] [value, Error] [value, Error] Error
5294// Issue parallel requests for all dependencies and return the current
5295// status if they have results, have some error, or are still pending.
5296
5297
5298function concurrentRequests(getRecoilValue, deps) {
5299 const results = Array(deps.length).fill(undefined);
5300 const exceptions = Array(deps.length).fill(undefined);
5301
5302 for (const [i, dep] of deps.entries()) {
5303 try {
5304 results[i] = getRecoilValue(dep);
5305 } catch (e) {
5306 // exceptions can either be Promises of pending results or real errors
5307 exceptions[i] = e;
5308 }
5309 }
5310
5311 return [results, exceptions];
5312}
5313
5314function isError(exp) {
5315 return exp != null && !Recoil_isPromise(exp);
5316}
5317
5318function unwrapDependencies(dependencies) {
5319 return Array.isArray(dependencies) ? dependencies : Object.getOwnPropertyNames(dependencies).map(key => dependencies[key]);
5320}
5321
5322function getValueFromLoadablePromiseResult(result) {
5323 if (result != null && typeof result === 'object' && result.hasOwnProperty('__value')) {
5324 return result.__value;
5325 }
5326
5327 return result;
5328}
5329
5330function wrapResults(dependencies, results) {
5331 return Array.isArray(dependencies) ? results : // Object.getOwnPropertyNames() has consistent key ordering with ES6
5332 Object.getOwnPropertyNames(dependencies).reduce((out, key, idx) => ({ ...out,
5333 [key]: results[idx]
5334 }), {});
5335}
5336
5337function wrapLoadables(dependencies, results, exceptions) {
5338 const output = exceptions.map((exception, idx) => exception == null ? loadableWithValue$4(results[idx]) : Recoil_isPromise(exception) ? loadableWithPromise$4(exception) : loadableWithError$4(exception));
5339 return wrapResults(dependencies, output);
5340}
5341
5342function combineAsyncResultsWithSyncResults(syncResults, asyncResults) {
5343 return asyncResults.map((result, idx) =>
5344 /**
5345 * it's important we use === undefined as opposed to == null, because the
5346 * resolved value of the async promise could be `null`, in which case we
5347 * don't want to use syncResults[idx], which would be undefined. If async
5348 * promise resolves to `undefined`, that's ok because `syncResults[idx]`
5349 * will also be `undefined`. That's a little hacky, but it works.
5350 */
5351 result === undefined ? syncResults[idx] : result);
5352} // Selector that requests all dependencies in parallel and immediately returns
5353// current results without waiting.
5354
5355
5356const waitForNone = Recoil_selectorFamily({
5357 key: '__waitForNone',
5358 get: dependencies => ({
5359 get
5360 }) => {
5361 // Issue requests for all dependencies in parallel.
5362 const deps = unwrapDependencies(dependencies);
5363 const [results, exceptions] = concurrentRequests(get, deps); // Always return the current status of the results; never block.
5364
5365 return wrapLoadables(dependencies, results, exceptions);
5366 }
5367}); // Selector that requests all dependencies in parallel and waits for at least
5368// one to be available before returning results. It will only error if all
5369// dependencies have errors.
5370
5371const waitForAny = Recoil_selectorFamily({
5372 key: '__waitForAny',
5373 get: dependencies => ({
5374 get
5375 }) => {
5376 // Issue requests for all dependencies in parallel.
5377 // Exceptions can either be Promises of pending results or real errors
5378 const deps = unwrapDependencies(dependencies);
5379 const [results, exceptions] = concurrentRequests(get, deps); // If any results are available, return the current status
5380
5381 if (exceptions.some(exp => exp == null)) {
5382 return wrapLoadables(dependencies, results, exceptions);
5383 } // Since we are waiting for any results, only throw an error if all
5384 // dependencies have an error. Then, throw the first one.
5385
5386
5387 if (exceptions.every(isError)) {
5388 throw exceptions.find(isError);
5389 }
5390
5391 if (Recoil_gkx_1('recoil_async_selector_refactor')) {
5392 // Otherwise, return a promise that will resolve when the next result is
5393 // available, whichever one happens to be next. But, if all pending
5394 // dependencies end up with errors, then reject the promise.
5395 return new Promise((resolve, reject) => {
5396 for (const [i, exp] of exceptions.entries()) {
5397 if (Recoil_isPromise(exp)) {
5398 exp.then(result => {
5399 results[i] = getValueFromLoadablePromiseResult(result);
5400 exceptions[i] = null;
5401 resolve(wrapLoadables(dependencies, results, exceptions));
5402 }).catch(error => {
5403 exceptions[i] = error;
5404
5405 if (exceptions.every(isError)) {
5406 reject(exceptions[0]);
5407 }
5408 });
5409 }
5410 }
5411 });
5412 } else {
5413 throw new Promise((resolve, reject) => {
5414 for (const [i, exp] of exceptions.entries()) {
5415 if (Recoil_isPromise(exp)) {
5416 exp.then(result => {
5417 results[i] = result;
5418 exceptions[i] = null;
5419 resolve(wrapLoadables(dependencies, results, exceptions));
5420 }).catch(error => {
5421 exceptions[i] = error;
5422
5423 if (exceptions.every(isError)) {
5424 reject(exceptions[0]);
5425 }
5426 });
5427 }
5428 }
5429 });
5430 }
5431 }
5432}); // Selector that requests all dependencies in parallel and waits for all to be
5433// available before returning a value. It will error if any dependencies error.
5434
5435const waitForAll = Recoil_selectorFamily({
5436 key: '__waitForAll',
5437 get: dependencies => ({
5438 get
5439 }) => {
5440 // Issue requests for all dependencies in parallel.
5441 // Exceptions can either be Promises of pending results or real errors
5442 const deps = unwrapDependencies(dependencies);
5443 const [results, exceptions] = concurrentRequests(get, deps); // If all results are available, return the results
5444
5445 if (exceptions.every(exp => exp == null)) {
5446 return wrapResults(dependencies, results);
5447 } // If we have any errors, throw the first error
5448
5449
5450 const error = exceptions.find(isError);
5451
5452 if (error != null) {
5453 throw error;
5454 }
5455
5456 if (Recoil_gkx_1('recoil_async_selector_refactor')) {
5457 // Otherwise, return a promise that will resolve when all results are available
5458 return Promise.all(exceptions).then(exceptionResults => wrapResults(dependencies, combineAsyncResultsWithSyncResults(results, exceptionResults).map(getValueFromLoadablePromiseResult)));
5459 } else {
5460 throw Promise.all(exceptions).then(results => wrapResults(dependencies, results));
5461 }
5462 }
5463});
5464const noWait = Recoil_selectorFamily({
5465 key: '__noWait',
5466 get: dependency => ({
5467 get
5468 }) => {
5469 try {
5470 return loadableWithValue$4(get(dependency));
5471 } catch (exception) {
5472 return Recoil_isPromise(exception) ? loadableWithPromise$4(exception) : loadableWithError$4(exception);
5473 }
5474 }
5475});
5476var Recoil_WaitFor = {
5477 waitForNone,
5478 waitForAny,
5479 waitForAll,
5480 noWait
5481};
5482
5483const {
5484 batchUpdates: batchUpdates$3,
5485 setBatcher: setBatcher$1
5486} = Recoil_Batching;
5487
5488const {
5489 DefaultValue: DefaultValue$4
5490} = Recoil_Node;
5491
5492const {
5493 RecoilRoot: RecoilRoot$2
5494} = Recoil_RecoilRoot_react;
5495
5496const {
5497 isRecoilValue: isRecoilValue$6
5498} = Recoil_RecoilValue$1;
5499
5500const {
5501 freshSnapshot: freshSnapshot$2
5502} = Recoil_Snapshot$1;
5503
5504const {
5505 useGotoRecoilSnapshot: useGotoRecoilSnapshot$1,
5506 useRecoilCallback: useRecoilCallback$1,
5507 useRecoilSnapshot: useRecoilSnapshot$1,
5508 useRecoilState: useRecoilState$1,
5509 useRecoilStateLoadable: useRecoilStateLoadable$1,
5510 useRecoilTransactionObserver: useRecoilTransactionObserver$1,
5511 useRecoilValue: useRecoilValue$1,
5512 useRecoilValueLoadable: useRecoilValueLoadable$1,
5513 useResetRecoilState: useResetRecoilState$1,
5514 useSetRecoilState: useSetRecoilState$1,
5515 useSetUnvalidatedAtomValues: useSetUnvalidatedAtomValues$1,
5516 useTransactionObservation_DEPRECATED: useTransactionObservation_DEPRECATED$1
5517} = Recoil_Hooks;
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535const {
5536 noWait: noWait$1,
5537 waitForAll: waitForAll$1,
5538 waitForAny: waitForAny$1,
5539 waitForNone: waitForNone$1
5540} = Recoil_WaitFor;
5541
5542var Recoil_index = {
5543 // Types
5544 DefaultValue: DefaultValue$4,
5545 // Components
5546 RecoilRoot: RecoilRoot$2,
5547 useRecoilBridgeAcrossReactRoots_UNSTABLE: Recoil_useRecoilBridgeAcrossReactRoots,
5548 // RecoilValues
5549 atom: Recoil_atom,
5550 selector: Recoil_selector,
5551 // Convenience RecoilValues
5552 atomFamily: Recoil_atomFamily,
5553 selectorFamily: Recoil_selectorFamily,
5554 constSelector: Recoil_constSelector,
5555 errorSelector: Recoil_errorSelector,
5556 readOnlySelector: Recoil_readOnlySelector,
5557 // Hooks that accept RecoilValues
5558 useRecoilValue: useRecoilValue$1,
5559 useRecoilValueLoadable: useRecoilValueLoadable$1,
5560 useRecoilState: useRecoilState$1,
5561 useRecoilStateLoadable: useRecoilStateLoadable$1,
5562 useSetRecoilState: useSetRecoilState$1,
5563 useResetRecoilState: useResetRecoilState$1,
5564 // Hooks for asynchronous Recoil
5565 useRecoilCallback: useRecoilCallback$1,
5566 // Hooks for Snapshots
5567 useGotoRecoilSnapshot: useGotoRecoilSnapshot$1,
5568 useRecoilSnapshot: useRecoilSnapshot$1,
5569 useRecoilTransactionObserver_UNSTABLE: useRecoilTransactionObserver$1,
5570 useTransactionObservation_UNSTABLE: useTransactionObservation_DEPRECATED$1,
5571 useSetUnvalidatedAtomValues_UNSTABLE: useSetUnvalidatedAtomValues$1,
5572 // Concurrency Helpers
5573 noWait: noWait$1,
5574 waitForNone: waitForNone$1,
5575 waitForAny: waitForAny$1,
5576 waitForAll: waitForAll$1,
5577 // Other functions
5578 isRecoilValue: isRecoilValue$6,
5579 // Batching
5580 batchUpdates: batchUpdates$3,
5581 setBatcher: setBatcher$1,
5582 // Snapshot Utils
5583 snapshot_UNSTABLE: freshSnapshot$2
5584};
5585var Recoil_index_1 = Recoil_index.DefaultValue;
5586var Recoil_index_2 = Recoil_index.RecoilRoot;
5587var Recoil_index_3 = Recoil_index.useRecoilBridgeAcrossReactRoots_UNSTABLE;
5588var Recoil_index_4 = Recoil_index.atom;
5589var Recoil_index_5 = Recoil_index.selector;
5590var Recoil_index_6 = Recoil_index.atomFamily;
5591var Recoil_index_7 = Recoil_index.selectorFamily;
5592var Recoil_index_8 = Recoil_index.constSelector;
5593var Recoil_index_9 = Recoil_index.errorSelector;
5594var Recoil_index_10 = Recoil_index.readOnlySelector;
5595var Recoil_index_11 = Recoil_index.useRecoilValue;
5596var Recoil_index_12 = Recoil_index.useRecoilValueLoadable;
5597var Recoil_index_13 = Recoil_index.useRecoilState;
5598var Recoil_index_14 = Recoil_index.useRecoilStateLoadable;
5599var Recoil_index_15 = Recoil_index.useSetRecoilState;
5600var Recoil_index_16 = Recoil_index.useResetRecoilState;
5601var Recoil_index_17 = Recoil_index.useRecoilCallback;
5602var Recoil_index_18 = Recoil_index.useGotoRecoilSnapshot;
5603var Recoil_index_19 = Recoil_index.useRecoilSnapshot;
5604var Recoil_index_20 = Recoil_index.useRecoilTransactionObserver_UNSTABLE;
5605var Recoil_index_21 = Recoil_index.useTransactionObservation_UNSTABLE;
5606var Recoil_index_22 = Recoil_index.useSetUnvalidatedAtomValues_UNSTABLE;
5607var Recoil_index_23 = Recoil_index.noWait;
5608var Recoil_index_24 = Recoil_index.waitForNone;
5609var Recoil_index_25 = Recoil_index.waitForAny;
5610var Recoil_index_26 = Recoil_index.waitForAll;
5611var Recoil_index_27 = Recoil_index.isRecoilValue;
5612var Recoil_index_28 = Recoil_index.batchUpdates;
5613var Recoil_index_29 = Recoil_index.setBatcher;
5614var Recoil_index_30 = Recoil_index.snapshot_UNSTABLE;
5615
5616exports.DefaultValue = Recoil_index_1;
5617exports.RecoilRoot = Recoil_index_2;
5618exports.atom = Recoil_index_4;
5619exports.atomFamily = Recoil_index_6;
5620exports.batchUpdates = Recoil_index_28;
5621exports.constSelector = Recoil_index_8;
5622exports.default = Recoil_index;
5623exports.errorSelector = Recoil_index_9;
5624exports.isRecoilValue = Recoil_index_27;
5625exports.noWait = Recoil_index_23;
5626exports.readOnlySelector = Recoil_index_10;
5627exports.selector = Recoil_index_5;
5628exports.selectorFamily = Recoil_index_7;
5629exports.setBatcher = Recoil_index_29;
5630exports.snapshot_UNSTABLE = Recoil_index_30;
5631exports.useGotoRecoilSnapshot = Recoil_index_18;
5632exports.useRecoilBridgeAcrossReactRoots_UNSTABLE = Recoil_index_3;
5633exports.useRecoilCallback = Recoil_index_17;
5634exports.useRecoilSnapshot = Recoil_index_19;
5635exports.useRecoilState = Recoil_index_13;
5636exports.useRecoilStateLoadable = Recoil_index_14;
5637exports.useRecoilTransactionObserver_UNSTABLE = Recoil_index_20;
5638exports.useRecoilValue = Recoil_index_11;
5639exports.useRecoilValueLoadable = Recoil_index_12;
5640exports.useResetRecoilState = Recoil_index_16;
5641exports.useSetRecoilState = Recoil_index_15;
5642exports.useSetUnvalidatedAtomValues_UNSTABLE = Recoil_index_22;
5643exports.useTransactionObservation_UNSTABLE = Recoil_index_21;
5644exports.waitForAll = Recoil_index_26;
5645exports.waitForAny = Recoil_index_25;
5646exports.waitForNone = Recoil_index_24;