/** @license React vundefined * react-refresh-runtime.development.js * * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ 'use strict'; if (process.env.NODE_ENV !== "production") { (function() { 'use strict'; // The Symbol used to tag the ReactElement-like types. If there is no native Symbol // nor polyfill, then a plain number is used for performance. var hasSymbol = typeof Symbol === 'function' && Symbol.for; // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary // (unstable) APIs that have been removed. Can we remove the symbols? var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; // We never remove these associations. // It's OK to reference families, but use WeakMap/Set for types. var allFamiliesByID = new Map(); var allFamiliesByType = new PossiblyWeakMap(); var allSignaturesByType = new PossiblyWeakMap(); // This WeakMap is read by React, so we only put families // that have actually been edited here. This keeps checks fast. // $FlowIssue var updatedFamiliesByType = new PossiblyWeakMap(); // This is cleared on every performReactRefresh() call. // It is an array of [Family, NextType] tuples. var pendingUpdates = []; // This is injected by the renderer via DevTools global hook. var helpersByRendererID = new Map(); var helpersByRoot = new Map(); // We keep track of mounted roots so we can schedule updates. var mountedRoots = new Set(); // If a root captures an error, we add its element to this Map so we can retry on edit. var failedRoots = new Map(); var didSomeRootFailOnMount = false; function computeFullKey(signature) { if (signature.fullKey !== null) { return signature.fullKey; } var fullKey = signature.ownKey; var hooks; try { hooks = signature.getCustomHooks(); } catch (err) { // This can happen in an edge case, e.g. if expression like Foo.useSomething // depends on Foo which is lazily initialized during rendering. // In that case just assume we'll have to remount. signature.forceReset = true; signature.fullKey = fullKey; return fullKey; } for (var i = 0; i < hooks.length; i++) { var hook = hooks[i]; if (typeof hook !== 'function') { // Something's wrong. Assume we need to remount. signature.forceReset = true; signature.fullKey = fullKey; return fullKey; } var nestedHookSignature = allSignaturesByType.get(hook); if (nestedHookSignature === undefined) { // No signature means Hook wasn't in the source code, e.g. in a library. // We'll skip it because we can assume it won't change during this session. continue; } var nestedHookKey = computeFullKey(nestedHookSignature); if (nestedHookSignature.forceReset) { signature.forceReset = true; } fullKey += '\n---\n' + nestedHookKey; } signature.fullKey = fullKey; return fullKey; } function haveEqualSignatures(prevType, nextType) { var prevSignature = allSignaturesByType.get(prevType); var nextSignature = allSignaturesByType.get(nextType); if (prevSignature === undefined && nextSignature === undefined) { return true; } if (prevSignature === undefined || nextSignature === undefined) { return false; } if (computeFullKey(prevSignature) !== computeFullKey(nextSignature)) { return false; } if (nextSignature.forceReset) { return false; } return true; } function isReactClass(type) { return type.prototype && type.prototype.isReactComponent; } function canPreserveStateBetween(prevType, nextType) { if (isReactClass(prevType) || isReactClass(nextType)) { return false; } if (haveEqualSignatures(prevType, nextType)) { return true; } return false; } function resolveFamily(type) { // Only check updated types to keep lookups fast. return updatedFamiliesByType.get(type); } function performReactRefresh() { { if (pendingUpdates.length === 0) { return null; } var staleFamilies = new Set(); var updatedFamilies = new Set(); var updates = pendingUpdates; pendingUpdates = []; updates.forEach(function (_ref) { var family = _ref[0], nextType = _ref[1]; // Now that we got a real edit, we can create associations // that will be read by the React reconciler. var prevType = family.current; updatedFamiliesByType.set(prevType, family); updatedFamiliesByType.set(nextType, family); family.current = nextType; // Determine whether this should be a re-render or a re-mount. if (canPreserveStateBetween(prevType, nextType)) { updatedFamilies.add(family); } else { staleFamilies.add(family); } }); // TODO: rename these fields to something more meaningful. var update = { updatedFamilies: updatedFamilies, // Families that will re-render preserving state staleFamilies: staleFamilies // Families that will be remounted }; helpersByRendererID.forEach(function (helpers) { // Even if there are no roots, set the handler on first update. // This ensures that if *new* roots are mounted, they'll use the resolve handler. helpers.setRefreshHandler(resolveFamily); }); var didError = false; var firstError = null; failedRoots.forEach(function (element, root) { var helpers = helpersByRoot.get(root); if (helpers === undefined) { throw new Error('Could not find helpers for a root. This is a bug in React Refresh.'); } try { helpers.scheduleRoot(root, element); } catch (err) { if (!didError) { didError = true; firstError = err; } // Keep trying other roots. } }); mountedRoots.forEach(function (root) { var helpers = helpersByRoot.get(root); if (helpers === undefined) { throw new Error('Could not find helpers for a root. This is a bug in React Refresh.'); } try { helpers.scheduleRefresh(root, update); } catch (err) { if (!didError) { didError = true; firstError = err; } // Keep trying other roots. } }); if (didError) { throw firstError; } return update; } } function register(type, id) { { if (type === null) { return; } if (typeof type !== 'function' && typeof type !== 'object') { return; } // This can happen in an edge case, e.g. if we register // return value of a HOC but it returns a cached component. // Ignore anything but the first registration for each type. if (allFamiliesByType.has(type)) { return; } // Create family or remember to update it. // None of this bookkeeping affects reconciliation // until the first performReactRefresh() call above. var family = allFamiliesByID.get(id); if (family === undefined) { family = { current: type }; allFamiliesByID.set(id, family); } else { pendingUpdates.push([family, type]); } allFamiliesByType.set(type, family); // Visit inner types because we might not have registered them. if (typeof type === 'object' && type !== null) { switch (type.$$typeof) { case REACT_FORWARD_REF_TYPE: register(type.render, id + '$render'); break; case REACT_MEMO_TYPE: register(type.type, id + '$type'); break; } } } } function setSignature(type, key) { var forceReset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var getCustomHooks = arguments.length > 3 ? arguments[3] : undefined; { allSignaturesByType.set(type, { forceReset: forceReset, ownKey: key, fullKey: null, getCustomHooks: getCustomHooks || function () { return []; } }); } } // This is lazily called during first render for a type. // It captures Hook list at that time so inline requires don't break comparisons. function collectCustomHooksForSignature(type) { { var signature = allSignaturesByType.get(type); if (signature !== undefined) { computeFullKey(signature); } } } function getFamilyByID(id) { { return allFamiliesByID.get(id); } } function getFamilyByType(type) { { return allFamiliesByType.get(type); } } function findAffectedHostInstances(families) { { var affectedInstances = new Set(); mountedRoots.forEach(function (root) { var helpers = helpersByRoot.get(root); if (helpers === undefined) { throw new Error('Could not find helpers for a root. This is a bug in React Refresh.'); } var instancesForRoot = helpers.findHostInstancesForRefresh(root, families); instancesForRoot.forEach(function (inst) { affectedInstances.add(inst); }); }); return affectedInstances; } } function injectIntoGlobalHook(globalObject) { { // For React Native, the global hook will be set up by require('react-devtools-core'). // That code will run before us. So we need to monkeypatch functions on existing hook. // For React Web, the global hook will be set up by the extension. // This will also run before us. var hook = globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__; if (hook === undefined) { // However, if there is no DevTools extension, we'll need to set up the global hook ourselves. // Note that in this case it's important that renderer code runs *after* this method call. // Otherwise, the renderer will think that there is no global hook, and won't do the injection. var nextID = 0; globalObject.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook = { supportsFiber: true, inject: function (injected) { return nextID++; }, onCommitFiberRoot: function (id, root, maybePriorityLevel, didError) {}, onCommitFiberUnmount: function () {} }; } // Here, we just want to get a reference to scheduleRefresh. var oldInject = hook.inject; hook.inject = function (injected) { var id = oldInject.apply(this, arguments); if (typeof injected.scheduleRefresh === 'function' && typeof injected.setRefreshHandler === 'function') { // This version supports React Refresh. helpersByRendererID.set(id, injected); } return id; }; // We also want to track currently mounted roots. var oldOnCommitFiberRoot = hook.onCommitFiberRoot; hook.onCommitFiberRoot = function (id, root, maybePriorityLevel, didError) { var helpers = helpersByRendererID.get(id); if (helpers === undefined) { return; } helpersByRoot.set(root, helpers); var current = root.current; var alternate = current.alternate; // We need to determine whether this root has just (un)mounted. // This logic is copy-pasted from similar logic in the DevTools backend. // If this breaks with some refactoring, you'll want to update DevTools too. if (alternate !== null) { var wasMounted = alternate.memoizedState != null && alternate.memoizedState.element != null; var isMounted = current.memoizedState != null && current.memoizedState.element != null; if (!wasMounted && isMounted) { // Mount a new root. mountedRoots.add(root); failedRoots.delete(root); } else if (wasMounted && isMounted) {// Update an existing root. // This doesn't affect our mounted root Set. } else if (wasMounted && !isMounted) { // Unmount an existing root. mountedRoots.delete(root); if (didError) { // We'll remount it on future edits. // Remember what was rendered so we can restore it. failedRoots.set(root, alternate.memoizedState.element); } else { helpersByRoot.delete(root); } } else if (!wasMounted && !isMounted) { if (didError && !failedRoots.has(root)) { // The root had an error during the initial mount. // We can't read its last element from the memoized state // because there was no previously committed alternate. // Ideally, it would be nice if we had a way to extract // the last attempted rendered element, but accessing the update queue // would tie this package too closely to the reconciler version. // So instead, we just set a flag. // TODO: Maybe we could fix this as the same time as when we fix // DevTools to not depend on `alternate.memoizedState.element`. didSomeRootFailOnMount = true; } } } else { // Mount a new root. mountedRoots.add(root); } return oldOnCommitFiberRoot.apply(this, arguments); }; } } function hasUnrecoverableErrors() { return didSomeRootFailOnMount; } // Exposed for testing. function _getMountedRootCount() { { return mountedRoots.size; } } // This is a wrapper over more primitive functions for setting signature. // Signatures let us decide whether the Hook order has changed on refresh. // // This function is intended to be used as a transform target, e.g.: // var _s = createSignatureFunctionForTransform() // // function Hello() { // const [foo, setFoo] = useState(0); // const value = useCustomHook(); // _s(); /* Second call triggers collecting the custom Hook list. // * This doesn't happen during the module evaluation because we // * don't want to change the module order with inline requires. // * Next calls are noops. */ // return