class

Analyzer::Swift::Vapor

Inherits Analyzer::Swift::SwiftEngine < FileScanEngine < Analyzer < FileHelper < Reference < Object

Constants

CHAINED_GROUP_PATTERN = /^\s*\.group(?:ed)?\s*\(/

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.

GROUP_ASSIGN_PATTERN = /\b(?:let|var)\s+([A-Za-z_]\w*)\s*=\s*(?:(#{SWIFT_RECEIVER})\.)?grouped\s*\(/

The base may be a dotted receiver (app.routes.grouped(...)), an implicit self (bare grouped(...)), or a single identifier (router.grouped(...)).

GROUP_CLOSURE_PATTERN = /(#{SWIFT_RECEIVER})\.group(?:ed)?\s*\(/
INLINE_GROUP_PATTERN = /(#{SWIFT_RECEIVER})\.grouped\s*\(/
INLINE_VERB_PATTERN = /^\s*\.(?:(?:get|post|put|delete|patch)\s*[({]|on\s*\()/
ON_ROUTE_PATTERN = /(#{SWIFT_RECEIVER})\.on\s*\(/
ROUTE_CALL_RE = /\.(?:(?:get|post|put|delete|patch)\s*[({]|on\s*\()/

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.

ROUTE_PATTERN = /(#{SWIFT_RECEIVER})\.(get|post|put|delete|patch)\s*([({])/
ROUTER_BINDING_PATTERN = /\b(?:let|var)\s+([A-Za-z_]\w*)\s*=\s*(?:try\s+|await\s+)*Application\b/
ROUTER_EXTENSION_PATTERN = /\bextension\s+(?:RoutesBuilder|Router)\b/

extension RoutesBuilder { ... self.get(...) ... } — inside such an extension self (and bare grouped(...), handled by GROUP_ASSIGN_PATTERN) is router-like.

ROUTER_PARAM_PATTERN = /(?:_\s+)?([A-Za-z_]\w*)\s*:\s*(?:some\s+|any\s+|inout\s+)*(?:RoutesBuilder|Router|Application)\b/

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.

ROUTER_TYPE_RE = Regex.union("RoutesBuilder", "Router", "Application")

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.

SWIFT_RECEIVER = /(?:\$\d+|[A-Za-z_]\w*)(?:\.(?:\$\d+|[A-Za-z_]\w*))*/

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

tech_name
Source

Instance methods

analyze_file(path : String) : Array(Endpoint)
Source
parse_route_path(route_args : String) : String

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)

Source
tech

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.

Source