Packages
lustre
4.0.0-rc1
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
).