Repowise ships language-aware resolvers under
packages/core/src/repowise/core/ingestion/resolvers/. Each tier
provides a different depth of analysis; lower tiers fall back to the
generic resolver (file and symbol extraction, no import edges).
Coverage matrix
| Tier | Languages | What works |
|---|---|---|
| Full | Python · TypeScript · JavaScript · Svelte · Vue · Java · Kotlin · Go · Rust · C++ · C# · Scala · Ruby | AST parsing, import resolution, named bindings, call resolution, heritage extraction, docstrings; multi-project workspace resolvers (.csproj/.sln for C#, Cargo.toml [workspace] for Rust, go.mod multi-module, package.json workspaces, Gradle/Maven for JVM); framework-aware edges (Django, FastAPI, Flask, ASP.NET, Spring, Express/NestJS, Next.js, Gin/Echo/Chi, Axum/Actix, Rails); per-language dynamic-hint extractors for runtime DI / reflection / plugins; code-health markers |
| Good | C · Swift · PHP · Dart · Object Pascal | AST parsing, import resolution, named bindings, call resolution, heritage (Swift extension conformance, PHP trait use, Dart mixins), docstrings; dedicated workspace-aware resolvers (SPM, composer PSR-4, pubspec.yaml, uses-clause unit-name fallback for Object Pascal); Laravel / TYPO3 / Flutter framework edges. Dart and Object Pascal also get code-health markers; C, Swift, and PHP don't yet |
| SQL / dbt | .sql via a dedicated sqlglot handler | Tables/views/functions/procedures as symbols with wiki pages; dbt projects get real ref()/source() lineage; app-to-database contracts in workspace mode |
| Shell | .sh · .bash · .zsh | Function definitions as symbols, source / . import edges (including $SCRIPT_DIR and $(dirname "$0") idioms), and function-level complexity markers. No class metrics, heritage, bindings, or dead-code flagging |
| Config / data | OpenAPI · Protobuf · GraphQL · Dockerfile · Makefile · YAML · JSON · TOML · Terraform · Markdown · AsciiDoc · XAML | Included in the file tree; special handlers extract endpoints/targets where applicable. XAML (WPF, WinUI 3, UWP, MAUI, Avalonia/Uno) additionally gets a regex-based resolver linking .xaml/.axaml files by ResourceDictionary reference |
| Lightweight | Elixir · Clojure · Haskell · Lean 4 · Erlang · F# · HTML | Regex-tier file-level import graph only, no symbols or calls (HTML uses the tree-sitter-html grammar instead of the regex tier) |
| Partial | Luau / Roblox | AST symbols + require() resolution (Rojo / .luaurc aware); no health markers yet |
| Structural | Objective-C · R · Zig · Julia · Elm · OCaml · Crystal · Nim · D | Git history only (blame, hotspots, co-change); no AST parsing |
19 languages parsed to AST, 13 of them at the Full tier (5 more at the
Good tier, plus Luau at the Partial tier). The thirteen Full-tier languages
plus Dart and Object Pascal also get the
code-health marker suite. Scala's import
resolution is partial: it shares the JVM index with Java and Kotlin, with
SBT/Mill build-file parsing as a fallback. Svelte and Vue share the
TypeScript resolver: a single-file component's <script> block and markup
expressions are projected to a TypeScript buffer at byte-identical
offsets, so the same queries, config, and code-health dialects apply.
Framework awareness
Several languages get extra treatment: repowise recognises common framework conventions and emits edges for them, even when the underlying call goes through a decorator or a runtime registry.
| Language | Frameworks |
|---|---|
| Python | Django (URL patterns, models, signals), FastAPI (route handlers, dependency injection), Flask (route decorators) |
| C# | ASP.NET (controllers, attributes), dependency injection containers |
| Java / Kotlin | Spring Boot (@RestController, @Component, @Autowired) |
| JavaScript / TypeScript | Express, NestJS (@Controller, @Module, @Injectable) |
| Go | Gin, Echo, Chi router patterns |
| Rust | Axum, Actix routes |
| Ruby | Rails (Zeitwerk autoloading, route DSL) |
| PHP | Laravel routes, TYPO3 conventions |
| Dart | Flutter route tables, runApp() edges |
Dead-code awareness
Repowise's dead-code detector knows about dynamic dispatch patterns that look "unused" to a static analyzer but aren't:
- Naming patterns:
*Plugin,*Handler,*Adapter,*Middleware - Dynamic imports:
importlib.import_module(),__import__(), dynamicrequire() - Framework convention files (Flask blueprints, FastAPI routers, Django apps, Rails controllers, Laravel providers, TYPO3 extensions)
These are excluded from safe_to_delete findings to keep the
false-positive rate near zero.
Code-health marker rollout
Code-health markers, Extract Method (dataflow), and the performance
signal each roll out per language independently, since they run off a
separate complexity-walker map rather than the .scm grammar:
| Signal | Coverage |
|---|---|
| Complexity, class metrics, assertion smells | All Full-tier languages, plus Dart |
Performance risk (io_in_loop, etc.) | Python, TypeScript/JavaScript, Svelte, Vue, Java, Go, C#, Rust, Dart, Kotlin, C++, Scala, Ruby |
| Extract Method (dataflow) | Python, Go, TypeScript/JavaScript, Svelte, Vue, Java, Rust, C++; C#, Kotlin, Dart, Scala, Ruby, and Object Pascal pending (Kotlin is blocked on the grammar, not merely unscheduled) |
Adding a language
Adding new language support is five required steps: a LanguageSpec
module, a manual LanguageTag registration, a tree-sitter .scm query
file, a LanguageConfig entry, and the grammar dependency. Two of those
are one-line registrations, but the LanguageTag edit can't be derived
and has to be made by hand. No changes to parser.py, graph.py, or
any other analysis core file. See
architecture/language-support.md
in the OSS repo for the full recipe, including the optional steps that
buy heritage extraction, named bindings, and call resolution.
Working in a language we don't list? Repowise still indexes the file tree, ownership, and churn; you just won't get import edges or framework-aware analysis. Open a Discussion and we'll prioritise.