deslop/circular-dependency
Disallow runtime import cycles between modules (A imports B ... imports A).
- Category: Dead Code
- Severity: warn
- Source:
deslop-js - Framework: global
- Enabled when: react-doctor deadCode analysis enabled (default true); whole-project scan only — skipped in --diff/--staged modes
- Documentation: https://github.com/millionco/deslop-js
Validation prompt
Use this to decide whether a fired diagnostic is real or a false positive.
Fires from deslop's detectCycles, which runs Tarjan SCC over the module graph and reports each elementary import cycle as a CircularDependency of { files }; the array lists the modules of one elementary cycle in import-edge order, rotated by canonicalizeCycle to start at the alphabetically-first module path (the 2-node case is just the two paths sorted by name), so it does not necessarily begin at the importing module. buildAdjacencyList already drops edges whose imported symbols are every isTypeOnly, so a reported cycle always contains at least one value/runtime import and the bare type-only-cycle case never reaches you; this is the value/runtime detector, distinct from the separate detectReExportCycles. False positive to SUPPRESS: an intentional bidirectional collaboration where every back-edge value is only touched lazily — inside a function body, handler, or getter that runs after both modules finish evaluating — so there is no module-eval-time access and no TDZ ('Cannot access X before initialization') risk; confirm only when one module reads a value from its cycle partner at top-level/module-initialization time.
Fix prompt
Use this once validation confirms the diagnostic is real.
Break the cycle by extracting the shared value the back-edge needs into a third leaf module both files import one-directionally (A->C, B->C), or by inverting the dependency so the lower-level module stops importing the higher-level one (pass the value in as a parameter / inject it rather than importing it). If the reference is genuinely lazy, defer it: turn a top-level import { x } from './b' used inside a function into a local access at call time, or move the back-import after this module's own exports initialize, eliminating the TDZ window where one module reads its partner's binding before that binding is assigned. Prefer extraction over deferral — a stable acyclic graph restores tree-shaking and predictable init order. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#temporal_dead_zone_tdz