UNPKG

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