class Analyzer::Zig::Tokamak

Overview

Tokamak declares routes two ways:

  1. Inline tk.Route arrays: const routes: []const tk.Route = &.{ .get("/", hello), .group("/api", &.{ .get("/health", health) }), }; .group(prefix, &.{ … }) composes its prefix onto every nested route; .post0/.put0/.patch0 are body-less verb variants.

  2. 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) (where chat = @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.cr

Constant 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_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 with root.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"}

Instance Method Summary

Instance methods inherited from class Analyzer

analyze analyze, base_path : String base_path, base_paths : Array(String) base_paths, callees_needed? : Bool callees_needed?, 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, url : String url

Constructor methods inherited from class Analyzer

new(options : Hash(String, YAML::Any)) new

Macros inherited from class Analyzer

define_getter_methods(names) define_getter_methods

Instance methods inherited from module FileHelper

all_files : Array(String) all_files, get_files_by_extension(extension : String) : Array(String) get_files_by_extension, 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_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

Instance Method Detail

def analyze #

[View source]