UNPKG

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