module
Noir::TreeSitterGoRouteExtractor
Overview
Tree-sitter-backed Go route extractor.
Scope for this first cut: recognise the idioms shared by Gin / Echo /
Fiber / Hertz / Iris — a router or group object with HTTP-verb methods
attached (r.GET("/path", handler)), plus .Group("/prefix")
chaining so nested groups resolve correctly.
Deliberately not covered yet (legacy regex extractor still handles these):
- Mux-style
r.HandleFunc("/x", h).Methods("GET")chain - Chi's
r.Route("/api", func(r chi.Router) { ... })nested closures - Static-file routes (
r.Static("/public", "./public"))
All of the above can grow into this extractor once the PoC is proven.
Extended Modules
Defined in:
miniparsers/go_route_extractor_ts.crConstant Summary
-
ANY_FAN_OUT_VERBS =
["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"] -
The seven canonical HTTP methods Gin's
r.Any, Echo'se.Any, Beego's*route etc. all stand for. Used by analyzer-level fan-out (see.fan_out_verbs). -
HTTP_VERB_METHODS =
Set {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "Get", "Post", "Put", "Delete", "Patch", "Head", "Options", "ANY", "Any", "All"} -
HTTP verbs Gin/Echo/Fiber/etc. accept as method names on router objects. Mixed case is allowed because both
r.GET(...)(Gin) andr.Get(...)(fiber, gin alt) appear in the wild. -
NON_ROUTER_OPERANDS =
Set {"gjson", "result", "results", "header", "headers", "Header", "Headers", "cookie", "cookies", "Cookie", "Cookies", "params", "Params", "values", "Values", "vars", "Vars", "url", "URL", "uri", "URI", "cache", "Cache", "db", "DB", "tx", "Tx", "conn", "Conn", "config", "cfg", "conf", "Config", "logger", "log", "client", "Client", "request", "Request", "req", "Req", "response", "Response", "resp", "Resp", "fixtures", "Fixtures", "slog"} -
Common non-router identifiers in Go code that expose
.Get(string)or.Post(...)style methods but emit values, not routes. The selector-expression walk emits a verb route on every match of<operand>.<HttpVerb>(stringLit, ...), so without this guard patterns likegjson.Get(json, "Files.0.UID"),header.Get("Content-Type"), orparams.Get("user")become bogus/Files.0.UID,/Content-Type,/userendpoints.Keep this list conservative — it only rejects names that are almost never used to hold a real router instance. Generic names like
r,c,app,mux,engineare intentionally not included.
Class Method Summary
-
.fan_out_verbs(verb : String) : Array(String)
Returns the list of verbs to emit for a given extracted route verb.
Instance Method Summary
- #extract_chi_routes(source : String, skip_functions : Set(String) = Set(String).new) : Array(Route)
- #extract_gf_routes(source : String) : Array(Route)
-
#extract_goyave_statics(source : String) : Array(StaticPath)
Goyave-style
<router>.Static(&fs, "/prefix", false): the first/-prefixed string argument is the URL prefix; the disk path is derived by stripping its leading slash (matching the legacy extractor's behaviour, which used the same identifier for both). -
#extract_groups(source : String, external_groups : Hash(String, String) = Hash(String, String).new, group_method : String = "Group", group_aliases : Array(String) = [] of String) : Hash(String, String)
Extracts only
<name> := <parent>.<group_method>("/prefix")declarations. -
#extract_mux_statics(source : String) : Array(StaticPath)
Mux-style `
.PathPrefix("/x/").Handler(<... -
#extract_routes(source : String, external_groups : Hash(String, String) = Hash(String, String).new, group_method : String = "Group", handle_method : String | Nil = nil, handlefunc_methods : Bool = false, group_aliases : Array(String) = [] of String, extra_verbs : Array(String) = [] of String) : Array(Route)
Parses
sourceand returns every verb route it can resolve. -
#extract_simple_statics(source : String, method_name : String = "Static") : Array(StaticPath)
<router>.<method_name>("/prefix", "./dir", ...). -
#walk_chi_public(node : LibTreeSitter::TSNode, source : String, sink : Array(Route))
Exposes the closure-scoped walker against an arbitrary node (typically a function body captured elsewhere).
Class Method Detail
Returns the list of verbs to emit for a given extracted route
verb. ANY / ALL (case-insensitive — verbs are uppercased
before they reach this helper) expand to every canonical HTTP
method so downstream output formats list each method
explicitly instead of carrying a non-HTTP "ANY" verb that
tools like SARIF/Postman can't ingest. Anything else passes
through as a single-element list.
Instance Method Detail
Goyave-style <router>.Static(&fs, "/prefix", false): the first
/-prefixed string argument is the URL prefix; the disk path is
derived by stripping its leading slash (matching the legacy
extractor's behaviour, which used the same identifier for both).
Extracts only <name> := <parent>.<group_method>("/prefix")
declarations. Used by the Go engine to run a cross-file fixpoint
so group names defined in one file but referenced in another are
known by the time #extract_routes runs on the referencing file.
Mux-style <router>.PathPrefix("/x/").Handler(<... http.Dir("./x/") ...>).
URL prefix comes from the PathPrefix arg; disk path from the
http.Dir(...) call nested somewhere inside the Handler(...)
argument expression.
Parses source and returns every verb route it can resolve.
external_groups supplies group prefixes defined in other files of
the same Go package, so cross-file patterns like
routes.go calling v1.GET(...) under a v1 := r.Group("/v1")
declared in main.go resolve correctly.
group_method is the method name used for grouping — Gin/Echo/Fiber/
Hertz use .Group(...), Iris uses .Party(...). Mux uses the
special two-call chain <parent>.PathPrefix("/prefix").Subrouter();
pass "Subrouter" and the collector will peek through the chain to
pull the prefix from the .PathPrefix(...) call.
handle_method is the "method-first" shape some routers use
(httprouter's .Handle("METHOD", "/path", handler)); set to nil
to disable.
handlefunc_methods enables mux's
<router>.HandleFunc("/path", h).Methods("METHOD") chain — the
outer call is .Methods(...), so this piggybacks on the walk rather
than decode_verb_call.
<router>.<method_name>("/prefix", "./dir", ...). The first two
string args are taken as (url_prefix, disk_path). Covers the
Gin/Echo/Fiber/Hertz/GoZero shape.
Exposes the closure-scoped walker against an arbitrary node (typically a function body captured elsewhere). Uses chi defaults.