/** @license React v0.9.0 * 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'; // ATTENTION // When adding new symbols to this file, // Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols' // 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 REACT_ELEMENT_TYPE = 0xeac7; var REACT_PORTAL_TYPE = 0xeaca; var REACT_FRAGMENT_TYPE = 0xeacb; var REACT_STRICT_MODE_TYPE = 0xeacc; var REACT_PROFILER_TYPE = 0xead2; var REACT_PROVIDER_TYPE = 0xeacd; var REACT_CONTEXT_TYPE = 0xeace; var REACT_FORWARD_REF_TYPE = 0xead0; var REACT_SUSPENSE_TYPE = 0xead1; var REACT_SUSPENSE_LIST_TYPE = 0xead8; var REACT_MEMO_TYPE = 0xead3; var REACT_LAZY_TYPE = 0xead4; var REACT_BLOCK_TYPE = 0xead9; var REACT_SERVER_BLOCK_TYPE = 0xeada; var REACT_FUNDAMENTAL_TYPE = 0xead5; var REACT_SCOPE_TYPE = 0xead7; var REACT_OPAQUE_ID_TYPE = 0xeae0; var REACT_DEBUG_TRACING_MODE_TYPE = 0xeae1; var REACT_OFFSCREEN_TYPE = 0xeae2; var REACT_LEGACY_HIDDEN_TYPE = 0xeae3; if (typeof Symbol === 'function' && Symbol.for) { var symbolFor = Symbol.for; REACT_ELEMENT_TYPE = symbolFor('react.element'); REACT_PORTAL_TYPE = symbolFor('react.portal'); REACT_FRAGMENT_TYPE = symbolFor('react.fragment'); REACT_STRICT_MODE_TYPE = symbolFor('react.strict_mode'); REACT_PROFILER_TYPE = symbolFor('react.profiler'); REACT_PROVIDER_TYPE = symbolFor('react.provider'); REACT_CONTEXT_TYPE = symbolFor('react.context'); REACT_FORWARD_REF_TYPE = symbolFor('react.forward_ref'); REACT_SUSPENSE_TYPE = symbolFor('react.suspense'); REACT_SUSPENSE_LIST_TYPE = symbolFor('react.suspense_list'); REACT_MEMO_TYPE = symbolFor('react.memo'); REACT_LAZY_TYPE = symbolFor('react.lazy'); REACT_BLOCK_TYPE = symbolFor('react.block'); REACT_SERVER_BLOCK_TYPE = symbolFor('react.server.block'); REACT_FUNDAMENTAL_TYPE = symbolFor('react.fundamental'); REACT_SCOPE_TYPE = symbolFor('react.scope'); REACT_OPAQUE_ID_TYPE = symbolFor('react.opaque.id'); REACT_DEBUG_TRACING_MODE_TYPE = symbolFor('react.debug_trace_mode'); REACT_OFFSCREEN_TYPE = symbolFor('react.offscreen'); REACT_LEGACY_HIDDEN_TYPE = symbolFor('react.legacy_hidden'); } 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 remember it so we can retry on edit. var failedRoots = new Set(); // In environments that support WeakMap, we also remember the last element for every root. // It needs to be weak because we do this even for roots that failed to mount. // If there is no WeakMap, we won't attempt to do retrying. // $FlowIssue var rootElements = // $FlowIssue typeof WeakMap === 'function' ? new WeakMap() : null; var isPerformingRefresh = 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); } // If we didn't care about IE11, we could use new Map/Set(iterable). function cloneMap(map) { var clone = new Map(); map.forEach(function (value, key) { clone.set(key, value); }); return clone; } function cloneSet(set) { var clone = new Set(); set.forEach(function (value) { clone.add(value); }); return clone; } function performReactRefresh() { if (pendingUpdates.length === 0) { return null; } if (isPerformingRefresh) { return null; } isPerformingRefresh = true; try { 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; // We snapshot maps and sets that are mutated during commits. // If we don't do this, there is a risk they will be mutated while // we iterate over them. For example, trying to recover a failed root // may cause another root to be added to the failed list -- an infinite loop. var failedRootsSnapshot = cloneSet(failedRoots); var mountedRootsSnapshot = cloneSet(mountedRoots); var helpersByRootSnapshot = cloneMap(helpersByRoot); failedRootsSnapshot.forEach(function (root) { var helpers = helpersByRootSnapshot.get(root); if (helpers === undefined) { throw new Error('Could not find helpers for a root. This is a bug in React Refresh.'); } if (!failedRoots.has(root)) {// No longer failed. } if (rootElements === null) { return; } if (!rootElements.has(root)) { return; } var element = rootElements.get(root); try { helpers.scheduleRoot(root, element); } catch (err) { if (!didError) { didError = true; firstError = err; } // Keep trying other roots. } }); mountedRootsSnapshot.forEach(function (root) { var helpers = helpersByRootSnapshot.get(root); if (helpers === undefined) { throw new Error('Could not find helpers for a root. This is a bug in React Refresh.'); } if (!mountedRoots.has(root)) {// No longer mounted. } try { helpers.scheduleRefresh(root, update); } catch (err) { if (!didError) { didError = true; firstError = err; } // Keep trying other roots. } }); if (didError) { throw firstError; } return update; } finally { isPerformingRefresh = false; } } 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 = { renderers: new Map(), supportsFiber: true, inject: function (injected) { return nextID++; }, onScheduleFiberRoot: function (id, root, children) {}, 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; }; // Do the same for any already injected roots. // This is useful if ReactDOM has already been initialized. // https://github.com/facebook/react/issues/17626 hook.renderers.forEach(function (injected, id) { if (typeof injected.scheduleRefresh === 'function' && typeof injected.setRefreshHandler === 'function') { // This version supports React Refresh. helpersByRendererID.set(id, injected); } }); // We also want to track currently mounted roots. var oldOnCommitFiberRoot = hook.onCommitFiberRoot; var oldOnScheduleFiberRoot = hook.onScheduleFiberRoot || function () {}; hook.onScheduleFiberRoot = function (id, root, children) { if (!isPerformingRefresh) { // If it was intentionally scheduled, don't attempt to restore. // This includes intentionally scheduled unmounts. failedRoots.delete(root); if (rootElements !== null) { rootElements.set(root, children); } } return oldOnScheduleFiberRoot.apply(this, arguments); }; 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) ; else if (wasMounted && !isMounted) { // Unmount an existing root. mountedRoots.delete(root); if (didError) { // We'll remount it on future edits. failedRoots.add(root); } else { helpersByRoot.delete(root); } } else if (!wasMounted && !isMounted) { if (didError) { // We'll remount it on future edits. failedRoots.add(root); } } } else { // Mount a new root. mountedRoots.add(root); } return oldOnCommitFiberRoot.apply(this, arguments); }; } } function hasUnrecoverableErrors() { // TODO: delete this after removing dependency in RN. return false; } // 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