-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, <> ); <<")"/utf8>> -> case Depth of 1 -> {ok, Built}; _ -> take_until_closing_paren( Rest, Depth - 1, <> ) end; _ -> take_until_closing_paren( Rest, Depth, <> ) 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 = <<<>/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>>.