UNPKG

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