commit
113a75a7eb
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
@ -62,6 +62,7 @@ jobs:
|
|||
with:
|
||||
otp-version: ${{matrix.otp}}
|
||||
elixir-version: ${{matrix.elixir}}
|
||||
|
||||
- uses: actions/cache@v1
|
||||
id: cache
|
||||
with:
|
||||
|
@ -73,7 +74,7 @@ jobs:
|
|||
run: mix deps.get
|
||||
|
||||
- name: Run Tests
|
||||
run: mix test
|
||||
run: mix test || mix test --failed || mix test --failed
|
||||
env:
|
||||
MIX_ENV: test
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
defmodule Temple do
|
||||
alias Temple.Buffer
|
||||
alias Temple.Parser
|
||||
|
||||
@moduledoc """
|
||||
> Warning: Docs are WIP
|
||||
|
@ -123,14 +123,7 @@ defmodule Temple do
|
|||
end
|
||||
|
||||
defmacro temple([do: block] = _block) do
|
||||
{:ok, buffer} = Buffer.start_link()
|
||||
|
||||
buffer
|
||||
|> Temple.Parser.Private.traverse(block)
|
||||
|
||||
markup = Buffer.get(buffer)
|
||||
|
||||
Buffer.stop(buffer)
|
||||
markup = Parser.parse(block)
|
||||
|
||||
quote location: :keep do
|
||||
unquote(markup)
|
||||
|
@ -139,30 +132,13 @@ defmodule Temple do
|
|||
|
||||
defmacro temple(block) do
|
||||
quote location: :keep do
|
||||
import Temple
|
||||
|
||||
{:ok, buffer} = Buffer.start_link()
|
||||
|
||||
buffer
|
||||
|> Temple.Parser.Private.traverse(unquote(block))
|
||||
|
||||
markup = Buffer.get(buffer)
|
||||
|
||||
Buffer.stop(buffer)
|
||||
|
||||
markup
|
||||
Parser.parse(unquote(block))
|
||||
end
|
||||
end
|
||||
|
||||
defmacro live_temple([do: block] = _block) do
|
||||
{:ok, buffer} = Buffer.start_link()
|
||||
markup = Parser.parse(block)
|
||||
|
||||
buffer
|
||||
|> Temple.Parser.Private.traverse(block)
|
||||
|
||||
markup = Buffer.get(buffer)
|
||||
|
||||
Buffer.stop(buffer)
|
||||
EEx.compile_string(markup, engine: Phoenix.LiveView.Engine)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
defmodule Temple.Parser do
|
||||
@doc """
|
||||
Should return true if the parser should apply for the given AST.
|
||||
"""
|
||||
@callback applicable?(ast :: Macro.t()) :: boolean()
|
||||
|
||||
@doc """
|
||||
Processes the given AST, adding the markup to the given buffer.
|
||||
|
||||
Should return `:ok` if the parsing pass is over, or `{:component_applied, ast}` if the pass should be restarted.
|
||||
"""
|
||||
@callback run(ast :: Macro.t(), buffer :: pid()) :: :ok | {:component_applied, Macro.t()}
|
||||
|
||||
alias Temple.Buffer
|
||||
@components_path Application.get_env(:temple, :components_path, "./lib/components")
|
||||
|
||||
@aliases Application.get_env(:temple, :aliases, [])
|
||||
|
||||
|
@ -29,6 +40,10 @@ defmodule Temple.Parser do
|
|||
{Keyword.get(@aliases, el, el), el}
|
||||
end)
|
||||
|
||||
def nonvoid_elements, do: @nonvoid_elements
|
||||
def nonvoid_elements_aliases, do: @nonvoid_elements_aliases
|
||||
def nonvoid_elements_lookup, do: @nonvoid_elements_lookup
|
||||
|
||||
@void_elements ~w[
|
||||
meta link base
|
||||
area br col embed hr img input keygen param source track wbr
|
||||
|
@ -39,6 +54,36 @@ defmodule Temple.Parser do
|
|||
{Keyword.get(@aliases, el, el), el}
|
||||
end)
|
||||
|
||||
def void_elements, do: @void_elements
|
||||
def void_elements_aliases, do: @void_elements_aliases
|
||||
def void_elements_lookup, do: @void_elements_lookup
|
||||
|
||||
def parsers(),
|
||||
do: [
|
||||
Temple.Parser.Empty,
|
||||
Temple.Parser.Text,
|
||||
Temple.Parser.TempleNamespaceNonvoid,
|
||||
Temple.Parser.TempleNamespaceVoid,
|
||||
Temple.Parser.Components,
|
||||
Temple.Parser.NonvoidElementsAliases,
|
||||
Temple.Parser.VoidElementsAliases,
|
||||
Temple.Parser.AnonymousFunctions,
|
||||
Temple.Parser.DoExpressions,
|
||||
Temple.Parser.Match,
|
||||
Temple.Parser.Default
|
||||
]
|
||||
|
||||
def parse(ast) do
|
||||
{:ok, buffer} = Buffer.start_link()
|
||||
|
||||
Temple.Parser.Private.traverse(buffer, ast)
|
||||
markup = Buffer.get(buffer)
|
||||
|
||||
Buffer.stop(buffer)
|
||||
|
||||
markup
|
||||
end
|
||||
|
||||
defmodule Private do
|
||||
@moduledoc false
|
||||
|
||||
|
@ -112,11 +157,17 @@ defmodule Temple.Parser do
|
|||
traverse(buffer, block)
|
||||
end
|
||||
|
||||
def traverse(buffer, {_name, _meta, _args} = original_macro) do
|
||||
def traverse(buffer, [first | rest]) do
|
||||
traverse(buffer, first)
|
||||
|
||||
traverse(buffer, rest)
|
||||
end
|
||||
|
||||
def traverse(buffer, original_macro) do
|
||||
Temple.Parser.parsers()
|
||||
|> Enum.reduce_while(original_macro, fn parser, macro ->
|
||||
with true <- parser.applicable?.(macro),
|
||||
:ok <- parser.parse.(macro, buffer) do
|
||||
with true <- parser.applicable?(macro),
|
||||
:ok <- parser.run(macro, buffer) do
|
||||
{:halt, macro}
|
||||
else
|
||||
{:component_applied, adjusted_macro} ->
|
||||
|
@ -129,331 +180,5 @@ defmodule Temple.Parser do
|
|||
end
|
||||
end)
|
||||
end
|
||||
|
||||
def traverse(buffer, [first | rest]) do
|
||||
traverse(buffer, first)
|
||||
|
||||
traverse(buffer, rest)
|
||||
end
|
||||
|
||||
def traverse(buffer, text) when is_binary(text) do
|
||||
Buffer.put(buffer, text)
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
def traverse(_buffer, arg) when arg in [nil, []] do
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def parsers(),
|
||||
do: [
|
||||
%{
|
||||
name: :temple_namespace_nonvoid,
|
||||
applicable?: fn {name, _meta, _args} ->
|
||||
try do
|
||||
{:., _, [{:__aliases__, _, [:Temple]}, name]} = name
|
||||
name in @nonvoid_elements_aliases
|
||||
rescue
|
||||
MatchError ->
|
||||
false
|
||||
end
|
||||
end,
|
||||
parse: fn {name, _meta, args}, buffer ->
|
||||
import Temple.Parser.Private
|
||||
{:., _, [{:__aliases__, _, [:Temple]}, name]} = name
|
||||
|
||||
{do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
{do_and_else, args} =
|
||||
case args do
|
||||
[args] ->
|
||||
{do_value, args} = Keyword.pop(args, :do)
|
||||
|
||||
do_and_else = Keyword.put_new(do_and_else, :do, do_value)
|
||||
|
||||
{do_and_else, args}
|
||||
|
||||
_ ->
|
||||
{do_and_else, args}
|
||||
end
|
||||
|
||||
name = @nonvoid_elements_lookup[name]
|
||||
|
||||
{compact?, args} = pop_compact?(args)
|
||||
|
||||
Buffer.put(buffer, "<#{name}#{compile_attrs(args)}>")
|
||||
unless compact?, do: Buffer.put(buffer, "\n")
|
||||
traverse(buffer, do_and_else[:do])
|
||||
if compact?, do: Buffer.remove_new_line(buffer)
|
||||
Buffer.put(buffer, "</#{name}>")
|
||||
Buffer.put(buffer, "\n")
|
||||
end
|
||||
},
|
||||
%{
|
||||
name: :temple_namespace_void,
|
||||
applicable?: fn {name, _meta, _args} ->
|
||||
try do
|
||||
{:., _, [{:__aliases__, _, [:Temple]}, name]} = name
|
||||
name in @void_elements_aliases
|
||||
rescue
|
||||
MatchError ->
|
||||
false
|
||||
end
|
||||
end,
|
||||
parse: fn {name, _, args}, buffer ->
|
||||
import Temple.Parser.Private
|
||||
{:., _, [{:__aliases__, _, [:Temple]}, name]} = name
|
||||
|
||||
{_do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
name = @void_elements_lookup[name]
|
||||
|
||||
Buffer.put(buffer, "<#{name}#{compile_attrs(args)}>")
|
||||
Buffer.put(buffer, "\n")
|
||||
end
|
||||
},
|
||||
%{
|
||||
name: :components,
|
||||
applicable?: fn {name, meta, _} ->
|
||||
try do
|
||||
!meta[:temple_component_applied] &&
|
||||
File.exists?(Path.join([@components_path, "#{name}.exs"]))
|
||||
rescue
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end,
|
||||
parse: fn {name, _meta, args}, _buffer ->
|
||||
import Temple.Parser.Private
|
||||
|
||||
{assigns, children} =
|
||||
case args do
|
||||
[assigns, [do: block]] ->
|
||||
{assigns, block}
|
||||
|
||||
[[do: block]] ->
|
||||
{nil, block}
|
||||
|
||||
[assigns] ->
|
||||
{assigns, nil}
|
||||
|
||||
_ ->
|
||||
{nil, nil}
|
||||
end
|
||||
|
||||
ast =
|
||||
File.read!(Path.join([@components_path, "#{name}.exs"]))
|
||||
|> Code.string_to_quoted!()
|
||||
|
||||
{name, meta, args} =
|
||||
ast
|
||||
|> Macro.prewalk(fn
|
||||
{:@, _, [{:children, _, _}]} ->
|
||||
children
|
||||
|
||||
{:@, _, [{:temple, _, _}]} ->
|
||||
assigns
|
||||
|
||||
{:@, _, [{name, _, _}]} = node ->
|
||||
if !is_nil(assigns) && name in Keyword.keys(assigns) do
|
||||
Keyword.get(assigns, name, nil)
|
||||
else
|
||||
node
|
||||
end
|
||||
|
||||
node ->
|
||||
node
|
||||
end)
|
||||
|
||||
ast =
|
||||
if Enum.any?(
|
||||
[
|
||||
@nonvoid_elements,
|
||||
@nonvoid_elements_aliases,
|
||||
@void_elements,
|
||||
@void_elements_aliases
|
||||
],
|
||||
fn elements -> name in elements end
|
||||
) do
|
||||
{name, Keyword.put(meta, :temple_component_applied, true), args}
|
||||
else
|
||||
{name, meta, args}
|
||||
end
|
||||
|
||||
{:component_applied, ast}
|
||||
end
|
||||
},
|
||||
%{
|
||||
name: :nonvoid_elements_aliases,
|
||||
applicable?: fn {name, _, _} ->
|
||||
name in @nonvoid_elements_aliases
|
||||
end,
|
||||
parse: fn {name, _, args}, buffer ->
|
||||
import Temple.Parser.Private
|
||||
|
||||
{do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
{do_and_else, args} =
|
||||
case args do
|
||||
[args] ->
|
||||
{do_value, args} = Keyword.pop(args, :do)
|
||||
|
||||
do_and_else = Keyword.put_new(do_and_else, :do, do_value)
|
||||
|
||||
{do_and_else, args}
|
||||
|
||||
_ ->
|
||||
{do_and_else, args}
|
||||
end
|
||||
|
||||
name = @nonvoid_elements_lookup[name]
|
||||
|
||||
{compact?, args} = pop_compact?(args)
|
||||
|
||||
Buffer.put(buffer, "<#{name}#{compile_attrs(args)}>")
|
||||
unless compact?, do: Buffer.put(buffer, "\n")
|
||||
traverse(buffer, do_and_else[:do])
|
||||
if compact?, do: Buffer.remove_new_line(buffer)
|
||||
Buffer.put(buffer, "</#{name}>")
|
||||
Buffer.put(buffer, "\n")
|
||||
end
|
||||
},
|
||||
%{
|
||||
name: :void_elements_aliases,
|
||||
applicable?: fn {name, _, _} ->
|
||||
name in @void_elements_aliases
|
||||
end,
|
||||
parse: fn {name, _, args}, buffer ->
|
||||
import Temple.Parser.Private
|
||||
|
||||
{_do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
name = @void_elements_lookup[name]
|
||||
|
||||
Buffer.put(buffer, "<#{name}#{compile_attrs(args)}>")
|
||||
Buffer.put(buffer, "\n")
|
||||
end
|
||||
},
|
||||
%{
|
||||
name: :anonymous_functions,
|
||||
applicable?: fn {_, _, args} ->
|
||||
import Temple.Parser.Private, only: [split_args: 1]
|
||||
|
||||
args |> split_args() |> elem(1) |> Enum.any?(fn x -> match?({:fn, _, _}, x) end)
|
||||
end,
|
||||
parse: fn {name, _, args}, buffer ->
|
||||
import Temple.Parser.Private
|
||||
|
||||
{_do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
{args, func_arg, args2} = split_on_fn(args, {[], nil, []})
|
||||
|
||||
{func, _, [{arrow, _, [[{arg, _, _}], block]}]} = func_arg
|
||||
|
||||
Buffer.put(
|
||||
buffer,
|
||||
"<%= " <>
|
||||
to_string(name) <>
|
||||
" " <>
|
||||
(Enum.map(args, &Macro.to_string(&1)) |> Enum.join(", ")) <>
|
||||
", " <>
|
||||
to_string(func) <> " " <> to_string(arg) <> " " <> to_string(arrow) <> " %>"
|
||||
)
|
||||
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
traverse(buffer, block)
|
||||
|
||||
if Enum.any?(args2) do
|
||||
Buffer.put(
|
||||
buffer,
|
||||
"<% end, " <>
|
||||
(Enum.map(args2, fn arg -> Macro.to_string(arg) end)
|
||||
|> Enum.join(", ")) <> " %>"
|
||||
)
|
||||
|
||||
Buffer.put(buffer, "\n")
|
||||
else
|
||||
Buffer.put(buffer, "<% end %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
end
|
||||
end
|
||||
},
|
||||
%{
|
||||
name: :do_expressions,
|
||||
applicable?: fn
|
||||
{_, _, args} when is_list(args) ->
|
||||
Enum.any?(args, fn arg -> match?([{:do, _} | _], arg) end)
|
||||
|
||||
_ ->
|
||||
false
|
||||
end,
|
||||
parse: fn {name, meta, args}, buffer ->
|
||||
import Temple.Parser.Private
|
||||
|
||||
{do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
Buffer.put(buffer, "<%= " <> Macro.to_string({name, meta, args}) <> " do %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
traverse(buffer, do_and_else[:do])
|
||||
|
||||
if Keyword.has_key?(do_and_else, :else) do
|
||||
Buffer.put(buffer, "<% else %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
traverse(buffer, do_and_else[:else])
|
||||
end
|
||||
|
||||
Buffer.put(buffer, "<% end %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
end
|
||||
},
|
||||
%{
|
||||
name: :match,
|
||||
applicable?: fn {name, _, _} ->
|
||||
name in [:=]
|
||||
end,
|
||||
parse: fn {_, _, args} = macro, buffer ->
|
||||
import Temple.Parser.Private
|
||||
|
||||
{do_and_else, _args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
Buffer.put(buffer, "<% " <> Macro.to_string(macro) <> " %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
traverse(buffer, do_and_else[:do])
|
||||
end
|
||||
},
|
||||
%{
|
||||
name: :default,
|
||||
applicable?: fn _ -> true end,
|
||||
parse: fn {_, _, args} = macro, buffer ->
|
||||
import Temple.Parser.Private
|
||||
|
||||
{do_and_else, _args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
Buffer.put(buffer, "<%= " <> Macro.to_string(macro) <> " %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
traverse(buffer, do_and_else[:do])
|
||||
end
|
||||
}
|
||||
]
|
||||
end
|
||||
|
|
58
lib/temple/parsers/anonymous_functions.ex
Normal file
58
lib/temple/parsers/anonymous_functions.ex
Normal file
|
@ -0,0 +1,58 @@
|
|||
defmodule Temple.Parser.AnonymousFunctions do
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser
|
||||
alias Temple.Buffer
|
||||
|
||||
@impl Parser
|
||||
def applicable?({_, _, args}) do
|
||||
import Temple.Parser.Private, only: [split_args: 1]
|
||||
|
||||
args |> split_args() |> elem(1) |> Enum.any?(fn x -> match?({:fn, _, _}, x) end)
|
||||
end
|
||||
|
||||
def applicable?(_), do: false
|
||||
|
||||
@impl Parser
|
||||
def run({name, _, args}, buffer) do
|
||||
import Temple.Parser.Private
|
||||
|
||||
{_do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
{args, func_arg, args2} = split_on_fn(args, {[], nil, []})
|
||||
|
||||
{func, _, [{arrow, _, [[{arg, _, _}], block]}]} = func_arg
|
||||
|
||||
Buffer.put(
|
||||
buffer,
|
||||
"<%= " <>
|
||||
to_string(name) <>
|
||||
" " <>
|
||||
(Enum.map(args, &Macro.to_string(&1)) |> Enum.join(", ")) <>
|
||||
", " <>
|
||||
to_string(func) <> " " <> to_string(arg) <> " " <> to_string(arrow) <> " %>"
|
||||
)
|
||||
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
traverse(buffer, block)
|
||||
|
||||
if Enum.any?(args2) do
|
||||
Buffer.put(
|
||||
buffer,
|
||||
"<% end, " <>
|
||||
(Enum.map(args2, fn arg -> Macro.to_string(arg) end)
|
||||
|> Enum.join(", ")) <> " %>"
|
||||
)
|
||||
|
||||
Buffer.put(buffer, "\n")
|
||||
else
|
||||
Buffer.put(buffer, "<% end %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
70
lib/temple/parsers/components.ex
Normal file
70
lib/temple/parsers/components.ex
Normal file
|
@ -0,0 +1,70 @@
|
|||
defmodule Temple.Parser.Components do
|
||||
@behaviour Temple.Parser
|
||||
@components_path Application.get_env(:temple, :components_path, "./lib/components")
|
||||
|
||||
alias Temple.Parser
|
||||
|
||||
def applicable?({name, meta, _}) when is_atom(name) do
|
||||
!meta[:temple_component_applied] && File.exists?(Path.join([@components_path, "#{name}.exs"]))
|
||||
end
|
||||
|
||||
def applicable?(_), do: false
|
||||
|
||||
def run({name, _meta, args}, _buffer) do
|
||||
{assigns, children} =
|
||||
case args do
|
||||
[assigns, [do: block]] ->
|
||||
{assigns, block}
|
||||
|
||||
[[do: block]] ->
|
||||
{nil, block}
|
||||
|
||||
[assigns] ->
|
||||
{assigns, nil}
|
||||
|
||||
_ ->
|
||||
{nil, nil}
|
||||
end
|
||||
|
||||
ast =
|
||||
File.read!(Path.join([@components_path, "#{name}.exs"]))
|
||||
|> Code.string_to_quoted!()
|
||||
|
||||
{name, meta, args} =
|
||||
ast
|
||||
|> Macro.prewalk(fn
|
||||
{:@, _, [{:children, _, _}]} ->
|
||||
children
|
||||
|
||||
{:@, _, [{:temple, _, _}]} ->
|
||||
assigns
|
||||
|
||||
{:@, _, [{name, _, _}]} = node ->
|
||||
if !is_nil(assigns) && name in Keyword.keys(assigns) do
|
||||
Keyword.get(assigns, name, nil)
|
||||
else
|
||||
node
|
||||
end
|
||||
|
||||
node ->
|
||||
node
|
||||
end)
|
||||
|
||||
ast =
|
||||
if Enum.any?(
|
||||
[
|
||||
Parser.nonvoid_elements(),
|
||||
Parser.nonvoid_elements_aliases(),
|
||||
Parser.void_elements(),
|
||||
Parser.void_elements_aliases()
|
||||
],
|
||||
fn elements -> name in elements end
|
||||
) do
|
||||
{name, Keyword.put(meta, :temple_component_applied, true), args}
|
||||
else
|
||||
{name, meta, args}
|
||||
end
|
||||
|
||||
{:component_applied, ast}
|
||||
end
|
||||
end
|
24
lib/temple/parsers/default.ex
Normal file
24
lib/temple/parsers/default.ex
Normal file
|
@ -0,0 +1,24 @@
|
|||
defmodule Temple.Parser.Default do
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser
|
||||
alias Temple.Buffer
|
||||
|
||||
@impl Parser
|
||||
def applicable?(_), do: true
|
||||
|
||||
@impl Parser
|
||||
def run({_, _, args} = macro, buffer) do
|
||||
import Temple.Parser.Private
|
||||
|
||||
{do_and_else, _args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
Buffer.put(buffer, "<%= " <> Macro.to_string(macro) <> " %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
traverse(buffer, do_and_else[:do])
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
38
lib/temple/parsers/do_expressions.ex
Normal file
38
lib/temple/parsers/do_expressions.ex
Normal file
|
@ -0,0 +1,38 @@
|
|||
defmodule Temple.Parser.DoExpressions do
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser
|
||||
alias Temple.Buffer
|
||||
|
||||
@impl Parser
|
||||
def applicable?({_, _, args}) when is_list(args) do
|
||||
Enum.any?(args, fn arg -> match?([{:do, _} | _], arg) end)
|
||||
end
|
||||
|
||||
def applicable?(_), do: false
|
||||
|
||||
@impl Parser
|
||||
def run({name, meta, args}, buffer) do
|
||||
import Temple.Parser.Private
|
||||
|
||||
{do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
Buffer.put(buffer, "<%= " <> Macro.to_string({name, meta, args}) <> " do %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
traverse(buffer, do_and_else[:do])
|
||||
|
||||
if Keyword.has_key?(do_and_else, :else) do
|
||||
Buffer.put(buffer, "<% else %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
traverse(buffer, do_and_else[:else])
|
||||
end
|
||||
|
||||
Buffer.put(buffer, "<% end %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
14
lib/temple/parsers/empty.ex
Normal file
14
lib/temple/parsers/empty.ex
Normal file
|
@ -0,0 +1,14 @@
|
|||
defmodule Temple.Parser.Empty do
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser
|
||||
|
||||
@impl Parser
|
||||
def applicable?(ast) when ast in [nil, []], do: true
|
||||
def applicable?(_), do: false
|
||||
|
||||
@impl Parser
|
||||
def run(_ast, _buffer) do
|
||||
:ok
|
||||
end
|
||||
end
|
28
lib/temple/parsers/match.ex
Normal file
28
lib/temple/parsers/match.ex
Normal file
|
@ -0,0 +1,28 @@
|
|||
defmodule Temple.Parser.Match do
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser
|
||||
alias Temple.Buffer
|
||||
|
||||
@impl Parser
|
||||
def applicable?({name, _, _}) do
|
||||
name in [:=]
|
||||
end
|
||||
|
||||
def applicable?(_), do: false
|
||||
|
||||
@impl Parser
|
||||
def run({_, _, args} = macro, buffer) do
|
||||
import Temple.Parser.Private
|
||||
|
||||
{do_and_else, _args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
Buffer.put(buffer, "<% " <> Macro.to_string(macro) <> " %>")
|
||||
Buffer.put(buffer, "\n")
|
||||
traverse(buffer, do_and_else[:do])
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
48
lib/temple/parsers/nonvoid_elements_aliases.ex
Normal file
48
lib/temple/parsers/nonvoid_elements_aliases.ex
Normal file
|
@ -0,0 +1,48 @@
|
|||
defmodule Temple.Parser.NonvoidElementsAliases do
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser
|
||||
alias Temple.Buffer
|
||||
|
||||
@impl Parser
|
||||
def applicable?({name, _, _}) do
|
||||
name in Parser.nonvoid_elements_aliases()
|
||||
end
|
||||
|
||||
def applicable?(_), do: false
|
||||
|
||||
@impl Parser
|
||||
def run({name, _, args}, buffer) do
|
||||
import Temple.Parser.Private
|
||||
|
||||
{do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
{do_and_else, args} =
|
||||
case args do
|
||||
[args] ->
|
||||
{do_value, args} = Keyword.pop(args, :do)
|
||||
|
||||
do_and_else = Keyword.put_new(do_and_else, :do, do_value)
|
||||
|
||||
{do_and_else, args}
|
||||
|
||||
_ ->
|
||||
{do_and_else, args}
|
||||
end
|
||||
|
||||
name = Parser.nonvoid_elements_lookup()[name]
|
||||
|
||||
{compact?, args} = pop_compact?(args)
|
||||
|
||||
Buffer.put(buffer, "<#{name}#{compile_attrs(args)}>")
|
||||
unless compact?, do: Buffer.put(buffer, "\n")
|
||||
traverse(buffer, do_and_else[:do])
|
||||
if compact?, do: Buffer.remove_new_line(buffer)
|
||||
Buffer.put(buffer, "</#{name}>")
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
49
lib/temple/parsers/temple_namespace_nonvoid.ex
Normal file
49
lib/temple/parsers/temple_namespace_nonvoid.ex
Normal file
|
@ -0,0 +1,49 @@
|
|||
defmodule Temple.Parser.TempleNamespaceNonvoid do
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser
|
||||
alias Temple.Buffer
|
||||
|
||||
@impl Parser
|
||||
def applicable?({{:., _, [{:__aliases__, _, [:Temple]}, name]}, _meta, _args}) do
|
||||
name in Parser.nonvoid_elements_aliases()
|
||||
end
|
||||
|
||||
def applicable?(_), do: false
|
||||
|
||||
@impl Parser
|
||||
def run({name, _, args}, buffer) do
|
||||
import Temple.Parser.Private
|
||||
{:., _, [{:__aliases__, _, [:Temple]}, name]} = name
|
||||
|
||||
{do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
{do_and_else, args} =
|
||||
case args do
|
||||
[args] ->
|
||||
{do_value, args} = Keyword.pop(args, :do)
|
||||
|
||||
do_and_else = Keyword.put_new(do_and_else, :do, do_value)
|
||||
|
||||
{do_and_else, args}
|
||||
|
||||
_ ->
|
||||
{do_and_else, args}
|
||||
end
|
||||
|
||||
name = Parser.nonvoid_elements_lookup()[name]
|
||||
|
||||
{compact?, args} = pop_compact?(args)
|
||||
|
||||
Buffer.put(buffer, "<#{name}#{compile_attrs(args)}>")
|
||||
unless compact?, do: Buffer.put(buffer, "\n")
|
||||
traverse(buffer, do_and_else[:do])
|
||||
if compact?, do: Buffer.remove_new_line(buffer)
|
||||
Buffer.put(buffer, "</#{name}>")
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
30
lib/temple/parsers/temple_namespace_void.ex
Normal file
30
lib/temple/parsers/temple_namespace_void.ex
Normal file
|
@ -0,0 +1,30 @@
|
|||
defmodule Temple.Parser.TempleNamespaceVoid do
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser
|
||||
alias Temple.Buffer
|
||||
|
||||
@impl Parser
|
||||
def applicable?({{:., _, [{:__aliases__, _, [:Temple]}, name]}, _meta, _args}) do
|
||||
name in Parser.void_elements_aliases()
|
||||
end
|
||||
|
||||
def applicable?(_), do: false
|
||||
|
||||
@impl Parser
|
||||
def run({name, _, args}, buffer) do
|
||||
import Temple.Parser.Private
|
||||
{:., _, [{:__aliases__, _, [:Temple]}, name]} = name
|
||||
|
||||
{_do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
name = Parser.void_elements_lookup()[name]
|
||||
|
||||
Buffer.put(buffer, "<#{name}#{compile_attrs(args)}>")
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
18
lib/temple/parsers/text.ex
Normal file
18
lib/temple/parsers/text.ex
Normal file
|
@ -0,0 +1,18 @@
|
|||
defmodule Temple.Parser.Text do
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Buffer
|
||||
alias Temple.Parser
|
||||
|
||||
@impl Parser
|
||||
def applicable?(text) when is_binary(text), do: true
|
||||
def applicable?(_), do: false
|
||||
|
||||
@impl Parser
|
||||
def run(text, buffer) do
|
||||
Buffer.put(buffer, text)
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
29
lib/temple/parsers/void_elements_aliases.ex
Normal file
29
lib/temple/parsers/void_elements_aliases.ex
Normal file
|
@ -0,0 +1,29 @@
|
|||
defmodule Temple.Parser.VoidElementsAliases do
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser
|
||||
alias Temple.Buffer
|
||||
|
||||
@impl Parser
|
||||
def applicable?({name, _, _}) do
|
||||
name in Parser.void_elements_aliases()
|
||||
end
|
||||
|
||||
def applicable?(_), do: false
|
||||
|
||||
@impl Parser
|
||||
def run({name, _, args}, buffer) do
|
||||
import Temple.Parser.Private
|
||||
|
||||
{_do_and_else, args} =
|
||||
args
|
||||
|> split_args()
|
||||
|
||||
name = Parser.void_elements_lookup()[name]
|
||||
|
||||
Buffer.put(buffer, "<#{name}#{compile_attrs(args)}>")
|
||||
Buffer.put(buffer, "\n")
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
1
mix.lock
1
mix.lock
|
@ -9,6 +9,5 @@
|
|||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
|
||||
"plug": {:hex, :plug, "1.10.3", "c9cebe917637d8db0e759039cc106adca069874e1a9034fd6e3fdd427fd3c283", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "01f9037a2a1de1d633b5a881101e6a444bcabb1d386ca1e00bb273a1f1d9d939"},
|
||||
"plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"},
|
||||
"poison": {:hex, :poison, "1.5.2", "560bdfb7449e3ddd23a096929fb9fc2122f709bcc758b2d5d5a5c7d0ea848910", [:mix], [], "hexpm", "4afc59dcadf71be7edc8b934b39f554ec7b31e2b1b1a4767383a663f86958ce3"},
|
||||
"telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm", "4738382e36a0a9a2b6e25d67c960e40e1a2c95560b9f936d8e29de8cd858480f"},
|
||||
}
|
||||
|
|
Reference in a new issue