release: v0.4.0 — language-support upgrades across all Good-tier languages#106
Merged
RaghavChamadiya merged 10 commits intomainfrom Apr 26, 2026
Merged
release: v0.4.0 — language-support upgrades across all Good-tier languages#106RaghavChamadiya merged 10 commits intomainfrom
RaghavChamadiya merged 10 commits intomainfrom
Conversation
… 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.
…/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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.vue/.svelte/.astroSFC probing, Kotlin Gradle subprojects + sourceSets, Rails / Zeitwerk autoloading, Swift SPMPackage.swifttargets, Scala SBT / Mill multi-project, and Cargo[workspace]member crates.@Beanfactories, Rails routes + ActiveRecord, Laravel routes + service providers + Eloquent, Expressapp.use(router)+ NestJS@Modulearrays, Gin/Echo/Chi, and Axum/Actix.getBean/@Bean, Rubysend/const_get/delegate, PHPcall_user_func/ReflectionClass/containerget, ScalaClass.forName/given/implicit val, SwiftNSClassFromString/Selector/KVC, C function-pointer assignment +dlopen/dlsym, Luaugame:GetService/metatables, Goreflect.TypeOf/plugin.Open/plugin.Lookup. All wired intoHintRegistrysofind_dynamic_edge_filesautomatically suppresses dead-code findings for files involved in any new dynamic edge..scmsymbol coverage closures: Java records + class/interface/record annotation modifiers, Kotlin typealias + class-level vals, Scala 3enum/given/var+@deprecated/@tailrec, Swiftsubscript, Ruby top-level constants, PHPconst/property, C primitive/struct typedef aliases.interface … extends …now resolves; Go struct embedding now traversesfield_declaration_list; Swiftextension_declarationheritage works..csproj/.sln-aware resolver, ASP.NET edges,.NETdynamic hints, cross-repo<ProjectReference>+ internal NuGet, modern C#.scmfeatures, XML doc parsing) rolls forward into this release unchanged.Test plan
pytest— 1409 passed, 11 skipped, 2 xfailed; one unrelated pre-existing failure (test_mcp_full_exploration_flow) carries frommain.pyproject.toml,repowise.{core,cli,server}.__version__).docs/CHANGELOG.mdv0.4.0 entry covers every shipped change.README.mdSupported-languages table reflects new resolver + framework + dynamic-hint coverage.pip install -e .andrepowise --versionreports0.4.0.repowise initon a Spring + Rails + Laravel + Cargo-workspace fixture and confirm framework edges land in the wiki.