Packages
surface
0.9.5
0.12.3
0.12.2
0.12.1
0.12.0
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.1
0.1.0
0.1.0-alpha.2
0.1.0-alpha.1
0.1.0-alpha.0
A component based library for Phoenix LiveView
Current section
Files
Jump to
Current section
Files
lib/surface/compiler/converter_0_8.ex
defmodule Surface.Compiler.Converter_0_8 do
@moduledoc false
@behaviour Surface.Compiler.Converter
@impl true
def after_convert_file(_ext, content), do: content
@impl true
def opts() do
[handle_full_node: ["#template", "#slot"]]
end
@impl true
def convert(:tag_open_begin, "<#template", _state, _opts) do
"<:"
end
def convert(:tag_open_end, ">", %{tag_open_begin: "<#template"} = state, _opts) do
slot = "default"
{"#{String.trim(slot)}>", Map.put(state, :slot_name, slot)}
end
def convert(:tag_open_end, text, %{tag_open_begin: "<#template"} = state, _opts) do
[_, slot] = Regex.run(~r/slot="(\w+)"/s, text)
{"#{String.trim(slot)}>", Map.put(state, :slot_name, slot)}
end
def convert(:tag_close, "</#template>", %{slot_name: slot_name} = state, _opts) do
{"</:#{slot_name}>", Map.delete(state, :slot_name)}
end
def convert(:tag_open_end, text, %{tag_open_begin: "<#slot" = begin}, _opts) do
{attrs, self_close} = extract_tag_attrs(begin, text, extract: ["index", "name", "for", ":args"])
can_convert? = Enum.any?(attrs, fn {k, v} -> k == "index" and is_nil(v) end)
needs_convertion? = Enum.any?(attrs, fn {k, v} -> k != :others and !is_nil(v) end)
if can_convert? and needs_convertion? do
" #{new_slot_attrs(attrs)}#{tag_close_text(self_close)}"
else
text
end
end
def convert(_type, text, _state, _opts) do
text
end
defp extract_tag_attrs(begin, text, opts) do
extract = Keyword.get(opts, :extract, [])
[{:tag_open, "#slot", attrs_tokens, %{ignored_body?: false, self_close: self_close}}] =
Surface.Compiler.Tokenizer.tokenize!(begin <> text)
attrs =
for {attr_name, {attr_type, attr_value, _value_meta}, _attr_meta} <- attrs_tokens,
reduce: %{others: []} |> Map.merge(Map.new(extract, &{&1, nil})) do
acc ->
if attr_name in extract do
Map.put(acc, attr_name, attr_value)
else
Map.update!(acc, :others, &[{attr_name, attr_type, attr_value} | &1])
end
end
{attrs, self_close}
end
defp new_slot_attrs(attrs) do
root_expr = [slot_name(attrs), attrs[":args"]] |> Enum.reject(&is_nil/1) |> Enum.join(", ")
attrs_text([{:root, :expr, root_expr} | Enum.reverse(attrs.others)])
end
defp slot_name(%{"name" => nil, "for" => nil}), do: "@default"
defp slot_name(%{"name" => name, "for" => nil}), do: "@#{name}"
defp slot_name(%{"name" => nil, "for" => for_text}), do: for_text
defp attrs_text(attrs) do
attrs |> Enum.map(&attr_text/1) |> Enum.join(" ")
end
defp attr_text({:root, :expr, attr_value}), do: "{#{attr_value}}"
defp attr_text({attr_name, :expr, attr_value}), do: "#{attr_name}={#{attr_value}}"
defp tag_close_text(self_close)
defp tag_close_text(true), do: " />"
defp tag_close_text(false), do: ">"
end