Current section

Files

Jump to
lustre src lustre.erl
Raw

src/lustre.erl

-module(lustre).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([main/0, application/3, element/1, simple/3, component/4, start_actor/2, start_server_component/2, register/2, add_renderer/2, dispatch/1, remove_renderer/1, shutdown/0, is_browser/0, start/3, is_registered/1]).
-export_type([app/3, client_spa/0, server_component/0, error/0]).
-opaque app(SJV, SJW, SJX) :: {app,
fun((SJV) -> {SJW, lustre@effect:effect(SJX)}),
fun((SJW, SJX) -> {SJW, lustre@effect:effect(SJX)}),
fun((SJW) -> lustre@internals@vdom:element(SJX)),
gleam@option:option(gleam@dict:dict(binary(), fun((gleam@dynamic:dynamic_()) -> {ok,
SJX} |
{error, list(gleam@dynamic:decode_error())})))}.
-type client_spa() :: any().
-type server_component() :: any().
-type error() :: {actor_error, gleam@otp@actor:start_error()} |
{bad_component_name, binary()} |
{component_already_registered, binary()} |
{element_not_found, binary()} |
not_a_browser |
not_erlang.
-spec main() -> nil.
main() ->
Args = erlang:element(4, argv:load()),
_pipe = glint:new(),
_pipe@1 = glint:as_gleam_module(_pipe),
_pipe@2 = glint:with_name(_pipe@1, <<"lustre"/utf8>>),
_pipe@3 = glint:add(
_pipe@2,
[<<"add"/utf8>>, <<"esbuild"/utf8>>],
lustre@cli@add:esbuild()
),
_pipe@4 = glint:add(
_pipe@3,
[<<"build"/utf8>>, <<"app"/utf8>>],
lustre@cli@build:app()
),
_pipe@5 = glint:add(
_pipe@4,
[<<"build"/utf8>>, <<"component"/utf8>>],
lustre@cli@build:component()
),
_pipe@6 = glint:add(_pipe@5, [<<"dev"/utf8>>], lustre@cli@dev:run()),
glint:run(_pipe@6, Args).
-spec application(
fun((SKP) -> {SKQ, lustre@effect:effect(SKR)}),
fun((SKQ, SKR) -> {SKQ, lustre@effect:effect(SKR)}),
fun((SKQ) -> lustre@internals@vdom:element(SKR))
) -> app(SKP, SKQ, SKR).
application(Init, Update, View) ->
{app, Init, Update, View, none}.
-spec element(lustre@internals@vdom:element(SKD)) -> app(nil, nil, SKD).
element(Html) ->
Init = fun(_) -> {nil, lustre@effect:none()} end,
Update = fun(_, _) -> {nil, lustre@effect:none()} end,
View = fun(_) -> Html end,
application(Init, Update, View).
-spec simple(
fun((SKI) -> SKJ),
fun((SKJ, SKK) -> SKJ),
fun((SKJ) -> lustre@internals@vdom:element(SKK))
) -> app(SKI, SKJ, SKK).
simple(Init, Update, View) ->
Init@1 = fun(Flags) -> {Init(Flags), lustre@effect:none()} end,
Update@1 = fun(Model, Msg) -> {Update(Model, Msg), lustre@effect:none()} end,
application(Init@1, Update@1, View).
-spec component(
fun((SKY) -> {SKZ, lustre@effect:effect(SLA)}),
fun((SKZ, SLA) -> {SKZ, lustre@effect:effect(SLA)}),
fun((SKZ) -> lustre@internals@vdom:element(SLA)),
gleam@dict:dict(binary(), fun((gleam@dynamic:dynamic_()) -> {ok, SLA} |
{error, list(gleam@dynamic:decode_error())}))
) -> app(SKY, SKZ, SLA).
component(Init, Update, View, On_attribute_change) ->
{app, Init, Update, View, {some, On_attribute_change}}.
-spec do_start(app(SLU, any(), SLW), binary(), SLU) -> {ok,
fun((lustre@internals@runtime:action(SLW, client_spa())) -> nil)} |
{error, error()}.
do_start(_, _, _) ->
{error, not_a_browser}.
-spec do_start_actor(app(SMZ, any(), SNB), SMZ) -> {ok,
gleam@erlang@process:subject(lustre@internals@runtime:action(SNB, server_component()))} |
{error, error()}.
do_start_actor(App, Flags) ->
On_attribute_change = gleam@option:unwrap(
erlang:element(5, App),
gleam@dict:new()
),
_pipe = (erlang:element(2, App))(Flags),
_pipe@1 = lustre@internals@runtime:start(
_pipe,
erlang:element(3, App),
erlang:element(4, App),
On_attribute_change
),
gleam@result:map_error(_pipe@1, fun(Field@0) -> {actor_error, Field@0} end).
-spec start_actor(app(SMO, any(), SMQ), SMO) -> {ok,
gleam@erlang@process:subject(lustre@internals@runtime:action(SMQ, server_component()))} |
{error, error()}.
start_actor(App, Flags) ->
do_start_actor(App, Flags).
-spec start_server_component(app(SME, any(), SMG), SME) -> {ok,
fun((lustre@internals@runtime:action(SMG, server_component())) -> nil)} |
{error, error()}.
start_server_component(App, Flags) ->
gleam@result:map(
start_actor(App, Flags),
fun(Runtime) ->
fun(_capture) -> gleam@otp@actor:send(Runtime, _capture) end
end
).
-spec register(app(nil, any(), any()), binary()) -> {ok, nil} | {error, error()}.
register(_, _) ->
{error, not_a_browser}.
-spec add_renderer(any(), fun((lustre@internals@patch:patch(SNS)) -> nil)) -> lustre@internals@runtime:action(SNS, server_component()).
add_renderer(Id, Renderer) ->
{add_renderer, gleam@dynamic:from(Id), Renderer}.
-spec dispatch(SNW) -> lustre@internals@runtime:action(SNW, any()).
dispatch(Msg) ->
{dispatch, Msg}.
-spec remove_renderer(any()) -> lustre@internals@runtime:action(any(), server_component()).
remove_renderer(Id) ->
{remove_renderer, gleam@dynamic:from(Id)}.
-spec shutdown() -> lustre@internals@runtime:action(any(), any()).
shutdown() ->
shutdown.
-spec is_browser() -> boolean().
is_browser() ->
false.
-spec start(app(SLK, any(), SLM), binary(), SLK) -> {ok,
fun((lustre@internals@runtime:action(SLM, client_spa())) -> nil)} |
{error, error()}.
start(App, Selector, Flags) ->
gleam@bool:guard(
not is_browser(),
{error, not_a_browser},
fun() -> do_start(App, Selector, Flags) end
).
-spec is_registered(binary()) -> boolean().
is_registered(_) ->
false.