fix(group): accept raw-string Go route paths in the framework query

The framework route query anchored the path on interpreted_string_literal
only, so `GET(`/health`, h)` produced no group-layer contract although
ingestion (Strategy A) decodes both Go string forms via the shared
stringLiteral. Match raw_string_literal too so both strategies emit the
same contract id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rgb-vgx 2026-10-04 17:16:44 +07:00
parent 2bc0bed628
commit c60af8247b
2 changed files with 21 additions and 2 deletions

View file

@ -21,7 +21,8 @@ import type { HttpDetection, HttpLanguagePlugin } from './types.js';
// ─── Provider: framework routing ──────────────────────────────────────
// Matches `\w+\.GET(...)` etc. (gin and echo share this shape).
// Captures the receiver, the HTTP method (field name), and the path literal
// — anchored as the FIRST argument so the code can pick the handler out of
// — anchored as the FIRST argument (either Go string form; stringLiteral
// decodes both, as ingestion does) so the code can pick the handler out of
// the remaining arguments. Which argument that is depends on the framework:
// gin is `GET(path, middleware..., handler)` (last), echo is
// `GET(path, handler, middleware...)` (first) — see readFrameworkImports and
@ -43,7 +44,7 @@ const FRAMEWORK_ROUTE_PATTERNS = compilePatterns({
field: (field_identifier) @http_method (#match? @http_method "^(GET|POST|PUT|DELETE|PATCH)$"))
arguments: (argument_list
.
(interpreted_string_literal) @path))
[(interpreted_string_literal) (raw_string_literal)] @path))
`,
},
],

View file

@ -430,6 +430,24 @@ func routes(r *gin.Engine) {
).toEqual([{ method: 'GET', path: '/api/x', name: 'X' }]);
});
it('accepts a raw-string (backtick) route path, as ingestion does', () => {
// Ingestion (Strategy A) decodes both Go string forms for the route path;
// the group layer must emit the same contract for a backtick path, both
// on a bound group and on a chained `Group(...).GET(...)` receiver.
expect(
providers(`package main
func routes(r *gin.Engine) {
g := r.Group("/api")
g.GET(\`/health\`, h.Health)
r.Group("/v1").POST(\`/raw\\x2fy\`, h.Raw)
}
`),
).toEqual([
{ method: 'GET', path: '/api/health', name: 'Health' },
{ method: 'POST', path: '/v1/raw\\x2fy', name: 'Raw' },
]);
});
it('decodes Go string escapes in group prefixes and route paths', () => {
// "/api\x2fv1" and "/health\x2fcheck" are `/api/v1` and `/health/check`
// once Go processes the escapes — the id must match the registered URL.