77 lines
1.8 KiB
Elixir
77 lines
1.8 KiB
Elixir
defmodule Temple.HtmlToTemple do
|
|
@moduledoc false
|
|
|
|
@tags Temple.Html.void_elements() ++
|
|
Temple.Html.nonvoid_elements() ++ Temple.Svg.elements() ++ [:html]
|
|
|
|
def parse(doc) do
|
|
result =
|
|
doc
|
|
|> Floki.parse()
|
|
|> List.wrap()
|
|
|> Enum.map(&do_parse(&1, 0))
|
|
|> Enum.join("\n")
|
|
|
|
{:ok, result}
|
|
end
|
|
|
|
def do_parse({tag, [], []}, indent) do
|
|
tag = tag |> find_tag
|
|
(Temple.Utils.kebab_to_snake(tag) <> "()\n") |> pad_indent(indent)
|
|
end
|
|
|
|
def do_parse({tag, attrs, []}, indent) do
|
|
tag = tag |> find_tag
|
|
(Temple.Utils.kebab_to_snake(tag) <> build_attrs(attrs) <> "\n") |> pad_indent(indent)
|
|
end
|
|
|
|
def do_parse({tag, attrs, [""]}, indent), do: do_parse({tag, attrs, []}, indent)
|
|
|
|
def do_parse({tag, attrs, children}, indent) do
|
|
tag = tag |> find_tag
|
|
|
|
head =
|
|
(Temple.Utils.kebab_to_snake(tag) <> build_attrs(attrs) <> " do\n")
|
|
|> pad_indent(indent)
|
|
|
|
parsed_childs =
|
|
for child <- children do
|
|
do_parse(child, indent + 1)
|
|
end
|
|
|> Enum.join("\n")
|
|
|
|
head <> parsed_childs <> pad_indent("end\n", indent)
|
|
end
|
|
|
|
def do_parse(text, indent) when is_binary(text) do
|
|
(~s|text "| <> text <> ~s|"\n|) |> pad_indent(indent)
|
|
end
|
|
|
|
defp build_attrs([]), do: ""
|
|
|
|
defp build_attrs(attrs) do
|
|
attrs =
|
|
for {key, value} <- attrs do
|
|
wrap_in_quotes(key) <> ~s|: "| <> value <> ~s|"|
|
|
end
|
|
|> Enum.join(", ")
|
|
|
|
" " <> attrs
|
|
end
|
|
|
|
defp wrap_in_quotes(key) do
|
|
if Regex.match?(~r/[^a-zA-Z_]/, key) do
|
|
~s|"| <> key <> ~s|"|
|
|
else
|
|
key
|
|
end
|
|
end
|
|
|
|
defp pad_indent(paddable, indent) do
|
|
String.pad_leading(paddable, 2 * indent + String.length(paddable))
|
|
end
|
|
|
|
defp find_tag(tag),
|
|
do: @tags |> Enum.find(fn x -> String.downcase(to_string(x)) == tag end)
|
|
end
|