Skip to content

Latest commit

 

History

161 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Energy State Analyzer

Visualizes "energy states" in Python, F#, TypeScript, Kotlin, and C++ code as you edit: parts of a file that are complex, deeply nested, or otherwise harder to understand and maintain get highlighted with colored gutter icons, inline decorations, and entries in the Problems panel.

Energy State Analyzer screenshot

Features

Real-time analysis of the active Python, F#, TypeScript, Kotlin, or C++ file, re-run on every edit and on editor focus change, via these detectors (see docs/detectors for full detail on each):

Violations are shown three ways:

  • A colored background + gutter lightning-bolt icon on the affected lines (orange = high severity, gold = medium, green = low; colors are configurable, see Extension Settings).
  • A hover tooltip explaining the specific violation.
  • An entry in the Problems panel, sourced as "Energy State Analyzer".

For functions flagged as too complex (cyclomatic or cognitive), a progressive heatmap in the configured high-energy color (orange by default) is also painted across the function body: each contributing line (an if, for, and, etc.) is shaded from light to dark based on how much it drives up that function's complexity relative to its own worst line, so you can see exactly which branches to break apart first, instead of just knowing the function as a whole is complex.

Energy and Entropy

The name is a deliberate analogy to thermodynamics: a function's "energy" is its complexity, nesting, and parameter count, while its "entropy" is how many ways it can be called, misunderstood, or silently broken by a change. Primitive obsession raises entropy too: broad, interchangeable strings and numbers admit invalid calls and swaps, and force the reader to retain conventions that distinct, validated domain types could express. See docs/energy-and-entropy.md for the full explanation of why cyclomatic and cognitive complexity are tracked as separate metrics rather than one score.

Command-Line Usage

The same detectors also run headlessly, without VS Code, useful for CI or for an AI coding agent that wants to check the complexity of code it just generated and keep refactoring until it's clean:

npx energy-state-analyzer path/to/file.py   # or .fs / .fsx / .ts / .kt / .cpp / .hpp

See docs/cli.md for scanning a whole repo, aggregated markdown/JSON/human reports, and diffing a PR against a base branch.

Requirements

The extension activates automatically when you open a Python, F#, TypeScript, Kotlin, or C++ file; it bundles its own grammars for parsing (via web-tree-sitter), so no compiler or external parser is required. F# files only get a fsharp language ID (and so trigger analysis) if you have an F# language extension installed (e.g. Ionide), VS Code otherwise treats .fs files as plain text. The CLI recognizes the full VS Code C++ suffix set, including compound template suffixes such as .hpp.in; see Command-Line Usage.

Development

Product and test sources are F#. Install the pinned .NET tools (Fable and Fantomas) and npm dependencies, then use the wrapped commands:

just setup
just install
just build
just test

Fable emits JavaScript with --lang javascript --noCache into ignored fable-out/; webpack then creates dist/extension.js and dist/cli.js. just lint checks F# formatting, just format formats it, and just analyze runs the built F# CLI against the production F# source. Press F5 for the Extension Development Host.

Extension Settings

Settings split into two concerns: which detectors run and how they look live in VS Code (editor-only toggles and colors), while how strict each detector is belongs in a project .esaconfig.json shared with the CLI/CI. An explicitly configured VS Code value can override a detail setting for the current workspace.

Enable/disable detectors and pick colors (VS Code settings)

Every detector has an enabled toggle, plus the magic-number/string switches and the color palette. All toggles default to true. See each detector's doc (linked under Features above) for what it flags:

  • energyStateAnalyzer.nesting.enabled (true)
  • energyStateAnalyzer.cyclomaticComplexity.enabled (true)
  • energyStateAnalyzer.cognitiveComplexity.enabled (true)
  • energyStateAnalyzer.coherence.enabled (true)
  • energyStateAnalyzer.matchOpportunity.enabled (true)
  • energyStateAnalyzer.parameterCount.enabled (true)
  • energyStateAnalyzer.primitiveObsession.enabled (true)
  • energyStateAnalyzer.opaqueBoolean.enabled (true)
  • energyStateAnalyzer.logicalControlFlow.enabled (true)
  • energyStateAnalyzer.inversion.enabled (true)
  • energyStateAnalyzer.errorShadowing.enabled (true)
  • energyStateAnalyzer.magicNumber.enabled (true)
  • energyStateAnalyzer.magicString.enabled (true)
  • energyStateAnalyzer.colors.highEnergy / .mediumEnergy / .lowEnergy (#fb8500 / #ffb703 / #99dd99)
  • energyStateAnalyzer.colors.backgroundOpacity (0.1)

Thresholds and allowlists (.esaconfig.json)

Set thresholds, ratios, and magic-number/string allowlists in an .esaconfig.json file to share them between the editor and CLI/CI — see docs/configuration.md for the schema, per-key defaults, guidance on choosing thresholds, and how the file layers over VS Code settings (defaults < .esaconfig.json < host override). The keys (all optional; an absent key keeps its default) include:

  • nesting.mediumThreshold / highThreshold (3 / 5)
  • cognitiveComplexity.mediumThreshold / highThreshold (15 / 25)
  • coherence.largeFunctionLines (20), maxLargeFunctions (5), singleDomainNameShare (0.7)
  • matchOpportunity.minBranches (3)
  • parameterCount.mediumThreshold / highThreshold (5 / 8)
  • errorShadowing.threshold / highThreshold / minNamedNodes (0.5 / 0.7 / 8)
  • magicNumber.allowlist ([0, 1, -1, 2])
  • magicString.minDuplicates (2), allowlist (["", "utf-8", "__main__"])

The magic-number/string enabled toggles above remain in VS Code — enabling or disabling a detector is an editor-only convenience, so it stays out of the shared project file.

Changes take effect immediately on the active editor.

To exclude files/folders (e.g. test fixtures, generated code) from both the extension's live analysis and the CLI, add a .esaignore file to your workspace root — see docs/cli.md.

Commands

  • Energy State Analyzer: Analyze Energy State (energy-state-analyzer.analyze), manually re-run analysis on the active editor.
  • Energy State Analyzer: Export SARIF Report (energy-state-analyzer.exportSarif), scan the workspace and write .energy-state/latest.sarif for SARIF-compatible tools.

Known Issues

  • TypeScript arrow functions aren't analyzed by complexity/parameter-count/coherence (same limitation Python already has for lambda), only named function declarations and class methods are.
  • C++ analysis is syntax-only: it does not preprocess macros, resolve includes, instantiate templates, or perform type checking. C++ lambdas are not treated as standalone functions by function-level detectors.
  • Several detectors have per-language gaps beyond the above, see the "Known limitations" section of the relevant detector doc.