React's compiler and hooks plugin carry the highest activity risk — 5 functions

Five god-functions in BuildHIR.ts and ExhaustiveDeps.ts dominate React's structural risk, combining cyclomatic complexity up to 150 with active recent commit churn across both the new compiler and the exhaustive-deps lint rule.

Stephen Collins ·
oss javascript refactoring code-health

Antipatterns Detected

complex_branching5deeply_nested5exit_heavy5god_function5long_function5cyclic_hub1

Key Points

What is a god function and why does it matter in React?

A god function is a single function that has taken on so many responsibilities that it becomes the hub of a large portion of the system's logic — in React's case, functions like `lowerStatement` and `create` call 63 and 89 other functions respectively, meaning a change in one place can trigger unexpected behavior across dozens of downstream paths. The risk is proportional to both size and coupling: the more a function does and the more it calls, the harder it is to change safely. In an actively developed codebase like React's compiler, god functions are live regression hazards, not just aesthetic problems.

How do I reduce cyclomatic complexity in JavaScript?

The most direct technique is extract-method refactoring: identify distinct logical branches (e.g., each `case` in a large `switch`, or each major `if` block) and move them into named functions with clear inputs and outputs, which reduces the path count of the original function while making each sub-path independently testable. Combining this with early-return guards to flatten nesting can bring a CC-150 function down to a dispatcher with single-digit complexity.

Is React actively maintained?

Yes — the "fire" quadrant designation on all five top hotspots indicates that these structurally complex functions are also the ones with the highest recent commit activity, meaning development is actively happening in the compiler and hooks tooling right now. The recent commit activity levels on the top functions range from 18.26 to 20.2, confirming sustained, frequent recent changes rather than a quiet maintenance period.

How do I reproduce this analysis?

Run the Hotspots CLI against the facebook/react repository at commit `ad5dfc8` to reproduce these exact scores and quadrant assignments.

What does activity-weighted risk mean?

Complexity × recent commit frequency — functions that are hard to understand AND actively changing are the highest priority for refactoring.

Of React’s 3,529 analyzed functions, 402 are rated critical — and the five highest-risk hotspots are all concentrated in two actively developed subsystems: the React Compiler’s HIR builder (BuildHIR.ts) and the eslint-plugin-react-hooks exhaustive-deps rule (ExhaustiveDeps.ts). The top-ranked function, lowerStatement, sits in the “fire” quadrant with a cyclomatic complexity of 150 and a recent commit activity of 20.2, meaning it is both structurally extreme and actively changing right now — a live regression risk, not a backlog cleanup item. Every one of the top five functions shares the same pattern fingerprint: god-function, complex branching, deep nesting, exit-heavy, and long — a consistent structural signature across two of React’s most actively evolved components.

BuildHIR.ts is where React’s new compiler does its heaviest lifting: three of the top five hotspots in this analysis live in that single file, each responsible for translating a different syntactic category into the compiler’s high-level IR. The other two sit in ExhaustiveDeps.ts, the exhaustive-deps lint rule’s core analysis logic. Both files are under active development simultaneously — making this a story of two packages accumulating structural debt in real time, not dormant code waiting to be cleaned up.

The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).

Top 5 Hotspots

FunctionFileRiskCCNDFO
lowerStatementcompiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts25.4150863
lowerExpressioncompiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts23.8141676
lowerAssignmentcompiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts23.672642
visitFunctionWithDependenciespackages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts20.91311074
createpackages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts20.81251089

Large Repo Analysis

react is a large repository. To stay within memory constraints, this analysis used hybrid touch mode: structural complexity — CC, ND, FO — is measured precisely for every function. Git activity is tracked at the function level (via git log -L) only for files with 5 or more commits in the last 30 days; other files use a file-level approximation. Rankings therefore surface functions that are both structurally complex and in the most actively-changing parts of the codebase. Dormant code with high structural complexity will rank lower than it would under a full per-function analysis — to surface it, run hotspots analyze . --per-function-touches on a machine with sufficient memory.

Hotspot Analysis

lowerStatement — compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts

CC 150. That number means 150 independent execution paths — one for every JavaScript statement type the compiler’s IR builder must handle. With nesting depth 8 and fan-out 63, lowerStatement has become the central routing table for BuildHIR.ts: every statement form added to JavaScript’s surface syntax lands here, adding branches that compound the existing count. Its activity risk of 25.4 is the highest in the repo, and it is being actively modified — complex code that is changing now, not later.

Recommendation: Write characterization tests scoped to individual statement types before any further feature work touches this function — the absence of a targeted test net is the most acute risk. Then apply extract-method refactoring to isolate each statement category (loops, conditionals, try/catch, declarations) into dedicated lower* helpers, reducing the CC-150 surface into individually testable units.

lowerExpression — compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts

Where lowerStatement is broad, lowerExpression is deeply coupled: its fan-out of 76 — the highest in this dataset — means a change here propagates through more downstream components than any other hotspot. At CC 141 and nesting depth 6, it handles the full expression surface of the language with the same accumulation pattern as its neighbor. The two functions are being modified in parallel, which compounds the risk: when statement-lowering and expression-lowering changes land in the same release, the blast radius overlaps across 63 and 76 callees respectively.

Before refactoring, map the 76 callees via fan-out analysis to identify which belong to the same conceptual cluster. Then extract expression-category sub-functions (member expressions, call expressions, literals) as independent units — this reduces both CC and coupling before the next compiler feature lands.

lowerAssignment — compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts

The third BuildHIR.ts function handles assignment expressions specifically: simple assignment, destructuring, compound assignment, optional chaining targets. CC 72 and fan-out 42 are lower than its neighbors but qualify as a god function by any reasonable threshold, and the fire-quadrant placement means it is changing alongside them. The priority here is coordination rather than isolated refactoring — start by extracting destructuring and compound-assignment branches, and use that work to surface shared utilities that may also simplify lowerStatement and lowerExpression in the same pass.

visitFunctionWithDependencies — packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts

This function orchestrates the exhaustive-deps rule’s core analysis: it walks a hook’s callback, resolves its dependency scope, and validates the dependency array. CC 131 is severe, but the defining metric here is nesting depth of 10 — the deepest in this dataset. Ten control-structure levels means the innermost logic is ten conditional frames removed from the function signature, making local reasoning unreliable and test coverage hard to reason about without full execution traces.

Recommendation: Nesting depth is the most actionable signal. Identify the innermost nested blocks and extract them into named helper functions with clear input contracts — this makes the dependency-resolution logic independently unit-testable without exercising the full visitor path. Each extracted helper will inherit a narrower scope of callee dependencies, reducing both ND and effective coupling per unit.

create — packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts

create is the rule factory — the function ESLint calls to instantiate the exhaustive-deps rule’s visitor object. At CC 125 and fan-out 89, the highest callout count in this dataset, it has become the coordination hub for the entire rule. Unlike most entry points that delegate immediately, create has absorbed significant behavioral logic alongside its initialization role, making it both a structural hotspot and a coupling bottleneck: nearly every dependency-tracking path in the rule connects through this function.

Audit which of the 89 callees form cohesive sub-responsibilities — scope analysis, dependency tracking, write detection — and extract each into a dedicated visitor or helper. This reduces CC and coupling simultaneously and makes individual rule behaviors testable without instantiating the full rule factory.

Patterns Found

Antipatterns detected across the top functions in this snapshot:

PatternOccurrences
complex_branching5
deeply_nested5
exit_heavy5
god_function5
long_function5
cyclic_hub1

These labels belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.

Reproduce This Analysis

git clone https://github.com/facebook/react
cd react
git checkout ad5dfc82b7107728da1430dd142f75b97b684dac
hotspots analyze . --mode snapshot --explain-patterns --force --hybrid-touches 5

To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.

Hotspots highlights structural and activity risk — not “bad code.” Findings are a prioritization aid, not a bug predictor. Editorial policy →

Run this on your own codebase

Hotspots runs locally in under a minute — no account, no data leaves your machine.

macOS
$ brew install Stephen-Collins-tech/tap/hotspots
Linux / cargo
$ cargo install hotspots-cli
Run in any repo
$ hotspots analyze .
★ Star on GitHub

Related Analyses