Current section
Files
Jump to
Current section
Files
src/roundabout.erl
-module(roundabout).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/roundabout.gleam").
-export([route/3, fixed/1, str/1, int/1, parse_definitions/2, parse/1, main/2]).
-export_type([segment/0, route/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque segment() :: {fixed, binary()} | {str, binary()} | {int, binary()}.
-opaque route() :: {route, binary(), list(segment()), list(route())}.
-file("src/roundabout.gleam", 43).
?DOC(
" Make a route defintion\n"
"\n"
" e.g.\n"
" ```gleam\n"
" route(\"users\", [fixed(\"users\"), int(\"user_id\")], [])\n"
" ```\n"
"\n"
" `name` is the name for this route, this will be used for generating the variant names and helper names.\n"
"\n"
" `path` defines the url segments e.g. /users/1.\n"
"\n"
" `children` generates sub types for nested routes, this is useful for middleware.\n"
).
-spec route(binary(), list(segment()), list(route())) -> route().
route(Name, Path, Children) ->
{route, Name, Path, Children}.
-file("src/roundabout.gleam", 57).
?DOC(
" A path segment that is constant\n"
"\n"
" e.g.\n"
" ```gleam\n"
" [fixed(\"users\"), str(\"user_id\")]\n"
" ```\n"
).
-spec fixed(binary()) -> segment().
fixed(Value) ->
{fixed, Value}.
-file("src/roundabout.gleam", 67).
?DOC(
" A path segment that should resolve to a string\n"
"\n"
" e.g.\n"
" ```gleam\n"
" [fixed(\"users\"), str(\"user_id\")]\n"
" ```\n"
).
-spec str(binary()) -> segment().
str(Name) ->
{str, Name}.
-file("src/roundabout.gleam", 77).
?DOC(
" A path segment that should resolve to an integer\n"
"\n"
" e.g.\n"
" ```gleam\n"
" [fixed(\"users\"), int(\"user_id\")]\n"
" ```\n"
).
-spec int(binary()) -> segment().
int(Name) ->
{int, Name}.
-file("src/roundabout.gleam", 148).
-spec assert_no_duplicate_variant_names(
binary(),
list(roundabout@internal@node:node_())
) -> {ok, list(roundabout@internal@node:node_())} | {error, binary()}.
assert_no_duplicate_variant_names(Parent_name, Nodes) ->
Variant_names = gleam@list:map(
Nodes,
fun(Item) ->
roundabout@internal@type_name:snake(
erlang:element(2, erlang:element(2, Item))
)
end
),
As_set = gleam@set:from_list(Variant_names),
case erlang:length(Variant_names) =:= gleam@set:size(As_set) of
true ->
{ok, Nodes};
false ->
{error,
<<<<"Route "/utf8, Parent_name/binary>>/binary,
" contain duplicate route names"/utf8>>}
end.
-file("src/roundabout.gleam", 206).
-spec assert_no_duplicate_segment_names(binary(), list(segment())) -> {ok,
list(segment())} |
{error, binary()}.
assert_no_duplicate_segment_names(Node_name, Segments) ->
Segment_names = gleam@list:filter_map(Segments, fun(Seg) -> case Seg of
{fixed, _} ->
{error, nil};
{str, Val} ->
{ok, justin:snake_case(Val)};
{int, Val@1} ->
{ok, justin:snake_case(Val@1)}
end end),
As_set = gleam@set:from_list(Segment_names),
case erlang:length(Segment_names) =:= gleam@set:size(As_set) of
true ->
{ok, Segments};
false ->
{error,
<<<<"Route "/utf8, Node_name/binary>>/binary,
" contain duplicate segment names"/utf8>>}
end.
-file("src/roundabout.gleam", 174).
-spec parse_definition_info(route()) -> {ok, roundabout@internal@node:info()} |
{error, binary()}.
parse_definition_info(Input) ->
gleam@result:'try'(
assert_no_duplicate_segment_names(
erlang:element(2, Input),
erlang:element(3, Input)
),
fun(Input_path) ->
Path_result = begin
_pipe = Input_path,
gleam@list:try_map(_pipe, fun(Seg) -> case Seg of
{fixed, Val} ->
_pipe@1 = roundabout@internal@constant:new(Val),
gleam@result:map(
_pipe@1,
fun(Field@0) -> {seg_fixed, Field@0} end
);
{str, Val@1} ->
_pipe@2 = roundabout@internal@parameter:new(
Val@1,
str
),
gleam@result:map(
_pipe@2,
fun(Field@0) -> {seg_param, Field@0} end
);
{int, Val@2} ->
_pipe@3 = roundabout@internal@parameter:new(
Val@2,
int
),
gleam@result:map(
_pipe@3,
fun(Field@0) -> {seg_param, Field@0} end
)
end end)
end,
gleam@result:'try'(
roundabout@internal@type_name:new(erlang:element(2, Input)),
fun(Name) ->
gleam@result:'try'(
Path_result,
fun(Path) -> _pipe@4 = {info, Name, Path},
{ok, _pipe@4} end
)
end
)
end
).
-file("src/roundabout.gleam", 163).
-spec parse_definition(route()) -> {ok, roundabout@internal@node:node_()} |
{error, binary()}.
parse_definition(Definition) ->
gleam@result:'try'(
parse_definition_info(Definition),
fun(Info) ->
gleam@result:'try'(
parse_definitions(
erlang:element(2, Definition),
erlang:element(4, Definition)
),
fun(Children) -> _pipe = {node, Info, Children},
{ok, _pipe} end
)
end
).
-file("src/roundabout.gleam", 137).
?DOC(false).
-spec parse_definitions(binary(), list(route())) -> {ok,
list(roundabout@internal@node:node_())} |
{error, binary()}.
parse_definitions(Parent_name, Definitions) ->
gleam@result:'try'(
gleam@list:try_map(Definitions, fun parse_definition/1),
fun(Nodes) ->
gleam@result:'try'(
assert_no_duplicate_variant_names(Parent_name, Nodes),
fun(Nodes@1) -> {ok, Nodes@1} end
)
end
).
-file("src/roundabout.gleam", 127).
?DOC(false).
-spec parse(list(route())) -> {ok, roundabout@internal@node:node_()} |
{error, binary()}.
parse(Definitions) ->
gleam@result:'try'(
parse_definitions(<<"root"/utf8>>, Definitions),
fun(Children) ->
Root = {node,
{info, roundabout@internal@type_name:unsafe(<<""/utf8>>), []},
Children},
{ok, Root}
end
).
-file("src/roundabout.gleam", 86).
?DOC(
" Generate the routes file\n"
"\n"
" ```gleam\n"
" roundabout.main(route_definitions, \"src/my_app/generated/routes\")\n"
" ```\n"
).
-spec main(list(route()), binary()) -> {ok, nil} | {error, binary()}.
main(Definitions, Output_path) ->
gleam@result:'try'(
parse(Definitions),
fun(Root) ->
Output_path@1 = case gleam_stdlib:string_ends_with(
Output_path,
<<".gleam"/utf8>>
) of
true ->
Output_path;
false ->
<<Output_path/binary, ".gleam"/utf8>>
end,
Types = roundabout@internal@generate_types:generate_type_rec(
[],
Root
),
Segments_to_route = roundabout@internal@generate_segments_to_route:generate_segments_to_route_rec(
[],
Root
),
Routes_to_path = roundabout@internal@generate_route_to_path:generate_route_to_path_rec(
[],
Root
),
Helpers = roundabout@internal@generate_helpers:generate_helpers_rec(
[],
Root
),
Utils = roundabout@internal@generate_other:generate_utils(),
All = glam@doc:concat(
[roundabout@internal@generate_other:generate_header(),
roundabout@internal@generate_other:generate_imports(),
Types,
Segments_to_route,
Routes_to_path,
Helpers,
Utils]
),
Generated_code = begin
_pipe = All,
glam@doc:to_string(_pipe, 80)
end,
Output_dir = filepath:directory_name(Output_path@1),
_ = simplifile:create_directory_all(Output_dir),
_ = simplifile:write(Output_path@1, Generated_code),
{ok, nil}
end
).