-module(proute@config).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/proute/config.gleam").
-export([default_page_shared_state_type/1, parse/1, describe_error/1]).
-export_type([config/0, mount/0, raw_config/0, raw_mount/0, config_error/0]).
-type config() :: {config, binary(), binary(), list(mount())}.
-type mount() :: {mount,
binary(),
binary(),
binary(),
binary(),
binary(),
binary(),
binary(),
binary(),
binary()}.
-type raw_config() :: {raw_config, binary(), binary(), list(raw_mount())}.
-type raw_mount() :: {raw_mount,
binary(),
{ok, binary()} | {error, nil},
{ok, binary()} | {error, nil},
{ok, binary()} | {error, nil},
{ok, binary()} | {error, nil}}.
-type config_error() :: {missing_config, binary()} |
{malformed_config, binary()} |
missing_proute_table |
missing_mounts |
{missing_mount_name, integer()} |
{invalid_mount_name, binary()} |
{duplicate_mount_name, binary()} |
{invalid_constructor_prefix, binary(), binary()} |
{invalid_route_root, binary(), binary()} |
{invalid_page_shared_state_type, binary(), binary()}.
-file("src/proute/config.gleam", 352).
-spec join_path(list(binary())) -> binary().
join_path(Parts) ->
_pipe = Parts,
_pipe@1 = gleam@list:filter(_pipe, fun(Part) -> Part /= <<""/utf8>> end),
gleam@string:join(_pipe@1, <<"/"/utf8>>).
-file("src/proute/config.gleam", 338).
-spec validate_constructor_prefix(binary(), binary()) -> {ok, nil} |
{error, config_error()}.
validate_constructor_prefix(Mount_name, Constructor_prefix) ->
case Constructor_prefix of
<<""/utf8>> ->
{ok, nil};
_ ->
case proute@names:is_valid_type_name(
<<Constructor_prefix/binary, "Home"/utf8>>
) of
true ->
{ok, nil};
false ->
{error,
{invalid_constructor_prefix,
Mount_name,
Constructor_prefix}}
end
end.
-file("src/proute/config.gleam", 334).
-spec default_page_shared_state_type(binary()) -> binary().
default_page_shared_state_type(Name) ->
<<<<<<Name/binary, "/page_shared_state."/utf8>>/binary,
(proute@names:pascal_case(Name))/binary>>/binary,
"PageSharedState"/utf8>>.
-file("src/proute/config.gleam", 327).
-spec default_constructor_prefix(binary(), binary()) -> binary().
default_constructor_prefix(Name, Route_root) ->
case Route_root of
<<"/"/utf8>> ->
<<""/utf8>>;
_ ->
proute@names:pascal_case(Name)
end.
-file("src/proute/config.gleam", 315).
-spec is_valid_route_root(binary()) -> boolean().
is_valid_route_root(Route_root) ->
(Route_root =:= <<"/"/utf8>>) orelse (((((gleam_stdlib:string_starts_with(
Route_root,
<<"/"/utf8>>
)
andalso not gleam_stdlib:string_ends_with(Route_root, <<"/"/utf8>>))
andalso not gleam_stdlib:contains_string(Route_root, <<"//"/utf8>>))
andalso not gleam_stdlib:contains_string(Route_root, <<"?"/utf8>>))
andalso not gleam_stdlib:contains_string(Route_root, <<"#"/utf8>>))
andalso not gleam_stdlib:contains_string(Route_root, <<" "/utf8>>)).
-file("src/proute/config.gleam", 303).
-spec normalize_route_root(binary()) -> binary().
normalize_route_root(Route_root) ->
Pieces = begin
_pipe = Route_root,
_pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>),
gleam@list:filter(_pipe@1, fun(Piece) -> Piece /= <<""/utf8>> end)
end,
case Pieces of
[] ->
<<"/"/utf8>>;
_ ->
<<"/"/utf8, (gleam@string:join(Pieces, <<"/"/utf8>>))/binary>>
end.
-file("src/proute/config.gleam", 293).
-spec resolve_route_root(raw_mount()) -> {ok, binary()} |
{error, config_error()}.
resolve_route_root(Mount) ->
Root = gleam@result:unwrap(
erlang:element(4, Mount),
<<"/"/utf8, (erlang:element(2, Mount))/binary>>
),
Normalized = normalize_route_root(Root),
case is_valid_route_root(Normalized) of
true ->
{ok, Normalized};
false ->
{error, {invalid_route_root, erlang:element(2, Mount), Root}}
end.
-file("src/proute/config.gleam", 225).
-spec resolve_mount(raw_mount(), binary(), binary()) -> {ok, mount()} |
{error, config_error()}.
resolve_mount(Mount, Pages_root, Output_root) ->
gleam@result:'try'(
resolve_route_root(Mount),
fun(Route_root) ->
Pages = gleam@result:unwrap(
erlang:element(3, Mount),
join_path(
[Pages_root, erlang:element(2, Mount), <<"pages"/utf8>>]
)
),
Output_dir = join_path([Output_root, erlang:element(2, Mount)]),
Constructor_prefix = gleam@result:unwrap(
erlang:element(5, Mount),
default_constructor_prefix(erlang:element(2, Mount), Route_root)
),
Page_shared_state_type = gleam@result:unwrap(
erlang:element(6, Mount),
default_page_shared_state_type(erlang:element(2, Mount))
),
gleam@result:'try'(
validate_constructor_prefix(
erlang:element(2, Mount),
Constructor_prefix
),
fun(_) ->
gleam@result:'try'(
begin
_pipe = proute@names:parse_type_reference(
Page_shared_state_type
),
gleam@result:map_error(
_pipe,
fun(_) ->
{invalid_page_shared_state_type,
erlang:element(2, Mount),
Page_shared_state_type}
end
)
end,
fun(_) ->
{ok,
{mount,
erlang:element(2, Mount),
Pages,
Route_root,
Output_dir,
join_path(
[Output_dir, <<"routes.gleam"/utf8>>]
),
join_path(
[Output_dir, <<"pages.gleam"/utf8>>]
),
join_path(
[Output_dir,
<<"page_input.gleam"/utf8>>]
),
Constructor_prefix,
Page_shared_state_type}}
end
)
end
)
end
).
-file("src/proute/config.gleam", 289).
-spec is_valid_mount_name(binary()) -> boolean().
is_valid_mount_name(Name) ->
proute@names:is_valid_module_path(Name).
-file("src/proute/config.gleam", 269).
-spec validate_mount_names(list(raw_mount()), gleam@dict:dict(binary(), nil)) -> {ok,
nil} |
{error, config_error()}.
validate_mount_names(Mounts, Seen) ->
case Mounts of
[] ->
{ok, nil};
[Mount | Rest] ->
case is_valid_mount_name(erlang:element(2, Mount)) of
false ->
{error, {invalid_mount_name, erlang:element(2, Mount)}};
true ->
case gleam@dict:has_key(Seen, erlang:element(2, Mount)) of
true ->
{error,
{duplicate_mount_name, erlang:element(2, Mount)}};
false ->
validate_mount_names(
Rest,
gleam@dict:insert(
Seen,
erlang:element(2, Mount),
nil
)
)
end
end
end.
-file("src/proute/config.gleam", 211).
-spec resolve(raw_config()) -> {ok, config()} | {error, config_error()}.
resolve(Raw) ->
gleam@result:'try'(
validate_mount_names(erlang:element(4, Raw), maps:new()),
fun(_) -> _pipe = erlang:element(4, Raw),
_pipe@1 = gleam@list:try_map(
_pipe,
fun(_capture) ->
resolve_mount(
_capture,
erlang:element(2, Raw),
erlang:element(3, Raw)
)
end
),
gleam@result:map(
_pipe@1,
fun(Mounts) ->
{config,
erlang:element(2, Raw),
erlang:element(3, Raw),
Mounts}
end
) end
).
-file("src/proute/config.gleam", 415).
-spec describe_tom_error(tom:get_error()) -> binary().
describe_tom_error(Error) ->
case Error of
{not_found, Path} ->
<<"missing "/utf8, (gleam@string:join(Path, <<"."/utf8>>))/binary>>;
{wrong_type, _, Expected, Got} ->
<<<<<<"expected "/utf8, Expected/binary>>/binary, ", got "/utf8>>/binary,
Got/binary>>
end.
-file("src/proute/config.gleam", 388).
-spec optional_string_result(
gleam@dict:dict(binary(), tom:toml()),
binary(),
list(binary())
) -> {ok, {ok, binary()} | {error, nil}} | {error, config_error()}.
optional_string_result(Table, Field, Path) ->
case tom:get_string(Table, [Field]) of
{ok, Value} ->
{ok, {ok, Value}};
{error, {not_found, _}} ->
{ok, {error, nil}};
{error, Error} ->
{error,
{malformed_config,
<<<<<<"Invalid "/utf8,
(gleam@string:join(Path, <<"."/utf8>>))/binary>>/binary,
": "/utf8>>/binary,
(describe_tom_error(Error))/binary>>}}
end.
-file("src/proute/config.gleam", 358).
-spec optional_string(
gleam@dict:dict(binary(), tom:toml()),
binary(),
list(binary()),
binary()
) -> {ok, binary()} | {error, config_error()}.
optional_string(Table, Field, Path, Default) ->
case optional_string_result(Table, Field, Path) of
{ok, {ok, Value}} ->
{ok, Value};
{ok, {error, _}} ->
{ok, Default};
{error, Error} ->
{error, Error}
end.
-file("src/proute/config.gleam", 371).
-spec required_mount_name(gleam@dict:dict(binary(), tom:toml()), integer()) -> {ok,
binary()} |
{error, config_error()}.
required_mount_name(Table, Index) ->
case tom:get_string(Table, [<<"name"/utf8>>]) of
{ok, Value} ->
{ok, Value};
{error, {not_found, _}} ->
{error, {missing_mount_name, Index}};
{error, Error} ->
{error,
{malformed_config,
<<<<<<"Invalid proute.mounts."/utf8,
(erlang:integer_to_binary(Index))/binary>>/binary,
".name: "/utf8>>/binary,
(describe_tom_error(Error))/binary>>}}
end.
-file("src/proute/config.gleam", 155).
-spec read_mounts_loop(
list(gleam@dict:dict(binary(), tom:toml())),
integer(),
list(raw_mount())
) -> {ok, list(raw_mount())} | {error, config_error()}.
read_mounts_loop(Mounts, Index, Read) ->
case Mounts of
[] ->
{ok, lists:reverse(Read)};
[Mount | Rest] ->
gleam@result:'try'(
required_mount_name(Mount, Index),
fun(Name) ->
gleam@result:'try'(
optional_string_result(
Mount,
<<"pages"/utf8>>,
[<<"proute"/utf8>>,
<<"mounts"/utf8>>,
erlang:integer_to_binary(Index),
<<"pages"/utf8>>]
),
fun(Pages) ->
gleam@result:'try'(
optional_string_result(
Mount,
<<"route_root"/utf8>>,
[<<"proute"/utf8>>,
<<"mounts"/utf8>>,
erlang:integer_to_binary(Index),
<<"route_root"/utf8>>]
),
fun(Route_root) ->
gleam@result:'try'(
optional_string_result(
Mount,
<<"constructor_prefix"/utf8>>,
[<<"proute"/utf8>>,
<<"mounts"/utf8>>,
erlang:integer_to_binary(Index),
<<"constructor_prefix"/utf8>>]
),
fun(Constructor_prefix) ->
gleam@result:'try'(
optional_string_result(
Mount,
<<"page_shared_state_type"/utf8>>,
[<<"proute"/utf8>>,
<<"mounts"/utf8>>,
erlang:integer_to_binary(
Index
),
<<"page_shared_state_type"/utf8>>]
),
fun(Page_shared_state_type) ->
read_mounts_loop(
Rest,
Index + 1,
[{raw_mount,
Name,
Pages,
Route_root,
Constructor_prefix,
Page_shared_state_type} |
Read]
)
end
)
end
)
end
)
end
)
end
)
end.
-file("src/proute/config.gleam", 135).
-spec read_mounts(gleam@dict:dict(binary(), tom:toml())) -> {ok,
list(raw_mount())} |
{error, config_error()}.
read_mounts(Proute) ->
case tom:get_array(Proute, [<<"mounts"/utf8>>]) of
{error, {not_found, _}} ->
{error, missing_mounts};
{error, Error} ->
{error,
{malformed_config,
<<"Invalid proute.mounts: "/utf8,
(describe_tom_error(Error))/binary>>}};
{ok, []} ->
{error, missing_mounts};
{ok, Mounts} ->
case gleam@list:try_map(Mounts, fun tom:as_table/1) of
{ok, Mounts@1} ->
_pipe = Mounts@1,
read_mounts_loop(_pipe, 1, []);
{error, Error@1} ->
{error,
{malformed_config,
<<"Invalid proute.mounts: expected array of tables, "/utf8,
(describe_tom_error(Error@1))/binary>>}}
end
end.
-file("src/proute/config.gleam", 406).
-spec read_proute_table(gleam@dict:dict(binary(), tom:toml())) -> {ok,
gleam@dict:dict(binary(), tom:toml())} |
{error, config_error()}.
read_proute_table(Table) ->
case tom:get_table(Table, [<<"proute"/utf8>>]) of
{ok, Value} ->
{ok, Value};
{error, {not_found, _}} ->
{error, missing_proute_table};
{error, Error} ->
{error,
{malformed_config,
<<"Invalid proute: "/utf8,
(describe_tom_error(Error))/binary>>}}
end.
-file("src/proute/config.gleam", 115).
-spec read_raw_config(gleam@dict:dict(binary(), tom:toml())) -> {ok,
raw_config()} |
{error, config_error()}.
read_raw_config(Document) ->
gleam@result:'try'(
read_proute_table(Document),
fun(Proute) ->
gleam@result:'try'(
read_mounts(Proute),
fun(Mounts) ->
gleam@result:'try'(
optional_string(
Proute,
<<"pages_root"/utf8>>,
[<<"proute"/utf8>>, <<"pages_root"/utf8>>],
<<"src"/utf8>>
),
fun(Pages_root) ->
gleam@result:'try'(
optional_string(
Proute,
<<"output_root"/utf8>>,
[<<"proute"/utf8>>, <<"output_root"/utf8>>],
<<"src/generated/proute"/utf8>>
),
fun(Output_root) ->
{ok,
{raw_config,
Pages_root,
Output_root,
Mounts}}
end
)
end
)
end
)
end
).
-file("src/proute/config.gleam", 58).
-spec parse(binary()) -> {ok, config()} | {error, config_error()}.
parse(Source) ->
gleam@result:'try'(
begin
_pipe = tom:parse(Source),
gleam@result:map_error(
_pipe,
fun(Error) ->
{malformed_config,
<<"Could not parse proute.toml: "/utf8,
(gleam@string:inspect(Error))/binary>>}
end
)
end,
fun(Document) ->
gleam@result:'try'(
read_raw_config(Document),
fun(Raw) -> resolve(Raw) end
)
end
).
-file("src/proute/config.gleam", 70).
-spec describe_error(config_error()) -> binary().
describe_error(Error) ->
case Error of
{missing_config, Path} ->
<<<<"Missing proute config: expected "/utf8, Path/binary>>/binary,
" in the current directory."/utf8>>;
{malformed_config, Message} ->
Message;
missing_proute_table ->
<<"Missing [proute] config table in proute.toml."/utf8>>;
missing_mounts ->
<<"Missing [[proute.mounts]] entries in proute.toml."/utf8>>;
{missing_mount_name, Index} ->
<<<<"Missing required name for [[proute.mounts]] entry #"/utf8,
(erlang:integer_to_binary(Index))/binary>>/binary,
"."/utf8>>;
{invalid_mount_name, Name} ->
<<<<"Invalid mount name "/utf8,
(gleam@string:inspect(Name))/binary>>/binary,
": use a valid Gleam module path segment."/utf8>>;
{duplicate_mount_name, Name@1} ->
<<<<"Duplicate mount name "/utf8,
(gleam@string:inspect(Name@1))/binary>>/binary,
" in proute.toml."/utf8>>;
{invalid_constructor_prefix, Name@2, Constructor_prefix} ->
<<<<<<<<<<<<"Invalid constructor_prefix "/utf8,
(gleam@string:inspect(Constructor_prefix))/binary>>/binary,
" for mount "/utf8>>/binary,
(gleam@string:inspect(Name@2))/binary>>/binary,
": it must produce valid Gleam route constructors, such as "/utf8>>/binary,
(gleam@string:inspect(
<<Constructor_prefix/binary, "Home"/utf8>>
))/binary>>/binary,
"."/utf8>>;
{invalid_route_root, Name@3, Route_root} ->
<<<<<<<<"Invalid route_root "/utf8,
(gleam@string:inspect(Route_root))/binary>>/binary,
" for mount "/utf8>>/binary,
(gleam@string:inspect(Name@3))/binary>>/binary,
": route roots must normalize to / or an absolute path without empty segments."/utf8>>;
{invalid_page_shared_state_type, Name@4, Value} ->
<<<<<<<<<<<<"Invalid page_shared_state_type "/utf8,
(gleam@string:inspect(Value))/binary>>/binary,
" for mount "/utf8>>/binary,
(gleam@string:inspect(Name@4))/binary>>/binary,
": use a Gleam module path and type name, such as "/utf8>>/binary,
(gleam@string:inspect(
default_page_shared_state_type(Name@4)
))/binary>>/binary,
"."/utf8>>
end.