Packages
lustre
4.0.0-rc.2
5.7.1
5.7.0
5.6.0
5.5.2
5.5.1
5.5.0
5.4.0
5.3.5
5.3.4
5.3.3
5.3.2
5.3.1
5.3.0
5.2.1
5.2.0
5.1.1
5.1.0
5.0.3
5.0.2
5.0.1
5.0.0
4.6.4
4.6.3
4.6.2
4.6.1
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.6
4.3.5
4.3.4
4.3.3
4.3.2
4.3.1
4.3.0
4.2.6
4.2.5
4.2.4
4.2.3
4.2.2
4.2.1
4.2.0
4.1.8
4.1.7
4.1.6
4.1.5
4.1.4
4.1.3
4.1.2
4.1.1
4.1.0
4.0.0
4.0.0-rc1
4.0.0-rc.2
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.12
3.0.11
3.0.10
3.0.9
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
3.0.0-rc.8
3.0.0-rc.7
3.0.0-rc.6
3.0.0-rc.5
3.0.0-rc.4
3.0.0-rc.3
3.0.0-rc.2
3.0.0-rc.1
2.0.1
2.0.0
1.3.0
1.2.0
1.1.0
1.0.0
Create HTML templates, single page applications, Web Components, and real-time server components in Gleam!
Current section
Files
Jump to
Current section
Files
src/lustre@cli@dev.erl
-module(lustre@cli@dev).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([run/0]).
-export_type([error/0]).
-type error() :: build_error |
{bundle_error, lustre@cli@esbuild:error()} |
{main_missing, binary()} |
{main_incorrect_type, binary(), lustre@cli@project:type()} |
{main_bad_app_type, binary(), lustre@cli@project:type()} |
{module_missing, binary()}.
-spec explain(error()) -> nil.
explain(Error) ->
case Error of
build_error ->
lustre@cli@project:explain(build_error);
{bundle_error, Error@1} ->
lustre@cli@esbuild:explain(Error@1);
{main_missing, Module} ->
gleam@io:println(
<<<<"
Module `"/utf8, Module/binary>>/binary,
"` doesn't have a public `main` function I can preview."/utf8>>
);
{main_incorrect_type, Module@1, Type_} ->
gleam@io:println(
<<<<<<<<"
I cannot preview the `main` function exposed by module `"/utf8,
Module@1/binary>>/binary,
"`.
To start a preview server I need it to take no arguments and return a Lustre
`App`.
The one I found has type `"/utf8>>/binary,
(lustre@cli@project:type_to_string(Type_))/binary>>/binary,
"`."/utf8>>
);
{main_bad_app_type, Module@2, Type_@1} ->
gleam@io:println(
<<<<<<<<"
I cannot preview the `main` function exposed by module `"/utf8,
Module@2/binary>>/binary,
"`.
To start a preview server I need it to return a Lustre `App` that doesn't need
any flags.
The one I found has type `"/utf8>>/binary,
(lustre@cli@project:type_to_string(Type_@1))/binary>>/binary,
"`.
Its return type should look something like this:
import lustre.{type App}
pub fn main() -> App(flags, model, msg) {
todo as \"your Lustre application to preview\"
}"/utf8>>
);
{module_missing, Module@3} ->
gleam@io:println(
<<<<"
I couldn't find a public module called `"/utf8,
Module@3/binary>>/binary,
"` in your project."/utf8>>
)
end.
-spec index_html(binary(), binary(), boolean()) -> binary().
index_html(App_name, Container_id, Include_styles) ->
Styles = case Include_styles of
true ->
lustre@element@html:link(
[lustre@attribute:rel(<<"stylesheet"/utf8>>),
lustre@attribute:href(
<<"https://cdn.jsdelivr.net/gh/lustre-labs/ui/priv/styles.css"/utf8>>
)]
);
false ->
lustre@element:none()
end,
_pipe = lustre@element@html:html(
[],
[lustre@element@html:head(
[],
[lustre@element@html:meta(
[lustre@attribute:attribute(
<<"charset"/utf8>>,
<<"utf-8"/utf8>>
)]
),
lustre@element@html:meta(
[lustre@attribute:attribute(
<<"name"/utf8>>,
<<"viewport"/utf8>>
),
lustre@attribute:attribute(
<<"content"/utf8>>,
<<"width=device-width, initial-scale=1"/utf8>>
)]
),
lustre@element@html:title([], App_name),
lustre@element@html:script(
[lustre@attribute:type_(<<"module"/utf8>>),
lustre@attribute:src(<<"./index.mjs"/utf8>>)],
<<""/utf8>>
),
Styles]
),
lustre@element@html:body(
[],
[lustre@element@html:'div'(
[lustre@attribute:id(Container_id)],
[]
)]
)]
),
_pipe@1 = lustre@element:to_string(_pipe),
gleam@string:append(<<"<!DOCTYPE html>"/utf8>>, _pipe@1).
-spec is_nil_type(lustre@cli@project:type()) -> boolean().
is_nil_type(T) ->
case T of
{named, <<"Nil"/utf8>>, <<""/utf8>>, <<"gleam"/utf8>>, []} ->
true;
_ ->
false
end.
-spec is_type_variable(lustre@cli@project:type()) -> boolean().
is_type_variable(T) ->
case T of
{variable, _} ->
true;
_ ->
false
end.
-spec is_compatible_flags_type(lustre@cli@project:type()) -> boolean().
is_compatible_flags_type(T) ->
is_nil_type(T) orelse is_type_variable(T).
-spec check_is_lustre_app(binary(), lustre@cli@project:module_()) -> {ok,
boolean()} |
{error, error()}.
check_is_lustre_app(Module_path, Module) ->
lustre@cli@utils:'try'(
gleam@dict:get(erlang:element(3, Module), <<"main"/utf8>>),
lustre@cli@utils:replace({main_missing, Module_path}),
fun(Main) ->
lustre@cli@utils:guard(
erlang:element(2, Main) /= [],
{main_incorrect_type,
Module_path,
{fn, erlang:element(2, Main), erlang:element(3, Main)}},
fun() -> case erlang:element(3, Main) of
{named,
<<"App"/utf8>>,
<<"lustre"/utf8>>,
<<"lustre"/utf8>>,
[Flags | _]} ->
case is_compatible_flags_type(Flags) of
true ->
{ok, true};
false ->
{error,
{main_bad_app_type,
Module_path,
erlang:element(3, Main)}}
end;
_ ->
{ok, false}
end end
)
end
).
-spec run() -> glint:command(nil).
run() ->
Description = <<"
"/utf8>>,
_pipe@2 = glint:command(
fun(Input) ->
{command_input, _, Flags, _} = Input,
_assert_subject = glint@flag:get_string(Flags, <<"host"/utf8>>),
{ok, Host} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"lustre/cli/dev"/utf8>>,
function => <<"run"/utf8>>,
line => 27})
end,
_assert_subject@1 = glint@flag:get_string(Flags, <<"port"/utf8>>),
{ok, Port} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"lustre/cli/dev"/utf8>>,
function => <<"run"/utf8>>,
line => 28})
end,
_assert_subject@2 = glint@flag:get_bool(
Flags,
<<"include-styles"/utf8>>
),
{ok, Include_styles} = case _assert_subject@2 of
{ok, _} -> _assert_subject@2;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@2,
module => <<"lustre/cli/dev"/utf8>>,
function => <<"run"/utf8>>,
line => 29})
end,
Script = (lustre@cli@step:new(
<<"Building your project"/utf8>>,
fun() ->
lustre@cli@step:'try'(
lustre@cli@project:interface(),
lustre@cli@utils:replace(build_error),
fun(Interface) ->
lustre@cli@step:'try'(
gleam@dict:get(
erlang:element(4, Interface),
erlang:element(2, Interface)
),
lustre@cli@utils:replace(
{module_missing,
erlang:element(2, Interface)}
),
fun(Module) ->
lustre@cli@step:'try'(
check_is_lustre_app(
erlang:element(2, Interface),
Module
),
fun gleam@function:identity/1,
fun(Is_app) ->
lustre@cli@step:done(
<<"✅ Project compiled successfully"/utf8>>,
fun() ->
lustre@cli@step:new(
<<"Creating the application entry point"/utf8>>,
fun() ->
Root = lustre@cli@project:root(
),
Tempdir = filepath:join(
Root,
<<"build/.lustre"/utf8>>
),
_ = simplifile:create_directory_all(
Tempdir
),
Entry = begin
_pipe = case Is_app of
true ->
<<" import { start } from '../dev/javascript/lustre/lustre.mjs';
import { main } from '../dev/javascript/${app_name}/${app_name}.mjs';
start(main(), ${container_id});
"/utf8>>;
false ->
<<" import { main } from '../dev/javascript/${app_name}/${app_name}.mjs';
main();
"/utf8>>
end,
_pipe@1 = gleam@string:replace(
_pipe,
<<"${app_name}"/utf8>>,
erlang:element(
2,
Interface
)
),
gleam@string:replace(
_pipe@1,
<<"${container_id}"/utf8>>,
<<"app"/utf8>>
)
end,
Html = index_html(
erlang:element(
2,
Interface
),
<<"app"/utf8>>,
Include_styles
),
_assert_subject@3 = simplifile:write(
<<Tempdir/binary,
"/entry.mjs"/utf8>>,
Entry
),
{ok, _} = case _assert_subject@3 of
{ok, _} -> _assert_subject@3;
_assert_fail@3 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@3,
module => <<"lustre/cli/dev"/utf8>>,
function => <<"run"/utf8>>,
line => 65}
)
end,
_assert_subject@4 = simplifile:write(
<<Tempdir/binary,
"/index.html"/utf8>>,
Html
),
{ok, _} = case _assert_subject@4 of
{ok, _} -> _assert_subject@4;
_assert_fail@4 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@4,
module => <<"lustre/cli/dev"/utf8>>,
function => <<"run"/utf8>>,
line => 66}
)
end,
lustre@cli@step:run(
lustre@cli@esbuild:bundle(
filepath:join(
Tempdir,
<<"entry.mjs"/utf8>>
),
filepath:join(
Tempdir,
<<"index.mjs"/utf8>>
),
false
),
lustre@cli@utils:map(
fun(Field@0) -> {bundle_error, Field@0} end
),
fun(_) ->
lustre@cli@step:run(
lustre@cli@esbuild:serve(
Host,
Port
),
lustre@cli@utils:map(
fun(Field@0) -> {bundle_error, Field@0} end
),
fun(_) ->
lustre@cli@step:return(
nil
)
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
)),
case lustre@cli@step:execute(Script) of
{ok, _} ->
nil;
{error, Error} ->
explain(Error)
end
end
),
_pipe@3 = glint:description(_pipe@2, Description),
_pipe@4 = glint:unnamed_args(_pipe@3, {eq_args, 0}),
_pipe@7 = glint:flag(
_pipe@4,
<<"host"/utf8>>,
begin
Description@1 = <<""/utf8>>,
Default = <<"0.0.0.0"/utf8>>,
_pipe@5 = glint@flag:string(),
_pipe@6 = glint@flag:default(_pipe@5, Default),
glint@flag:description(_pipe@6, Description@1)
end
),
_pipe@10 = glint:flag(
_pipe@7,
<<"port"/utf8>>,
begin
Description@2 = <<""/utf8>>,
Default@1 = <<"1234"/utf8>>,
_pipe@8 = glint@flag:string(),
_pipe@9 = glint@flag:default(_pipe@8, Default@1),
glint@flag:description(_pipe@9, Description@2)
end
),
glint:flag(
_pipe@10,
<<"include-styles"/utf8>>,
begin
Description@3 = <<""/utf8>>,
Default@2 = false,
_pipe@11 = glint@flag:bool(),
_pipe@12 = glint@flag:default(_pipe@11, Default@2),
glint@flag:description(_pipe@12, Description@3)
end
).