UNPKG

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