Metadata-Version: 2.4
Name: codaviz
Version: 0.7.0
Summary: Analyze and visualize complexity hotspots in Python, JS/TS, Go, Ruby, Rust, Java, and PHP codebases.
Author: Stefane Fermigier
Author-email: Stefane Fermigier <sf@abilian.com>
License-Expression: Apache-2.0
License-File: LICENSE
Requires-Dist: cognitive-complexity>=1.3
Requires-Dist: cyclopts>=3.0
Requires-Dist: jinja2>=3.1
Requires-Dist: mccabe>=0.7
Requires-Dist: pluggy>=1.5
Requires-Dist: radon>=6.0
Requires-Dist: tree-sitter>=0.26,<0.27 ; extra == 'treesitter'
Requires-Dist: tree-sitter-language-pack>=1.17 ; extra == 'treesitter'
Requires-Python: >=3.12
Provides-Extra: treesitter
Description-Content-Type: text/markdown

# codaviz

A lightweight CLI that analyzes code complexity and emits a single, self-contained, interactive HTML report — a simpler, local alternative to SonarQube for spotting where to refactor. Python works out of the box; JavaScript/TypeScript, Go, Ruby, Rust, Java, and PHP are supported via an optional [tree-sitter](https://tree-sitter.github.io/) extra.

Point it at a repo and it ranks **complexity hotspots**, draws a **treemap** (sized by lines of code, colored by a metric you pick), lets you **drill into any module** to read its functions and source, and flags **circular imports** and **over-threshold functions**. No server, no database, no network — the report is one HTML file you can open offline or email to a teammate.

![codaviz interactive report — treemap, top-modules chart, and per-function drill-down with cyclomatic + cognitive complexity](docs/src/images/screenshot.png)

Full documentation lives in [`docs/src/`](docs/src/) (built with [Zensical](https://zensical.org/): `make docs`).

## Quick start

codaviz is a [uv](https://docs.astral.sh/uv/) project. From a checkout:

```bash
uv sync                          # install (Python analysis)
uv sync --extra treesitter       # + JS/TS, Go, Ruby, Rust, Java, PHP
uv run codaviz /path/to/project  # writes ./report.html
open report.html                 # (macOS; use xdg-open on Linux)
```

Try it on codaviz itself:

```bash
uv run codaviz . && open report.html
```

To install it as a standalone command:

```bash
uv tool install .                  # Python only
uv tool install ".[treesitter]"    # all languages
# then, anywhere: codaviz /path/to/project
```

## Usage

```
codaviz [OPTIONS] [PATHS...]

  PATHS                Project directories to analyze (default: current dir).
                       Pass several to merge a workspace into one report.

  -f, --format         html | json | csv          (default: html)
  -o, --output FILE    Output file
                       (html → report.html; json/csv → stdout unless set)
      --no-source      Omit embedded source snippets (smaller, shareable report)
      --version        Show version and exit
  -h, --help           Show help and exit
```

Examples:

```bash
codaviz ~/src/myapp                     # interactive report.html
codaviz ~/src/myapp -o myapp.html       # custom output path
codaviz ~/src/myapp --no-source -o share.html   # no source embedded
codaviz ~/src/myapp -f json > data.json # raw entity data
codaviz ~/src/myapp -f csv  > data.csv  # one row per package/module/function
codaviz packages/*                      # merge a workspace into one report
```

## The report

- **Treemap** — packages and modules as nested tiles, sized by lines of code and colored by the selected metric (packages by their *aggregate* over all descendants; greener = better). Click a package to zoom in; a **depth** control caps how many levels show at once so large trees stay readable.
- **Metric selector** — switch between **Maintainability index** (default), **max/total cyclomatic**, **max/total cognitive**, and **lines of code**; the treemap, bar chart, and table all re-rank instantly.
- **Hotspots table & bar chart** — ranked by the selected metric, with LOC / MI / max & total cyclomatic / max & total cognitive / function count. A **Modules / Packages** toggle switches between per-module rows and package aggregates — so a complex package still stands out even when it's split into many small modules.
- **Function detail** — click a tile, bar, or row to see that module's functions, each with a **CC** (cyclomatic) and **Cog** (cognitive) badge, line number, and source snippet. Functions over either threshold get a "consider extracting" / "hard to follow" hint.
- **Circular imports** — modules that import each other (statically detected) are listed as cycles.

## What gets analyzed

Inside a git repo, codaviz analyzes the source files git knows about — tracked **and** uncommitted — while honoring `.gitignore` (so `.venv`, build output, and ignored trees are skipped). Outside a repo, it walks the directory. Each file is dispatched by extension to the analyzer for its language. On top of that it always skips common noise: virtualenvs, caches, `build/`, `dist/`, `node_modules/`, `site-packages/`, `migrations/`, and test files (`tests/`, `test_*.py`, `*_test.py`, `conftest.py`) unless you opt in.

## Languages

| Language | Metrics | Extensions |
|---|---|---|
| **Python** | CC, cognitive, MI, SLOC | `.py` |
| **JavaScript / TypeScript** | CC, SLOC | `.js .jsx .mjs .cjs .ts .tsx .mts .cts` |
| **Go** | CC, SLOC | `.go` |
| **Ruby** | CC, SLOC | `.rb` |
| **Rust** | CC, SLOC | `.rs` |
| **Java** | CC, SLOC | `.java` |
| **PHP** | CC, SLOC | `.php .phtml` |

Python works with no extra dependencies. Every other language uses [tree-sitter](https://tree-sitter.github.io/) and needs the optional `treesitter` extra (`pip install codaviz[treesitter]` / `uv sync --extra treesitter`); without it, those files are simply skipped. Maintainability index is Python-only and per-language cognitive complexity is planned, so non-Python modules report cyclomatic + SLOC and the report opens on a cyclomatic lens. A single report can mix languages.

**Adding a language.** codaviz uses a [pluggy](https://pluggy.readthedocs.io/) plugin system: a package contributes analyzers over the `codaviz` hook namespace and registers via the `codaviz` entry-point group. A new tree-sitter language is a small config subclass (its grammar + which node kinds count) — no new parsing code.

## Metrics

| Metric | Meaning | Direction |
|---|---|---|
| **Cyclomatic (CC)** | McCabe complexity — branch/loop count + 1. Per function. Matches Ruff's C901 / `python -m mccabe`. | higher = worse |
| **Cognitive (Cog)** | SonarSource cognitive complexity — penalises *nesting*, ignores shorthand humans read easily. The better "how hard to understand" signal. Per function. | higher = worse |
| **Maintainability index (MI)** | radon's 0–100 composite (≥20 = A/good, 10–19 = B, <10 = C). Per module. Kept as the familiar number. | lower = worse |
| **SLOC** | Source lines of code (excludes blanks/comments). | — (used for tile size) |

For **Python**, cyclomatic complexity comes from [`mccabe`](https://github.com/PyCQA/mccabe) (so the numbers match Ruff), cognitive from [`cognitive_complexity`](https://github.com/Melevir/cognitive_complexity), MI + SLOC from [`radon`](https://radon.readthedocs.io/), and circular imports from a static `ast` import graph (no code is executed). For **other languages**, cyclomatic + SLOC are computed from the tree-sitter syntax tree — McCabe-*family* (decision points + 1), not tied to any specific external tool, so numbers are internally consistent per language but not claimed to match gocyclo/PMD/ESLint.

## Configuration

Optional `[tool.codaviz]` table in the analyzed project's `pyproject.toml`:

```toml
[tool.codaviz]
exclude = ["generated/*.py", "vendor/**"]  # extra glob patterns to skip
max-complexity = 15                         # cyclomatic threshold for hints
max-cognitive = 15                          # cognitive threshold for hints
treemap-depth = 2                           # initial treemap depth (0 = all levels)
include-tests = false                       # set true to analyze test files too
```

## Known limitations

- **Nested defs**: closures and methods of function-local classes are folded into their enclosing function's score rather than listed separately — matching how Ruff/mccabe report the outer function.
- **Circular imports**: resolution favors false negatives over false positives. `src/` layouts, implicit namespace packages, and relative imports resolve correctly (names are computed relative to the detected source root); dynamic or conditional imports are not tracked.
- **Color scale**: the badness ramp is green→amber→red with a "better → worse" legend and a numeric table as non-color channels; a fully colorblind-safe palette is a planned option.

## Development

```bash
make test     # uv run pytest
make lint     # ruff check + format check + type checks
make format   # ruff format + autofix
```

The test suite spans unit / integration / end-to-end tiers, including in-browser execution of the report's JavaScript via Node.

## Status

Latest release **0.6.0**; **multi-language + plugin support** has landed on `main` (see [`CHANGES.md`](CHANGES.md), Unreleased). Stable and usable: hotspots, treemap (package-level aggregates, tunable depth), drill-down, cyclomatic + cognitive complexity, maintainability index, circular imports, threshold hints, `src/`-layout and multi-root/workspace analysis, **seven languages** behind a pluggy plugin seam, and HTML/JSON/CSV output. Planned next (rough order): a shared **cognitive-complexity walker** for the tree-sitter languages, **churn-weighted hotspots** (complexity × git change-frequency), and **coupling metrics** (afferent/efferent, instability). See [`notes/`](notes/) for the vision, spec, and plans.

## Non-goals

Security scanning (use Bandit), runtime profiling (use `cProfile`/`scalene`), and test coverage (use `pytest-cov`) are out of scope — codaviz focuses on structural complexity.

## License

Apache License 2.0 — see [`LICENSE`](LICENSE).
