Skip to content

feat(lang-java): add @ctxo/lang-java syntax-tier plugin#74

Open
utafrali wants to merge 1 commit into
alperhankendi:masterfrom
utafrali:feat/add-lang-java
Open

feat(lang-java): add @ctxo/lang-java syntax-tier plugin#74
utafrali wants to merge 1 commit into
alperhankendi:masterfrom
utafrali:feat/add-lang-java

Conversation

@utafrali
Copy link
Copy Markdown

@utafrali utafrali commented Apr 19, 2026

Summary

Adds @ctxo/lang-java — a Java language plugin built on tree-sitter-java, scoped to tier: 'syntax'. Detection wiring (pom.xml, build.gradle, build.gradle.kts, .java) was already in place in @ctxo/cli, so no CLI changes are needed.

Coverage

  • Symbols: classes, interfaces, enums, records, methods, constructors. Nested types are dotted-qualified (Outer.Inner); methods are qualified by enclosing type (Outer.method); constructors as ClassName.ClassName.
  • Edges: imports (with wildcard skip and static-import normalization), extends, implements (including interface extends). Edge targets are name-keyed and resolved against the cross-file symbol registry — same convention as @ctxo/lang-csharp, so SymbolGraph.resolveNodeId binds them to real symbols on indexed targets.
  • Cyclomatic complexity: counts if, for, enhanced_for, while, do, switch_label, catch_clause, ternary_expression, plus &&/|| short-circuit operators.

Validation

  • 29/29 unit tests pass (covers symbol kinds, nested types, constructors, generics, registry-resolution, wildcard-import skip, static-import normalization, regression test for __unresolved__ sentinel removal)
  • E2E demo on a 3-file Maven project (pom.xml + 3 .java files): implements edge from PercentageDiscount resolves to src/main/java/com/example/shop/Discount.java::Discount::interface — verified by joining edges → symbols in the SQLite cache. No dangling targets.
  • pnpm typecheck clean; pnpm build produces dist/index.js (13.7 KB) + dist/index.d.ts (3.5 KB)

Test plan

  • CI green (lint, typecheck, vitest, build)
  • Reviewer can clone a Maven/Gradle project, run npm install -D @ctxo/lang-java, then ctxo init + ctxo index
  • SQLite cache shows resolved extends/implements edges (no __unresolved__:: sentinel anywhere)

Out of scope (tracked as separate follow-up issues)

Process notes

  • Added a changeset (.changeset/add-lang-java.md) for a minor bump on @ctxo/lang-java
  • Version 0.8.0 to align with sibling plugins (@ctxo/lang-go@0.8.0, @ctxo/lang-csharp@0.7.2, @ctxo/lang-typescript@0.7.1)
  • peerDependencies: { "@ctxo/plugin-api": "^0.7.1" } matches siblings
  • Updated site/docs/languages/overview.md support matrix with the Java row
  • A new packages/lang-java/README.md documents coverage, edge encoding, and the known limitations from the follow-up issues

Review process

This PR went through three rounds of internal review focused on (a) contract compliance vs. siblings, (b) empirical end-to-end edge resolution, and (c) ecosystem integration. The first draft used an __unresolved__::Name::kind sentinel for unresolved edge targets — reviewers showed this never matches SymbolGraph.resolveNodeId's fuzzy lookup. The current encoding mirrors @ctxo/lang-csharp's registry-walk fallback and was verified end-to-end against the demo SQLite (one cross-file implements edge, RESOLVED).

Implements the Java language plugin against Plugin API v1, scoped to syntax tier.
Built on tree-sitter-java. Detection wiring (pom.xml, build.gradle, .java) was
already in place in @ctxo/cli — no CLI changes needed.

Coverage:
- Symbols: classes, interfaces, enums, records, methods, constructors. Nested
  types are qualified Outer.Inner. Methods are qualified Outer.method.
- Edges: imports (with wildcard skip and static-import normalization), extends,
  implements. Edge targets are name-keyed and resolved against the cross-file
  symbol registry, matching the convention used by @ctxo/lang-csharp so the
  SymbolGraph fuzzy resolver binds them to real symbols.
- Cyclomatic complexity: counts if, for, enhanced_for, while, do, switch_label,
  catch_clause, ternary_expression, and &&/|| short-circuits.

Validation:
- 29/29 unit tests pass (including a registry-resolution test confirming
  cross-file extends/implements bind to real symbol IDs)
- E2E demo on a 3-file Maven project: implements edge from PercentageDiscount
  resolves to src/.../Discount.java::Discount::interface (RESOLVED, not
  dangling) — verified by joining edges → symbols in the SQLite cache.

Out of scope (tracked as separate issues):
- full tier (JDT/javac) — Go composite pattern as reference
- Sealed permits, enum constants with bodies, initializer blocks, anonymous
  inner classes — require new SymbolKind/EdgeKind values in @ctxo/plugin-api
- Doctor language-coverage-check.ts resolves require from CLI dist instead of
  consumer project root; pre-existing CLI bug surfaces as a spurious
  "missing plugins for: java" warning even when the plugin loads correctly
- TreeSitterAdapter and logger duplication across lang-go / lang-csharp /
  lang-java — promote to a shared package
- runtime-check.ts and index-command.ts hardcoded language tables
@alperhankendi
Copy link
Copy Markdown
Owner

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