Packages

A simple and easy to use API created on top of the Mist web server

Current section

Files

Jump to
howdy src howdy@url_parser.erl
Raw

src/howdy@url_parser.erl

-module(howdy@url_parser).
-compile(no_auto_import).
-export([parse/2]).
-export_type([segment_error/0, url_segment/0]).
-type segment_error() :: non_matching_url.
-type url_segment() :: {matching_segment, binary(), binary()} |
{matching_template_typed_segment,
binary(),
binary(),
binary(),
gleam@dynamic:dynamic()} |
{wildcard_segment, binary(), binary(), binary()} |
non_matching_segment.
-spec parse(binary(), binary()) -> {ok, list(url_segment())} |
{error, segment_error()}.
parse(Template, Path) ->
case gleam@string:ends_with(Template, <<"*"/utf8>>) of
true ->
wildcard_parse(Template, Path);
false ->
template_parse(Template, Path)
end.
-spec template_parse(binary(), binary()) -> {ok, list(url_segment())} |
{error, segment_error()}.
template_parse(Template, Path) ->
Template_url = gleam@uri:path_segments(Template),
Path_url = gleam@uri:path_segments(Path),
_pipe = gleam@list:strict_zip(Template_url, Path_url),
_pipe@1 = gleam@result:replace_error(_pipe, non_matching_url),
_pipe@2 = gleam@result:map(_pipe@1, fun url_parts/1),
gleam@result:flatten(_pipe@2).
-spec wildcard_parse(binary(), binary()) -> {ok, list(url_segment())} |
{error, segment_error()}.
wildcard_parse(Template, Path) ->
Template_url = gleam@uri:path_segments(Template),
Path_url = gleam@uri:path_segments(Path),
_pipe = gleam@list:zip(Template_url, Path_url),
wildcard_parts(_pipe, Template, Path).
-spec wildcard_parts(list({binary(), binary()}), binary(), binary()) -> {ok,
list(url_segment())} |
{error, segment_error()}.
wildcard_parts(Url_parts, Template, Path) ->
_pipe = gleam@list:map(
Url_parts,
fun(Part) ->
case {is_wild_card(erlang:element(1, Part)),
template_matches_path(Part)} of
{true, _@1} ->
{wildcard_segment,
erlang:element(1, Part),
erlang:element(2, Part),
wildcard_join_paths(Template, Path)};
{_@2, true} ->
{matching_segment,
erlang:element(1, Part),
erlang:element(2, Part)};
{_@3, _@4} ->
non_matching_segment
end
end
),
has_nonmatching_segments(_pipe).
-spec wildcard_join_paths(binary(), binary()) -> binary().
wildcard_join_paths(Template, Path) ->
Striped_template = gleam@string:drop_right(Template, 1),
case gleam@string:starts_with(Path, Striped_template) of
true ->
gleam@string:drop_left(Path, gleam@string:length(Striped_template));
false ->
Path
end.
-spec is_wild_card(binary()) -> boolean().
is_wild_card(Template_segment) ->
Template_segment =:= <<"*"/utf8>>.
-spec url_parts(list({binary(), binary()})) -> {ok, list(url_segment())} |
{error, segment_error()}.
url_parts(Url_parts) ->
_pipe = gleam@list:map(Url_parts, fun convert_to_url_segment/1),
has_nonmatching_segments(_pipe).
-spec convert_to_url_segment({binary(), binary()}) -> url_segment().
convert_to_url_segment(Url_part) ->
case {is_templated_path(Url_part), template_matches_path(Url_part)} of
{true, false} ->
process_templated_url_segment(Url_part);
{false, true} ->
{matching_segment,
erlang:element(1, Url_part),
erlang:element(2, Url_part)};
{_@1, _@2} ->
non_matching_segment
end.
-spec is_templated_path({binary(), binary()}) -> boolean().
is_templated_path(Key_value) ->
gleam@string:starts_with(erlang:element(1, Key_value), <<"{"/utf8>>) andalso gleam@string:ends_with(
erlang:element(1, Key_value),
<<"}"/utf8>>
).
-spec template_matches_path({binary(), binary()}) -> boolean().
template_matches_path(Key_value) ->
gleam@string:lowercase(erlang:element(1, Key_value)) =:= gleam@string:lowercase(
erlang:element(2, Key_value)
).
-spec process_templated_url_segment({binary(), binary()}) -> url_segment().
process_templated_url_segment(Url_part) ->
case do_process_templated_url_segment(Url_part) of
{ok, Result} ->
Result;
{error, _@1} ->
non_matching_segment
end.
-spec do_process_templated_url_segment({binary(), binary()}) -> {ok,
url_segment()} |
{error, nil}.
do_process_templated_url_segment(Url_part) ->
{Template_url, Path_url} = Url_part,
_pipe = Template_url,
_pipe@1 = gleam@string:drop_left(_pipe, 1),
_pipe@2 = gleam@string:drop_right(_pipe@1, 1),
_pipe@3 = gleam@string:split_once(_pipe@2, <<":"/utf8>>),
_pipe@4 = gleam@result:map(
_pipe@3,
fun(_capture) -> process_template(_capture, Path_url) end
),
gleam@result:map(
_pipe@4,
fun(_capture@1) ->
convert_to_template_url_segment(_capture@1, Template_url, Path_url)
end
).
-spec process_template({binary(), binary()}, binary()) -> {gleam@option:option(gleam@dynamic:dynamic()),
binary()}.
process_template(Key_value, Input) ->
{Name, Template_type} = Key_value,
Result = case gleam@string:lowercase(Template_type) of
<<"string"/utf8>> ->
process_string(Input);
<<"int"/utf8>> ->
process_int(Input);
<<"float"/utf8>> ->
process_float(Input);
<<"uuid"/utf8>> ->
process_uuid(Input);
_@1 ->
none
end,
{Result, Name}.
-spec convert_to_template_url_segment(
{gleam@option:option(gleam@dynamic:dynamic()), binary()},
binary(),
binary()
) -> url_segment().
convert_to_template_url_segment(Result, Template_segment, Path_segment) ->
{Processed, Name} = Result,
case Processed of
{some, Value} ->
{matching_template_typed_segment,
Template_segment,
Path_segment,
Name,
Value};
none ->
non_matching_segment
end.
-spec process_string(binary()) -> gleam@option:option(gleam@dynamic:dynamic()).
process_string(Value) ->
_pipe = gleam@string:to_option(Value),
gleam@option:map(_pipe, fun(Str) -> gleam@dynamic:from(Str) end).
-spec process_int(binary()) -> gleam@option:option(gleam@dynamic:dynamic()).
process_int(Value) ->
_pipe = gleam@int:parse(Value),
_pipe@1 = gleam@option:from_result(_pipe),
gleam@option:map(_pipe@1, fun(Num) -> gleam@dynamic:from(Num) end).
-spec process_float(binary()) -> gleam@option:option(gleam@dynamic:dynamic()).
process_float(Value) ->
_pipe = gleam@float:parse(Value),
_pipe@1 = gleam@option:from_result(_pipe),
gleam@option:map(_pipe@1, fun(Num) -> gleam@dynamic:from(Num) end).
-spec process_uuid(binary()) -> gleam@option:option(gleam@dynamic:dynamic()).
process_uuid(Value) ->
_pipe = howdy@uuid:from_string(Value),
_pipe@1 = gleam@option:from_result(_pipe),
gleam@option:map(_pipe@1, fun(_) -> gleam@dynamic:from(Value) end).
-spec has_nonmatching_segments(list(url_segment())) -> {ok, list(url_segment())} |
{error, segment_error()}.
has_nonmatching_segments(Segments) ->
case gleam@list:contains(Segments, non_matching_segment) of
true ->
{error, non_matching_url};
false ->
{ok, Segments}
end.