-module(proute@validate@pages).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/proute/validate/pages.gleam").
-export([validate_mount/1, describe_error/1]).
-export_type([validation_error/0, page_module/0, module_shape/0]).
-type validation_error() :: {validation_error, binary(), binary(), binary()}.
-type page_module() :: {page_module,
proute@discover:page_route(),
boolean(),
boolean()}.
-type module_shape() :: {module_shape,
boolean(),
boolean(),
list(integer()),
list(integer()),
list(integer()),
{ok, integer()} | {error, nil}}.
-file("src/proute/validate/pages.gleam", 334).
-spec count_commas(list(binary()), integer(), integer()) -> integer().
count_commas(Chars, Depth, Commas) ->
case Chars of
[] ->
Commas;
[Char | Rest] ->
case Char of
<<"("/utf8>> ->
count_commas(Rest, Depth + 1, Commas);
<<"["/utf8>> ->
count_commas(Rest, Depth + 1, Commas);
<<"{"/utf8>> ->
count_commas(Rest, Depth + 1, Commas);
<<")"/utf8>> ->
count_commas(Rest, Depth - 1, Commas);
<<"]"/utf8>> ->
count_commas(Rest, Depth - 1, Commas);
<<"}"/utf8>> ->
count_commas(Rest, Depth - 1, Commas);
<<","/utf8>> ->
case Depth of
0 ->
count_commas(Rest, Depth, Commas + 1);
_ ->
count_commas(Rest, Depth, Commas)
end;
_ ->
count_commas(Rest, Depth, Commas)
end
end.
-file("src/proute/validate/pages.gleam", 312).
-spec count_params(binary()) -> integer().
count_params(Params) ->
Trimmed = gleam@string:trim(Params),
case Trimmed of
<<""/utf8>> ->
0;
_ ->
case gleam_stdlib:string_ends_with(Trimmed, <<","/utf8>>) of
true ->
_pipe = Trimmed,
_pipe@1 = gleam@string:drop_end(_pipe, 1),
_pipe@2 = gleam@string:to_graphemes(_pipe@1),
_pipe@3 = count_commas(_pipe@2, 0, 0),
(fun(Commas) -> Commas + 1 end)(_pipe@3);
false ->
_pipe@4 = Trimmed,
_pipe@5 = gleam@string:to_graphemes(_pipe@4),
_pipe@6 = count_commas(_pipe@5, 0, 0),
(fun(Commas@1) -> Commas@1 + 1 end)(_pipe@6)
end
end.
-file("src/proute/validate/pages.gleam", 292).
-spec take_until_closing_paren(binary(), integer(), binary()) -> {ok, binary()} |
{error, nil}.
take_until_closing_paren(Text, Depth, Built) ->
case gleam_stdlib:string_pop_grapheme(Text) of
{error, _} ->
{error, nil};
{ok, {Char, Rest}} ->
case Char of
<<"("/utf8>> ->
take_until_closing_paren(
Rest,
Depth + 1,
<<Built/binary, Char/binary>>
);
<<")"/utf8>> ->
case Depth of
1 ->
{ok, Built};
_ ->
take_until_closing_paren(
Rest,
Depth - 1,
<<Built/binary, Char/binary>>
)
end;
_ ->
take_until_closing_paren(
Rest,
Depth,
<<Built/binary, Char/binary>>
)
end
end.
-file("src/proute/validate/pages.gleam", 281).
-spec public_fn_params(binary(), binary()) -> {ok, binary()} | {error, nil}.
public_fn_params(Declaration, Name) ->
Prefix = <<<<"pub fn "/utf8, Name/binary>>/binary, "("/utf8>>,
gleam@result:'try'(
case gleam_stdlib:string_starts_with(Declaration, Prefix) of
true ->
{ok,
gleam@string:drop_start(Declaration, string:length(Prefix))};
false ->
{error, nil}
end,
fun(Rest) -> take_until_closing_paren(Rest, 1, <<""/utf8>>) end
).
-file("src/proute/validate/pages.gleam", 273).
-spec public_fn_arities(list(binary()), binary()) -> list(integer()).
public_fn_arities(Declarations, Name) ->
_pipe = Declarations,
gleam@list:filter_map(
_pipe,
fun(Declaration) -> _pipe@1 = public_fn_params(Declaration, Name),
gleam@result:map(_pipe@1, fun count_params/1) end
).
-file("src/proute/validate/pages.gleam", 264).
-spec public_fn_arity(list(binary()), binary()) -> {ok, integer()} |
{error, nil}.
public_fn_arity(Declarations, Name) ->
_pipe = Declarations,
_pipe@1 = public_fn_arities(_pipe, Name),
gleam@list:first(_pipe@1).
-file("src/proute/validate/pages.gleam", 254).
-spec has_public_type(list(binary()), binary()) -> boolean().
has_public_type(Declarations, Name) ->
_pipe = Declarations,
gleam@list:any(
_pipe,
fun(Declaration) ->
(((Declaration =:= (<<"pub type "/utf8, Name/binary>>)) orelse gleam_stdlib:string_starts_with(
Declaration,
<<<<"pub type "/utf8, Name/binary>>/binary, " "/utf8>>
))
orelse gleam_stdlib:string_starts_with(
Declaration,
<<<<"pub type "/utf8, Name/binary>>/binary, "{"/utf8>>
))
orelse gleam_stdlib:string_starts_with(
Declaration,
<<<<"pub type "/utf8, Name/binary>>/binary, " {"/utf8>>
)
end
).
-file("src/proute/validate/pages.gleam", 402).
-spec declaration_complete(binary()) -> boolean().
declaration_complete(Declaration) ->
(gleam_stdlib:string_starts_with(Declaration, <<"pub type "/utf8>>) orelse gleam_stdlib:contains_string(
Declaration,
<<"{"/utf8>>
))
orelse gleam_stdlib:contains_string(Declaration, <<"->"/utf8>>).
-file("src/proute/validate/pages.gleam", 359).
-spec collect_declarations(list(binary()), list(binary()), binary()) -> list(binary()).
collect_declarations(Lines, Declarations, Current) ->
case Lines of
[] ->
case Current of
<<""/utf8>> ->
Declarations;
_ ->
[gleam@string:trim(Current) | Declarations]
end;
[Line | Rest] ->
Trimmed = gleam@string:trim(Line),
case {Current,
gleam_stdlib:string_starts_with(Trimmed, <<"pub type "/utf8>>),
gleam_stdlib:string_starts_with(Trimmed, <<"pub fn "/utf8>>)} of
{<<""/utf8>>, false, false} ->
collect_declarations(Rest, Declarations, <<""/utf8>>);
{<<""/utf8>>, _, _} ->
case declaration_complete(Trimmed) of
true ->
collect_declarations(
Rest,
[Trimmed | Declarations],
<<""/utf8>>
);
false ->
collect_declarations(Rest, Declarations, Trimmed)
end;
{_, _, _} ->
Next = <<<<Current/binary, " "/utf8>>/binary,
Trimmed/binary>>,
case declaration_complete(Next) of
true ->
collect_declarations(
Rest,
[gleam@string:trim(Next) | Declarations],
<<""/utf8>>
);
false ->
collect_declarations(Rest, Declarations, Next)
end
end
end.
-file("src/proute/validate/pages.gleam", 408).
-spec strip_comment(binary()) -> binary().
strip_comment(Line) ->
case gleam@string:split_once(Line, <<"//"/utf8>>) of
{ok, {Before, _}} ->
Before;
{error, _} ->
Line
end.
-file("src/proute/validate/pages.gleam", 351).
-spec declarations(binary()) -> list(binary()).
declarations(Source) ->
_pipe = Source,
_pipe@1 = gleam@string:split(_pipe, <<"\n"/utf8>>),
_pipe@2 = gleam@list:map(_pipe@1, fun strip_comment/1),
_pipe@3 = collect_declarations(_pipe@2, [], <<""/utf8>>),
lists:reverse(_pipe@3).
-file("src/proute/validate/pages.gleam", 239).
-spec module_shape(binary()) -> module_shape().
module_shape(Source) ->
Declarations = begin
_pipe = Source,
declarations(_pipe)
end,
{module_shape,
has_public_type(Declarations, <<"Model"/utf8>>),
has_public_type(Declarations, <<"Message"/utf8>>),
public_fn_arities(Declarations, <<"init"/utf8>>),
public_fn_arities(Declarations, <<"initial_model"/utf8>>),
public_fn_arities(Declarations, <<"update"/utf8>>),
public_fn_arity(Declarations, <<"view"/utf8>>)}.
-file("src/proute/validate/pages.gleam", 215).
-spec expected_init_arity(proute@discover:page_route()) -> integer().
expected_init_arity(Route) ->
case erlang:element(6, Route) of
[] ->
2;
_ ->
3
end.
-file("src/proute/validate/pages.gleam", 141).
-spec result_to_list({ok, HMU} | {error, any()}) -> list(HMU).
result_to_list(Result) ->
case Result of
{ok, Value} ->
[Value];
{error, _} ->
[]
end.
-file("src/proute/validate/pages.gleam", 203).
-spec error(proute@discover:page_route(), binary(), binary()) -> validation_error().
error(Route, Item, Expected) ->
{validation_error, erlang:element(7, Route), Item, Expected}.
-file("src/proute/validate/pages.gleam", 161).
-spec require_arity(
list(validation_error()),
list(integer()),
integer(),
proute@discover:page_route(),
binary(),
binary()
) -> list(validation_error()).
require_arity(Errors, Actual, Expected_arity, Route, Item, Expected) ->
case gleam@list:contains(Actual, Expected_arity) of
true ->
Errors;
false ->
[error(Route, Item, Expected) | Errors]
end.
-file("src/proute/validate/pages.gleam", 189).
-spec require_any_arity(
list(validation_error()),
list(integer()),
list(integer()),
proute@discover:page_route(),
binary(),
binary()
) -> list(validation_error()).
require_any_arity(Errors, Actual, Expected_arities, Route, Item, Expected) ->
case gleam@list:any(
Expected_arities,
fun(Arity) -> gleam@list:contains(Actual, Arity) end
) of
true ->
Errors;
false ->
[error(Route, Item, Expected) | Errors]
end.
-file("src/proute/validate/pages.gleam", 231).
-spec expected_initial_model_shape(proute@discover:page_route()) -> binary().
expected_initial_model_shape(Route) ->
case erlang:element(6, Route) of
[] ->
<<"pub fn initial_model(page_shared_state, query_params) -> Model"/utf8>>;
_ ->
<<"pub fn initial_model(page_shared_state, route_params, query_params) -> Model"/utf8>>
end.
-file("src/proute/validate/pages.gleam", 222).
-spec expected_optional_init_shape(proute@discover:page_route()) -> binary().
expected_optional_init_shape(Route) ->
case erlang:element(6, Route) of
[] ->
<<"optional pub fn init(page_shared_state, query_params) -> #(Model, Effect(Message))"/utf8>>;
_ ->
<<"optional pub fn init(page_shared_state, route_params, query_params) -> #(Model, Effect(Message))"/utf8>>
end.
-file("src/proute/validate/pages.gleam", 175).
-spec require_optional_arity(
list(validation_error()),
list(integer()),
integer(),
proute@discover:page_route(),
binary(),
binary()
) -> list(validation_error()).
require_optional_arity(Errors, Actual, Expected_arity, Route, Item, Expected) ->
case Actual of
[] ->
Errors;
_ ->
require_arity(Errors, Actual, Expected_arity, Route, Item, Expected)
end.
-file("src/proute/validate/pages.gleam", 148).
-spec require(
list(validation_error()),
boolean(),
proute@discover:page_route(),
binary(),
binary()
) -> list(validation_error()).
require(Errors, Condition, Route, Item, Expected) ->
case Condition of
true ->
Errors;
false ->
[error(Route, Item, Expected) | Errors]
end.
-file("src/proute/validate/pages.gleam", 93).
-spec validate_shape(proute@discover:page_route(), module_shape()) -> {ok,
page_module()} |
{error, list(validation_error())}.
validate_shape(Route, Shape) ->
Errors = begin
_pipe = [],
_pipe@1 = require(
_pipe,
erlang:element(2, Shape),
Route,
<<"Model"/utf8>>,
<<"pub type Model"/utf8>>
),
_pipe@2 = require(
_pipe@1,
erlang:element(3, Shape),
Route,
<<"Message"/utf8>>,
<<"pub type Message"/utf8>>
),
_pipe@3 = require_optional_arity(
_pipe@2,
erlang:element(4, Shape),
expected_init_arity(Route),
Route,
<<"init"/utf8>>,
expected_optional_init_shape(Route)
),
_pipe@4 = require_arity(
_pipe@3,
erlang:element(5, Shape),
expected_init_arity(Route),
Route,
<<"initial_model"/utf8>>,
expected_initial_model_shape(Route)
),
_pipe@5 = require_any_arity(
_pipe@4,
erlang:element(6, Shape),
[2, 3],
Route,
<<"update"/utf8>>,
<<"pub fn update(model, msg) -> #(Model, Effect(Message)) or pub fn update(page_shared_state, model, msg) -> #(Model, Effect(Message))"/utf8>>
),
require_arity(
_pipe@5,
result_to_list(erlang:element(7, Shape)),
1,
Route,
<<"view"/utf8>>,
<<"pub fn view(model) -> Element(Message)"/utf8>>
)
end,
case Errors of
[] ->
{ok,
{page_module,
Route,
gleam@list:contains(
erlang:element(4, Shape),
expected_init_arity(Route)
),
gleam@list:contains(erlang:element(6, Shape), 3)}};
_ ->
{error, lists:reverse(Errors)}
end.
-file("src/proute/validate/pages.gleam", 76).
-spec validate_route(proute@discover:page_route()) -> {ok, page_module()} |
{error, list(validation_error())}.
validate_route(Route) ->
case simplifile:read(erlang:element(7, Route)) of
{error, _} ->
_pipe = [{validation_error,
erlang:element(7, Route),
<<"page file"/utf8>>,
<<"a readable Gleam source file"/utf8>>}],
{error, _pipe};
{ok, Source} ->
validate_shape(Route, module_shape(Source))
end.
-file("src/proute/validate/pages.gleam", 52).
-spec validate_routes(
list(proute@discover:page_route()),
list(page_module()),
list(validation_error())
) -> {ok, list(page_module())} | {error, list(validation_error())}.
validate_routes(Routes, Modules, Errors) ->
case Routes of
[] ->
case Errors of
[] ->
{ok, lists:reverse(Modules)};
_ ->
{error, lists:reverse(Errors)}
end;
[Route | Rest] ->
case validate_route(Route) of
{ok, Module_} ->
validate_routes(Rest, [Module_ | Modules], Errors);
{error, Route_errors} ->
validate_routes(
Rest,
Modules,
lists:append(lists:reverse(Route_errors), Errors)
)
end
end.
-file("src/proute/validate/pages.gleam", 34).
-spec validate_mount(proute@discover:mount_routes()) -> {ok,
list(page_module())} |
{error, list(validation_error())}.
validate_mount(Mount_routes) ->
{mount_routes, _, Routes} = Mount_routes,
validate_routes(Routes, [], []).
-file("src/proute/validate/pages.gleam", 42).
-spec describe_error(validation_error()) -> binary().
describe_error(Error) ->
<<<<<<<<<<<<"Invalid page module "/utf8,
(gleam@string:inspect(erlang:element(2, Error)))/binary>>/binary,
": "/utf8>>/binary,
(erlang:element(3, Error))/binary>>/binary,
". Expected "/utf8>>/binary,
(erlang:element(4, Error))/binary>>/binary,
"."/utf8>>.