Better whitespace handling and control (#145)
* Fine tune whitespace The EEx outut now emits more human-readable and predictable formatting. This includes proper indenting, at least for each "root" template. * Internal whitespace control You can now use a bang version of any nonvoid tag to emit the markup witout the internal whitespace. This means that there will not be a newline emitted after the opening tag and before the closing tag.
This commit is contained in:
parent
87ddbaa6b5
commit
c965048f40
32 changed files with 613 additions and 148 deletions
|
@ -16,7 +16,6 @@ locals_without_parens = ~w[
|
|||
details summary menuitem menu
|
||||
meta link base
|
||||
area br col embed hr img input keygen param source track wbr
|
||||
txt partial
|
||||
|
||||
animate animateMotion animateTransform circle clipPath
|
||||
color-profile defs desc discard ellipse feBlend
|
||||
|
@ -26,13 +25,7 @@ locals_without_parens = ~w[
|
|||
marker mask mesh meshgradient meshpatch meshrow metadata mpath path pattern polygon
|
||||
polyline radialGradient rect set solidcolor stop svg switch symbol text
|
||||
textPath tspan unknown use view
|
||||
|
||||
form_for inputs_for
|
||||
checkbox color_input checkbox color_input date_input date_select datetime_local_input
|
||||
datetime_select email_input file_input hidden_input number_input password_input range_input
|
||||
search_input telephone_input textarea text_input time_input time_select url_input
|
||||
reset submit phx_label radio_button multiple_select select phx_link phx_button
|
||||
]a |> Enum.map(fn e -> {e, :*} end)
|
||||
]a |> Enum.flat_map(fn e -> [{e, :*}, {:"#{e}!", :*}] end)
|
||||
|
||||
[
|
||||
inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"],
|
||||
|
|
|
@ -29,7 +29,7 @@ defmodule Temple do
|
|||
|
||||
# The class attribute also can take a keyword list of classes to conditionally render, based on the boolean result of the value.
|
||||
|
||||
div class: ["text-red-500": false, "text-green-500": true ] do
|
||||
div class: ["text-red-500": false, "text-green-500": true] do
|
||||
"Alert!"
|
||||
end
|
||||
|
||||
|
@ -71,6 +71,34 @@ defmodule Temple do
|
|||
end
|
||||
```
|
||||
|
||||
## Whitespace Control
|
||||
|
||||
By default, Temple will emit internal whitespace into tags, something like this.
|
||||
|
||||
```elixir
|
||||
span do
|
||||
"Hello, world!"
|
||||
end
|
||||
```
|
||||
|
||||
```html
|
||||
<span>
|
||||
Hello, world!
|
||||
</span>
|
||||
```
|
||||
|
||||
If you need to create a "tight" tag, you can call the "bang" version of the desired tag.
|
||||
|
||||
```elixir
|
||||
span! do
|
||||
"Hello, world!"
|
||||
end
|
||||
```
|
||||
|
||||
```html
|
||||
<span>Hello, world!</span>
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Mode
|
||||
|
@ -151,7 +179,8 @@ defmodule Temple do
|
|||
markup =
|
||||
block
|
||||
|> Parser.parse()
|
||||
|> Enum.map(&Temple.Generator.to_eex/1)
|
||||
|> Enum.map(fn parsed -> Temple.Generator.to_eex(parsed, 0) end)
|
||||
|> Enum.intersperse("\n")
|
||||
|> :erlang.iolist_to_binary()
|
||||
|
||||
quote location: :keep do
|
||||
|
@ -163,7 +192,8 @@ defmodule Temple do
|
|||
quote location: :keep do
|
||||
unquote(block)
|
||||
|> Parser.parse()
|
||||
|> Enum.map(&Temple.Generator.to_eex/1)
|
||||
|> Enum.map(fn parsed -> Temple.Generator.to_eex(parsed, 0) end)
|
||||
|> Enum.intersperse("\n")
|
||||
|> :erlang.iolist_to_binary()
|
||||
end
|
||||
end
|
||||
|
@ -190,7 +220,8 @@ defmodule Temple do
|
|||
markup =
|
||||
block
|
||||
|> Parser.parse()
|
||||
|> Enum.map(&Temple.Generator.to_eex/1)
|
||||
|> Enum.map(fn parsed -> Temple.Generator.to_eex(parsed, 0) end)
|
||||
|> Enum.intersperse("\n")
|
||||
|> :erlang.iolist_to_binary()
|
||||
|
||||
EEx.compile_string(markup, engine: engine, line: __CALLER__.line, file: __CALLER__.file)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
defprotocol Temple.Generator do
|
||||
@moduledoc false
|
||||
|
||||
def to_eex(ast)
|
||||
def to_eex(ast, indent \\ 0)
|
||||
end
|
||||
|
|
|
@ -58,7 +58,7 @@ defmodule Temple.Parser do
|
|||
option textarea output progress meter
|
||||
details summary menuitem menu
|
||||
html
|
||||
]a
|
||||
]a |> Enum.flat_map(fn el -> [el, :"#{el}!"] end)
|
||||
|
||||
@nonvoid_elements_aliases Enum.map(@nonvoid_elements, fn el ->
|
||||
Keyword.get(@aliases, el, el)
|
||||
|
|
|
@ -32,14 +32,14 @@ defmodule Temple.Parser.AnonymousFunctions do
|
|||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{elixir_ast: {name, _, args}, children: children}) do
|
||||
def to_eex(%{elixir_ast: {name, _, args}, children: children}, indent \\ 0) do
|
||||
{_do_and_else, args} = Temple.Parser.Utils.split_args(args)
|
||||
|
||||
{args, {func, _, [{arrow, _, [[{arg, _, _}], _block]}]}, args2} =
|
||||
Temple.Parser.Utils.split_on_fn(args, {[], nil, []})
|
||||
|
||||
[
|
||||
"<%= ",
|
||||
"#{Parser.Utils.indent(indent)}<%= ",
|
||||
to_string(name),
|
||||
" ",
|
||||
Enum.map(args, &Macro.to_string(&1)) |> Enum.join(", "),
|
||||
|
@ -51,16 +51,16 @@ defmodule Temple.Parser.AnonymousFunctions do
|
|||
to_string(arrow),
|
||||
" %>",
|
||||
"\n",
|
||||
for(child <- children, do: Temple.Generator.to_eex(child)),
|
||||
for(child <- children, do: Temple.Generator.to_eex(child, indent + 1)),
|
||||
if Enum.any?(args2) do
|
||||
[
|
||||
"<% end, ",
|
||||
"#{Parser.Utils.indent(indent)}<% end, ",
|
||||
Enum.map(args2, fn arg -> Macro.to_string(arg) end)
|
||||
|> Enum.join(", "),
|
||||
" %>"
|
||||
]
|
||||
else
|
||||
["<% end %>", "\n"]
|
||||
["#{Parser.Utils.indent(indent)}<% end %>", "\n"]
|
||||
end
|
||||
]
|
||||
end
|
||||
|
|
|
@ -2,6 +2,8 @@ defmodule Temple.Parser.Components do
|
|||
@moduledoc false
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser
|
||||
|
||||
defstruct module: nil, assigns: [], children: [], slots: []
|
||||
|
||||
@impl Temple.Parser
|
||||
|
@ -88,12 +90,12 @@ defmodule Temple.Parser.Components do
|
|||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{module: module, assigns: assigns, children: children, slots: slots}) do
|
||||
def to_eex(%{module: module, assigns: assigns, children: children, slots: slots}, indent \\ 0) do
|
||||
component_function = Temple.Config.mode().component_function
|
||||
renderer = Temple.Config.mode().renderer.(module)
|
||||
|
||||
[
|
||||
"<%= #{component_function} ",
|
||||
"#{Parser.Utils.indent(indent)}<%= #{component_function} ",
|
||||
renderer,
|
||||
", ",
|
||||
Macro.to_string(assigns),
|
||||
|
@ -102,23 +104,22 @@ defmodule Temple.Parser.Components do
|
|||
" do %>\n",
|
||||
if not Enum.empty?(children) do
|
||||
[
|
||||
"<% {:default, _} -> %>\n",
|
||||
for(child <- children, do: Temple.Generator.to_eex(child)),
|
||||
"\n"
|
||||
"#{Parser.Utils.indent(indent + 1)}<% {:default, _} -> %>\n",
|
||||
for(child <- children, do: Temple.Generator.to_eex(child, indent + 2))
|
||||
]
|
||||
else
|
||||
""
|
||||
end,
|
||||
for slot <- slots do
|
||||
[
|
||||
"<% {:",
|
||||
"#{Parser.Utils.indent(indent + 1)}<% {:",
|
||||
to_string(slot.name),
|
||||
", ",
|
||||
"#{Macro.to_string(slot.assigns)}} -> %>\n",
|
||||
for(child <- slot.content, do: Temple.Generator.to_eex(child))
|
||||
for(child <- slot.content, do: Temple.Generator.to_eex(child, indent + 2))
|
||||
]
|
||||
end,
|
||||
"<% end %>"
|
||||
"\n#{Parser.Utils.indent(indent)}<% end %>"
|
||||
]
|
||||
else
|
||||
" %>"
|
||||
|
|
|
@ -15,8 +15,8 @@ defmodule Temple.Parser.Default do
|
|||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{elixir_ast: expression}) do
|
||||
["<%= ", Macro.to_string(expression), " %>\n"]
|
||||
def to_eex(%{elixir_ast: expression}, indent \\ 0) do
|
||||
["#{Parser.Utils.indent(indent)}<%= ", Macro.to_string(expression), " %>"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,18 +30,23 @@ defmodule Temple.Parser.DoExpressions do
|
|||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{elixir_ast: expression, children: [do_body, else_body]}) do
|
||||
def to_eex(%{elixir_ast: expression, children: [do_body, else_body]}, indent \\ 0) do
|
||||
[
|
||||
"<%= ",
|
||||
"#{Parser.Utils.indent(indent)}<%= ",
|
||||
Macro.to_string(expression),
|
||||
" do %>",
|
||||
"\n",
|
||||
for(child <- do_body, do: Temple.Generator.to_eex(child)),
|
||||
for(child <- do_body, do: Temple.Generator.to_eex(child, indent + 1))
|
||||
|> Enum.intersperse("\n"),
|
||||
if(else_body != nil,
|
||||
do: ["<% else %>\n", for(child <- else_body, do: Temple.Generator.to_eex(child))],
|
||||
do: [
|
||||
"#{Parser.Utils.indent(indent)}\n<% else %>\n",
|
||||
for(child <- else_body, do: Temple.Generator.to_eex(child, indent + 1))
|
||||
|> Enum.intersperse("\n")
|
||||
],
|
||||
else: ""
|
||||
),
|
||||
"<% end %>"
|
||||
"\n#{Parser.Utils.indent(indent)}<% end %>"
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
33
lib/temple/parser/element_list.ex
Normal file
33
lib/temple/parser/element_list.ex
Normal file
|
@ -0,0 +1,33 @@
|
|||
defmodule Temple.Parser.ElementList do
|
||||
@moduledoc false
|
||||
|
||||
@behaviour Temple.Parser
|
||||
|
||||
defstruct children: [], whitespace: :loose
|
||||
|
||||
@impl Temple.Parser
|
||||
def applicable?(asts), do: is_list(asts)
|
||||
|
||||
@impl Temple.Parser
|
||||
def run(asts) do
|
||||
children = Enum.flat_map(asts, &Temple.Parser.parse/1)
|
||||
|
||||
Temple.Ast.new(__MODULE__, children: children)
|
||||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{children: children, whitespace: whitespace}, indent \\ 0) do
|
||||
child_indent = if whitespace == :loose, do: indent + 1, else: 0
|
||||
self_indent = if whitespace == :loose, do: indent, else: 0
|
||||
whitespace = if whitespace == :tight, do: [], else: ["\n"]
|
||||
|
||||
[
|
||||
whitespace,
|
||||
for(child <- children, do: Temple.Generator.to_eex(child, child_indent))
|
||||
|> Enum.intersperse("\n"),
|
||||
whitespace,
|
||||
Temple.Parser.Utils.indent(self_indent)
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -16,7 +16,7 @@ defmodule Temple.Parser.Empty do
|
|||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(_) do
|
||||
def to_eex(_, _ \\ 0) do
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,8 +19,8 @@ defmodule Temple.Parser.Match do
|
|||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{elixir_ast: elixir_ast}) do
|
||||
["<% ", Macro.to_string(elixir_ast), " %>"]
|
||||
def to_eex(%{elixir_ast: elixir_ast}, indent \\ 0) do
|
||||
["#{Parser.Utils.indent(indent)}<% ", Macro.to_string(elixir_ast), " %>"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ defmodule Temple.Parser.NonvoidElementsAliases do
|
|||
@moduledoc false
|
||||
@behaviour Temple.Parser
|
||||
|
||||
defstruct name: nil, attrs: [], children: []
|
||||
defstruct name: nil, attrs: [], children: [], meta: %{}
|
||||
|
||||
alias Temple.Parser
|
||||
|
||||
|
@ -23,18 +23,34 @@ defmodule Temple.Parser.NonvoidElementsAliases do
|
|||
|
||||
children = Temple.Parser.parse(do_and_else[:do])
|
||||
|
||||
Temple.Ast.new(__MODULE__, name: to_string(name), attrs: args, children: children)
|
||||
Temple.Ast.new(__MODULE__,
|
||||
name: to_string(name) |> String.replace_suffix("!", ""),
|
||||
attrs: args,
|
||||
children:
|
||||
Temple.Ast.new(Temple.Parser.ElementList,
|
||||
children: children,
|
||||
whitespace: whitespace(to_string(name))
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
defp whitespace(name) do
|
||||
if String.ends_with?(name, "!") do
|
||||
:tight
|
||||
else
|
||||
:loose
|
||||
end
|
||||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{name: name, attrs: attrs, children: children}) do
|
||||
def to_eex(%{name: name, attrs: attrs, children: children}, indent \\ 0) do
|
||||
[
|
||||
"<",
|
||||
"#{Parser.Utils.indent(indent)}<",
|
||||
name,
|
||||
Temple.Parser.Utils.compile_attrs(attrs),
|
||||
">\n",
|
||||
for(child <- children, do: Temple.Generator.to_eex(child)),
|
||||
"\n</",
|
||||
">",
|
||||
Temple.Generator.to_eex(children, indent),
|
||||
"</",
|
||||
name,
|
||||
">"
|
||||
]
|
||||
|
|
|
@ -18,12 +18,12 @@ defmodule Temple.Parser.RightArrow do
|
|||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{elixir_ast: elixir_ast, children: children}) do
|
||||
def to_eex(%{elixir_ast: elixir_ast, children: children}, indent \\ 0) do
|
||||
[
|
||||
"<% ",
|
||||
"#{Parser.Utils.indent(indent)}<% ",
|
||||
Macro.to_string(elixir_ast),
|
||||
" -> %>\n",
|
||||
for(child <- children, do: Temple.Generator.to_eex(child))
|
||||
for(child <- children, do: Temple.Generator.to_eex(child, indent + 1))
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule Temple.Parser.Slot do
|
||||
@moduledoc false
|
||||
@behaviour Temple.Parser
|
||||
alias Temple.Parser.Utils
|
||||
|
||||
defstruct name: nil, args: []
|
||||
|
||||
|
@ -26,15 +27,15 @@ defmodule Temple.Parser.Slot do
|
|||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{name: name, args: args}) do
|
||||
def to_eex(%{name: name, args: args}, indent \\ 0) do
|
||||
render_block_function = Temple.Config.mode().render_block_function
|
||||
|
||||
[
|
||||
"<%= #{render_block_function}(@inner_block, {:",
|
||||
"#{Utils.indent(indent)}<%= #{render_block_function}(@inner_block, {:",
|
||||
to_string(name),
|
||||
", ",
|
||||
Macro.to_string(quote(do: Enum.into(unquote(args), %{}))),
|
||||
"}) %>"
|
||||
"}) %>\n"
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,8 +16,8 @@ defmodule Temple.Parser.Text do
|
|||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{text: text}) do
|
||||
[text, "\n"]
|
||||
def to_eex(%{text: text}, indent \\ 0) do
|
||||
[Parser.Utils.indent(indent), text]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -113,4 +113,8 @@ defmodule Temple.Parser.Utils do
|
|||
def pop_compact?(args) do
|
||||
Keyword.pop(args, :compact, false)
|
||||
end
|
||||
|
||||
def indent(level) do
|
||||
String.duplicate(" ", level * 2)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,8 @@ defmodule Temple.Parser.VoidElementsAliases do
|
|||
@moduledoc false
|
||||
@behaviour Temple.Parser
|
||||
|
||||
alias Temple.Parser.Utils
|
||||
|
||||
defstruct name: nil, attrs: []
|
||||
|
||||
@impl Temple.Parser
|
||||
|
@ -28,12 +30,12 @@ defmodule Temple.Parser.VoidElementsAliases do
|
|||
end
|
||||
|
||||
defimpl Temple.Generator do
|
||||
def to_eex(%{name: name, attrs: attrs}) do
|
||||
def to_eex(%{name: name, attrs: attrs}, indent \\ 0) do
|
||||
[
|
||||
"<",
|
||||
"#{Utils.indent(indent)}<",
|
||||
to_string(name),
|
||||
Temple.Parser.Utils.compile_attrs(attrs),
|
||||
">\n"
|
||||
">"
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,7 +18,19 @@ defmodule Temple.ComponentTest do
|
|||
end
|
||||
|
||||
assert evaluate_template(result) ==
|
||||
~s{<div class="font-bold">Hello, world</div><div><aside class="foobar">I'm a component!</aside></div>}
|
||||
~s"""
|
||||
<div class="font-bold">
|
||||
Hello, world
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<aside class="foobar">
|
||||
I'm a component!
|
||||
</aside>
|
||||
|
||||
</div>
|
||||
|
||||
"""
|
||||
end
|
||||
|
||||
test "function components can accept local assigns" do
|
||||
|
@ -34,7 +46,16 @@ defmodule Temple.ComponentTest do
|
|||
end
|
||||
|
||||
assert evaluate_template(result) ==
|
||||
~s{<div class="font-bold">Hello, world</div><div class="bg-red">I'm a component!</div>}
|
||||
~s"""
|
||||
<div class="font-bold">
|
||||
Hello, world
|
||||
</div>
|
||||
<div class="bg-red">
|
||||
|
||||
I'm a component!
|
||||
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "function components can use other components" do
|
||||
|
@ -50,8 +71,21 @@ defmodule Temple.ComponentTest do
|
|||
end
|
||||
|
||||
assert evaluate_template(result) == ~s"""
|
||||
<div id="inner" outer-id="from-outer">outer!</div>
|
||||
<div id="inner" outer-id="set by root inner">inner!</div>
|
||||
<div id="inner" outer-id="from-outer">
|
||||
|
||||
|
||||
outer!
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="inner" outer-id="set by root inner">
|
||||
|
||||
inner!
|
||||
|
||||
</div>
|
||||
|
||||
"""
|
||||
end
|
||||
|
||||
|
@ -63,7 +97,14 @@ defmodule Temple.ComponentTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert evaluate_template(result) == ~s{<div class="barbarbar">doo doo</div>}
|
||||
assert evaluate_template(result) == ~s"""
|
||||
<div class="barbarbar">
|
||||
|
||||
doo doo
|
||||
|
||||
</div>
|
||||
|
||||
"""
|
||||
end
|
||||
|
||||
test "components can be void elements" do
|
||||
|
@ -72,7 +113,11 @@ defmodule Temple.ComponentTest do
|
|||
c Temple.Components.VoidComponent, foo: :bar
|
||||
end
|
||||
|
||||
assert evaluate_template(result) == ~s{<div class="void!!">bar</div>}
|
||||
assert evaluate_template(result) == ~s"""
|
||||
<div class="void!!">
|
||||
bar
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "components can have named slots" do
|
||||
|
@ -94,6 +139,22 @@ defmodule Temple.ComponentTest do
|
|||
end
|
||||
|
||||
assert evaluate_template(result, assigns) ==
|
||||
~s{<div><div>the value is Header</div><div class="wrapped"><button class="btn" phx-click="toggle">bob</button></div></div>}
|
||||
~s"""
|
||||
<div>
|
||||
|
||||
<div>
|
||||
the value is Header
|
||||
</div>
|
||||
|
||||
<div class="wrapped">
|
||||
|
||||
<button class="btn" phx-click="toggle">
|
||||
bob
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,9 +7,9 @@ defmodule Temple.Parser.AnonymousFunctionsTest do
|
|||
test "returns true when the node contains an anonymous function as an argument to a function" do
|
||||
raw_asts = [
|
||||
quote do
|
||||
form_for changeset, Routes.foo_path(conn, :create), fn form ->
|
||||
form_for(changeset, Routes.foo_path(conn, :create), fn form ->
|
||||
Does.something!(form)
|
||||
end
|
||||
end)
|
||||
end
|
||||
]
|
||||
|
||||
|
@ -47,9 +47,9 @@ defmodule Temple.Parser.AnonymousFunctionsTest do
|
|||
|
||||
raw_ast =
|
||||
quote do
|
||||
form_for changeset, Routes.foo_path(conn, :create), fn form ->
|
||||
form_for(changeset, Routes.foo_path(conn, :create), fn form ->
|
||||
unquote(expected_child)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
ast = AnonymousFunctions.run(raw_ast)
|
||||
|
@ -69,9 +69,9 @@ defmodule Temple.Parser.AnonymousFunctionsTest do
|
|||
test "emits eex" do
|
||||
raw_ast =
|
||||
quote do
|
||||
form_for changeset, Routes.foo_path(conn, :create), fn form ->
|
||||
form_for(changeset, Routes.foo_path(conn, :create), fn form ->
|
||||
Does.something!(form)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
result =
|
||||
|
|
|
@ -187,7 +187,12 @@ defmodule Temple.Parser.ComponentsTest do
|
|||
|> Temple.Generator.to_eex()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() ==
|
||||
~s|<%= Temple.Component.__component__ SomeModule, [foo: :bar] do %>\n<% {:default, _} -> %>\nI'm a component!\n<% end %>|
|
||||
~s"""
|
||||
<%= Temple.Component.__component__ SomeModule, [foo: :bar] do %>
|
||||
<% {:default, _} -> %>
|
||||
I'm a component!
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "emits eex for void component with slots" do
|
||||
|
@ -208,7 +213,14 @@ defmodule Temple.Parser.ComponentsTest do
|
|||
|> Temple.Generator.to_eex()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() ==
|
||||
~s|<%= Temple.Component.__component__ SomeModule, [foo: :bar] do %>\n<% {:foo, %{form: form}} -> %>\n<div>\nin the slot\n\n</div>\n<% end %>|
|
||||
~s"""
|
||||
<%= Temple.Component.__component__ SomeModule, [foo: :bar] do %>
|
||||
<% {:foo, %{form: form}} -> %>
|
||||
<div>
|
||||
in the slot
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "emits eex for nonvoid component with slots" do
|
||||
|
@ -233,7 +245,18 @@ defmodule Temple.Parser.ComponentsTest do
|
|||
|> Temple.Generator.to_eex()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() ==
|
||||
~s|<%= Temple.Component.__component__ SomeModule, [foo: :bar] do %>\n<% {:default, _} -> %>\n<div>\ninner content\n\n</div>\n<% {:foo, %{form: form}} -> %><div>\nin the slot\n\n</div><% end %>|
|
||||
~s"""
|
||||
<%= Temple.Component.__component__ SomeModule, [foo: :bar] do %>
|
||||
<% {:default, _} -> %>
|
||||
<div>
|
||||
inner content
|
||||
</div>
|
||||
<% {:foo, %{form: form}} -> %>
|
||||
<div>
|
||||
in the slot
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "emits eex for void component" do
|
||||
|
|
|
@ -2,6 +2,7 @@ defmodule Temple.Parser.DefaultTest do
|
|||
use ExUnit.Case, async: true
|
||||
|
||||
alias Temple.Parser.Default
|
||||
alias Temple.Support.Utils
|
||||
|
||||
describe "applicable?/1" do
|
||||
test "returns true when the node is an elixir expression" do
|
||||
|
@ -35,8 +36,11 @@ defmodule Temple.Parser.DefaultTest do
|
|||
end
|
||||
|> Default.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> Utils.iolist_to_binary()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() == ~s|<%= Foo.bar!(baz) %>\n|
|
||||
assert result == ~s"""
|
||||
<%= Foo.bar!(baz) %>
|
||||
"""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ defmodule Temple.Parser.DoExpressionsTest do
|
|||
use ExUnit.Case, async: true
|
||||
|
||||
alias Temple.Parser.DoExpressions
|
||||
alias Temple.Support.Utils
|
||||
|
||||
describe "applicable?/1" do
|
||||
test "returns true when the node contains a do expression" do
|
||||
|
@ -47,9 +48,14 @@ defmodule Temple.Parser.DoExpressionsTest do
|
|||
end
|
||||
|> DoExpressions.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> Utils.iolist_to_binary()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() ==
|
||||
~s|<%= for(big <- boys) do %>\nbob\n<% end %>|
|
||||
assert result ==
|
||||
~s"""
|
||||
<%= for(big <- boys) do %>
|
||||
bob
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "emits eex for that includes in else clause" do
|
||||
|
@ -65,9 +71,17 @@ defmodule Temple.Parser.DoExpressionsTest do
|
|||
end
|
||||
|> DoExpressions.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> Utils.iolist_to_binary()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() ==
|
||||
~s|<%= if(foo?) do %>\nbob\nbobby\n<% else %>\ncarol\n<% end %>|
|
||||
assert result ==
|
||||
~s"""
|
||||
<%= if(foo?) do %>
|
||||
bob
|
||||
bobby
|
||||
<% else %>
|
||||
carol
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "emits eex for a case expression" do
|
||||
|
@ -80,9 +94,15 @@ defmodule Temple.Parser.DoExpressionsTest do
|
|||
end
|
||||
|> DoExpressions.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> Utils.iolist_to_binary()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() ==
|
||||
~s|<%= case(foo?) do %>\n<% :bing -> %>\n<%= :bong %>\n<% end %>|
|
||||
assert result ==
|
||||
~s"""
|
||||
<%= case(foo?) do %>
|
||||
<% :bing -> %>
|
||||
<%= :bong %>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,8 @@ defmodule Temple.Parser.NonvoidElementsAliasesTest do
|
|||
use ExUnit.Case, async: true
|
||||
|
||||
alias Temple.Parser.NonvoidElementsAliases
|
||||
alias Temple.Parser.ElementList
|
||||
alias Temple.Support.Utils
|
||||
|
||||
describe "applicable?/1" do
|
||||
test "returns true when the node is a nonvoid element or alias" do
|
||||
|
@ -63,19 +65,25 @@ defmodule Temple.Parser.NonvoidElementsAliasesTest do
|
|||
assert %NonvoidElementsAliases{
|
||||
name: "div",
|
||||
attrs: [class: "foo", id: {:var, [], _}],
|
||||
children: [
|
||||
%NonvoidElementsAliases{
|
||||
name: "select",
|
||||
children: [
|
||||
%NonvoidElementsAliases{
|
||||
name: "option",
|
||||
children: %ElementList{
|
||||
children: [
|
||||
%NonvoidElementsAliases{
|
||||
name: "select",
|
||||
children: %ElementList{
|
||||
children: [
|
||||
%Temple.Parser.Text{text: "foo"}
|
||||
%NonvoidElementsAliases{
|
||||
name: "option",
|
||||
children: %ElementList{
|
||||
children: [
|
||||
%Temple.Parser.Text{text: "foo"}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
} = ast
|
||||
end
|
||||
end
|
||||
|
@ -94,9 +102,44 @@ defmodule Temple.Parser.NonvoidElementsAliasesTest do
|
|||
end
|
||||
|> NonvoidElementsAliases.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> Utils.iolist_to_binary()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() ==
|
||||
~s|<div class="foo"<%= {:safe, Temple.Parser.Utils.build_attr("id", var)} %>>\n<select>\n<option>\nfoo\n\n</option>\n</select>\n</div>|
|
||||
assert result ==
|
||||
~s"""
|
||||
<div class="foo"<%= {:safe, Temple.Parser.Utils.build_attr("id", var)} %>>
|
||||
<select>
|
||||
<option>
|
||||
foo
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "produce 'tight' markup" do
|
||||
result =
|
||||
quote do
|
||||
div class: "foo", id: var do
|
||||
select__ do
|
||||
option! do
|
||||
"foo"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|> NonvoidElementsAliases.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> :erlang.iolist_to_binary()
|
||||
|> Kernel.<>("\n")
|
||||
|
||||
assert result ==
|
||||
~s"""
|
||||
<div class="foo"<%= {:safe, Temple.Parser.Utils.build_attr("id", var)} %>>
|
||||
<select>
|
||||
<option>foo</option>
|
||||
</select>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ defmodule Temple.Parser.RightArrowTest do
|
|||
use ExUnit.Case, async: true
|
||||
|
||||
alias Temple.Parser.RightArrow
|
||||
alias Temple.Support.Utils
|
||||
|
||||
describe "applicable?/1" do
|
||||
test "returns true when the node contains a right arrow" do
|
||||
|
@ -70,9 +71,13 @@ defmodule Temple.Parser.RightArrowTest do
|
|||
|> List.first()
|
||||
|> RightArrow.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> Utils.iolist_to_binary()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() ==
|
||||
~s|<% :bing -> %>\n<%= :bong %>\n|
|
||||
assert result ==
|
||||
~s"""
|
||||
<% :bing -> %>
|
||||
<%= :bong %>
|
||||
"""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -42,7 +42,9 @@ defmodule Temple.Parser.SlotTest do
|
|||
|> Temple.Generator.to_eex()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() ==
|
||||
~s|<%= Temple.Component.__render_block__(@inner_block, {:header, Enum.into([value: Form.form_for(changeset, action)], %{})}) %>|
|
||||
~s"""
|
||||
<%= Temple.Component.__render_block__(@inner_block, {:header, Enum.into([value: Form.form_for(changeset, action)], %{})}) %>
|
||||
"""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ defmodule Temple.Parser.TempleNamespaceNonvoidTest do
|
|||
|
||||
alias Temple.Parser.NonvoidElementsAliases
|
||||
alias Temple.Parser.TempleNamespaceNonvoid
|
||||
alias Temple.Support.Utils
|
||||
|
||||
describe "applicable?/1" do
|
||||
test "returns true when the node is a Temple aliased nonvoid element" do
|
||||
|
@ -50,7 +51,10 @@ defmodule Temple.Parser.TempleNamespaceNonvoidTest do
|
|||
assert %NonvoidElementsAliases{
|
||||
name: "div",
|
||||
attrs: [class: "foo", id: {:var, [], _}],
|
||||
children: [%Temple.Parser.Text{text: "foo"}]
|
||||
children: %Temple.Parser.ElementList{
|
||||
children: [%Temple.Parser.Text{text: "foo"}],
|
||||
whitespace: :loose
|
||||
}
|
||||
} = ast
|
||||
end
|
||||
end
|
||||
|
@ -65,9 +69,14 @@ defmodule Temple.Parser.TempleNamespaceNonvoidTest do
|
|||
end
|
||||
|> TempleNamespaceNonvoid.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> Utils.iolist_to_binary()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() ==
|
||||
~s|<div class="foo"<%= {:safe, Temple.Parser.Utils.build_attr("id", var)} %>>\nfoo\n\n</div>|
|
||||
assert result ==
|
||||
~s"""
|
||||
<div class="foo"<%= {:safe, Temple.Parser.Utils.build_attr("id", var)} %>>
|
||||
foo
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ defmodule Temple.Parser.TempleNamespaceVoidTest do
|
|||
|
||||
alias Temple.Parser.TempleNamespaceVoid
|
||||
alias Temple.Parser.VoidElementsAliases
|
||||
alias Temple.Support.Utils
|
||||
|
||||
describe "applicable?/1" do
|
||||
test "returns true when the node is a Temple aliased nonvoid element" do
|
||||
|
@ -58,8 +59,9 @@ defmodule Temple.Parser.TempleNamespaceVoidTest do
|
|||
end
|
||||
|> TempleNamespaceVoid.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> Utils.iolist_to_binary()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() == ~s|<meta content="foo">\n|
|
||||
assert result == ~s|<meta content="foo">\n|
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ defmodule Temple.Parser.TextTest do
|
|||
use ExUnit.Case, async: true
|
||||
|
||||
alias Temple.Parser.Text
|
||||
alias Temple.Support.Utils
|
||||
|
||||
describe "applicable?/1" do
|
||||
test "returns true when the node is a string literal" do
|
||||
|
@ -35,8 +36,9 @@ defmodule Temple.Parser.TextTest do
|
|||
"string literal"
|
||||
|> Text.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> Utils.iolist_to_binary()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() == ~s|string literal\n|
|
||||
assert result == ~s|string literal\n|
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ defmodule Temple.Parser.VoidElementsAliasesTest do
|
|||
use ExUnit.Case, async: true
|
||||
|
||||
alias Temple.Parser.VoidElementsAliases
|
||||
alias Temple.Support.Utils
|
||||
|
||||
describe "applicable?/1" do
|
||||
test "returns true when the node is a nonvoid element or alias" do
|
||||
|
@ -63,8 +64,9 @@ defmodule Temple.Parser.VoidElementsAliasesTest do
|
|||
end
|
||||
|> VoidElementsAliases.run()
|
||||
|> Temple.Generator.to_eex()
|
||||
|> Utils.iolist_to_binary()
|
||||
|
||||
assert result |> :erlang.iolist_to_binary() == ~s|<meta content="foo">\n|
|
||||
assert result == ~s|<meta content="foo">\n|
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,4 +33,20 @@ defmodule Temple.Support.Utils do
|
|||
|> elem(0)
|
||||
|> Phoenix.HTML.safe_to_string()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Converts an iolist to a binary and appends a new line.
|
||||
"""
|
||||
def iolist_to_binary(iolist) do
|
||||
iolist
|
||||
|> :erlang.iolist_to_binary()
|
||||
|> append_new_line()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Appends a new line to a string.
|
||||
"""
|
||||
def append_new_line(string) do
|
||||
string <> "\n"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,7 +11,12 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert result == ~s{<div class="hello"><div class="hi"></div></div>}
|
||||
assert result == ~s"""
|
||||
<div class="hello">
|
||||
<div class="hi">
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders void element" do
|
||||
|
@ -32,7 +37,12 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert result == ~s{<div class="hello">hifoo</div>}
|
||||
assert result == ~s"""
|
||||
<div class="hello">
|
||||
hi
|
||||
foo
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders a variable text node as eex" do
|
||||
|
@ -43,7 +53,11 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert result == ~s{<div class="hello"><%= foo %></div>}
|
||||
assert result == ~s"""
|
||||
<div class="hello">
|
||||
<%= foo %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders an assign text node as eex" do
|
||||
|
@ -54,7 +68,11 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert result == ~s{<div class="hello"><%= @foo %></div>}
|
||||
assert result == ~s"""
|
||||
<div class="hello">
|
||||
<%= @foo %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders a match expression" do
|
||||
|
@ -67,7 +85,12 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert result == ~s{<% x = 420 %><div>blaze it</div>}
|
||||
assert result == ~s"""
|
||||
<% x = 420 %>
|
||||
<div>
|
||||
blaze it
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders a non-match expression" do
|
||||
|
@ -80,7 +103,12 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert result == ~s{<%= IO.inspect(:foo) %><div>bar</div>}
|
||||
assert result == ~s"""
|
||||
<%= IO.inspect(:foo) %>
|
||||
<div>
|
||||
bar
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders an expression in attr as eex" do
|
||||
|
@ -102,7 +130,12 @@ defmodule TempleTest do
|
|||
end
|
||||
|
||||
assert result ==
|
||||
~s|<div<%= {:safe, Temple.Parser.Utils.build_attr("class", Enum.map([:one, :two], fn x -> x end))} %>><div class="hi"></div></div>|
|
||||
~s"""
|
||||
<div<%= {:safe, Temple.Parser.Utils.build_attr("class", Enum.map([:one, :two], fn x -> x end))} %>>
|
||||
<div class="hi">
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders a for comprehension as eex" do
|
||||
|
@ -113,7 +146,12 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert result == ~s{<%= for(x <- 1..5) do %><div class="hi"></div><% end %>}
|
||||
assert result == ~s"""
|
||||
<%= for(x <- 1..5) do %>
|
||||
<div class="hi">
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders an if expression as eex" do
|
||||
|
@ -124,7 +162,12 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert result == ~s{<%= if(true == false) do %><div class="hi"></div><% end %>}
|
||||
assert result == ~s"""
|
||||
<%= if(true == false) do %>
|
||||
<div class="hi">
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders an if/else expression as eex" do
|
||||
|
@ -138,7 +181,15 @@ defmodule TempleTest do
|
|||
end
|
||||
|
||||
assert result ==
|
||||
~s{<%= if(true == false) do %><div class="hi"></div><% else %><div class="haha"></div><% end %>}
|
||||
~s"""
|
||||
<%= if(true == false) do %>
|
||||
<div class="hi">
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="haha">
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders an unless expression as eex" do
|
||||
|
@ -149,7 +200,12 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert result == ~s{<%= unless(true == false) do %><div class="hi"></div><% end %>}
|
||||
assert result == ~s"""
|
||||
<%= unless(true == false) do %>
|
||||
<div class="hi">
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders a case expression as eex" do
|
||||
|
@ -161,14 +217,12 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
expected =
|
||||
~S"""
|
||||
<%= case(@foo) do %>
|
||||
expected = ~S"""
|
||||
<%= case(@foo) do %>
|
||||
<% :baz -> %>
|
||||
<%= some_component(form: @form) %>
|
||||
<% end %>
|
||||
"""
|
||||
|> String.trim()
|
||||
<%= some_component(form: @form) %>
|
||||
<% end %>
|
||||
"""
|
||||
|
||||
assert result == expected
|
||||
end
|
||||
|
@ -176,70 +230,99 @@ defmodule TempleTest do
|
|||
test "renders multiline anonymous function with 1 arg before the function" do
|
||||
result =
|
||||
temple do
|
||||
form_for Routes.user_path(@conn, :create), fn f ->
|
||||
form_for(Routes.user_path(@conn, :create), fn f ->
|
||||
"Name: "
|
||||
text_input f, :name
|
||||
end
|
||||
text_input(f, :name)
|
||||
end)
|
||||
end
|
||||
|
||||
assert result ==
|
||||
~s{<%= form_for Routes.user_path(@conn, :create), fn f -> %>Name: <%= text_input(f, :name) %><% end %>}
|
||||
~s"""
|
||||
<%= form_for Routes.user_path(@conn, :create), fn f -> %>
|
||||
Name:
|
||||
<%= text_input(f, :name) %>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders multiline anonymous functions with 2 args before the function" do
|
||||
result =
|
||||
temple do
|
||||
form_for @changeset, Routes.user_path(@conn, :create), fn f ->
|
||||
form_for(@changeset, Routes.user_path(@conn, :create), fn f ->
|
||||
"Name: "
|
||||
text_input f, :name
|
||||
end
|
||||
text_input(f, :name)
|
||||
end)
|
||||
end
|
||||
|
||||
assert result ==
|
||||
~s{<%= form_for @changeset, Routes.user_path(@conn, :create), fn f -> %>Name: <%= text_input(f, :name) %><% end %>}
|
||||
~s"""
|
||||
<%= form_for @changeset, Routes.user_path(@conn, :create), fn f -> %>
|
||||
Name:
|
||||
<%= text_input(f, :name) %>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders multiline anonymous functions with complex nested children" do
|
||||
result =
|
||||
temple do
|
||||
form_for @changeset, Routes.user_path(@conn, :create), fn f ->
|
||||
form_for(@changeset, Routes.user_path(@conn, :create), fn f ->
|
||||
div do
|
||||
"Name: "
|
||||
text_input f, :name
|
||||
text_input(f, :name)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
assert result ==
|
||||
~s{<%= form_for @changeset, Routes.user_path(@conn, :create), fn f -> %><div>Name: <%= text_input(f, :name) %></div><% end %>}
|
||||
~s"""
|
||||
<%= form_for @changeset, Routes.user_path(@conn, :create), fn f -> %>
|
||||
<div>
|
||||
Name:
|
||||
<%= text_input(f, :name) %>
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders multiline anonymous function with 3 arg before the function" do
|
||||
result =
|
||||
temple do
|
||||
form_for @changeset, Routes.user_path(@conn, :create), [foo: :bar], fn f ->
|
||||
form_for(@changeset, Routes.user_path(@conn, :create), [foo: :bar], fn f ->
|
||||
"Name: "
|
||||
text_input f, :name
|
||||
end
|
||||
text_input(f, :name)
|
||||
end)
|
||||
end
|
||||
|
||||
assert result ==
|
||||
~s{<%= form_for @changeset, Routes.user_path(@conn, :create), [foo: :bar], fn f -> %>Name: <%= text_input(f, :name) %><% end %>}
|
||||
~s"""
|
||||
<%= form_for @changeset, Routes.user_path(@conn, :create), [foo: :bar], fn f -> %>
|
||||
Name:
|
||||
<%= text_input(f, :name) %>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "renders multiline anonymous function with 1 arg before the function and 1 arg after" do
|
||||
result =
|
||||
temple do
|
||||
form_for @changeset,
|
||||
fn f ->
|
||||
"Name: "
|
||||
text_input f, :name
|
||||
end,
|
||||
foo: :bar
|
||||
form_for(
|
||||
@changeset,
|
||||
fn f ->
|
||||
"Name: "
|
||||
text_input(f, :name)
|
||||
end,
|
||||
foo: :bar
|
||||
)
|
||||
end
|
||||
|
||||
assert result ==
|
||||
~s{<%= form_for @changeset, fn f -> %>Name: <%= text_input(f, :name) %><% end, [foo: :bar] %>}
|
||||
~s"""
|
||||
<%= form_for @changeset, fn f -> %>
|
||||
Name:
|
||||
<%= text_input(f, :name) %>
|
||||
<% end, [foo: :bar] %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "tags prefixed with Temple. should be interpreted as temple tags" do
|
||||
|
@ -252,7 +335,13 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert result == ~s{<div><span>bob</span></div>}
|
||||
assert result == ~s"""
|
||||
<div>
|
||||
<span>
|
||||
bob
|
||||
</span>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "can pass do as an arg instead of a block" do
|
||||
|
@ -267,7 +356,17 @@ defmodule TempleTest do
|
|||
end
|
||||
|
||||
assert result ==
|
||||
~s{<div class="font-bold">Hello, world</div><div class="font-bold">Hello, world</div><div>Hello, world</div>}
|
||||
~s"""
|
||||
<div class="font-bold">
|
||||
Hello, world
|
||||
</div>
|
||||
<div class="font-bold">
|
||||
Hello, world
|
||||
</div>
|
||||
<div>
|
||||
Hello, world
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "for with 2 generators" do
|
||||
|
@ -280,7 +379,16 @@ defmodule TempleTest do
|
|||
end
|
||||
|
||||
assert result ==
|
||||
~s{<%= for(x <- 1..5, y <- 6..10) do %><div><%= x %></div><div><%= y %></div><% end %>}
|
||||
~s"""
|
||||
<%= for(x <- 1..5, y <- 6..10) do %>
|
||||
<div>
|
||||
<%= x %>
|
||||
</div>
|
||||
<div>
|
||||
<%= y %>
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
test "can pass an expression as assigns" do
|
||||
|
@ -292,7 +400,15 @@ defmodule TempleTest do
|
|||
end
|
||||
|
||||
assert result ==
|
||||
~s{<fieldset<%= Temple.Parser.Utils.runtime_attrs(if(true == false) do [disabled: true]else []end) %>><input type="text"></fieldset>}
|
||||
~s"""
|
||||
<fieldset<%= Temple.Parser.Utils.runtime_attrs(if(true == false) do
|
||||
[disabled: true]
|
||||
else
|
||||
[]
|
||||
end) %>>
|
||||
<input type="text">
|
||||
</fieldset>
|
||||
"""
|
||||
end
|
||||
|
||||
test "can pass a variable as assigns" do
|
||||
|
@ -304,7 +420,11 @@ defmodule TempleTest do
|
|||
end
|
||||
|
||||
assert result ==
|
||||
~s{<fieldset<%= Temple.Parser.Utils.runtime_attrs(foo_bar) %>><input type="text"></fieldset>}
|
||||
~s"""
|
||||
<fieldset<%= Temple.Parser.Utils.runtime_attrs(foo_bar) %>>
|
||||
<input type="text">
|
||||
</fieldset>
|
||||
"""
|
||||
end
|
||||
|
||||
test "can pass a function as assigns" do
|
||||
|
@ -316,7 +436,11 @@ defmodule TempleTest do
|
|||
end
|
||||
|
||||
assert result ==
|
||||
~s{<fieldset<%= Temple.Parser.Utils.runtime_attrs(Foo.foo_bar()) %>><input type="text"></fieldset>}
|
||||
~s"""
|
||||
<fieldset<%= Temple.Parser.Utils.runtime_attrs(Foo.foo_bar()) %>>
|
||||
<input type="text">
|
||||
</fieldset>
|
||||
"""
|
||||
end
|
||||
|
||||
test "hr tag works" do
|
||||
|
@ -334,7 +458,23 @@ defmodule TempleTest do
|
|||
end
|
||||
|
||||
assert evaluate_template(result, assigns) ==
|
||||
~s{<div>foo</div><hr><div>foo</div><hr class="foofoo"><div>bar</div><hr class="foofoo"><div>bar</div>}
|
||||
~s"""
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
<hr class="foofoo">
|
||||
<div>
|
||||
bar
|
||||
</div>
|
||||
<hr class="foofoo">
|
||||
<div>
|
||||
bar
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
test "boolean attributes" do
|
||||
|
@ -363,6 +503,10 @@ defmodule TempleTest do
|
|||
end
|
||||
end
|
||||
|
||||
assert evaluate_template(result, assigns) == ~s{<div class="text-red">\nfoo\n\n</div>}
|
||||
assert evaluate_template(result, assigns) == ~s"""
|
||||
<div class="text-red">
|
||||
foo
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
|
46
test/whitespace_test.exs
Normal file
46
test/whitespace_test.exs
Normal file
|
@ -0,0 +1,46 @@
|
|||
defmodule Temple.WhitespaceTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
import Temple
|
||||
|
||||
alias Temple.Support.Utils
|
||||
|
||||
test "only emits a single new line" do
|
||||
result =
|
||||
temple do
|
||||
div class: "hello" do
|
||||
span id: "foo" do
|
||||
"Howdy, "
|
||||
end
|
||||
|
||||
div class: "hi" do
|
||||
"Jim Bob"
|
||||
end
|
||||
|
||||
c WhoaNelly, foo: "bar" do
|
||||
slot :silver do
|
||||
"esketit"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|> Utils.append_new_line()
|
||||
|
||||
expected = ~s"""
|
||||
<div class="hello">
|
||||
<span id="foo">
|
||||
Howdy,
|
||||
</span>
|
||||
<div class="hi">
|
||||
Jim Bob
|
||||
</div>
|
||||
<%= Temple.Component.__component__ WhoaNelly, [foo: "bar"] do %>
|
||||
<% {:silver, %{}} -> %>
|
||||
esketit
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
|
||||
assert result == expected
|
||||
end
|
||||
end
|
Reference in a new issue