import type {Fiber} from './ReactInternalTypes';
import {
enableProfilerCommitHooks,
enableProfilerNestedUpdatePhase,
enableProfilerTimer,
} from 'shared/ReactFeatureFlags';
import {HostRoot, Profiler} from './ReactWorkTags';
import * as Scheduler from 'scheduler';
const {unstable_now: now} = Scheduler;
export type ProfilerTimer = {
getCommitTime(): number,
isCurrentUpdateNested(): boolean,
markNestedUpdateScheduled(): void,
recordCommitTime(): void,
startProfilerTimer(fiber: Fiber): void,
stopProfilerTimerIfRunning(fiber: Fiber): void,
stopProfilerTimerIfRunningAndRecordDelta(fiber: Fiber): void,
syncNestedUpdateFlag(): void,
...
};
let commitTime: number = 0;
let layoutEffectStartTime: number = -1;
let profilerStartTime: number = -1;
let passiveEffectStartTime: number = -1;
let currentUpdateIsNested: boolean = false;
let nestedUpdateScheduled: boolean = false;
function isCurrentUpdateNested(): boolean {
return currentUpdateIsNested;
}
function markNestedUpdateScheduled(): void {
if (enableProfilerNestedUpdatePhase) {
nestedUpdateScheduled = true;
}
}
function resetNestedUpdateFlag(): void {
if (enableProfilerNestedUpdatePhase) {
currentUpdateIsNested = false;
nestedUpdateScheduled = false;
}
}
function syncNestedUpdateFlag(): void {
if (enableProfilerNestedUpdatePhase) {
currentUpdateIsNested = nestedUpdateScheduled;
nestedUpdateScheduled = false;
}
}
function getCommitTime(): number {
return commitTime;
}
function recordCommitTime(): void {
if (!enableProfilerTimer) {
return;
}
commitTime = now();
}
function startProfilerTimer(fiber: Fiber): void {
if (!enableProfilerTimer) {
return;
}
profilerStartTime = now();
if (((fiber.actualStartTime: any): number) < 0) {
fiber.actualStartTime = now();
}
}
function stopProfilerTimerIfRunning(fiber: Fiber): void {
if (!enableProfilerTimer) {
return;
}
profilerStartTime = -1;
}
function stopProfilerTimerIfRunningAndRecordDelta(
fiber: Fiber,
overrideBaseTime: boolean,
): void {
if (!enableProfilerTimer) {
return;
}
if (profilerStartTime >= 0) {
const elapsedTime = now() - profilerStartTime;
fiber.actualDuration += elapsedTime;
if (overrideBaseTime) {
fiber.selfBaseDuration = elapsedTime;
}
profilerStartTime = -1;
}
}
function recordLayoutEffectDuration(fiber: Fiber): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
if (layoutEffectStartTime >= 0) {
const elapsedTime = now() - layoutEffectStartTime;
layoutEffectStartTime = -1;
let parentFiber = fiber.return;
while (parentFiber !== null) {
switch (parentFiber.tag) {
case HostRoot:
const root = parentFiber.stateNode;
root.effectDuration += elapsedTime;
return;
case Profiler:
const parentStateNode = parentFiber.stateNode;
parentStateNode.effectDuration += elapsedTime;
return;
}
parentFiber = parentFiber.return;
}
}
}
function recordPassiveEffectDuration(fiber: Fiber): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
if (passiveEffectStartTime >= 0) {
const elapsedTime = now() - passiveEffectStartTime;
passiveEffectStartTime = -1;
let parentFiber = fiber.return;
while (parentFiber !== null) {
switch (parentFiber.tag) {
case HostRoot:
const root = parentFiber.stateNode;
if (root !== null) {
root.passiveEffectDuration += elapsedTime;
}
return;
case Profiler:
const parentStateNode = parentFiber.stateNode;
if (parentStateNode !== null) {
parentStateNode.passiveEffectDuration += elapsedTime;
}
return;
}
parentFiber = parentFiber.return;
}
}
}
function startLayoutEffectTimer(): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
layoutEffectStartTime = now();
}
function startPassiveEffectTimer(): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
passiveEffectStartTime = now();
}
function transferActualDuration(fiber: Fiber): void {
let child = fiber.child;
while (child) {
fiber.actualDuration += child.actualDuration;
child = child.sibling;
}
}
export {
getCommitTime,
isCurrentUpdateNested,
markNestedUpdateScheduled,
recordCommitTime,
recordLayoutEffectDuration,
recordPassiveEffectDuration,
resetNestedUpdateFlag,
startLayoutEffectTimer,
startPassiveEffectTimer,
startProfilerTimer,
stopProfilerTimerIfRunning,
stopProfilerTimerIfRunningAndRecordDelta,
syncNestedUpdateFlag,
transferActualDuration,
};