UNPKG

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