Packages
lustre
4.3.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@internals@patch.erl
-module(lustre@internals@patch).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([attribute_diff_to_json/2, attributes/2, is_empty_element_diff/1, element_diff_to_json/1, patch_to_json/1, elements/2]).
-export_type([patch/1, element_diff/1, attribute_diff/1]).
-type patch(ODI) :: {diff, element_diff(ODI)} |
{emit, binary(), gleam@json:json()} |
{init, list(binary()), lustre@internals@vdom:element(ODI)}.
-type element_diff(ODJ) :: {element_diff,
gleam@dict:dict(binary(), lustre@internals@vdom:element(ODJ)),
gleam@set:set(binary()),
gleam@dict:dict(binary(), attribute_diff(ODJ)),
gleam@dict:dict(binary(), fun((gleam@dynamic:dynamic_()) -> {ok, ODJ} |
{error, list(gleam@dynamic:decode_error())}))}.
-type attribute_diff(ODK) :: {attribute_diff,
gleam@set:set(lustre@internals@vdom:attribute(ODK)),
gleam@set:set(binary()),
gleam@dict:dict(binary(), fun((gleam@dynamic:dynamic_()) -> {ok, ODK} |
{error, list(gleam@dynamic:decode_error())}))}.
-spec do_attribute(
attribute_diff(OEJ),
binary(),
{ok, lustre@internals@vdom:attribute(OEJ)} | {error, nil},
{ok, lustre@internals@vdom:attribute(OEJ)} | {error, nil}
) -> attribute_diff(OEJ).
do_attribute(Diff, Key, Old, New) ->
case {Old, New} of
{{error, _}, {error, _}} ->
Diff;
{{ok, Old@1}, {ok, {event, Name, Handler} = New@1}} when Old@1 =:= New@1 ->
erlang:setelement(
4,
Diff,
gleam@dict:insert(erlang:element(4, Diff), Name, Handler)
);
{{ok, Old@2}, {ok, New@2}} when Old@2 =:= New@2 ->
Diff;
{{ok, _}, {error, _}} ->
erlang:setelement(
3,
Diff,
gleam@set:insert(erlang:element(3, Diff), Key)
);
{_, {ok, {event, Name@1, Handler@1} = New@3}} ->
erlang:setelement(
4,
erlang:setelement(
2,
Diff,
gleam@set:insert(erlang:element(2, Diff), New@3)
),
gleam@dict:insert(erlang:element(4, Diff), Name@1, Handler@1)
);
{_, {ok, New@4}} ->
erlang:setelement(
2,
Diff,
gleam@set:insert(erlang:element(2, Diff), New@4)
)
end.
-spec do_key_sort(list(binary()), list(binary())) -> gleam@order:order().
do_key_sort(Xs, Ys) ->
case {Xs, Ys} of
{[], []} ->
eq;
{[], _} ->
lt;
{_, []} ->
gt;
{[<<"-"/utf8>> | Xs@1], [<<"-"/utf8>> | Ys@1]} ->
do_key_sort(Xs@1, Ys@1);
{[X | Xs@2], [Y | Ys@2]} ->
_assert_subject = gleam@int:parse(X),
{ok, X@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 => <<"lustre/internals/patch"/utf8>>,
function => <<"do_key_sort"/utf8>>,
line => 298})
end,
_assert_subject@1 = gleam@int:parse(Y),
{ok, Y@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 => <<"lustre/internals/patch"/utf8>>,
function => <<"do_key_sort"/utf8>>,
line => 299})
end,
case gleam@int:compare(X@1, Y@1) of
eq ->
do_key_sort(Xs@2, Ys@2);
Order ->
Order
end
end.
-spec key_sort(binary(), binary()) -> gleam@order:order().
key_sort(X, Y) ->
do_key_sort(
gleam@string:split(X, <<"-"/utf8>>),
gleam@string:split(Y, <<"-"/utf8>>)
).
-spec attribute_diff_to_json(attribute_diff(any()), binary()) -> gleam@json:json().
attribute_diff_to_json(Diff, Key) ->
gleam@json:preprocessed_array(
[gleam@json:preprocessed_array(
(gleam@set:fold(
erlang:element(2, Diff),
[],
fun(Array, Attr) ->
case lustre@internals@vdom:attribute_to_json(Attr, Key) of
{ok, Json} ->
[Json | Array];
{error, _} ->
Array
end
end
))
),
gleam@json:preprocessed_array(
(gleam@set:fold(
erlang:element(3, Diff),
[],
fun(Array@1, Key@1) ->
[gleam@json:string(Key@1) | Array@1]
end
))
)]
).
-spec zip(list(OFA), list(OFA)) -> list({gleam@option:option(OFA),
gleam@option:option(OFA)}).
zip(Xs, Ys) ->
case {Xs, Ys} of
{[], []} ->
[];
{[X | Xs@1], [Y | Ys@1]} ->
[{{some, X}, {some, Y}} | zip(Xs@1, Ys@1)];
{[X@1 | Xs@2], []} ->
[{{some, X@1}, none} | zip(Xs@2, [])];
{[], [Y@1 | Ys@2]} ->
[{none, {some, Y@1}} | zip([], Ys@2)]
end.
-spec attribute_dict(list(lustre@internals@vdom:attribute(OFG))) -> gleam@dict:dict(binary(), lustre@internals@vdom:attribute(OFG)).
attribute_dict(Attributes) ->
gleam@list:fold(
Attributes,
gleam@dict:new(),
fun(Dict, Attr) -> case Attr of
{attribute, <<"class"/utf8>>, Value, _} ->
case gleam@dict:get(Dict, <<"class"/utf8>>) of
{ok, {attribute, _, Classes, _}} ->
Classes@1 = gleam@dynamic:from(
<<<<(gleam@dynamic:unsafe_coerce(Classes))/binary,
" "/utf8>>/binary,
(gleam@dynamic:unsafe_coerce(Value))/binary>>
),
gleam@dict:insert(
Dict,
<<"class"/utf8>>,
{attribute, <<"class"/utf8>>, Classes@1, false}
);
{ok, _} ->
gleam@dict:insert(Dict, <<"class"/utf8>>, Attr);
{error, _} ->
gleam@dict:insert(Dict, <<"class"/utf8>>, Attr)
end;
{attribute, <<"style"/utf8>>, Value@1, _} ->
case gleam@dict:get(Dict, <<"style"/utf8>>) of
{ok, {attribute, _, Styles, _}} ->
Styles@1 = gleam@dynamic:from(
lists:append(
gleam@dynamic:unsafe_coerce(Styles),
gleam@dynamic:unsafe_coerce(Value@1)
)
),
gleam@dict:insert(
Dict,
<<"style"/utf8>>,
{attribute, <<"style"/utf8>>, Styles@1, false}
);
{ok, _} ->
gleam@dict:insert(Dict, <<"class"/utf8>>, Attr);
{error, _} ->
gleam@dict:insert(Dict, <<"class"/utf8>>, Attr)
end;
{attribute, Key, _, _} ->
gleam@dict:insert(Dict, Key, Attr);
{event, Key@1, _} ->
gleam@dict:insert(Dict, Key@1, Attr)
end end
).
-spec attributes(
list(lustre@internals@vdom:attribute(OED)),
list(lustre@internals@vdom:attribute(OED))
) -> attribute_diff(OED).
attributes(Old, New) ->
Old@1 = attribute_dict(Old),
New@1 = attribute_dict(New),
Init = {attribute_diff, gleam@set:new(), gleam@set:new(), gleam@dict:new()},
{Diff@2, New@4} = (gleam@dict:fold(
Old@1,
{Init, New@1},
fun(_use0, Key, Attr) ->
{Diff, New@2} = _use0,
New_attr = gleam@dict:get(New@2, Key),
Diff@1 = do_attribute(Diff, Key, {ok, Attr}, New_attr),
New@3 = gleam@dict:delete(New@2, Key),
{Diff@1, New@3}
end
)),
gleam@dict:fold(
New@4,
Diff@2,
fun(Diff@3, Key@1, Attr@1) ->
do_attribute(Diff@3, Key@1, {error, nil}, {ok, Attr@1})
end
).
-spec event_handler(lustre@internals@vdom:attribute(OFM)) -> {ok,
{binary(),
fun((gleam@dynamic:dynamic_()) -> {ok, OFM} |
{error, list(gleam@dynamic:decode_error())})}} |
{error, nil}.
event_handler(Attribute) ->
case Attribute of
{attribute, _, _, _} ->
{error, nil};
{event, Name, Handler} ->
Name@1 = gleam@string:drop_left(Name, 2),
{ok, {Name@1, Handler}}
end.
-spec is_empty_element_diff(element_diff(any())) -> boolean().
is_empty_element_diff(Diff) ->
((erlang:element(2, Diff) =:= gleam@dict:new()) andalso (erlang:element(
3,
Diff
)
=:= gleam@set:new()))
andalso (erlang:element(4, Diff) =:= gleam@dict:new()).
-spec is_empty_attribute_diff(attribute_diff(any())) -> boolean().
is_empty_attribute_diff(Diff) ->
(erlang:element(2, Diff) =:= gleam@set:new()) andalso (erlang:element(
3,
Diff
)
=:= gleam@set:new()).
-spec element_diff_to_json(element_diff(any())) -> gleam@json:json().
element_diff_to_json(Diff) ->
gleam@json:preprocessed_array(
[gleam@json:preprocessed_array(
lists:reverse(
begin
_pipe = maps:to_list(erlang:element(2, Diff)),
_pipe@1 = gleam@list:sort(
_pipe,
fun(X, Y) ->
key_sort(
erlang:element(1, X),
erlang:element(1, Y)
)
end
),
gleam@list:fold(
_pipe@1,
[],
fun(Array, Patch) ->
{Key, Element} = Patch,
Json = gleam@json:preprocessed_array(
[gleam@json:string(Key),
lustre@internals@vdom:element_to_json(
Element,
Key
)]
),
[Json | Array]
end
)
end
)
),
gleam@json:preprocessed_array(
begin
_pipe@2 = gleam@set:to_list(erlang:element(3, Diff)),
_pipe@3 = gleam@list:sort(_pipe@2, fun key_sort/2),
gleam@list:fold(
_pipe@3,
[],
fun(Array@1, Key@1) ->
Json@1 = gleam@json:preprocessed_array(
[gleam@json:string(Key@1)]
),
[Json@1 | Array@1]
end
)
end
),
gleam@json:preprocessed_array(
lists:reverse(
(gleam@dict:fold(
erlang:element(4, Diff),
[],
fun(Array@2, Key@2, Diff@1) ->
gleam@bool:guard(
is_empty_attribute_diff(Diff@1),
Array@2,
fun() ->
Json@2 = gleam@json:preprocessed_array(
[gleam@json:string(Key@2),
attribute_diff_to_json(
Diff@1,
Key@2
)]
),
[Json@2 | Array@2]
end
)
end
))
)
)]
).
-spec patch_to_json(patch(any())) -> gleam@json:json().
patch_to_json(Patch) ->
case Patch of
{diff, Diff} ->
gleam@json:preprocessed_array(
[gleam@json:int(0), element_diff_to_json(Diff)]
);
{emit, Name, Event} ->
gleam@json:preprocessed_array(
[gleam@json:int(1), gleam@json:string(Name), Event]
);
{init, Attrs, Element} ->
gleam@json:preprocessed_array(
[gleam@json:int(2),
gleam@json:array(Attrs, fun gleam@json:string/1),
lustre@internals@vdom:element_to_json(Element, <<"0"/utf8>>)]
)
end.
-spec do_element_list(
element_diff(ODW),
list(lustre@internals@vdom:element(ODW)),
list(lustre@internals@vdom:element(ODW)),
binary()
) -> element_diff(ODW).
do_element_list(Diff, Old_elements, New_elements, Key) ->
Children = zip(Old_elements, New_elements),
gleam@list:index_fold(
Children,
Diff,
fun(Diff@1, _use1, Pos) ->
{Old, New} = _use1,
Key@1 = <<<<Key/binary, "-"/utf8>>/binary,
(gleam@int:to_string(Pos))/binary>>,
do_elements(Diff@1, Old, New, Key@1)
end
).
-spec do_elements(
element_diff(ODP),
gleam@option:option(lustre@internals@vdom:element(ODP)),
gleam@option:option(lustre@internals@vdom:element(ODP)),
binary()
) -> element_diff(ODP).
do_elements(Diff, Old, New, Key) ->
case {Old, New} of
{none, none} ->
Diff;
{{some, _}, none} ->
erlang:setelement(
3,
Diff,
gleam@set:insert(erlang:element(3, Diff), Key)
);
{none, {some, New@1}} ->
erlang:setelement(
5,
erlang:setelement(
2,
Diff,
gleam@dict:insert(erlang:element(2, Diff), Key, New@1)
),
fold_event_handlers(erlang:element(5, Diff), New@1, Key)
);
{{some, Old@1}, {some, New@2}} ->
case {Old@1, New@2} of
{{map, Old_subtree}, {map, New_subtree}} ->
do_elements(
Diff,
{some, Old_subtree()},
{some, New_subtree()},
Key
);
{{map, Subtree}, _} ->
do_elements(Diff, {some, Subtree()}, {some, New@2}, Key);
{_, {map, Subtree@1}} ->
do_elements(Diff, {some, Old@1}, {some, Subtree@1()}, Key);
{{text, Old@2}, {text, New@3}} when Old@2 =:= New@3 ->
Diff;
{{text, _}, {text, _}} ->
erlang:setelement(
2,
Diff,
gleam@dict:insert(erlang:element(2, Diff), Key, New@2)
);
{{element, _, _, _, _, _, _, _}, {text, _}} ->
erlang:setelement(
2,
Diff,
gleam@dict:insert(erlang:element(2, Diff), Key, New@2)
);
{{text, _}, {element, _, _, _, _, _, _, _}} ->
erlang:setelement(
5,
erlang:setelement(
2,
Diff,
gleam@dict:insert(
erlang:element(2, Diff),
Key,
New@2
)
),
fold_event_handlers(erlang:element(5, Diff), New@2, Key)
);
{{element, _, Old_ns, Old_tag, Old_attrs, Old_children, _, _},
{element, _, New_ns, New_tag, New_attrs, New_children, _, _}} when (Old_ns =:= New_ns) andalso (Old_tag =:= New_tag) ->
Attribute_diff = attributes(Old_attrs, New_attrs),
Handlers@1 = (gleam@dict:fold(
erlang:element(4, Attribute_diff),
erlang:element(5, Diff),
fun(Handlers, Name, Handler) ->
Name@1 = gleam@string:drop_left(Name, 2),
gleam@dict:insert(
Handlers,
<<<<Key/binary, "-"/utf8>>/binary,
Name@1/binary>>,
Handler
)
end
)),
Diff@1 = erlang:setelement(
5,
erlang:setelement(
4,
Diff,
case is_empty_attribute_diff(Attribute_diff) of
true ->
erlang:element(4, Diff);
false ->
gleam@dict:insert(
erlang:element(4, Diff),
Key,
Attribute_diff
)
end
),
Handlers@1
),
do_element_list(Diff@1, Old_children, New_children, Key);
{{element, _, _, _, _, _, _, _}, {element, _, _, _, _, _, _, _}} ->
erlang:setelement(
5,
erlang:setelement(
2,
Diff,
gleam@dict:insert(
erlang:element(2, Diff),
Key,
New@2
)
),
fold_event_handlers(erlang:element(5, Diff), New@2, Key)
);
{{fragment, Old_elements, _}, {fragment, New_elements, _}} ->
do_element_list(Diff, Old_elements, New_elements, Key);
{_, {fragment, _, _}} ->
erlang:setelement(
5,
erlang:setelement(
2,
Diff,
gleam@dict:insert(
erlang:element(2, Diff),
Key,
New@2
)
),
fold_event_handlers(erlang:element(5, Diff), New@2, Key)
);
{{fragment, _, _}, _} ->
erlang:setelement(
5,
erlang:setelement(
2,
Diff,
gleam@dict:insert(
erlang:element(2, Diff),
Key,
New@2
)
),
fold_event_handlers(erlang:element(5, Diff), New@2, Key)
)
end
end.
-spec elements(
lustre@internals@vdom:element(ODL),
lustre@internals@vdom:element(ODL)
) -> element_diff(ODL).
elements(Old, New) ->
do_elements(
{element_diff,
gleam@dict:new(),
gleam@set:new(),
gleam@dict:new(),
gleam@dict:new()},
{some, Old},
{some, New},
<<"0"/utf8>>
).
-spec fold_element_list_event_handlers(
gleam@dict:dict(binary(), fun((gleam@dynamic:dynamic_()) -> {ok, OFZ} |
{error, list(gleam@dynamic:decode_error())})),
list(lustre@internals@vdom:element(OFZ)),
binary()
) -> gleam@dict:dict(binary(), fun((gleam@dynamic:dynamic_()) -> {ok, OFZ} |
{error, list(gleam@dynamic:decode_error())})).
fold_element_list_event_handlers(Handlers, Elements, Key) ->
gleam@list:index_fold(
Elements,
Handlers,
fun(Handlers@1, Element, Index) ->
Key@1 = <<<<Key/binary, "-"/utf8>>/binary,
(gleam@int:to_string(Index))/binary>>,
fold_event_handlers(Handlers@1, Element, Key@1)
end
).
-spec fold_event_handlers(
gleam@dict:dict(binary(), fun((gleam@dynamic:dynamic_()) -> {ok, OFR} |
{error, list(gleam@dynamic:decode_error())})),
lustre@internals@vdom:element(OFR),
binary()
) -> gleam@dict:dict(binary(), fun((gleam@dynamic:dynamic_()) -> {ok, OFR} |
{error, list(gleam@dynamic:decode_error())})).
fold_event_handlers(Handlers, Element, Key) ->
case Element of
{text, _} ->
Handlers;
{map, Subtree} ->
fold_event_handlers(Handlers, Subtree(), Key);
{element, _, _, _, Attrs, Children, _, _} ->
Handlers@2 = gleam@list:fold(
Attrs,
Handlers,
fun(Handlers@1, Attr) -> case event_handler(Attr) of
{ok, {Name, Handler}} ->
gleam@dict:insert(
Handlers@1,
<<<<Key/binary, "-"/utf8>>/binary, Name/binary>>,
Handler
);
{error, _} ->
Handlers@1
end end
),
fold_element_list_event_handlers(Handlers@2, Children, Key);
{fragment, Elements, _} ->
fold_element_list_event_handlers(Handlers, Elements, Key)
end.