import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import type {WorkTagMap} from 'react-devtools-shared/src/backend/types';
import {
getDisplayName,
getWrappedDisplayName,
} from 'react-devtools-shared/src/utils';
import {gt, gte} from 'react-devtools-shared/src/backend/utils';
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 'react-devtools-shared/src/backend/shared/ReactSymbols';
export type getDisplayNameForFiberType = (fiber: Fiber) => string | null;
export type getTypeSymbolType = (type: any) => symbol | string | number;
export type ReactPriorityLevelsType = {
ImmediatePriority: number,
UserBlockingPriority: number,
NormalPriority: number,
LowPriority: number,
IdlePriority: number,
NoPriority: number,
};
export function getInternalReactConstants(version: string): {
getDisplayNameForFiber: getDisplayNameForFiberType,
getTypeSymbol: getTypeSymbolType,
ReactPriorityLevels: ReactPriorityLevelsType,
ReactTypeOfWork: WorkTagMap,
StrictModeBits: number,
SuspenseyImagesMode: 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;
}
const SuspenseyImagesMode = 0b0100000;
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,
ViewTransitionComponent: 30,
ActivityComponent: 31,
};
} 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,
ViewTransitionComponent: -1,
ActivityComponent: -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,
ViewTransitionComponent: -1,
ActivityComponent: -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,
ViewTransitionComponent: -1,
ActivityComponent: -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,
ViewTransitionComponent: -1,
ActivityComponent: -1,
};
}
function getTypeSymbol(type: any): symbol | string | 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,
ViewTransitionComponent,
ActivityComponent,
} = 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 ||
(Array.isArray(fiber.memoizedState?.memoizedState) &&
fiber.memoizedState.memoizedState[0]?.[REACT_MEMO_CACHE_SENTINEL]) ||
fiber.memoizedState?.memoizedState?.[REACT_MEMO_CACHE_SENTINEL])
) {
const displayNameWithoutForgetWrapper = getDisplayNameForFiber(
fiber,
true,
);
if (displayNameWithoutForgetWrapper == null) {
return null;
}
return `Forget(${displayNameWithoutForgetWrapper})`;
}
switch (tag) {
case ActivityComponent:
return 'Activity';
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 ViewTransitionComponent:
return 'ViewTransition';
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,
SuspenseyImagesMode,
};
}