Skip to content

release: v0.4.0 — language-support upgrades across all Good-tier languages#106

Merged
RaghavChamadiya merged 10 commits intomainfrom
feat/language-tier-upgrades
Apr 26, 2026
Merged

release: v0.4.0 — language-support upgrades across all Good-tier languages#106
RaghavChamadiya merged 10 commits intomainfrom
feat/language-tier-upgrades

Conversation

@RaghavChamadiya
Copy link
Copy Markdown
Collaborator

Summary

  • Workspace-aware import resolvers for every Good-tier language: PHP composer PSR-4, Go multi-module monorepos, TypeScript npm/yarn/pnpm workspaces + .vue/.svelte/.astro SFC probing, Kotlin Gradle subprojects + sourceSets, Rails / Zeitwerk autoloading, Swift SPM Package.swift targets, Scala SBT / Mill multi-project, and Cargo [workspace] member crates.
  • Framework-aware edges for Spring Boot DI + @Bean factories, Rails routes + ActiveRecord, Laravel routes + service providers + Eloquent, Express app.use(router) + NestJS @Module arrays, Gin/Echo/Chi, and Axum/Actix.
  • Per-language dynamic-hint extractors for Spring getBean/@Bean, Ruby send/const_get/delegate, PHP call_user_func/ReflectionClass/container get, Scala Class.forName/given/implicit val, Swift NSClassFromString/Selector/KVC, C function-pointer assignment + dlopen/dlsym, Luau game:GetService/metatables, Go reflect.TypeOf/plugin.Open/plugin.Lookup. All wired into HintRegistry so find_dynamic_edge_files automatically suppresses dead-code findings for files involved in any new dynamic edge.
  • .scm symbol coverage closures: Java records + class/interface/record annotation modifiers, Kotlin typealias + class-level vals, Scala 3 enum/given/var + @deprecated/@tailrec, Swift subscript, Ruby top-level constants, PHP const/property, C primitive/struct typedef aliases.
  • Documentation extraction added for Java module-level Javadoc and Luau (both module + symbol).
  • Heritage fixes: Java interface … extends … now resolves; Go struct embedding now traverses field_declaration_list; Swift extension_declaration heritage works.
  • Pre-existing C# Full-tier work (.csproj/.sln-aware resolver, ASP.NET edges, .NET dynamic hints, cross-repo <ProjectReference> + internal NuGet, modern C# .scm features, XML doc parsing) rolls forward into this release unchanged.
  • +90 unit tests. Final regression: 1409 passing (up from 1278 at the start of the language-support pass) plus the one pre-existing unrelated MCP integration failure.
  • Net no public-API changes — all additive. Heritage / bindings / dead-code internals were split into per-language subpackages with re-export shims; old import paths keep working.

Test plan

  • pytest — 1409 passed, 11 skipped, 2 xfailed; one unrelated pre-existing failure (test_mcp_full_exploration_flow) carries from main.
  • All four version pins match (pyproject.toml, repowise.{core,cli,server}.__version__).
  • docs/CHANGELOG.md v0.4.0 entry covers every shipped change.
  • README.md Supported-languages table reflects new resolver + framework + dynamic-hint coverage.
  • Manual smoke: pip install -e . and repowise --version reports 0.4.0.
  • Manual smoke: repowise init on a Spring + Rails + Laravel + Cargo-workspace fixture and confirm framework edges land in the wiki.

… per-language subpackages

- heritage.py (623 LOC) -> extractors/heritage/{lang}.py with __init__.py
  re-exporting extract_heritage, HERITAGE_EXTRACTORS, heritage_node_types_for
- bindings.py (527 LOC) -> extractors/bindings/{lang}.py with __init__.py
  dispatcher preserving extract_import_bindings public API
- dead_code.py (744 LOC) -> analysis/dead_code/ subpackage with analyzer,
  models, constants, and dynamic_markers separated; public API
  (DeadCodeAnalyzer, DeadCodeKind, DeadCodeFindingData, DeadCodeReport)
  preserved

Also fixes Swift extension protocol conformance: extension_declaration was
parsed correctly by _extract_swift_heritage but the upstream filter in
languages/registry.py discarded it. Adds extension_declaration to Swift's
heritage_node_types so 'extension Foo: Protocol {}' produces a heritage
edge.

Adds first regression coverage for Kotlin and Swift extractors
(test_kotlin_extractors.py, test_swift_extractors.py) covering interface
parsing as class_declaration, class/object capture, extension
conformance, multi-protocol conformance, and class/protocol inheritance.
… enable internal-symbol audit

- analysis/dead_code/dynamic_markers.py: add find_dynamic_edge_files(graph)
  enumerating files involved in edge_type="dynamic" or "dynamic_*" edges.
  Expand _DYNAMIC_IMPORT_MARKERS for Go, Ruby, PHP, Kotlin; add Swift
  and Scala marker tuples.
- analysis/dead_code/analyzer.py: union find_dynamic_import_files
  (text-scan) with find_dynamic_edge_files (graph-scan) in __init__,
  so DotNet DI / Activator / Django / Pytest / Node dynamic hints
  suppress dead-code false positives. Generalize evidence string from
  importlib-specific wording to "dynamic imports or runtime-resolved
  edges". Flip detect_unused_internals default to True so private
  unused symbols surface (safe_to_delete=False, confidence 0.65).
- generation/models.py: DeadCodeConfig.detect_unused_internals defaults
  to True, matching the analyzer.
- ingestion/graph.py: GraphBuilder.add_dynamic_edges forwards
  DynamicEdge.edge_type (prefixing dynamic_ when missing) instead of
  hard-coding "dynamic", preserving semantic sub-types like
  dynamic_uses / dynamic_imports / dynamic_url_route for downstream
  consumers.
- tests/unit/test_dead_code.py: 10 new cases pinning graph-edge
  suppression, sub-type prefix recognition, per-language marker
  coverage, and the unused-internal default-on / explicit-opt-out
  toggle.
- .gitignore: keep the local-only language work tracker out of git.

Full pytest run: 1296 passed (1286 baseline + 10 new), one pre-existing
unrelated test_mcp_full_exploration_flow failure carries unchanged.
…otlin, Ruby, Swift, Scala

Mirror the C# dotnet/ reference pattern across every Good-tier language:
build a lazy, cached project index per language, stash it on
ResolverContext via getattr/setattr, and consult it before stem
matching.

Indexes added:
- php_composer: composer.json autoload.psr-4 / autoload-dev longest-prefix map
- ts_workspace: npm/yarn/pnpm "workspaces" field (array + object form), glob-expanded
- kotlin_gradle: settings.gradle subprojects + per-module sourceSets srcDirs overrides; package_to_files lookup
- ruby_rails: Zeitwerk autoload index gated on config/application.rb; CamelCase -> snake_case + namespace_to_file
- swift_spm: Package.swift .target / .executableTarget / .testTarget regex (default Sources/<name>, Tests/<name>; honours explicit path:)
- scala_build: SBT lazy val ... project.in(file(...)) and Mill object ... extends ScalaModule, autodetected per repo

Other resolver upgrades:
- go.py gains read_go_modules + longest-module-prefix matching for
  multi-module monorepos; legacy go_module_path retained.
- typescript.py gains optional .vue / .svelte / .astro extension
  probing, gated on ResolverContext.has_sfc_files so pure-TS repos
  pay no extra path lookups.

ResolverContext: typed go_modules and has_sfc_files fields populated
once at GraphBuilder context-build time; rails_lookup(name) accessor
lazily builds + queries the Rails index.

Tests: 47 new unit tests across 7 new files (test_php_resolver,
test_go_resolver, test_typescript_resolver, test_swift_resolver,
test_kotlin_resolver, test_scala_resolver, test_ruby_resolver) using
real tmp_path manifests, mirroring the existing test_csharp_resolver
pattern. Full suite: 1343 passing (up from 1296), one pre-existing
unrelated failure unchanged.
…ho/Chi, Axum/Actix

Adds framework-aware synthetic edges for six new ecosystems alongside
the existing Django/FastAPI/Flask/ASP.NET coverage:

- Spring Boot (Java/Kotlin): @Autowired field/constructor injection
  resolves bean classes, including interface->impl via heritage; @bean
  factory methods in @configuration classes link to return-type files.
- Rails (Ruby): config/routes.rb walked with namespace-stack tracking
  for resources/get-to/namespace blocks; ActiveRecord belongs_to /
  has_many / has_one model->model edges. Reuses ctx.rails_lookup.
- Laravel (PHP): routes/web.php and routes/api.php parsed for modern
  [Foo::class, 'm'] and legacy 'Foo@m' syntax plus Route::resource;
  service provider bind/singleton/instance edges; Eloquent
  hasMany / belongsTo / hasOne / morph* relationships. Uses the
  composer PSR-4 map.
- Express / NestJS (TS/JS): app.use(routerVar) mirrors the FastAPI
  router-var resolver; @module({ controllers: [...], providers: [...],
  imports: [...] }) arrays parsed into module->target edges.
- Gin/Echo/Chi (Go): r.GET/POST/... handlers resolved package- or
  receiver-qualified via the Go import list and a function-name->file
  map; lambda handlers ignored cleanly.
- Axum/Actix (Rust): Router::new().route("/p", get(fn)),
  web::get().to(fn), .service(fn), .configure(fn) all resolve via a
  function-name->file map.

All slices live in framework_edges.py, gated by tech_stack tokens
or cheap import-signal predicates, and write edge_type="framework"
edges via the existing _add_edge_if_new helper.

Tests: 25 new cases across 6 files following the
test_csharp_framework_edges.py harness (real tmp_path repos, ASTParser,
nx.DiGraph, graph.has_edge assertions).
- .scm symbol coverage gaps closed across Java records, Kotlin
  typealias + class-level vals, Scala 3 enum/given/var, Swift
  subscript, Ruby top-level constants, PHP const/property,
  C primitive/struct typedef aliases, plus annotation modifier
  capture on Java class/interface/record and Scala class/function.
- Java module-level Javadoc and Luau (both module + symbol) doc
  extraction added to extractors/docstrings.py.
- Eight new dynamic-hint extractors registered in HintRegistry:
  Spring (getBean / @bean), Ruby (send / const_get / delegate),
  PHP (call_user_func / ReflectionClass / container get),
  Scala (Class.forName / given / implicit val), Swift
  (NSClassFromString / Selector / KVC), C (function-pointer
  assignment / dlopen / dlsym), Luau (game:GetService /
  setmetatable __index), Go (reflect.TypeOf / plugin.Open /
  plugin.Lookup).
- Heritage fixes: Java interface extends_interfaces field,
  Go struct embedding via field_declaration_list traversal.
- Per-language extractor tests for Java, Ruby, Scala, PHP, Go,
  plus dynamic-hint tests covering all eight new extractors.
Parse root Cargo.toml [workspace] members and each member's
[package] name to build a workspace index. resolve_rust_import
consults the index after the same-crate probe so
use sibling_crate::module resolves to the sibling crate's src/.
Cargo's "-" → "_" import-identifier rewrite is honoured.
Copy link
Copy Markdown
Collaborator

@swati510 swati510 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

…/get_overview shape

`test_mcp_full_exploration_flow` had drifted from current API:
- `architecture_diagram_mermaid` was deliberately dropped from
  get_overview() (agents call get_architecture_diagram instead);
  the unit test in tests/unit/server/test_mcp.py pins the removal.
- get_context() module/file `content_md` is gated behind
  include=["full_doc"] to keep default responses cheap.

Updates the integration test to match both contracts.
The _SKIP_DIRS check walked src.parts of the absolute path. On Linux CI
with tmp_path under /tmp/..., 'tmp' is in ruby's _SKIP_DIRS and every
fixture file got filtered out. Compute the relative path first, then
check skip dirs against its parts only.
@RaghavChamadiya RaghavChamadiya merged commit 05c0be9 into main Apr 26, 2026
5 checks passed
@RaghavChamadiya RaghavChamadiya deleted the feat/language-tier-upgrades branch April 26, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants