Across immer’s 180 analyzed functions, the highest-ranked hotspots split into two groups: performance tooling under perf-testing/, and production library code in the patches, array methods, and proxy layers. That distinction matters because resolveOriginalName and printSummaryTable are useful maintenance targets, but enablePatches, enableArrayMethods, and get are closer to behavior that library users depend on. With 16 critical-band functions in a codebase of 180, roughly one in eleven functions warrants immediate attention.
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
| Function | File | Risk | CC | ND | FO |
|---|---|---|---|---|---|
resolveOriginalName | perf-testing/read-cpuprofile.js | 15.4 | 29 | 8 | 9 |
enablePatches | src/plugins/patches.ts | 15.3 | 39 | 3 | 48 |
enableArrayMethods | src/plugins/arrayMethods.ts | 14.8 | 7 | 4 | 28 |
get | src/core/proxy.ts | 14.6 | 15 | 2 | 9 |
printSummaryTable | perf-testing/immutability-benchmarks.mjs | 14.1 | 24 | 7 | 14 |
Codemod / Tooling Files in Results
Two top-five functions, resolveOriginalName and printSummaryTable, live under perf-testing/. They are performance-analysis utilities rather than production library code, so they do not represent direct API risk to immer consumers. They are still worth improving if benchmark maintenance is active. To focus future analyses only on shipped library code, add the following to your .hotspotsrc.json: { "exclude": ["perf-testing/"] }.
Hotspot Analysis
resolveOriginalName — perf-testing/read-cpuprofile.js
resolveOriginalName appears to parse CPU profile data and map generated or transformed stack-frame names back to readable symbols. Its cyclomatic complexity of 29 and max nesting depth of 8 make it hard to reason about, especially because profile formats often require many fallback cases. Its fan-out of 9 is modest, so the main risk is concentrated branching rather than broad coupling.
Recommendation: Treat this as tooling debt: preserve representative CPU profile fixtures, then extract the name-resolution cases into small parser helpers. A fixture-driven test suite is the fastest way to make the 29 branches safe to simplify.
enablePatches — src/plugins/patches.ts
enablePatches almost certainly activates immer’s optional JSON-Patch plugin, registering the handlers that generate and apply patch objects. Its cyclomatic complexity of 39 and fan-out of 48 make it the most structurally complex production function in this dataset. A modification here has a broad blast radius because the function coordinates many callees from one plugin entry point, even though its nesting depth of 3 is not extreme.
Recommendation: Start by mapping the 48 fan-out targets into operational phases: patch creation, inverse patch handling, path construction, and plugin registration. Extract those phases behind narrower helper functions, then add tests for each patch operation before changing the top-level control flow.
enableArrayMethods — src/plugins/arrayMethods.ts
enableArrayMethods likely registers or activates immer’s interception layer for JavaScript array methods — the entry point that wires up proxied behavior for array mutations. Its cyclomatic complexity of 7 is manageable, but its fan-out of 28 is the signal to watch: one function coordinates a large share of the array plugin surface. The max nesting depth of 4 also suggests there are branch clusters that can be made more explicit.
Recommendation: Group related callees behind narrower interfaces so enableArrayMethods remains a registration point rather than a coordinator for every array behavior. Characterization tests around mutation interception should come first, because fan-out-driven changes can fail in indirect ways.
get — src/core/proxy.ts
The get trap in src/core/proxy.ts is likely part of immer’s proxy layer, where reads from draft objects are intercepted and resolved. Its cyclomatic complexity of 15 is high for a core access path, but its max nesting depth of 2 keeps the structure relatively flat. The fan-out of 9 means the function delegates to several helpers without becoming as broadly coupled as the patches or array-method entry points.
Recommendation: Use a decision table for the read cases this proxy trap supports, then make sure each case has a targeted test. If the cases are already conceptually separate, extract them into named predicate or resolution helpers to keep the proxy trap easy to audit.
printSummaryTable — perf-testing/immutability-benchmarks.mjs
printSummaryTable appears to format benchmark results for human review. Its cyclomatic complexity of 24 and max nesting depth of 7 indicate that display formatting, grouping, and conditional output rules are probably mixed together. The fan-out of 14 is high enough that adding a new benchmark column or summary mode could have surprising effects.
Recommendation: Split benchmark summarization from terminal formatting: first compute a normalized table model, then pass that model to a printer. That creates a pure unit to test for the 24 branches while keeping presentation changes isolated.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
long_function | 4 |
exit_heavy | 3 |
god_function | 3 |
neighbor_risk | 3 |
complex_branching | 3 |
deeply_nested | 2 |
cyclic_hub | 1 |
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.
Key Takeaways
enablePatcheshas CC 39 and FO 48, making it the production hotspot with the widest blast radius; decompose it before extending patch behavior.enableArrayMethodshas manageable CC but FO 28, so the next array-plugin change should start with characterization tests around mutation interception.resolveOriginalNameandprintSummaryTableare perf-testing utilities, not public API paths; improve them when benchmark maintenance is active, or excludeperf-testing/for a production-only analysis.
Reproduce This Analysis
git clone https://github.com/immerjs/immer
cd immer
git checkout cdccf1a6d0d349ad587a736f0eb8a3da43fc7747
hotspots analyze . --mode snapshot --explain-patterns --force
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 →