fix(s28): api-reference handle ~/path ASP.NET convention
Some checks failed
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Has been cancelled
Docker API / Deploy API on stage (push) Has been cancelled

ASP.NET Core convention для HttpX-атрибутов: `~/path` означает
'absolute from root, ignore class [Route]'. До фикса генератор клеил
`base-route` + `~/path` → невалидный `/~/connect/token`.

Теперь tilde корректно срезается, /connect/token виден в reference.

Также добавлен unit test ApiReferenceDocsJobTests (Sprint 28) для
lock-down regex behavior на double-nested generics.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
nns 2026-06-09 03:41:15 +05:00
parent 5b87b5d599
commit 99b84132ba
3 changed files with 23 additions and 4 deletions

View file

@ -55,7 +55,7 @@ Base route: `/api/auth`
| Method | Route | Permission | Summary |
|---|---|---|---|
| POST | `/~/connect/token` | — | |
| POST | `/connect/token` | — | |
## `CounterpartiesController`
Base route: `/api/catalog/counterparties`

View file

@ -125,6 +125,12 @@ def main() -> int:
if auth_m:
perm = f'auth:{auth_m.group(1) or "any"}'
# Compose full route.
# ASP.NET Core convention: `~/path` в HttpX-атрибуте означает
# "absolute from root, ignore class-level [Route]". Срезаем `~`
# и используем sub как абсолютный путь.
if sub.startswith('~/'):
full = sub[1:] # `~/connect/token` → `/connect/token`
else:
parts = [p.strip('/') for p in (base, sub) if p]
full = '/' + '/'.join(parts)
full = full.rstrip('/') or '/'

View file

@ -132,7 +132,20 @@ private static IEnumerable<EndpointInfo> ScanDir(string dir)
if (!http.Success) continue;
var httpMethod = http.Groups[1].Value.ToUpperInvariant();
var subRoute = http.Groups[2].Success ? http.Groups[2].Value : "";
var fullRoute = "/" + string.Join("/", new[] { baseRoute, subRoute }.Where(s => !string.IsNullOrEmpty(s))).Trim('/');
// Sprint 28: ASP.NET Core convention `~/path` означает "absolute
// from root, ignore class [Route]". Без обработки `~` попадал
// в начало пути и получался невалидный `/~/connect/token`.
string fullRoute;
if (subRoute.StartsWith("~/", StringComparison.Ordinal))
{
fullRoute = subRoute[1..]; // `~/connect/token` → `/connect/token`
}
else
{
fullRoute = "/" + string.Join("/",
new[] { baseRoute, subRoute }
.Where(s => !string.IsNullOrEmpty(s))).Trim('/');
}
var permMatch = Regex.Match(attrs, @"\[RequiresPermission\(""([^""]+)""\)\]");
var perm = permMatch.Success ? permMatch.Groups[1].Value : "";