class
Analyzer::Fsharp::Giraffe
- Analyzer::Fsharp::Giraffe
- Analyzer
- Reference
- Object
Overview
Giraffe is a functional web framework on top of ASP.NET Core. Routes
are HttpHandler values composed via the >=> Kleisli operator and
collected with choose [...]. Common combinators surfaced here:
route "/path"— exact path matchrouteCi "/path"— case-insensitive variantroutex "regex"— regex variant (path is reported verbatim)routef "/users/%i/%s"— typed parameterssubRoute "/prefix" handlerand friends — mount nested routes
HTTP method filters (GET, POST, etc.) appearing on the same
textual line as a route are honored; lines without an explicit
method default to a fallback set.
Defined in:
analyzer/analyzers/fsharp/giraffe.crConstant Summary
-
FALLBACK_METHODS =
["GET", "POST", "PUT", "DELETE", "PATCH"] -
HTTP_METHODS =
["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"] of ::String -
METHOD_WORD_PATTERNS =
HTTP_METHODS.map do |m| {m, /\b#{m}\b/} end -
NO_UTF_CHECK =
Regex::MatchOptions::NO_UTF_CHECK -
PCRE2 (Crystal's regex backend) re-validates UTF-8 encoding of the subject on every
match_at_byte_indexcall by default -- an O(remaining-length) pass, since our scan loop calls it at every character position that O(n²) rather than O(n).content(andcleaned, built from it) is always sourced throughAnalyzer#read_file_content, which reads withinvalid: :skip, so both are guaranteed structurally valid UTF-8 already -- the same invariantString#scanin the standard library relies on when it sets this same option after its first match. Confirmed empirically: a 4x-larger synthetic file went from ~16.7s to ~0.014s once this was applied to the combinator matchers below (~1000x). -
ROUTE_BIND_RE =
/\GrouteBind(?:\s*<[^>\n]*>)?\s+"([^"]+)"/ -
ROUTE_COMBINATOR =
/(?:route(?:Bind|Ci[fx]?|xp?|f)?|subRoute(?:Ci|f)?)\b/ -
Crystal recompiles an interpolated regex literal on every evaluation (a full PCRE2 JIT compile). Both the stop-line matcher and the per-verb window probes interpolate only fixed patterns, so precompile them once at load time.
-
ROUTE_CONST_RE =
/\G(?:routeCix|routexp|routeCi|routex|route)\s+([A-Za-z_][A-Za-z0-9_']*(?:\.[A-Za-z_][A-Za-z0-9_']*)*)/ -
ROUTE_HANDLER_STOP_RE =
/\A(?:(?:GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\b.*\b#{ROUTE_COMBINATOR}|#{ROUTE_COMBINATOR})/ -
ROUTE_RE =
/\G(?:routeCix|routexp|routeCi|routex|route)\s+"([^"]+)"/ -
ROUTEF_PARAM_TYPES =
{'i' => "int", 'd' => "int64", 'b' => "bool", 'c' => "char", 's' => "string", 'f' => "float", 'O' => "guid", 'u' => "uint64"} -
Mapping of routef format specifiers to noir path-param types.
-
ROUTEF_RE =
/\G(?:routef|routeCif)\s+"([^"]+)"/ -
SUB_ROUTE_RE =
/\G(subRoute(?:Ci|f)?)\s+"([^"]+)"\s*([\(\[])/ -
Combinator matchers for the main scan loop below.
\G(rather than\A) anchors each match to the exact byte offset passed toRegex#match_at_byte_index, mirroring what\Adid against a freshly slicedcleaned[i..]remainder -- but without the slice. -
VERB_CHOOSE_RE =
/\G(GET_HEAD|GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s*>=>\s*choose\s*\[/ -
GET_HEADis Giraffe's own Endpoint-Routing combinator for[ GET; HEAD ]; it must come first in the alternation soGETcannot claim its prefix.VERB_METHODSmaps a matched token to the verbs it actually applies. -
VERB_LIST_RE =
/\G(GET_HEAD|GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s*\[/ -
VERB_METHODS =
{"GET_HEAD" => ["GET", "HEAD"]} -
Verbs a matched Endpoint-Routing verb token dispatches on. Only tokens that mean more than themselves need an entry.
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.