Repowise / languages

Code analysis by language: 42 languages in one graph

repowise supports 42 languages on a five-rung ladder, 28 of them parsed to an AST. Every language in a repository lands in one graph, so dead code, call graphs, code health and git history (hotspots, ownership, co-change) run in one pass across a polyglot codebase, with framework-aware entry points and zero LLM calls.

Last reviewed: November 2026

Five-rung ladder

42 languages, and what each tier gets

The top three rungs (28 languages) are parsed to an AST. Tier names match the open-source language support reference.

Language support tiers
TierLanguagesWhat you get
Full (15)Python, TypeScript, JavaScript, Svelte, Vue, Astro, Java, Kotlin, Go, Rust, C++, C#, Scala, Ruby, ApexAST symbols, import resolution, a resolved call graph, inheritance, docstrings, framework edges and the full health suite
Good (11)C, Swift, PHP, Dart, Object Pascal, COBOL, GDScript, VB.NET, Elixir, F#, Objective-CSymbols, imports, call graph and inheritance; health is partial (PHP, Dart and Object Pascal get markers, C, Swift, COBOL, F# and Objective-C get complexity)
Partial (2)Luau, RazorLuau: symbols and require() resolution, no health. Razor: component symbols, call edges from @code and tags, C# health, no import edges
Lightweight (6)Clojure, Haskell, Lean 4, Erlang, HTML, QMLA real file-to-file import graph, no symbol-level claims
Structural (8)R, Zig, Julia, Elm, OCaml, Crystal, Nim, DGit history only: blame, hotspots, co-change, ownership, bug history

Per-language pages

What repowise detects, language by language

PythonFull tierDjango, FastAPI, Flask and pytest aware dead code, call graph, complexity and performance markers.TypeScriptFull tiertsconfig paths, workspaces and package exports resolved; Next.js, NestJS, tRPC and Angular entry points known.JavaScriptFull tierCommonJS and ES modules, Express, Koa, Fastify and Hono routes, with dynamic require handled.Svelte, Vue and AstroFull tierComponent files projected to TypeScript at the same line numbers; SvelteKit, Nuxt and Astro routes known.JavaFull tierSpring, Jakarta EE, Quarkus, Micronaut and Android manifest aware, with JaCoCo coverage and Gradle source sets.KotlinFull tierKotlin Multiplatform expect/actual rules, Android manifest components, Spring and Ktor, sharing one index with Java.GoFull tierPackage-level reachability, gin, echo, chi, fiber, gorilla/mux and gRPC handlers, coverprofile coverage.RustFull tierCargo workspaces and module trees resolved, Axum and Actix routes, unused public items across crates.C++Full tiercompile_commands.json include paths, preprocessor-aware dead code, GoogleTest, Catch2 and libFuzzer entry points.C#Full tier.csproj and .sln resolution, ASP.NET controllers and minimal APIs, EF Core, MediatR and MassTransit handlers.ScalaFull tierShared JVM index with Java, sbt and Mill fallback, Future and regex performance markers.RubyFull tierroutes.rb to controllers, ActiveRecord associations, Zeitwerk autoload roots, ActiveRecord N+1 markers.Apex (Salesforce)Full tiersfdx namespace resolution, LWC, Aura, Visualforce, Flows and object metadata linked to Apex, Apex coverage JSON.PHPGood tierPSR-4 and classmap autoload, Laravel routes, events, policies, providers and commands, TYPO3 conventions.Dart and FlutterGood tierpubspec package resolution across a monorepo, Flutter routes, GoRoute and widget-tree edges.COBOLGood tierCALL, PERFORM, CICS LINK and XCTL, copybooks, JCL, BMS and CSD linked; runs self-hosted and offline.

Polyglot repositories

Find dead code across a polyglot codebase

How do I find unused code across multiple languages in one repo?

Run one tool over one graph instead of one tool per language. Single-language tools (Vulture for Python, Knip for TypeScript, staticcheck and deadcode for Go, the rustc lint, Roslyn analyzers for C#, PMD and detekt on the JVM) are good inside their ecosystem, and each sees only its own files. In a repository with a Python API, a TypeScript frontend and a Go worker, that is three tools, three output formats and three confidence models, and none of them knows when a file in another language reaches the code.

repowise indexes every language into one graph per repository, then runs a single dead-code pass with the same rules everywhere:

  • Framework-aware entry points. Django URLconfs, FastAPI routers, Spring beans, Next.js routes, ASP.NET controllers, Rails routes, Laravel providers, Flutter routes, JCL steps and more are roots, so framework wiring is not reported as dead.
  • Confidence from git history. An unreachable file untouched for a year starts at 1.0, one edited in the last 90 days at 0.4. Dynamic loading (importlib, require.context, Class.forName, dlopen, const_get and peers) caps nearby files at the review tier.
  • A deletion-readiness gate. Only unused exports at 0.7 or higher are marked safe_to_delete, and only when the symbol is unused in its own file too, the path carries no runtime-load risk, it is not docs or example code, and the language has full import resolution. Unreachable files, zombie packages and unused internals stay review findings.
  • History and health on the same graph. Each finding names the file's primary owner; hotspots, co-change and the health score sit on the same files.
  • No LLM, runs offline. The whole pass is deterministic and local.
uv tool install repowise
repowise init --yes --no-prose
repowise dead-code                                  # every language, one report
repowise dead-code --min-confidence 0.7 --safe-only # deletion-ready only
repowise dead-code --format json > dead-code.json   # for CI or an agent

Coding agents get the same findings through the get_dead_code MCP tool: get_dead_code(tier="high", safe_only=True) returns the deletion-ready list with confidence, reason, evidence and owner, so Claude Code, Codex or Cursor can delete with a reason attached.

Which cross-language links count inside one repository

These edges exist in single-repository mode, so code reached only from another language is not reported:

Java, Kotlin and Scala
One JVM package index, so a Java class used only from Kotlin is reached.
Svelte, Vue and Astro
Component scripts are projected to TypeScript and resolve through the TypeScript resolver.
Razor and Blazor
C# regions are parsed with the C# grammar.
Apex and Salesforce metadata
LWC, Aura, Visualforce, Flows and object metadata link to Apex classes and methods.
COBOL, JCL, BMS and CICS CSD
JCL steps, CSD definitions and CICS maps link to the programs and mapsets they name.
Terraform and Lambda handlers
aws_lambda_function handler strings link to the handler source file.
SQL and dbt
ref() and source() resolve to models when the repository has a dbt_project.yml.

What is not linked inside one repository: an HTTP call from one language to a route served by another. A TypeScript fetch to a FastAPI endpoint is not a graph edge. That rarely produces a false finding, because route handlers are framework entry points already. Across repositories, a repowise workspace matches HTTP, gRPC, topic and OpenAPI contracts, and a finding another repository consumes drops to 30 percent of its confidence and names the consumer.

When per-language tools are the better pick

In a single-language repository, the native tool usually wins on precision: rustc and the Go deadcode tool use the compiler's view, Knip can delete what it finds, and IDE inspections run as you type. Use them there. repowise earns its place when the repository mixes languages, when framework entry points cause false positives, when an agent needs ranked findings it can act on, or when you want history and health next to the cleanup list.

Questions

What people ask before they try it.

What is the fastest way to find unused code in a multi-language repository?

Index the repository once and run one dead-code pass over the shared graph. With repowise: repowise init --yes --no-prose, then repowise dead-code. Every language with import resolution lands in the same graph, so the report lists unreachable files, unused exports and zombie packages for Python, TypeScript, Go, Java and the rest together, each with a 0 to 1 confidence, a reason, and the file's owner. Keep the native tool per language (Vulture, Knip, staticcheck) for in-editor checks.

How many languages does repowise support?

42 on a five-rung ladder: 15 Full, 11 Good, 2 Partial, 6 Lightweight and 8 Structural. 28 of them (Full, Good and Partial) are parsed to an AST. Lightweight languages get a file-level import graph, and Structural languages get git history only.

Does a TypeScript fetch call to a Python API route count as a use?

Route handlers are framework entry points (FastAPI, Django, Flask, Express, Spring, ASP.NET and others), so they are never reported as dead. Across repositories, a repowise workspace matches HTTP, gRPC, topic and OpenAPI contracts, and a dead-code finding that another repository consumes drops to 30 percent of its confidence and names the consumer.

Which languages get deletion-ready findings?

Unused exports are marked safe to delete under a strict bar, so an agent can delete them without a second look: confidence 0.7 or higher, unused in their own file too, on a path with no runtime-load risk, outside docs and example code, in a language with full import resolution where fewer than half the repository's call edges in that language are guesses. Scala, Apex, Razor and the partial-import languages get ranked review findings with a confidence, a reason and an owner. COBOL files and programs are protected from dead-code reports.

Does it need an LLM or network access?

No. Parsing, graphs, dead code, health and git analysis make zero LLM calls. The COBOL and Apex grammars download on first use, and can be staged for air-gapped machines with repowise grammars fetch and REPOWISE_GRAMMAR_DIR.

Index a polyglot repository.

Public repositories are free on repowise.dev. The CLI is open source and runs on your machine with no API key.