class
Analyzer::Zig::Tokamak
- Analyzer::Zig::Tokamak
- Analyzer
- Reference
- Object
Overview
Tokamak declares routes two ways:
-
Inline
tk.Routearrays: const routes: []const tk.Route = &.{ .get("/", hello), .group("/api", &.{ .get("/health", health) }), };.group(prefix, &.{ … })composes its prefix onto every nested route;.post0/.put0/.patch0are body-less verb variants. -
Controller modules mounted with
.router(T). The controller declares one handler per route, naming the function with the method + path: pub fn @"GET /chat/:id"(db: *Session, id: u32) !Chat { … }.router(chat)(wherechat = @import("api/chat.zig")) mounts every such function, composing any enclosing.group(...)prefix. The mount and the controller usually live in different files, so the mount prefixes are resolved project-wide and keyed by controller file.
A controller's routes can also be declared as const bindings rather than
functions — the handler lives in another file and the route is just a name:
pub const Protected = struct { pub const @"GET /projects" = getAllProjects; pub const @"PUT /projects/:id" = updateProject; };
Such structs are mounted by qualified name (.router(api.Protected),
where api = @import("api.zig") and Protected is a struct inside it), so
the route set of one file is partitioned across several mounts. Each route
therefore carries the prefix of every mount that targets its enclosing
struct (or any whole-file mount).
Not yet resolved: a .group(prefix, RouteConst) whose body is a reference
to a tk.Route const (rather than an inline &.{ … } array) — those
controllers' routes are emitted without the referenced-group prefix.
Defined in:
analyzer/analyzers/zig/tokamak.crConstant Summary
-
GROUP_RE =
/\.\s*group\s*\(\s*"([^"]*)"\s*,\s*&?\s*\.\s*\{/ -
GROUP_VALUE_RE =
/\.\s*group\s*\(\s*"([^"]*)"\s*,(?!\s*&?\s*\.\s*\{)/ -
Value-form group whose body is a single route value rather than an
&.{ … }array (tk.group("/api", tk.router(api))). The negative lookahead — which must absorb its own leading whitespace, so a backtracking\s*can't slip past it — keeps the array form to GROUP_RE. -
IMPORT_RE =
/(?:pub\s+)?(?:const|var)\s+([A-Za-z_]\w*)\s*=\s*@import\(\s*"([^"]+\.zig)"\s*\)/ -
ROUTE_CONST_RE =
/pub\s+const\s+@"(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(\/[^"]*)"/ -
ROUTE_FILE_RE =
Regex.union("tk.Route", ".group(", ".router(", "pub fn @\"", "pub const @\"") -
Cheap whole-file route gate. One precompiled
Regex.unionscan (PCRE2 JIT) replaces five naiveString#includes?char scans and rejects a non-route file in a single pass instead of running all five. Equivalent to the OR-of-substrings it replaces (union escapes each literal). -
ROUTE_FN_RE =
/pub\s+fn\s+@"(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(\/[^"]*)"/ -
ROUTE_RE =
/\.\s*(get|post0|post|put0|put|patch0|patch|delete|head|options)\s*\(\s*"(\/[^"]*)"\s*,\s*([A-Za-z_][\w.]*)/ -
The path must be a rooted URL (
"/..."). Tokamak handlers commonly build a JSON response withroot.put("name", value)/data.get("key"); those data-object calls share the verb names but never take a/-rooted key, so the leading-slash guard keeps them out of the route set. -
ROUTER_MOUNT_RE =
/\.\s*router\s*\(\s*([A-Za-z_][\w.]*)\s*\)/ -
STRUCT_DECL_RE =
/(?:^|[^A-Za-z0-9_.])(?:pub\s+)?const\s+([A-Za-z_]\w*)\s*=\s*struct\s*\{/ -
VERB_METHOD =
{"get" => "GET", "post" => "POST", "post0" => "POST", "put" => "PUT", "put0" => "PUT", "patch" => "PATCH", "patch0" => "PATCH", "delete" => "DELETE", "head" => "HEAD", "options" => "OPTIONS"}
Class Method Summary
Instance Method Summary
- #analyze
-
#tech : String
Instance-side view of the same declaration.
Instance methods inherited from class Analyzer
analyze
analyze,
base_path : String
base_path,
base_paths : Array(String)
base_paths,
base_relative_path(path : String) : String
base_relative_path,
callees_needed? : Bool
callees_needed?,
content_matches?(content : String, markers : Regex) : Bool
content_matches?,
http_header_name(name : String) : String | Nil
http_header_name,
line_number_for_index(content : String, char_index : Int32) : Int32
line_number_for_index,
logger : NoirLogger
logger,
parallel_analyze(files : Array(String), &block : String -> Nil)
parallel_analyze,
read_file_content(path : String) : String
read_file_content,
result : Array(Endpoint)
result,
tech : String
tech,
unique_params(params : Array(Param)) : Array(Param)
unique_params,
url : String
url,
web_root_path(path : String, markers : Array(String)) : String
web_root_path
Constructor methods inherited from class Analyzer
new(options : Hash(String, YAML::Any))
new
Macros inherited from class Analyzer
analyzer_for(tech)
analyzer_for
Instance methods inherited from module FileHelper
all_files : Array(String)
all_files,
get_files_by_basename(basename : String) : Array(String)
get_files_by_basename,
get_files_by_extension(extension : String) : Array(String)
get_files_by_extension,
get_files_by_extensions(extensions : Array(String)) : Array(String)
get_files_by_extensions,
get_files_by_prefix(prefix : String) : Array(String)
get_files_by_prefix,
get_files_by_prefix_and_extension(prefix : String, extension : String) : Array(String)
get_files_by_prefix_and_extension,
get_files_by_relative_path(relative_path : String, root : String = "") : Array(String)
get_files_by_relative_path,
get_public_dir_files(base_path : String, folder : String) : Array(String)
get_public_dir_files,
get_public_files(base_path : String, anchors : Array(String) = ["shard.yml", "Gemfile"]) : Array(String)
get_public_files,
walked_path(expanded : String) : String
walked_path
Class Method Detail
Instance Method Detail
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.