Skip to content

Commit 6e38598

Browse files
authored
Optimize and unify TreeDOM.all/filter (#3937)
1 parent dd9bf61 commit 6e38598

File tree

5 files changed

+40
-53
lines changed

5 files changed

+40
-53
lines changed

lib/phoenix_live_view/test/client_proxy.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,9 +1630,9 @@ defmodule Phoenix.LiveViewTest.ClientProxy do
16301630
defp maybe_put_cid(payload, cid), do: Map.put(payload, "cid", cid)
16311631

16321632
defp root_page_title(root_html) do
1633-
case TreeDOM.all(root_html, fn node -> TreeDOM.tag(node) == "head" end) do
1633+
case TreeDOM.filter(root_html, fn node -> TreeDOM.tag(node) == "head" end) do
16341634
[node] ->
1635-
case TreeDOM.all(node, fn node -> TreeDOM.tag(node) == "title" end) do
1635+
case TreeDOM.filter(node, fn node -> TreeDOM.tag(node) == "title" end) do
16361636
[title] -> TreeDOM.to_text(title)
16371637
_ -> nil
16381638
end

lib/phoenix_live_view/test/tree_dom.ex

Lines changed: 35 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,10 @@ defmodule Phoenix.LiveViewTest.TreeDOM do
1616
@doc """
1717
Filters nodes and returns them in reverse order.
1818
"""
19-
def reverse_filter(node, fun) do
20-
node
21-
|> LazyHTML.Tree.postwalk([], fn node, acc ->
22-
if fun.(node), do: {node, [node | acc]}, else: {node, acc}
19+
def reverse_filter(tree, fun) do
20+
reduce(tree, [], fn x, acc ->
21+
if fun.(x), do: [x | acc], else: acc
2322
end)
24-
|> elem(1)
25-
end
26-
27-
@doc """
28-
Finds all nodes that match `fun`. Walks the tree in a pre-walk manner, visiting parents before children.
29-
"""
30-
def all(node, fun) do
31-
prewalk(node, fun, [])
32-
|> Enum.reverse()
3323
end
3424

3525
@doc """
@@ -158,18 +148,41 @@ defmodule Phoenix.LiveViewTest.TreeDOM do
158148
defp value_key(_), do: nil
159149

160150
@doc """
161-
Walks the tree and updates nodes based on the given function.
151+
Reduces the tree with the given function.
162152
"""
163-
def walk(tree, fun) when is_function(fun, 1) do
164-
LazyHTML.Tree.postwalk(tree, walk_fun(fun))
153+
def reduce(tree, acc, fun) when is_function(fun, 2) do
154+
do_reduce(tree, acc, fn
155+
text, acc when is_binary(text) -> acc
156+
{:comment, _children}, acc -> acc
157+
{_tag, _attrs, _children} = node, acc -> fun.(node, acc)
158+
end)
165159
end
166160

167-
defp walk_fun(fun) when is_function(fun, 1) do
168-
fn
161+
defp do_reduce([], acc, _fun), do: acc
162+
163+
defp do_reduce([node | rest], acc, fun) do
164+
acc = do_reduce(node, acc, fun)
165+
do_reduce(rest, acc, fun)
166+
end
167+
168+
defp do_reduce({tag, attrs, children}, acc, fun) do
169+
acc = fun.({tag, attrs, children}, acc)
170+
do_reduce(children, acc, fun)
171+
end
172+
173+
defp do_reduce(node, acc, fun) do
174+
fun.(node, acc)
175+
end
176+
177+
@doc """
178+
Walks the tree and updates nodes based on the given function.
179+
"""
180+
def walk(tree, fun) when is_function(fun, 1) do
181+
LazyHTML.Tree.postwalk(tree, fn
169182
text when is_binary(text) -> text
170183
{:comment, _children} = comment -> comment
171184
{_tag, _attrs, _children} = node -> fun.(node)
172-
end
185+
end)
173186
end
174187

175188
defp by_id(tree, id) do
@@ -201,40 +214,14 @@ defmodule Phoenix.LiveViewTest.TreeDOM do
201214
def inspect_html(dom_node),
202215
do: " " <> String.replace(to_html(dom_node), "\n", "\n ") <> "\n"
203216

204-
defp prewalk([], _fun, acc), do: List.flatten(acc)
205-
defp prewalk(text, _fun, acc) when is_binary(text), do: acc
206-
defp prewalk({:comment, _children} = _comment, _fun, acc), do: acc
207-
208-
defp prewalk({_tag, _attrs, children} = node, fun, acc) do
209-
new_acc =
210-
if fun.(node) do
211-
[node | acc]
212-
else
213-
acc
214-
end
215-
216-
prewalk_children(children, fun, new_acc)
217-
end
218-
219-
defp prewalk(list, fun, acc) when is_list(list) do
220-
prewalk_children(list, fun, acc)
221-
end
222-
223-
defp prewalk_children([], _fun, acc), do: acc
224-
225-
defp prewalk_children([head | tail], fun, acc) do
226-
new_acc = prewalk(head, fun, acc)
227-
prewalk_children(tail, fun, new_acc)
228-
end
229-
230217
### Functions specific for LiveView
231218

232219
@doc """
233220
Find live views in the given HTML tree.
234221
"""
235222
def find_live_views(tree) do
236223
tree
237-
|> all(fn node -> attribute(node, "data-phx-session") end)
224+
|> filter(fn node -> attribute(node, "data-phx-session") end)
238225
|> Enum.map(fn {_, attributes, _} -> attributes end)
239226
|> parse_live_views_attributes()
240227
end
@@ -321,7 +308,7 @@ defmodule Phoenix.LiveViewTest.TreeDOM do
321308
error_reporter.("""
322309
Duplicate id found while testing LiveView: #{id}
323310
324-
#{inspect_html(all(tree, fn node -> attribute(node, "id") == id end))}
311+
#{inspect_html(filter(tree, fn node -> attribute(node, "id") == id end))}
325312
326313
LiveView requires that all elements have unique ids, duplicate IDs will cause
327314
undefined behavior at runtime, as DOM patching will not be able to target the correct
@@ -346,7 +333,7 @@ defmodule Phoenix.LiveViewTest.TreeDOM do
346333
error_reporter.("""
347334
Duplicate live component found while testing LiveView:
348335
349-
#{inspect_html(all(tree, fn node -> attribute(node, @phx_component) == to_string(cid) end))}
336+
#{inspect_html(filter(tree, fn node -> attribute(node, @phx_component) == to_string(cid) end))}
350337
351338
This most likely means that you are conditionally rendering the same
352339
LiveComponent multiple times with the same ID in the same LiveView.

test/phoenix_component/components_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ defmodule Phoenix.LiveView.ComponentsTest do
621621
"""
622622

623623
html = t2h(template)
624-
assert [p] = TreeDOM.all(html, &(TreeDOM.tag(&1) == "p"))
624+
assert [p] = TreeDOM.filter(html, &(TreeDOM.tag(&1) == "p"))
625625
assert TreeDOM.to_text(p) =~ "bar"
626626
end
627627

test/phoenix_live_view/integrations/stream_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ defmodule Phoenix.LiveView.StreamTest do
780780
html
781781
|> TreeDOM.normalize_to_tree()
782782
|> TreeDOM.by_id!(id)
783-
|> TreeDOM.all(fn node ->
783+
|> TreeDOM.filter(fn node ->
784784
TreeDOM.tag(node) == "div" && TreeDOM.attribute(node, "phx-update") == "stream"
785785
end)
786786
|> case do

test/phoenix_live_view/integrations/update_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ defmodule Phoenix.LiveView.UpdateTest do
4343

4444
html
4545
|> TreeDOM.normalize_to_tree(sort_attributes: true)
46-
|> TreeDOM.all(fn node -> TreeDOM.attribute(node, "id") in ids end)
46+
|> TreeDOM.filter(fn node -> TreeDOM.attribute(node, "id") in ids end)
4747
end
4848
end

0 commit comments

Comments
 (0)