-module(lightspeed@router).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lightspeed/router.gleam").
-export([new/1, add/4, resolve/2, mount_instructions/2, decode/2, view_id/1, params/1, match_label/1]).
-export_type([route_param/0, route/1, router/1, route_match/1, matched_route/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(" Router integration helpers for mount/render flows.\n").
-type route_param() :: {route_param, binary(), binary()}.
-type route(LKJ) :: {route,
binary(),
binary(),
fun((lightspeed@event:inbound_event(), list(route_param())) -> {ok, LKJ} |
{error, lightspeed@event:decode_error()})}.
-type router(LKK) :: {router, binary(), list(route(LKK))}.
-type route_match(LKL) :: {found, matched_route(LKL)} |
{not_found, binary(), binary()}.
-type matched_route(LKM) :: {matched_route,
binary(),
binary(),
binary(),
list(route_param()),
fun((lightspeed@event:inbound_event(), list(route_param())) -> {ok, LKM} |
{error, lightspeed@event:decode_error()})}.
-file("src/lightspeed/router.gleam", 48).
?DOC(" Create a new router with a fallback not-found view.\n").
-spec new(binary()) -> router(any()).
new(Not_found_view) ->
{router, Not_found_view, []}.
-file("src/lightspeed/router.gleam", 53).
?DOC(" Register a route pattern.\n").
-spec add(
router(LKP),
binary(),
binary(),
fun((lightspeed@event:inbound_event(), list(route_param())) -> {ok, LKP} |
{error, lightspeed@event:decode_error()})
) -> router(LKP).
add(Router, Pattern, View_id, Decode_event) ->
{router,
erlang:element(2, Router),
[{route, Pattern, View_id, Decode_event} | erlang:element(3, Router)]}.
-file("src/lightspeed/router.gleam", 229).
-spec join_graphemes(list(binary())) -> binary().
join_graphemes(Graphemes) ->
case Graphemes of
[] ->
<<""/utf8>>;
[Grapheme | Rest] ->
<<Grapheme/binary, (join_graphemes(Rest))/binary>>
end.
-file("src/lightspeed/router.gleam", 217).
-spec param_name(binary()) -> gleam@option:option(binary()).
param_name(Segment) ->
case gleam@string:to_graphemes(Segment) of
[<<":"/utf8>> | Rest] ->
case Rest of
[] ->
none;
_ ->
{some, join_graphemes(Rest)}
end;
_ ->
none
end.
-file("src/lightspeed/router.gleam", 173).
-spec match_segments(list(binary()), list(binary()), list(route_param())) -> gleam@option:option(list(route_param())).
match_segments(Pattern_segments, Path_segments, Captures_rev) ->
case {Pattern_segments, Path_segments} of
{[], []} ->
{some, lists:reverse(Captures_rev)};
{[], _} ->
none;
{_, []} ->
none;
{[Pattern_segment | Pattern_rest], [Path_segment | Path_rest]} ->
case param_name(Pattern_segment) of
{some, Name} ->
match_segments(
Pattern_rest,
Path_rest,
[{route_param, Name, Path_segment} | Captures_rev]
);
none ->
case Pattern_segment =:= Path_segment of
true ->
match_segments(
Pattern_rest,
Path_rest,
Captures_rev
);
false ->
none
end
end
end.
-file("src/lightspeed/router.gleam", 206).
-spec filter_empty(list(binary()), list(binary())) -> list(binary()).
filter_empty(Values, Kept_rev) ->
case Values of
[] ->
lists:reverse(Kept_rev);
[Value | Rest] ->
case Value =:= <<""/utf8>> of
true ->
filter_empty(Rest, Kept_rev);
false ->
filter_empty(Rest, [Value | Kept_rev])
end
end.
-file("src/lightspeed/router.gleam", 200).
-spec segments(binary()) -> list(binary()).
segments(Path) ->
_pipe = Path,
_pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>),
filter_empty(_pipe@1, []).
-file("src/lightspeed/router.gleam", 167).
-spec match_pattern(binary(), binary()) -> gleam@option:option(list(route_param())).
match_pattern(Pattern, Path) ->
Pattern_segments = segments(Pattern),
Path_segments = segments(Path),
match_segments(Pattern_segments, Path_segments, []).
-file("src/lightspeed/router.gleam", 119).
-spec find_match(list(route(LLM)), binary()) -> gleam@option:option(matched_route(LLM)).
find_match(Routes, Normalized_path) ->
case Routes of
[] ->
none;
[Route | Rest] ->
case match_pattern(erlang:element(2, Route), Normalized_path) of
{some, Captures} ->
{some,
{matched_route,
Normalized_path,
erlang:element(2, Route),
erlang:element(3, Route),
Captures,
erlang:element(4, Route)}};
none ->
find_match(Rest, Normalized_path)
end
end.
-file("src/lightspeed/router.gleam", 243).
-spec drop_last(binary()) -> binary().
drop_last(Path) ->
case lists:reverse(gleam@string:to_graphemes(Path)) of
[] ->
<<""/utf8>>;
[_ | Rest] ->
_pipe = Rest,
_pipe@1 = lists:reverse(_pipe),
join_graphemes(_pipe@1)
end.
-file("src/lightspeed/router.gleam", 236).
-spec ends_with_slash(binary()) -> boolean().
ends_with_slash(Path) ->
case lists:reverse(gleam@string:to_graphemes(Path)) of
[<<"/"/utf8>> | _] ->
true;
_ ->
false
end.
-file("src/lightspeed/router.gleam", 156).
-spec trim_trailing_slashes(binary()) -> binary().
trim_trailing_slashes(Path) ->
case Path of
<<"/"/utf8>> ->
<<"/"/utf8>>;
_ ->
case ends_with_slash(Path) of
true ->
trim_trailing_slashes(drop_last(Path));
false ->
Path
end
end.
-file("src/lightspeed/router.gleam", 142).
-spec normalize_path(binary()) -> binary().
normalize_path(Path) ->
No_query = case gleam@string:split(Path, <<"?"/utf8>>) of
[First | _] ->
First;
[] ->
Path
end,
Trimmed = trim_trailing_slashes(No_query),
case Trimmed of
<<""/utf8>> ->
<<"/"/utf8>>;
_ ->
Trimmed
end.
-file("src/lightspeed/router.gleam", 67).
?DOC(" Resolve one path into a route match.\n").
-spec resolve(router(LKV), binary()) -> route_match(LKV).
resolve(Router, Path) ->
Normalized = normalize_path(Path),
case find_match(lists:reverse(erlang:element(3, Router)), Normalized) of
{some, Matched} ->
{found, Matched};
none ->
{not_found, Normalized, erlang:element(2, Router)}
end.
-file("src/lightspeed/router.gleam", 77).
?DOC(" Build a mount/render ISA sequence for a resolved route.\n").
-spec mount_instructions(route_match(any()), binary()) -> list(lightspeed@agent@isa:instruction()).
mount_instructions(Route_match, Csrf_token) ->
case Route_match of
{found, Matched} ->
[{mount, erlang:element(2, Matched), Csrf_token},
{render, erlang:element(4, Matched)}];
{not_found, Path, View_id} ->
[{mount, Path, Csrf_token}, {render, View_id}]
end.
-file("src/lightspeed/router.gleam", 94).
?DOC(" Decode one inbound event against a matched route decoder.\n").
-spec decode(matched_route(LLB), lightspeed@event:inbound_event()) -> {ok, LLB} |
{error, lightspeed@event:decode_error()}.
decode(Matched, Inbound) ->
(erlang:element(6, Matched))(Inbound, erlang:element(5, Matched)).
-file("src/lightspeed/router.gleam", 102).
?DOC(" Matched route view id.\n").
-spec view_id(matched_route(any())) -> binary().
view_id(Matched) ->
erlang:element(4, Matched).
-file("src/lightspeed/router.gleam", 107).
?DOC(" Matched route captured params.\n").
-spec params(matched_route(any())) -> list(route_param()).
params(Matched) ->
erlang:element(5, Matched).
-file("src/lightspeed/router.gleam", 112).
?DOC(" Render stable route match labels for logs.\n").
-spec match_label(route_match(any())) -> binary().
match_label(Route_match) ->
case Route_match of
{found, Matched} ->
<<"found:"/utf8, (erlang:element(3, Matched))/binary>>;
{not_found, _, View_id} ->
<<"not_found:"/utf8, View_id/binary>>
end.