module

Noir::TreeSitterJavaRouteExtractor

Tree-sitter-backed Java route extractor.

Scope for this first cut: Spring's annotation-based routing — class-level @RequestMapping-family annotations composing with method-level mapping annotations. This is the most common Java route shape by a wide margin and what src/analyzer/analyzers/java/ spring.cr exists to surface. Covers:

  • @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping — each fixes the HTTP verb
  • @RequestMapping — generic; verb comes from a method = RequestMethod.X element-value pair, or is reported as ANY when none is given because Spring matches all HTTP methods
  • Class-level mapping annotations contribute a prefix that's concatenated onto the per-method path
  • Annotation value supplied positionally (@GetMapping("/x")) or as a keyword element (value = "/x" / path = "/x"), including arrays
  • Same-file meta-annotations that compose Spring mapping annotations of their own
  • Multi-line annotations (the Java grammar eats whitespace for us)

Deliberately not covered yet (handled by the legacy analyzer while this PoC stabilises):

  • Cross-file meta-annotation resolution

Other JVM frameworks (Armeria, Play, JSP, Vert.x) can layer on top of this once the Spring port is validated.

Constants

ANNOTATION_VERBS = {"GetMapping" => "GET", "PostMapping" => "POST", "PutMapping" => "PUT", "DeleteMapping" => "DELETE", "PatchMapping" => "PATCH", "RequestMapping" => nil, "GetExchange" => "GET", "PostExchange" => "POST", "PutExchange" => "PUT", "DeleteExchange" => "DELETE", "PatchExchange" => "PATCH", "HttpExchange" => nil}

Spring mapping annotation names mapped to the HTTP verb they imply. nil means "look at the annotation's method = argument".

VERB_IDENTIFIERS = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "TRACE"}

Known HTTP-verb identifiers we consider valid method = ... values. Used when reconstructing verbs from ERROR nodes around the invalid [...] bracket syntax.

Instance methods

extract_controller_interface_implementations_from(root : LibTreeSitter::TSNode, source : String, external_meta_mappings = Hash(String, ClassMapping).new) : Array(ControllerInterfaceImplementation)
Source
extract_interface_routes_from(root : LibTreeSitter::TSNode, source : String, external_meta_mappings = Hash(String, ClassMapping).new) : Hash(String, Array(Route))
Source
extract_meta_mappings_from(root : LibTreeSitter::TSNode, source : String, constants : Hash(String, String) | Nil = nil) : Hash(String, ClassMapping)
Source
extract_routes(source : String) : Array(Route)

Parses source and returns every Spring-style route it can resolve. Top-level classes are scanned in order; nested classes inherit their parent class's mapping prefix.

Source
extract_routes_from(root : LibTreeSitter::TSNode, source : String, external_meta_mappings = Hash(String, ClassMapping).new) : Array(Route)

_from variant — accept a pre-parsed root so the Spring analyzer can amortise tree-sitter parses across multiple extractions on the same file. Tree lifetime is the caller's responsibility.

Source
extract_string_constants(source : String) : Hash(String, String)
Source
extract_string_constants_from(root : LibTreeSitter::TSNode, source : String) : Hash(String, String)
Source

Nested types