Current section
Files
Jump to
Current section
Files
src/inertia.erl
-module(inertia).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/inertia.gleam").
-export([init/2, enable_ssr/0, from_context/1, add_context/2, shared_add/2, shared_get/1, root_view/1, root_ssr/1, handle_request/2, add_prop/3, add_error/3, add_once/3, add_defer/4, add_merge/3, add_flash/3, add_flashes/2, new_page_object/2, render/2, redirect/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/inertia.gleam", 45).
-spec manifest_entries() -> list(internal@manifest:entry()).
manifest_entries() ->
Manifest_file = gleam@result:unwrap(
internal@template:has_manifest(),
<<""/utf8>>
),
case internal@context:get_orelse(<<"manifest_entries"/utf8>>, []) of
[] when Manifest_file =/= <<""/utf8>> ->
case internal@template:read_file_lines(Manifest_file) of
<<""/utf8>> ->
[];
Lines ->
Entries = internal@manifest:parse(Lines),
internal@context:add_entry(
<<"manifest_entries"/utf8>>,
Entries
),
Entries
end;
[] when Manifest_file =:= <<""/utf8>> ->
[];
Entries@1 ->
Entries@1
end.
-file("src/inertia.gleam", 64).
?DOC(" Initializes the inertia context\n").
-spec init(binary(), binary()) -> nil.
init(App, Version) ->
internal@context:add_entry(<<"app"/utf8>>, App),
internal@context:add_entry(<<"version"/utf8>>, Version).
-file("src/inertia.gleam", 71).
?DOC(" Enable SSR mode\n").
-spec enable_ssr() -> nil.
enable_ssr() ->
internal@context:add_entry(<<"ssr_enabled"/utf8>>, true),
internal@context:add_entry(
<<"ssr_prod_mode"/utf8>>,
internal@template:has_ssr_manifest()
).
-file("src/inertia.gleam", 78).
?DOC(" Gets an entry from the inertia context, if it not exists returns an empty String\n").
-spec from_context(binary()) -> binary().
from_context(Name) ->
internal@context:get_orelse(Name, <<""/utf8>>).
-file("src/inertia.gleam", 84).
?DOC(" Adds an entry to the Inertia context\n").
-spec add_context(binary(), binary()) -> nil.
add_context(Name, Value) ->
internal@context:add_entry(Name, Value).
-file("src/inertia.gleam", 90).
?DOC(" Adds a shared value to the Inertia context\n").
-spec shared_add(binary(), binary()) -> nil.
shared_add(Name, Value) ->
internal@context:shared_add_entry(Name, Value).
-file("src/inertia.gleam", 96).
?DOC(" Gets a shared value from the Inertia context\n").
-spec shared_get(binary()) -> binary().
shared_get(Name) ->
internal@context:shared_get_orelse(Name, <<""/utf8>>).
-file("src/inertia.gleam", 103).
?DOC(
" Creates the root view based on index.html file when the request is a full page load.\n"
" If the index.html file is not found, it will render a default error message\n"
).
-spec root_view(binary()) -> binary().
root_view(State) ->
Pdir = begin
_pipe = internal@context:get_orelse(<<"app"/utf8>>, <<""/utf8>>),
_pipe@1 = fun gleam_erlang_ffi:priv_directory/1(_pipe),
gleam@result:unwrap(_pipe@1, <<""/utf8>>)
end,
Entries = manifest_entries(),
case internal@template:read_template(Pdir) of
{ok, Content} ->
internal@template:parse_template(Content, State, Entries);
_ ->
<<"
<html lang='en'>
<head>
<title>Inertia Error</title>
</head>
<body>
<h1 style='color:red;padding:4px;font-size:24px'>Error: No root template</h1>
</body>
</html>
"/utf8>>
end.
-file("src/inertia.gleam", 114).
-spec root_ssr(internal@ssr:s_s_r_render_response()) -> binary().
root_ssr(Res) ->
Pdir = begin
_pipe = internal@context:get_orelse(<<"app"/utf8>>, <<""/utf8>>),
_pipe@1 = fun gleam_erlang_ffi:priv_directory/1(_pipe),
gleam@result:unwrap(_pipe@1, <<""/utf8>>)
end,
case internal@template:read_template(Pdir) of
{ok, Content} ->
internal@template:parse_ssr_template(Content, Res);
_ ->
<<"
<html lang='en'>
<head>
<title>Inertia Error</title>
</head>
<body>
<h1 style='color:red;padding:4px;font-size:24px'>Error: No root template</h1>
</body>
</html>
"/utf8>>
end.
-file("src/inertia.gleam", 126).
?DOC(" Handle request middleware that manages all Inertia requests\n").
-spec handle_request(
gleam@http@request:request(wisp@internal:connection()),
fun((gleam@http@request:request(wisp@internal:connection())) -> gleam@http@response:response(wisp:body()))
) -> gleam@http@response:response(wisp:body()).
handle_request(Req, Next) ->
_pipe = Next(Req),
_pipe@1 = fun gleam@http@response:set_header/3(
_pipe,
<<"X-Inertia"/utf8>>,
<<"true"/utf8>>
),
_pipe@2 = fun gleam@http@response:set_header/3(
_pipe@1,
<<"Vary"/utf8>>,
<<"X-Inertia"/utf8>>
),
fun gleam@http@response:set_header/3(
_pipe@2,
<<"X-Inertia-Version"/utf8>>,
internal@context:get_orelse(<<"version"/utf8>>, <<"v1"/utf8>>)
).
-file("src/inertia.gleam", 135).
?DOC(" Adds a basic property to be injected on the client. The value must be a `json.Json` value\n").
-spec add_prop(internal@props:page_object(), binary(), gleam@json:json()) -> internal@props:page_object().
add_prop(Self, Name, Value) ->
New_props = lists:append(
erlang:element(4, Self),
[{base_prop, Name, Value}]
),
{page_object,
erlang:element(2, Self),
erlang:element(3, Self),
New_props,
erlang:element(5, Self),
erlang:element(6, Self),
erlang:element(7, Self),
erlang:element(8, Self),
erlang:element(9, Self)}.
-file("src/inertia.gleam", 146).
?DOC(" Adds an error property. The value must be a `json.Json` value\n").
-spec add_error(internal@props:page_object(), binary(), gleam@json:json()) -> internal@props:page_object().
add_error(Self, Name, Value) ->
New_errors = lists:append(
erlang:element(5, Self),
[{error_prop, Name, Value}]
),
{page_object,
erlang:element(2, Self),
erlang:element(3, Self),
erlang:element(4, Self),
New_errors,
erlang:element(6, Self),
erlang:element(7, Self),
erlang:element(8, Self),
erlang:element(9, Self)}.
-file("src/inertia.gleam", 157).
?DOC(" Adds an once property. The property value must be a function that returns a `json.Json` value.\n").
-spec add_once(
internal@props:page_object(),
binary(),
fun(() -> gleam@json:json())
) -> internal@props:page_object().
add_once(Self, Name, Value) ->
New_props = lists:append(
erlang:element(4, Self),
[{once_prop, Name, Value}]
),
{page_object,
erlang:element(2, Self),
erlang:element(3, Self),
New_props,
erlang:element(5, Self),
erlang:element(6, Self),
erlang:element(7, Self),
erlang:element(8, Self),
erlang:element(9, Self)}.
-file("src/inertia.gleam", 169).
?DOC(
" Adds a deferred property. Usually, a deferred property is a time-consuming function that will take time\n"
" to generate its outcome. The property value is a function that returns `Result(json.Json, Nil)`\n"
).
-spec add_defer(
internal@props:page_object(),
binary(),
fun(() -> {ok, gleam@json:json()} | {error, nil}),
gleam@option:option(binary())
) -> internal@props:page_object().
add_defer(Self, Name, Value, Group) ->
New_props = lists:append(
erlang:element(6, Self),
[{defer_prop, Name, Value, Group}]
),
{page_object,
erlang:element(2, Self),
erlang:element(3, Self),
erlang:element(4, Self),
erlang:element(5, Self),
New_props,
erlang:element(7, Self),
erlang:element(8, Self),
erlang:element(9, Self)}.
-file("src/inertia.gleam", 182).
?DOC(" Adds a Merge property\n").
-spec add_merge(
internal@props:page_object(),
binary(),
fun(() -> gleam@json:json())
) -> internal@props:page_object().
add_merge(Self, Name, Value) ->
New_props = lists:append(
erlang:element(4, Self),
[{merge_prop, Name, Value}]
),
{page_object,
erlang:element(2, Self),
erlang:element(3, Self),
New_props,
erlang:element(5, Self),
erlang:element(6, Self),
erlang:element(7, Self),
erlang:element(8, Self),
erlang:element(9, Self)}.
-file("src/inertia.gleam", 193).
?DOC(" Adds a flash message on the request. The flash message value IS NOT persisted between requests.\n").
-spec add_flash(
gleam@http@request:request(wisp@internal:connection()),
binary(),
binary()
) -> gleam@http@request:request(wisp@internal:connection()).
add_flash(Req, Name, Value) ->
internal@flash:set_flash_message(Req, Name, Value).
-file("src/inertia.gleam", 203).
?DOC(" Adds multiple flash messages on the request. The flash message value IS NOT persisted between requests.\n").
-spec add_flashes(
gleam@http@request:request(wisp@internal:connection()),
list(internal@flash:flash_prop())
) -> gleam@http@request:request(wisp@internal:connection()).
add_flashes(Req, Messages) ->
internal@flash:set_flash_messages(Req, Messages).
-file("src/inertia.gleam", 212).
?DOC(" Creates a page object that will manage all properties for the current page component.\n").
-spec new_page_object(
gleam@http@request:request(wisp@internal:connection()),
binary()
) -> internal@props:page_object().
new_page_object(Req, Component) ->
{page_object,
Component,
erlang:element(8, Req),
gleam@list:new(),
gleam@list:new(),
gleam@list:new(),
internal@props:dict_to_prop(internal@context:shared_get_all()),
internal@context:get_orelse(<<"version"/utf8>>, <<"v1"/utf8>>),
none}.
-file("src/inertia.gleam", 228).
-spec new_render_context(gleam@http@request:request(wisp@internal:connection())) -> internal@props:render_context().
new_render_context(Req) ->
Component = begin
_pipe = gleam@http@request:get_header(
Req,
<<"x-inertia-partial-component"/utf8>>
),
gleam@result:unwrap(_pipe, <<""/utf8>>)
end,
First_load = Component =:= <<""/utf8>>,
Except_once = case gleam@http@request:get_header(
Req,
<<"x-inertia-except-once-props"/utf8>>
) of
{ok, Str} ->
gleam@string:split(Str, <<","/utf8>>);
{error, _} ->
[]
end,
Excepts = case gleam@http@request:get_header(
Req,
<<"x-inertia-partial-except"/utf8>>
) of
{ok, Str@1} ->
lists:append(Except_once, gleam@string:split(Str@1, <<","/utf8>>));
{error, _} ->
Except_once
end,
Partials = case gleam@http@request:get_header(
Req,
<<"x-inertia-partial-data"/utf8>>
) of
{ok, Str@2} ->
gleam@string:split(Str@2, <<","/utf8>>);
{error, _} ->
[]
end,
Resets = case gleam@http@request:get_header(Req, <<"x-inertia-reset"/utf8>>) of
{ok, Str@3} ->
gleam@string:split(Str@3, <<","/utf8>>);
{error, _} ->
[]
end,
Version = internal@context:get_orelse(<<"version"/utf8>>, <<"v1"/utf8>>),
{render_context,
Req,
Component,
Version,
First_load,
Resets,
Partials,
Excepts}.
-file("src/inertia.gleam", 308).
-spec csr_render(
gleam@http@request:request(wisp@internal:connection()),
binary()
) -> gleam@http@response:response(wisp:body()).
csr_render(Req, Body) ->
case gleam@http@request:get_header(
Req,
string:lowercase(<<"X-Inertia"/utf8>>)
) of
{ok, _} ->
wisp:json_body(wisp:ok(), Body);
_ ->
wisp:html_body(wisp:ok(), root_view(Body))
end.
-file("src/inertia.gleam", 290).
-spec ssr_render(binary()) -> gleam@http@response:response(wisp:body()).
ssr_render(Body) ->
Ssr_url = case internal@context:get_orelse(<<"ssr_prod_mode"/utf8>>, false) of
true ->
<<"http://localhost:13714/render"/utf8>>;
false ->
<<"http://localhost:5173/__inertia_ssr/render"/utf8>>
end,
case internal@ssr:server_render(Ssr_url, Body) of
{ok, Res} ->
wisp:html_body(wisp:ok(), root_ssr(Res));
{error, Err} ->
wisp:log_error(gleam@string:inspect(Err)),
wisp:html_body(
wisp:internal_server_error(),
<<"<p>fail to process SSR response</p>"/utf8>>
)
end.
-file("src/inertia.gleam", 275).
?DOC(
" Renders a Inertia component based on the PageObject.\n"
"\n"
" #Example:\n"
" ```gleam\n"
" inertia.new_page_object(req, \"index)\n"
" |> inertia.render(req)\n"
" ```\n"
).
-spec render(
internal@props:page_object(),
gleam@http@request:request(wisp@internal:connection())
) -> gleam@http@response:response(wisp:body()).
render(Page_object, Req) ->
Po = begin
_pipe = Page_object,
_pipe@1 = internal@props:page_object_to_json(
_pipe,
new_render_context(Req)
),
gleam@json:to_string(_pipe@1)
end,
case internal@context:get_orelse(<<"ssr_enabled"/utf8>>, false) of
true ->
ssr_render(Po);
false ->
csr_render(Req, Po)
end.
-file("src/inertia.gleam", 323).
?DOC(
" Creates a reponse with status code 303 for Post, Patch, Put or Delete request,\n"
" otherwise the status code is 302\n"
"\n"
" #Example\n"
" ```gleam\n"
" inertia.redirect(req, \"/\")\n"
" ```\n"
).
-spec redirect(gleam@http@request:request(wisp@internal:connection()), binary()) -> gleam@http@response:response(wisp:body()).
redirect(Req, Path) ->
case erlang:element(2, Req) of
post ->
Cookies = begin
_pipe = erlang:element(3, Req),
gleam@list:filter(
_pipe,
fun(Pair) ->
erlang:element(1, Pair) =:= <<"inertia_flash"/utf8>>
end
)
end,
case Cookies of
[Ic] ->
_pipe@1 = wisp:redirect(Path),
wisp:set_cookie(
_pipe@1,
Req,
erlang:element(1, Ic),
erlang:element(2, Ic),
plain_text,
10
);
_ ->
wisp:redirect(Path)
end;
put ->
Cookies = begin
_pipe = erlang:element(3, Req),
gleam@list:filter(
_pipe,
fun(Pair) ->
erlang:element(1, Pair) =:= <<"inertia_flash"/utf8>>
end
)
end,
case Cookies of
[Ic] ->
_pipe@1 = wisp:redirect(Path),
wisp:set_cookie(
_pipe@1,
Req,
erlang:element(1, Ic),
erlang:element(2, Ic),
plain_text,
10
);
_ ->
wisp:redirect(Path)
end;
patch ->
Cookies = begin
_pipe = erlang:element(3, Req),
gleam@list:filter(
_pipe,
fun(Pair) ->
erlang:element(1, Pair) =:= <<"inertia_flash"/utf8>>
end
)
end,
case Cookies of
[Ic] ->
_pipe@1 = wisp:redirect(Path),
wisp:set_cookie(
_pipe@1,
Req,
erlang:element(1, Ic),
erlang:element(2, Ic),
plain_text,
10
);
_ ->
wisp:redirect(Path)
end;
delete ->
Cookies = begin
_pipe = erlang:element(3, Req),
gleam@list:filter(
_pipe,
fun(Pair) ->
erlang:element(1, Pair) =:= <<"inertia_flash"/utf8>>
end
)
end,
case Cookies of
[Ic] ->
_pipe@1 = wisp:redirect(Path),
wisp:set_cookie(
_pipe@1,
Req,
erlang:element(1, Ic),
erlang:element(2, Ic),
plain_text,
10
);
_ ->
wisp:redirect(Path)
end;
_ ->
{response, 302, [{<<"location"/utf8>>, Path}], {text, <<""/utf8>>}}
end.