The Problem

TypeScript agents and developers need fast, deterministic answers about code structure—what names exist, where they're referenced, where duplicate logic lives, and where low-value "slop" code accumulates. Existing tools either require network services, index databases, or produce non-deterministic output that breaks scripted workflows.

What This Does

scanr is a single static-analysis CLI binary written in Rust (52 files under src/). It extracts structural inventory (functions, types, components, hooks), traces declaration-to-usage references, detects near-duplicate functions and types via APTED tree edit distance, and flags evidence-backed "slop" patterns. All analysis is offline, deterministic, and gitignore-aware.

The codebase splits into three command groups: src/commands/ handles the CLI surface (search, scan, refs, dupes, slop, tree), src/scan/ implements structural extraction and rule checking, and src/similarity/ contains the tree-diffing engine. A .claude-plugin/ directory packages it for Claude Code agents.

How It Is Wired

Execution starts at src/main.rs, which parses arguments via src/cli.rs and dispatches to command handlers in src/commands/. Each command follows the same pattern: parse flags → walk the filesystem (respecting .gitignore) → process files → emit sorted, stable output.

The scan command routes through src/scan/typescript/extract.rs and parse.rs to build structural inventories. The dupes command uses src/similarity/apted.rs for exact tree matching and fast_similarity.rs for approximate comparison. The slop command draws on detectors in src/slop/exact_detectors.rs, contextual_detectors.rs, and low_value_detectors.rs.

The widest blast radius sits in src/scan/typescript/extract.rs—nearly every command depends on its inventory output, and changes there ripple through refs, dupes, and slop. The src/similarity/ module is the most complex, with 18 files handling tree adaptation, fingerprinting, and type comparison; modifying it requires understanding the AST adapter chain (typescript_structure_adapter.rstree.rsapted.rs).

External effects are minimal: the binary reads files, writes to stdout, and exits. No database, network calls, or API keys. The Makefile and Dockerfile provide build paths, and GitHub Actions in .github/workflows/ runs CI and release builds.

How To Use It

# Build from source (Rust 1.95+)
git clone https://github.com/moses-y/scanr
cd scanr
cargo build --release

# Or via Homebrew
brew install nikuscs/tap/scanr

No environment variables or configuration files required. Run commands directly:

scanr search "useState" --root . --json
scanr scan --root . --mode inventory
scanr refs Card --root .
scanr dupes --root . --types
scanr slop --root .
scanr tree --root .

Real-World Use

For a CI pipeline reviewing TypeScript PRs, scanr can gate merges on structural quality:

scanr scan --root . --mode inventory --json > inventory.json
scanr dupes --root . --types --json > dupes.json
scanr slop --root . --json > slop.json
# Parse JSON outputs in a script; fail the build on high-severity findings

The deterministic, JSON-sorted output makes these results stable across runs—critical for diff-based review tooling.

Code Health & Issues

Deep static analysis has not run on this repository. Structural observations from the file layout:

  • Low - No CONTRIBUTING.md or explicit contribution guide; the 5 doc files cover usage but not development workflow.
  • Low - Forked from nikuscs/scanr with 0 stars on this fork; upstream maintenance status is unclear.
  • Positive - 9 test files exist alongside source modules, CI is configured, and a Cargo.lock is committed for reproducible builds.

The Bottom Line

A focused, well-architected tool for TypeScript codebase analysis that prioritizes determinism and offline operation. The Rust implementation is solid, with clear module boundaries and test coverage. Teams needing fast, scriptable structural analysis without external dependencies will find it valuable; those wanting IDE-grade intelligence should look elsewhere.