Skip to content

Commit

Permalink
encode extra elements
Browse files Browse the repository at this point in the history
  • Loading branch information
leandrocp committed Jan 25, 2024
1 parent 0f6dfa9 commit 3608603
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 74 deletions.
72 changes: 41 additions & 31 deletions lib/beacon/template/heex/json_encoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ defmodule Beacon.Template.HEEx.JSONEncoder do
Note that:
* `rendered_html` key is optional
* Comprehensions are not supported
## Example
Expand Down Expand Up @@ -265,50 +264,61 @@ defmodule Beacon.Template.HEEx.JSONEncoder do
arg = ["<%= ", arg, " %>", "\n"]

template =
Enum.reduce(nodes, [arg], fn node, acc ->
text = [extract_eex_block_node_text(node) | " \n "]
[text | acc]
end)
|> Enum.reverse()
|> List.to_string()
Enum.reduce(nodes, [arg], fn node, acc ->
text = [extract_node_text(node) | " \n "]
[text | acc]
end)
|> Enum.reverse()
|> List.to_string()

Beacon.Template.HEEx.render(site, template, assigns)
end

defp extract_eex_block_node_text("end" = _value), do: ["<% end %>"]

defp extract_eex_block_node_text(value) when is_binary(value), do: value

defp extract_eex_block_node_text({:eex, expr, %{opt: ~c"="}}) do
["<%= ", expr, " %>"]
defp extract_node_text({nodes, "end"} = value) when is_list(nodes) do
value
|> Tuple.to_list()
|> Enum.reduce([], fn node, acc -> [extract_node_text(node) | acc] end)
|> Enum.reverse()
end

defp extract_eex_block_node_text({:eex, expr, _}) do
["<% ", expr, " %>"]
defp extract_node_text(value) when is_list(value) do
value
|> Enum.reduce([], fn node, acc -> [extract_node_text(node) | acc] end)
|> Enum.reverse()
end

defp extract_eex_block_node_text({:eex_block, expr, children}) do
["<%= ", expr, " %>", extract_eex_block_node_text(children)]
end
defp extract_node_text("end" = _value), do: ["<% end %>"]

defp extract_eex_block_node_text({:tag_block, tag, _, children, _}) do
["<", tag, ">", extract_eex_block_node_text(children), "</", tag, ">"]
end
defp extract_node_text(value) when is_binary(value), do: value

defp extract_eex_block_node_text(value) when is_tuple(value) do
value
|> Tuple.to_list()
|> Enum.reduce([], fn node, acc -> [extract_eex_block_node_text(node) | acc] end)
|> Enum.reverse()
defp extract_node_text({:text, text, _}), do: text

defp extract_node_text({:html_comment, children}), do: [extract_node_text(children), "\n"]

# TODO: eex comments are stripped out of rendered html by the heex engine
defp extract_node_text({:eex_comment, _content}), do: []

defp extract_node_text({:eex, expr, %{opt: ~c"="}}), do: ["<%= ", expr, " %>"]

defp extract_node_text({:eex, expr, _}), do: ["<% ", expr, " %>"]

defp extract_node_text({:eex_block, expr, children}), do: ["<%= ", expr, " %>", extract_node_text(children)]

defp extract_node_text({:tag_self_close, tag, attrs}) do
attrs =
Enum.reduce(attrs, [], fn attr, acc ->
[extract_node_attr(attr) | acc]
end)

[?<, tag, " ", attrs, "/>"]
end

defp extract_eex_block_node_text(value) when is_list(value) do
value
|> Enum.reduce([], fn node, acc -> [extract_eex_block_node_text(node) | acc] end)
|> Enum.reverse()
defp extract_node_text({:tag_block, tag, _, children, _}) do
[?<, tag, ?>, extract_node_text(children), "</", tag, ">"]
end

defp extract_eex_block_node_text(_value), do: []
defp extract_node_attr({attr, {:string, text, _}, _}), do: [attr, ?=, ?", text, ?", " "]
defp extract_node_attr({attr, {:expr, expr, _}, _}), do: [attr, ?=, ?{, expr, ?}, " "]

def encode_eex_block(value) when is_tuple(value) do
value
Expand Down
102 changes: 59 additions & 43 deletions test/beacon/template/heex/json_encoder_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,13 @@ defmodule Beacon.Template.HEEx.JSONEncoderTest do
assert_output(
~S|
<%= for employee <- @beacon_live_data[:employees] do %>
<!-- start -->
<!-- regular <!-- comment --> -->
<%= employee.position %>
<div>
<%= for person <- @beacon_live_data[:persons] do %>
<%= if person.id == employee.id do %>
<span><%= person.name %></span>
<img src={if person.picture , do: person.picture, else: "default.jpg"} width="200" />
<% end %>
<% end %>
</div>
Expand All @@ -181,15 +182,15 @@ defmodule Beacon.Template.HEEx.JSONEncoderTest do
"arg" => "for employee <- @beacon_live_data[:employees] do",
"tag" => "eex_block",
"rendered_html" =>
"\n<!-- start -->CEO\n <div>\n\n\n <span>José</span>\n\n\n\n\n </div>\n\n<!-- start -->Manager\n <div>\n\n\n\n\n\n </div>\n",
"\n<!-- regular <!-- comment --> -->\nCEO\n <div>\n\n\n <span>José</span>\n <img width=\"200\" src=\"profile.jpg\">\n\n\n\n\n </div>\n\n<!-- regular <!-- comment --> -->\nManager\n <div>\n\n\n\n\n <span>Chris</span>\n <img width=\"200\" src=\"default.jpg\">\n\n\n </div>\n",
"ast" =>
"[[[{\"type\":\"html_comment\",\"content\":[{\"type\":\"text\",\"content\":[\"<!-- start -->\",{}]}]},{\"type\":\"eex\",\"content\":[\"employee.position\",{\"line\":4,\"opt\":[61],\"column\":11}]},{\"type\":\"text\",\"content\":[\"\\n \",{\"newlines\":1}]},{\"type\":\"tag_block\",\"content\":[\"div\",{\"type\":\"text\",\"content\":[\"\\n \",{\"newlines\":1}]},{\"type\":\"eex_block\",\"content\":[\"for person <- @beacon_live_data[:persons] do\",{\"type\":[[\"text\",\"\\n \",{\"newlines\":1}],[\"eex_block\",\"if person.id == employee.id do\",[{\"type\":[[\"text\",\"\\n \",{\"newlines\":1}],[\"tag_block\",\"span\",[],[{\"type\":\"eex\",\"content\":[\"person.name\",{\"line\":8,\"opt\":[61],\"column\":23}]}],{\"mode\":\"inline\"}],[\"text\",\"\\n \",{\"newlines\":1}]],\"content\":[\"end\"]}]],[\"text\",\"\\n \",{\"newlines\":1}]],\"content\":[\"end\"]}]},{\"type\":\"text\",\"content\":[\"\\n \",{\"newlines\":1}]},{\"mode\":\"block\"}]},{\"type\":\"text\",\"content\":[\"\\n \",{\"newlines\":1}]}],\"end\"]]"
"[[[{\"type\":\"html_comment\",\"content\":[{\"type\":\"text\",\"content\":[\"<!-- regular <!-- comment --> -->\",{}]}]},{\"type\":\"eex\",\"content\":[\"employee.position\",{\"line\":4,\"opt\":[61],\"column\":11}]},{\"type\":\"text\",\"content\":[\"\\n \",{\"newlines\":1}]},{\"type\":\"tag_block\",\"content\":[\"div\",{\"type\":\"text\",\"content\":[\"\\n \",{\"newlines\":1}]},{\"type\":\"eex_block\",\"content\":[\"for person <- @beacon_live_data[:persons] do\",{\"type\":[[\"text\",\"\\n \",{\"newlines\":1}],[\"eex_block\",\"if person.id == employee.id do\",[{\"type\":[[\"text\",\"\\n \",{\"newlines\":1}],[\"tag_block\",\"span\",[],[{\"type\":\"eex\",\"content\":[\"person.name\",{\"line\":8,\"opt\":[61],\"column\":23}]}],{\"mode\":\"inline\"}],[\"text\",\"\\n \",{\"newlines\":1}],[\"tag_self_close\",\"img\",[{\"type\":\"src\",\"content\":[{\"type\":\"expr\",\"content\":[\"if person.picture , do: person.picture, else: \\\"default.jpg\\\"\",{\"line\":9,\"column\":27}]},{\"line\":9,\"column\":22}]},{\"type\":\"width\",\"content\":[{\"type\":\"string\",\"content\":[\"200\",{\"delimiter\":34}]},{\"line\":9,\"column\":88}]}]],[\"text\",\"\\n \",{\"newlines\":1}]],\"content\":[\"end\"]}]],[\"text\",\"\\n \",{\"newlines\":1}]],\"content\":[\"end\"]}]},{\"type\":\"text\",\"content\":[\"\\n \",{\"newlines\":1}]},{\"mode\":\"block\"}]},{\"type\":\"text\",\"content\":[\"\\n \",{\"newlines\":1}]}],\"end\"]]"
}
],
%{
beacon_live_data: %{
employees: [%{id: 1, position: "CEO"}, %{id: 2, position: "Manager"}],
persons: [%{id: 1, name: "José"}, %{id: 99, name: "Chris"}]
persons: [%{id: 1, name: "José", picture: "profile.jpg"}, %{id: 2, name: "Chris", picture: nil}]
}
}
)
Expand Down Expand Up @@ -278,7 +279,7 @@ defmodule Beacon.Template.HEEx.JSONEncoderTest do
test "encode eex_block" do
ast =
{[
{:html_comment, [{:text, "<!-- start -->", %{}}]},
{:html_comment, [{:text, "<!-- regular <!-- comment --> -->", %{}}]},
{:eex, "employee.position", %{line: 4, opt: ~c"=", column: 11}},
{:text, "\n ", %{newlines: 1}},
{:tag_block, "div", [],
Expand All @@ -293,6 +294,13 @@ defmodule Beacon.Template.HEEx.JSONEncoderTest do
{[
{:text, "\n ", %{newlines: 1}},
{:tag_block, "span", [], [{:eex, "person.name", %{line: 8, opt: ~c"=", column: 23}}], %{mode: :inline}},
{:text, "\n ", %{newlines: 1}},
{:tag_self_close, "img",
[
{"src", {:expr, "if person.picture , do: person.picture, else: \"default.jpg\"", %{line: 9, column: 27}},
%{line: 9, column: 22}},
{"width", {:string, "200", %{delimiter: 34}}, %{line: 9, column: 88}}
]},
{:text, "\n ", %{newlines: 1}}
], "end"}
]},
Expand All @@ -304,44 +312,52 @@ defmodule Beacon.Template.HEEx.JSONEncoderTest do
{:text, "\n ", %{newlines: 1}}
], "end"}

assert JSONEncoder.encode_eex_block(ast) == [
assert JSONEncoder.encode_eex_block(ast) ==
[
%{type: :html_comment, content: [%{type: :text, content: ["<!-- start -->", %{}]}]},
%{type: :eex, content: ["employee.position", %{line: 4, opt: ~c"=", column: 11}]},
%{type: :text, content: ["\n ", %{newlines: 1}]},
%{
type: :tag_block,
content: [
"div",
%{type: :text, content: ["\n ", %{newlines: 1}]},
%{
type: :eex_block,
content: [
"for person <- @beacon_live_data[:persons] do",
%{
type: [
{:text, "\n ", %{newlines: 1}},
{:eex_block, "if person.id == employee.id do",
[
{[
{:text, "\n ", %{newlines: 1}},
{:tag_block, "span", [], [{:eex, "person.name", %{line: 8, opt: ~c"=", column: 23}}], %{mode: :inline}},
{:text, "\n ", %{newlines: 1}}
], "end"}
]},
{:text, "\n ", %{newlines: 1}}
],
content: ["end"]
}
]
},
%{type: :text, content: ["\n ", %{newlines: 1}]},
%{mode: :block}
]
},
%{type: :text, content: ["\n ", %{newlines: 1}]}
],
"end"
]
[
%{type: :html_comment, content: [%{type: :text, content: ["<!-- regular <!-- comment --> -->", %{}]}]},
%{type: :eex, content: ["employee.position", %{line: 4, opt: ~c"=", column: 11}]},
%{type: :text, content: ["\n ", %{newlines: 1}]},
%{
type: :tag_block,
content: [
"div",
%{type: :text, content: ["\n ", %{newlines: 1}]},
%{
type: :eex_block,
content: [
"for person <- @beacon_live_data[:persons] do",
%{
type: [
{:text, "\n ", %{newlines: 1}},
{:eex_block, "if person.id == employee.id do",
[
{[
{:text, "\n ", %{newlines: 1}},
{:tag_block, "span", [], [{:eex, "person.name", %{line: 8, opt: ~c"=", column: 23}}], %{mode: :inline}},
{:text, "\n ", %{newlines: 1}},
{:tag_self_close, "img",
[
{"src", {:expr, "if person.picture , do: person.picture, else: \"default.jpg\"", %{line: 9, column: 27}},
%{line: 9, column: 22}},
{"width", {:string, "200", %{delimiter: 34}}, %{line: 9, column: 88}}
]},
{:text, "\n ", %{newlines: 1}}
], "end"}
]},
{:text, "\n ", %{newlines: 1}}
],
content: ["end"]
}
]
},
%{type: :text, content: ["\n ", %{newlines: 1}]},
%{mode: :block}
]
},
%{type: :text, content: ["\n ", %{newlines: 1}]}
],
"end"
]
end
end

0 comments on commit 3608603

Please sign in to comment.