import {
ComponentFilterDisplayName,
ComponentFilterElementType,
ComponentFilterHOC,
ComponentFilterLocation,
ElementTypeClass,
ElementTypeContext,
ElementTypeFunction,
ElementTypeForwardRef,
ElementTypeHostComponent,
ElementTypeMemo,
ElementTypeOtherOrUnknown,
ElementTypeProfiler,
ElementTypeRoot,
ElementTypeSuspense,
ElementTypeSuspenseList,
ElementTypeTracingMarker,
StrictMode,
} from 'react-devtools-shared/src/frontend/types';
import {
deletePathInObject,
getDisplayName,
getWrappedDisplayName,
getDefaultComponentFilters,
getInObject,
getUID,
renamePathInObject,
setInObject,
utfEncodeString,
filterOutLocationComponentFilters,
} from 'react-devtools-shared/src/utils';
import {sessionStorageGetItem} from 'react-devtools-shared/src/storage';
import {
gt,
gte,
parseSourceFromComponentStack,
serializeToString,
} from 'react-devtools-shared/src/backend/utils';
import {
cleanForBridge,
copyWithDelete,
copyWithRename,
copyWithSet,
getEffectDurations,
} from './utils';
import {
__DEBUG__,
PROFILING_FLAG_BASIC_SUPPORT,
PROFILING_FLAG_TIMELINE_SUPPORT,
SESSION_STORAGE_RELOAD_AND_PROFILE_KEY,
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
TREE_OPERATION_ADD,
TREE_OPERATION_REMOVE,
TREE_OPERATION_REMOVE_ROOT,
TREE_OPERATION_REORDER_CHILDREN,
TREE_OPERATION_SET_SUBTREE_MODE,
TREE_OPERATION_UPDATE_ERRORS_OR_WARNINGS,
TREE_OPERATION_UPDATE_TREE_BASE_DURATION,
} from '../constants';
import {inspectHooksOfFiber} from 'react-debug-tools';
import {
patchConsoleUsingWindowValues,
registerRenderer as registerRendererWithConsole,
patchForStrictMode as patchConsoleForStrictMode,
unpatchForStrictMode as unpatchConsoleForStrictMode,
} from './console';
import {
CONCURRENT_MODE_NUMBER,
CONCURRENT_MODE_SYMBOL_STRING,
DEPRECATED_ASYNC_MODE_SYMBOL_STRING,
PROVIDER_NUMBER,
PROVIDER_SYMBOL_STRING,
CONTEXT_NUMBER,
CONTEXT_SYMBOL_STRING,
CONSUMER_SYMBOL_STRING,
STRICT_MODE_NUMBER,
STRICT_MODE_SYMBOL_STRING,
PROFILER_NUMBER,
PROFILER_SYMBOL_STRING,
REACT_MEMO_CACHE_SENTINEL,
SCOPE_NUMBER,
SCOPE_SYMBOL_STRING,
FORWARD_REF_NUMBER,
FORWARD_REF_SYMBOL_STRING,
MEMO_NUMBER,
MEMO_SYMBOL_STRING,
SERVER_CONTEXT_SYMBOL_STRING,
} from './ReactSymbols';
import {format} from './utils';
import {enableStyleXFeatures} from 'react-devtools-feature-flags';
import is from 'shared/objectIs';
import hasOwnProperty from 'shared/hasOwnProperty';
import {getStyleXData} from './StyleX/utils';
import {createProfilingHooks} from './profilingHooks';
import type {GetTimelineData, ToggleProfilingStatus} from './profilingHooks';
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import type {
ChangeDescription,
CommitDataBackend,
DevToolsHook,
InspectedElement,
InspectedElementPayload,
InstanceAndStyle,
NativeType,
PathFrame,
PathMatch,
ProfilingDataBackend,
ProfilingDataForRootBackend,
ReactRenderer,
RendererInterface,
SerializedElement,
WorkTagMap,
CurrentDispatcherRef,
LegacyDispatcherRef,
} from './types';
import type {
ComponentFilter,
ElementType,
Plugins,
} from 'react-devtools-shared/src/frontend/types';
import type {Source} from 'react-devtools-shared/src/shared/types';
import {getStackByFiberInDevAndProd} from './DevToolsFiberComponentStack';
type getDisplayNameForFiberType = (fiber: Fiber) => string | null;
type getTypeSymbolType = (type: any) => symbol | number;
type ReactPriorityLevelsType = {
ImmediatePriority: number,
UserBlockingPriority: number,
NormalPriority: number,
LowPriority: number,
IdlePriority: number,
NoPriority: number,
};
export function getDispatcherRef(renderer: {
+currentDispatcherRef?: LegacyDispatcherRef | CurrentDispatcherRef,
...
}): void | CurrentDispatcherRef {
if (renderer.currentDispatcherRef === undefined) {
return undefined;
}
const injectedRef = renderer.currentDispatcherRef;
if (
typeof injectedRef.H === 'undefined' &&
typeof injectedRef.current !== 'undefined'
) {
return {
get H() {
return (injectedRef: any).current;
},
set H(value) {
(injectedRef: any).current = value;
},
};
}
return (injectedRef: any);
}
function getFiberFlags(fiber: Fiber): number {
return fiber.flags !== undefined ? fiber.flags : (fiber: any).effectTag;
}
const getCurrentTime =
typeof performance === 'object' && typeof performance.now === 'function'
? () => performance.now()
: () => Date.now();
export function getInternalReactConstants(version: string): {
getDisplayNameForFiber: getDisplayNameForFiberType,
getTypeSymbol: getTypeSymbolType,
ReactPriorityLevels: ReactPriorityLevelsType,
ReactTypeOfWork: WorkTagMap,
StrictModeBits: number,
} {
let ReactPriorityLevels: ReactPriorityLevelsType = {
ImmediatePriority: 99,
UserBlockingPriority: 98,
NormalPriority: 97,
LowPriority: 96,
IdlePriority: 95,
NoPriority: 90,
};
if (gt(version, '17.0.2')) {
ReactPriorityLevels = {
ImmediatePriority: 1,
UserBlockingPriority: 2,
NormalPriority: 3,
LowPriority: 4,
IdlePriority: 5,
NoPriority: 0,
};
}
let StrictModeBits = 0;
if (gte(version, '18.0.0-alpha')) {
StrictModeBits = 0b011000;
} else if (gte(version, '16.9.0')) {
StrictModeBits = 0b1;
} else if (gte(version, '16.3.0')) {
StrictModeBits = 0b10;
}
let ReactTypeOfWork: WorkTagMap = ((null: any): WorkTagMap);
if (gt(version, '17.0.1')) {
ReactTypeOfWork = {
CacheComponent: 24,
ClassComponent: 1,
ContextConsumer: 9,
ContextProvider: 10,
CoroutineComponent: -1,
CoroutineHandlerPhase: -1,
DehydratedSuspenseComponent: 18,
ForwardRef: 11,
Fragment: 7,
FunctionComponent: 0,
HostComponent: 5,
HostPortal: 4,
HostRoot: 3,
HostHoistable: 26,
HostSingleton: 27,
HostText: 6,
IncompleteClassComponent: 17,
IncompleteFunctionComponent: 28,
IndeterminateComponent: 2,
LazyComponent: 16,
LegacyHiddenComponent: 23,
MemoComponent: 14,
Mode: 8,
OffscreenComponent: 22,
Profiler: 12,
ScopeComponent: 21,
SimpleMemoComponent: 15,
SuspenseComponent: 13,
SuspenseListComponent: 19,
TracingMarkerComponent: 25,
YieldComponent: -1,
Throw: 29,
};
} else if (gte(version, '17.0.0-alpha')) {
ReactTypeOfWork = {
CacheComponent: -1,
ClassComponent: 1,
ContextConsumer: 9,
ContextProvider: 10,
CoroutineComponent: -1,
CoroutineHandlerPhase: -1,
DehydratedSuspenseComponent: 18,
ForwardRef: 11,
Fragment: 7,
FunctionComponent: 0,
HostComponent: 5,
HostPortal: 4,
HostRoot: 3,
HostHoistable: -1,
HostSingleton: -1,
HostText: 6,
IncompleteClassComponent: 17,
IncompleteFunctionComponent: -1,
IndeterminateComponent: 2,
LazyComponent: 16,
LegacyHiddenComponent: 24,
MemoComponent: 14,
Mode: 8,
OffscreenComponent: 23,
Profiler: 12,
ScopeComponent: 21,
SimpleMemoComponent: 15,
SuspenseComponent: 13,
SuspenseListComponent: 19,
TracingMarkerComponent: -1,
YieldComponent: -1,
Throw: -1,
};
} else if (gte(version, '16.6.0-beta.0')) {
ReactTypeOfWork = {
CacheComponent: -1,
ClassComponent: 1,
ContextConsumer: 9,
ContextProvider: 10,
CoroutineComponent: -1,
CoroutineHandlerPhase: -1,
DehydratedSuspenseComponent: 18,
ForwardRef: 11,
Fragment: 7,
FunctionComponent: 0,
HostComponent: 5,
HostPortal: 4,
HostRoot: 3,
HostHoistable: -1,
HostSingleton: -1,
HostText: 6,
IncompleteClassComponent: 17,
IncompleteFunctionComponent: -1,
IndeterminateComponent: 2,
LazyComponent: 16,
LegacyHiddenComponent: -1,
MemoComponent: 14,
Mode: 8,
OffscreenComponent: -1,
Profiler: 12,
ScopeComponent: -1,
SimpleMemoComponent: 15,
SuspenseComponent: 13,
SuspenseListComponent: 19,
TracingMarkerComponent: -1,
YieldComponent: -1,
Throw: -1,
};
} else if (gte(version, '16.4.3-alpha')) {
ReactTypeOfWork = {
CacheComponent: -1,
ClassComponent: 2,
ContextConsumer: 11,
ContextProvider: 12,
CoroutineComponent: -1,
CoroutineHandlerPhase: -1,
DehydratedSuspenseComponent: -1,
ForwardRef: 13,
Fragment: 9,
FunctionComponent: 0,
HostComponent: 7,
HostPortal: 6,
HostRoot: 5,
HostHoistable: -1,
HostSingleton: -1,
HostText: 8,
IncompleteClassComponent: -1,
IncompleteFunctionComponent: -1,
IndeterminateComponent: 4,
LazyComponent: -1,
LegacyHiddenComponent: -1,
MemoComponent: -1,
Mode: 10,
OffscreenComponent: -1,
Profiler: 15,
ScopeComponent: -1,
SimpleMemoComponent: -1,
SuspenseComponent: 16,
SuspenseListComponent: -1,
TracingMarkerComponent: -1,
YieldComponent: -1,
Throw: -1,
};
} else {
ReactTypeOfWork = {
CacheComponent: -1,
ClassComponent: 2,
ContextConsumer: 12,
ContextProvider: 13,
CoroutineComponent: 7,
CoroutineHandlerPhase: 8,
DehydratedSuspenseComponent: -1,
ForwardRef: 14,
Fragment: 10,
FunctionComponent: 1,
HostComponent: 5,
HostPortal: 4,
HostRoot: 3,
HostHoistable: -1,
HostSingleton: -1,
HostText: 6,
IncompleteClassComponent: -1,
IncompleteFunctionComponent: -1,
IndeterminateComponent: 0,
LazyComponent: -1,
LegacyHiddenComponent: -1,
MemoComponent: -1,
Mode: 11,
OffscreenComponent: -1,
Profiler: 15,
ScopeComponent: -1,
SimpleMemoComponent: -1,
SuspenseComponent: 16,
SuspenseListComponent: -1,
TracingMarkerComponent: -1,
YieldComponent: 9,
Throw: -1,
};
}
function getTypeSymbol(type: any): symbol | number {
const symbolOrNumber =
typeof type === 'object' && type !== null ? type.$$typeof : type;
return typeof symbolOrNumber === 'symbol'
?
symbolOrNumber.toString()
: symbolOrNumber;
}
const {
CacheComponent,
ClassComponent,
IncompleteClassComponent,
IncompleteFunctionComponent,
FunctionComponent,
IndeterminateComponent,
ForwardRef,
HostRoot,
HostHoistable,
HostSingleton,
HostComponent,
HostPortal,
HostText,
Fragment,
LazyComponent,
LegacyHiddenComponent,
MemoComponent,
OffscreenComponent,
Profiler,
ScopeComponent,
SimpleMemoComponent,
SuspenseComponent,
SuspenseListComponent,
TracingMarkerComponent,
Throw,
} = ReactTypeOfWork;
function resolveFiberType(type: any): $FlowFixMe {
const typeSymbol = getTypeSymbol(type);
switch (typeSymbol) {
case MEMO_NUMBER:
case MEMO_SYMBOL_STRING:
return resolveFiberType(type.type);
case FORWARD_REF_NUMBER:
case FORWARD_REF_SYMBOL_STRING:
return type.render;
default:
return type;
}
}
function getDisplayNameForFiber(
fiber: Fiber,
shouldSkipForgetCheck: boolean = false,
): string | null {
const {elementType, type, tag} = fiber;
let resolvedType = type;
if (typeof type === 'object' && type !== null) {
resolvedType = resolveFiberType(type);
}
let resolvedContext: any = null;
if (
!shouldSkipForgetCheck &&
(fiber.updateQueue?.memoCache != null ||
fiber.memoizedState?.memoizedState?.[REACT_MEMO_CACHE_SENTINEL])
) {
const displayNameWithoutForgetWrapper = getDisplayNameForFiber(
fiber,
true,
);
if (displayNameWithoutForgetWrapper == null) {
return null;
}
return `Forget(${displayNameWithoutForgetWrapper})`;
}
switch (tag) {
case CacheComponent:
return 'Cache';
case ClassComponent:
case IncompleteClassComponent:
case IncompleteFunctionComponent:
case FunctionComponent:
case IndeterminateComponent:
return getDisplayName(resolvedType);
case ForwardRef:
return getWrappedDisplayName(
elementType,
resolvedType,
'ForwardRef',
'Anonymous',
);
case HostRoot:
const fiberRoot = fiber.stateNode;
if (fiberRoot != null && fiberRoot._debugRootType !== null) {
return fiberRoot._debugRootType;
}
return null;
case HostComponent:
case HostSingleton:
case HostHoistable:
return type;
case HostPortal:
case HostText:
return null;
case Fragment:
return 'Fragment';
case LazyComponent:
return 'Lazy';
case MemoComponent:
case SimpleMemoComponent:
return getWrappedDisplayName(
elementType,
resolvedType,
'Memo',
'Anonymous',
);
case SuspenseComponent:
return 'Suspense';
case LegacyHiddenComponent:
return 'LegacyHidden';
case OffscreenComponent:
return 'Offscreen';
case ScopeComponent:
return 'Scope';
case SuspenseListComponent:
return 'SuspenseList';
case Profiler:
return 'Profiler';
case TracingMarkerComponent:
return 'TracingMarker';
case Throw:
return 'Error';
default:
const typeSymbol = getTypeSymbol(type);
switch (typeSymbol) {
case CONCURRENT_MODE_NUMBER:
case CONCURRENT_MODE_SYMBOL_STRING:
case DEPRECATED_ASYNC_MODE_SYMBOL_STRING:
return null;
case PROVIDER_NUMBER:
case PROVIDER_SYMBOL_STRING:
resolvedContext = fiber.type._context || fiber.type.context;
return `${resolvedContext.displayName || 'Context'}.Provider`;
case CONTEXT_NUMBER:
case CONTEXT_SYMBOL_STRING:
case SERVER_CONTEXT_SYMBOL_STRING:
if (
fiber.type._context === undefined &&
fiber.type.Provider === fiber.type
) {
resolvedContext = fiber.type;
return `${resolvedContext.displayName || 'Context'}.Provider`;
}
resolvedContext = fiber.type._context || fiber.type;
return `${resolvedContext.displayName || 'Context'}.Consumer`;
case CONSUMER_SYMBOL_STRING:
resolvedContext = fiber.type._context;
return `${resolvedContext.displayName || 'Context'}.Consumer`;
case STRICT_MODE_NUMBER:
case STRICT_MODE_SYMBOL_STRING:
return null;
case PROFILER_NUMBER:
case PROFILER_SYMBOL_STRING:
return `Profiler(${fiber.memoizedProps.id})`;
case SCOPE_NUMBER:
case SCOPE_SYMBOL_STRING:
return 'Scope';
default:
return null;
}
}
}
return {
getDisplayNameForFiber,
getTypeSymbol,
ReactPriorityLevels,
ReactTypeOfWork,
StrictModeBits,
};
}
const fiberToIDMap: Map<Fiber, number> = new Map();
const idToArbitraryFiberMap: Map<number, Fiber> = new Map();
const fiberToComponentStackMap: WeakMap<Fiber, string> = new WeakMap();
export function attach(
hook: DevToolsHook,
rendererID: number,
renderer: ReactRenderer,
global: Object,
): RendererInterface {
const version = renderer.reconcilerVersion || renderer.version;
const {
getDisplayNameForFiber,
getTypeSymbol,
ReactPriorityLevels,
ReactTypeOfWork,
StrictModeBits,
} = getInternalReactConstants(version);
const {
CacheComponent,
ClassComponent,
ContextConsumer,
DehydratedSuspenseComponent,
ForwardRef,
Fragment,
FunctionComponent,
HostRoot,
HostHoistable,
HostSingleton,
HostPortal,
HostComponent,
HostText,
IncompleteClassComponent,
IncompleteFunctionComponent,
IndeterminateComponent,
LegacyHiddenComponent,
MemoComponent,
OffscreenComponent,
SimpleMemoComponent,
SuspenseComponent,
SuspenseListComponent,
TracingMarkerComponent,
Throw,
} = ReactTypeOfWork;
const {
ImmediatePriority,
UserBlockingPriority,
NormalPriority,
LowPriority,
IdlePriority,
NoPriority,
} = ReactPriorityLevels;
const {
getLaneLabelMap,
injectProfilingHooks,
overrideHookState,
overrideHookStateDeletePath,
overrideHookStateRenamePath,
overrideProps,
overridePropsDeletePath,
overridePropsRenamePath,
scheduleRefresh,
setErrorHandler,
setSuspenseHandler,
scheduleUpdate,
} = renderer;
const supportsTogglingError =
typeof setErrorHandler === 'function' &&
typeof scheduleUpdate === 'function';
const supportsTogglingSuspense =
typeof setSuspenseHandler === 'function' &&
typeof scheduleUpdate === 'function';
if (typeof scheduleRefresh === 'function') {
renderer.scheduleRefresh = (...args) => {
try {
hook.emit('fastRefreshScheduled');
} finally {
return scheduleRefresh(...args);
}
};
}
let getTimelineData: null | GetTimelineData = null;
let toggleProfilingStatus: null | ToggleProfilingStatus = null;
if (typeof injectProfilingHooks === 'function') {
const response = createProfilingHooks({
getDisplayNameForFiber,
getIsProfiling: () => isProfiling,
getLaneLabelMap,
currentDispatcherRef: getDispatcherRef(renderer),
workTagMap: ReactTypeOfWork,
reactVersion: version,
});
injectProfilingHooks(response.profilingHooks);
getTimelineData = response.getTimelineData;
toggleProfilingStatus = response.toggleProfilingStatus;
}
const fibersWithChangedErrorOrWarningCounts: Set<Fiber> = new Set();
const pendingFiberToErrorsMap: Map<Fiber, Map<string, number>> = new Map();
const pendingFiberToWarningsMap: Map<Fiber, Map<string, number>> = new Map();
const fiberIDToErrorsMap: Map<number, Map<string, number>> = new Map();
const fiberIDToWarningsMap: Map<number, Map<string, number>> = new Map();
function clearErrorsAndWarnings() {
for (const id of fiberIDToErrorsMap.keys()) {
const fiber = idToArbitraryFiberMap.get(id);
if (fiber != null) {
fibersWithChangedErrorOrWarningCounts.add(fiber);
updateMostRecentlyInspectedElementIfNecessary(id);
}
}
for (const id of fiberIDToWarningsMap.keys()) {
const fiber = idToArbitraryFiberMap.get(id);
if (fiber != null) {
fibersWithChangedErrorOrWarningCounts.add(fiber);
updateMostRecentlyInspectedElementIfNecessary(id);
}
}
fiberIDToErrorsMap.clear();
fiberIDToWarningsMap.clear();
flushPendingEvents();
}
function clearMessageCountHelper(
fiberID: number,
pendingFiberToMessageCountMap: Map<Fiber, Map<string, number>>,
fiberIDToMessageCountMap: Map<number, Map<string, number>>,
) {
const fiber = idToArbitraryFiberMap.get(fiberID);
if (fiber != null) {
pendingFiberToErrorsMap.delete(fiber);
if (fiberIDToMessageCountMap.has(fiberID)) {
fiberIDToMessageCountMap.delete(fiberID);
fibersWithChangedErrorOrWarningCounts.add(fiber);
flushPendingEvents();
updateMostRecentlyInspectedElementIfNecessary(fiberID);
} else {
fibersWithChangedErrorOrWarningCounts.delete(fiber);
}
}
}
function clearErrorsForFiberID(fiberID: number) {
clearMessageCountHelper(
fiberID,
pendingFiberToErrorsMap,
fiberIDToErrorsMap,
);
}
function clearWarningsForFiberID(fiberID: number) {
clearMessageCountHelper(
fiberID,
pendingFiberToWarningsMap,
fiberIDToWarningsMap,
);
}
function updateMostRecentlyInspectedElementIfNecessary(
fiberID: number,
): void {
if (
mostRecentlyInspectedElement !== null &&
mostRecentlyInspectedElement.id === fiberID
) {
hasElementUpdatedSinceLastInspected = true;
}
}
function onErrorOrWarning(
fiber: Fiber,
type: 'error' | 'warn',
args: $ReadOnlyArray<any>,
): void {
if (type === 'error') {
const maybeID = getFiberIDUnsafe(fiber);
if (maybeID != null && forceErrorForFiberIDs.get(maybeID) === true) {
return;
}
}
const message = format(...args);
if (__DEBUG__) {
debug('onErrorOrWarning', fiber, null, `${type}: "${message}"`);
}
fibersWithChangedErrorOrWarningCounts.add(fiber);
const fiberMap =
type === 'error' ? pendingFiberToErrorsMap : pendingFiberToWarningsMap;
const messageMap = fiberMap.get(fiber);
if (messageMap != null) {
const count = messageMap.get(message) || 0;
messageMap.set(message, count + 1);
} else {
fiberMap.set(fiber, new Map([[message, 1]]));
}
flushPendingErrorsAndWarningsAfterDelay();
}
registerRendererWithConsole(renderer, onErrorOrWarning);
patchConsoleUsingWindowValues();
const debug = (
name: string,
fiber: Fiber,
parentFiber: ?Fiber,
extraString: string = '',
): void => {
if (__DEBUG__) {
const displayName =
fiber.tag + ':' + (getDisplayNameForFiber(fiber) || 'null');
const maybeID = getFiberIDUnsafe(fiber) || '<no id>';
const parentDisplayName = parentFiber
? parentFiber.tag +
':' +
(getDisplayNameForFiber(parentFiber) || 'null')
: '';
const maybeParentID = parentFiber
? getFiberIDUnsafe(parentFiber) || '<no-id>'
: '';
console.groupCollapsed(
`[renderer] %c${name} %c${displayName} (${maybeID}) %c${
parentFiber ? `${parentDisplayName} (${maybeParentID})` : ''
} %c${extraString}`,
'color: red; font-weight: bold;',
'color: blue;',
'color: purple;',
'color: black;',
);
console.log(new Error().stack.split('\n').slice(1).join('\n'));
console.groupEnd();
}
};
const hideElementsWithDisplayNames: Set<RegExp> = new Set();
const hideElementsWithPaths: Set<RegExp> = new Set();
const hideElementsWithTypes: Set<ElementType> = new Set();
let traceUpdatesEnabled: boolean = false;
const traceUpdatesForNodes: Set<NativeType> = new Set();
function applyComponentFilters(componentFilters: Array<ComponentFilter>) {
hideElementsWithTypes.clear();
hideElementsWithDisplayNames.clear();
hideElementsWithPaths.clear();
componentFilters.forEach(componentFilter => {
if (!componentFilter.isEnabled) {
return;
}
switch (componentFilter.type) {
case ComponentFilterDisplayName:
if (componentFilter.isValid && componentFilter.value !== '') {
hideElementsWithDisplayNames.add(
new RegExp(componentFilter.value, 'i'),
);
}
break;
case ComponentFilterElementType:
hideElementsWithTypes.add(componentFilter.value);
break;
case ComponentFilterLocation:
if (componentFilter.isValid && componentFilter.value !== '') {
hideElementsWithPaths.add(new RegExp(componentFilter.value, 'i'));
}
break;
case ComponentFilterHOC:
hideElementsWithDisplayNames.add(new RegExp('\\('));
break;
default:
console.warn(
`Invalid component filter type "${componentFilter.type}"`,
);
break;
}
});
}
if (window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ != null) {
const componentFiltersWithoutLocationBasedOnes =
filterOutLocationComponentFilters(
window.__REACT_DEVTOOLS_COMPONENT_FILTERS__,
);
applyComponentFilters(componentFiltersWithoutLocationBasedOnes);
} else {
applyComponentFilters(getDefaultComponentFilters());
}
function updateComponentFilters(componentFilters: Array<ComponentFilter>) {
if (isProfiling) {
throw Error('Cannot modify filter preferences while profiling');
}
hook.getFiberRoots(rendererID).forEach(root => {
currentRootID = getOrGenerateFiberID(root.current);
pushOperation(TREE_OPERATION_REMOVE_ROOT);
flushPendingEvents(root);
currentRootID = -1;
});
applyComponentFilters(componentFilters);
rootDisplayNameCounter.clear();
hook.getFiberRoots(rendererID).forEach(root => {
currentRootID = getOrGenerateFiberID(root.current);
setRootPseudoKey(currentRootID, root.current);
mountFiberRecursively(root.current, null, false, false);
flushPendingEvents(root);
currentRootID = -1;
});
reevaluateErrorsAndWarnings();
flushPendingEvents();
}
function shouldFilterFiber(fiber: Fiber): boolean {
const {tag, type, key} = fiber;
switch (tag) {
case DehydratedSuspenseComponent:
return true;
case HostPortal:
case HostText:
case LegacyHiddenComponent:
case OffscreenComponent:
case Throw:
return true;
case HostRoot:
return false;
case Fragment:
return key === null;
default:
const typeSymbol = getTypeSymbol(type);
switch (typeSymbol) {
case CONCURRENT_MODE_NUMBER:
case CONCURRENT_MODE_SYMBOL_STRING:
case DEPRECATED_ASYNC_MODE_SYMBOL_STRING:
case STRICT_MODE_NUMBER:
case STRICT_MODE_SYMBOL_STRING:
return true;
default:
break;
}
}
const elementType = getElementTypeForFiber(fiber);
if (hideElementsWithTypes.has(elementType)) {
return true;
}
if (hideElementsWithDisplayNames.size > 0) {
const displayName = getDisplayNameForFiber(fiber);
if (displayName != null) {
for (const displayNameRegExp of hideElementsWithDisplayNames) {
if (displayNameRegExp.test(displayName)) {
return true;
}
}
}
}
return false;
}
function getElementTypeForFiber(fiber: Fiber): ElementType {
const {type, tag} = fiber;
switch (tag) {
case ClassComponent:
case IncompleteClassComponent:
return ElementTypeClass;
case IncompleteFunctionComponent:
case FunctionComponent:
case IndeterminateComponent:
return ElementTypeFunction;
case ForwardRef:
return ElementTypeForwardRef;
case HostRoot:
return ElementTypeRoot;
case HostComponent:
case HostHoistable:
case HostSingleton:
return ElementTypeHostComponent;
case HostPortal:
case HostText:
case Fragment:
return ElementTypeOtherOrUnknown;
case MemoComponent:
case SimpleMemoComponent:
return ElementTypeMemo;
case SuspenseComponent:
return ElementTypeSuspense;
case SuspenseListComponent:
return ElementTypeSuspenseList;
case TracingMarkerComponent:
return ElementTypeTracingMarker;
default:
const typeSymbol = getTypeSymbol(type);
switch (typeSymbol) {
case CONCURRENT_MODE_NUMBER:
case CONCURRENT_MODE_SYMBOL_STRING:
case DEPRECATED_ASYNC_MODE_SYMBOL_STRING:
return ElementTypeOtherOrUnknown;
case PROVIDER_NUMBER:
case PROVIDER_SYMBOL_STRING:
return ElementTypeContext;
case CONTEXT_NUMBER:
case CONTEXT_SYMBOL_STRING:
return ElementTypeContext;
case STRICT_MODE_NUMBER:
case STRICT_MODE_SYMBOL_STRING:
return ElementTypeOtherOrUnknown;
case PROFILER_NUMBER:
case PROFILER_SYMBOL_STRING:
return ElementTypeProfiler;
default:
return ElementTypeOtherOrUnknown;
}
}
}
const idToTreeBaseDurationMap: Map<number, number> = new Map();
const idToRootMap: Map<number, number> = new Map();
let currentRootID: number = -1;
function getOrGenerateFiberID(fiber: Fiber): number {
let id = null;
if (fiberToIDMap.has(fiber)) {
id = fiberToIDMap.get(fiber);
} else {
const {alternate} = fiber;
if (alternate !== null && fiberToIDMap.has(alternate)) {
id = fiberToIDMap.get(alternate);
}
}
let didGenerateID = false;
if (id === null) {
didGenerateID = true;
id = getUID();
}
const refinedID = ((id: any): number);
if (!fiberToIDMap.has(fiber)) {
fiberToIDMap.set(fiber, refinedID);
idToArbitraryFiberMap.set(refinedID, fiber);
}
const {alternate} = fiber;
if (alternate !== null) {
if (!fiberToIDMap.has(alternate)) {
fiberToIDMap.set(alternate, refinedID);
}
}
if (__DEBUG__) {
if (didGenerateID) {
debug(
'getOrGenerateFiberID()',
fiber,
fiber.return,
'Generated a new UID',
);
}
}
return refinedID;
}
function getFiberIDThrows(fiber: Fiber): number {
const maybeID = getFiberIDUnsafe(fiber);
if (maybeID !== null) {
return maybeID;
}
throw Error(
`Could not find ID for Fiber "${getDisplayNameForFiber(fiber) || ''}"`,
);
}
function getFiberIDUnsafe(fiber: Fiber): number | null {
if (fiberToIDMap.has(fiber)) {
return ((fiberToIDMap.get(fiber): any): number);
} else {
const {alternate} = fiber;
if (alternate !== null && fiberToIDMap.has(alternate)) {
return ((fiberToIDMap.get(alternate): any): number);
}
}
return null;
}
function untrackFiberID(fiber: Fiber) {
if (__DEBUG__) {
debug('untrackFiberID()', fiber, fiber.return, 'schedule after delay');
}
untrackFibersSet.add(fiber);
const alternate = fiber.alternate;
if (alternate !== null) {
untrackFibersSet.add(alternate);
}
if (untrackFibersTimeoutID === null) {
untrackFibersTimeoutID = setTimeout(untrackFibers, 1000);
}
}
const untrackFibersSet: Set<Fiber> = new Set();
let untrackFibersTimeoutID: TimeoutID | null = null;
function untrackFibers() {
if (untrackFibersTimeoutID !== null) {
clearTimeout(untrackFibersTimeoutID);
untrackFibersTimeoutID = null;
}
untrackFibersSet.forEach(fiber => {
const fiberID = getFiberIDUnsafe(fiber);
if (fiberID !== null) {
idToArbitraryFiberMap.delete(fiberID);
clearErrorsForFiberID(fiberID);
clearWarningsForFiberID(fiberID);
}
fiberToIDMap.delete(fiber);
fiberToComponentStackMap.delete(fiber);
const {alternate} = fiber;
if (alternate !== null) {
fiberToIDMap.delete(alternate);
fiberToComponentStackMap.delete(alternate);
}
if (forceErrorForFiberIDs.has(fiberID)) {
forceErrorForFiberIDs.delete(fiberID);
if (forceErrorForFiberIDs.size === 0 && setErrorHandler != null) {
setErrorHandler(shouldErrorFiberAlwaysNull);
}
}
});
untrackFibersSet.clear();
}
function getChangeDescription(
prevFiber: Fiber | null,
nextFiber: Fiber,
): ChangeDescription | null {
switch (getElementTypeForFiber(nextFiber)) {
case ElementTypeClass:
case ElementTypeFunction:
case ElementTypeMemo:
case ElementTypeForwardRef:
if (prevFiber === null) {
return {
context: null,
didHooksChange: false,
isFirstMount: true,
props: null,
state: null,
};
} else {
const data: ChangeDescription = {
context: getContextChangedKeys(nextFiber),
didHooksChange: false,
isFirstMount: false,
props: getChangedKeys(
prevFiber.memoizedProps,
nextFiber.memoizedProps,
),
state: getChangedKeys(
prevFiber.memoizedState,
nextFiber.memoizedState,
),
};
const indices = getChangedHooksIndices(
prevFiber.memoizedState,
nextFiber.memoizedState,
);
data.hooks = indices;
data.didHooksChange = indices !== null && indices.length > 0;
return data;
}
default:
return null;
}
}
function updateContextsForFiber(fiber: Fiber) {
switch (getElementTypeForFiber(fiber)) {
case ElementTypeClass:
case ElementTypeForwardRef:
case ElementTypeFunction:
case ElementTypeMemo:
if (idToContextsMap !== null) {
const id = getFiberIDThrows(fiber);
const contexts = getContextsForFiber(fiber);
if (contexts !== null) {
idToContextsMap.set(id, contexts);
}
}
break;
default:
break;
}
}
const NO_CONTEXT = {};
function getContextsForFiber(fiber: Fiber): [Object, any] | null {
let legacyContext = NO_CONTEXT;
let modernContext = NO_CONTEXT;
switch (getElementTypeForFiber(fiber)) {
case ElementTypeClass:
const instance = fiber.stateNode;
if (instance != null) {
if (
instance.constructor &&
instance.constructor.contextType != null
) {
modernContext = instance.context;
} else {
legacyContext = instance.context;
if (legacyContext && Object.keys(legacyContext).length === 0) {
legacyContext = NO_CONTEXT;
}
}
}
return [legacyContext, modernContext];
case ElementTypeForwardRef:
case ElementTypeFunction:
case ElementTypeMemo:
const dependencies = fiber.dependencies;
if (dependencies && dependencies.firstContext) {
modernContext = dependencies.firstContext;
}
return [legacyContext, modernContext];
default:
return null;
}
}
function crawlToInitializeContextsMap(fiber: Fiber) {
const id = getFiberIDUnsafe(fiber);
if (id !== null) {
updateContextsForFiber(fiber);
let current = fiber.child;
while (current !== null) {
crawlToInitializeContextsMap(current);
current = current.sibling;
}
}
}
function getContextChangedKeys(fiber: Fiber): null | boolean | Array<string> {
if (idToContextsMap !== null) {
const id = getFiberIDThrows(fiber);
const prevContexts = idToContextsMap.has(id)
?
idToContextsMap.get(id)
: null;
const nextContexts = getContextsForFiber(fiber);
if (prevContexts == null || nextContexts == null) {
return null;
}
const [prevLegacyContext, prevModernContext] = prevContexts;
const [nextLegacyContext, nextModernContext] = nextContexts;
switch (getElementTypeForFiber(fiber)) {
case ElementTypeClass:
if (prevContexts && nextContexts) {
if (nextLegacyContext !== NO_CONTEXT) {
return getChangedKeys(prevLegacyContext, nextLegacyContext);
} else if (nextModernContext !== NO_CONTEXT) {
return prevModernContext !== nextModernContext;
}
}
break;
case ElementTypeForwardRef:
case ElementTypeFunction:
case ElementTypeMemo:
if (nextModernContext !== NO_CONTEXT) {
let prevContext = prevModernContext;
let nextContext = nextModernContext;
while (prevContext && nextContext) {
if (!is(prevContext.memoizedValue, nextContext.memoizedValue)) {
return true;
}
prevContext = prevContext.next;
nextContext = nextContext.next;
}
return false;
}
break;
default:
break;
}
}
return null;
}
function isHookThatCanScheduleUpdate(hookObject: any) {
const queue = hookObject.queue;
if (!queue) {
return false;
}
const boundHasOwnProperty = hasOwnProperty.bind(queue);
if (boundHasOwnProperty('pending')) {
return true;
}
return (
boundHasOwnProperty('value') &&
boundHasOwnProperty('getSnapshot') &&
typeof queue.getSnapshot === 'function'
);
}
function didStatefulHookChange(prev: any, next: any): boolean {
const prevMemoizedState = prev.memoizedState;
const nextMemoizedState = next.memoizedState;
if (isHookThatCanScheduleUpdate(prev)) {
return prevMemoizedState !== nextMemoizedState;
}
return false;
}
function getChangedHooksIndices(prev: any, next: any): null | Array<number> {
if (prev == null || next == null) {
return null;
}
const indices = [];
let index = 0;
if (
next.hasOwnProperty('baseState') &&
next.hasOwnProperty('memoizedState') &&
next.hasOwnProperty('next') &&
next.hasOwnProperty('queue')
) {
while (next !== null) {
if (didStatefulHookChange(prev, next)) {
indices.push(index);
}
next = next.next;
prev = prev.next;
index++;
}
}
return indices;
}
function getChangedKeys(prev: any, next: any): null | Array<string> {
if (prev == null || next == null) {
return null;
}
if (
next.hasOwnProperty('baseState') &&
next.hasOwnProperty('memoizedState') &&
next.hasOwnProperty('next') &&
next.hasOwnProperty('queue')
) {
return null;
}
const keys = new Set([...Object.keys(prev), ...Object.keys(next)]);
const changedKeys = [];
for (const key of keys) {
if (prev[key] !== next[key]) {
changedKeys.push(key);
}
}
return changedKeys;
}
function didFiberRender(prevFiber: Fiber, nextFiber: Fiber): boolean {
switch (nextFiber.tag) {
case ClassComponent:
case FunctionComponent:
case ContextConsumer:
case MemoComponent:
case SimpleMemoComponent:
case ForwardRef:
const PerformedWork = 0b000000000000000000000000001;
return (getFiberFlags(nextFiber) & PerformedWork) === PerformedWork;
default:
return (
prevFiber.memoizedProps !== nextFiber.memoizedProps ||
prevFiber.memoizedState !== nextFiber.memoizedState ||
prevFiber.ref !== nextFiber.ref
);
}
}
type OperationsArray = Array<number>;
type StringTableEntry = {
encodedString: Array<number>,
id: number,
};
const pendingOperations: OperationsArray = [];
const pendingRealUnmountedIDs: Array<number> = [];
const pendingSimulatedUnmountedIDs: Array<number> = [];
let pendingOperationsQueue: Array<OperationsArray> | null = [];
const pendingStringTable: Map<string, StringTableEntry> = new Map();
let pendingStringTableLength: number = 0;
let pendingUnmountedRootID: number | null = null;
function pushOperation(op: number): void {
if (__DEV__) {
if (!Number.isInteger(op)) {
console.error(
'pushOperation() was called but the value is not an integer.',
op,
);
}
}
pendingOperations.push(op);
}
function shouldBailoutWithPendingOperations() {
if (isProfiling) {
if (
currentCommitProfilingMetadata != null &&
currentCommitProfilingMetadata.durations.length > 0
) {
return false;
}
}
return (
pendingOperations.length === 0 &&
pendingRealUnmountedIDs.length === 0 &&
pendingSimulatedUnmountedIDs.length === 0 &&
pendingUnmountedRootID === null
);
}
function flushOrQueueOperations(operations: OperationsArray): void {
if (shouldBailoutWithPendingOperations()) {
return;
}
if (pendingOperationsQueue !== null) {
pendingOperationsQueue.push(operations);
} else {
hook.emit('operations', operations);
}
}
let flushPendingErrorsAndWarningsAfterDelayTimeoutID: null | TimeoutID = null;
function clearPendingErrorsAndWarningsAfterDelay() {
if (flushPendingErrorsAndWarningsAfterDelayTimeoutID !== null) {
clearTimeout(flushPendingErrorsAndWarningsAfterDelayTimeoutID);
flushPendingErrorsAndWarningsAfterDelayTimeoutID = null;
}
}
function flushPendingErrorsAndWarningsAfterDelay() {
clearPendingErrorsAndWarningsAfterDelay();
flushPendingErrorsAndWarningsAfterDelayTimeoutID = setTimeout(() => {
flushPendingErrorsAndWarningsAfterDelayTimeoutID = null;
if (pendingOperations.length > 0) {
return;
}
recordPendingErrorsAndWarnings();
if (shouldBailoutWithPendingOperations()) {
return;
}
const operations: OperationsArray = new Array(
3 + pendingOperations.length,
);
operations[0] = rendererID;
operations[1] = currentRootID;
operations[2] = 0;
for (let j = 0; j < pendingOperations.length; j++) {
operations[3 + j] = pendingOperations[j];
}
flushOrQueueOperations(operations);
pendingOperations.length = 0;
}, 1000);
}
function reevaluateErrorsAndWarnings() {
fibersWithChangedErrorOrWarningCounts.clear();
fiberIDToErrorsMap.forEach((countMap, fiberID) => {
const fiber = idToArbitraryFiberMap.get(fiberID);
if (fiber != null) {
fibersWithChangedErrorOrWarningCounts.add(fiber);
}
});
fiberIDToWarningsMap.forEach((countMap, fiberID) => {
const fiber = idToArbitraryFiberMap.get(fiberID);
if (fiber != null) {
fibersWithChangedErrorOrWarningCounts.add(fiber);
}
});
recordPendingErrorsAndWarnings();
}
function mergeMapsAndGetCountHelper(
fiber: Fiber,
fiberID: number,
pendingFiberToMessageCountMap: Map<Fiber, Map<string, number>>,
fiberIDToMessageCountMap: Map<number, Map<string, number>>,
): number {
let newCount = 0;
let messageCountMap = fiberIDToMessageCountMap.get(fiberID);
const pendingMessageCountMap = pendingFiberToMessageCountMap.get(fiber);
if (pendingMessageCountMap != null) {
if (messageCountMap == null) {
messageCountMap = pendingMessageCountMap;
fiberIDToMessageCountMap.set(fiberID, pendingMessageCountMap);
} else {
const refinedMessageCountMap = ((messageCountMap: any): Map<
string,
number,
>);
pendingMessageCountMap.forEach((pendingCount, message) => {
const previousCount = refinedMessageCountMap.get(message) || 0;
refinedMessageCountMap.set(message, previousCount + pendingCount);
});
}
}
if (!shouldFilterFiber(fiber)) {
if (messageCountMap != null) {
messageCountMap.forEach(count => {
newCount += count;
});
}
}
pendingFiberToMessageCountMap.delete(fiber);
return newCount;
}
function recordPendingErrorsAndWarnings() {
clearPendingErrorsAndWarningsAfterDelay();
fibersWithChangedErrorOrWarningCounts.forEach(fiber => {
const fiberID = getFiberIDUnsafe(fiber);
if (fiberID === null) {
} else {
const errorCount = mergeMapsAndGetCountHelper(
fiber,
fiberID,
pendingFiberToErrorsMap,
fiberIDToErrorsMap,
);
const warningCount = mergeMapsAndGetCountHelper(
fiber,
fiberID,
pendingFiberToWarningsMap,
fiberIDToWarningsMap,
);
pushOperation(TREE_OPERATION_UPDATE_ERRORS_OR_WARNINGS);
pushOperation(fiberID);
pushOperation(errorCount);
pushOperation(warningCount);
}
pendingFiberToErrorsMap.delete(fiber);
pendingFiberToWarningsMap.delete(fiber);
});
fibersWithChangedErrorOrWarningCounts.clear();
}
function flushPendingEvents(root: Object): void {
recordPendingErrorsAndWarnings();
if (shouldBailoutWithPendingOperations()) {
return;
}
const numUnmountIDs =
pendingRealUnmountedIDs.length +
pendingSimulatedUnmountedIDs.length +
(pendingUnmountedRootID === null ? 0 : 1);
const operations = new Array<number>(
2 +
1 +
pendingStringTableLength +
(numUnmountIDs > 0 ? 2 + numUnmountIDs : 0) +
pendingOperations.length,
);
let i = 0;
operations[i++] = rendererID;
operations[i++] = currentRootID;
operations[i++] = pendingStringTableLength;
pendingStringTable.forEach((entry, stringKey) => {
const encodedString = entry.encodedString;
const length = encodedString.length;
operations[i++] = length;
for (let j = 0; j < length; j++) {
operations[i + j] = encodedString[j];
}
i += length;
});
if (numUnmountIDs > 0) {
operations[i++] = TREE_OPERATION_REMOVE;
operations[i++] = numUnmountIDs;
for (let j = pendingRealUnmountedIDs.length - 1; j >= 0; j--) {
operations[i++] = pendingRealUnmountedIDs[j];
}
for (let j = 0; j < pendingSimulatedUnmountedIDs.length; j++) {
operations[i + j] = pendingSimulatedUnmountedIDs[j];
}
i += pendingSimulatedUnmountedIDs.length;
if (pendingUnmountedRootID !== null) {
operations[i] = pendingUnmountedRootID;
i++;
}
}
for (let j = 0; j < pendingOperations.length; j++) {
operations[i + j] = pendingOperations[j];
}
i += pendingOperations.length;
flushOrQueueOperations(operations);
pendingOperations.length = 0;
pendingRealUnmountedIDs.length = 0;
pendingSimulatedUnmountedIDs.length = 0;
pendingUnmountedRootID = null;
pendingStringTable.clear();
pendingStringTableLength = 0;
}
function getStringID(string: string | null): number {
if (string === null) {
return 0;
}
const existingEntry = pendingStringTable.get(string);
if (existingEntry !== undefined) {
return existingEntry.id;
}
const id = pendingStringTable.size + 1;
const encodedString = utfEncodeString(string);
pendingStringTable.set(string, {
encodedString,
id,
});
pendingStringTableLength += encodedString.length + 1;
return id;
}
function recordMount(fiber: Fiber, parentFiber: Fiber | null) {
const isRoot = fiber.tag === HostRoot;
const id = getOrGenerateFiberID(fiber);
if (__DEBUG__) {
debug('recordMount()', fiber, parentFiber);
}
const hasOwnerMetadata = fiber.hasOwnProperty('_debugOwner');
const isProfilingSupported = fiber.hasOwnProperty('treeBaseDuration');
let profilingFlags = 0;
if (isProfilingSupported) {
profilingFlags = PROFILING_FLAG_BASIC_SUPPORT;
if (typeof injectProfilingHooks === 'function') {
profilingFlags |= PROFILING_FLAG_TIMELINE_SUPPORT;
}
}
if (isRoot) {
pushOperation(TREE_OPERATION_ADD);
pushOperation(id);
pushOperation(ElementTypeRoot);
pushOperation((fiber.mode & StrictModeBits) !== 0 ? 1 : 0);
pushOperation(profilingFlags);
pushOperation(StrictModeBits !== 0 ? 1 : 0);
pushOperation(hasOwnerMetadata ? 1 : 0);
if (isProfiling) {
if (displayNamesByRootID !== null) {
displayNamesByRootID.set(id, getDisplayNameForRoot(fiber));
}
}
} else {
const {key} = fiber;
const displayName = getDisplayNameForFiber(fiber);
const elementType = getElementTypeForFiber(fiber);
const debugOwner = fiber._debugOwner;
let ownerID: number;
if (debugOwner != null) {
if (typeof debugOwner.tag === 'number') {
ownerID = getOrGenerateFiberID((debugOwner: any));
} else {
ownerID = 0;
}
} else {
ownerID = 0;
}
const parentID = parentFiber ? getFiberIDThrows(parentFiber) : 0;
const displayNameStringID = getStringID(displayName);
const keyString = key === null ? null : String(key);
const keyStringID = getStringID(keyString);
pushOperation(TREE_OPERATION_ADD);
pushOperation(id);
pushOperation(elementType);
pushOperation(parentID);
pushOperation(ownerID);
pushOperation(displayNameStringID);
pushOperation(keyStringID);
if (
(fiber.mode & StrictModeBits) !== 0 &&
(((parentFiber: any): Fiber).mode & StrictModeBits) === 0
) {
pushOperation(TREE_OPERATION_SET_SUBTREE_MODE);
pushOperation(id);
pushOperation(StrictMode);
}
}
if (isProfilingSupported) {
idToRootMap.set(id, currentRootID);
recordProfilingDurations(fiber);
}
}
function recordUnmount(fiber: Fiber, isSimulated: boolean) {
if (__DEBUG__) {
debug(
'recordUnmount()',
fiber,
null,
isSimulated ? 'unmount is simulated' : '',
);
}
if (trackedPathMatchFiber !== null) {
if (
fiber === trackedPathMatchFiber ||
fiber === trackedPathMatchFiber.alternate
) {
setTrackedPath(null);
}
}
const unsafeID = getFiberIDUnsafe(fiber);
if (unsafeID === null) {
return;
}
const id = ((unsafeID: any): number);
const isRoot = fiber.tag === HostRoot;
if (isRoot) {
pendingUnmountedRootID = id;
} else if (!shouldFilterFiber(fiber)) {
if (isSimulated) {
pendingSimulatedUnmountedIDs.push(id);
} else {
pendingRealUnmountedIDs.push(id);
}
}
if (!fiber._debugNeedsRemount) {
untrackFiberID(fiber);
const isProfilingSupported = fiber.hasOwnProperty('treeBaseDuration');
if (isProfilingSupported) {
idToRootMap.delete(id);
idToTreeBaseDurationMap.delete(id);
}
}
}
function mountFiberRecursively(
firstChild: Fiber,
parentFiber: Fiber | null,
traverseSiblings: boolean,
traceNearestHostComponentUpdate: boolean,
) {
let fiber: Fiber | null = firstChild;
while (fiber !== null) {
getOrGenerateFiberID(fiber);
if (__DEBUG__) {
debug('mountFiberRecursively()', fiber, parentFiber);
}
const mightSiblingsBeOnTrackedPath =
updateTrackedPathStateBeforeMount(fiber);
const shouldIncludeInTree = !shouldFilterFiber(fiber);
if (shouldIncludeInTree) {
recordMount(fiber, parentFiber);
}
if (traceUpdatesEnabled) {
if (traceNearestHostComponentUpdate) {
const elementType = getElementTypeForFiber(fiber);
if (elementType === ElementTypeHostComponent) {
traceUpdatesForNodes.add(fiber.stateNode);
traceNearestHostComponentUpdate = false;
}
}
}
const isSuspense = fiber.tag === ReactTypeOfWork.SuspenseComponent;
if (isSuspense) {
const isTimedOut = fiber.memoizedState !== null;
if (isTimedOut) {
const primaryChildFragment = fiber.child;
const fallbackChildFragment = primaryChildFragment
? primaryChildFragment.sibling
: null;
const fallbackChild = fallbackChildFragment
? fallbackChildFragment.child
: null;
if (fallbackChild !== null) {
mountFiberRecursively(
fallbackChild,
shouldIncludeInTree ? fiber : parentFiber,
true,
traceNearestHostComponentUpdate,
);
}
} else {
let primaryChild: Fiber | null = null;
const areSuspenseChildrenConditionallyWrapped =
OffscreenComponent === -1;
if (areSuspenseChildrenConditionallyWrapped) {
primaryChild = fiber.child;
} else if (fiber.child !== null) {
primaryChild = fiber.child.child;
}
if (primaryChild !== null) {
mountFiberRecursively(
primaryChild,
shouldIncludeInTree ? fiber : parentFiber,
true,
traceNearestHostComponentUpdate,
);
}
}
} else {
if (fiber.child !== null) {
mountFiberRecursively(
fiber.child,
shouldIncludeInTree ? fiber : parentFiber,
true,
traceNearestHostComponentUpdate,
);
}
}
updateTrackedPathStateAfterMount(mightSiblingsBeOnTrackedPath);
fiber = traverseSiblings ? fiber.sibling : null;
}
}
function unmountFiberChildrenRecursively(fiber: Fiber) {
if (__DEBUG__) {
debug('unmountFiberChildrenRecursively()', fiber);
}
const isTimedOutSuspense =
fiber.tag === ReactTypeOfWork.SuspenseComponent &&
fiber.memoizedState !== null;
let child = fiber.child;
if (isTimedOutSuspense) {
const primaryChildFragment = fiber.child;
const fallbackChildFragment = primaryChildFragment
? primaryChildFragment.sibling
: null;
child = fallbackChildFragment ? fallbackChildFragment.child : null;
}
while (child !== null) {
if (child.return !== null) {
unmountFiberChildrenRecursively(child);
recordUnmount(child, true);
}
child = child.sibling;
}
}
function recordProfilingDurations(fiber: Fiber) {
const id = getFiberIDThrows(fiber);
const {actualDuration, treeBaseDuration} = fiber;
idToTreeBaseDurationMap.set(id, treeBaseDuration || 0);
if (isProfiling) {
const {alternate} = fiber;
if (
alternate == null ||
treeBaseDuration !== alternate.treeBaseDuration
) {
const convertedTreeBaseDuration = Math.floor(
(treeBaseDuration || 0) * 1000,
);
pushOperation(TREE_OPERATION_UPDATE_TREE_BASE_DURATION);
pushOperation(id);
pushOperation(convertedTreeBaseDuration);
}
if (alternate == null || didFiberRender(alternate, fiber)) {
if (actualDuration != null) {
let selfDuration = actualDuration;
let child = fiber.child;
while (child !== null) {
selfDuration -= child.actualDuration || 0;
child = child.sibling;
}
const metadata =
((currentCommitProfilingMetadata: any): CommitProfilingData);
metadata.durations.push(id, actualDuration, selfDuration);
metadata.maxActualDuration = Math.max(
metadata.maxActualDuration,
actualDuration,
);
if (recordChangeDescriptions) {
const changeDescription = getChangeDescription(alternate, fiber);
if (changeDescription !== null) {
if (metadata.changeDescriptions !== null) {
metadata.changeDescriptions.set(id, changeDescription);
}
}
updateContextsForFiber(fiber);
}
}
}
}
}
function recordResetChildren(fiber: Fiber, childSet: Fiber) {
if (__DEBUG__) {
debug('recordResetChildren()', childSet, fiber);
}
const nextChildren: Array<number> = [];
let child: null | Fiber = childSet;
while (child !== null) {
findReorderedChildrenRecursively(child, nextChildren);
child = child.sibling;
}
const numChildren = nextChildren.length;
if (numChildren < 2) {
return;
}
pushOperation(TREE_OPERATION_REORDER_CHILDREN);
pushOperation(getFiberIDThrows(fiber));
pushOperation(numChildren);
for (let i = 0; i < nextChildren.length; i++) {
pushOperation(nextChildren[i]);
}
}
function findReorderedChildrenRecursively(
fiber: Fiber,
nextChildren: Array<number>,
) {
if (!shouldFilterFiber(fiber)) {
nextChildren.push(getFiberIDThrows(fiber));
} else {
let child = fiber.child;
const isTimedOutSuspense =
fiber.tag === SuspenseComponent && fiber.memoizedState !== null;
if (isTimedOutSuspense) {
const primaryChildFragment = fiber.child;
const fallbackChildFragment = primaryChildFragment
? primaryChildFragment.sibling
: null;
const fallbackChild = fallbackChildFragment
? fallbackChildFragment.child
: null;
if (fallbackChild !== null) {
child = fallbackChild;
}
}
while (child !== null) {
findReorderedChildrenRecursively(child, nextChildren);
child = child.sibling;
}
}
}
function updateFiberRecursively(
nextFiber: Fiber,
prevFiber: Fiber,
parentFiber: Fiber | null,
traceNearestHostComponentUpdate: boolean,
): boolean {
const id = getOrGenerateFiberID(nextFiber);
if (__DEBUG__) {
debug('updateFiberRecursively()', nextFiber, parentFiber);
}
if (traceUpdatesEnabled) {
const elementType = getElementTypeForFiber(nextFiber);
if (traceNearestHostComponentUpdate) {
if (elementType === ElementTypeHostComponent) {
traceUpdatesForNodes.add(nextFiber.stateNode);
traceNearestHostComponentUpdate = false;
}
} else {
if (
elementType === ElementTypeFunction ||
elementType === ElementTypeClass ||
elementType === ElementTypeContext ||
elementType === ElementTypeMemo ||
elementType === ElementTypeForwardRef
) {
traceNearestHostComponentUpdate = didFiberRender(
prevFiber,
nextFiber,
);
}
}
}
if (
mostRecentlyInspectedElement !== null &&
mostRecentlyInspectedElement.id === id &&
didFiberRender(prevFiber, nextFiber)
) {
hasElementUpdatedSinceLastInspected = true;
}
const shouldIncludeInTree = !shouldFilterFiber(nextFiber);
const isSuspense = nextFiber.tag === SuspenseComponent;
let shouldResetChildren = false;
const prevDidTimeout = isSuspense && prevFiber.memoizedState !== null;
const nextDidTimeOut = isSuspense && nextFiber.memoizedState !== null;
if (prevDidTimeout && nextDidTimeOut) {
const nextFiberChild = nextFiber.child;
const nextFallbackChildSet = nextFiberChild
? nextFiberChild.sibling
: null;
const prevFiberChild = prevFiber.child;
const prevFallbackChildSet = prevFiberChild
? prevFiberChild.sibling
: null;
if (prevFallbackChildSet == null && nextFallbackChildSet != null) {
mountFiberRecursively(
nextFallbackChildSet,
shouldIncludeInTree ? nextFiber : parentFiber,
true,
traceNearestHostComponentUpdate,
);
shouldResetChildren = true;
}
if (
nextFallbackChildSet != null &&
prevFallbackChildSet != null &&
updateFiberRecursively(
nextFallbackChildSet,
prevFallbackChildSet,
nextFiber,
traceNearestHostComponentUpdate,
)
) {
shouldResetChildren = true;
}
} else if (prevDidTimeout && !nextDidTimeOut) {
const nextPrimaryChildSet = nextFiber.child;
if (nextPrimaryChildSet !== null) {
mountFiberRecursively(
nextPrimaryChildSet,
shouldIncludeInTree ? nextFiber : parentFiber,
true,
traceNearestHostComponentUpdate,
);
}
shouldResetChildren = true;
} else if (!prevDidTimeout && nextDidTimeOut) {
unmountFiberChildrenRecursively(prevFiber);
const nextFiberChild = nextFiber.child;
const nextFallbackChildSet = nextFiberChild
? nextFiberChild.sibling
: null;
if (nextFallbackChildSet != null) {
mountFiberRecursively(
nextFallbackChildSet,
shouldIncludeInTree ? nextFiber : parentFiber,
true,
traceNearestHostComponentUpdate,
);
shouldResetChildren = true;
}
} else {
if (nextFiber.child !== prevFiber.child) {
let nextChild = nextFiber.child;
let prevChildAtSameIndex = prevFiber.child;
while (nextChild) {
if (nextChild.alternate) {
const prevChild = nextChild.alternate;
if (
updateFiberRecursively(
nextChild,
prevChild,
shouldIncludeInTree ? nextFiber : parentFiber,
traceNearestHostComponentUpdate,
)
) {
shouldResetChildren = true;
}
if (prevChild !== prevChildAtSameIndex) {
shouldResetChildren = true;
}
} else {
mountFiberRecursively(
nextChild,
shouldIncludeInTree ? nextFiber : parentFiber,
false,
traceNearestHostComponentUpdate,
);
shouldResetChildren = true;
}
nextChild = nextChild.sibling;
if (!shouldResetChildren && prevChildAtSameIndex !== null) {
prevChildAtSameIndex = prevChildAtSameIndex.sibling;
}
}
if (prevChildAtSameIndex !== null) {
shouldResetChildren = true;
}
} else {
if (traceUpdatesEnabled) {
if (traceNearestHostComponentUpdate) {
const hostFibers = findAllCurrentHostFibers(
getFiberIDThrows(nextFiber),
);
hostFibers.forEach(hostFiber => {
traceUpdatesForNodes.add(hostFiber.stateNode);
});
}
}
}
}
if (shouldIncludeInTree) {
const isProfilingSupported = nextFiber.hasOwnProperty('treeBaseDuration');
if (isProfilingSupported) {
recordProfilingDurations(nextFiber);
}
}
if (shouldResetChildren) {
if (shouldIncludeInTree) {
let nextChildSet = nextFiber.child;
if (nextDidTimeOut) {
const nextFiberChild = nextFiber.child;
nextChildSet = nextFiberChild ? nextFiberChild.sibling : null;
}
if (nextChildSet != null) {
recordResetChildren(nextFiber, nextChildSet);
}
return false;
} else {
return true;
}
} else {
return false;
}
}
function cleanup() {
}
function rootSupportsProfiling(root: any) {
if (root.memoizedInteractions != null) {
return true;
} else if (
root.current != null &&
root.current.hasOwnProperty('treeBaseDuration')
) {
return true;
} else {
return false;
}
}
function flushInitialOperations() {
const localPendingOperationsQueue = pendingOperationsQueue;
pendingOperationsQueue = null;
if (
localPendingOperationsQueue !== null &&
localPendingOperationsQueue.length > 0
) {
localPendingOperationsQueue.forEach(operations => {
hook.emit('operations', operations);
});
} else {
if (trackedPath !== null) {
mightBeOnTrackedPath = true;
}
hook.getFiberRoots(rendererID).forEach(root => {
currentRootID = getOrGenerateFiberID(root.current);
setRootPseudoKey(currentRootID, root.current);
if (isProfiling && rootSupportsProfiling(root)) {
currentCommitProfilingMetadata = {
changeDescriptions: recordChangeDescriptions ? new Map() : null,
durations: [],
commitTime: getCurrentTime() - profilingStartTime,
maxActualDuration: 0,
priorityLevel: null,
updaters: getUpdatersList(root),
effectDuration: null,
passiveEffectDuration: null,
};
}
mountFiberRecursively(root.current, null, false, false);
flushPendingEvents(root);
currentRootID = -1;
});
}
}
function getUpdatersList(root: any): Array<SerializedElement> | null {
return root.memoizedUpdaters != null
? Array.from(root.memoizedUpdaters)
.filter(fiber => getFiberIDUnsafe(fiber) !== null)
.map(fiberToSerializedElement)
: null;
}
function handleCommitFiberUnmount(fiber: any) {
if (!untrackFibersSet.has(fiber)) {
recordUnmount(fiber, false);
}
}
function handlePostCommitFiberRoot(root: any) {
if (isProfiling && rootSupportsProfiling(root)) {
if (currentCommitProfilingMetadata !== null) {
const {effectDuration, passiveEffectDuration} =
getEffectDurations(root);
currentCommitProfilingMetadata.effectDuration = effectDuration;
currentCommitProfilingMetadata.passiveEffectDuration =
passiveEffectDuration;
}
}
}
function handleCommitFiberRoot(root: any, priorityLevel: void | number) {
const current = root.current;
const alternate = current.alternate;
untrackFibers();
currentRootID = getOrGenerateFiberID(current);
if (trackedPath !== null) {
mightBeOnTrackedPath = true;
}
if (traceUpdatesEnabled) {
traceUpdatesForNodes.clear();
}
const isProfilingSupported = rootSupportsProfiling(root);
if (isProfiling && isProfilingSupported) {
currentCommitProfilingMetadata = {
changeDescriptions: recordChangeDescriptions ? new Map() : null,
durations: [],
commitTime: getCurrentTime() - profilingStartTime,
maxActualDuration: 0,
priorityLevel:
priorityLevel == null ? null : formatPriorityLevel(priorityLevel),
updaters: getUpdatersList(root),
effectDuration: null,
passiveEffectDuration: null,
};
}
if (alternate) {
const wasMounted =
alternate.memoizedState != null &&
alternate.memoizedState.element != null &&
alternate.memoizedState.isDehydrated !== true;
const isMounted =
current.memoizedState != null &&
current.memoizedState.element != null &&
current.memoizedState.isDehydrated !== true;
if (!wasMounted && isMounted) {
setRootPseudoKey(currentRootID, current);
mountFiberRecursively(current, null, false, false);
} else if (wasMounted && isMounted) {
updateFiberRecursively(current, alternate, null, false);
} else if (wasMounted && !isMounted) {
removeRootPseudoKey(currentRootID);
recordUnmount(current, false);
}
} else {
setRootPseudoKey(currentRootID, current);
mountFiberRecursively(current, null, false, false);
}
if (isProfiling && isProfilingSupported) {
if (!shouldBailoutWithPendingOperations()) {
const commitProfilingMetadata =
((rootToCommitProfilingMetadataMap: any): CommitProfilingMetadataMap).get(
currentRootID,
);
if (commitProfilingMetadata != null) {
commitProfilingMetadata.push(
((currentCommitProfilingMetadata: any): CommitProfilingData),
);
} else {
((rootToCommitProfilingMetadataMap: any): CommitProfilingMetadataMap).set(
currentRootID,
[((currentCommitProfilingMetadata: any): CommitProfilingData)],
);
}
}
}
flushPendingEvents(root);
if (traceUpdatesEnabled) {
hook.emit('traceUpdates', traceUpdatesForNodes);
}
currentRootID = -1;
}
function findAllCurrentHostFibers(id: number): $ReadOnlyArray<Fiber> {
const fibers = [];
const fiber = findCurrentFiberUsingSlowPathById(id);
if (!fiber) {
return fibers;
}
let node: Fiber = fiber;
while (true) {
if (node.tag === HostComponent || node.tag === HostText) {
fibers.push(node);
} else if (node.child) {
node.child.return = node;
node = node.child;
continue;
}
if (node === fiber) {
return fibers;
}
while (!node.sibling) {
if (!node.return || node.return === fiber) {
return fibers;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
return fibers;
}
function findNativeNodesForFiberID(id: number) {
try {
const fiber = findCurrentFiberUsingSlowPathById(id);
if (fiber === null) {
return null;
}
const hostFibers = findAllCurrentHostFibers(id);
return hostFibers.map(hostFiber => hostFiber.stateNode).filter(Boolean);
} catch (err) {
return null;
}
}
function getDisplayNameForFiberID(id: number): null | string {
const fiber = idToArbitraryFiberMap.get(id);
return fiber != null ? getDisplayNameForFiber(fiber) : null;
}
function getFiberForNative(hostInstance: NativeType) {
return renderer.findFiberByHostInstance(hostInstance);
}
function getFiberIDForNative(
hostInstance: NativeType,
findNearestUnfilteredAncestor: boolean = false,
) {
let fiber = renderer.findFiberByHostInstance(hostInstance);
if (fiber != null) {
if (findNearestUnfilteredAncestor) {
while (fiber !== null && shouldFilterFiber(fiber)) {
fiber = fiber.return;
}
}
return getFiberIDThrows(((fiber: any): Fiber));
}
return null;
}
function assertIsMounted(fiber: Fiber) {
if (getNearestMountedFiber(fiber) !== fiber) {
throw new Error('Unable to find node on an unmounted component.');
}
}
function getNearestMountedFiber(fiber: Fiber): null | Fiber {
let node = fiber;
let nearestMounted: null | Fiber = fiber;
if (!fiber.alternate) {
let nextNode: Fiber = node;
do {
node = nextNode;
const Placement = 0b000000000000000000000000010;
const Hydrating = 0b000000000000001000000000000;
if ((node.flags & (Placement | Hydrating)) !== 0) {
nearestMounted = node.return;
}
nextNode = node.return;
} while (nextNode);
} else {
while (node.return) {
node = node.return;
}
}
if (node.tag === HostRoot) {
return nearestMounted;
}
return null;
}
function findCurrentFiberUsingSlowPathById(id: number): Fiber | null {
const fiber = idToArbitraryFiberMap.get(id);
if (fiber == null) {
console.warn(`Could not find Fiber with id "${id}"`);
return null;
}
const alternate = fiber.alternate;
if (!alternate) {
const nearestMounted = getNearestMountedFiber(fiber);
if (nearestMounted === null) {
throw new Error('Unable to find node on an unmounted component.');
}
if (nearestMounted !== fiber) {
return null;
}
return fiber;
}
let a: Fiber = fiber;
let b: Fiber = alternate;
while (true) {
const parentA = a.return;
if (parentA === null) {
break;
}
const parentB = parentA.alternate;
if (parentB === null) {
const nextParent = parentA.return;
if (nextParent !== null) {
a = b = nextParent;
continue;
}
break;
}
if (parentA.child === parentB.child) {
let child = parentA.child;
while (child) {
if (child === a) {
assertIsMounted(parentA);
return fiber;
}
if (child === b) {
assertIsMounted(parentA);
return alternate;
}
child = child.sibling;
}
throw new Error('Unable to find node on an unmounted component.');
}
if (a.return !== b.return) {
a = parentA;
b = parentB;
} else {
let didFindChild = false;
let child = parentA.child;
while (child) {
if (child === a) {
didFindChild = true;
a = parentA;
b = parentB;
break;
}
if (child === b) {
didFindChild = true;
b = parentA;
a = parentB;
break;
}
child = child.sibling;
}
if (!didFindChild) {
child = parentB.child;
while (child) {
if (child === a) {
didFindChild = true;
a = parentB;
b = parentA;
break;
}
if (child === b) {
didFindChild = true;
b = parentB;
a = parentA;
break;
}
child = child.sibling;
}
if (!didFindChild) {
throw new Error(
'Child was not found in either parent set. This indicates a bug ' +
'in React related to the return pointer. Please file an issue.',
);
}
}
}
if (a.alternate !== b) {
throw new Error(
"Return fibers should always be each others' alternates. " +
'This error is likely caused by a bug in React. Please file an issue.',
);
}
}
if (a.tag !== HostRoot) {
throw new Error('Unable to find node on an unmounted component.');
}
if (a.stateNode.current === a) {
return fiber;
}
return alternate;
}
function prepareViewAttributeSource(
id: number,
path: Array<string | number>,
): void {
if (isMostRecentlyInspectedElement(id)) {
window.$attribute = getInObject(
((mostRecentlyInspectedElement: any): InspectedElement),
path,
);
}
}
function prepareViewElementSource(id: number): void {
const fiber = idToArbitraryFiberMap.get(id);
if (fiber == null) {
console.warn(`Could not find Fiber with id "${id}"`);
return;
}
const {elementType, tag, type} = fiber;
switch (tag) {
case ClassComponent:
case IncompleteClassComponent:
case IncompleteFunctionComponent:
case IndeterminateComponent:
case FunctionComponent:
global.$type = type;
break;
case ForwardRef:
global.$type = type.render;
break;
case MemoComponent:
case SimpleMemoComponent:
global.$type =
elementType != null && elementType.type != null
? elementType.type
: type;
break;
default:
global.$type = null;
break;
}
}
function fiberToSerializedElement(fiber: Fiber): SerializedElement {
return {
displayName: getDisplayNameForFiber(fiber) || 'Anonymous',
id: getFiberIDThrows(fiber),
key: fiber.key,
type: getElementTypeForFiber(fiber),
};
}
function getOwnersList(id: number): Array<SerializedElement> | null {
const fiber = findCurrentFiberUsingSlowPathById(id);
if (fiber == null) {
return null;
}
const owners: Array<SerializedElement> = [fiberToSerializedElement(fiber)];
let owner = fiber._debugOwner;
while (owner != null) {
if (typeof owner.tag === 'number') {
const ownerFiber: Fiber = (owner: any);
owners.unshift(fiberToSerializedElement(ownerFiber));
owner = ownerFiber._debugOwner;
} else {
break;
}
}
return owners;
}
function getInstanceAndStyle(id: number): InstanceAndStyle {
let instance = null;
let style = null;
const fiber = findCurrentFiberUsingSlowPathById(id);
if (fiber !== null) {
instance = fiber.stateNode;
if (fiber.memoizedProps !== null) {
style = fiber.memoizedProps.style;
}
}
return {instance, style};
}
function isErrorBoundary(fiber: Fiber): boolean {
const {tag, type} = fiber;
switch (tag) {
case ClassComponent:
case IncompleteClassComponent:
const instance = fiber.stateNode;
return (
typeof type.getDerivedStateFromError === 'function' ||
(instance !== null &&
typeof instance.componentDidCatch === 'function')
);
default:
return false;
}
}
function getNearestErrorBoundaryID(fiber: Fiber): number | null {
let parent = fiber.return;
while (parent !== null) {
if (isErrorBoundary(parent)) {
return getFiberIDUnsafe(parent);
}
parent = parent.return;
}
return null;
}
function inspectElementRaw(id: number): InspectedElement | null {
const fiber = findCurrentFiberUsingSlowPathById(id);
if (fiber == null) {
return null;
}
const {
_debugOwner: debugOwner,
stateNode,
key,
memoizedProps,
memoizedState,
dependencies,
tag,
type,
} = fiber;
const elementType = getElementTypeForFiber(fiber);
const usesHooks =
(tag === FunctionComponent ||
tag === SimpleMemoComponent ||
tag === ForwardRef) &&
(!!memoizedState || !!dependencies);
const showState = !usesHooks && tag !== CacheComponent;
const typeSymbol = getTypeSymbol(type);
let canViewSource = false;
let context = null;
if (
tag === ClassComponent ||
tag === FunctionComponent ||
tag === IncompleteClassComponent ||
tag === IncompleteFunctionComponent ||
tag === IndeterminateComponent ||
tag === MemoComponent ||
tag === ForwardRef ||
tag === SimpleMemoComponent
) {
canViewSource = true;
if (stateNode && stateNode.context != null) {
const shouldHideContext =
elementType === ElementTypeClass &&
!(type.contextTypes || type.contextType);
if (!shouldHideContext) {
context = stateNode.context;
}
}
} else if (
(typeSymbol === CONTEXT_NUMBER || typeSymbol === CONTEXT_SYMBOL_STRING) &&
!(
(type._context === undefined && type.Provider === type)
)
) {
const consumerResolvedContext = type._context || type;
context = consumerResolvedContext._currentValue || null;
let current = ((fiber: any): Fiber).return;
while (current !== null) {
const currentType = current.type;
const currentTypeSymbol = getTypeSymbol(currentType);
if (
currentTypeSymbol === PROVIDER_NUMBER ||
currentTypeSymbol === PROVIDER_SYMBOL_STRING
) {
const providerResolvedContext =
currentType._context || currentType.context;
if (providerResolvedContext === consumerResolvedContext) {
context = current.memoizedProps.value;
break;
}
}
current = current.return;
}
} else if (
typeSymbol === CONSUMER_SYMBOL_STRING
) {
const consumerResolvedContext = type._context;
context = consumerResolvedContext._currentValue || null;
let current = ((fiber: any): Fiber).return;
while (current !== null) {
const currentType = current.type;
const currentTypeSymbol = getTypeSymbol(currentType);
if (
currentTypeSymbol === CONTEXT_SYMBOL_STRING
) {
const providerResolvedContext = currentType;
if (providerResolvedContext === consumerResolvedContext) {
context = current.memoizedProps.value;
break;
}
}
current = current.return;
}
}
let hasLegacyContext = false;
if (context !== null) {
hasLegacyContext = !!type.contextTypes;
context = {value: context};
}
let owners: null | Array<SerializedElement> = null;
let owner = debugOwner;
while (owner != null) {
if (typeof owner.tag === 'number') {
const ownerFiber: Fiber = (owner: any);
if (owners === null) {
owners = [];
}
owners.push(fiberToSerializedElement(ownerFiber));
owner = ownerFiber._debugOwner;
} else {
break;
}
}
const isTimedOutSuspense =
tag === SuspenseComponent && memoizedState !== null;
let hooks = null;
if (usesHooks) {
const originalConsoleMethods: {[string]: $FlowFixMe} = {};
for (const method in console) {
try {
originalConsoleMethods[method] = console[method];
console[method] = () => {};
} catch (error) {}
}
try {
hooks = inspectHooksOfFiber(fiber, getDispatcherRef(renderer));
} finally {
for (const method in originalConsoleMethods) {
try {
console[method] = originalConsoleMethods[method];
} catch (error) {}
}
}
}
let rootType = null;
let current = fiber;
while (current.return !== null) {
current = current.return;
}
const fiberRoot = current.stateNode;
if (fiberRoot != null && fiberRoot._debugRootType !== null) {
rootType = fiberRoot._debugRootType;
}
const errors = fiberIDToErrorsMap.get(id) || new Map();
const warnings = fiberIDToWarningsMap.get(id) || new Map();
let isErrored = false;
let targetErrorBoundaryID;
if (isErrorBoundary(fiber)) {
const DidCapture = 0b000000000000000000010000000;
isErrored =
(fiber.flags & DidCapture) !== 0 ||
forceErrorForFiberIDs.get(id) === true;
targetErrorBoundaryID = isErrored ? id : getNearestErrorBoundaryID(fiber);
} else {
targetErrorBoundaryID = getNearestErrorBoundaryID(fiber);
}
const plugins: Plugins = {
stylex: null,
};
if (enableStyleXFeatures) {
if (memoizedProps != null && memoizedProps.hasOwnProperty('xstyle')) {
plugins.stylex = getStyleXData(memoizedProps.xstyle);
}
}
let source = null;
if (canViewSource) {
source = getSourceForFiber(fiber);
}
return {
id,
canEditHooks: typeof overrideHookState === 'function',
canEditFunctionProps: typeof overrideProps === 'function',
canEditHooksAndDeletePaths:
typeof overrideHookStateDeletePath === 'function',
canEditHooksAndRenamePaths:
typeof overrideHookStateRenamePath === 'function',
canEditFunctionPropsDeletePaths:
typeof overridePropsDeletePath === 'function',
canEditFunctionPropsRenamePaths:
typeof overridePropsRenamePath === 'function',
canToggleError: supportsTogglingError && targetErrorBoundaryID != null,
isErrored,
targetErrorBoundaryID,
canToggleSuspense:
supportsTogglingSuspense &&
(!isTimedOutSuspense ||
forceFallbackForSuspenseIDs.has(id)),
canViewSource,
source,
hasLegacyContext,
key: key != null ? key : null,
displayName: getDisplayNameForFiber(fiber),
type: elementType,
context,
hooks,
props: memoizedProps,
state: showState ? memoizedState : null,
errors: Array.from(errors.entries()),
warnings: Array.from(warnings.entries()),
owners,
rootType,
rendererPackageName: renderer.rendererPackageName,
rendererVersion: renderer.version,
plugins,
};
}
let mostRecentlyInspectedElement: InspectedElement | null = null;
let hasElementUpdatedSinceLastInspected: boolean = false;
let currentlyInspectedPaths: Object = {};
function isMostRecentlyInspectedElement(id: number): boolean {
return (
mostRecentlyInspectedElement !== null &&
mostRecentlyInspectedElement.id === id
);
}
function isMostRecentlyInspectedElementCurrent(id: number): boolean {
return (
isMostRecentlyInspectedElement(id) && !hasElementUpdatedSinceLastInspected
);
}
function mergeInspectedPaths(path: Array<string | number>) {
let current = currentlyInspectedPaths;
path.forEach(key => {
if (!current[key]) {
current[key] = {};
}
current = current[key];
});
}
function createIsPathAllowed(
key: string | null,
secondaryCategory: 'hooks' | null,
) {
return function isPathAllowed(path: Array<string | number>): boolean {
switch (secondaryCategory) {
case 'hooks':
if (path.length === 1) {
return true;
}
if (
path[path.length - 2] === 'hookSource' &&
path[path.length - 1] === 'fileName'
) {
return true;
}
if (
path[path.length - 1] === 'subHooks' ||
path[path.length - 2] === 'subHooks'
) {
return true;
}
break;
default:
break;
}
let current =
key === null ? currentlyInspectedPaths : currentlyInspectedPaths[key];
if (!current) {
return false;
}
for (let i = 0; i < path.length; i++) {
current = current[path[i]];
if (!current) {
return false;
}
}
return true;
};
}
function updateSelectedElement(inspectedElement: InspectedElement): void {
const {hooks, id, props} = inspectedElement;
const fiber = idToArbitraryFiberMap.get(id);
if (fiber == null) {
console.warn(`Could not find Fiber with id "${id}"`);
return;
}
const {elementType, stateNode, tag, type} = fiber;
switch (tag) {
case ClassComponent:
case IncompleteClassComponent:
case IndeterminateComponent:
global.$r = stateNode;
break;
case IncompleteFunctionComponent:
case FunctionComponent:
global.$r = {
hooks,
props,
type,
};
break;
case ForwardRef:
global.$r = {
hooks,
props,
type: type.render,
};
break;
case MemoComponent:
case SimpleMemoComponent:
global.$r = {
hooks,
props,
type:
elementType != null && elementType.type != null
? elementType.type
: type,
};
break;
default:
global.$r = null;
break;
}
}
function storeAsGlobal(
id: number,
path: Array<string | number>,
count: number,
): void {
if (isMostRecentlyInspectedElement(id)) {
const value = getInObject(
((mostRecentlyInspectedElement: any): InspectedElement),
path,
);
const key = `$reactTemp${count}`;
window[key] = value;
console.log(key);
console.log(value);
}
}
function getSerializedElementValueByPath(
id: number,
path: Array<string | number>,
): ?string {
if (isMostRecentlyInspectedElement(id)) {
const valueToCopy = getInObject(
((mostRecentlyInspectedElement: any): InspectedElement),
path,
);
return serializeToString(valueToCopy);
}
}
function inspectElement(
requestID: number,
id: number,
path: Array<string | number> | null,
forceFullData: boolean,
): InspectedElementPayload {
if (path !== null) {
mergeInspectedPaths(path);
}
if (isMostRecentlyInspectedElement(id) && !forceFullData) {
if (!hasElementUpdatedSinceLastInspected) {
if (path !== null) {
let secondaryCategory = null;
if (path[0] === 'hooks') {
secondaryCategory = 'hooks';
}
return {
id,
responseID: requestID,
type: 'hydrated-path',
path,
value: cleanForBridge(
getInObject(
((mostRecentlyInspectedElement: any): InspectedElement),
path,
),
createIsPathAllowed(null, secondaryCategory),
path,
),
};
} else {
return {
id,
responseID: requestID,
type: 'no-change',
};
}
}
} else {
currentlyInspectedPaths = {};
}
hasElementUpdatedSinceLastInspected = false;
try {
mostRecentlyInspectedElement = inspectElementRaw(id);
} catch (error) {
if (error.name === 'ReactDebugToolsRenderError') {
let message = 'Error rendering inspected element.';
let stack;
console.error(message + '\n\n', error);
if (error.cause != null) {
const fiber = findCurrentFiberUsingSlowPathById(id);
const componentName =
fiber != null ? getDisplayNameForFiber(fiber) : null;
console.error(
'React DevTools encountered an error while trying to inspect hooks. ' +
'This is most likely caused by an error in current inspected component' +
(componentName != null ? `: "${componentName}".` : '.') +
'\nThe error thrown in the component is: \n\n',
error.cause,
);
if (error.cause instanceof Error) {
message = error.cause.message || message;
stack = error.cause.stack;
}
}
return {
type: 'error',
errorType: 'user',
id,
responseID: requestID,
message,
stack,
};
}
if (error.name === 'ReactDebugToolsUnsupportedHookError') {
return {
type: 'error',
errorType: 'unknown-hook',
id,
responseID: requestID,
message:
'Unsupported hook in the react-debug-tools package: ' +
error.message,
};
}
console.error('Error inspecting element.\n\n', error);
return {
type: 'error',
errorType: 'uncaught',
id,
responseID: requestID,
message: error.message,
stack: error.stack,
};
}
if (mostRecentlyInspectedElement === null) {
return {
id,
responseID: requestID,
type: 'not-found',
};
}
updateSelectedElement(mostRecentlyInspectedElement);
const cleanedInspectedElement = {...mostRecentlyInspectedElement};
cleanedInspectedElement.context = cleanForBridge(
cleanedInspectedElement.context,
createIsPathAllowed('context', null),
);
cleanedInspectedElement.hooks = cleanForBridge(
cleanedInspectedElement.hooks,
createIsPathAllowed('hooks', 'hooks'),
);
cleanedInspectedElement.props = cleanForBridge(
cleanedInspectedElement.props,
createIsPathAllowed('props', null),
);
cleanedInspectedElement.state = cleanForBridge(
cleanedInspectedElement.state,
createIsPathAllowed('state', null),
);
return {
id,
responseID: requestID,
type: 'full-data',
value: cleanedInspectedElement,
};
}
function logElementToConsole(id: number) {
const result = isMostRecentlyInspectedElementCurrent(id)
? mostRecentlyInspectedElement
: inspectElementRaw(id);
if (result === null) {
console.warn(`Could not find Fiber with id "${id}"`);
return;
}
const supportsGroup = typeof console.groupCollapsed === 'function';
if (supportsGroup) {
console.groupCollapsed(
`[Click to expand] %c<${result.displayName || 'Component'} />`,
'color: var(--dom-tag-name-color); font-weight: normal;',
);
}
if (result.props !== null) {
console.log('Props:', result.props);
}
if (result.state !== null) {
console.log('State:', result.state);
}
if (result.hooks !== null) {
console.log('Hooks:', result.hooks);
}
const nativeNodes = findNativeNodesForFiberID(id);
if (nativeNodes !== null) {
console.log('Nodes:', nativeNodes);
}
if (window.chrome || /firefox/i.test(navigator.userAgent)) {
console.log(
'Right-click any value to save it as a global variable for further inspection.',
);
}
if (supportsGroup) {
console.groupEnd();
}
}
function deletePath(
type: 'context' | 'hooks' | 'props' | 'state',
id: number,
hookID: ?number,
path: Array<string | number>,
): void {
const fiber = findCurrentFiberUsingSlowPathById(id);
if (fiber !== null) {
const instance = fiber.stateNode;
switch (type) {
case 'context':
path = path.slice(1);
switch (fiber.tag) {
case ClassComponent:
if (path.length === 0) {
} else {
deletePathInObject(instance.context, path);
}
instance.forceUpdate();
break;
case FunctionComponent:
break;
}
break;
case 'hooks':
if (typeof overrideHookStateDeletePath === 'function') {
overrideHookStateDeletePath(fiber, ((hookID: any): number), path);
}
break;
case 'props':
if (instance === null) {
if (typeof overridePropsDeletePath === 'function') {
overridePropsDeletePath(fiber, path);
}
} else {
fiber.pendingProps = copyWithDelete(instance.props, path);
instance.forceUpdate();
}
break;
case 'state':
deletePathInObject(instance.state, path);
instance.forceUpdate();
break;
}
}
}
function renamePath(
type: 'context' | 'hooks' | 'props' | 'state',
id: number,
hookID: ?number,
oldPath: Array<string | number>,
newPath: Array<string | number>,
): void {
const fiber = findCurrentFiberUsingSlowPathById(id);
if (fiber !== null) {
const instance = fiber.stateNode;
switch (type) {
case 'context':
oldPath = oldPath.slice(1);
newPath = newPath.slice(1);
switch (fiber.tag) {
case ClassComponent:
if (oldPath.length === 0) {
} else {
renamePathInObject(instance.context, oldPath, newPath);
}
instance.forceUpdate();
break;
case FunctionComponent:
break;
}
break;
case 'hooks':
if (typeof overrideHookStateRenamePath === 'function') {
overrideHookStateRenamePath(
fiber,
((hookID: any): number),
oldPath,
newPath,
);
}
break;
case 'props':
if (instance === null) {
if (typeof overridePropsRenamePath === 'function') {
overridePropsRenamePath(fiber, oldPath, newPath);
}
} else {
fiber.pendingProps = copyWithRename(
instance.props,
oldPath,
newPath,
);
instance.forceUpdate();
}
break;
case 'state':
renamePathInObject(instance.state, oldPath, newPath);
instance.forceUpdate();
break;
}
}
}
function overrideValueAtPath(
type: 'context' | 'hooks' | 'props' | 'state',
id: number,
hookID: ?number,
path: Array<string | number>,
value: any,
): void {
const fiber = findCurrentFiberUsingSlowPathById(id);
if (fiber !== null) {
const instance = fiber.stateNode;
switch (type) {
case 'context':
path = path.slice(1);
switch (fiber.tag) {
case ClassComponent:
if (path.length === 0) {
instance.context = value;
} else {
setInObject(instance.context, path, value);
}
instance.forceUpdate();
break;
case FunctionComponent:
break;
}
break;
case 'hooks':
if (typeof overrideHookState === 'function') {
overrideHookState(fiber, ((hookID: any): number), path, value);
}
break;
case 'props':
switch (fiber.tag) {
case ClassComponent:
fiber.pendingProps = copyWithSet(instance.props, path, value);
instance.forceUpdate();
break;
default:
if (typeof overrideProps === 'function') {
overrideProps(fiber, path, value);
}
break;
}
break;
case 'state':
switch (fiber.tag) {
case ClassComponent:
setInObject(instance.state, path, value);
instance.forceUpdate();
break;
}
break;
}
}
}
type CommitProfilingData = {
changeDescriptions: Map<number, ChangeDescription> | null,
commitTime: number,
durations: Array<number>,
effectDuration: number | null,
maxActualDuration: number,
passiveEffectDuration: number | null,
priorityLevel: string | null,
updaters: Array<SerializedElement> | null,
};
type CommitProfilingMetadataMap = Map<number, Array<CommitProfilingData>>;
type DisplayNamesByRootID = Map<number, string>;
let currentCommitProfilingMetadata: CommitProfilingData | null = null;
let displayNamesByRootID: DisplayNamesByRootID | null = null;
let idToContextsMap: Map<number, any> | null = null;
let initialTreeBaseDurationsMap: Map<number, number> | null = null;
let initialIDToRootMap: Map<number, number> | null = null;
let isProfiling: boolean = false;
let profilingStartTime: number = 0;
let recordChangeDescriptions: boolean = false;
let rootToCommitProfilingMetadataMap: CommitProfilingMetadataMap | null =
null;
function getProfilingData(): ProfilingDataBackend {
const dataForRoots: Array<ProfilingDataForRootBackend> = [];
if (rootToCommitProfilingMetadataMap === null) {
throw Error(
'getProfilingData() called before any profiling data was recorded',
);
}
rootToCommitProfilingMetadataMap.forEach(
(commitProfilingMetadata, rootID) => {
const commitData: Array<CommitDataBackend> = [];
const initialTreeBaseDurations: Array<[number, number]> = [];
const displayName =
(displayNamesByRootID !== null && displayNamesByRootID.get(rootID)) ||
'Unknown';
if (initialTreeBaseDurationsMap != null) {
initialTreeBaseDurationsMap.forEach((treeBaseDuration, id) => {
if (
initialIDToRootMap != null &&
initialIDToRootMap.get(id) === rootID
) {
initialTreeBaseDurations.push([id, treeBaseDuration]);
}
});
}
commitProfilingMetadata.forEach((commitProfilingData, commitIndex) => {
const {
changeDescriptions,
durations,
effectDuration,
maxActualDuration,
passiveEffectDuration,
priorityLevel,
commitTime,
updaters,
} = commitProfilingData;
const fiberActualDurations: Array<[number, number]> = [];
const fiberSelfDurations: Array<[number, number]> = [];
for (let i = 0; i < durations.length; i += 3) {
const fiberID = durations[i];
fiberActualDurations.push([fiberID, durations[i + 1]]);
fiberSelfDurations.push([fiberID, durations[i + 2]]);
}
commitData.push({
changeDescriptions:
changeDescriptions !== null
? Array.from(changeDescriptions.entries())
: null,
duration: maxActualDuration,
effectDuration,
fiberActualDurations,
fiberSelfDurations,
passiveEffectDuration,
priorityLevel,
timestamp: commitTime,
updaters,
});
});
dataForRoots.push({
commitData,
displayName,
initialTreeBaseDurations,
rootID,
});
},
);
let timelineData = null;
if (typeof getTimelineData === 'function') {
const currentTimelineData = getTimelineData();
if (currentTimelineData) {
const {
batchUIDToMeasuresMap,
internalModuleSourceToRanges,
laneToLabelMap,
laneToReactMeasureMap,
...rest
} = currentTimelineData;
timelineData = {
...rest,
batchUIDToMeasuresKeyValueArray: Array.from(
batchUIDToMeasuresMap.entries(),
),
internalModuleSourceToRanges: Array.from(
internalModuleSourceToRanges.entries(),
),
laneToLabelKeyValueArray: Array.from(laneToLabelMap.entries()),
laneToReactMeasureKeyValueArray: Array.from(
laneToReactMeasureMap.entries(),
),
};
}
}
return {
dataForRoots,
rendererID,
timelineData,
};
}
function startProfiling(shouldRecordChangeDescriptions: boolean) {
if (isProfiling) {
return;
}
recordChangeDescriptions = shouldRecordChangeDescriptions;
displayNamesByRootID = new Map();
initialTreeBaseDurationsMap = new Map(idToTreeBaseDurationMap);
initialIDToRootMap = new Map(idToRootMap);
idToContextsMap = new Map();
hook.getFiberRoots(rendererID).forEach(root => {
const rootID = getFiberIDThrows(root.current);
((displayNamesByRootID: any): DisplayNamesByRootID).set(
rootID,
getDisplayNameForRoot(root.current),
);
if (shouldRecordChangeDescriptions) {
crawlToInitializeContextsMap(root.current);
}
});
isProfiling = true;
profilingStartTime = getCurrentTime();
rootToCommitProfilingMetadataMap = new Map();
if (toggleProfilingStatus !== null) {
toggleProfilingStatus(true);
}
}
function stopProfiling() {
isProfiling = false;
recordChangeDescriptions = false;
if (toggleProfilingStatus !== null) {
toggleProfilingStatus(false);
}
}
if (
sessionStorageGetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true'
) {
startProfiling(
sessionStorageGetItem(SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY) ===
'true',
);
}
function shouldErrorFiberAlwaysNull() {
return null;
}
const forceErrorForFiberIDs = new Map<number | null, $FlowFixMe>();
function shouldErrorFiberAccordingToMap(fiber: any) {
if (typeof setErrorHandler !== 'function') {
throw new Error(
'Expected overrideError() to not get called for earlier React versions.',
);
}
const id = getFiberIDUnsafe(fiber);
if (id === null) {
return null;
}
let status = null;
if (forceErrorForFiberIDs.has(id)) {
status = forceErrorForFiberIDs.get(id);
if (status === false) {
forceErrorForFiberIDs.delete(id);
if (forceErrorForFiberIDs.size === 0) {
setErrorHandler(shouldErrorFiberAlwaysNull);
}
}
}
return status;
}
function overrideError(id: number, forceError: boolean) {
if (
typeof setErrorHandler !== 'function' ||
typeof scheduleUpdate !== 'function'
) {
throw new Error(
'Expected overrideError() to not get called for earlier React versions.',
);
}
forceErrorForFiberIDs.set(id, forceError);
if (forceErrorForFiberIDs.size === 1) {
setErrorHandler(shouldErrorFiberAccordingToMap);
}
const fiber = idToArbitraryFiberMap.get(id);
if (fiber != null) {
scheduleUpdate(fiber);
}
}
function shouldSuspendFiberAlwaysFalse() {
return false;
}
const forceFallbackForSuspenseIDs = new Set<number>();
function shouldSuspendFiberAccordingToSet(fiber: any) {
const maybeID = getFiberIDUnsafe(((fiber: any): Fiber));
return maybeID !== null && forceFallbackForSuspenseIDs.has(maybeID);
}
function overrideSuspense(id: number, forceFallback: boolean) {
if (
typeof setSuspenseHandler !== 'function' ||
typeof scheduleUpdate !== 'function'
) {
throw new Error(
'Expected overrideSuspense() to not get called for earlier React versions.',
);
}
if (forceFallback) {
forceFallbackForSuspenseIDs.add(id);
if (forceFallbackForSuspenseIDs.size === 1) {
setSuspenseHandler(shouldSuspendFiberAccordingToSet);
}
} else {
forceFallbackForSuspenseIDs.delete(id);
if (forceFallbackForSuspenseIDs.size === 0) {
setSuspenseHandler(shouldSuspendFiberAlwaysFalse);
}
}
const fiber = idToArbitraryFiberMap.get(id);
if (fiber != null) {
scheduleUpdate(fiber);
}
}
let trackedPath: Array<PathFrame> | null = null;
let trackedPathMatchFiber: Fiber | null = null;
let trackedPathMatchDepth = -1;
let mightBeOnTrackedPath = false;
function setTrackedPath(path: Array<PathFrame> | null) {
if (path === null) {
trackedPathMatchFiber = null;
trackedPathMatchDepth = -1;
mightBeOnTrackedPath = false;
}
trackedPath = path;
}
function updateTrackedPathStateBeforeMount(fiber: Fiber): boolean {
if (trackedPath === null || !mightBeOnTrackedPath) {
return false;
}
const returnFiber = fiber.return;
const returnAlternate = returnFiber !== null ? returnFiber.alternate : null;
if (
trackedPathMatchFiber === returnFiber ||
(trackedPathMatchFiber === returnAlternate && returnAlternate !== null)
) {
const actualFrame = getPathFrame(fiber);
const expectedFrame = trackedPath[trackedPathMatchDepth + 1];
if (expectedFrame === undefined) {
throw new Error('Expected to see a frame at the next depth.');
}
if (
actualFrame.index === expectedFrame.index &&
actualFrame.key === expectedFrame.key &&
actualFrame.displayName === expectedFrame.displayName
) {
trackedPathMatchFiber = fiber;
trackedPathMatchDepth++;
if (trackedPathMatchDepth === trackedPath.length - 1) {
mightBeOnTrackedPath = false;
} else {
mightBeOnTrackedPath = true;
}
return false;
}
}
mightBeOnTrackedPath = false;
return true;
}
function updateTrackedPathStateAfterMount(
mightSiblingsBeOnTrackedPath: boolean,
) {
mightBeOnTrackedPath = mightSiblingsBeOnTrackedPath;
}
const rootPseudoKeys: Map<number, string> = new Map();
const rootDisplayNameCounter: Map<string, number> = new Map();
function setRootPseudoKey(id: number, fiber: Fiber) {
const name = getDisplayNameForRoot(fiber);
const counter = rootDisplayNameCounter.get(name) || 0;
rootDisplayNameCounter.set(name, counter + 1);
const pseudoKey = `${name}:${counter}`;
rootPseudoKeys.set(id, pseudoKey);
}
function removeRootPseudoKey(id: number) {
const pseudoKey = rootPseudoKeys.get(id);
if (pseudoKey === undefined) {
throw new Error('Expected root pseudo key to be known.');
}
const name = pseudoKey.slice(0, pseudoKey.lastIndexOf(':'));
const counter = rootDisplayNameCounter.get(name);
if (counter === undefined) {
throw new Error('Expected counter to be known.');
}
if (counter > 1) {
rootDisplayNameCounter.set(name, counter - 1);
} else {
rootDisplayNameCounter.delete(name);
}
rootPseudoKeys.delete(id);
}
function getDisplayNameForRoot(fiber: Fiber): string {
let preferredDisplayName = null;
let fallbackDisplayName = null;
let child = fiber.child;
for (let i = 0; i < 3; i++) {
if (child === null) {
break;
}
const displayName = getDisplayNameForFiber(child);
if (displayName !== null) {
if (typeof child.type === 'function') {
preferredDisplayName = displayName;
} else if (fallbackDisplayName === null) {
fallbackDisplayName = displayName;
}
}
if (preferredDisplayName !== null) {
break;
}
child = child.child;
}
return preferredDisplayName || fallbackDisplayName || 'Anonymous';
}
function getPathFrame(fiber: Fiber): PathFrame {
const {key} = fiber;
let displayName = getDisplayNameForFiber(fiber);
const index = fiber.index;
switch (fiber.tag) {
case HostRoot:
const id = getFiberIDThrows(fiber);
const pseudoKey = rootPseudoKeys.get(id);
if (pseudoKey === undefined) {
throw new Error('Expected mounted root to have known pseudo key.');
}
displayName = pseudoKey;
break;
case HostComponent:
displayName = fiber.type;
break;
default:
break;
}
return {
displayName,
key,
index,
};
}
function getPathForElement(id: number): Array<PathFrame> | null {
let fiber: ?Fiber = idToArbitraryFiberMap.get(id);
if (fiber == null) {
return null;
}
const keyPath = [];
while (fiber !== null) {
keyPath.push(getPathFrame(fiber));
fiber = fiber.return;
}
keyPath.reverse();
return keyPath;
}
function getBestMatchForTrackedPath(): PathMatch | null {
if (trackedPath === null) {
return null;
}
if (trackedPathMatchFiber === null) {
return null;
}
let fiber: null | Fiber = trackedPathMatchFiber;
while (fiber !== null && shouldFilterFiber(fiber)) {
fiber = fiber.return;
}
if (fiber === null) {
return null;
}
return {
id: getFiberIDThrows(fiber),
isFullMatch: trackedPathMatchDepth === trackedPath.length - 1,
};
}
const formatPriorityLevel = (priorityLevel: ?number) => {
if (priorityLevel == null) {
return 'Unknown';
}
switch (priorityLevel) {
case ImmediatePriority:
return 'Immediate';
case UserBlockingPriority:
return 'User-Blocking';
case NormalPriority:
return 'Normal';
case LowPriority:
return 'Low';
case IdlePriority:
return 'Idle';
case NoPriority:
default:
return 'Unknown';
}
};
function setTraceUpdatesEnabled(isEnabled: boolean): void {
traceUpdatesEnabled = isEnabled;
}
function hasFiberWithId(id: number): boolean {
return idToArbitraryFiberMap.has(id);
}
function getComponentStackForFiber(fiber: Fiber): string | null {
let componentStack = fiberToComponentStackMap.get(fiber);
if (componentStack == null) {
const dispatcherRef = getDispatcherRef(renderer);
if (dispatcherRef == null) {
return null;
}
componentStack = getStackByFiberInDevAndProd(
ReactTypeOfWork,
fiber,
dispatcherRef,
);
fiberToComponentStackMap.set(fiber, componentStack);
}
return componentStack;
}
function getSourceForFiber(fiber: Fiber): Source | null {
const componentStack = getComponentStackForFiber(fiber);
if (componentStack == null) {
return null;
}
return parseSourceFromComponentStack(componentStack);
}
return {
cleanup,
clearErrorsAndWarnings,
clearErrorsForFiberID,
clearWarningsForFiberID,
getSerializedElementValueByPath,
deletePath,
findNativeNodesForFiberID,
flushInitialOperations,
getBestMatchForTrackedPath,
getComponentStackForFiber,
getSourceForFiber,
getDisplayNameForFiberID,
getFiberForNative,
getFiberIDForNative,
getInstanceAndStyle,
getOwnersList,
getPathForElement,
getProfilingData,
handleCommitFiberRoot,
handleCommitFiberUnmount,
handlePostCommitFiberRoot,
hasFiberWithId,
inspectElement,
logElementToConsole,
patchConsoleForStrictMode,
prepareViewAttributeSource,
prepareViewElementSource,
overrideError,
overrideSuspense,
overrideValueAtPath,
renamePath,
renderer,
setTraceUpdatesEnabled,
setTrackedPath,
startProfiling,
stopProfiling,
storeAsGlobal,
unpatchConsoleForStrictMode,
updateComponentFilters,
};
}