UNPKG

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