-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", 44). ?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", 58). ?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", 68). ?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", 78). ?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", 152). -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@name:parameter_name( 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, " contains duplicate route names"/utf8>>} end. -file("src/roundabout.gleam", 210). -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, " contains duplicate segment names"/utf8>>} end. -file("src/roundabout.gleam", 178). -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@fixed: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@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", 167). -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", 141). ?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", 131). ?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@name:unsafe(<<""/utf8>>), []}, Children}, {ok, Root} end ). -file("src/roundabout.gleam", 87). ?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 -> <> end, Types = roundabout@internal@generate_types:generate_type_rec( roundabout@internal@ancestors:empty(), Root ), Segments_to_route = roundabout@internal@generate_segments_to_route:generate_segments_to_route_rec( roundabout@internal@ancestors:empty(), Root ), Routes_to_path = roundabout@internal@generate_route_to_path:generate_route_to_path_rec( roundabout@internal@ancestors:empty(), Root ), Helpers = roundabout@internal@generate_helpers:generate_helpers_rec( roundabout@internal@ancestors:empty(), 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 ).