Current section
Files
Jump to
Current section
Files
src/sketch@css.erl
-module(sketch@css).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([compute_modules/1, generate_stylesheets/3, main/0]).
-export_type([module_/0, css/0]).
-type module_() :: {module,
binary(),
binary(),
gleam@option:option(glance:module_())}.
-type css() :: {css, list({binary(), binary()}), list(binary())}.
-spec recursive_modules_read(binary()) -> {ok, list(module_())} |
{error, simplifile:file_error()}.
recursive_modules_read(Dir) ->
gleam@result:map(
simplifile_erl:read_directory(Dir),
fun(Dir_content) ->
gleam@list:flatten(
(gleam@list:filter_map(
Dir_content,
fun(Path) ->
Path@1 = gleam@string:join([Dir, Path], <<"/"/utf8>>),
gleam@result:'try'(
simplifile_erl:is_directory(Path@1),
fun(Is_dir) ->
gleam@bool:guard(
Is_dir,
recursive_modules_read(Path@1),
fun() ->
gleam@result:map(
simplifile:read(Path@1),
fun(Content) ->
[{module, Path@1, Content, none}]
end
)
end
)
end
)
end
))
)
end
).
-spec parse_modules(list(module_())) -> list(module_()).
parse_modules(Modules) ->
gleam@list:filter_map(
Modules,
fun(Module) ->
gleam@result:map(
begin
_pipe = glance:module(erlang:element(3, Module)),
sketch@css@error:glance(_pipe)
end,
fun(Ast) -> erlang:setelement(4, Module, {some, Ast}) end
)
end
).
-spec select_css_files(list(module_()), binary()) -> list(module_()).
select_css_files(Modules, Interface) ->
gleam@list:filter(
Modules,
fun(Module) ->
not gleam_stdlib:contains_string(
erlang:element(2, Module),
Interface
)
andalso ((gleam@string:ends_with(
erlang:element(2, Module),
<<"_styles.gleam"/utf8>>
)
orelse gleam@string:ends_with(
erlang:element(2, Module),
<<"_css.gleam"/utf8>>
))
orelse gleam@string:ends_with(
erlang:element(2, Module),
<<"_sketch.gleam"/utf8>>
))
end
).
-spec find_sketch_imports(list(glance:definition(glance:import()))) -> {list(binary()),
list(binary()),
list({binary(), binary()})}.
find_sketch_imports(Imports) ->
Imports@1 = gleam@list:filter(
Imports,
fun(I) ->
erlang:element(2, erlang:element(3, I)) =:= <<"sketch"/utf8>>
end
),
Aliases = begin
_pipe = gleam@list:map(
Imports@1,
fun(I@1) -> case erlang:element(3, erlang:element(3, I@1)) of
none ->
erlang:element(2, erlang:element(3, I@1));
{some, {discarded, _}} ->
erlang:element(2, erlang:element(3, I@1));
{some, {named, S}} ->
S
end end
),
gleam@list:unique(_pipe)
end,
Exposed = (gleam@list:flat_map(
Imports@1,
fun(I@2) ->
gleam@list:filter_map(
erlang:element(5, erlang:element(3, I@2)),
fun(Value) ->
gleam@bool:guard(
erlang:element(2, Value) /= <<"class"/utf8>>,
{error, nil},
fun() ->
_pipe@1 = gleam@option:map(
erlang:element(3, Value),
fun(Field@0) -> {ok, Field@0} end
),
gleam@option:unwrap(
_pipe@1,
{ok, erlang:element(2, Value)}
)
end
)
end
)
end
)),
Properties = (gleam@list:flat_map(
Imports@1,
fun(I@3) ->
gleam@list:filter_map(
erlang:element(5, erlang:element(3, I@3)),
fun(Value@1) ->
gleam@bool:guard(
erlang:element(2, Value@1) =:= <<"class"/utf8>>,
{error, nil},
fun() ->
{ok,
{begin
_pipe@2 = erlang:element(3, Value@1),
gleam@option:unwrap(
_pipe@2,
erlang:element(2, Value@1)
)
end,
erlang:element(2, Value@1)}}
end
)
end
)
end
)),
{Aliases, Exposed, Properties}.
-spec keep_fn_call(glance:function_()) -> {ok,
{glance:expression(), list(glance:expression())}} |
{error, nil}.
keep_fn_call(Function) ->
case erlang:element(6, Function) of
[{expression, {call, Call, [{field, _, {list, Body, _}}]}}] ->
{ok, {Call, Body}};
_ ->
{error, nil}
end.
-spec keep_valid_class(list(binary()), list(binary()), glance:expression()) -> {ok,
nil} |
{error, nil}.
keep_valid_class(Imports, Exposed, Call) ->
case Call of
{variable, Fcall} ->
Is_class = not gleam@list:contains(Exposed, Fcall),
gleam@bool:guard(Is_class, {error, nil}, fun() -> {ok, nil} end);
{field_access, {variable, Module}, Fcall@1} ->
Not_class = Fcall@1 /= <<"class"/utf8>>,
Not_sketch_class = not gleam@list:contains(Imports, Module) orelse Not_class,
gleam@bool:guard(
Not_sketch_class,
{error, nil},
fun() -> {ok, nil} end
);
_ ->
{error, nil}
end.
-spec add_expressions({list({NSJ, list(NYG)}), NYB}, NSJ, list(NYG)) -> {list({NSJ,
list(NYG)}),
NYB}.
add_expressions(Results, Name, Expressions) ->
{Results@1, Medias} = Results,
{begin
_pipe = gleam@list:key_find(Results@1, Name),
_pipe@1 = gleam@result:unwrap(_pipe, []),
_pipe@2 = lists:append(_pipe@1, Expressions),
gleam@list:key_set(Results@1, Name, _pipe@2)
end,
Medias}.
-spec string_to_string(glance:expression()) -> binary().
string_to_string(Param) ->
case Param of
{string, M} ->
M;
{variable, V} ->
<<<<"var(--"/utf8,
(gleam@string:replace(V, <<"_"/utf8>>, <<"-"/utf8>>))/binary>>/binary,
")"/utf8>>;
_ ->
<<""/utf8>>
end.
-spec property_to_string(list(glance:field(glance:expression()))) -> {ok,
binary()} |
{error, nil}.
property_to_string(Param) ->
case Param of
[{field, none, {string, Param@1}}, {field, none, P}] ->
{ok,
<<<<<<<<" "/utf8, Param@1/binary>>/binary, ": "/utf8>>/binary,
(string_to_string(P))/binary>>/binary,
";"/utf8>>};
_ ->
{error, nil}
end.
-spec template_areas_to_string(list(glance:field(glance:expression()))) -> {ok,
binary()} |
{error, nil}.
template_areas_to_string(Param) ->
case Param of
[{field, none, {list, Content, _}}] ->
{ok,
<<<<" grid-template-areas:\n"/utf8,
(begin
_pipe = gleam@list:map(
Content,
fun string_to_string/1
),
_pipe@1 = gleam@list:map(
_pipe,
fun(A) ->
<<<<" \""/utf8, A/binary>>/binary,
"\""/utf8>>
end
),
gleam@string:join(_pipe@1, <<"\n"/utf8>>)
end)/binary>>/binary,
";"/utf8>>};
_ ->
{error, nil}
end.
-spec remove_file(binary()) -> binary().
remove_file(Dst_path) ->
_pipe = Dst_path,
_pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>),
_pipe@2 = lists:reverse(_pipe@1),
_pipe@3 = gleam@list:drop(_pipe@2, 1),
_pipe@4 = lists:reverse(_pipe@3),
gleam@string:join(_pipe@4, <<"/"/utf8>>).
-spec rewrite_pipe(glance:expression()) -> glance:expression().
rewrite_pipe(Expression) ->
case Expression of
{binary_operator, pipe, Left, Right} ->
case Right of
{call, F, Args} ->
{call, F, gleam@list:prepend(Args, {field, none, Left})};
{variable, V} ->
{call, {variable, V}, [{field, none, Left}]};
_ ->
Expression
end;
_ ->
Expression
end.
-spec select_composes(list({binary(), binary()}), list(glance:expression())) -> list(binary()).
select_composes(Properties, Expressions) ->
gleam@list:fold(
Expressions,
[],
fun(Classes, Expression) -> case rewrite_pipe(Expression) of
{call, {variable, V}, [{field, none, {call, {variable, T}, _}}]} ->
F = begin
_pipe = gleam@list:key_find(Properties, V),
gleam@result:unwrap(_pipe, <<""/utf8>>)
end,
gleam@bool:guard(
F /= <<"compose"/utf8>>,
Classes,
fun() ->
_pipe@1 = gleam@string:replace(
T,
<<"_"/utf8>>,
<<"-"/utf8>>
),
gleam@list:prepend(Classes, _pipe@1)
end
);
{call,
{variable, V},
[{field, none, {call, {field_access, _, T}, _}}]} ->
F = begin
_pipe = gleam@list:key_find(Properties, V),
gleam@result:unwrap(_pipe, <<""/utf8>>)
end,
gleam@bool:guard(
F /= <<"compose"/utf8>>,
Classes,
fun() ->
_pipe@1 = gleam@string:replace(
T,
<<"_"/utf8>>,
<<"-"/utf8>>
),
gleam@list:prepend(Classes, _pipe@1)
end
);
{call,
{field_access, _, F@1},
[{field, none, {call, {variable, T@1}, _}}]} ->
gleam@bool:guard(
F@1 /= <<"compose"/utf8>>,
Classes,
fun() ->
_pipe@2 = gleam@string:replace(
T@1,
<<"_"/utf8>>,
<<"-"/utf8>>
),
gleam@list:prepend(Classes, _pipe@2)
end
);
{call,
{field_access, _, F@1},
[{field, none, {call, {field_access, _, T@1}, _}}]} ->
gleam@bool:guard(
F@1 /= <<"compose"/utf8>>,
Classes,
fun() ->
_pipe@2 = gleam@string:replace(
T@1,
<<"_"/utf8>>,
<<"-"/utf8>>
),
gleam@list:prepend(Classes, _pipe@2)
end
);
_ ->
Classes
end end
).
-spec size_to_string(glance:expression()) -> binary().
size_to_string(Value) ->
case rewrite_pipe(Value) of
{int, I} ->
I;
{float, F} ->
F;
_ ->
<<""/utf8>>
end.
-spec property_body(list(glance:field(glance:expression()))) -> binary().
property_body(Param) ->
case Param of
[{field, none, P}] ->
case rewrite_pipe(P) of
{call,
{field_access, {variable, _}, Size},
[{field, none, Value}]} ->
<<(size_to_string(Value))/binary, Size/binary>>;
{call, {variable, Size@1}, [{field, none, Value@1}]} ->
<<(size_to_string(Value@1))/binary, Size@1/binary>>;
P@1 ->
string_to_string(P@1)
end;
_ ->
gleam@string:inspect(Param)
end.
-spec media_to_string(list({binary(), binary()}), glance:expression()) -> {ok,
binary()} |
{error, nil}.
media_to_string(Properties, Media) ->
case rewrite_pipe(Media) of
{call, {variable, Media@1}, P} ->
gleam@result:'try'(
gleam@list:key_find(Properties, Media@1),
fun(Name) ->
gleam@bool:guard(
Name /= <<"max_width"/utf8>>,
{error, nil},
fun() ->
{ok,
<<"(max-width: "/utf8,
(property_body(P))/binary>>}
end
)
end
);
{call, {field_access, {variable, _}, Media@2}, P@1} ->
case Media@2 of
<<"max_width"/utf8>> ->
{ok,
<<<<<<<<"("/utf8,
(gleam@string:replace(
Media@2,
<<"_"/utf8>>,
<<"-"/utf8>>
))/binary>>/binary,
": "/utf8>>/binary,
(property_body(P@1))/binary>>/binary,
")"/utf8>>};
<<"min_width"/utf8>> ->
{ok,
<<<<<<<<"("/utf8,
(gleam@string:replace(
Media@2,
<<"_"/utf8>>,
<<"-"/utf8>>
))/binary>>/binary,
": "/utf8>>/binary,
(property_body(P@1))/binary>>/binary,
")"/utf8>>};
<<"max_height"/utf8>> ->
{ok,
<<<<<<<<"("/utf8,
(gleam@string:replace(
Media@2,
<<"_"/utf8>>,
<<"-"/utf8>>
))/binary>>/binary,
": "/utf8>>/binary,
(property_body(P@1))/binary>>/binary,
")"/utf8>>};
<<"min_height"/utf8>> ->
{ok,
<<<<<<<<"("/utf8,
(gleam@string:replace(
Media@2,
<<"_"/utf8>>,
<<"-"/utf8>>
))/binary>>/binary,
": "/utf8>>/binary,
(property_body(P@1))/binary>>/binary,
")"/utf8>>};
<<"not"/utf8>> ->
case P@1 of
[{field, none, M}] ->
gleam@result:'try'(
media_to_string(Properties, M),
fun(Left) ->
{ok,
<<<<"not("/utf8, Left/binary>>/binary,
")"/utf8>>}
end
);
_ ->
{error, nil}
end;
<<"and"/utf8>> ->
case P@1 of
[{field, none, M@1}, {field, none, N}] ->
gleam@result:'try'(
media_to_string(Properties, M@1),
fun(Left@1) ->
gleam@result:'try'(
media_to_string(Properties, N),
fun(Right) ->
{ok,
<<<<<<<<Left@1/binary,
" "/utf8>>/binary,
Media@2/binary>>/binary,
" "/utf8>>/binary,
Right/binary>>}
end
)
end
);
_ ->
{error, nil}
end;
<<"or"/utf8>> ->
case P@1 of
[{field, none, M@1}, {field, none, N}] ->
gleam@result:'try'(
media_to_string(Properties, M@1),
fun(Left@1) ->
gleam@result:'try'(
media_to_string(Properties, N),
fun(Right) ->
{ok,
<<<<<<<<Left@1/binary,
" "/utf8>>/binary,
Media@2/binary>>/binary,
" "/utf8>>/binary,
Right/binary>>}
end
)
end
);
_ ->
{error, nil}
end;
<<"landscape"/utf8>> ->
{ok,
<<<<"(orientation: "/utf8, Media@2/binary>>/binary,
")"/utf8>>};
<<"portait"/utf8>> ->
{ok,
<<<<"(orientation: "/utf8, Media@2/binary>>/binary,
")"/utf8>>};
<<"dark_theme"/utf8>> ->
{ok,
<<<<"(prefers-color-scheme: "/utf8,
(gleam@string:replace(
Media@2,
<<"_"/utf8>>,
<<"-"/utf8>>
))/binary>>/binary,
")"/utf8>>};
<<"light_theme"/utf8>> ->
{ok,
<<<<"(prefers-color-scheme: "/utf8,
(gleam@string:replace(
Media@2,
<<"_"/utf8>>,
<<"-"/utf8>>
))/binary>>/binary,
")"/utf8>>};
_ ->
{error, nil}
end;
_ ->
{error, nil}
end.
-spec css_property(binary(), list(glance:field(glance:expression()))) -> {ok,
binary()} |
{error, any()}.
css_property(Name, Param) ->
Prop = begin
_pipe = gleam@string:split(Name, <<"-"/utf8>>),
_pipe@1 = gleam@list:filter(_pipe, fun(A) -> A /= <<""/utf8>> end),
gleam@string:join(_pipe@1, <<"-"/utf8>>)
end,
Body = property_body(Param),
{ok,
<<<<<<<<" "/utf8, Prop/binary>>/binary, ": "/utf8>>/binary,
Body/binary>>/binary,
";"/utf8>>}.
-spec dst_flag() -> glint:flag(binary()).
dst_flag() ->
_pipe = glint:string_flag(<<"dest"/utf8>>),
_pipe@1 = glint:flag_default(_pipe, <<"styles"/utf8>>),
glint:flag_help(
_pipe@1,
<<"Define the directory in which styles should be output."/utf8>>
).
-spec src_flag() -> glint:flag(binary()).
src_flag() ->
_pipe = glint:string_flag(<<"src"/utf8>>),
_pipe@1 = glint:flag_default(_pipe, <<"src"/utf8>>),
glint:flag_help(
_pipe@1,
<<"Define the directory in which styles should be read. Default to src."/utf8>>
).
-spec interface_flag() -> glint:flag(binary()).
interface_flag() ->
_pipe = glint:string_flag(<<"interface"/utf8>>),
_pipe@1 = glint:flag_default(_pipe, <<"src/sketch/styles"/utf8>>),
glint:flag_help(
_pipe@1,
<<"Define the directory in which interfaces should be output. Default to src/sketch/styles."/utf8>>
).
-spec skip_not_css_properties(binary()) -> {ok, binary()} | {error, nil}.
skip_not_css_properties(Name) ->
case gleam@list:contains(
[<<"compose"/utf8>>, <<"none"/utf8>>, <<"media"/utf8>>],
Name
)
orelse gleam@result:is_ok(
gleam@list:key_find(
[{<<"placeholder"/utf8>>, <<"::placeholder"/utf8>>},
{<<"hover"/utf8>>, <<":hover"/utf8>>},
{<<"active"/utf8>>, <<":active"/utf8>>},
{<<"focus"/utf8>>, <<":focus"/utf8>>},
{<<"focus_visible"/utf8>>, <<":focus_visible"/utf8>>},
{<<"focus_within"/utf8>>, <<":focus-within"/utf8>>},
{<<"enabled"/utf8>>, <<":enabled"/utf8>>},
{<<"disabled"/utf8>>, <<":disabled"/utf8>>},
{<<"read_only"/utf8>>, <<":read-only"/utf8>>},
{<<"read_write"/utf8>>, <<":read-write"/utf8>>},
{<<"checked"/utf8>>, <<":checked"/utf8>>},
{<<"blank"/utf8>>, <<":blank"/utf8>>},
{<<"valid"/utf8>>, <<":valid"/utf8>>},
{<<"invalid"/utf8>>, <<":invalid"/utf8>>},
{<<"required"/utf8>>, <<":required"/utf8>>},
{<<"optional"/utf8>>, <<":optional"/utf8>>},
{<<"link"/utf8>>, <<":link"/utf8>>},
{<<"visited"/utf8>>, <<":visited"/utf8>>},
{<<"target"/utf8>>, <<":target"/utf8>>},
{<<"nth_child"/utf8>>, <<":nth-child"/utf8>>},
{<<"nth_last_child"/utf8>>, <<":nth-last-child"/utf8>>},
{<<"nth_of_type"/utf8>>, <<":nth-of-type"/utf8>>},
{<<"nth_last_of_type"/utf8>>, <<":nth-last-of-type"/utf8>>},
{<<"first_child"/utf8>>, <<":first-child"/utf8>>},
{<<"last_child"/utf8>>, <<":last-child"/utf8>>},
{<<"only_child"/utf8>>, <<":only-child"/utf8>>},
{<<"first_of_type"/utf8>>, <<":first-of-type"/utf8>>},
{<<"last_of_type"/utf8>>, <<":last-of-type"/utf8>>},
{<<"only_of_type"/utf8>>, <<":only-of-type"/utf8>>},
{<<"pseudo_selector"/utf8>>, <<":pseudo-selector"/utf8>>}],
Name
)
) of
true ->
{error, nil};
false ->
{ok, Name}
end.
-spec compute_css_property(binary(), list(glance:field(glance:expression()))) -> {ok,
binary()} |
{error, nil}.
compute_css_property(Name, Param) ->
gleam@result:'try'(
skip_not_css_properties(Name),
fun(Name@1) ->
Is_property = Name@1 =:= <<"property"/utf8>>,
Is_areas = Name@1 =:= <<"grid_template_areas"/utf8>>,
gleam@bool:guard(
Is_property,
property_to_string(Param),
fun() ->
gleam@bool:guard(
Is_areas,
template_areas_to_string(Param),
fun() -> css_property(Name@1, Param) end
)
end
)
end
).
-spec class_body(
list(binary()),
list({binary(), binary()}),
list(glance:expression())
) -> list(binary()).
class_body(Imports, Properties, Body) ->
gleam@list:filter_map(Body, fun(Property) -> case Property of
{call, {variable, Name}, Param} ->
gleam@result:'try'(
gleam@list:key_find(Properties, Name),
fun(Name@1) -> compute_css_property(Name@1, Param) end
);
{call, {field_access, {variable, Module_name}, Name@2}, Param@1} ->
Is_sketch = gleam@list:contains(Imports, Module_name),
gleam@bool:guard(
not Is_sketch,
{error, nil},
fun() -> compute_css_property(Name@2, Param@1) end
);
_ ->
{error, nil}
end end).
-spec compile_classes(
list(binary()),
list({binary(), binary()}),
binary(),
list({binary(), list(glance:expression())}),
binary()
) -> binary().
compile_classes(Imports, Properties, Name, All_classes, Prefix) ->
_pipe@2 = gleam@list:map(
All_classes,
fun(Class) ->
{Selector, Body} = Class,
Body@1 = begin
_pipe = class_body(Imports, Properties, Body),
_pipe@1 = gleam@list:map(
_pipe,
fun(S) -> <<Prefix/binary, S/binary>> end
),
gleam@string:join(_pipe@1, <<"\n"/utf8>>)
end,
Head = <<<<<<<<Prefix/binary, "."/utf8>>/binary, Name/binary>>/binary,
Selector/binary>>/binary,
" {\n"/utf8>>,
<<<<<<<<Head/binary, Body@1/binary>>/binary, "\n"/utf8>>/binary,
Prefix/binary>>/binary,
"}"/utf8>>
end
),
gleam@string:join(_pipe@2, <<"\n\n"/utf8>>).
-spec add_media(
list(binary()),
list({binary(), binary()}),
{list({binary(), list(glance:expression())}),
list({binary(), list({binary(), list(glance:expression())})})},
list(glance:field(glance:expression()))
) -> fun(() -> {ok,
{list({binary(), list(glance:expression())}),
list({binary(), list({binary(), list(glance:expression())})})}} |
{error, nil}).
add_media(Imports, Properties, Results, Param) ->
fun() ->
{Results@1, Medias} = Results,
case Param of
[{field, none, Media}, {field, none, {list, Content, _}}] ->
gleam@result:'try'(
media_to_string(Properties, Media),
fun(Media@1) ->
{Content@1, _} = split_body(
Imports,
Properties,
Content
),
{ok,
{Results@1,
gleam@list:key_set(Medias, Media@1, Content@1)}}
end
);
_ ->
{ok, {Results@1, Medias}}
end
end.
-spec split_body(
list(binary()),
list({binary(), binary()}),
list(glance:expression())
) -> {list({binary(), list(glance:expression())}),
list({binary(), list({binary(), list(glance:expression())})})}.
split_body(Imports, Properties, Body) ->
gleam@list:fold(Body, {[], []}, fun(Results, Item) -> _pipe = case Item of
{call, {variable, Name}, Param} ->
push_in_subclass(
Imports,
Results,
Item,
Name,
Param,
Properties,
true
);
{call, {field_access, {variable, Module_name}, Name@1}, Param@1} ->
Is_sketch = gleam@list:contains(Imports, Module_name),
gleam@bool:guard(
not Is_sketch,
{error, nil},
fun() ->
push_in_subclass(
Imports,
Results,
Item,
Name@1,
Param@1,
Properties,
false
)
end
);
_ ->
{error, nil}
end,
gleam@result:unwrap(_pipe, Results) end).
-spec push_in_subclass(
list(binary()),
{list({binary(), list(glance:expression())}),
list({binary(), list({binary(), list(glance:expression())})})},
glance:expression(),
binary(),
list(glance:field(glance:expression())),
list({binary(), binary()}),
boolean()
) -> {ok,
{list({binary(), list(glance:expression())}),
list({binary(), list({binary(), list(glance:expression())})})}} |
{error, nil}.
push_in_subclass(Imports, Results, Item, Name, Param, Properties, Unqualified) ->
Is_media = Name =:= <<"media"/utf8>>,
Add_media = add_media(Imports, Properties, Results, Param),
gleam@bool:lazy_guard(
Is_media,
Add_media,
fun() -> gleam@result:'try'(case Unqualified of
true ->
gleam@list:key_find(Properties, Name);
false ->
{ok, Name}
end, fun(Name@1) ->
Is_pseudo = gleam@list:key_find(
[{<<"placeholder"/utf8>>, <<"::placeholder"/utf8>>},
{<<"hover"/utf8>>, <<":hover"/utf8>>},
{<<"active"/utf8>>, <<":active"/utf8>>},
{<<"focus"/utf8>>, <<":focus"/utf8>>},
{<<"focus_visible"/utf8>>,
<<":focus_visible"/utf8>>},
{<<"focus_within"/utf8>>, <<":focus-within"/utf8>>},
{<<"enabled"/utf8>>, <<":enabled"/utf8>>},
{<<"disabled"/utf8>>, <<":disabled"/utf8>>},
{<<"read_only"/utf8>>, <<":read-only"/utf8>>},
{<<"read_write"/utf8>>, <<":read-write"/utf8>>},
{<<"checked"/utf8>>, <<":checked"/utf8>>},
{<<"blank"/utf8>>, <<":blank"/utf8>>},
{<<"valid"/utf8>>, <<":valid"/utf8>>},
{<<"invalid"/utf8>>, <<":invalid"/utf8>>},
{<<"required"/utf8>>, <<":required"/utf8>>},
{<<"optional"/utf8>>, <<":optional"/utf8>>},
{<<"link"/utf8>>, <<":link"/utf8>>},
{<<"visited"/utf8>>, <<":visited"/utf8>>},
{<<"target"/utf8>>, <<":target"/utf8>>},
{<<"nth_child"/utf8>>, <<":nth-child"/utf8>>},
{<<"nth_last_child"/utf8>>,
<<":nth-last-child"/utf8>>},
{<<"nth_of_type"/utf8>>, <<":nth-of-type"/utf8>>},
{<<"nth_last_of_type"/utf8>>,
<<":nth-last-of-type"/utf8>>},
{<<"first_child"/utf8>>, <<":first-child"/utf8>>},
{<<"last_child"/utf8>>, <<":last-child"/utf8>>},
{<<"only_child"/utf8>>, <<":only-child"/utf8>>},
{<<"first_of_type"/utf8>>,
<<":first-of-type"/utf8>>},
{<<"last_of_type"/utf8>>, <<":last-of-type"/utf8>>},
{<<"only_of_type"/utf8>>, <<":only-of-type"/utf8>>},
{<<"pseudo_selector"/utf8>>,
<<":pseudo-selector"/utf8>>}],
Name@1
),
Add_body = fun() ->
{ok, add_expressions(Results, <<""/utf8>>, [Item])}
end,
gleam@bool:lazy_guard(
gleam@result:is_error(Is_pseudo),
Add_body,
fun() ->
{ok, Name@2} = case Is_pseudo of
{ok, _} -> Is_pseudo;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"sketch/css"/utf8>>,
function => <<"push_in_subclass"/utf8>>,
line => 250})
end,
case {Name@2, Param} of
{<<":pseudo-selector"/utf8>>,
[{field, none, {string, Selector}},
{field, none, {list, Expressions, _}}]} ->
{ok,
add_expressions(
Results,
Selector,
Expressions
)};
{<<":nth-child"/utf8>>,
[{field, none, {string, Selector@1}},
{field, none, {list, Expressions@1, _}}]} ->
{ok,
add_expressions(
Results,
<<<<<<Name@2/binary, "("/utf8>>/binary,
Selector@1/binary>>/binary,
")"/utf8>>,
Expressions@1
)};
{<<":nth-last-child"/utf8>>,
[{field, none, {string, Selector@2}},
{field, none, {list, Expressions@2, _}}]} ->
{ok,
add_expressions(
Results,
<<<<<<Name@2/binary, "("/utf8>>/binary,
Selector@2/binary>>/binary,
")"/utf8>>,
Expressions@2
)};
{<<":nth-of-type"/utf8>>,
[{field, none, {string, Selector@3}},
{field, none, {list, Expressions@3, _}}]} ->
{ok,
add_expressions(
Results,
<<<<<<Name@2/binary, "("/utf8>>/binary,
Selector@3/binary>>/binary,
")"/utf8>>,
Expressions@3
)};
{<<":nth-last-of-type"/utf8>>,
[{field, none, {string, Selector@4}},
{field, none, {list, Expressions@4, _}}]} ->
{ok,
add_expressions(
Results,
<<<<<<Name@2/binary, "("/utf8>>/binary,
Selector@4/binary>>/binary,
")"/utf8>>,
Expressions@4
)};
{_, [{field, none, {list, Expressions@5, _}}]} ->
{ok,
add_expressions(
Results,
Name@2,
Expressions@5
)};
{_, _} ->
{error, nil}
end
end
)
end) end
).
-spec function_definition(
list(binary()),
list(binary()),
list({binary(), binary()}),
glance:function_()
) -> {ok, {binary(), binary(), binary()}} | {error, nil}.
function_definition(Imports, Exposed, Properties, Function) ->
gleam@result:'try'(
keep_fn_call(Function),
fun(_use0) ->
{Call, Body} = _use0,
gleam@result:'try'(
keep_valid_class(Imports, Exposed, Call),
fun(_) ->
Name = gleam@string:replace(
erlang:element(2, Function),
<<"_"/utf8>>,
<<"-"/utf8>>
),
{All_classes, Medias} = split_body(
Imports,
Properties,
Body
),
Body@1 = compile_classes(
Imports,
Properties,
Name,
All_classes,
<<""/utf8>>
),
Composes = begin
_pipe = All_classes,
_pipe@1 = gleam@list:flat_map(
_pipe,
fun gleam@pair:second/1
),
select_composes(Properties, _pipe@1)
end,
Body@3 = begin
Medias@1 = begin
_pipe@2 = gleam@list:map(
Medias,
fun(Media) ->
{Media@1, All_classes@1} = Media,
Body@2 = compile_classes(
Imports,
Properties,
Name,
All_classes@1,
<<" "/utf8>>
),
Head = <<<<"@media "/utf8, Media@1/binary>>/binary,
" {\n"/utf8>>,
<<<<Head/binary, Body@2/binary>>/binary,
"\n}"/utf8>>
end
),
gleam@string:join(_pipe@2, <<"\n\n"/utf8>>)
end,
gleam@bool:guard(
Medias@1 =:= <<""/utf8>>,
Body@1,
fun() ->
<<<<Body@1/binary, "\n\n"/utf8>>/binary,
Medias@1/binary>>
end
)
end,
Name@1 = begin
_pipe@3 = [Name | Composes],
_pipe@4 = lists:reverse(_pipe@3),
gleam@string:join(_pipe@4, <<" "/utf8>>)
end,
{ok, {erlang:element(2, Function), Name@1, Body@3}}
end
)
end
).
-spec parse_css_modules(list(module_()), list(module_())) -> list({module_(),
css()}).
parse_css_modules(Styles_modules, _) ->
gleam@list:filter_map(
Styles_modules,
fun(Styles_module) -> case erlang:element(4, Styles_module) of
none ->
{error, nil};
{some, Ast} ->
{ok,
({Styles_module,
begin
{Imports, Exposed, Properties} = find_sketch_imports(
erlang:element(2, Ast)
),
gleam@list:fold(
erlang:element(6, Ast),
{css, [], []},
fun(Css, Function) ->
_pipe = function_definition(
Imports,
Exposed,
Properties,
erlang:element(3, Function)
),
_pipe@1 = gleam@result:map(
_pipe,
fun(Content) ->
Classes = gleam@list:key_set(
erlang:element(2, Css),
erlang:element(1, Content),
erlang:element(2, Content)
),
Content@1 = gleam@list:prepend(
erlang:element(3, Css),
erlang:element(3, Content)
),
{css, Classes, Content@1}
end
),
gleam@result:unwrap(_pipe@1, Css)
end
)
end})}
end end
).
-spec compute_modules(list(module_())) -> list({module_(), css()}).
compute_modules(Modules) ->
Styles_modules = parse_modules(Modules),
parse_css_modules(Styles_modules, Modules).
-spec compute_styles_modules(list(module_()), binary()) -> list({module_(),
css()}).
compute_styles_modules(Modules, Interface) ->
Modules@1 = parse_modules(Modules),
Styles_modules = select_css_files(Modules@1, Interface),
parse_css_modules(Styles_modules, Modules@1).
-spec generate_stylesheets(binary(), binary(), binary()) -> {ok, nil} |
{error, sketch@css@error:error()}.
generate_stylesheets(Src, Dst, Src_interfaces) ->
gleam@result:'try'(
begin
_pipe = simplifile_erl:is_directory(Src),
sketch@css@error:simplifile(_pipe)
end,
fun(Is_dir) ->
gleam@bool:guard(
not Is_dir,
sketch@css@error:not_a_directory(Src),
fun() ->
gleam@result:map(
begin
_pipe@1 = recursive_modules_read(Src),
sketch@css@error:simplifile(_pipe@1)
end,
fun(Modules) ->
Css_modules = compute_styles_modules(
Modules,
Src_interfaces
),
_ = simplifile:create_directory_all(Dst),
gleam@list:each(
Css_modules,
fun(_use0) ->
{Module, Css_module} = _use0,
Dst_path = gleam@string:replace(
erlang:element(2, Module),
Src,
Dst
),
Dst_path@1 = gleam@string:replace(
Dst_path,
<<".gleam"/utf8>>,
<<".css"/utf8>>
),
Parent_dst_path = remove_file(Dst_path@1),
_ = simplifile:create_directory_all(
Parent_dst_path
),
_ = simplifile:write(
Dst_path@1,
gleam@string:join(
erlang:element(3, Css_module),
<<"\n\n"/utf8>>
)
),
Src_styles_path = gleam@string:replace(
erlang:element(2, Module),
Src,
Src_interfaces
),
Parent_src_styles_path = remove_file(
Src_styles_path
),
_ = simplifile:create_directory_all(
Parent_src_styles_path
),
_ = simplifile:write(
Src_styles_path,
begin
_pipe@2 = gleam@list:map(
erlang:element(2, Css_module),
fun(C) ->
<<<<<<<<"pub const "/utf8,
(erlang:element(
1,
C
))/binary>>/binary,
" = \""/utf8>>/binary,
(erlang:element(
2,
C
))/binary>>/binary,
"\""/utf8>>
end
),
gleam@string:join(
_pipe@2,
<<"\n\n"/utf8>>
)
end
)
end
)
end
)
end
)
end
).
-spec css() -> glint:command(nil).
css() ->
glint:command_help(
<<"Generate CSS for your gleam_styles.gleam files!"/utf8>>,
fun() ->
glint:flag(
dst_flag(),
fun(Dst) ->
glint:flag(
src_flag(),
fun(Src) ->
glint:flag(
interface_flag(),
fun(Interface) ->
glint:command(
fun(_, _, Flags) ->
_assert_subject = Dst(Flags),
{ok, Dst@1} = 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 => <<"sketch/css"/utf8>>,
function => <<"css"/utf8>>,
line => 584}
)
end,
_assert_subject@1 = Src(Flags),
{ok, Src@1} = 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 => <<"sketch/css"/utf8>>,
function => <<"css"/utf8>>,
line => 585}
)
end,
_assert_subject@2 = Interface(Flags),
{ok, Interface@1} = 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 => <<"sketch/css"/utf8>>,
function => <<"css"/utf8>>,
line => 586}
)
end,
_assert_subject@3 = simplifile:current_directory(
),
{ok, Cwd} = 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 => <<"sketch/css"/utf8>>,
function => <<"css"/utf8>>,
line => 587}
)
end,
Src@2 = gleam@string:join(
[Cwd, Src@1],
<<"/"/utf8>>
),
Dst@2 = gleam@string:join(
[Cwd, Dst@1],
<<"/"/utf8>>
),
Interface@2 = gleam@string:join(
[Cwd, Interface@1],
<<"/"/utf8>>
),
gleam@io:println(
<<"Compiling Gleam styles files in "/utf8,
Src@2/binary>>
),
gleam@io:println(
<<"Writing CSS files to "/utf8,
Dst@2/binary>>
),
gleam@io:println(
<<"Writing interfaces files to "/utf8,
Interface@2/binary>>
),
_ = generate_stylesheets(
Src@2,
Dst@2,
Interface@2
),
gleam@io:println(<<"Done!"/utf8>>),
nil
end
)
end
)
end
)
end
)
end
).
-spec main() -> nil.
main() ->
_pipe = glint:new(),
_pipe@1 = glint:with_name(_pipe, <<"Sketch CSS"/utf8>>),
_pipe@2 = glint:pretty_help(_pipe@1, glint:default_pretty_help()),
_pipe@3 = glint:add(_pipe@2, [<<"generate"/utf8>>], css()),
glint:run(_pipe@3, erlang:element(4, argv:load())).