import type {Fiber, FiberRoot} from './ReactInternalTypes';
import type {Transition} from './ReactFiberTracingMarkerComponent';
import type {ConcurrentUpdate} from './ReactFiberConcurrentUpdates';
export type Lanes = number;
export type Lane = number;
export type LaneMap<T> = Array<T>;
import {
enableRetryLaneExpiration,
enableSchedulingProfiler,
enableTransitionTracing,
enableUpdaterTracking,
syncLaneExpirationMs,
transitionLaneExpirationMs,
retryLaneExpirationMs,
disableLegacyMode,
} from 'shared/ReactFeatureFlags';
import {isDevToolsPresent} from './ReactFiberDevToolsHook';
import {clz32} from './clz32';
import {LegacyRoot} from './ReactRootTags';
export const TotalLanes = 31;
export const NoLanes: Lanes = 0b0000000000000000000000000000000;
export const NoLane: Lane = 0b0000000000000000000000000000000;
export const SyncHydrationLane: Lane = 0b0000000000000000000000000000001;
export const SyncLane: Lane = 0b0000000000000000000000000000010;
export const SyncLaneIndex: number = 1;
export const InputContinuousHydrationLane: Lane = 0b0000000000000000000000000000100;
export const InputContinuousLane: Lane = 0b0000000000000000000000000001000;
export const DefaultHydrationLane: Lane = 0b0000000000000000000000000010000;
export const DefaultLane: Lane = 0b0000000000000000000000000100000;
export const SyncUpdateLanes: Lane =
SyncLane | InputContinuousLane | DefaultLane;
const TransitionHydrationLane: Lane = 0b0000000000000000000000001000000;
const TransitionLanes: Lanes = 0b0000000001111111111111110000000;
const TransitionLane1: Lane = 0b0000000000000000000000010000000;
const TransitionLane2: Lane = 0b0000000000000000000000100000000;
const TransitionLane3: Lane = 0b0000000000000000000001000000000;
const TransitionLane4: Lane = 0b0000000000000000000010000000000;
const TransitionLane5: Lane = 0b0000000000000000000100000000000;
const TransitionLane6: Lane = 0b0000000000000000001000000000000;
const TransitionLane7: Lane = 0b0000000000000000010000000000000;
const TransitionLane8: Lane = 0b0000000000000000100000000000000;
const TransitionLane9: Lane = 0b0000000000000001000000000000000;
const TransitionLane10: Lane = 0b0000000000000010000000000000000;
const TransitionLane11: Lane = 0b0000000000000100000000000000000;
const TransitionLane12: Lane = 0b0000000000001000000000000000000;
const TransitionLane13: Lane = 0b0000000000010000000000000000000;
const TransitionLane14: Lane = 0b0000000000100000000000000000000;
const TransitionLane15: Lane = 0b0000000001000000000000000000000;
const RetryLanes: Lanes = 0b0000011110000000000000000000000;
const RetryLane1: Lane = 0b0000000010000000000000000000000;
const RetryLane2: Lane = 0b0000000100000000000000000000000;
const RetryLane3: Lane = 0b0000001000000000000000000000000;
const RetryLane4: Lane = 0b0000010000000000000000000000000;
export const SomeRetryLane: Lane = RetryLane1;
export const SelectiveHydrationLane: Lane = 0b0000100000000000000000000000000;
const NonIdleLanes: Lanes = 0b0000111111111111111111111111111;
export const IdleHydrationLane: Lane = 0b0001000000000000000000000000000;
export const IdleLane: Lane = 0b0010000000000000000000000000000;
export const OffscreenLane: Lane = 0b0100000000000000000000000000000;
export const DeferredLane: Lane = 0b1000000000000000000000000000000;
export const UpdateLanes: Lanes =
SyncLane | InputContinuousLane | DefaultLane | TransitionLanes;
export const HydrationLanes =
SyncHydrationLane |
InputContinuousHydrationLane |
DefaultHydrationLane |
TransitionHydrationLane |
SelectiveHydrationLane |
IdleHydrationLane;
export function getLabelForLane(lane: Lane): string | void {
if (enableSchedulingProfiler) {
if (lane & SyncHydrationLane) {
return 'SyncHydrationLane';
}
if (lane & SyncLane) {
return 'Sync';
}
if (lane & InputContinuousHydrationLane) {
return 'InputContinuousHydration';
}
if (lane & InputContinuousLane) {
return 'InputContinuous';
}
if (lane & DefaultHydrationLane) {
return 'DefaultHydration';
}
if (lane & DefaultLane) {
return 'Default';
}
if (lane & TransitionHydrationLane) {
return 'TransitionHydration';
}
if (lane & TransitionLanes) {
return 'Transition';
}
if (lane & RetryLanes) {
return 'Retry';
}
if (lane & SelectiveHydrationLane) {
return 'SelectiveHydration';
}
if (lane & IdleHydrationLane) {
return 'IdleHydration';
}
if (lane & IdleLane) {
return 'Idle';
}
if (lane & OffscreenLane) {
return 'Offscreen';
}
if (lane & DeferredLane) {
return 'Deferred';
}
}
}
export const NoTimestamp = -1;
let nextTransitionLane: Lane = TransitionLane1;
let nextRetryLane: Lane = RetryLane1;
function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes {
const pendingSyncLanes = lanes & SyncUpdateLanes;
if (pendingSyncLanes !== 0) {
return pendingSyncLanes;
}
switch (getHighestPriorityLane(lanes)) {
case SyncHydrationLane:
return SyncHydrationLane;
case SyncLane:
return SyncLane;
case InputContinuousHydrationLane:
return InputContinuousHydrationLane;
case InputContinuousLane:
return InputContinuousLane;
case DefaultHydrationLane:
return DefaultHydrationLane;
case DefaultLane:
return DefaultLane;
case TransitionHydrationLane:
return TransitionHydrationLane;
case TransitionLane1:
case TransitionLane2:
case TransitionLane3:
case TransitionLane4:
case TransitionLane5:
case TransitionLane6:
case TransitionLane7:
case TransitionLane8:
case TransitionLane9:
case TransitionLane10:
case TransitionLane11:
case TransitionLane12:
case TransitionLane13:
case TransitionLane14:
case TransitionLane15:
return lanes & TransitionLanes;
case RetryLane1:
case RetryLane2:
case RetryLane3:
case RetryLane4:
return lanes & RetryLanes;
case SelectiveHydrationLane:
return SelectiveHydrationLane;
case IdleHydrationLane:
return IdleHydrationLane;
case IdleLane:
return IdleLane;
case OffscreenLane:
return OffscreenLane;
case DeferredLane:
return NoLanes;
default:
if (__DEV__) {
console.error(
'Should have found matching lanes. This is a bug in React.',
);
}
return lanes;
}
}
export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes {
const pendingLanes = root.pendingLanes;
if (pendingLanes === NoLanes) {
return NoLanes;
}
let nextLanes: Lanes = NoLanes;
const suspendedLanes = root.suspendedLanes;
const pingedLanes = root.pingedLanes;
const warmLanes = root.warmLanes;
const rootHasPendingCommit = root.finishedLanes !== NoLanes;
const nonIdlePendingLanes = pendingLanes & NonIdleLanes;
if (nonIdlePendingLanes !== NoLanes) {
const nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes;
if (nonIdleUnblockedLanes !== NoLanes) {
nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes);
} else {
const nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes;
if (nonIdlePingedLanes !== NoLanes) {
nextLanes = getHighestPriorityLanes(nonIdlePingedLanes);
} else {
if (!rootHasPendingCommit) {
const lanesToPrewarm = nonIdlePendingLanes & ~warmLanes;
if (lanesToPrewarm !== NoLanes) {
nextLanes = getHighestPriorityLanes(lanesToPrewarm);
}
}
}
}
} else {
const unblockedLanes = pendingLanes & ~suspendedLanes;
if (unblockedLanes !== NoLanes) {
nextLanes = getHighestPriorityLanes(unblockedLanes);
} else {
if (pingedLanes !== NoLanes) {
nextLanes = getHighestPriorityLanes(pingedLanes);
} else {
if (!rootHasPendingCommit) {
const lanesToPrewarm = pendingLanes & ~warmLanes;
if (lanesToPrewarm !== NoLanes) {
nextLanes = getHighestPriorityLanes(lanesToPrewarm);
}
}
}
}
}
if (nextLanes === NoLanes) {
return NoLanes;
}
if (
wipLanes !== NoLanes &&
wipLanes !== nextLanes &&
(wipLanes & suspendedLanes) === NoLanes
) {
const nextLane = getHighestPriorityLane(nextLanes);
const wipLane = getHighestPriorityLane(wipLanes);
if (
nextLane >= wipLane ||
(nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes)
) {
return wipLanes;
}
}
return nextLanes;
}
export function getNextLanesToFlushSync(
root: FiberRoot,
extraLanesToForceSync: Lane | Lanes,
): Lanes {
const lanesToFlush = SyncUpdateLanes | extraLanesToForceSync;
const pendingLanes = root.pendingLanes;
if (pendingLanes === NoLanes) {
return NoLanes;
}
const suspendedLanes = root.suspendedLanes;
const pingedLanes = root.pingedLanes;
const unblockedLanes = pendingLanes & ~(suspendedLanes & ~pingedLanes);
const unblockedLanesWithMatchingPriority =
unblockedLanes & getLanesOfEqualOrHigherPriority(lanesToFlush);
if (unblockedLanesWithMatchingPriority & HydrationLanes) {
return (
(unblockedLanesWithMatchingPriority & HydrationLanes) | SyncHydrationLane
);
}
if (unblockedLanesWithMatchingPriority) {
return unblockedLanesWithMatchingPriority | SyncLane;
}
return NoLanes;
}
export function checkIfRootIsPrerendering(
root: FiberRoot,
renderLanes: Lanes,
): boolean {
const pendingLanes = root.pendingLanes;
const suspendedLanes = root.suspendedLanes;
const pingedLanes = root.pingedLanes;
const unblockedLanes = pendingLanes & ~(suspendedLanes & ~pingedLanes);
return (unblockedLanes & renderLanes) === 0;
}
export function getEntangledLanes(root: FiberRoot, renderLanes: Lanes): Lanes {
let entangledLanes = renderLanes;
if ((entangledLanes & InputContinuousLane) !== NoLanes) {
entangledLanes |= entangledLanes & DefaultLane;
}
const allEntangledLanes = root.entangledLanes;
if (allEntangledLanes !== NoLanes) {
const entanglements = root.entanglements;
let lanes = entangledLanes & allEntangledLanes;
while (lanes > 0) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
entangledLanes |= entanglements[index];
lanes &= ~lane;
}
}
return entangledLanes;
}
function computeExpirationTime(lane: Lane, currentTime: number) {
switch (lane) {
case SyncHydrationLane:
case SyncLane:
case InputContinuousHydrationLane:
case InputContinuousLane:
return currentTime + syncLaneExpirationMs;
case DefaultHydrationLane:
case DefaultLane:
case TransitionHydrationLane:
case TransitionLane1:
case TransitionLane2:
case TransitionLane3:
case TransitionLane4:
case TransitionLane5:
case TransitionLane6:
case TransitionLane7:
case TransitionLane8:
case TransitionLane9:
case TransitionLane10:
case TransitionLane11:
case TransitionLane12:
case TransitionLane13:
case TransitionLane14:
case TransitionLane15:
return currentTime + transitionLaneExpirationMs;
case RetryLane1:
case RetryLane2:
case RetryLane3:
case RetryLane4:
return enableRetryLaneExpiration
? currentTime + retryLaneExpirationMs
: NoTimestamp;
case SelectiveHydrationLane:
case IdleHydrationLane:
case IdleLane:
case OffscreenLane:
case DeferredLane:
return NoTimestamp;
default:
if (__DEV__) {
console.error(
'Should have found matching lanes. This is a bug in React.',
);
}
return NoTimestamp;
}
}
export function markStarvedLanesAsExpired(
root: FiberRoot,
currentTime: number,
): void {
const pendingLanes = root.pendingLanes;
const suspendedLanes = root.suspendedLanes;
const pingedLanes = root.pingedLanes;
const expirationTimes = root.expirationTimes;
let lanes = enableRetryLaneExpiration
? pendingLanes
: pendingLanes & ~RetryLanes;
while (lanes > 0) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
const expirationTime = expirationTimes[index];
if (expirationTime === NoTimestamp) {
if (
(lane & suspendedLanes) === NoLanes ||
(lane & pingedLanes) !== NoLanes
) {
expirationTimes[index] = computeExpirationTime(lane, currentTime);
}
} else if (expirationTime <= currentTime) {
root.expiredLanes |= lane;
}
lanes &= ~lane;
}
}
export function getHighestPriorityPendingLanes(root: FiberRoot): Lanes {
return getHighestPriorityLanes(root.pendingLanes);
}
export function getLanesToRetrySynchronouslyOnError(
root: FiberRoot,
originallyAttemptedLanes: Lanes,
): Lanes {
if (root.errorRecoveryDisabledLanes & originallyAttemptedLanes) {
return NoLanes;
}
const everythingButOffscreen = root.pendingLanes & ~OffscreenLane;
if (everythingButOffscreen !== NoLanes) {
return everythingButOffscreen;
}
if (everythingButOffscreen & OffscreenLane) {
return OffscreenLane;
}
return NoLanes;
}
export function includesSyncLane(lanes: Lanes): boolean {
return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes;
}
export function isSyncLane(lanes: Lanes): boolean {
return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes;
}
export function includesNonIdleWork(lanes: Lanes): boolean {
return (lanes & NonIdleLanes) !== NoLanes;
}
export function includesOnlyRetries(lanes: Lanes): boolean {
return (lanes & RetryLanes) === lanes;
}
export function includesOnlyNonUrgentLanes(lanes: Lanes): boolean {
const UrgentLanes = SyncLane | InputContinuousLane | DefaultLane;
return (lanes & UrgentLanes) === NoLanes;
}
export function includesOnlyTransitions(lanes: Lanes): boolean {
return (lanes & TransitionLanes) === lanes;
}
export function includesTransitionLane(lanes: Lanes): boolean {
return (lanes & TransitionLanes) !== NoLanes;
}
export function includesBlockingLane(lanes: Lanes): boolean {
const SyncDefaultLanes =
InputContinuousHydrationLane |
InputContinuousLane |
DefaultHydrationLane |
DefaultLane;
return (lanes & SyncDefaultLanes) !== NoLanes;
}
export function includesExpiredLane(root: FiberRoot, lanes: Lanes): boolean {
return (lanes & root.expiredLanes) !== NoLanes;
}
export function isBlockingLane(lane: Lane): boolean {
const SyncDefaultLanes =
InputContinuousHydrationLane |
InputContinuousLane |
DefaultHydrationLane |
DefaultLane;
return (lane & SyncDefaultLanes) !== NoLanes;
}
export function isTransitionLane(lane: Lane): boolean {
return (lane & TransitionLanes) !== NoLanes;
}
export function claimNextTransitionLane(): Lane {
const lane = nextTransitionLane;
nextTransitionLane <<= 1;
if ((nextTransitionLane & TransitionLanes) === NoLanes) {
nextTransitionLane = TransitionLane1;
}
return lane;
}
export function claimNextRetryLane(): Lane {
const lane = nextRetryLane;
nextRetryLane <<= 1;
if ((nextRetryLane & RetryLanes) === NoLanes) {
nextRetryLane = RetryLane1;
}
return lane;
}
export function getHighestPriorityLane(lanes: Lanes): Lane {
return lanes & -lanes;
}
function getLanesOfEqualOrHigherPriority(lanes: Lane | Lanes): Lanes {
const lowestPriorityLaneIndex = 31 - clz32(lanes);
return (1 << (lowestPriorityLaneIndex + 1)) - 1;
}
export function pickArbitraryLane(lanes: Lanes): Lane {
return getHighestPriorityLane(lanes);
}
function pickArbitraryLaneIndex(lanes: Lanes) {
return 31 - clz32(lanes);
}
function laneToIndex(lane: Lane) {
return pickArbitraryLaneIndex(lane);
}
export function includesSomeLane(a: Lanes | Lane, b: Lanes | Lane): boolean {
return (a & b) !== NoLanes;
}
export function isSubsetOfLanes(set: Lanes, subset: Lanes | Lane): boolean {
return (set & subset) === subset;
}
export function mergeLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
return a | b;
}
export function removeLanes(set: Lanes, subset: Lanes | Lane): Lanes {
return set & ~subset;
}
export function intersectLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
return a & b;
}
export function laneToLanes(lane: Lane): Lanes {
return lane;
}
export function higherPriorityLane(a: Lane, b: Lane): Lane {
return a !== NoLane && a < b ? a : b;
}
export function createLaneMap<T>(initial: T): LaneMap<T> {
const laneMap = [];
for (let i = 0; i < TotalLanes; i++) {
laneMap.push(initial);
}
return laneMap;
}
export function markRootUpdated(root: FiberRoot, updateLane: Lane) {
root.pendingLanes |= updateLane;
if (updateLane !== IdleLane) {
root.suspendedLanes = NoLanes;
root.pingedLanes = NoLanes;
root.warmLanes = NoLanes;
}
}
export function markRootSuspended(
root: FiberRoot,
suspendedLanes: Lanes,
spawnedLane: Lane,
didSkipSuspendedSiblings: boolean,
) {
root.suspendedLanes |= suspendedLanes;
root.pingedLanes &= ~suspendedLanes;
if (!didSkipSuspendedSiblings) {
root.warmLanes |= suspendedLanes;
} else {
}
const expirationTimes = root.expirationTimes;
let lanes = suspendedLanes;
while (lanes > 0) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
expirationTimes[index] = NoTimestamp;
lanes &= ~lane;
}
if (spawnedLane !== NoLane) {
markSpawnedDeferredLane(root, spawnedLane, suspendedLanes);
}
}
export function markRootPinged(root: FiberRoot, pingedLanes: Lanes) {
root.pingedLanes |= root.suspendedLanes & pingedLanes;
root.warmLanes &= ~pingedLanes;
}
export function markRootFinished(
root: FiberRoot,
finishedLanes: Lanes,
remainingLanes: Lanes,
spawnedLane: Lane,
updatedLanes: Lanes,
suspendedRetryLanes: Lanes,
) {
const previouslyPendingLanes = root.pendingLanes;
const noLongerPendingLanes = previouslyPendingLanes & ~remainingLanes;
root.pendingLanes = remainingLanes;
root.suspendedLanes = NoLanes;
root.pingedLanes = NoLanes;
root.warmLanes = NoLanes;
root.expiredLanes &= remainingLanes;
root.entangledLanes &= remainingLanes;
root.errorRecoveryDisabledLanes &= remainingLanes;
root.shellSuspendCounter = 0;
const entanglements = root.entanglements;
const expirationTimes = root.expirationTimes;
const hiddenUpdates = root.hiddenUpdates;
let lanes = noLongerPendingLanes;
while (lanes > 0) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
entanglements[index] = NoLanes;
expirationTimes[index] = NoTimestamp;
const hiddenUpdatesForLane = hiddenUpdates[index];
if (hiddenUpdatesForLane !== null) {
hiddenUpdates[index] = null;
for (let i = 0; i < hiddenUpdatesForLane.length; i++) {
const update = hiddenUpdatesForLane[i];
if (update !== null) {
update.lane &= ~OffscreenLane;
}
}
}
lanes &= ~lane;
}
if (spawnedLane !== NoLane) {
markSpawnedDeferredLane(
root,
spawnedLane,
NoLanes,
);
}
if (
suspendedRetryLanes !== NoLanes &&
updatedLanes === NoLanes &&
!(disableLegacyMode && root.tag === LegacyRoot)
) {
const freshlySpawnedRetryLanes =
suspendedRetryLanes &
~(previouslyPendingLanes & ~finishedLanes);
root.suspendedLanes |= freshlySpawnedRetryLanes;
}
}
function markSpawnedDeferredLane(
root: FiberRoot,
spawnedLane: Lane,
entangledLanes: Lanes,
) {
root.pendingLanes |= spawnedLane;
root.suspendedLanes &= ~spawnedLane;
const spawnedLaneIndex = laneToIndex(spawnedLane);
root.entangledLanes |= spawnedLane;
root.entanglements[spawnedLaneIndex] |=
DeferredLane |
(entangledLanes & UpdateLanes);
}
export function markRootEntangled(root: FiberRoot, entangledLanes: Lanes) {
const rootEntangledLanes = (root.entangledLanes |= entangledLanes);
const entanglements = root.entanglements;
let lanes = rootEntangledLanes;
while (lanes) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
if (
(lane & entangledLanes) |
(entanglements[index] & entangledLanes)
) {
entanglements[index] |= entangledLanes;
}
lanes &= ~lane;
}
}
export function upgradePendingLanesToSync(
root: FiberRoot,
lanesToUpgrade: Lanes,
) {
root.pendingLanes |= SyncLane;
root.entangledLanes |= SyncLane;
let lanes = lanesToUpgrade;
while (lanes) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
root.entanglements[SyncLaneIndex] |= lane;
lanes &= ~lane;
}
}
export function markHiddenUpdate(
root: FiberRoot,
update: ConcurrentUpdate,
lane: Lane,
) {
const index = laneToIndex(lane);
const hiddenUpdates = root.hiddenUpdates;
const hiddenUpdatesForLane = hiddenUpdates[index];
if (hiddenUpdatesForLane === null) {
hiddenUpdates[index] = [update];
} else {
hiddenUpdatesForLane.push(update);
}
update.lane = lane | OffscreenLane;
}
export function getBumpedLaneForHydration(
root: FiberRoot,
renderLanes: Lanes,
): Lane {
const renderLane = getHighestPriorityLane(renderLanes);
let lane;
if ((renderLane & SyncUpdateLanes) !== NoLane) {
lane = SyncHydrationLane;
} else {
switch (renderLane) {
case SyncLane:
lane = SyncHydrationLane;
break;
case InputContinuousLane:
lane = InputContinuousHydrationLane;
break;
case DefaultLane:
lane = DefaultHydrationLane;
break;
case TransitionLane1:
case TransitionLane2:
case TransitionLane3:
case TransitionLane4:
case TransitionLane5:
case TransitionLane6:
case TransitionLane7:
case TransitionLane8:
case TransitionLane9:
case TransitionLane10:
case TransitionLane11:
case TransitionLane12:
case TransitionLane13:
case TransitionLane14:
case TransitionLane15:
case RetryLane1:
case RetryLane2:
case RetryLane3:
case RetryLane4:
lane = TransitionHydrationLane;
break;
case IdleLane:
lane = IdleHydrationLane;
break;
default:
lane = NoLane;
break;
}
}
if ((lane & (root.suspendedLanes | renderLanes)) !== NoLane) {
return NoLane;
}
return lane;
}
export function addFiberToLanesMap(
root: FiberRoot,
fiber: Fiber,
lanes: Lanes | Lane,
) {
if (!enableUpdaterTracking) {
return;
}
if (!isDevToolsPresent) {
return;
}
const pendingUpdatersLaneMap = root.pendingUpdatersLaneMap;
while (lanes > 0) {
const index = laneToIndex(lanes);
const lane = 1 << index;
const updaters = pendingUpdatersLaneMap[index];
updaters.add(fiber);
lanes &= ~lane;
}
}
export function movePendingFibersToMemoized(root: FiberRoot, lanes: Lanes) {
if (!enableUpdaterTracking) {
return;
}
if (!isDevToolsPresent) {
return;
}
const pendingUpdatersLaneMap = root.pendingUpdatersLaneMap;
const memoizedUpdaters = root.memoizedUpdaters;
while (lanes > 0) {
const index = laneToIndex(lanes);
const lane = 1 << index;
const updaters = pendingUpdatersLaneMap[index];
if (updaters.size > 0) {
updaters.forEach(fiber => {
const alternate = fiber.alternate;
if (alternate === null || !memoizedUpdaters.has(alternate)) {
memoizedUpdaters.add(fiber);
}
});
updaters.clear();
}
lanes &= ~lane;
}
}
export function addTransitionToLanesMap(
root: FiberRoot,
transition: Transition,
lane: Lane,
) {
if (enableTransitionTracing) {
const transitionLanesMap = root.transitionLanes;
const index = laneToIndex(lane);
let transitions = transitionLanesMap[index];
if (transitions === null) {
transitions = new Set();
}
transitions.add(transition);
transitionLanesMap[index] = transitions;
}
}
export function getTransitionsForLanes(
root: FiberRoot,
lanes: Lane | Lanes,
): Array<Transition> | null {
if (!enableTransitionTracing) {
return null;
}
const transitionsForLanes = [];
while (lanes > 0) {
const index = laneToIndex(lanes);
const lane = 1 << index;
const transitions = root.transitionLanes[index];
if (transitions !== null) {
transitions.forEach(transition => {
transitionsForLanes.push(transition);
});
}
lanes &= ~lane;
}
if (transitionsForLanes.length === 0) {
return null;
}
return transitionsForLanes;
}
export function clearTransitionsForLanes(root: FiberRoot, lanes: Lane | Lanes) {
if (!enableTransitionTracing) {
return;
}
while (lanes > 0) {
const index = laneToIndex(lanes);
const lane = 1 << index;
const transitions = root.transitionLanes[index];
if (transitions !== null) {
root.transitionLanes[index] = null;
}
lanes &= ~lane;
}
}
export function getGroupNameOfHighestPriorityLane(lanes: Lanes): string {
if (
lanes &
(SyncHydrationLane |
SyncLane |
InputContinuousHydrationLane |
InputContinuousLane |
DefaultHydrationLane |
DefaultLane)
) {
return 'Blocking';
}
if (lanes & (TransitionHydrationLane | TransitionLanes)) {
return 'Transition';
}
if (lanes & RetryLanes) {
return 'Suspense';
}
if (
lanes &
(SelectiveHydrationLane |
IdleHydrationLane |
IdleLane |
OffscreenLane |
DeferredLane)
) {
return 'Idle';
}
return 'Other';
}