module Noir::TreeSitterPythonRouteExtractor

Overview

Tree-sitter-backed port of PythonRouteExtractor.

Unlike the regex extractor (which is line-oriented and relies on the caller to loop over lines), this one parses the whole source once and walks the resulting AST. That buys us:

Behaviour mirrors the regex extractor closely enough that the same analyzer adapters could switch to it with minimal changes; parity is verified in spec/unit_test/miniparser/python_route_extractor_ts_spec.cr.

Extended Modules

Defined in:

miniparsers/python_route_extractor_ts.cr

Constant Summary

HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options", "trace"] of ::String

Instance Method Summary

Instance Method Detail

def extract_blueprints(source : String, module_names : Array(String)) : Array(BlueprintDecl) #

Parses source and returns every Blueprint(...) assignment that matches one of module_names or a bare Blueprint.

module_names is the list of module prefixes allowed before .Blueprint (e.g. ["flask"]). A bare Blueprint call is always accepted, matching the regex extractor.

Uses a tree-sitter query to find the two Blueprint assignment shapes (bare and module-qualified). The url_prefix keyword is still extracted procedurally because a Blueprint may be declared without one and the query language can't express "this keyword, if present" cleanly.


[View source]
def extract_decorations(source : String, router_names : Array(String) | Nil = nil, extra_attributes : Hash(String, String) | Nil = nil) : Array(Decoration) #

Parses source and returns every route decoration found.

router_names optionally restricts which variable names count as routers; nil accepts any identifier (matching the regex extractor, which doesn't gate on the name).

extra_attributes optionally widens the set of decorator attribute names that count as a route. Each entry maps an attribute name (e.g. "websocket") to the HTTP method the synthesised endpoint should carry (Quart's @app.websocket is emitted as GET so the downstream pipeline keeps treating it as an HTTP-shaped endpoint; the caller flips protocol = "ws" based on attribute_name).


[View source]