UNPKG

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