Analyzer::Swift::Vapor
Inherits Analyzer::Swift::SwiftEngine < FileScanEngine < Analyzer < FileHelper < Reference < Object
Constants
app.grouped("a").grouped("b") — a group call chained onto the previous
one; app.grouped("a").get("b") — a route verb called straight on a
group expression.
The base may be a dotted receiver (app.routes.grouped(...)), an implicit
self (bare grouped(...)), or a single identifier (router.grouped(...)).
route_definition? runs on every scanned line (route detection, param
lookahead, body-boundary checks). A verb may take a trailing closure
with no parens (app.get { ... }). The pattern opens with a literal
., so PCRE2 only tries offsets holding one.
extension RoutesBuilder { ... self.get(...) ... } — inside such an
extension self (and bare grouped(...), handled by GROUP_ASSIGN_PATTERN)
is router-like.
A function parameter (or binding) typed as a Vapor router:
func routes(_ app: Application), func boot(routes: RoutesBuilder),
func boot(router: Router) (Vapor 3), let app = Application(...).
Tracking these makes route detection receiver-aware, so that non-router
.get/.delete/... calls — Environment.get("DATABASE_URL"),
model.delete(on: req.db), req.client.get(url) — stop surfacing as
phantom endpoints.
Gate for register_router_params. All three patterns it runs require
one of these three words, so a line without any of them cannot
contribute a receiver and does not need to be matched at all.
That pattern opens with an unanchored ([A-Za-z_]\w*), so PCRE2 tries
it at every offset of the subject and backtracks the greedy \w* on
each one — quadratic in the line length. Up to roughly half a megabyte
the JIT absorbs it; past that the JIT stack overflows, PCRE2 falls back
to the interpreter, and the cost becomes visible all at once: a
600 KB single-line .swift file (generated code, a vendored bundle)
took 75 s in this one scan where 300 KB took milliseconds.
A literal union is a plain memchr-class search with no backtracking, and since the full pattern requires one of these three words the gate cannot change what is found.
Patterns for route definitions in Vapor:
app.get("path") { ... }
app.post("path", "segment") { ... }
routes.get("path", ":param") { ... }
users.get { ... } (trailing closure, no parens: the receiver's own path)
$0.get(...) (shorthand parameter of group { ... })
A receiver segment is an identifier or a shorthand closure param ($0).
Class methods
Instance methods
Parse route path from route arguments Examples: "hello" -> /hello "users", ":id" -> /users/:id "api", "users", ":userID" -> /api/users/:userID SiteURL.faq.pathComponents -> /SiteURL.faq ":owner", .fragment(.faviconIco) -> /:owner/.fragment(.faviconIco)
Instance-side view of the same declaration. The per-file rescues live on
this base class, which has no way to name the analyzer that is running
inside them, so a skipped file could not be attributed to a tech.
Deriving it from analyzer_for keeps the name written exactly once.