UNPKG

247 kBJavaScriptView Raw
1import react from 'react';
2import reactDom from 'react-dom';
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 web build
3154 */
3155const {
3156 unstable_batchedUpdates
3157} = reactDom;
3158
3159var ReactBatchedUpdates = {
3160 unstable_batchedUpdates
3161};
3162
3163/**
3164 * Copyright (c) Facebook, Inc. and its affiliates.
3165 *
3166 * This source code is licensed under the MIT license found in the
3167 * LICENSE file in the root directory of this source tree.
3168 *
3169 * @emails oncall+recoil
3170 *
3171 * @format
3172 *
3173 * This is to export esstiential functions from react-dom
3174 * for our web build
3175 */
3176// @fb-only: const {unstable_batchedUpdates} = require('ReactDOMComet');
3177// prettier-ignore
3178const {
3179 unstable_batchedUpdates: unstable_batchedUpdates$1
3180} = ReactBatchedUpdates; // @oss-only
3181
3182
3183var Recoil_ReactBatchedUpdates = {
3184 unstable_batchedUpdates: unstable_batchedUpdates$1
3185};
3186
3187/**
3188 * Copyright (c) Facebook, Inc. and its affiliates.
3189 *
3190 * This source code is licensed under the MIT license found in the
3191 * LICENSE file in the root directory of this source tree.
3192 *
3193 * @emails oncall+recoil
3194 *
3195 * @format
3196 */
3197const {
3198 batchStart: batchStart$1
3199} = Recoil_RecoilValueInterface;
3200
3201const {
3202 unstable_batchedUpdates: unstable_batchedUpdates$2
3203} = Recoil_ReactBatchedUpdates;
3204
3205let batcher = unstable_batchedUpdates$2; // flowlint-next-line unclear-type:off
3206
3207/**
3208 * Sets the provided batcher function as the batcher function used by Recoil.
3209 *
3210 * Set the batcher to a custom batcher for your renderer,
3211 * if you use a renderer other than React DOM or React Native.
3212 */
3213const setBatcher = newBatcher => {
3214 batcher = newBatcher;
3215};
3216/**
3217 * Returns the current batcher function.
3218 */
3219
3220
3221const getBatcher = () => batcher;
3222/**
3223 * Calls the current batcher function and passes the
3224 * provided callback function.
3225 */
3226
3227
3228const batchUpdates = callback => {
3229 batcher(() => {
3230 let batchEnd = () => undefined;
3231
3232 try {
3233 batchEnd = batchStart$1();
3234 callback();
3235 } finally {
3236 batchEnd();
3237 }
3238 });
3239};
3240
3241var Recoil_Batching = {
3242 getBatcher,
3243 setBatcher,
3244 batchUpdates
3245};
3246
3247const {
3248 isSSR: isSSR$1
3249} = Recoil_Environment;
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261const {
3262 batchUpdates: batchUpdates$1
3263} = Recoil_Batching;
3264
3265const {
3266 initializeNodeIfNewToStore: initializeNodeIfNewToStore$1,
3267 peekNodeInfo: peekNodeInfo$1
3268} = Recoil_FunctionalCore;
3269
3270const {
3271 graph: graph$2
3272} = Recoil_Graph;
3273
3274const {
3275 DEFAULT_VALUE: DEFAULT_VALUE$1,
3276 recoilValues: recoilValues$1,
3277 recoilValuesForKeys: recoilValuesForKeys$2
3278} = Recoil_Node;
3279
3280const {
3281 AbstractRecoilValue: AbstractRecoilValue$2,
3282 getRecoilValueAsLoadable: getRecoilValueAsLoadable$1,
3283 setRecoilValue: setRecoilValue$1,
3284 setUnvalidatedRecoilValue: setUnvalidatedRecoilValue$1
3285} = Recoil_RecoilValueInterface;
3286
3287const {
3288 updateRetainCount: updateRetainCount$1
3289} = Recoil_Retention;
3290
3291const {
3292 getNextTreeStateVersion: getNextTreeStateVersion$1,
3293 makeEmptyStoreState: makeEmptyStoreState$1
3294} = Recoil_State; // Opaque at this surface because it's part of the public API from here.
3295
3296
3297const retainWarning = `
3298Recoil Snapshots only last for the duration of the callback they are provided to. To keep a Snapshot longer, do this:
3299
3300 const release = snapshot.retain();
3301 try {
3302 await useTheSnapshotAsynchronously(snapshot);
3303 } finally {
3304 release();
3305 }
3306
3307This is currently a DEV-only warning but will become a thrown exception in the next release of Recoil.
3308`; // A "Snapshot" is "read-only" and captures a specific set of values of atoms.
3309// However, the data-flow-graph and selector values may evolve as selector
3310// evaluation functions are executed and async selectors resolve.
3311
3312class Snapshot {
3313 constructor(storeState) {
3314 _defineProperty(this, "_store", void 0);
3315
3316 _defineProperty(this, "_refCount", 0);
3317
3318 _defineProperty(this, "getLoadable", recoilValue => {
3319 this.checkRefCount_INTERNAL();
3320 return getRecoilValueAsLoadable$1(this._store, recoilValue);
3321 });
3322
3323 _defineProperty(this, "getPromise", recoilValue => {
3324 this.checkRefCount_INTERNAL();
3325 return this.getLoadable(recoilValue).toPromise();
3326 });
3327
3328 _defineProperty(this, "getNodes_UNSTABLE", opt => {
3329 this.checkRefCount_INTERNAL(); // TODO Deal with modified selectors
3330
3331 if ((opt === null || opt === void 0 ? void 0 : opt.isModified) === true) {
3332 if ((opt === null || opt === void 0 ? void 0 : opt.isInitialized) === false) {
3333 return [];
3334 }
3335
3336 const state = this._store.getState().currentTree;
3337
3338 return recoilValuesForKeys$2(state.dirtyAtoms);
3339 }
3340
3341 const knownAtoms = this._store.getState().knownAtoms;
3342
3343 const knownSelectors = this._store.getState().knownSelectors;
3344
3345 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(), ({
3346 key
3347 }) => !knownAtoms.has(key) && !knownSelectors.has(key));
3348 });
3349
3350 _defineProperty(this, "getInfo_UNSTABLE", ({
3351 key
3352 }) => {
3353 this.checkRefCount_INTERNAL();
3354 return peekNodeInfo$1(this._store, this._store.getState().currentTree, key);
3355 });
3356
3357 _defineProperty(this, "map", mapper => {
3358 this.checkRefCount_INTERNAL();
3359 const mutableSnapshot = new MutableSnapshot(this, batchUpdates$1);
3360 mapper(mutableSnapshot); // if removing batchUpdates from `set` add it here
3361
3362 return cloneSnapshot(mutableSnapshot.getStore_INTERNAL());
3363 });
3364
3365 _defineProperty(this, "asyncMap", async mapper => {
3366 this.checkRefCount_INTERNAL();
3367 const mutableSnapshot = new MutableSnapshot(this, batchUpdates$1);
3368 await mapper(mutableSnapshot);
3369 return cloneSnapshot(mutableSnapshot.getStore_INTERNAL());
3370 });
3371
3372 this._store = {
3373 getState: () => storeState,
3374 replaceState: replacer => {
3375 storeState.currentTree = replacer(storeState.currentTree); // no batching so nextTree is never active
3376 },
3377 getGraph: version => {
3378 const graphs = storeState.graphsByVersion;
3379
3380 if (graphs.has(version)) {
3381 return Recoil_nullthrows(graphs.get(version));
3382 }
3383
3384 const newGraph = graph$2();
3385 graphs.set(version, newGraph);
3386 return newGraph;
3387 },
3388 subscribeToTransactions: () => ({
3389 release: () => {}
3390 }),
3391 addTransactionMetadata: () => {
3392 throw Recoil_err('Cannot subscribe to Snapshots');
3393 }
3394 }; // Initialize any nodes that are live in the parent store (primarily so that this
3395 // snapshot gets counted towards the node's live stores count).
3396
3397 for (const nodeKey of this._store.getState().nodeCleanupFunctions.keys()) {
3398 initializeNodeIfNewToStore$1(this._store, storeState.currentTree, nodeKey, 'get');
3399 updateRetainCount$1(this._store, nodeKey, 1);
3400 }
3401
3402 this.retain();
3403 this.autorelease_INTERNAL();
3404 }
3405
3406 retain() {
3407 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
3408 return () => undefined;
3409 }
3410
3411 this._refCount++;
3412 let released = false;
3413 return () => {
3414 if (!released) {
3415 released = true;
3416 this.release_INTERNAL();
3417 }
3418 };
3419 }
3420
3421 autorelease_INTERNAL() {
3422 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
3423 return;
3424 }
3425
3426 if (!isSSR$1) {
3427 window.setTimeout(() => this.release_INTERNAL(), 0);
3428 }
3429 }
3430
3431 release_INTERNAL() {
3432 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
3433 return;
3434 }
3435
3436 this._refCount--;
3437
3438 if (this._refCount === 0) ;
3439 }
3440
3441 checkRefCount_INTERNAL() {
3442 if (Recoil_gkx_1('recoil_memory_managament_2020') && this._refCount <= 0) {
3443 if (process.env.NODE_ENV !== "production") {
3444 Recoil_recoverableViolation(retainWarning);
3445 } // What we will ship later:
3446 // throw err(retainWarning);
3447
3448 }
3449 }
3450
3451 getStore_INTERNAL() {
3452 this.checkRefCount_INTERNAL();
3453 return this._store;
3454 }
3455
3456 getID() {
3457 this.checkRefCount_INTERNAL();
3458 return this.getID_INTERNAL();
3459 }
3460
3461 getID_INTERNAL() {
3462 this.checkRefCount_INTERNAL();
3463 return this._store.getState().currentTree.stateID;
3464 } // We want to allow the methods to be destructured and used as accessors
3465 // eslint-disable-next-line fb-www/extra-arrow-initializer
3466
3467
3468}
3469
3470function cloneStoreState(store, treeState, bumpVersion = false) {
3471 const storeState = store.getState();
3472 const version = bumpVersion ? getNextTreeStateVersion$1() : treeState.version;
3473 return {
3474 currentTree: bumpVersion ? {
3475 // TODO snapshots shouldn't really have versions because a new version number
3476 // is always assigned when the snapshot is gone to.
3477 version,
3478 stateID: version,
3479 transactionMetadata: { ...treeState.transactionMetadata
3480 },
3481 dirtyAtoms: new Set(treeState.dirtyAtoms),
3482 atomValues: treeState.atomValues.clone(),
3483 nonvalidatedAtoms: treeState.nonvalidatedAtoms.clone()
3484 } : treeState,
3485 commitDepth: 0,
3486 nextTree: null,
3487 previousTree: null,
3488 knownAtoms: new Set(storeState.knownAtoms),
3489 // FIXME here's a copy
3490 knownSelectors: new Set(storeState.knownSelectors),
3491 // FIXME here's a copy
3492 transactionSubscriptions: new Map(),
3493 nodeTransactionSubscriptions: new Map(),
3494 nodeToComponentSubscriptions: new Map(),
3495 queuedComponentCallbacks_DEPRECATED: [],
3496 suspendedComponentResolvers: new Set(),
3497 graphsByVersion: new Map().set(version, store.getGraph(treeState.version)),
3498 versionsUsedByComponent: new Map(),
3499 retention: {
3500 referenceCounts: new Map(),
3501 nodesRetainedByZone: new Map(),
3502 retainablesToCheckForRelease: new Set()
3503 },
3504 nodeCleanupFunctions: new Map()
3505 };
3506} // Factory to build a fresh snapshot
3507
3508
3509function freshSnapshot(initializeState) {
3510 const snapshot = new Snapshot(makeEmptyStoreState$1());
3511 return initializeState != null ? snapshot.map(initializeState) : snapshot;
3512} // Factory to clone a snapahot state
3513
3514
3515function cloneSnapshot(store, version = 'current') {
3516 const storeState = store.getState();
3517 const treeState = version === 'current' ? storeState.currentTree : Recoil_nullthrows(storeState.previousTree);
3518 return new Snapshot(cloneStoreState(store, treeState));
3519}
3520
3521class MutableSnapshot extends Snapshot {
3522 constructor(snapshot, batch) {
3523 super(cloneStoreState(snapshot.getStore_INTERNAL(), snapshot.getStore_INTERNAL().getState().currentTree, true));
3524
3525 _defineProperty(this, "_batch", void 0);
3526
3527 _defineProperty(this, "set", (recoilState, newValueOrUpdater) => {
3528 this.checkRefCount_INTERNAL();
3529 const store = this.getStore_INTERNAL(); // This batchUpdates ensures this `set` is applied immediately and you can
3530 // read the written value after calling `set`. I would like to remove this
3531 // behavior and only batch in `Snapshot.map`, but this would be a breaking
3532 // change potentially.
3533
3534 this._batch(() => {
3535 updateRetainCount$1(store, recoilState.key, 1);
3536 setRecoilValue$1(this.getStore_INTERNAL(), recoilState, newValueOrUpdater);
3537 });
3538 });
3539
3540 _defineProperty(this, "reset", recoilState => {
3541 this.checkRefCount_INTERNAL();
3542 const store = this.getStore_INTERNAL(); // See note at `set` about batched updates.
3543
3544 this._batch(() => {
3545 updateRetainCount$1(store, recoilState.key, 1);
3546 setRecoilValue$1(this.getStore_INTERNAL(), recoilState, DEFAULT_VALUE$1);
3547 });
3548 });
3549
3550 _defineProperty(this, "setUnvalidatedAtomValues_DEPRECATED", values => {
3551 this.checkRefCount_INTERNAL();
3552 const store = this.getStore_INTERNAL(); // See note at `set` about batched updates.
3553
3554 batchUpdates$1(() => {
3555 for (const [k, v] of values.entries()) {
3556 updateRetainCount$1(store, k, 1);
3557 setUnvalidatedRecoilValue$1(store, new AbstractRecoilValue$2(k), v);
3558 }
3559 });
3560 });
3561
3562 this._batch = batch;
3563 } // We want to allow the methods to be destructured and used as accessors
3564 // eslint-disable-next-line fb-www/extra-arrow-initializer
3565
3566
3567}
3568
3569var Recoil_Snapshot = {
3570 Snapshot,
3571 MutableSnapshot,
3572 freshSnapshot,
3573 cloneSnapshot
3574};
3575
3576var Recoil_Snapshot_1 = Recoil_Snapshot.Snapshot;
3577var Recoil_Snapshot_2 = Recoil_Snapshot.MutableSnapshot;
3578var Recoil_Snapshot_3 = Recoil_Snapshot.freshSnapshot;
3579var Recoil_Snapshot_4 = Recoil_Snapshot.cloneSnapshot;
3580
3581var Recoil_Snapshot$1 = /*#__PURE__*/Object.freeze({
3582 __proto__: null,
3583 Snapshot: Recoil_Snapshot_1,
3584 MutableSnapshot: Recoil_Snapshot_2,
3585 freshSnapshot: Recoil_Snapshot_3,
3586 cloneSnapshot: Recoil_Snapshot_4
3587});
3588
3589// @fb-only: const RecoilusagelogEvent = require('RecoilusagelogEvent');
3590// @fb-only: const RecoilUsageLogFalcoEvent = require('RecoilUsageLogFalcoEvent');
3591// @fb-only: const URI = require('URI');
3592
3593
3594const {
3595 getNextTreeStateVersion: getNextTreeStateVersion$2,
3596 makeEmptyStoreState: makeEmptyStoreState$2
3597} = Recoil_State;
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611const {
3612 cleanUpNode: cleanUpNode$2,
3613 getDownstreamNodes: getDownstreamNodes$2,
3614 setNodeValue: setNodeValue$2,
3615 setUnvalidatedAtomValue_DEPRECATED: setUnvalidatedAtomValue_DEPRECATED$1
3616} = Recoil_FunctionalCore;
3617
3618const {
3619 graph: graph$3
3620} = Recoil_Graph;
3621
3622const {
3623 cloneGraph: cloneGraph$1
3624} = Recoil_Graph;
3625
3626const {
3627 applyAtomValueWrites: applyAtomValueWrites$1
3628} = Recoil_RecoilValueInterface;
3629
3630const {
3631 releaseScheduledRetainablesNow: releaseScheduledRetainablesNow$1
3632} = Recoil_Retention;
3633
3634const {
3635 freshSnapshot: freshSnapshot$1
3636} = Recoil_Snapshot$1;
3637
3638
3639
3640const {
3641 useCallback,
3642 useContext,
3643 useEffect,
3644 useMemo,
3645 useRef,
3646 useState
3647} = react;
3648
3649function notInAContext() {
3650 throw Recoil_err('This component must be used inside a <RecoilRoot> component.');
3651}
3652
3653const defaultStore = Object.freeze({
3654 getState: notInAContext,
3655 replaceState: notInAContext,
3656 getGraph: notInAContext,
3657 subscribeToTransactions: notInAContext,
3658 addTransactionMetadata: notInAContext
3659});
3660let stateReplacerIsBeingExecuted = false;
3661
3662function startNextTreeIfNeeded(store) {
3663 if (stateReplacerIsBeingExecuted) {
3664 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.');
3665 }
3666
3667 const storeState = store.getState();
3668
3669 if (storeState.nextTree === null) {
3670 if (Recoil_gkx_1('recoil_memory_managament_2020') && Recoil_gkx_1('recoil_release_on_cascading_update_killswitch_2021')) {
3671 // If this is a cascading update (that is, rendering due to one state change
3672 // invokes a second state change), we won't have cleaned up retainables yet
3673 // because this normally happens after notifying components. Do it before
3674 // proceeding with the cascading update so that it remains predictable:
3675 if (storeState.commitDepth > 0) {
3676 releaseScheduledRetainablesNow$1(store);
3677 }
3678 }
3679
3680 const version = storeState.currentTree.version;
3681 const nextVersion = getNextTreeStateVersion$2();
3682 storeState.nextTree = { ...storeState.currentTree,
3683 version: nextVersion,
3684 stateID: nextVersion,
3685 dirtyAtoms: new Set(),
3686 transactionMetadata: {}
3687 };
3688 storeState.graphsByVersion.set(nextVersion, cloneGraph$1(Recoil_nullthrows(storeState.graphsByVersion.get(version))));
3689 }
3690}
3691
3692const AppContext = react.createContext({
3693 current: defaultStore
3694});
3695
3696const useStoreRef = () => useContext(AppContext);
3697
3698const MutableSourceContext = react.createContext(null); // TODO T2710559282599660
3699
3700function useRecoilMutableSource() {
3701 const mutableSource = useContext(MutableSourceContext);
3702
3703 if (mutableSource == null) {
3704 Recoil_expectationViolation('Attempted to use a Recoil hook outside of a <RecoilRoot>. ' + '<RecoilRoot> must be an ancestor of any component that uses ' + 'Recoil hooks.');
3705 }
3706
3707 return mutableSource;
3708}
3709
3710function notifyComponents(store, storeState, treeState) {
3711 const dependentNodes = getDownstreamNodes$2(store, treeState, treeState.dirtyAtoms);
3712
3713 for (const key of dependentNodes) {
3714 const comps = storeState.nodeToComponentSubscriptions.get(key);
3715
3716 if (comps) {
3717 for (const [_subID, [_debugName, callback]] of comps) {
3718 callback(treeState);
3719 }
3720 }
3721 }
3722}
3723
3724function sendEndOfBatchNotifications(store) {
3725 const storeState = store.getState();
3726 const treeState = storeState.currentTree; // Inform transaction subscribers of the transaction:
3727
3728 const dirtyAtoms = treeState.dirtyAtoms;
3729
3730 if (dirtyAtoms.size) {
3731 // Execute Node-specific subscribers before global subscribers
3732 for (const [key, subscriptions] of storeState.nodeTransactionSubscriptions) {
3733 if (dirtyAtoms.has(key)) {
3734 for (const [_, subscription] of subscriptions) {
3735 subscription(store);
3736 }
3737 }
3738 }
3739
3740 for (const [_, subscription] of storeState.transactionSubscriptions) {
3741 subscription(store);
3742 }
3743
3744 if (!Recoil_gkx_1('recoil_early_rendering_2021') || storeState.suspendedComponentResolvers.size) {
3745 // Notifying components is needed to wake from suspense, even when using
3746 // early rendering.
3747 notifyComponents(store, storeState, treeState); // Wake all suspended components so the right one(s) can try to re-render.
3748 // We need to wake up components not just when some asynchronous selector
3749 // resolved, but also when changing synchronous values because this may cause
3750 // a selector to change from asynchronous to synchronous, in which case there
3751 // would be no follow-up asynchronous resolution to wake us up.
3752 // TODO OPTIMIZATION Only wake up related downstream components
3753
3754 storeState.suspendedComponentResolvers.forEach(cb => cb());
3755 storeState.suspendedComponentResolvers.clear();
3756 }
3757 } // Special behavior ONLY invoked by useInterface.
3758 // FIXME delete queuedComponentCallbacks_DEPRECATED when deleting useInterface.
3759
3760
3761 storeState.queuedComponentCallbacks_DEPRECATED.forEach(cb => cb(treeState));
3762 storeState.queuedComponentCallbacks_DEPRECATED.splice(0, storeState.queuedComponentCallbacks_DEPRECATED.length);
3763}
3764
3765function endBatch(storeRef) {
3766 const storeState = storeRef.current.getState();
3767 storeState.commitDepth++;
3768
3769 try {
3770 const {
3771 nextTree
3772 } = storeState; // Ignore commits that are not because of Recoil transactions -- namely,
3773 // because something above RecoilRoot re-rendered:
3774
3775 if (nextTree === null) {
3776 return;
3777 } // nextTree is now committed -- note that copying and reset occurs when
3778 // a transaction begins, in startNextTreeIfNeeded:
3779
3780
3781 storeState.previousTree = storeState.currentTree;
3782 storeState.currentTree = nextTree;
3783 storeState.nextTree = null;
3784 sendEndOfBatchNotifications(storeRef.current);
3785
3786 if (storeState.previousTree != null) {
3787 storeState.graphsByVersion.delete(storeState.previousTree.version);
3788 } else {
3789 Recoil_recoverableViolation('Ended batch with no previous state, which is unexpected', 'recoil');
3790 }
3791
3792 storeState.previousTree = null;
3793
3794 if (Recoil_gkx_1('recoil_memory_managament_2020')) {
3795 releaseScheduledRetainablesNow$1(storeRef.current);
3796 }
3797 } finally {
3798 storeState.commitDepth--;
3799 }
3800}
3801/*
3802 * The purpose of the Batcher is to observe when React batches end so that
3803 * Recoil state changes can be batched. Whenever Recoil state changes, we call
3804 * setState on the batcher. Then we wait for that change to be committed, which
3805 * signifies the end of the batch. That's when we respond to the Recoil change.
3806 */
3807
3808
3809function Batcher({
3810 setNotifyBatcherOfChange
3811}) {
3812 const storeRef = useStoreRef();
3813 const [_, setState] = useState([]);
3814 setNotifyBatcherOfChange(() => setState({}));
3815 useEffect(() => {
3816 // enqueueExecution runs this function immediately; it is only used to
3817 // manipulate the order of useEffects during tests, since React seems to
3818 // call useEffect in an unpredictable order sometimes.
3819 Recoil_Queue.enqueueExecution('Batcher', () => {
3820 endBatch(storeRef);
3821 });
3822 }); // If an asynchronous selector resolves after the Batcher is unmounted,
3823 // notifyBatcherOfChange will still be called. An error gets thrown whenever
3824 // setState is called after a component is already unmounted, so this sets
3825 // notifyBatcherOfChange to be a no-op.
3826
3827 useEffect(() => {
3828 return () => {
3829 setNotifyBatcherOfChange(() => {});
3830 };
3831 }, [setNotifyBatcherOfChange]);
3832 return null;
3833}
3834
3835if (process.env.NODE_ENV !== "production") {
3836 if (typeof window !== 'undefined' && !window.$recoilDebugStates) {
3837 window.$recoilDebugStates = [];
3838 }
3839} // When removing this deprecated function, remove stateBySettingRecoilValue
3840// which will no longer be needed.
3841
3842
3843function initialStoreState_DEPRECATED(store, initializeState) {
3844 const initial = makeEmptyStoreState$2();
3845 initializeState({
3846 // $FlowFixMe[escaped-generic]
3847 set: (atom, value) => {
3848 const state = initial.currentTree;
3849 const writes = setNodeValue$2(store, state, atom.key, value);
3850 const writtenNodes = new Set(writes.keys());
3851 const nonvalidatedAtoms = state.nonvalidatedAtoms.clone();
3852
3853 for (const n of writtenNodes) {
3854 nonvalidatedAtoms.delete(n);
3855 }
3856
3857 initial.currentTree = { ...state,
3858 dirtyAtoms: Recoil_unionSets(state.dirtyAtoms, writtenNodes),
3859 atomValues: applyAtomValueWrites$1(state.atomValues, writes),
3860 // NB: PLEASE un-export applyAtomValueWrites when deleting this code
3861 nonvalidatedAtoms
3862 };
3863 },
3864 setUnvalidatedAtomValues: atomValues => {
3865 // FIXME replace this with a mutative loop
3866 atomValues.forEach((v, k) => {
3867 initial.currentTree = setUnvalidatedAtomValue_DEPRECATED$1(initial.currentTree, k, v);
3868 });
3869 }
3870 });
3871 return initial;
3872}
3873
3874function initialStoreState(initializeState) {
3875 const snapshot = freshSnapshot$1().map(initializeState);
3876 return snapshot.getStore_INTERNAL().getState();
3877}
3878
3879let nextID = 0;
3880
3881function RecoilRoot_INTERNAL({
3882 initializeState_DEPRECATED,
3883 initializeState,
3884 store_INTERNAL: storeProp,
3885 // For use with React "context bridging"
3886 children
3887}) {
3888 var _createMutableSource;
3889
3890 // prettier-ignore
3891 // @fb-only: useEffect(() => {
3892 // @fb-only: if (gkx('recoil_usage_logging')) {
3893 // @fb-only: try {
3894 // @fb-only: RecoilUsageLogFalcoEvent.log(() => ({
3895 // @fb-only: type: RecoilusagelogEvent.RECOIL_ROOT_MOUNTED,
3896 // @fb-only: path: URI.getRequestURI().getPath(),
3897 // @fb-only: }));
3898 // @fb-only: } catch {
3899 // @fb-only: recoverableViolation(
3900 // @fb-only: 'Error when logging Recoil Usage event',
3901 // @fb-only: 'recoil',
3902 // @fb-only: );
3903 // @fb-only: }
3904 // @fb-only: }
3905 // @fb-only: }, []);
3906 let storeState; // eslint-disable-line prefer-const
3907
3908 const getGraph = version => {
3909 const graphs = storeState.current.graphsByVersion;
3910
3911 if (graphs.has(version)) {
3912 return Recoil_nullthrows(graphs.get(version));
3913 }
3914
3915 const newGraph = graph$3();
3916 graphs.set(version, newGraph);
3917 return newGraph;
3918 };
3919
3920 const subscribeToTransactions = (callback, key) => {
3921 if (key == null) {
3922 // Global transaction subscriptions
3923 const {
3924 transactionSubscriptions
3925 } = storeRef.current.getState();
3926 const id = nextID++;
3927 transactionSubscriptions.set(id, callback);
3928 return {
3929 release: () => {
3930 transactionSubscriptions.delete(id);
3931 }
3932 };
3933 } else {
3934 // Node-specific transaction subscriptions:
3935 const {
3936 nodeTransactionSubscriptions
3937 } = storeRef.current.getState();
3938
3939 if (!nodeTransactionSubscriptions.has(key)) {
3940 nodeTransactionSubscriptions.set(key, new Map());
3941 }
3942
3943 const id = nextID++;
3944 Recoil_nullthrows(nodeTransactionSubscriptions.get(key)).set(id, callback);
3945 return {
3946 release: () => {
3947 const subs = nodeTransactionSubscriptions.get(key);
3948
3949 if (subs) {
3950 subs.delete(id);
3951
3952 if (subs.size === 0) {
3953 nodeTransactionSubscriptions.delete(key);
3954 }
3955 }
3956 }
3957 };
3958 }
3959 };
3960
3961 const addTransactionMetadata = metadata => {
3962 startNextTreeIfNeeded(storeRef.current);
3963
3964 for (const k of Object.keys(metadata)) {
3965 Recoil_nullthrows(storeRef.current.getState().nextTree).transactionMetadata[k] = metadata[k];
3966 }
3967 };
3968
3969 const replaceState = replacer => {
3970 const storeState = storeRef.current.getState();
3971 startNextTreeIfNeeded(storeRef.current); // Use replacer to get the next state:
3972
3973 const nextTree = Recoil_nullthrows(storeState.nextTree);
3974 let replaced;
3975
3976 try {
3977 stateReplacerIsBeingExecuted = true;
3978 replaced = replacer(nextTree);
3979 } finally {
3980 stateReplacerIsBeingExecuted = false;
3981 }
3982
3983 if (replaced === nextTree) {
3984 return;
3985 }
3986
3987 if (process.env.NODE_ENV !== "production") {
3988 if (typeof window !== 'undefined') {
3989 window.$recoilDebugStates.push(replaced); // TODO this shouldn't happen here because it's not batched
3990 }
3991 } // Save changes to nextTree and schedule a React update:
3992
3993
3994 storeState.nextTree = replaced;
3995
3996 if (Recoil_gkx_1('recoil_early_rendering_2021')) {
3997 notifyComponents(store, storeState, replaced);
3998 }
3999
4000 Recoil_nullthrows(notifyBatcherOfChange.current)();
4001 };
4002
4003 const notifyBatcherOfChange = useRef(null);
4004 const setNotifyBatcherOfChange = useCallback(x => {
4005 notifyBatcherOfChange.current = x;
4006 }, [notifyBatcherOfChange]); // FIXME T2710559282599660
4007
4008 const createMutableSource = (_createMutableSource = react.createMutableSource) !== null && _createMutableSource !== void 0 ? _createMutableSource : // flowlint-line unclear-type:off
4009 react.unstable_createMutableSource; // flowlint-line unclear-type:off
4010
4011 const store = storeProp !== null && storeProp !== void 0 ? storeProp : {
4012 getState: () => storeState.current,
4013 replaceState,
4014 getGraph,
4015 subscribeToTransactions,
4016 addTransactionMetadata
4017 };
4018 const storeRef = useRef(store);
4019 storeState = useRef(initializeState_DEPRECATED != null ? initialStoreState_DEPRECATED(store, initializeState_DEPRECATED) : initializeState != null ? initialStoreState(initializeState) : makeEmptyStoreState$2());
4020 const mutableSource = useMemo(() => createMutableSource ? createMutableSource(storeState, () => storeState.current.currentTree.version) : null, [createMutableSource, storeState]); // Cleanup when the <RecoilRoot> is unmounted
4021
4022 useEffect(() => () => {
4023 for (const atomKey of storeRef.current.getState().knownAtoms) {
4024 cleanUpNode$2(storeRef.current, atomKey);
4025 }
4026 }, []);
4027 return /*#__PURE__*/react.createElement(AppContext.Provider, {
4028 value: storeRef
4029 }, /*#__PURE__*/react.createElement(MutableSourceContext.Provider, {
4030 value: mutableSource
4031 }, /*#__PURE__*/react.createElement(Batcher, {
4032 setNotifyBatcherOfChange: setNotifyBatcherOfChange
4033 }), children));
4034}
4035
4036function RecoilRoot(props) {
4037 const {
4038 override,
4039 ...propsExceptOverride
4040 } = props;
4041 const ancestorStoreRef = useStoreRef();
4042
4043 if (override === false && ancestorStoreRef.current !== defaultStore) {
4044 // If ancestorStoreRef.current !== defaultStore, it means that this
4045 // RecoilRoot is not nested within another.
4046 return props.children;
4047 }
4048
4049 return /*#__PURE__*/react.createElement(RecoilRoot_INTERNAL, propsExceptOverride);
4050}
4051
4052var Recoil_RecoilRoot_react = {
4053 useStoreRef,
4054 useRecoilMutableSource,
4055 RecoilRoot,
4056 notifyComponents_FOR_TESTING: notifyComponents,
4057 sendEndOfBatchNotifications_FOR_TESTING: sendEndOfBatchNotifications
4058};
4059
4060/**
4061 * Copyright (c) Facebook, Inc. and its affiliates.
4062 *
4063 * MIT License
4064 *
4065 * Copyright (c) 2014-2019 Georg Tavonius
4066 *
4067 * Permission is hereby granted, free of charge, to any person obtaining a copy
4068 * of this software and associated documentation files (the "Software"), to deal
4069 * in the Software without restriction, including without limitation the rights
4070 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4071 * copies of the Software, and to permit persons to whom the Software is
4072 * furnished to do so, subject to the following conditions:
4073 *
4074 * The above copyright notice and this permission notice shall be included in all
4075 * copies or substantial portions of the Software.
4076 *
4077 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4078 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4079 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4080 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4081 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4082 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4083 * SOFTWARE.
4084 *
4085 * @emails oncall+recoil
4086 *
4087 * @format
4088 */
4089
4090const UNKNOWN_FUNCTION = '<unknown>';
4091/**
4092 * This parses the different stack traces and puts them into one format
4093 * This borrows heavily from TraceKit (https://github.com/csnover/TraceKit)
4094 */
4095
4096function stackTraceParser(stackString) {
4097 const lines = stackString.split('\n');
4098 return lines.reduce((stack, line) => {
4099 const parseResult = parseChrome(line) || parseWinjs(line) || parseGecko(line) || parseNode(line) || parseJSC(line);
4100
4101 if (parseResult) {
4102 stack.push(parseResult);
4103 }
4104
4105 return stack;
4106 }, []);
4107}
4108
4109const chromeRe = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\/|[a-z]:\\|\\\\).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
4110const chromeEvalRe = /\((\S*)(?::(\d+))(?::(\d+))\)/;
4111
4112function parseChrome(line) {
4113 const parts = chromeRe.exec(line);
4114
4115 if (!parts) {
4116 return null;
4117 }
4118
4119 const isNative = parts[2] && parts[2].indexOf('native') === 0; // start of line
4120
4121 const isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
4122
4123 const submatch = chromeEvalRe.exec(parts[2]);
4124
4125 if (isEval && submatch != null) {
4126 // throw out eval line/column and use top-most line/column number
4127 parts[2] = submatch[1]; // url
4128
4129 parts[3] = submatch[2]; // line
4130
4131 parts[4] = submatch[3]; // column
4132 }
4133
4134 return {
4135 file: !isNative ? parts[2] : null,
4136 methodName: parts[1] || UNKNOWN_FUNCTION,
4137 arguments: isNative ? [parts[2]] : [],
4138 lineNumber: parts[3] ? +parts[3] : null,
4139 column: parts[4] ? +parts[4] : null
4140 };
4141}
4142
4143const winjsRe = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
4144
4145function parseWinjs(line) {
4146 const parts = winjsRe.exec(line);
4147
4148 if (!parts) {
4149 return null;
4150 }
4151
4152 return {
4153 file: parts[2],
4154 methodName: parts[1] || UNKNOWN_FUNCTION,
4155 arguments: [],
4156 lineNumber: +parts[3],
4157 column: parts[4] ? +parts[4] : null
4158 };
4159}
4160
4161const geckoRe = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i;
4162const geckoEvalRe = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
4163
4164function parseGecko(line) {
4165 const parts = geckoRe.exec(line);
4166
4167 if (!parts) {
4168 return null;
4169 }
4170
4171 const isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
4172 const submatch = geckoEvalRe.exec(parts[3]);
4173
4174 if (isEval && submatch != null) {
4175 // throw out eval line/column and use top-most line number
4176 parts[3] = submatch[1];
4177 parts[4] = submatch[2];
4178 parts[5] = null; // no column when eval
4179 }
4180
4181 return {
4182 file: parts[3],
4183 methodName: parts[1] || UNKNOWN_FUNCTION,
4184 arguments: parts[2] ? parts[2].split(',') : [],
4185 lineNumber: parts[4] ? +parts[4] : null,
4186 column: parts[5] ? +parts[5] : null
4187 };
4188}
4189
4190const javaScriptCoreRe = /^\s*(?:([^@]*)(?:\((.*?)\))?@)?(\S.*?):(\d+)(?::(\d+))?\s*$/i;
4191
4192function parseJSC(line) {
4193 const parts = javaScriptCoreRe.exec(line);
4194
4195 if (!parts) {
4196 return null;
4197 }
4198
4199 return {
4200 file: parts[3],
4201 methodName: parts[1] || UNKNOWN_FUNCTION,
4202 arguments: [],
4203 lineNumber: +parts[4],
4204 column: parts[5] ? +parts[5] : null
4205 };
4206}
4207
4208const nodeRe = /^\s*at (?:((?:\[object object\])?[^\\/]+(?: \[as \S+\])?) )?\(?(.*?):(\d+)(?::(\d+))?\)?\s*$/i;
4209
4210function parseNode(line) {
4211 const parts = nodeRe.exec(line);
4212
4213 if (!parts) {
4214 return null;
4215 }
4216
4217 return {
4218 file: parts[2],
4219 methodName: parts[1] || UNKNOWN_FUNCTION,
4220 arguments: [],
4221 lineNumber: +parts[3],
4222 column: parts[4] ? +parts[4] : null
4223 };
4224}
4225
4226var Recoil_stackTraceParser = stackTraceParser;
4227
4228const {
4229 useRef: useRef$1
4230} = react;
4231
4232function useComponentName() {
4233 const nameRef = useRef$1();
4234
4235 if (process.env.NODE_ENV !== "production") {
4236 if (Recoil_gkx_1('recoil_infer_component_names')) {
4237 var _nameRef$current;
4238
4239 if (nameRef.current === undefined) {
4240 // There is no blessed way to determine the calling React component from
4241 // within a hook. This hack uses the fact that hooks must start with 'use'
4242 // and that hooks are either called by React Components or other hooks. It
4243 // follows therefore, that to find the calling component, you simply need
4244 // to look down the stack and find the first function which doesn't start
4245 // with 'use'. We are only enabling this in dev for now, since once the
4246 // codebase is minified, the naming assumptions no longer hold true.
4247 // eslint-disable-next-line fb-www/no-new-error
4248 const frames = Recoil_stackTraceParser(new Error().stack);
4249
4250 for (const {
4251 methodName
4252 } of frames) {
4253 // I observed cases where the frame was of the form 'Object.useXXX'
4254 // hence why I'm searching for hooks following a word boundary
4255 if (!methodName.match(/\buse[^\b]+$/)) {
4256 return nameRef.current = methodName;
4257 }
4258 }
4259
4260 nameRef.current = null;
4261 }
4262
4263 return (_nameRef$current = nameRef.current) !== null && _nameRef$current !== void 0 ? _nameRef$current : '<unable to determine component name>';
4264 }
4265 } // @fb-only: return "<component name only available when both in dev mode and when passing GK 'recoil_infer_component_names'>";
4266
4267
4268 return '<component name not available>'; // @oss-only
4269}
4270
4271var Recoil_useComponentName = useComponentName;
4272
4273/**
4274 * Copyright (c) Facebook, Inc. and its affiliates.
4275 *
4276 * This source code is licensed under the MIT license found in the
4277 * LICENSE file in the root directory of this source tree.
4278 *
4279 * @emails oncall+recoil
4280 *
4281 * @format
4282 */
4283
4284function shallowArrayEqual(a, b) {
4285 if (a === b) {
4286 return true;
4287 }
4288
4289 if (a.length !== b.length) {
4290 return false;
4291 }
4292
4293 for (let i = 0, l = a.length; i < l; i++) {
4294 if (a[i] !== b[i]) {
4295 return false;
4296 }
4297 }
4298
4299 return true;
4300}
4301
4302var Recoil_shallowArrayEqual = shallowArrayEqual;
4303
4304const {
4305 useEffect: useEffect$1,
4306 useRef: useRef$2
4307} = react;
4308
4309function usePrevious(value) {
4310 const ref = useRef$2();
4311 useEffect$1(() => {
4312 ref.current = value;
4313 });
4314 return ref.current;
4315}
4316
4317var Recoil_usePrevious = usePrevious;
4318
4319const {
4320 useStoreRef: useStoreRef$1
4321} = Recoil_RecoilRoot_react;
4322
4323const {
4324 SUSPENSE_TIMEOUT_MS: SUSPENSE_TIMEOUT_MS$1
4325} = Recoil_Retention;
4326
4327const {
4328 updateRetainCount: updateRetainCount$2
4329} = Recoil_Retention;
4330
4331const {
4332 RetentionZone: RetentionZone$3
4333} = Recoil_RetentionZone;
4334
4335const {
4336 isSSR: isSSR$2
4337} = Recoil_Environment;
4338
4339
4340
4341
4342
4343
4344
4345const {
4346 useEffect: useEffect$2,
4347 useRef: useRef$3
4348} = react; // I don't see a way to avoid the any type here because we want to accept readable
4349// and writable values with any type parameter, but normally with writable ones
4350// RecoilState<SomeT> is not a subtype of RecoilState<mixed>.
4351
4352
4353// flowlint-line unclear-type:off
4354function useRetain(toRetain) {
4355 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
4356 return;
4357 } // eslint-disable-next-line fb-www/react-hooks
4358
4359
4360 return useRetain_ACTUAL(toRetain);
4361}
4362
4363function useRetain_ACTUAL(toRetain) {
4364 const array = Array.isArray(toRetain) ? toRetain : [toRetain];
4365 const retainables = array.map(a => a instanceof RetentionZone$3 ? a : a.key);
4366 const storeRef = useStoreRef$1();
4367 useEffect$2(() => {
4368 if (!Recoil_gkx_1('recoil_memory_managament_2020')) {
4369 return;
4370 }
4371
4372 const store = storeRef.current;
4373
4374 if (timeoutID.current && !isSSR$2) {
4375 // Already performed a temporary retain on render, simply cancel the release
4376 // of that temporary retain.
4377 window.clearTimeout(timeoutID.current);
4378 timeoutID.current = null;
4379 } else {
4380 for (const r of retainables) {
4381 updateRetainCount$2(store, r, 1);
4382 }
4383 }
4384
4385 return () => {
4386 for (const r of retainables) {
4387 updateRetainCount$2(store, r, -1);
4388 }
4389 }; // eslint-disable-next-line fb-www/react-hooks-deps
4390 }, [storeRef, ...retainables]); // We want to retain if the component suspends. This is terrible but the Suspense
4391 // API affords us no better option. If we suspend and never commit after some
4392 // seconds, then release. The 'actual' retain/release in the effect above
4393 // cancels this.
4394
4395 const timeoutID = useRef$3();
4396 const previousRetainables = Recoil_usePrevious(retainables);
4397
4398 if (!isSSR$2 && (previousRetainables === undefined || !Recoil_shallowArrayEqual(previousRetainables, retainables))) {
4399 const store = storeRef.current;
4400
4401 for (const r of retainables) {
4402 updateRetainCount$2(store, r, 1);
4403 }
4404
4405 if (previousRetainables) {
4406 for (const r of previousRetainables) {
4407 updateRetainCount$2(store, r, -1);
4408 }
4409 }
4410
4411 if (timeoutID.current) {
4412 window.clearTimeout(timeoutID.current);
4413 }
4414
4415 timeoutID.current = window.setTimeout(() => {
4416 timeoutID.current = null;
4417
4418 for (const r of retainables) {
4419 updateRetainCount$2(store, r, -1);
4420 }
4421 }, SUSPENSE_TIMEOUT_MS$1);
4422 }
4423}
4424
4425var Recoil_useRetain = useRetain;
4426
4427const {
4428 batchUpdates: batchUpdates$2
4429} = Recoil_Batching;
4430
4431const {
4432 DEFAULT_VALUE: DEFAULT_VALUE$2
4433} = Recoil_Node;
4434
4435const {
4436 useRecoilMutableSource: useRecoilMutableSource$1,
4437 useStoreRef: useStoreRef$2
4438} = Recoil_RecoilRoot_react;
4439
4440const {
4441 isRecoilValue: isRecoilValue$2
4442} = Recoil_RecoilValue$1;
4443
4444const {
4445 AbstractRecoilValue: AbstractRecoilValue$3,
4446 getRecoilValueAsLoadable: getRecoilValueAsLoadable$2,
4447 setRecoilValue: setRecoilValue$2,
4448 setUnvalidatedRecoilValue: setUnvalidatedRecoilValue$2,
4449 subscribeToRecoilValue: subscribeToRecoilValue$1
4450} = Recoil_RecoilValueInterface;
4451
4452const {
4453 setByAddingToSet: setByAddingToSet$2
4454} = Recoil_CopyOnWrite;
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464const {
4465 mutableSourceExists: mutableSourceExists$2,
4466 useMutableSource: useMutableSource$1
4467} = Recoil_mutableSource;
4468
4469
4470
4471
4472
4473const {
4474 useCallback: useCallback$1,
4475 useEffect: useEffect$3,
4476 useMemo: useMemo$1,
4477 useRef: useRef$4,
4478 useState: useState$1
4479} = react;
4480
4481function handleLoadable(loadable, recoilValue, storeRef) {
4482 // We can't just throw the promise we are waiting on to Suspense. If the
4483 // upstream dependencies change it may produce a state in which the component
4484 // can render, but it would still be suspended on a Promise that may never resolve.
4485 if (loadable.state === 'hasValue') {
4486 return loadable.contents;
4487 } else if (loadable.state === 'loading') {
4488 const promise = new Promise(resolve => {
4489 storeRef.current.getState().suspendedComponentResolvers.add(resolve);
4490 }); // $FlowFixMe Flow(prop-missing) for integrating with tools that inspect thrown promises @fb-only
4491 // @fb-only: promise.displayName = `Recoil State: ${recoilValue.key}`;
4492
4493 throw promise;
4494 } else if (loadable.state === 'hasError') {
4495 throw loadable.contents;
4496 } else {
4497 throw Recoil_err(`Invalid value of loadable atom "${recoilValue.key}"`);
4498 }
4499}
4500
4501function validateRecoilValue(recoilValue, hookName) {
4502 if (!isRecoilValue$2(recoilValue)) {
4503 throw Recoil_err(`Invalid argument to ${hookName}: expected an atom or selector but got ${String(recoilValue)}`);
4504 }
4505}
4506
4507/**
4508 * Various things are broken with useRecoilInterface, particularly concurrent mode
4509 * and memory management. They will not be fixed.
4510 * */
4511function useRecoilInterface_DEPRECATED() {
4512 const storeRef = useStoreRef$2();
4513 const [, forceUpdate] = useState$1([]);
4514 const recoilValuesUsed = useRef$4(new Set());
4515 recoilValuesUsed.current = new Set(); // Track the RecoilValues used just during this render
4516
4517 const previousSubscriptions = useRef$4(new Set());
4518 const subscriptions = useRef$4(new Map());
4519 const unsubscribeFrom = useCallback$1(key => {
4520 const sub = subscriptions.current.get(key);
4521
4522 if (sub) {
4523 sub.release();
4524 subscriptions.current.delete(key);
4525 }
4526 }, [subscriptions]);
4527 const componentName = Recoil_useComponentName();
4528 useEffect$3(() => {
4529 const store = storeRef.current;
4530
4531 function updateState(_state, key) {
4532 if (!subscriptions.current.has(key)) {
4533 return;
4534 }
4535
4536 forceUpdate([]);
4537 }
4538
4539 Recoil_differenceSets(recoilValuesUsed.current, previousSubscriptions.current).forEach(key => {
4540 if (subscriptions.current.has(key)) {
4541 Recoil_expectationViolation(`Double subscription to RecoilValue "${key}"`);
4542 return;
4543 }
4544
4545 const sub = subscribeToRecoilValue$1(store, new AbstractRecoilValue$3(key), state => {
4546 updateState(state, key);
4547 }, componentName);
4548 subscriptions.current.set(key, sub);
4549 /**
4550 * Since we're subscribing in an effect we need to update to the latest
4551 * value of the atom since it may have changed since we rendered. We can
4552 * go ahead and do that now, unless we're in the middle of a batch --
4553 * in which case we should do it at the end of the batch, due to the
4554 * following edge case: Suppose an atom is updated in another useEffect
4555 * of this same component. Then the following sequence of events occur:
4556 * 1. Atom is updated and subs fired (but we may not be subscribed
4557 * yet depending on order of effects, so we miss this) Updated value
4558 * is now in nextTree, but not currentTree.
4559 * 2. This effect happens. We subscribe and update.
4560 * 3. From the update we re-render and read currentTree, with old value.
4561 * 4. Batcher's effect sets currentTree to nextTree.
4562 * In this sequence we miss the update. To avoid that, add the update
4563 * to queuedComponentCallback if a batch is in progress.
4564 */
4565 // FIXME delete queuedComponentCallbacks_DEPRECATED when deleting useInterface.
4566
4567 const state = store.getState();
4568
4569 if (state.nextTree) {
4570 store.getState().queuedComponentCallbacks_DEPRECATED.push(() => {
4571 updateState(store.getState(), key);
4572 });
4573 } else {
4574 updateState(store.getState(), key);
4575 }
4576 });
4577 Recoil_differenceSets(previousSubscriptions.current, recoilValuesUsed.current).forEach(key => {
4578 unsubscribeFrom(key);
4579 });
4580 previousSubscriptions.current = recoilValuesUsed.current;
4581 });
4582 useEffect$3(() => {
4583 const subs = subscriptions.current;
4584 return () => subs.forEach((_, key) => unsubscribeFrom(key));
4585 }, [unsubscribeFrom]);
4586 return useMemo$1(() => {
4587 // eslint-disable-next-line no-shadow
4588 function useSetRecoilState(recoilState) {
4589 if (process.env.NODE_ENV !== "production") {
4590 // $FlowFixMe[escaped-generic]
4591 validateRecoilValue(recoilState, 'useSetRecoilState');
4592 }
4593
4594 return newValueOrUpdater => {
4595 setRecoilValue$2(storeRef.current, recoilState, newValueOrUpdater);
4596 };
4597 } // eslint-disable-next-line no-shadow
4598
4599
4600 function useResetRecoilState(recoilState) {
4601 if (process.env.NODE_ENV !== "production") {
4602 // $FlowFixMe[escaped-generic]
4603 validateRecoilValue(recoilState, 'useResetRecoilState');
4604 }
4605
4606 return () => setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$2);
4607 } // eslint-disable-next-line no-shadow
4608
4609
4610 function useRecoilValueLoadable(recoilValue) {
4611 var _storeState$nextTree;
4612
4613 if (process.env.NODE_ENV !== "production") {
4614 // $FlowFixMe[escaped-generic]
4615 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
4616 }
4617
4618 if (!recoilValuesUsed.current.has(recoilValue.key)) {
4619 recoilValuesUsed.current = setByAddingToSet$2(recoilValuesUsed.current, recoilValue.key);
4620 } // TODO Restore optimization to memoize lookup
4621
4622
4623 const storeState = storeRef.current.getState();
4624 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);
4625 } // eslint-disable-next-line no-shadow
4626
4627
4628 function useRecoilValue(recoilValue) {
4629 if (process.env.NODE_ENV !== "production") {
4630 // $FlowFixMe[escaped-generic]
4631 validateRecoilValue(recoilValue, 'useRecoilValue');
4632 }
4633
4634 const loadable = useRecoilValueLoadable(recoilValue);
4635 return handleLoadable(loadable, recoilValue, storeRef);
4636 } // eslint-disable-next-line no-shadow
4637
4638
4639 function useRecoilState(recoilState) {
4640 if (process.env.NODE_ENV !== "production") {
4641 // $FlowFixMe[escaped-generic]
4642 validateRecoilValue(recoilState, 'useRecoilState');
4643 }
4644
4645 return [useRecoilValue(recoilState), useSetRecoilState(recoilState)];
4646 } // eslint-disable-next-line no-shadow
4647
4648
4649 function useRecoilStateLoadable(recoilState) {
4650 if (process.env.NODE_ENV !== "production") {
4651 // $FlowFixMe[escaped-generic]
4652 validateRecoilValue(recoilState, 'useRecoilStateLoadable');
4653 }
4654
4655 return [useRecoilValueLoadable(recoilState), useSetRecoilState(recoilState)];
4656 }
4657
4658 return {
4659 getRecoilValue: useRecoilValue,
4660 getRecoilValueLoadable: useRecoilValueLoadable,
4661 getRecoilState: useRecoilState,
4662 getRecoilStateLoadable: useRecoilStateLoadable,
4663 getSetRecoilState: useSetRecoilState,
4664 getResetRecoilState: useResetRecoilState
4665 };
4666 }, [recoilValuesUsed, storeRef]);
4667}
4668
4669const recoilComponentGetRecoilValueCount_FOR_TESTING = {
4670 current: 0
4671};
4672
4673function useRecoilValueLoadable_MUTABLESOURCE(recoilValue) {
4674 if (process.env.NODE_ENV !== "production") {
4675 // $FlowFixMe[escaped-generic]
4676 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
4677 }
4678
4679 const storeRef = useStoreRef$2();
4680 const getLoadable = useCallback$1(() => {
4681 var _storeState$nextTree2;
4682
4683 const store = storeRef.current;
4684 const storeState = store.getState();
4685 const treeState = Recoil_gkx_1('recoil_early_rendering_2021') ? (_storeState$nextTree2 = storeState.nextTree) !== null && _storeState$nextTree2 !== void 0 ? _storeState$nextTree2 : storeState.currentTree : storeState.currentTree;
4686 return getRecoilValueAsLoadable$2(store, recoilValue, treeState);
4687 }, [storeRef, recoilValue]);
4688 const getLoadableWithTesting = useCallback$1(() => {
4689 if (process.env.NODE_ENV !== "production") {
4690 recoilComponentGetRecoilValueCount_FOR_TESTING.current++;
4691 }
4692
4693 return getLoadable();
4694 }, [getLoadable]);
4695 const componentName = Recoil_useComponentName();
4696 const subscribe = useCallback$1((_storeState, callback) => {
4697 const store = storeRef.current;
4698 const subscription = subscribeToRecoilValue$1(store, recoilValue, () => {
4699 if (!Recoil_gkx_1('recoil_suppress_rerender_in_callback')) {
4700 return callback();
4701 } // Only re-render if the value has changed.
4702 // This will evaluate the atom/selector now as well as when the
4703 // component renders, but that may help with prefetching.
4704
4705
4706 const newLoadable = getLoadable();
4707
4708 if (!prevLoadableRef.current.is(newLoadable)) {
4709 callback();
4710 } // If the component is suspended then the effect setting prevLoadableRef
4711 // will not run. So, set the previous value here when its subscription
4712 // is fired to wake it up. We can't just rely on this, though, because
4713 // this only executes when an atom/selector is dirty and the atom/selector
4714 // passed to the hook can dynamically change.
4715
4716
4717 prevLoadableRef.current = newLoadable;
4718 }, componentName);
4719 return subscription.release;
4720 }, [storeRef, recoilValue, componentName, getLoadable]);
4721 const source = useRecoilMutableSource$1();
4722 const loadable = useMutableSource$1(source, getLoadableWithTesting, subscribe);
4723 const prevLoadableRef = useRef$4(loadable);
4724 useEffect$3(() => {
4725 prevLoadableRef.current = loadable;
4726 });
4727 return loadable;
4728}
4729
4730function useRecoilValueLoadable_LEGACY(recoilValue) {
4731 if (process.env.NODE_ENV !== "production") {
4732 // $FlowFixMe[escaped-generic]
4733 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
4734 }
4735
4736 const storeRef = useStoreRef$2();
4737 const [_, forceUpdate] = useState$1([]);
4738 const componentName = Recoil_useComponentName();
4739 useEffect$3(() => {
4740 const store = storeRef.current;
4741 const storeState = store.getState();
4742 const subscription = subscribeToRecoilValue$1(store, recoilValue, _state => {
4743 var _prevLoadableRef$curr;
4744
4745 if (!Recoil_gkx_1('recoil_suppress_rerender_in_callback')) {
4746 return forceUpdate([]);
4747 }
4748
4749 const newLoadable = getRecoilValueAsLoadable$2(store, recoilValue, store.getState().currentTree);
4750
4751 if (!((_prevLoadableRef$curr = prevLoadableRef.current) === null || _prevLoadableRef$curr === void 0 ? void 0 : _prevLoadableRef$curr.is(newLoadable))) {
4752 forceUpdate(newLoadable);
4753 }
4754
4755 prevLoadableRef.current = newLoadable;
4756 }, componentName);
4757 /**
4758 * Since we're subscribing in an effect we need to update to the latest
4759 * value of the atom since it may have changed since we rendered. We can
4760 * go ahead and do that now, unless we're in the middle of a batch --
4761 * in which case we should do it at the end of the batch, due to the
4762 * following edge case: Suppose an atom is updated in another useEffect
4763 * of this same component. Then the following sequence of events occur:
4764 * 1. Atom is updated and subs fired (but we may not be subscribed
4765 * yet depending on order of effects, so we miss this) Updated value
4766 * is now in nextTree, but not currentTree.
4767 * 2. This effect happens. We subscribe and update.
4768 * 3. From the update we re-render and read currentTree, with old value.
4769 * 4. Batcher's effect sets currentTree to nextTree.
4770 * In this sequence we miss the update. To avoid that, add the update
4771 * to queuedComponentCallback if a batch is in progress.
4772 */
4773
4774 if (storeState.nextTree) {
4775 store.getState().queuedComponentCallbacks_DEPRECATED.push(() => {
4776 prevLoadableRef.current = null;
4777 forceUpdate([]);
4778 });
4779 } else {
4780 var _prevLoadableRef$curr2;
4781
4782 if (!Recoil_gkx_1('recoil_suppress_rerender_in_callback')) {
4783 return forceUpdate([]);
4784 }
4785
4786 const newLoadable = getRecoilValueAsLoadable$2(store, recoilValue, store.getState().currentTree);
4787
4788 if (!((_prevLoadableRef$curr2 = prevLoadableRef.current) === null || _prevLoadableRef$curr2 === void 0 ? void 0 : _prevLoadableRef$curr2.is(newLoadable))) {
4789 forceUpdate(newLoadable);
4790 }
4791
4792 prevLoadableRef.current = newLoadable;
4793 }
4794
4795 return subscription.release;
4796 }, [componentName, recoilValue, storeRef]);
4797 const loadable = getRecoilValueAsLoadable$2(storeRef.current, recoilValue);
4798 const prevLoadableRef = useRef$4(loadable);
4799 useEffect$3(() => {
4800 prevLoadableRef.current = loadable;
4801 });
4802 return loadable;
4803}
4804/**
4805 Like useRecoilValue(), but either returns the value if available or
4806 just undefined if not available for any reason, such as pending or error.
4807*/
4808
4809
4810function useRecoilValueLoadable(recoilValue) {
4811 if (Recoil_gkx_1('recoil_memory_managament_2020')) {
4812 // eslint-disable-next-line fb-www/react-hooks
4813 Recoil_useRetain(recoilValue);
4814 }
4815
4816 if (mutableSourceExists$2()) {
4817 // eslint-disable-next-line fb-www/react-hooks
4818 return useRecoilValueLoadable_MUTABLESOURCE(recoilValue);
4819 } else {
4820 // eslint-disable-next-line fb-www/react-hooks
4821 return useRecoilValueLoadable_LEGACY(recoilValue);
4822 }
4823}
4824/**
4825 Returns the value represented by the RecoilValue.
4826 If the value is pending, it will throw a Promise to suspend the component,
4827 if the value is an error it will throw it for the nearest React error boundary.
4828 This will also subscribe the component for any updates in the value.
4829 */
4830
4831
4832function useRecoilValue(recoilValue) {
4833 if (process.env.NODE_ENV !== "production") {
4834 // $FlowFixMe[escaped-generic]
4835 validateRecoilValue(recoilValue, 'useRecoilValue');
4836 }
4837
4838 const storeRef = useStoreRef$2();
4839 const loadable = useRecoilValueLoadable(recoilValue);
4840 return handleLoadable(loadable, recoilValue, storeRef);
4841}
4842/**
4843 Returns a function that allows the value of a RecoilState to be updated, but does
4844 not subscribe the component to changes to that RecoilState.
4845*/
4846
4847
4848function useSetRecoilState(recoilState) {
4849 if (process.env.NODE_ENV !== "production") {
4850 // $FlowFixMe[escaped-generic]
4851 validateRecoilValue(recoilState, 'useSetRecoilState');
4852 }
4853
4854 const storeRef = useStoreRef$2();
4855 return useCallback$1(newValueOrUpdater => {
4856 setRecoilValue$2(storeRef.current, recoilState, newValueOrUpdater);
4857 }, [storeRef, recoilState]);
4858}
4859/**
4860 Returns a function that will reset the value of a RecoilState to its default
4861*/
4862
4863
4864function useResetRecoilState(recoilState) {
4865 if (process.env.NODE_ENV !== "production") {
4866 // $FlowFixMe[escaped-generic]
4867 validateRecoilValue(recoilState, 'useResetRecoilState');
4868 }
4869
4870 const storeRef = useStoreRef$2();
4871 return useCallback$1(() => {
4872 setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$2);
4873 }, [storeRef, recoilState]);
4874}
4875/**
4876 Equivalent to useState(). Allows the value of the RecoilState to be read and written.
4877 Subsequent updates to the RecoilState will cause the component to re-render. If the
4878 RecoilState is pending, this will suspend the component and initiate the
4879 retrieval of the value. If evaluating the RecoilState resulted in an error, this will
4880 throw the error so that the nearest React error boundary can catch it.
4881*/
4882
4883
4884function useRecoilState(recoilState) {
4885 if (process.env.NODE_ENV !== "production") {
4886 // $FlowFixMe[escaped-generic]
4887 validateRecoilValue(recoilState, 'useRecoilState');
4888 }
4889
4890 return [useRecoilValue(recoilState), useSetRecoilState(recoilState)];
4891}
4892/**
4893 Like useRecoilState(), but does not cause Suspense or React error handling. Returns
4894 an object that indicates whether the RecoilState is available, pending, or
4895 unavailable due to an error.
4896*/
4897
4898
4899function useRecoilStateLoadable(recoilState) {
4900 if (process.env.NODE_ENV !== "production") {
4901 // $FlowFixMe[escaped-generic]
4902 validateRecoilValue(recoilState, 'useRecoilStateLoadable');
4903 }
4904
4905 return [useRecoilValueLoadable(recoilState), useSetRecoilState(recoilState)];
4906}
4907
4908function useSetUnvalidatedAtomValues() {
4909 const storeRef = useStoreRef$2();
4910 return (values, transactionMetadata = {}) => {
4911 batchUpdates$2(() => {
4912 storeRef.current.addTransactionMetadata(transactionMetadata);
4913 values.forEach((value, key) => setUnvalidatedRecoilValue$2(storeRef.current, new AbstractRecoilValue$3(key), value));
4914 });
4915 };
4916}
4917
4918var Recoil_Hooks = {
4919 recoilComponentGetRecoilValueCount_FOR_TESTING,
4920 useRecoilInterface: useRecoilInterface_DEPRECATED,
4921 useRecoilState,
4922 useRecoilStateLoadable,
4923 useRecoilValue,
4924 useRecoilValueLoadable,
4925 useResetRecoilState,
4926 useSetRecoilState,
4927 useSetUnvalidatedAtomValues
4928};
4929
4930/**
4931 * Copyright (c) Facebook, Inc. and its affiliates.
4932 *
4933 * This source code is licensed under the MIT license found in the
4934 * LICENSE file in the root directory of this source tree.
4935 *
4936 * @emails oncall+recoil
4937 *
4938 * @format
4939 */
4940/**
4941 * Returns a map containing all of the keys + values from the original map where
4942 * the given callback returned true.
4943 */
4944
4945function filterMap(map, callback) {
4946 const result = new Map();
4947
4948 for (const [key, value] of map) {
4949 if (callback(value, key)) {
4950 result.set(key, value);
4951 }
4952 }
4953
4954 return result;
4955}
4956
4957var Recoil_filterMap = filterMap;
4958
4959/**
4960 * Copyright (c) Facebook, Inc. and its affiliates.
4961 *
4962 * This source code is licensed under the MIT license found in the
4963 * LICENSE file in the root directory of this source tree.
4964 *
4965 * @emails oncall+recoil
4966 *
4967 * @format
4968 */
4969/**
4970 * Returns a set containing all of the values from the original set where
4971 * the given callback returned true.
4972 */
4973
4974function filterSet(set, callback) {
4975 const result = new Set();
4976
4977 for (const value of set) {
4978 if (callback(value)) {
4979 result.add(value);
4980 }
4981 }
4982
4983 return result;
4984}
4985
4986var Recoil_filterSet = filterSet;
4987
4988/**
4989 * Copyright (c) Facebook, Inc. and its affiliates.
4990 *
4991 * This source code is licensed under the MIT license found in the
4992 * LICENSE file in the root directory of this source tree.
4993 *
4994 * @emails oncall+recoil
4995 *
4996 * @format
4997 */
4998
4999function mergeMaps(...maps) {
5000 const result = new Map();
5001
5002 for (let i = 0; i < maps.length; i++) {
5003 const iterator = maps[i].keys();
5004 let nextKey;
5005
5006 while (!(nextKey = iterator.next()).done) {
5007 // $FlowFixMe[incompatible-call] - map/iterator knows nothing about flow types
5008 result.set(nextKey.value, maps[i].get(nextKey.value));
5009 }
5010 }
5011 /* $FlowFixMe[incompatible-return] (>=0.66.0 site=www,mobile) This comment
5012 * suppresses an error found when Flow v0.66 was deployed. To see the error
5013 * delete this comment and run Flow. */
5014
5015
5016 return result;
5017}
5018
5019var Recoil_mergeMaps = mergeMaps;
5020
5021const {
5022 batchUpdates: batchUpdates$3
5023} = Recoil_Batching;
5024
5025const {
5026 DEFAULT_VALUE: DEFAULT_VALUE$3,
5027 getNode: getNode$3,
5028 nodes: nodes$1
5029} = Recoil_Node;
5030
5031const {
5032 useStoreRef: useStoreRef$3
5033} = Recoil_RecoilRoot_react;
5034
5035const {
5036 AbstractRecoilValue: AbstractRecoilValue$4,
5037 setRecoilValueLoadable: setRecoilValueLoadable$1
5038} = Recoil_RecoilValueInterface;
5039
5040const {
5041 SUSPENSE_TIMEOUT_MS: SUSPENSE_TIMEOUT_MS$2
5042} = Recoil_Retention;
5043
5044const {
5045 Snapshot: Snapshot$1,
5046 cloneSnapshot: cloneSnapshot$1
5047} = Recoil_Snapshot$1;
5048
5049const {
5050 isSSR: isSSR$3
5051} = Recoil_Environment;
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067const {
5068 useCallback: useCallback$2,
5069 useEffect: useEffect$4,
5070 useRef: useRef$5,
5071 useState: useState$2
5072} = react;
5073
5074function useTransactionSubscription(callback) {
5075 const storeRef = useStoreRef$3();
5076 useEffect$4(() => {
5077 const sub = storeRef.current.subscribeToTransactions(callback);
5078 return sub.release;
5079 }, [callback, storeRef]);
5080}
5081
5082function externallyVisibleAtomValuesInState(state) {
5083 const atomValues = state.atomValues.toMap();
5084 const persistedAtomContentsValues = Recoil_mapMap(Recoil_filterMap(atomValues, (v, k) => {
5085 const node = getNode$3(k);
5086 const persistence = node.persistence_UNSTABLE;
5087 return persistence != null && persistence.type !== 'none' && v.state === 'hasValue';
5088 }), v => v.contents); // Merge in nonvalidated atoms; we may not have defs for them but they will
5089 // all have persistence on or they wouldn't be there in the first place.
5090
5091 return Recoil_mergeMaps(state.nonvalidatedAtoms.toMap(), persistedAtomContentsValues);
5092}
5093
5094/**
5095 Calls the given callback after any atoms have been modified and the consequent
5096 component re-renders have been committed. This is intended for persisting
5097 the values of the atoms to storage. The stored values can then be restored
5098 using the useSetUnvalidatedAtomValues hook.
5099
5100 The callback receives the following info:
5101
5102 atomValues: The current value of every atom that is both persistable (persistence
5103 type not set to 'none') and whose value is available (not in an
5104 error or loading state).
5105
5106 previousAtomValues: The value of every persistable and available atom before
5107 the transaction began.
5108
5109 atomInfo: A map containing the persistence settings for each atom. Every key
5110 that exists in atomValues will also exist in atomInfo.
5111
5112 modifiedAtoms: The set of atoms that were written to during the transaction.
5113
5114 transactionMetadata: Arbitrary information that was added via the
5115 useSetUnvalidatedAtomValues hook. Useful for ignoring the useSetUnvalidatedAtomValues
5116 transaction, to avoid loops.
5117*/
5118function useTransactionObservation_DEPRECATED(callback) {
5119 useTransactionSubscription(useCallback$2(store => {
5120 let previousTree = store.getState().previousTree;
5121 const currentTree = store.getState().currentTree;
5122
5123 if (!previousTree) {
5124 Recoil_recoverableViolation('Transaction subscribers notified without a previous tree being present -- this is a bug in Recoil');
5125 previousTree = store.getState().currentTree; // attempt to trundle on
5126 }
5127
5128 const atomValues = externallyVisibleAtomValuesInState(currentTree);
5129 const previousAtomValues = externallyVisibleAtomValuesInState(previousTree);
5130 const atomInfo = Recoil_mapMap(nodes$1, node => {
5131 var _node$persistence_UNS, _node$persistence_UNS2, _node$persistence_UNS3, _node$persistence_UNS4;
5132
5133 return {
5134 persistence_UNSTABLE: {
5135 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',
5136 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
5137 }
5138 };
5139 }); // Filter on existance in atomValues so that externally-visible rules
5140 // are also applied to modified atoms (specifically exclude selectors):
5141
5142 const modifiedAtoms = Recoil_filterSet(currentTree.dirtyAtoms, k => atomValues.has(k) || previousAtomValues.has(k));
5143 callback({
5144 atomValues,
5145 previousAtomValues,
5146 atomInfo,
5147 modifiedAtoms,
5148 transactionMetadata: { ...currentTree.transactionMetadata
5149 }
5150 });
5151 }, [callback]));
5152}
5153
5154function useRecoilTransactionObserver(callback) {
5155 useTransactionSubscription(useCallback$2(store => {
5156 const snapshot = cloneSnapshot$1(store, 'current');
5157 const previousSnapshot = cloneSnapshot$1(store, 'previous');
5158 callback({
5159 snapshot,
5160 previousSnapshot
5161 });
5162 }, [callback]));
5163} // Return a snapshot of the current state and subscribe to all state changes
5164
5165
5166function useRecoilSnapshot() {
5167 const storeRef = useStoreRef$3();
5168 const [snapshot, setSnapshot] = useState$2(() => cloneSnapshot$1(storeRef.current));
5169 const previousSnapshot = Recoil_usePrevious(snapshot);
5170 const timeoutID = useRef$5();
5171 useEffect$4(() => {
5172 if (timeoutID.current && !isSSR$3) {
5173 window.clearTimeout(timeoutID.current);
5174 }
5175
5176 return snapshot.retain();
5177 }, [snapshot]);
5178 useTransactionSubscription(useCallback$2(store => setSnapshot(cloneSnapshot$1(store)), []));
5179
5180 if (previousSnapshot !== snapshot && !isSSR$3) {
5181 if (timeoutID.current) {
5182 previousSnapshot === null || previousSnapshot === void 0 ? void 0 : previousSnapshot.release_INTERNAL();
5183 window.clearTimeout(timeoutID.current);
5184 }
5185
5186 snapshot.retain();
5187 timeoutID.current = window.setTimeout(() => {
5188 snapshot.release_INTERNAL();
5189 timeoutID.current = null;
5190 }, SUSPENSE_TIMEOUT_MS$2);
5191 }
5192
5193 return snapshot;
5194}
5195
5196function useGotoRecoilSnapshot() {
5197 const storeRef = useStoreRef$3();
5198 return useCallback$2(snapshot => {
5199 var _storeState$nextTree;
5200
5201 const storeState = storeRef.current.getState();
5202 const prev = (_storeState$nextTree = storeState.nextTree) !== null && _storeState$nextTree !== void 0 ? _storeState$nextTree : storeState.currentTree;
5203 const next = snapshot.getStore_INTERNAL().getState().currentTree;
5204 batchUpdates$3(() => {
5205 const keysToUpdate = new Set();
5206
5207 for (const keys of [prev.atomValues.keys(), next.atomValues.keys()]) {
5208 for (const key of keys) {
5209 var _prev$atomValues$get, _next$atomValues$get;
5210
5211 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) {
5212 keysToUpdate.add(key);
5213 }
5214 }
5215 }
5216
5217 keysToUpdate.forEach(key => {
5218 setRecoilValueLoadable$1(storeRef.current, new AbstractRecoilValue$4(key), next.atomValues.has(key) ? Recoil_nullthrows(next.atomValues.get(key)) : DEFAULT_VALUE$3);
5219 });
5220 storeRef.current.replaceState(state => {
5221 return { ...state,
5222 stateID: snapshot.getID_INTERNAL()
5223 };
5224 });
5225 });
5226 }, [storeRef]);
5227}
5228
5229var Recoil_SnapshotHooks = {
5230 useRecoilSnapshot,
5231 useGotoRecoilSnapshot,
5232 useRecoilTransactionObserver,
5233 useTransactionObservation_DEPRECATED,
5234 useTransactionSubscription_DEPRECATED: useTransactionSubscription
5235};
5236
5237const {
5238 peekNodeInfo: peekNodeInfo$2
5239} = Recoil_FunctionalCore;
5240
5241const {
5242 useStoreRef: useStoreRef$4
5243} = Recoil_RecoilRoot_react;
5244
5245function useGetRecoilValueInfo() {
5246 const storeRef = useStoreRef$4();
5247 return ({
5248 key
5249 }) => peekNodeInfo$2(storeRef.current, storeRef.current.getState().currentTree, key);
5250}
5251
5252var Recoil_useGetRecoilValueInfo = useGetRecoilValueInfo;
5253
5254const {
5255 RecoilRoot: RecoilRoot$1,
5256 useStoreRef: useStoreRef$5
5257} = Recoil_RecoilRoot_react;
5258
5259
5260
5261const {
5262 useMemo: useMemo$2
5263} = react;
5264
5265function useRecoilBridgeAcrossReactRoots() {
5266 const store = useStoreRef$5().current;
5267 return useMemo$2(() => {
5268 // eslint-disable-next-line no-shadow
5269 function RecoilBridge({
5270 children
5271 }) {
5272 return /*#__PURE__*/react.createElement(RecoilRoot$1, {
5273 store_INTERNAL: store
5274 }, children);
5275 }
5276
5277 return RecoilBridge;
5278 }, [store]);
5279}
5280
5281var Recoil_useRecoilBridgeAcrossReactRoots = useRecoilBridgeAcrossReactRoots;
5282
5283const {
5284 loadableWithValue: loadableWithValue$1
5285} = Recoil_Loadable$1;
5286
5287const {
5288 DEFAULT_VALUE: DEFAULT_VALUE$4,
5289 getNode: getNode$4
5290} = Recoil_Node;
5291
5292const {
5293 copyTreeState: copyTreeState$1,
5294 getRecoilValueAsLoadable: getRecoilValueAsLoadable$3,
5295 invalidateDownstreams: invalidateDownstreams$1,
5296 writeLoadableToTreeState: writeLoadableToTreeState$1
5297} = Recoil_RecoilValueInterface;
5298
5299
5300
5301function isAtom(recoilValue) {
5302 return getNode$4(recoilValue.key).nodeType === 'atom';
5303}
5304
5305class TransactionInterfaceImpl {
5306 constructor(store, treeState) {
5307 _defineProperty(this, "_store", void 0);
5308
5309 _defineProperty(this, "_treeState", void 0);
5310
5311 _defineProperty(this, "_changes", void 0);
5312
5313 _defineProperty(this, "get", recoilValue => {
5314 if (this._changes.has(recoilValue.key)) {
5315 // $FlowFixMe[incompatible-return]
5316 return this._changes.get(recoilValue.key);
5317 }
5318
5319 if (!isAtom(recoilValue)) {
5320 throw Recoil_err('Reading selectors within atomicUpdate is not supported');
5321 }
5322
5323 const loadable = getRecoilValueAsLoadable$3(this._store, recoilValue, this._treeState);
5324
5325 if (loadable.state === 'hasValue') {
5326 return loadable.contents;
5327 } else if (loadable.state === 'hasError') {
5328 throw loadable.contents;
5329 } else {
5330 throw Recoil_err(`Expected Recoil atom ${recoilValue.key} to have a value, but it is in a loading state.`);
5331 }
5332 });
5333
5334 _defineProperty(this, "set", (recoilState, valueOrUpdater) => {
5335 if (!isAtom(recoilState)) {
5336 throw Recoil_err('Setting selectors within atomicUpdate is not supported');
5337 }
5338
5339 if (typeof valueOrUpdater === 'function') {
5340 const current = this.get(recoilState);
5341
5342 this._changes.set(recoilState.key, valueOrUpdater(current)); // flowlint-line unclear-type:off
5343
5344 } else {
5345 this._changes.set(recoilState.key, valueOrUpdater);
5346 }
5347 });
5348
5349 _defineProperty(this, "reset", recoilState => {
5350 this.set(recoilState, DEFAULT_VALUE$4);
5351 });
5352
5353 this._store = store;
5354 this._treeState = treeState;
5355 this._changes = new Map();
5356 } // Allow destructing
5357 // eslint-disable-next-line fb-www/extra-arrow-initializer
5358
5359
5360 newTreeState_INTERNAL() {
5361 if (this._changes.size === 0) {
5362 return this._treeState;
5363 }
5364
5365 const newState = copyTreeState$1(this._treeState);
5366
5367 for (const [k, v] of this._changes) {
5368 writeLoadableToTreeState$1(newState, k, loadableWithValue$1(v));
5369 }
5370
5371 invalidateDownstreams$1(this._store, newState);
5372 return newState;
5373 }
5374
5375}
5376
5377function atomicUpdater(store) {
5378 return fn => {
5379 store.replaceState(treeState => {
5380 const changeset = new TransactionInterfaceImpl(store, treeState);
5381 fn(changeset);
5382 return changeset.newTreeState_INTERNAL();
5383 });
5384 };
5385}
5386
5387var Recoil_AtomicUpdates = {
5388 atomicUpdater
5389};
5390
5391var Recoil_AtomicUpdates_1 = Recoil_AtomicUpdates.atomicUpdater;
5392
5393var Recoil_AtomicUpdates$1 = /*#__PURE__*/Object.freeze({
5394 __proto__: null,
5395 atomicUpdater: Recoil_AtomicUpdates_1
5396});
5397
5398/**
5399 * Copyright (c) Facebook, Inc. and its affiliates.
5400 *
5401 * This source code is licensed under the MIT license found in the
5402 * LICENSE file in the root directory of this source tree.
5403 *
5404 * @emails oncall+recoil
5405 *
5406 * @format
5407 */
5408
5409function invariant(condition, message) {
5410 if (!condition) {
5411 throw new Error(message);
5412 }
5413}
5414
5415var invariant_1 = invariant;
5416
5417// @oss-only
5418
5419
5420var Recoil_invariant = invariant_1;
5421
5422const {
5423 atomicUpdater: atomicUpdater$1
5424} = Recoil_AtomicUpdates$1;
5425
5426const {
5427 batchUpdates: batchUpdates$4
5428} = Recoil_Batching;
5429
5430const {
5431 DEFAULT_VALUE: DEFAULT_VALUE$5
5432} = Recoil_Node;
5433
5434const {
5435 useStoreRef: useStoreRef$6
5436} = Recoil_RecoilRoot_react;
5437
5438const {
5439 setRecoilValue: setRecoilValue$3
5440} = Recoil_RecoilValueInterface;
5441
5442const {
5443 Snapshot: Snapshot$2,
5444 cloneSnapshot: cloneSnapshot$2
5445} = Recoil_Snapshot$1;
5446
5447
5448
5449
5450
5451const {
5452 useGotoRecoilSnapshot: useGotoRecoilSnapshot$1
5453} = Recoil_SnapshotHooks;
5454
5455const {
5456 useCallback: useCallback$3
5457} = react;
5458
5459class Sentinel {}
5460
5461const SENTINEL = new Sentinel();
5462
5463function useRecoilCallback(fn, deps) {
5464 const storeRef = useStoreRef$6();
5465 const gotoSnapshot = useGotoRecoilSnapshot$1();
5466 return useCallback$3((...args) => {
5467 function set(recoilState, newValueOrUpdater) {
5468 setRecoilValue$3(storeRef.current, recoilState, newValueOrUpdater);
5469 }
5470
5471 function reset(recoilState) {
5472 setRecoilValue$3(storeRef.current, recoilState, DEFAULT_VALUE$5);
5473 } // Use currentTree for the snapshot to show the currently committed state
5474
5475
5476 const snapshot = cloneSnapshot$2(storeRef.current); // FIXME massive gains from doing this lazily
5477
5478 const atomicUpdate = atomicUpdater$1(storeRef.current);
5479 let ret = SENTINEL;
5480 batchUpdates$4(() => {
5481 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.';
5482
5483 if (typeof fn !== 'function') {
5484 throw Recoil_err(errMsg);
5485 } // flowlint-next-line unclear-type:off
5486
5487
5488 const cb = fn({
5489 set,
5490 reset,
5491 snapshot,
5492 gotoSnapshot,
5493 transact_UNSTABLE: atomicUpdate
5494 });
5495
5496 if (typeof cb !== 'function') {
5497 throw Recoil_err(errMsg);
5498 }
5499
5500 ret = cb(...args);
5501 });
5502 !!(ret instanceof Sentinel) ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'batchUpdates should return immediately') : Recoil_invariant(false) : void 0;
5503 return ret;
5504 }, deps != null ? [...deps, storeRef] : undefined // eslint-disable-line fb-www/react-hooks-deps
5505 );
5506}
5507
5508var Recoil_useRecoilCallback = useRecoilCallback;
5509
5510const {
5511 getNode: getNode$5
5512} = Recoil_Node;
5513
5514const {
5515 useStoreRef: useStoreRef$7
5516} = Recoil_RecoilRoot_react;
5517
5518const {
5519 useCallback: useCallback$4
5520} = react;
5521
5522function useRecoilRefresher(recoilValue) {
5523 const storeRef = useStoreRef$7();
5524 return useCallback$4(() => {
5525 var _node$clearCache;
5526
5527 const store = storeRef.current;
5528 const {
5529 currentTree
5530 } = store.getState();
5531 const node = getNode$5(recoilValue.key);
5532 (_node$clearCache = node.clearCache) === null || _node$clearCache === void 0 ? void 0 : _node$clearCache.call(node, store, currentTree);
5533 }, [recoilValue, storeRef]);
5534}
5535
5536var Recoil_useRecoilRefresher = useRecoilRefresher;
5537
5538const {
5539 atomicUpdater: atomicUpdater$2
5540} = Recoil_AtomicUpdates$1;
5541
5542const {
5543 useStoreRef: useStoreRef$8
5544} = Recoil_RecoilRoot_react;
5545
5546const {
5547 useMemo: useMemo$3
5548} = react;
5549
5550function useRecoilTransaction(fn, deps) {
5551 const storeRef = useStoreRef$8();
5552 return useMemo$3(() => (...args) => {
5553 const atomicUpdate = atomicUpdater$2(storeRef.current);
5554 atomicUpdate(transactionInterface => {
5555 fn(transactionInterface)(...args);
5556 });
5557 }, deps != null ? [...deps, storeRef] : undefined // eslint-disable-line fb-www/react-hooks-deps
5558 );
5559}
5560
5561var Recoil_useRecoilTransaction = useRecoilTransaction;
5562
5563/**
5564 * Copyright (c) Facebook, Inc. and its affiliates.
5565 *
5566 * This source code is licensed under the MIT license found in the
5567 * LICENSE file in the root directory of this source tree.
5568 *
5569 * @emails oncall+recoil
5570 *
5571 * @format
5572 */
5573
5574function isNode(object) {
5575 var _ownerDocument, _doc$defaultView;
5576
5577 if (typeof window === 'undefined') {
5578 return false;
5579 }
5580
5581 const doc = object != null ? (_ownerDocument = object.ownerDocument) !== null && _ownerDocument !== void 0 ? _ownerDocument : object : document;
5582 const defaultView = (_doc$defaultView = doc.defaultView) !== null && _doc$defaultView !== void 0 ? _doc$defaultView : window;
5583 return !!(object != null && (typeof defaultView.Node === 'function' ? object instanceof defaultView.Node : typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string'));
5584}
5585
5586var Recoil_isNode = isNode;
5587
5588const {
5589 isReactNative: isReactNative$1,
5590 isSSR: isSSR$4
5591} = Recoil_Environment;
5592
5593
5594
5595
5596
5597function shouldNotBeFrozen(value) {
5598 // Primitives and functions:
5599 if (value === null || typeof value !== 'object') {
5600 return true;
5601 } // React elements:
5602
5603
5604 switch (typeof value.$$typeof) {
5605 case 'symbol':
5606 return true;
5607
5608 case 'number':
5609 return true;
5610 } // Immutable structures:
5611
5612
5613 if (value['@@__IMMUTABLE_ITERABLE__@@'] != null || value['@@__IMMUTABLE_KEYED__@@'] != null || value['@@__IMMUTABLE_INDEXED__@@'] != null || value['@@__IMMUTABLE_ORDERED__@@'] != null || value['@@__IMMUTABLE_RECORD__@@'] != null) {
5614 return true;
5615 } // DOM nodes:
5616
5617
5618 if (Recoil_isNode(value)) {
5619 return true;
5620 }
5621
5622 if (Recoil_isPromise(value)) {
5623 return true;
5624 }
5625
5626 if (value instanceof Error) {
5627 return true;
5628 }
5629
5630 if (ArrayBuffer.isView(value)) {
5631 return true;
5632 } // Some environments, just as Jest, don't work with the instanceof check
5633
5634
5635 if (!isSSR$4 && !isReactNative$1 && ( // $FlowFixMe(site=recoil) Window does not have a FlowType definition https://github.com/facebook/flow/issues/6709
5636 value === window || value instanceof Window)) {
5637 return true;
5638 }
5639
5640 return false;
5641} // Recursively freeze a value to enforce it is read-only.
5642// This may also have minimal performance improvements for enumerating
5643// objects (based on browser implementations, of course)
5644
5645
5646function deepFreezeValue(value) {
5647 if (typeof value !== 'object' || shouldNotBeFrozen(value)) {
5648 return;
5649 }
5650
5651 Object.freeze(value); // Make all properties read-only
5652
5653 for (const key in value) {
5654 // $FlowFixMe[method-unbinding] added when improving typing for this parameters
5655 if (Object.prototype.hasOwnProperty.call(value, key)) {
5656 const prop = value[key]; // Prevent infinite recurssion for circular references.
5657
5658 if (typeof prop === 'object' && prop != null && !Object.isFrozen(prop)) {
5659 deepFreezeValue(prop);
5660 }
5661 }
5662 }
5663
5664 Object.seal(value); // This also makes existing properties non-configurable.
5665}
5666
5667var Recoil_deepFreezeValue = deepFreezeValue;
5668
5669const TIME_WARNING_THRESHOLD_MS = 15;
5670
5671function stringify(x, opt, key) {
5672 // A optimization to avoid the more expensive JSON.stringify() for simple strings
5673 // This may lose protection for u2028 and u2029, though.
5674 if (typeof x === 'string' && !x.includes('"') && !x.includes('\\')) {
5675 return `"${x}"`;
5676 } // Handle primitive types
5677
5678
5679 switch (typeof x) {
5680 case 'undefined':
5681 return '';
5682 // JSON.stringify(undefined) returns undefined, but we always want to return a string
5683
5684 case 'boolean':
5685 return x ? 'true' : 'false';
5686
5687 case 'number':
5688 case 'symbol':
5689 // case 'bigint': // BigInt is not supported in www
5690 return String(x);
5691
5692 case 'string':
5693 // Add surrounding quotes and escape internal quotes
5694 return JSON.stringify(x);
5695
5696 case 'function':
5697 if ((opt === null || opt === void 0 ? void 0 : opt.allowFunctions) !== true) {
5698 throw Recoil_err('Attempt to serialize function in a Recoil cache key');
5699 }
5700
5701 return `__FUNCTION(${x.name})__`;
5702 }
5703
5704 if (x === null) {
5705 return 'null';
5706 } // Fallback case for unknown types
5707
5708
5709 if (typeof x !== 'object') {
5710 var _JSON$stringify;
5711
5712 return (_JSON$stringify = JSON.stringify(x)) !== null && _JSON$stringify !== void 0 ? _JSON$stringify : '';
5713 } // Deal with all promises as equivalent for now.
5714
5715
5716 if (Recoil_isPromise(x)) {
5717 return '__PROMISE__';
5718 } // Arrays handle recursive stringification
5719
5720
5721 if (Array.isArray(x)) {
5722 return `[${x.map((v, i) => stringify(v, opt, i.toString()))}]`;
5723 } // If an object defines a toJSON() method, then use that to override the
5724 // serialization. This matches the behavior of JSON.stringify().
5725 // Pass the key for compatibility.
5726 // Immutable.js collections define this method to allow us to serialize them.
5727
5728
5729 if (typeof x.toJSON === 'function') {
5730 // flowlint-next-line unclear-type: off
5731 return stringify(x.toJSON(key), opt, key);
5732 } // For built-in Maps, sort the keys in a stable order instead of the
5733 // default insertion order. Support non-string keys.
5734
5735
5736 if (x instanceof Map) {
5737 const obj = {};
5738
5739 for (const [k, v] of x) {
5740 // Stringify will escape any nested quotes
5741 obj[typeof k === 'string' ? k : stringify(k, opt)] = v;
5742 }
5743
5744 return stringify(obj, opt, key);
5745 } // For built-in Sets, sort the keys in a stable order instead of the
5746 // default insertion order.
5747
5748
5749 if (x instanceof Set) {
5750 return stringify(Array.from(x).sort((a, b) => stringify(a, opt).localeCompare(stringify(b, opt))), opt, key);
5751 } // Anything else that is iterable serialize as an Array.
5752
5753
5754 if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === 'function') {
5755 // flowlint-next-line unclear-type: off
5756 return stringify(Array.from(x), opt, key);
5757 } // For all other Objects, sort the keys in a stable order.
5758
5759
5760 return `{${Object.keys(x).filter(k => x[k] !== undefined).sort() // stringify the key to add quotes and escape any nested slashes or quotes.
5761 .map(k => `${stringify(k, opt)}:${stringify(x[k], opt, k)}`).join(',')}}`;
5762} // Utility similar to JSON.stringify() except:
5763// * Serialize built-in Sets as an Array
5764// * Serialize built-in Maps as an Object. Supports non-string keys.
5765// * Serialize other iterables as arrays
5766// * Sort the keys of Objects and Maps to have a stable order based on string conversion.
5767// This overrides their default insertion order.
5768// * Still uses toJSON() of any object to override serialization
5769// * Support Symbols (though don't guarantee uniqueness)
5770// * We could support BigInt, but Flow doesn't seem to like it.
5771// See Recoil_stableStringify-test.js for examples
5772
5773
5774function stableStringify(x, opt = {
5775 allowFunctions: false
5776}) {
5777 if (process.env.NODE_ENV !== "production") {
5778 if (typeof window !== 'undefined') {
5779 const startTime = window.performance ? window.performance.now() : 0;
5780 const str = stringify(x, opt);
5781 const endTime = window.performance ? window.performance.now() : 0;
5782
5783 if (endTime - startTime > TIME_WARNING_THRESHOLD_MS) {
5784 /* eslint-disable fb-www/no-console */
5785 console.groupCollapsed(`Recoil: Spent ${endTime - startTime}ms computing a cache key`);
5786 console.warn(x, str);
5787 console.groupEnd();
5788 /* eslint-enable fb-www/no-console */
5789 }
5790
5791 return str;
5792 }
5793 }
5794
5795 return stringify(x, opt);
5796}
5797
5798var Recoil_stableStringify = stableStringify;
5799
5800class TreeCache {
5801 constructor(options) {
5802 var _options$onHit, _options$onSet, _options$mapNodeValue;
5803
5804 _defineProperty(this, "_numLeafs", void 0);
5805
5806 _defineProperty(this, "_root", void 0);
5807
5808 _defineProperty(this, "_onHit", void 0);
5809
5810 _defineProperty(this, "_onSet", void 0);
5811
5812 _defineProperty(this, "_mapNodeValue", void 0);
5813
5814 this._numLeafs = 0;
5815 this._root = null;
5816 this._onHit = (_options$onHit = options === null || options === void 0 ? void 0 : options.onHit) !== null && _options$onHit !== void 0 ? _options$onHit : () => {};
5817 this._onSet = (_options$onSet = options === null || options === void 0 ? void 0 : options.onSet) !== null && _options$onSet !== void 0 ? _options$onSet : () => {};
5818 this._mapNodeValue = (_options$mapNodeValue = options === null || options === void 0 ? void 0 : options.mapNodeValue) !== null && _options$mapNodeValue !== void 0 ? _options$mapNodeValue : val => val;
5819 }
5820
5821 size() {
5822 return this._numLeafs;
5823 } // TODO: nodeCount(): number
5824
5825
5826 root() {
5827 return this._root;
5828 }
5829
5830 get(getNodeValue, handlers) {
5831 var _this$getLeafNode;
5832
5833 return (_this$getLeafNode = this.getLeafNode(getNodeValue, handlers)) === null || _this$getLeafNode === void 0 ? void 0 : _this$getLeafNode.value;
5834 }
5835
5836 getLeafNode(getNodeValue, handlers) {
5837 return findLeaf(this.root(), nodeKey => this._mapNodeValue(getNodeValue(nodeKey)), {
5838 onNodeVisit: node => {
5839 handlers === null || handlers === void 0 ? void 0 : handlers.onNodeVisit(node);
5840
5841 if (node.type === 'leaf') {
5842 this._onHit(node);
5843 }
5844 }
5845 });
5846 }
5847
5848 set(route, value, handlers) {
5849 let leafNode;
5850 let newRoot = null;
5851
5852 const setRetryablePart = () => {
5853 newRoot = addLeaf(this.root(), route.map(([nodeKey, nodeValue]) => [nodeKey, this._mapNodeValue(nodeValue)]), null, value, null, {
5854 onNodeVisit: node => {
5855 handlers === null || handlers === void 0 ? void 0 : handlers.onNodeVisit(node);
5856
5857 if (node.type === 'leaf') {
5858 leafNode = node;
5859 }
5860 }
5861 }, () => {
5862 this.clear();
5863 setRetryablePart();
5864 });
5865 };
5866
5867 setRetryablePart();
5868
5869 if (!this.root()) {
5870 this._root = newRoot;
5871 }
5872
5873 this._numLeafs++;
5874
5875 this._onSet(Recoil_nullthrows(leafNode));
5876 }
5877
5878 delete(node) {
5879 if (!this.root()) {
5880 return false;
5881 }
5882
5883 const root = Recoil_nullthrows(this.root());
5884 const existsInTree = pruneNodeFromTree(root, node, node.parent);
5885
5886 if (!existsInTree) {
5887 return false;
5888 }
5889
5890 if (node === root || root.type === 'branch' && !root.branches.size) {
5891 this._root = null;
5892 this._numLeafs = 0;
5893 return true;
5894 }
5895
5896 this._numLeafs -= countDownstreamLeaves(node);
5897 return true;
5898 }
5899
5900 clear() {
5901 this._numLeafs = 0;
5902 this._root = null;
5903 }
5904
5905}
5906
5907const findLeaf = (root, getNodeValue, handlers) => {
5908 var _handlers$onNodeVisit;
5909
5910 if (root == null) {
5911 return undefined;
5912 }
5913
5914 handlers === null || handlers === void 0 ? void 0 : (_handlers$onNodeVisit = handlers.onNodeVisit) === null || _handlers$onNodeVisit === void 0 ? void 0 : _handlers$onNodeVisit.call(handlers, root);
5915
5916 if (root.type === 'leaf') {
5917 return root;
5918 }
5919
5920 const nodeValue = getNodeValue(root.nodeKey);
5921 return findLeaf(root.branches.get(nodeValue), getNodeValue, handlers);
5922};
5923
5924const addLeaf = (root, route, parent, value, branchKey, handlers, onAbort) => {
5925 var _handlers$onNodeVisit2;
5926
5927 let node;
5928
5929 if (root == null) {
5930 if (route.length === 0) {
5931 node = {
5932 type: 'leaf',
5933 value,
5934 parent,
5935 branchKey
5936 };
5937 } else {
5938 const [path, ...rest] = route;
5939 const [nodeKey, nodeValue] = path;
5940 node = {
5941 type: 'branch',
5942 nodeKey,
5943 parent,
5944 branches: new Map(),
5945 branchKey
5946 };
5947 node.branches.set(nodeValue, addLeaf(null, rest, node, value, nodeValue, handlers, onAbort));
5948 }
5949 } else {
5950 node = root;
5951
5952 if (route.length) {
5953 const [path, ...rest] = route;
5954 const [nodeKey, nodeValue] = path;
5955
5956 if (root.type !== 'branch' || root.nodeKey !== nodeKey) {
5957 Recoil_recoverableViolation('Existing cache must have a branch midway through the ' + 'route with matching node key. Resetting cache.');
5958 onAbort();
5959 return node; // ignored
5960 }
5961
5962 root.branches.set(nodeValue, addLeaf(root.branches.get(nodeValue), rest, root, value, nodeValue, handlers, onAbort));
5963 }
5964 }
5965
5966 handlers === null || handlers === void 0 ? void 0 : (_handlers$onNodeVisit2 = handlers.onNodeVisit) === null || _handlers$onNodeVisit2 === void 0 ? void 0 : _handlers$onNodeVisit2.call(handlers, node);
5967 return node;
5968};
5969
5970const pruneNodeFromTree = (root, node, parent) => {
5971 if (!parent) {
5972 return root === node;
5973 }
5974
5975 parent.branches.delete(node.branchKey);
5976 return pruneUpstreamBranches(root, parent, parent.parent);
5977};
5978
5979const pruneUpstreamBranches = (root, branchNode, parent) => {
5980 if (!parent) {
5981 return root === branchNode;
5982 }
5983
5984 if (branchNode.branches.size === 0) {
5985 parent.branches.delete(branchNode.branchKey);
5986 }
5987
5988 return pruneUpstreamBranches(root, parent, parent.parent);
5989};
5990
5991const countDownstreamLeaves = node => node.type === 'leaf' ? 1 : Array.from(node.branches.values()).reduce((sum, currNode) => sum + countDownstreamLeaves(currNode), 0);
5992
5993var Recoil_TreeCache = {
5994 TreeCache
5995};
5996
5997var Recoil_TreeCache_1 = Recoil_TreeCache.TreeCache;
5998
5999var Recoil_TreeCache$1 = /*#__PURE__*/Object.freeze({
6000 __proto__: null,
6001 TreeCache: Recoil_TreeCache_1
6002});
6003
6004class LRUCache {
6005 constructor(options) {
6006 var _options$mapKey;
6007
6008 _defineProperty(this, "_maxSize", void 0);
6009
6010 _defineProperty(this, "_size", void 0);
6011
6012 _defineProperty(this, "_head", void 0);
6013
6014 _defineProperty(this, "_tail", void 0);
6015
6016 _defineProperty(this, "_map", void 0);
6017
6018 _defineProperty(this, "_keyMapper", void 0);
6019
6020 this._maxSize = options.maxSize;
6021 this._size = 0;
6022 this._head = null;
6023 this._tail = null;
6024 this._map = new Map();
6025 this._keyMapper = (_options$mapKey = options.mapKey) !== null && _options$mapKey !== void 0 ? _options$mapKey : v => v;
6026 }
6027
6028 head() {
6029 return this._head;
6030 }
6031
6032 tail() {
6033 return this._tail;
6034 }
6035
6036 size() {
6037 return this._size;
6038 }
6039
6040 maxSize() {
6041 return this._maxSize;
6042 }
6043
6044 has(key) {
6045 return this._map.has(this._keyMapper(key));
6046 }
6047
6048 get(key) {
6049 const mappedKey = this._keyMapper(key);
6050
6051 const node = this._map.get(mappedKey);
6052
6053 if (!node) {
6054 return undefined;
6055 }
6056
6057 this.set(key, node.value);
6058 return node.value;
6059 }
6060
6061 set(key, val) {
6062 const mappedKey = this._keyMapper(key);
6063
6064 const existingNode = this._map.get(mappedKey);
6065
6066 if (existingNode) {
6067 this.delete(key);
6068 }
6069
6070 const head = this.head();
6071 const node = {
6072 key,
6073 right: head,
6074 left: null,
6075 value: val
6076 };
6077
6078 if (head) {
6079 head.left = node;
6080 } else {
6081 this._tail = node;
6082 }
6083
6084 this._map.set(mappedKey, node);
6085
6086 this._head = node;
6087 this._size++;
6088
6089 this._maybeDeleteLRU();
6090 }
6091
6092 _maybeDeleteLRU() {
6093 if (this.size() > this.maxSize()) {
6094 this.deleteLru();
6095 }
6096 }
6097
6098 deleteLru() {
6099 const tail = this.tail();
6100
6101 if (tail) {
6102 this.delete(tail.key);
6103 }
6104 }
6105
6106 delete(key) {
6107 const mappedKey = this._keyMapper(key);
6108
6109 if (!this._size || !this._map.has(mappedKey)) {
6110 return;
6111 }
6112
6113 const node = Recoil_nullthrows(this._map.get(mappedKey));
6114 const right = node.right;
6115 const left = node.left;
6116
6117 if (right) {
6118 right.left = node.left;
6119 }
6120
6121 if (left) {
6122 left.right = node.right;
6123 }
6124
6125 if (node === this.head()) {
6126 this._head = right;
6127 }
6128
6129 if (node === this.tail()) {
6130 this._tail = left;
6131 }
6132
6133 this._map.delete(mappedKey);
6134
6135 this._size--;
6136 }
6137
6138 clear() {
6139 this._size = 0;
6140 this._head = null;
6141 this._tail = null;
6142 this._map = new Map();
6143 }
6144
6145}
6146
6147var Recoil_LRUCache = {
6148 LRUCache
6149};
6150
6151var Recoil_LRUCache_1 = Recoil_LRUCache.LRUCache;
6152
6153var Recoil_LRUCache$1 = /*#__PURE__*/Object.freeze({
6154 __proto__: null,
6155 LRUCache: Recoil_LRUCache_1
6156});
6157
6158const {
6159 LRUCache: LRUCache$1
6160} = Recoil_LRUCache$1;
6161
6162const {
6163 TreeCache: TreeCache$1
6164} = Recoil_TreeCache$1;
6165
6166function treeCacheLRU(maxSize, mapNodeValue = v => v) {
6167 const lruCache = new LRUCache$1({
6168 maxSize
6169 });
6170 const cache = new TreeCache$1({
6171 mapNodeValue,
6172 onHit: node => {
6173 lruCache.set(node, true);
6174 },
6175 onSet: node => {
6176 const lruNode = lruCache.tail();
6177 lruCache.set(node, true);
6178
6179 if (lruNode && cache.size() > maxSize) {
6180 cache.delete(lruNode.key);
6181 }
6182 }
6183 }); // $FlowFixMe[method-unbinding]
6184
6185 return cache;
6186}
6187
6188var Recoil_treeCacheLRU = treeCacheLRU;
6189
6190const {
6191 TreeCache: TreeCache$2
6192} = Recoil_TreeCache$1;
6193
6194
6195
6196const defaultPolicy = {
6197 equality: 'reference',
6198 eviction: 'keep-all',
6199 maxSize: Infinity
6200};
6201
6202function treeCacheFromPolicy({
6203 equality = defaultPolicy.equality,
6204 eviction = defaultPolicy.eviction,
6205 maxSize = defaultPolicy.maxSize
6206} = defaultPolicy) {
6207 const valueMapper = getValueMapper(equality);
6208 const treeCache = getTreeCache(eviction, maxSize, valueMapper);
6209 return treeCache;
6210}
6211
6212function getValueMapper(equality) {
6213 switch (equality) {
6214 case 'reference':
6215 return val => val;
6216
6217 case 'value':
6218 return val => Recoil_stableStringify(val);
6219 }
6220
6221 throw Recoil_err(`Unrecognized equality policy ${equality}`);
6222}
6223
6224function getTreeCache(eviction, maxSize, mapNodeValue) {
6225 switch (eviction) {
6226 case 'keep-all':
6227 // $FlowFixMe[method-unbinding]
6228 return new TreeCache$2({
6229 mapNodeValue
6230 });
6231
6232 case 'lru':
6233 return Recoil_treeCacheLRU(Recoil_nullthrows(maxSize), mapNodeValue);
6234
6235 case 'most-recent':
6236 return Recoil_treeCacheLRU(1, mapNodeValue);
6237 }
6238
6239 throw Recoil_err(`Unrecognized eviction policy ${eviction}`);
6240}
6241
6242var Recoil_treeCacheFromPolicy = treeCacheFromPolicy;
6243
6244/**
6245 * Copyright (c) Facebook, Inc. and its affiliates.
6246 *
6247 * This source code is licensed under the MIT license found in the
6248 * LICENSE file in the root directory of this source tree.
6249 *
6250 * @emails oncall+recoil
6251 *
6252 * @format
6253 *
6254 * This is a stub for some integration into FB internal stuff
6255 */
6256function startPerfBlock(_id) {
6257 return () => null;
6258}
6259
6260var Recoil_PerformanceTimings = {
6261 startPerfBlock
6262};
6263
6264const {
6265 loadableWithError: loadableWithError$1,
6266 loadableWithPromise: loadableWithPromise$1,
6267 loadableWithValue: loadableWithValue$2
6268} = Recoil_Loadable$1;
6269
6270
6271
6272const {
6273 getNodeLoadable: getNodeLoadable$2,
6274 peekNodeLoadable: peekNodeLoadable$1,
6275 setNodeValue: setNodeValue$3
6276} = Recoil_FunctionalCore;
6277
6278const {
6279 saveDependencyMapToStore: saveDependencyMapToStore$1
6280} = Recoil_Graph;
6281
6282const {
6283 DEFAULT_VALUE: DEFAULT_VALUE$6,
6284 RecoilValueNotReady: RecoilValueNotReady$2,
6285 getConfigDeletionHandler: getConfigDeletionHandler$1,
6286 getNode: getNode$6,
6287 registerNode: registerNode$1
6288} = Recoil_Node;
6289
6290const {
6291 isRecoilValue: isRecoilValue$3
6292} = Recoil_RecoilValue$1;
6293
6294const {
6295 AbstractRecoilValue: AbstractRecoilValue$5
6296} = Recoil_RecoilValue$1;
6297
6298const {
6299 markRecoilValueModified: markRecoilValueModified$1,
6300 setRecoilValueLoadable: setRecoilValueLoadable$2
6301} = Recoil_RecoilValueInterface;
6302
6303const {
6304 retainedByOptionWithDefault: retainedByOptionWithDefault$1
6305} = Recoil_Retention;
6306
6307const {
6308 cloneSnapshot: cloneSnapshot$3
6309} = Recoil_Snapshot$1;
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323const {
6324 startPerfBlock: startPerfBlock$1
6325} = Recoil_PerformanceTimings;
6326
6327
6328
6329class Canceled {}
6330
6331const CANCELED = new Canceled();
6332/**
6333 * An ExecutionId is an arbitrary ID that lets us distinguish executions from
6334 * each other. This is necessary as we need a way of solving this problem:
6335 * "given 3 async executions, only update state for the 'latest' execution when
6336 * it finishes running regardless of when the other 2 finish". ExecutionIds
6337 * provide a convenient way of identifying executions so that we can track and
6338 * manage them over time.
6339 */
6340
6341const dependencyStack = []; // for detecting circular dependencies.
6342
6343const waitingStores = new Map();
6344/* eslint-disable no-redeclare */
6345
6346const getNewExecutionId = (() => {
6347 let executionId = 0;
6348 return () => executionId++;
6349})();
6350
6351function getInitialExecutionInfo() {
6352 return {
6353 depValuesDiscoveredSoFarDuringAsyncWork: null,
6354 latestLoadable: null,
6355 latestExecutionId: null,
6356 stateVersion: null
6357 };
6358}
6359
6360function selector(options) {
6361 let recoilValue = null;
6362 const {
6363 key,
6364 get,
6365 cachePolicy_UNSTABLE: cachePolicy
6366 } = options;
6367 const set = options.set != null ? options.set : undefined; // flow
6368
6369 if (process.env.NODE_ENV !== "production") {
6370 if (typeof key !== 'string') {
6371 throw Recoil_err('A key option with a unique string value must be provided when creating a selector.');
6372 }
6373
6374 if (typeof get !== 'function') {
6375 throw Recoil_err('Selectors must specify a get callback option to get the selector value.');
6376 }
6377 } // This is every discovered dependency across executions
6378
6379
6380 const discoveredDependencyNodeKeys = new Set();
6381 const cache = Recoil_treeCacheFromPolicy(cachePolicy !== null && cachePolicy !== void 0 ? cachePolicy : {
6382 equality: 'reference',
6383 eviction: 'keep-all'
6384 });
6385 const retainedBy = retainedByOptionWithDefault$1(options.retainedBy_UNSTABLE);
6386 const executionInfoMap = new Map();
6387 let liveStoresCount = 0;
6388
6389 function selectorIsLive() {
6390 return !Recoil_gkx_1('recoil_memory_managament_2020') || liveStoresCount > 0;
6391 }
6392
6393 function getExecutionInfo(store) {
6394 if (!executionInfoMap.has(store)) {
6395 executionInfoMap.set(store, getInitialExecutionInfo());
6396 }
6397
6398 return Recoil_nullthrows(executionInfoMap.get(store));
6399 }
6400
6401 function selectorInit(store) {
6402 liveStoresCount++;
6403 store.getState().knownSelectors.add(key); // FIXME remove knownSelectors?
6404
6405 return () => {
6406 liveStoresCount--;
6407 store.getState().knownSelectors.delete(key);
6408 executionInfoMap.delete(store);
6409 };
6410 }
6411
6412 function selectorShouldDeleteConfigOnRelease() {
6413 return getConfigDeletionHandler$1(key) !== undefined && !selectorIsLive();
6414 }
6415
6416 function notifyStoreWhenAsyncSettles(store, loadable, executionId) {
6417 if (loadable.state === 'loading') {
6418 let stores = waitingStores.get(executionId);
6419
6420 if (stores == null) {
6421 waitingStores.set(executionId, stores = new Set());
6422 }
6423
6424 stores.add(store);
6425 }
6426 }
6427
6428 function notifyStoresOfSettledAsync(newLoadable, executionId) {
6429 const stores = waitingStores.get(executionId);
6430
6431 if (stores !== undefined) {
6432 for (const store of stores) {
6433 setRecoilValueLoadable$2(store, new AbstractRecoilValue$5(key), newLoadable);
6434 }
6435
6436 waitingStores.delete(executionId);
6437 }
6438 }
6439
6440 function getCachedNodeLoadable(store, state, nodeKey) {
6441 const isKeyPointingToSelector = store.getState().knownSelectors.has(nodeKey);
6442 /**
6443 * It's important that we don't bypass calling getNodeLoadable for atoms
6444 * as getNodeLoadable has side effects in state
6445 */
6446
6447 if (isKeyPointingToSelector && state.atomValues.has(nodeKey)) {
6448 return Recoil_nullthrows(state.atomValues.get(nodeKey));
6449 }
6450
6451 const loadable = getNodeLoadable$2(store, state, nodeKey);
6452
6453 if (loadable.state !== 'loading' && isKeyPointingToSelector) {
6454 state.atomValues.set(nodeKey, loadable);
6455 }
6456
6457 return loadable;
6458 }
6459 /**
6460 * This function attaches a then() and a catch() to a promise that was
6461 * returned from a selector's get() (either explicitly or implicitly by
6462 * running a function that uses the "async" keyword). If a selector's get()
6463 * returns a promise, we have two possibilities:
6464 *
6465 * 1. The promise will resolve, in which case it will have completely finished
6466 * executing without any remaining pending dependencies. No more retries
6467 * are needed and we can proceed with updating the cache and notifying
6468 * subscribers (if it is the latest execution, otherwise only the cache
6469 * will be updated and subscriptions will not be fired). This is the case
6470 * handled by the attached then() handler.
6471 *
6472 * 2. The promise will throw because it either has an error or it came across
6473 * an async dependency that has not yet resolved, in which case we will
6474 * call wrapDepdencyPromise(), whose responsibility is to handle dependency
6475 * promises. This case is handled by the attached catch() handler.
6476 *
6477 * Both branches will eventually resolve to the final result of the selector
6478 * (or an error if a real error occurred).
6479 *
6480 * The execution will run to completion even if it is stale, and its value
6481 * will be cached. But stale executions will not update global state or update
6482 * executionInfo as that is the responsibility of the 'latest' execution.
6483 *
6484 * Note this function should not be passed a promise that was thrown--AKA a
6485 * dependency promise. Dependency promises should be passed to
6486 * wrapPendingDependencyPromise()).
6487 */
6488
6489
6490 function wrapPendingPromise(store, promise, state, depValues, executionId, loadingDepsState) {
6491 return promise.then(value => {
6492 if (!selectorIsLive()) {
6493 // The selector was released since the request began; ignore the response.
6494 clearExecutionInfo(store, executionId);
6495 throw CANCELED;
6496 }
6497
6498 const loadable = loadableWithValue$2(value);
6499 maybeFreezeValue(value);
6500 setCache(state, depValuesToDepRoute(depValues), loadable);
6501 setDepsInStore(store, state, new Set(depValues.keys()), executionId);
6502 setLoadableInStoreToNotifyDeps(store, loadable, executionId);
6503 return value;
6504 }).catch(errorOrPromise => {
6505 if (!selectorIsLive()) {
6506 // The selector was released since the request began; ignore the response.
6507 clearExecutionInfo(store, executionId);
6508 throw CANCELED;
6509 }
6510
6511 if (isLatestExecution(store, executionId)) {
6512 updateExecutionInfoDepValues(depValues, store, executionId);
6513 }
6514
6515 if (Recoil_isPromise(errorOrPromise)) {
6516 return wrapPendingDependencyPromise(store, errorOrPromise, state, depValues, executionId, loadingDepsState);
6517 }
6518
6519 const loadable = loadableWithError$1(errorOrPromise);
6520 maybeFreezeValue(errorOrPromise);
6521 setCache(state, depValuesToDepRoute(depValues), loadable);
6522 setDepsInStore(store, state, new Set(depValues.keys()), executionId);
6523 setLoadableInStoreToNotifyDeps(store, loadable, executionId);
6524 throw errorOrPromise;
6525 });
6526 }
6527 /**
6528 * This function attaches a then() and a catch() to a promise that was
6529 * thrown from a selector's get(). If a selector's get() throws a promise,
6530 * we have two possibilities:
6531 *
6532 * 1. The promise will resolve, meaning one of our selector's dependencies is
6533 * now available and we should "retry" our get() by running it again. This
6534 * is the case handled by the attached then() handler.
6535 *
6536 * 2. The promise will throw because something went wrong with the dependency
6537 * promise (in other words a real error occurred). This case is handled by
6538 * the attached catch() handler. If the dependency promise throws, it is
6539 * _always_ a real error and not another dependency promise (any dependency
6540 * promises would have been handled upstream).
6541 *
6542 * The then() branch will eventually resolve to the final result of the
6543 * selector (or an error if a real error occurs), and the catch() will always
6544 * resolve to an error because the dependency promise is a promise that was
6545 * wrapped upstream, meaning it will only resolve to its real value or to a
6546 * real error.
6547 *
6548 * The execution will run to completion even if it is stale, and its value
6549 * will be cached. But stale executions will not update global state or update
6550 * executionInfo as that is the responsibility of the 'latest' execution.
6551 *
6552 * Note this function should not be passed a promise that was returned from
6553 * get(). The intention is that this function is only passed promises that
6554 * were thrown due to a pending dependency. Promises returned by get() should
6555 * be passed to wrapPendingPromise() instead.
6556 */
6557
6558
6559 function wrapPendingDependencyPromise(store, promise, state, existingDeps, executionId, loadingDepsState) {
6560 return promise.then(resolvedDep => {
6561 if (!selectorIsLive()) {
6562 // The selector was released since the request began; ignore the response.
6563 clearExecutionInfo(store, executionId);
6564 throw CANCELED;
6565 } // Check if we are handling a pending Recoil dependency or if the user
6566 // threw their own Promise to "suspend" a selector evaluation. We need
6567 // to check that the loadingDepPromise actually matches the promise that
6568 // we caught in case the selector happened to catch the promise we threw
6569 // for a pending Recoil dependency from `getRecoilValue()` and threw
6570 // their own promise instead.
6571
6572
6573 if (loadingDepsState.loadingDepKey != null && loadingDepsState.loadingDepPromise === promise) {
6574 /**
6575 * Note for async atoms, this means we are changing the atom's value
6576 * in the store for the given version. This should be alright because
6577 * the version of state is now stale and a new version will have
6578 * already been triggered by the atom being resolved (see this logic
6579 * in Recoil_atom.js)
6580 */
6581 state.atomValues.set(loadingDepsState.loadingDepKey, loadableWithValue$2(resolvedDep));
6582 } else {
6583 /**
6584 * If resolvedDepKey is not defined, the promise was a user-thrown
6585 * promise. User-thrown promises are an advanced feature and they
6586 * should be avoided in almost all cases. Using `loadable.map()` inside
6587 * of selectors for loading loadables and then throwing that mapped
6588 * loadable's promise is an example of a user-thrown promise.
6589 *
6590 * When we hit a user-thrown promise, we have to bail out of an optimization
6591 * where we bypass calculating selector cache keys for selectors that
6592 * have been previously seen for a given state (these selectors are saved in
6593 * state.atomValues) to avoid stale state as we have no way of knowing
6594 * what state changes happened (if any) in result to the promise resolving.
6595 *
6596 * Ideally we would only bail out selectors that are in the chain of
6597 * dependencies for this selector, but there's currently no way to get
6598 * a full list of a selector's downstream nodes because the state that
6599 * is executing may be a discarded tree (so store.getGraph(state.version)
6600 * will be empty), and the full dep tree may not be in the selector
6601 * caches in the case where the selector's cache was cleared. To solve
6602 * for this we would have to keep track of all running selector
6603 * executions and their downstream deps. Because this only covers edge
6604 * cases, that complexity might not be justifyable.
6605 */
6606 store.getState().knownSelectors.forEach(nodeKey => {
6607 state.atomValues.delete(nodeKey);
6608 });
6609 }
6610 /**
6611 * Optimization: Now that the dependency has resolved, let's try hitting
6612 * the cache in case the dep resolved to a value we have previously seen.
6613 *
6614 * TODO:
6615 * Note this optimization is not perfect because it only prevents re-executions
6616 * _after_ the point where an async dependency is found. Any code leading
6617 * up to the async dependency may have run unnecessarily. The ideal case
6618 * would be to wait for the async dependency to resolve first, check the
6619 * cache, and prevent _any_ execution of the selector if the resulting
6620 * value of the dependency leads to a path that is found in the cache.
6621 * The ideal case is more difficult to implement as it would require that
6622 * we capture and wait for the the async dependency right after checking
6623 * the cache. The current approach takes advantage of the fact that running
6624 * the selector already has a code path that lets us exit early when
6625 * an async dep resolves.
6626 */
6627
6628
6629 const cachedLoadable = getValFromCacheAndUpdatedDownstreamDeps(store, state);
6630
6631 if (cachedLoadable && cachedLoadable.state === 'hasValue') {
6632 setExecutionInfo(cachedLoadable, store);
6633 return cachedLoadable.contents;
6634 }
6635 /**
6636 * If this execution is stale, let's check to see if there is some in
6637 * progress execution with a matching state. If we find a match, then
6638 * we can take the value from that in-progress execution. Note this may
6639 * sound like an edge case, but may be very common in cases where a
6640 * loading dependency resolves from loading to having a value (thus
6641 * possibly triggering a re-render), and React re-renders before the
6642 * chained .then() functions run, thus starting a new execution as the
6643 * dep has changed value. Without this check we will run the selector
6644 * twice (once in the new execution and once again in this .then(), so
6645 * this check is necessary to keep unnecessary re-executions to a
6646 * minimum).
6647 *
6648 * Also note this code does not check across all executions that may be
6649 * running. It only optimizes for the _latest_ execution per store as
6650 * we currently do not maintain a list of all currently running executions.
6651 * This means in some cases we may run selectors more than strictly
6652 * necessary when there are multiple executions running for the same
6653 * selector. This may be a valid tradeoff as checking for dep changes
6654 * across all in-progress executions may take longer than just
6655 * re-running the selector. This will be app-dependent, and maybe in the
6656 * future we can make the behavior configurable. An ideal fix may be
6657 * to extend the tree cache to support caching loading states.
6658 */
6659
6660
6661 if (!isLatestExecution(store, executionId)) {
6662 var _executionInfo$latest;
6663
6664 const executionInfo = getExecutionInfoOfInProgressExecution(state);
6665
6666 if ((executionInfo === null || executionInfo === void 0 ? void 0 : (_executionInfo$latest = executionInfo.latestLoadable) === null || _executionInfo$latest === void 0 ? void 0 : _executionInfo$latest.state) === 'loading') {
6667 /**
6668 * Returning promise here without wrapping as the wrapper logic was
6669 * already done upstream when this promise was generated.
6670 */
6671 return executionInfo.latestLoadable.contents;
6672 }
6673 }
6674
6675 const [loadable, depValues] = evaluateSelectorGetter(store, state, executionId);
6676
6677 if (isLatestExecution(store, executionId)) {
6678 updateExecutionInfoDepValues(depValues, store, executionId);
6679 }
6680
6681 if (loadable.state !== 'loading') {
6682 setCache(state, depValuesToDepRoute(depValues), loadable);
6683 setDepsInStore(store, state, new Set(depValues.keys()), executionId);
6684 setLoadableInStoreToNotifyDeps(store, loadable, executionId);
6685 }
6686
6687 if (loadable.state === 'hasError') {
6688 throw loadable.contents;
6689 }
6690 /**
6691 * Returning any promises here without wrapping as the wrapepr logic was
6692 * already done when we called evaluateSelectorGetter() to get this
6693 * loadable
6694 */
6695
6696
6697 return loadable.contents;
6698 }).catch(error => {
6699 if (error instanceof Canceled) {
6700 Recoil_recoverableViolation('Selector was released while it had dependencies');
6701 throw CANCELED;
6702 }
6703
6704 if (!selectorIsLive()) {
6705 // The selector was released since the request began; ignore the response.
6706 clearExecutionInfo(store, executionId);
6707 throw CANCELED;
6708 }
6709
6710 const loadable = loadableWithError$1(error);
6711 maybeFreezeValue(error);
6712 setCache(state, depValuesToDepRoute(existingDeps), loadableWithError$1(error));
6713 setDepsInStore(store, state, new Set(existingDeps.keys()), executionId);
6714 setLoadableInStoreToNotifyDeps(store, loadable, executionId);
6715 throw error;
6716 });
6717 }
6718
6719 function setLoadableInStoreToNotifyDeps(store, loadable, executionId) {
6720 if (isLatestExecution(store, executionId)) {
6721 setExecutionInfo(loadable, store);
6722 notifyStoresOfSettledAsync(loadable, executionId);
6723 }
6724 }
6725
6726 function setDepsInStore(store, state, deps, executionId) {
6727 var _store$getState, _store$getState$curre, _store$getState2, _store$getState2$next;
6728
6729 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)) {
6730 var _store$getState$nextT, _store$getState3, _store$getState3$next;
6731
6732 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);
6733 }
6734 }
6735
6736 function setNewDepInStore(store, state, deps, newDepKey, executionId) {
6737 deps.add(newDepKey);
6738 setDepsInStore(store, state, deps, executionId);
6739 }
6740
6741 function evaluateSelectorGetter(store, state, executionId) {
6742 const endPerfBlock = startPerfBlock$1(key); // TODO T63965866: use execution ID here
6743
6744 let result;
6745 let resultIsError = false;
6746 let loadable;
6747 const loadingDepsState = {
6748 loadingDepKey: null,
6749 loadingDepPromise: null
6750 };
6751 const depValues = new Map();
6752 /**
6753 * Starting a fresh set of deps that we'll be using to update state. We're
6754 * starting a new set versus adding it in existing state deps because
6755 * the version of state that we update deps for may be a more recent version
6756 * than the version the selector was called with. This is because the latest
6757 * execution will update the deps of the current/latest version of state (
6758 * this is safe to do because the fact that the selector is the latest
6759 * execution means the deps we discover below are our best guess at the
6760 * deps for the current/latest state in the store)
6761 */
6762
6763 const deps = new Set();
6764 setDepsInStore(store, state, deps, executionId);
6765
6766 function getRecoilValue(dep) {
6767 const {
6768 key: depKey
6769 } = dep;
6770 setNewDepInStore(store, state, deps, depKey, executionId);
6771 const depLoadable = getCachedNodeLoadable(store, state, depKey);
6772 depValues.set(depKey, depLoadable);
6773
6774 switch (depLoadable.state) {
6775 case 'hasValue':
6776 return depLoadable.contents;
6777
6778 case 'hasError':
6779 throw depLoadable.contents;
6780
6781 case 'loading':
6782 loadingDepsState.loadingDepKey = depKey;
6783 loadingDepsState.loadingDepPromise = depLoadable.contents;
6784 throw depLoadable.contents;
6785 }
6786
6787 throw Recoil_err('Invalid Loadable state');
6788 }
6789
6790 let gateCallback = false;
6791
6792 const getCallback = fn => {
6793 return (...args) => {
6794 if (!gateCallback) {
6795 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.');
6796 }
6797
6798 const snapshot = cloneSnapshot$3(store);
6799 const cb = fn({
6800 snapshot
6801 });
6802
6803 if (typeof cb !== 'function') {
6804 throw Recoil_err('getCallback() expects a function that returns a function.');
6805 }
6806
6807 return cb(...args);
6808 };
6809 };
6810
6811 try {
6812 result = get({
6813 get: getRecoilValue,
6814 getCallback
6815 });
6816 result = isRecoilValue$3(result) ? getRecoilValue(result) : result;
6817 gateCallback = true;
6818
6819 if (Recoil_isPromise(result)) {
6820 result = wrapPendingPromise(store, result, state, depValues, executionId, loadingDepsState).finally(endPerfBlock);
6821 } else {
6822 endPerfBlock();
6823 }
6824 } catch (errorOrDepPromise) {
6825 result = errorOrDepPromise;
6826
6827 if (Recoil_isPromise(result)) {
6828 result = wrapPendingDependencyPromise(store, result, state, depValues, executionId, loadingDepsState).finally(endPerfBlock);
6829 } else {
6830 resultIsError = true;
6831 endPerfBlock();
6832 }
6833 }
6834
6835 if (resultIsError) {
6836 loadable = loadableWithError$1(result);
6837 } else if (Recoil_isPromise(result)) {
6838 loadable = loadableWithPromise$1(result);
6839 } else {
6840 loadable = loadableWithValue$2(result);
6841 }
6842
6843 if (loadable.state !== 'loading') {
6844 maybeFreezeValue(loadable.contents);
6845 }
6846
6847 return [loadable, depValues];
6848 }
6849
6850 function getValFromCacheAndUpdatedDownstreamDeps(store, state) {
6851 const depsAfterCacheDone = new Set();
6852 const executionInfo = getExecutionInfo(store);
6853 let cachedVal;
6854
6855 try {
6856 cachedVal = cache.get(nodeKey => {
6857 !(typeof nodeKey === 'string') ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Cache nodeKey is type string') : Recoil_invariant(false) : void 0;
6858 const loadable = getCachedNodeLoadable(store, state, nodeKey);
6859 return loadable.contents;
6860 }, {
6861 onNodeVisit: node => {
6862 if (node.type === 'branch' && node.nodeKey !== key && typeof node.nodeKey === 'string') {
6863 depsAfterCacheDone.add(node.nodeKey);
6864 discoveredDependencyNodeKeys.add(node.nodeKey);
6865 }
6866 }
6867 });
6868 } catch (error) {
6869 throw Recoil_err(`Problem with cache lookup for selector "${key}": ${error.message}`);
6870 }
6871 /**
6872 * Ensure store contains correct dependencies if we hit the cache so that
6873 * the store deps and cache are in sync for a given state. This is important
6874 * because store deps are normally updated when new executions are created,
6875 * but cache hits don't trigger new executions but they still _may_ signifiy
6876 * a change in deps in the store if the store deps for this state are empty
6877 * or stale.
6878 */
6879
6880
6881 if (cachedVal) {
6882 setDepsInStore(store, state, depsAfterCacheDone, executionInfo.latestExecutionId);
6883 }
6884
6885 return cachedVal;
6886 }
6887 /**
6888 * FIXME: dep keys should take into account the state of the loadable to
6889 * prevent the edge case where a loadable with an error and a loadable with
6890 * an error as a value are treated as the same thing incorrectly. For example
6891 * these two should be treated differently:
6892 *
6893 * selector({key: '', get: () => new Error('hi')});
6894 * selector({key: '', get () => {throw new Error('hi')}});
6895 *
6896 * With current implementation they are treated the same
6897 */
6898
6899
6900 function depValuesToDepRoute(depValues) {
6901 return Array.from(depValues.entries()).map(([depKey, valLoadable]) => [depKey, valLoadable.contents]);
6902 }
6903
6904 function getValFromRunningNewExecutionAndUpdatedDeps(store, state) {
6905 const newExecutionId = getNewExecutionId();
6906 const [loadable, newDepValues] = evaluateSelectorGetter(store, state, newExecutionId);
6907 setExecutionInfo(loadable, store, newDepValues, newExecutionId, state);
6908 maybeSetCacheWithLoadable(state, depValuesToDepRoute(newDepValues), loadable);
6909 notifyStoreWhenAsyncSettles(store, loadable, newExecutionId);
6910 return loadable;
6911 }
6912 /**
6913 * Given a tree state, this function returns the "selector result", which is
6914 * defined as a size-2 tuple of [DependencyMap, Loadable<T>].
6915 *
6916 * The selector's get() function will only be re-evaluated if _both_ of the
6917 * following statements are true:
6918 *
6919 * 1. The current dep values from the given state produced a cache key that
6920 * was not found in the cache.
6921 * 2. There is no currently running async execution OR there is an
6922 * async execution that is running, but after comparing the dep values in
6923 * the given state with the dep values that the execution has discovered so
6924 * far we find that at least one dep value has changed, in which case we
6925 * start a new execution (the previously running execution will continue to
6926 * run to completion, but only the new execution will be deemed the
6927 * 'latest' execution, meaning it will be the only execution that will
6928 * update global state when it is finished. Any non-latest executions will
6929 * run to completion and update the selector cache but not global state).
6930 */
6931
6932
6933 function getSelectorValAndUpdatedDeps(store, state) {
6934 const cachedVal = getValFromCacheAndUpdatedDownstreamDeps(store, state);
6935
6936 if (cachedVal != null) {
6937 setExecutionInfo(cachedVal, store);
6938 return cachedVal;
6939 }
6940
6941 const inProgressExecutionInfo = getExecutionInfoOfInProgressExecution(state); // FIXME: this won't work with custom caching b/c it uses separate cache
6942
6943 if (inProgressExecutionInfo) {
6944 const executionInfo = inProgressExecutionInfo;
6945 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
6946
6947 return Recoil_nullthrows(executionInfo.latestLoadable);
6948 }
6949
6950 return getValFromRunningNewExecutionAndUpdatedDeps(store, state);
6951 }
6952 /**
6953 * Searches execution info across all stores to see if there is an in-progress
6954 * execution whose dependency values match the values of the requesting store.
6955 */
6956
6957
6958 function getExecutionInfoOfInProgressExecution(state) {
6959 var _Array$from$find;
6960
6961 const [, executionInfo] = (_Array$from$find = Array.from(executionInfoMap.entries()).find(([store, execInfo]) => {
6962 return execInfo.latestLoadable != null && execInfo.latestExecutionId != null && !haveAsyncDepsChanged(store, state);
6963 })) !== null && _Array$from$find !== void 0 ? _Array$from$find : [];
6964 return executionInfo;
6965 }
6966
6967 const mapOfCheckedVersions = new Map();
6968
6969 function haveAsyncDepsChanged(store, state) {
6970 var _executionInfo$depVal, _mapOfCheckedVersions;
6971
6972 const executionInfo = getExecutionInfo(store);
6973 const oldDepValues = (_executionInfo$depVal = executionInfo.depValuesDiscoveredSoFarDuringAsyncWork) !== null && _executionInfo$depVal !== void 0 ? _executionInfo$depVal : new Map();
6974 const cachedDepValuesCheckedForThisVersion = Array(((_mapOfCheckedVersions = mapOfCheckedVersions.get(state.version)) !== null && _mapOfCheckedVersions !== void 0 ? _mapOfCheckedVersions : new Map()).entries());
6975 const isCachedVersionSame = mapOfCheckedVersions.has(state.version) && cachedDepValuesCheckedForThisVersion.length === oldDepValues.size && cachedDepValuesCheckedForThisVersion.every(([nodeKey, nodeVal]) => {
6976 return oldDepValues.get(nodeKey) === nodeVal;
6977 });
6978
6979 if (oldDepValues == null || state.version === executionInfo.stateVersion || isCachedVersionSame) {
6980 return false;
6981 }
6982
6983 mapOfCheckedVersions.set(state.version, new Map(oldDepValues));
6984 return Array.from(oldDepValues).some(([nodeKey, oldVal]) => {
6985 const loadable = getCachedNodeLoadable(store, state, nodeKey);
6986 return loadable.contents !== oldVal.contents;
6987 });
6988 }
6989 /**
6990 * This function will update the selector's execution info when the selector
6991 * has either finished running an execution or has started a new execution. If
6992 * the given loadable is in a 'loading' state, the intention is that a new
6993 * execution has started. Otherwise, the intention is that an execution has
6994 * just finished.
6995 */
6996
6997
6998 function setExecutionInfo(loadable, store, depValues, newExecutionId, state) {
6999 const executionInfo = getExecutionInfo(store);
7000
7001 if (loadable.state === 'loading') {
7002 executionInfo.depValuesDiscoveredSoFarDuringAsyncWork = depValues;
7003 executionInfo.latestExecutionId = newExecutionId;
7004 executionInfo.latestLoadable = loadable;
7005 executionInfo.stateVersion = state === null || state === void 0 ? void 0 : state.version;
7006 } else {
7007 executionInfo.depValuesDiscoveredSoFarDuringAsyncWork = null;
7008 executionInfo.latestExecutionId = null;
7009 executionInfo.latestLoadable = null;
7010 executionInfo.stateVersion = null;
7011 }
7012 }
7013 /**
7014 * Conditionally updates the cache with a given loadable.
7015 *
7016 * We only cache loadables that are not loading because our cache keys are
7017 * based on dep values, which are in an unfinished state for loadables that
7018 * have a 'loading' state (new deps may be discovered while the selector
7019 * runs its async code). We never want to cache partial dependencies b/c it
7020 * could lead to errors, such as prematurely returning the result based on a
7021 * partial list of deps-- we need the full list of deps to ensure that we
7022 * are returning the correct result from cache.
7023 */
7024
7025
7026 function maybeSetCacheWithLoadable(state, depRoute, loadable) {
7027 if (loadable.state !== 'loading') {
7028 setCache(state, depRoute, loadable);
7029 }
7030 }
7031
7032 function updateExecutionInfoDepValues(depValues, store, executionId) {
7033 const executionInfo = getExecutionInfo(store);
7034
7035 if (isLatestExecution(store, executionId)) {
7036 executionInfo.depValuesDiscoveredSoFarDuringAsyncWork = depValues;
7037 }
7038 }
7039
7040 function clearExecutionInfo(store, executionId) {
7041 if (isLatestExecution(store, executionId)) {
7042 executionInfoMap.delete(store);
7043 }
7044 }
7045
7046 function isLatestExecution(store, executionId) {
7047 const executionInfo = getExecutionInfo(store);
7048 return executionId === executionInfo.latestExecutionId;
7049 }
7050
7051 function maybeFreezeValue(val) {
7052 if (process.env.NODE_ENV !== "production") {
7053 if (Boolean(options.dangerouslyAllowMutability) === false) {
7054 Recoil_deepFreezeValue(val);
7055 }
7056 }
7057 }
7058
7059 function setCache(state, cacheRoute, loadable) {
7060 state.atomValues.set(key, loadable);
7061
7062 try {
7063 cache.set(cacheRoute, loadable);
7064 } catch (error) {
7065 throw Recoil_err(`Problem with setting cache for selector "${key}": ${error.message}`);
7066 }
7067 }
7068
7069 function detectCircularDependencies(fn) {
7070 if (dependencyStack.includes(key)) {
7071 const message = `Recoil selector has circular dependencies: ${dependencyStack.slice(dependencyStack.indexOf(key)).join(' \u2192 ')}`;
7072 return loadableWithError$1(Recoil_err(message));
7073 }
7074
7075 dependencyStack.push(key);
7076
7077 try {
7078 return fn();
7079 } finally {
7080 dependencyStack.pop();
7081 }
7082 }
7083
7084 function selectorPeek(store, state) {
7085 const cacheVal = cache.get(nodeKey => {
7086 !(typeof nodeKey === 'string') ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Cache nodeKey is type string') : Recoil_invariant(false) : void 0;
7087 const peek = peekNodeLoadable$1(store, state, nodeKey);
7088 return peek === null || peek === void 0 ? void 0 : peek.contents;
7089 });
7090 return cacheVal;
7091 }
7092
7093 function selectorGet(store, state) {
7094 return detectCircularDependencies(() => getSelectorValAndUpdatedDeps(store, state));
7095 }
7096
7097 function invalidateSelector(state) {
7098 state.atomValues.delete(key);
7099 }
7100
7101 function clearSelectorCache(store, treeState) {
7102 !(recoilValue != null) ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Recoil Value can never be null') : Recoil_invariant(false) : void 0;
7103
7104 for (const nodeKey of discoveredDependencyNodeKeys) {
7105 var _node$clearCache;
7106
7107 const node = getNode$6(nodeKey);
7108 (_node$clearCache = node.clearCache) === null || _node$clearCache === void 0 ? void 0 : _node$clearCache.call(node, store, treeState);
7109 }
7110
7111 invalidateSelector(treeState);
7112 cache.clear();
7113 markRecoilValueModified$1(store, recoilValue);
7114 }
7115
7116 if (set != null) {
7117 /**
7118 * ES5 strict mode prohibits defining non-top-level function declarations,
7119 * so don't use function declaration syntax here
7120 */
7121 const selectorSet = (store, state, newValue) => {
7122 let syncSelectorSetFinished = false;
7123 const writes = new Map();
7124
7125 function getRecoilValue({
7126 key: depKey
7127 }) {
7128 if (syncSelectorSetFinished) {
7129 throw Recoil_err('Recoil: Async selector sets are not currently supported.');
7130 }
7131
7132 const loadable = getCachedNodeLoadable(store, state, depKey);
7133
7134 if (loadable.state === 'hasValue') {
7135 return loadable.contents;
7136 } else if (loadable.state === 'loading') {
7137 throw new RecoilValueNotReady$2(depKey);
7138 } else {
7139 throw loadable.contents;
7140 }
7141 }
7142
7143 function setRecoilState(recoilState, valueOrUpdater) {
7144 if (syncSelectorSetFinished) {
7145 throw Recoil_err('Recoil: Async selector sets are not currently supported.');
7146 }
7147
7148 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
7149 // flowlint-next-line unclear-type:off
7150 valueOrUpdater(getRecoilValue(recoilState)) : valueOrUpdater;
7151 const upstreamWrites = setNodeValue$3(store, state, recoilState.key, setValue);
7152 upstreamWrites.forEach((v, k) => writes.set(k, v));
7153 }
7154
7155 function resetRecoilState(recoilState) {
7156 setRecoilState(recoilState, DEFAULT_VALUE$6);
7157 }
7158
7159 const ret = set({
7160 set: setRecoilState,
7161 get: getRecoilValue,
7162 reset: resetRecoilState
7163 }, newValue); // set should be a void method, but if the user makes it `async`, then it
7164 // will return a Promise, which we don't currently support.
7165
7166 if (ret !== undefined) {
7167 throw Recoil_isPromise(ret) ? Recoil_err('Recoil: Async selector sets are not currently supported.') : Recoil_err('Recoil: selector set should be a void function.');
7168 }
7169
7170 syncSelectorSetFinished = true;
7171 return writes;
7172 };
7173
7174 return recoilValue = registerNode$1({
7175 key,
7176 nodeType: 'selector',
7177 peek: selectorPeek,
7178 get: selectorGet,
7179 set: selectorSet,
7180 init: selectorInit,
7181 invalidate: invalidateSelector,
7182 clearCache: clearSelectorCache,
7183 shouldDeleteConfigOnRelease: selectorShouldDeleteConfigOnRelease,
7184 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
7185 shouldRestoreFromSnapshots: false,
7186 retainedBy
7187 });
7188 } else {
7189 return recoilValue = registerNode$1({
7190 key,
7191 nodeType: 'selector',
7192 peek: selectorPeek,
7193 get: selectorGet,
7194 init: selectorInit,
7195 invalidate: invalidateSelector,
7196 clearCache: clearSelectorCache,
7197 shouldDeleteConfigOnRelease: selectorShouldDeleteConfigOnRelease,
7198 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
7199 shouldRestoreFromSnapshots: false,
7200 retainedBy
7201 });
7202 }
7203}
7204/* eslint-enable no-redeclare */
7205
7206
7207var Recoil_selector = selector;
7208
7209// @fb-only: const {scopedAtom} = require('Recoil_ScopedAtom');
7210const {
7211 loadableWithError: loadableWithError$2,
7212 loadableWithPromise: loadableWithPromise$2,
7213 loadableWithValue: loadableWithValue$3
7214} = Recoil_Loadable$1;
7215
7216const {
7217 peekNodeInfo: peekNodeInfo$3
7218} = Recoil_FunctionalCore;
7219
7220const {
7221 DEFAULT_VALUE: DEFAULT_VALUE$7,
7222 DefaultValue: DefaultValue$2,
7223 getConfigDeletionHandler: getConfigDeletionHandler$2,
7224 registerNode: registerNode$2,
7225 setConfigDeletionHandler: setConfigDeletionHandler$1
7226} = Recoil_Node;
7227
7228const {
7229 isRecoilValue: isRecoilValue$4
7230} = Recoil_RecoilValue$1;
7231
7232const {
7233 getRecoilValueAsLoadable: getRecoilValueAsLoadable$4,
7234 markRecoilValueModified: markRecoilValueModified$2,
7235 setRecoilValue: setRecoilValue$4,
7236 setRecoilValueLoadable: setRecoilValueLoadable$3
7237} = Recoil_RecoilValueInterface;
7238
7239const {
7240 retainedByOptionWithDefault: retainedByOptionWithDefault$2
7241} = Recoil_Retention;
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257function baseAtom(options) {
7258 const {
7259 key,
7260 persistence_UNSTABLE: persistence
7261 } = options;
7262 const retainedBy = retainedByOptionWithDefault$2(options.retainedBy_UNSTABLE);
7263 let liveStoresCount = 0;
7264 let defaultLoadable = Recoil_isPromise(options.default) ? loadableWithPromise$2(options.default.then(value => {
7265 defaultLoadable = loadableWithValue$3(value);
7266 return value;
7267 }).catch(error => {
7268 defaultLoadable = loadableWithError$2(error);
7269 throw error;
7270 })) : loadableWithValue$3(options.default);
7271 maybeFreezeValueOrPromise(options.default);
7272 let cachedAnswerForUnvalidatedValue = undefined; // Cleanup handlers for this atom
7273 // Rely on stable reference equality of the store to use it as a key per <RecoilRoot>
7274
7275 const cleanupEffectsByStore = new Map();
7276
7277 function maybeFreezeValueOrPromise(valueOrPromise) {
7278 if (process.env.NODE_ENV !== "production") {
7279 if (options.dangerouslyAllowMutability !== true) {
7280 if (Recoil_isPromise(valueOrPromise)) {
7281 return valueOrPromise.then(value => {
7282 Recoil_deepFreezeValue(value);
7283 return value;
7284 });
7285 } else {
7286 Recoil_deepFreezeValue(valueOrPromise);
7287 return valueOrPromise;
7288 }
7289 }
7290 }
7291
7292 return valueOrPromise;
7293 }
7294
7295 function wrapPendingPromise(store, promise) {
7296 const wrappedPromise = promise.then(value => {
7297 var _store$getState$nextT, _state$atomValues$get;
7298
7299 const state = (_store$getState$nextT = store.getState().nextTree) !== null && _store$getState$nextT !== void 0 ? _store$getState$nextT : store.getState().currentTree;
7300
7301 if (((_state$atomValues$get = state.atomValues.get(key)) === null || _state$atomValues$get === void 0 ? void 0 : _state$atomValues$get.contents) === wrappedPromise) {
7302 setRecoilValue$4(store, node, value);
7303 }
7304
7305 return value;
7306 }).catch(error => {
7307 var _store$getState$nextT2, _state$atomValues$get2;
7308
7309 const state = (_store$getState$nextT2 = store.getState().nextTree) !== null && _store$getState$nextT2 !== void 0 ? _store$getState$nextT2 : store.getState().currentTree;
7310
7311 if (((_state$atomValues$get2 = state.atomValues.get(key)) === null || _state$atomValues$get2 === void 0 ? void 0 : _state$atomValues$get2.contents) === wrappedPromise) {
7312 setRecoilValueLoadable$3(store, node, loadableWithError$2(error));
7313 }
7314
7315 throw error;
7316 });
7317 return wrappedPromise;
7318 }
7319
7320 function initAtom(store, initState, trigger) {
7321 liveStoresCount++;
7322 const alreadyKnown = store.getState().knownAtoms.has(key);
7323 store.getState().knownAtoms.add(key); // Setup async defaults to notify subscribers when they resolve
7324
7325 if (defaultLoadable.state === 'loading') {
7326 const notifyDefaultSubscribers = () => {
7327 var _store$getState$nextT3;
7328
7329 const state = (_store$getState$nextT3 = store.getState().nextTree) !== null && _store$getState$nextT3 !== void 0 ? _store$getState$nextT3 : store.getState().currentTree;
7330
7331 if (!state.atomValues.has(key)) {
7332 markRecoilValueModified$2(store, node);
7333 }
7334 };
7335
7336 defaultLoadable.contents.then(notifyDefaultSubscribers).catch(notifyDefaultSubscribers);
7337 } // Run Atom Effects
7338 // This state is scoped by Store, since this is in the initAtom() closure
7339
7340
7341 let initValue = DEFAULT_VALUE$7;
7342 let pendingSetSelf = null;
7343
7344 if (options.effects_UNSTABLE != null && !alreadyKnown) {
7345 let duringInit = true;
7346
7347 function getLoadable(recoilValue) {
7348 // Normally we can just get the current value of another atom.
7349 // But for our own value we need to check if there is a pending
7350 // initialized value or get the fallback default value.
7351 if (duringInit && recoilValue.key === key && !(initValue instanceof DefaultValue$2)) {
7352 // Cast T to S
7353 const retValue = initValue; // flowlint-line unclear-type:off
7354
7355 return retValue instanceof DefaultValue$2 ? defaultLoadable : // flowlint-line unclear-type:off
7356 Recoil_isPromise(retValue) ? loadableWithPromise$2(retValue.then(v => v instanceof DefaultValue$2 ? // Cast T to S
7357 defaultLoadable.toPromise() // flowlint-line unclear-type:off
7358 : v)) : loadableWithValue$3(retValue);
7359 }
7360
7361 return getRecoilValueAsLoadable$4(store, recoilValue);
7362 }
7363
7364 function getPromise(recoilValue) {
7365 return getLoadable(recoilValue).toPromise();
7366 }
7367
7368 function getInfo_UNSTABLE(recoilValue) {
7369 var _store$getState$nextT4;
7370
7371 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);
7372 return duringInit && recoilValue.key === key && !(initValue instanceof DefaultValue$2) ? { ...info,
7373 isSet: true,
7374 loadable: getLoadable(recoilValue)
7375 } : info;
7376 }
7377
7378 const setSelf = effect => valueOrUpdater => {
7379 if (duringInit) {
7380 const currentValue = initValue instanceof DefaultValue$2 || Recoil_isPromise(initValue) ? defaultLoadable.state === 'hasValue' ? defaultLoadable.contents : DEFAULT_VALUE$7 : initValue;
7381 initValue = typeof valueOrUpdater === 'function' ? // cast to any because we can't restrict T from being a function without losing support for opaque types
7382 valueOrUpdater(currentValue) // flowlint-line unclear-type:off
7383 : valueOrUpdater;
7384
7385 if (Recoil_isPromise(initValue)) {
7386 initValue = initValue.then(value => {
7387 // Avoid calling onSet() when setSelf() initializes with a Promise
7388 pendingSetSelf = {
7389 effect,
7390 value
7391 };
7392 return value;
7393 });
7394 }
7395 } else {
7396 if (Recoil_isPromise(valueOrUpdater)) {
7397 throw Recoil_err('Setting atoms to async values is not implemented.');
7398 }
7399
7400 if (typeof valueOrUpdater !== 'function') {
7401 pendingSetSelf = {
7402 effect,
7403 value: valueOrUpdater
7404 };
7405 }
7406
7407 setRecoilValue$4(store, node, typeof valueOrUpdater === 'function' ? currentValue => {
7408 const newValue = // cast to any because we can't restrict T from being a function without losing support for opaque types
7409 valueOrUpdater(currentValue); // flowlint-line unclear-type:off
7410
7411 pendingSetSelf = {
7412 effect,
7413 value: newValue
7414 };
7415 return newValue;
7416 } : valueOrUpdater);
7417 }
7418 };
7419
7420 const resetSelf = effect => () => setSelf(effect)(DEFAULT_VALUE$7);
7421
7422 const onSet = effect => handler => {
7423 store.subscribeToTransactions(currentStore => {
7424 var _currentTree$atomValu;
7425
7426 // eslint-disable-next-line prefer-const
7427 let {
7428 currentTree,
7429 previousTree
7430 } = currentStore.getState();
7431
7432 if (!previousTree) {
7433 Recoil_recoverableViolation('Transaction subscribers notified without a next tree being present -- this is a bug in Recoil');
7434 previousTree = currentTree; // attempt to trundle on
7435 }
7436
7437 const newLoadable = (_currentTree$atomValu = currentTree.atomValues.get(key)) !== null && _currentTree$atomValu !== void 0 ? _currentTree$atomValu : defaultLoadable;
7438
7439 if (newLoadable.state === 'hasValue') {
7440 var _previousTree$atomVal, _pendingSetSelf, _pendingSetSelf2, _pendingSetSelf3;
7441
7442 const newValue = newLoadable.contents;
7443 const oldLoadable = (_previousTree$atomVal = previousTree.atomValues.get(key)) !== null && _previousTree$atomVal !== void 0 ? _previousTree$atomVal : defaultLoadable;
7444 const oldValue = oldLoadable.state === 'hasValue' ? oldLoadable.contents : DEFAULT_VALUE$7; // TODO This isn't actually valid, use as a placeholder for now.
7445 // Ignore atom value changes that were set via setSelf() in the same effect.
7446 // We will still properly call the handler if there was a subsequent
7447 // set from something other than an atom effect which was batched
7448 // with the `setSelf()` call. However, we may incorrectly ignore
7449 // the handler if the subsequent batched call happens to set the
7450 // atom to the exact same value as the `setSelf()`. But, in that
7451 // case, it was kind of a noop, so the semantics are debatable..
7452
7453 if (((_pendingSetSelf = pendingSetSelf) === null || _pendingSetSelf === void 0 ? void 0 : _pendingSetSelf.effect) !== effect || ((_pendingSetSelf2 = pendingSetSelf) === null || _pendingSetSelf2 === void 0 ? void 0 : _pendingSetSelf2.value) !== newValue) {
7454 handler(newValue, oldValue, !currentTree.atomValues.has(key));
7455 } else if (((_pendingSetSelf3 = pendingSetSelf) === null || _pendingSetSelf3 === void 0 ? void 0 : _pendingSetSelf3.effect) === effect) {
7456 pendingSetSelf = null;
7457 }
7458 }
7459 }, key);
7460 };
7461
7462 for (const effect of (_options$effects_UNST = options.effects_UNSTABLE) !== null && _options$effects_UNST !== void 0 ? _options$effects_UNST : []) {
7463 var _options$effects_UNST;
7464
7465 const cleanup = effect({
7466 node,
7467 trigger,
7468 setSelf: setSelf(effect),
7469 resetSelf: resetSelf(effect),
7470 onSet: onSet(effect),
7471 getPromise,
7472 getLoadable,
7473 getInfo_UNSTABLE
7474 });
7475
7476 if (cleanup != null) {
7477 var _cleanupEffectsByStor;
7478
7479 cleanupEffectsByStore.set(store, [...((_cleanupEffectsByStor = cleanupEffectsByStore.get(store)) !== null && _cleanupEffectsByStor !== void 0 ? _cleanupEffectsByStor : []), cleanup]);
7480 }
7481 }
7482
7483 duringInit = false;
7484 } // Mutate initial state in place since we know there are no other subscribers
7485 // since we are the ones initializing on first use.
7486
7487
7488 if (!(initValue instanceof DefaultValue$2)) {
7489 var _store$getState$nextT5;
7490
7491 const frozenInitValue = maybeFreezeValueOrPromise(initValue);
7492 const initLoadable = Recoil_isPromise(frozenInitValue) ? loadableWithPromise$2(wrapPendingPromise(store, frozenInitValue)) : loadableWithValue$3(frozenInitValue);
7493 initState.atomValues.set(key, initLoadable); // If there is a pending transaction, then also mutate the next state tree.
7494 // This could happen if the atom was first initialized in an action that
7495 // also updated some other atom's state.
7496
7497 (_store$getState$nextT5 = store.getState().nextTree) === null || _store$getState$nextT5 === void 0 ? void 0 : _store$getState$nextT5.atomValues.set(key, initLoadable);
7498 }
7499
7500 return () => {
7501 var _cleanupEffectsByStor2;
7502
7503 liveStoresCount--;
7504 (_cleanupEffectsByStor2 = cleanupEffectsByStore.get(store)) === null || _cleanupEffectsByStor2 === void 0 ? void 0 : _cleanupEffectsByStor2.forEach(cleanup => cleanup());
7505 cleanupEffectsByStore.delete(store);
7506 store.getState().knownAtoms.delete(key); // FIXME remove knownAtoms?
7507 };
7508 }
7509
7510 function peekAtom(_store, state) {
7511 var _ref, _state$atomValues$get3;
7512
7513 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;
7514 }
7515
7516 function getAtom(_store, state) {
7517 if (state.atomValues.has(key)) {
7518 // Atom value is stored in state:
7519 return Recoil_nullthrows(state.atomValues.get(key));
7520 } else if (state.nonvalidatedAtoms.has(key)) {
7521 // Atom value is stored but needs validation before use.
7522 // We might have already validated it and have a cached validated value:
7523 if (cachedAnswerForUnvalidatedValue != null) {
7524 return cachedAnswerForUnvalidatedValue;
7525 }
7526
7527 if (persistence == null) {
7528 Recoil_expectationViolation(`Tried to restore a persisted value for atom ${key} but it has no persistence settings.`);
7529 return defaultLoadable;
7530 }
7531
7532 const nonvalidatedValue = state.nonvalidatedAtoms.get(key);
7533 const validatorResult = persistence.validator(nonvalidatedValue, DEFAULT_VALUE$7);
7534 const validatedValueLoadable = validatorResult instanceof DefaultValue$2 ? defaultLoadable : loadableWithValue$3(validatorResult);
7535 cachedAnswerForUnvalidatedValue = validatedValueLoadable;
7536 return cachedAnswerForUnvalidatedValue;
7537 } else {
7538 return defaultLoadable;
7539 }
7540 }
7541
7542 function invalidateAtom() {
7543 cachedAnswerForUnvalidatedValue = undefined;
7544 }
7545
7546 function setAtom(_store, state, newValue) {
7547 // Bail out if we're being set to the existing value, or if we're being
7548 // reset but have no stored value (validated or unvalidated) to reset from:
7549 if (state.atomValues.has(key)) {
7550 const existing = Recoil_nullthrows(state.atomValues.get(key));
7551
7552 if (existing.state === 'hasValue' && newValue === existing.contents) {
7553 return new Map();
7554 }
7555 } else if (!state.nonvalidatedAtoms.has(key) && newValue instanceof DefaultValue$2) {
7556 return new Map();
7557 }
7558
7559 maybeFreezeValueOrPromise(newValue);
7560 cachedAnswerForUnvalidatedValue = undefined; // can be released now if it was previously in use
7561
7562 return new Map().set(key, loadableWithValue$3(newValue));
7563 }
7564
7565 function shouldDeleteConfigOnReleaseAtom() {
7566 return getConfigDeletionHandler$2(key) !== undefined && liveStoresCount <= 0;
7567 }
7568
7569 const node = registerNode$2({
7570 key,
7571 nodeType: 'atom',
7572 peek: peekAtom,
7573 get: getAtom,
7574 set: setAtom,
7575 init: initAtom,
7576 invalidate: invalidateAtom,
7577 shouldDeleteConfigOnRelease: shouldDeleteConfigOnReleaseAtom,
7578 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
7579 persistence_UNSTABLE: options.persistence_UNSTABLE ? {
7580 type: options.persistence_UNSTABLE.type,
7581 backButton: options.persistence_UNSTABLE.backButton
7582 } : undefined,
7583 shouldRestoreFromSnapshots: true,
7584 retainedBy
7585 });
7586 return node;
7587} // prettier-ignore
7588
7589
7590function atom(options) {
7591 if (process.env.NODE_ENV !== "production") {
7592 if (typeof options.key !== 'string') {
7593 throw Recoil_err('A key option with a unique string value must be provided when creating an atom.');
7594 }
7595
7596 if (!('default' in options)) {
7597 throw Recoil_err('A default value must be specified when creating an atom.');
7598 }
7599 }
7600
7601 const {
7602 default: optionsDefault,
7603 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
7604 ...restOptions
7605 } = options;
7606
7607 if (isRecoilValue$4(optionsDefault) // Continue to use atomWithFallback for promise defaults for scoped atoms
7608 // for now, since scoped atoms don't support async defaults
7609 // @fb-only: || (isPromise(optionsDefault) && scopeRules_APPEND_ONLY_READ_THE_DOCS)
7610 ) {
7611 return atomWithFallback({ ...restOptions,
7612 default: optionsDefault // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
7613
7614 }); // @fb-only: } else if (scopeRules_APPEND_ONLY_READ_THE_DOCS && !isPromise(optionsDefault)) {
7615 // @fb-only: return scopedAtom<T>({
7616 // @fb-only: ...restOptions,
7617 // @fb-only: default: optionsDefault,
7618 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
7619 // @fb-only: });
7620 } else {
7621 return baseAtom({ ...restOptions,
7622 default: optionsDefault
7623 });
7624 }
7625}
7626
7627function atomWithFallback(options) {
7628 const base = atom({ ...options,
7629 default: DEFAULT_VALUE$7,
7630 persistence_UNSTABLE: options.persistence_UNSTABLE === undefined ? undefined : { ...options.persistence_UNSTABLE,
7631 validator: storedValue => storedValue instanceof DefaultValue$2 ? storedValue : Recoil_nullthrows(options.persistence_UNSTABLE).validator(storedValue, DEFAULT_VALUE$7)
7632 },
7633 // TODO Hack for now.
7634 // flowlint-next-line unclear-type: off
7635 effects_UNSTABLE: options.effects_UNSTABLE
7636 });
7637 const sel = Recoil_selector({
7638 key: `${options.key}__withFallback`,
7639 get: ({
7640 get
7641 }) => {
7642 const baseValue = get(base);
7643 return baseValue instanceof DefaultValue$2 ? options.default : baseValue;
7644 },
7645 set: ({
7646 set
7647 }, newValue) => set(base, newValue),
7648 dangerouslyAllowMutability: options.dangerouslyAllowMutability
7649 });
7650 setConfigDeletionHandler$1(sel.key, getConfigDeletionHandler$2(options.key));
7651 return sel;
7652}
7653
7654var Recoil_atom = atom;
7655
7656/**
7657 * Copyright (c) Facebook, Inc. and its affiliates.
7658 *
7659 * This source code is licensed under the MIT license found in the
7660 * LICENSE file in the root directory of this source tree.
7661 *
7662 * @emails oncall+recoil
7663 *
7664 * @format
7665 */
7666
7667class MapCache {
7668 constructor(options) {
7669 var _options$mapKey;
7670
7671 _defineProperty(this, "_map", void 0);
7672
7673 _defineProperty(this, "_keyMapper", void 0);
7674
7675 this._map = new Map();
7676 this._keyMapper = (_options$mapKey = options === null || options === void 0 ? void 0 : options.mapKey) !== null && _options$mapKey !== void 0 ? _options$mapKey : v => v;
7677 }
7678
7679 size() {
7680 return this._map.size;
7681 }
7682
7683 has(key) {
7684 return this._map.has(this._keyMapper(key));
7685 }
7686
7687 get(key) {
7688 return this._map.get(this._keyMapper(key));
7689 }
7690
7691 set(key, val) {
7692 this._map.set(this._keyMapper(key), val);
7693 }
7694
7695 delete(key) {
7696 this._map.delete(this._keyMapper(key));
7697 }
7698
7699 clear() {
7700 this._map.clear();
7701 }
7702
7703}
7704
7705var Recoil_MapCache = {
7706 MapCache
7707};
7708
7709var Recoil_MapCache_1 = Recoil_MapCache.MapCache;
7710
7711var Recoil_MapCache$1 = /*#__PURE__*/Object.freeze({
7712 __proto__: null,
7713 MapCache: Recoil_MapCache_1
7714});
7715
7716const {
7717 LRUCache: LRUCache$2
7718} = Recoil_LRUCache$1;
7719
7720const {
7721 MapCache: MapCache$1
7722} = Recoil_MapCache$1;
7723
7724const defaultPolicy$1 = {
7725 equality: 'reference',
7726 eviction: 'none',
7727 maxSize: Infinity
7728};
7729
7730function cacheFromPolicy({
7731 equality = defaultPolicy$1.equality,
7732 eviction = defaultPolicy$1.eviction,
7733 maxSize = defaultPolicy$1.maxSize
7734} = defaultPolicy$1) {
7735 const valueMapper = getValueMapper$1(equality);
7736 const cache = getCache(eviction, maxSize, valueMapper);
7737 return cache;
7738}
7739
7740function getValueMapper$1(equality) {
7741 switch (equality) {
7742 case 'reference':
7743 return val => val;
7744
7745 case 'value':
7746 return val => Recoil_stableStringify(val);
7747 }
7748
7749 throw Recoil_err(`Unrecognized equality policy ${equality}`);
7750}
7751
7752function getCache(eviction, maxSize, mapKey) {
7753 switch (eviction) {
7754 case 'keep-all':
7755 // $FlowFixMe[method-unbinding]
7756 return new MapCache$1({
7757 mapKey
7758 });
7759
7760 case 'lru':
7761 // $FlowFixMe[method-unbinding]
7762 return new LRUCache$2({
7763 mapKey,
7764 maxSize: Recoil_nullthrows(maxSize)
7765 });
7766
7767 case 'most-recent':
7768 // $FlowFixMe[method-unbinding]
7769 return new LRUCache$2({
7770 mapKey,
7771 maxSize: 1
7772 });
7773 }
7774
7775 throw Recoil_err(`Unrecognized eviction policy ${eviction}`);
7776}
7777
7778var Recoil_cacheFromPolicy = cacheFromPolicy;
7779
7780const {
7781 setConfigDeletionHandler: setConfigDeletionHandler$2
7782} = Recoil_Node;
7783
7784
7785
7786
7787
7788// Process scopeRules to handle any entries which are functions taking parameters
7789// prettier-ignore
7790// @fb-only: function mapScopeRules<P>(
7791// @fb-only: scopeRules?: ParameterizedScopeRules<P>,
7792// @fb-only: param: P,
7793// @fb-only: ): ScopeRules | void {
7794// @fb-only: return scopeRules?.map(rule =>
7795// @fb-only: Array.isArray(rule)
7796// @fb-only: ? rule.map(entry => (typeof entry === 'function' ? entry(param) : entry))
7797// @fb-only: : rule,
7798// @fb-only: );
7799// @fb-only: }
7800
7801/*
7802A function which returns an atom based on the input parameter.
7803
7804Each unique parameter returns a unique atom. E.g.,
7805
7806 const f = atomFamily(...);
7807 f({a: 1}) => an atom
7808 f({a: 2}) => a different atom
7809
7810This allows components to persist local, private state using atoms. Each
7811instance of the component may have a different key, which it uses as the
7812parameter for a family of atoms; in this way, each component will have
7813its own atom not shared by other instances. These state keys may be composed
7814into children's state keys as well.
7815*/
7816function atomFamily(options) {
7817 var _options$cachePolicyF, _options$cachePolicyF2;
7818
7819 const atomCache = Recoil_cacheFromPolicy({
7820 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',
7821 eviction: 'keep-all'
7822 }); // Simple atomFamily implementation to cache individual atoms based
7823 // on the parameter value equality.
7824
7825 return params => {
7826 var _stableStringify;
7827
7828 const cachedAtom = atomCache.get(params);
7829
7830 if (cachedAtom != null) {
7831 return cachedAtom;
7832 }
7833
7834 const {
7835 cachePolicyForParams_UNSTABLE,
7836 ...atomOptions
7837 } = options;
7838 const newAtom = Recoil_atom({ ...atomOptions,
7839 key: `${options.key}__${(_stableStringify = Recoil_stableStringify(params)) !== null && _stableStringify !== void 0 ? _stableStringify : 'void'}`,
7840 default: typeof options.default === 'function' ? // The default was parameterized
7841 // Flow doesn't know that T isn't a function, so we need to case to any
7842 options.default(params) // flowlint-line unclear-type:off
7843 : // Default may be a static value, promise, or RecoilValue
7844 options.default,
7845 retainedBy_UNSTABLE: typeof options.retainedBy_UNSTABLE === 'function' ? options.retainedBy_UNSTABLE(params) : options.retainedBy_UNSTABLE,
7846 effects_UNSTABLE: typeof options.effects_UNSTABLE === 'function' ? options.effects_UNSTABLE(params) : options.effects_UNSTABLE // prettier-ignore
7847 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS: mapScopeRules(
7848 // @fb-only: options.scopeRules_APPEND_ONLY_READ_THE_DOCS,
7849 // @fb-only: params,
7850 // @fb-only: ),
7851
7852 });
7853 atomCache.set(params, newAtom);
7854 setConfigDeletionHandler$2(newAtom.key, () => {
7855 atomCache.delete(params);
7856 });
7857 return newAtom;
7858 };
7859}
7860
7861var Recoil_atomFamily = atomFamily;
7862
7863const {
7864 setConfigDeletionHandler: setConfigDeletionHandler$3
7865} = Recoil_Node;
7866
7867
7868
7869 // Keep in mind the parameter needs to be serializable as a cahche key
7870// using Recoil_stableStringify
7871
7872
7873// Add a unique index to each selector in case the cache implementation allows
7874// duplicate keys based on equivalent stringified parameters
7875let nextIndex = 0;
7876/* eslint-disable no-redeclare */
7877
7878// Return a function that returns members of a family of selectors of the same type
7879// E.g.,
7880//
7881// const s = selectorFamily(...);
7882// s({a: 1}) => a selector
7883// s({a: 2}) => a different selector
7884//
7885// By default, the selectors are distinguished by distinct values of the
7886// parameter based on value equality, not reference equality. This allows using
7887// object literals or other equivalent objects at callsites to not create
7888// duplicate cache entries. This behavior may be overridden with the
7889// cacheImplementationForParams option.
7890function selectorFamily(options) {
7891 var _options$cachePolicyF, _options$cachePolicyF2;
7892
7893 const selectorCache = Recoil_cacheFromPolicy({
7894 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',
7895 eviction: 'keep-all'
7896 });
7897 return params => {
7898 var _stableStringify;
7899
7900 const cachedSelector = selectorCache.get(params);
7901
7902 if (cachedSelector != null) {
7903 return cachedSelector;
7904 }
7905
7906 const myKey = `${options.key}__selectorFamily/${(_stableStringify = Recoil_stableStringify(params, {
7907 // It is possible to use functions in parameters if the user uses
7908 // a cache with reference equality thanks to the incrementing index.
7909 allowFunctions: true
7910 })) !== null && _stableStringify !== void 0 ? _stableStringify : 'void'}/${nextIndex++}`; // Append index in case values serialize to the same key string
7911
7912 const myGet = callbacks => options.get(params)(callbacks);
7913
7914 const myCachePolicy = options.cachePolicy_UNSTABLE;
7915 const retainedBy = typeof options.retainedBy_UNSTABLE === 'function' ? options.retainedBy_UNSTABLE(params) : options.retainedBy_UNSTABLE;
7916 let newSelector;
7917
7918 if (options.set != null) {
7919 const set = options.set;
7920
7921 const mySet = (callbacks, newValue) => set(params)(callbacks, newValue);
7922
7923 newSelector = Recoil_selector({
7924 key: myKey,
7925 get: myGet,
7926 set: mySet,
7927 cachePolicy_UNSTABLE: myCachePolicy,
7928 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
7929 retainedBy_UNSTABLE: retainedBy
7930 });
7931 } else {
7932 newSelector = Recoil_selector({
7933 key: myKey,
7934 get: myGet,
7935 cachePolicy_UNSTABLE: myCachePolicy,
7936 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
7937 retainedBy_UNSTABLE: retainedBy
7938 });
7939 }
7940
7941 selectorCache.set(params, newSelector);
7942 setConfigDeletionHandler$3(newSelector.key, () => {
7943 selectorCache.delete(params);
7944 });
7945 return newSelector;
7946 };
7947}
7948/* eslint-enable no-redeclare */
7949
7950
7951var Recoil_selectorFamily = selectorFamily;
7952
7953// flowlint-next-line unclear-type:off
7954
7955
7956const constantSelector = Recoil_selectorFamily({
7957 key: '__constant',
7958 get: constant => () => constant,
7959 cachePolicyForParams_UNSTABLE: {
7960 equality: 'reference'
7961 }
7962}); // Function that returns a selector which always produces the
7963// same constant value. It may be called multiple times with the
7964// same value, based on reference equality, and will provide the
7965// same selector.
7966
7967function constSelector(constant) {
7968 return constantSelector(constant);
7969}
7970
7971var Recoil_constSelector = constSelector;
7972
7973// flowlint-next-line unclear-type:off
7974
7975
7976const throwingSelector = Recoil_selectorFamily({
7977 key: '__error',
7978 get: message => () => {
7979 throw Recoil_err(message);
7980 },
7981 // TODO Why?
7982 cachePolicyForParams_UNSTABLE: {
7983 equality: 'reference'
7984 }
7985}); // Function that returns a selector which always throws an error
7986// with the provided message.
7987
7988function errorSelector(message) {
7989 return throwingSelector(message);
7990}
7991
7992var Recoil_errorSelector = errorSelector;
7993
7994/**
7995 * Copyright (c) Facebook, Inc. and its affiliates.
7996 *
7997 * This source code is licensed under the MIT license found in the
7998 * LICENSE file in the root directory of this source tree.
7999 *
8000 * Wraps another recoil value and prevents writing to it.
8001 *
8002 * @emails oncall+recoil
8003 *
8004 * @format
8005 */
8006
8007function readOnlySelector(atom) {
8008 // flowlint-next-line unclear-type: off
8009 return atom;
8010}
8011
8012var Recoil_readOnlySelector = readOnlySelector;
8013
8014const {
8015 loadableWithError: loadableWithError$3,
8016 loadableWithPromise: loadableWithPromise$3,
8017 loadableWithValue: loadableWithValue$4
8018} = Recoil_Loadable$1;
8019
8020
8021
8022 /////////////////
8023// TRUTH TABLE
8024/////////////////
8025// Dependencies waitForNone waitForAny waitForAll waitForAllSettled
8026// [loading, loading] [Promise, Promise] Promise Promise Promise
8027// [value, loading] [value, Promise] [value, Promise] Promise Promise
8028// [value, value] [value, value] [value, value] [value, value] [value, value]
8029//
8030// [error, loading] [Error, Promise] [Error, Promise] Error Promise
8031// [error, error] [Error, Error] [Error, Error] Error [error, error]
8032// [value, error] [value, Error] [value, Error] Error [value, error]
8033// Issue parallel requests for all dependencies and return the current
8034// status if they have results, have some error, or are still pending.
8035
8036
8037function concurrentRequests(getRecoilValue, deps) {
8038 const results = Array(deps.length).fill(undefined);
8039 const exceptions = Array(deps.length).fill(undefined);
8040
8041 for (const [i, dep] of deps.entries()) {
8042 try {
8043 results[i] = getRecoilValue(dep);
8044 } catch (e) {
8045 // exceptions can either be Promises of pending results or real errors
8046 exceptions[i] = e;
8047 }
8048 }
8049
8050 return [results, exceptions];
8051}
8052
8053function isError(exp) {
8054 return exp != null && !Recoil_isPromise(exp);
8055}
8056
8057function unwrapDependencies(dependencies) {
8058 return Array.isArray(dependencies) ? dependencies : Object.getOwnPropertyNames(dependencies).map(key => dependencies[key]);
8059}
8060
8061function wrapResults(dependencies, results) {
8062 return Array.isArray(dependencies) ? results : // Object.getOwnPropertyNames() has consistent key ordering with ES6
8063 Object.getOwnPropertyNames(dependencies).reduce((out, key, idx) => ({ ...out,
8064 [key]: results[idx]
8065 }), {});
8066}
8067
8068function wrapLoadables(dependencies, results, exceptions) {
8069 const output = exceptions.map((exception, idx) => exception == null ? loadableWithValue$4(results[idx]) : Recoil_isPromise(exception) ? loadableWithPromise$3(exception) : loadableWithError$3(exception));
8070 return wrapResults(dependencies, output);
8071}
8072
8073function combineAsyncResultsWithSyncResults(syncResults, asyncResults) {
8074 return asyncResults.map((result, idx) =>
8075 /**
8076 * it's important we use === undefined as opposed to == null, because the
8077 * resolved value of the async promise could be `null`, in which case we
8078 * don't want to use syncResults[idx], which would be undefined. If async
8079 * promise resolves to `undefined`, that's ok because `syncResults[idx]`
8080 * will also be `undefined`. That's a little hacky, but it works.
8081 */
8082 result === undefined ? syncResults[idx] : result);
8083} // Selector that requests all dependencies in parallel and immediately returns
8084// current results without waiting.
8085
8086
8087const waitForNone = Recoil_selectorFamily({
8088 key: '__waitForNone',
8089 get: dependencies => ({
8090 get
8091 }) => {
8092 // Issue requests for all dependencies in parallel.
8093 const deps = unwrapDependencies(dependencies);
8094 const [results, exceptions] = concurrentRequests(get, deps); // Always return the current status of the results; never block.
8095
8096 return wrapLoadables(dependencies, results, exceptions);
8097 },
8098 dangerouslyAllowMutability: true
8099}); // Selector that requests all dependencies in parallel and waits for at least
8100// one to be available before returning results. It will only error if all
8101// dependencies have errors.
8102
8103const waitForAny = Recoil_selectorFamily({
8104 key: '__waitForAny',
8105 get: dependencies => ({
8106 get
8107 }) => {
8108 // Issue requests for all dependencies in parallel.
8109 // Exceptions can either be Promises of pending results or real errors
8110 const deps = unwrapDependencies(dependencies);
8111 const [results, exceptions] = concurrentRequests(get, deps); // If any results are available, value or error, return the current status
8112
8113 if (exceptions.some(exp => !Recoil_isPromise(exp))) {
8114 return wrapLoadables(dependencies, results, exceptions);
8115 } // Otherwise, return a promise that will resolve when the next result is
8116 // available, whichever one happens to be next. But, if all pending
8117 // dependencies end up with errors, then reject the promise.
8118
8119
8120 return new Promise(resolve => {
8121 for (const [i, exp] of exceptions.entries()) {
8122 if (Recoil_isPromise(exp)) {
8123 exp.then(result => {
8124 results[i] = result;
8125 exceptions[i] = undefined;
8126 resolve(wrapLoadables(dependencies, results, exceptions));
8127 }).catch(error => {
8128 exceptions[i] = error;
8129 resolve(wrapLoadables(dependencies, results, exceptions));
8130 });
8131 }
8132 }
8133 });
8134 },
8135 dangerouslyAllowMutability: true
8136}); // Selector that requests all dependencies in parallel and waits for all to be
8137// available before returning a value. It will error if any dependencies error.
8138
8139const waitForAll = Recoil_selectorFamily({
8140 key: '__waitForAll',
8141 get: dependencies => ({
8142 get
8143 }) => {
8144 // Issue requests for all dependencies in parallel.
8145 // Exceptions can either be Promises of pending results or real errors
8146 const deps = unwrapDependencies(dependencies);
8147 const [results, exceptions] = concurrentRequests(get, deps); // If all results are available, return the results
8148
8149 if (exceptions.every(exp => exp == null)) {
8150 return wrapResults(dependencies, results);
8151 } // If we have any errors, throw the first error
8152
8153
8154 const error = exceptions.find(isError);
8155
8156 if (error != null) {
8157 throw error;
8158 } // Otherwise, return a promise that will resolve when all results are available
8159
8160
8161 return Promise.all(exceptions).then(exceptionResults => wrapResults(dependencies, combineAsyncResultsWithSyncResults(results, exceptionResults)));
8162 },
8163 dangerouslyAllowMutability: true
8164});
8165const waitForAllSettled = Recoil_selectorFamily({
8166 key: '__waitForAllSettled',
8167 get: dependencies => ({
8168 get
8169 }) => {
8170 // Issue requests for all dependencies in parallel.
8171 // Exceptions can either be Promises of pending results or real errors
8172 const deps = unwrapDependencies(dependencies);
8173 const [results, exceptions] = concurrentRequests(get, deps); // If all results are available, return the results
8174
8175 if (exceptions.every(exp => !Recoil_isPromise(exp))) {
8176 return wrapLoadables(dependencies, results, exceptions);
8177 } // Wait for all results to settle
8178
8179
8180 return Promise.all(exceptions.map((exp, i) => Recoil_isPromise(exp) ? exp.then(result => {
8181 results[i] = result;
8182 exceptions[i] = undefined;
8183 }).catch(error => {
8184 results[i] = undefined;
8185 exceptions[i] = error;
8186 }) : null)) // Then wrap them as loadables
8187 .then(() => wrapLoadables(dependencies, results, exceptions));
8188 },
8189 dangerouslyAllowMutability: true
8190});
8191const noWait = Recoil_selectorFamily({
8192 key: '__noWait',
8193 get: dependency => ({
8194 get
8195 }) => {
8196 try {
8197 return loadableWithValue$4(get(dependency));
8198 } catch (exception) {
8199 return Recoil_isPromise(exception) ? loadableWithPromise$3(exception) : loadableWithError$3(exception);
8200 }
8201 },
8202 dangerouslyAllowMutability: true
8203});
8204var Recoil_WaitFor = {
8205 waitForNone,
8206 waitForAny,
8207 waitForAll,
8208 waitForAllSettled,
8209 noWait
8210};
8211
8212const {
8213 RecoilLoadable
8214} = Recoil_Loadable$1;
8215
8216const {
8217 DefaultValue: DefaultValue$3
8218} = Recoil_Node;
8219
8220const {
8221 RecoilRoot: RecoilRoot$2
8222} = Recoil_RecoilRoot_react;
8223
8224const {
8225 isRecoilValue: isRecoilValue$5
8226} = Recoil_RecoilValue$1;
8227
8228const {
8229 retentionZone: retentionZone$1
8230} = Recoil_RetentionZone;
8231
8232const {
8233 freshSnapshot: freshSnapshot$2
8234} = Recoil_Snapshot$1;
8235
8236const {
8237 useRecoilState: useRecoilState$1,
8238 useRecoilStateLoadable: useRecoilStateLoadable$1,
8239 useRecoilValue: useRecoilValue$1,
8240 useRecoilValueLoadable: useRecoilValueLoadable$1,
8241 useResetRecoilState: useResetRecoilState$1,
8242 useSetRecoilState: useSetRecoilState$1,
8243 useSetUnvalidatedAtomValues: useSetUnvalidatedAtomValues$1
8244} = Recoil_Hooks;
8245
8246const {
8247 useGotoRecoilSnapshot: useGotoRecoilSnapshot$2,
8248 useRecoilSnapshot: useRecoilSnapshot$1,
8249 useRecoilTransactionObserver: useRecoilTransactionObserver$1,
8250 useTransactionObservation_DEPRECATED: useTransactionObservation_DEPRECATED$1
8251} = Recoil_SnapshotHooks;
8252
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
8279const {
8280 noWait: noWait$1,
8281 waitForAll: waitForAll$1,
8282 waitForAllSettled: waitForAllSettled$1,
8283 waitForAny: waitForAny$1,
8284 waitForNone: waitForNone$1
8285} = Recoil_WaitFor;
8286
8287var Recoil_index = {
8288 // Types
8289 DefaultValue: DefaultValue$3,
8290 isRecoilValue: isRecoilValue$5,
8291 RecoilLoadable,
8292 // Recoil Root
8293 RecoilRoot: RecoilRoot$2,
8294 useRecoilBridgeAcrossReactRoots_UNSTABLE: Recoil_useRecoilBridgeAcrossReactRoots,
8295 // Atoms/Selectors
8296 atom: Recoil_atom,
8297 selector: Recoil_selector,
8298 // Convenience Atoms/Selectors
8299 atomFamily: Recoil_atomFamily,
8300 selectorFamily: Recoil_selectorFamily,
8301 constSelector: Recoil_constSelector,
8302 errorSelector: Recoil_errorSelector,
8303 readOnlySelector: Recoil_readOnlySelector,
8304 // Concurrency Helpers for Atoms/Selectors
8305 noWait: noWait$1,
8306 waitForNone: waitForNone$1,
8307 waitForAny: waitForAny$1,
8308 waitForAll: waitForAll$1,
8309 waitForAllSettled: waitForAllSettled$1,
8310 // Hooks for Atoms/Selectors
8311 useRecoilValue: useRecoilValue$1,
8312 useRecoilValueLoadable: useRecoilValueLoadable$1,
8313 useRecoilState: useRecoilState$1,
8314 useRecoilStateLoadable: useRecoilStateLoadable$1,
8315 useSetRecoilState: useSetRecoilState$1,
8316 useResetRecoilState: useResetRecoilState$1,
8317 useGetRecoilValueInfo_UNSTABLE: Recoil_useGetRecoilValueInfo,
8318 useRecoilRefresher_UNSTABLE: Recoil_useRecoilRefresher,
8319 // Hooks for complex operations
8320 useRecoilCallback: Recoil_useRecoilCallback,
8321 useRecoilTransaction_UNSTABLE: Recoil_useRecoilTransaction,
8322 // Snapshots
8323 useGotoRecoilSnapshot: useGotoRecoilSnapshot$2,
8324 useRecoilSnapshot: useRecoilSnapshot$1,
8325 useRecoilTransactionObserver_UNSTABLE: useRecoilTransactionObserver$1,
8326 useTransactionObservation_UNSTABLE: useTransactionObservation_DEPRECATED$1,
8327 useSetUnvalidatedAtomValues_UNSTABLE: useSetUnvalidatedAtomValues$1,
8328 snapshot_UNSTABLE: freshSnapshot$2,
8329 // Memory Management
8330 useRetain: Recoil_useRetain,
8331 retentionZone: retentionZone$1
8332};
8333var Recoil_index_1 = Recoil_index.DefaultValue;
8334var Recoil_index_2 = Recoil_index.isRecoilValue;
8335var Recoil_index_3 = Recoil_index.RecoilLoadable;
8336var Recoil_index_4 = Recoil_index.RecoilRoot;
8337var Recoil_index_5 = Recoil_index.useRecoilBridgeAcrossReactRoots_UNSTABLE;
8338var Recoil_index_6 = Recoil_index.atom;
8339var Recoil_index_7 = Recoil_index.selector;
8340var Recoil_index_8 = Recoil_index.atomFamily;
8341var Recoil_index_9 = Recoil_index.selectorFamily;
8342var Recoil_index_10 = Recoil_index.constSelector;
8343var Recoil_index_11 = Recoil_index.errorSelector;
8344var Recoil_index_12 = Recoil_index.readOnlySelector;
8345var Recoil_index_13 = Recoil_index.noWait;
8346var Recoil_index_14 = Recoil_index.waitForNone;
8347var Recoil_index_15 = Recoil_index.waitForAny;
8348var Recoil_index_16 = Recoil_index.waitForAll;
8349var Recoil_index_17 = Recoil_index.waitForAllSettled;
8350var Recoil_index_18 = Recoil_index.useRecoilValue;
8351var Recoil_index_19 = Recoil_index.useRecoilValueLoadable;
8352var Recoil_index_20 = Recoil_index.useRecoilState;
8353var Recoil_index_21 = Recoil_index.useRecoilStateLoadable;
8354var Recoil_index_22 = Recoil_index.useSetRecoilState;
8355var Recoil_index_23 = Recoil_index.useResetRecoilState;
8356var Recoil_index_24 = Recoil_index.useGetRecoilValueInfo_UNSTABLE;
8357var Recoil_index_25 = Recoil_index.useRecoilRefresher_UNSTABLE;
8358var Recoil_index_26 = Recoil_index.useRecoilCallback;
8359var Recoil_index_27 = Recoil_index.useRecoilTransaction_UNSTABLE;
8360var Recoil_index_28 = Recoil_index.useGotoRecoilSnapshot;
8361var Recoil_index_29 = Recoil_index.useRecoilSnapshot;
8362var Recoil_index_30 = Recoil_index.useRecoilTransactionObserver_UNSTABLE;
8363var Recoil_index_31 = Recoil_index.useTransactionObservation_UNSTABLE;
8364var Recoil_index_32 = Recoil_index.useSetUnvalidatedAtomValues_UNSTABLE;
8365var Recoil_index_33 = Recoil_index.snapshot_UNSTABLE;
8366var Recoil_index_34 = Recoil_index.useRetain;
8367var Recoil_index_35 = Recoil_index.retentionZone;
8368
8369export default Recoil_index;
8370export { 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 };