Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions lib/lazy_html/tree.ex
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,36 @@ defmodule LazyHTML.Tree do
@doc """
Performs a depth-first, post-order traversal of the given tree.

This function traverses the tree without modifying it, check `postwalk/2` and
`postwalk/3` if you need to modify the tree.
"""
@spec traverse(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Elixir, Macro.traverse is both prewalk and postwalk combined. So I think we should pick a different name here... maybe postwalk_reduce?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

postvisit, postscan, since they better indicate read-only?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

postscan is also fine by me. Or postreduce.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like postreduce!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8e33368
renamed to postreduce

t(),
acc,
(html_node(), acc -> acc)
) :: acc
when acc: term()
def traverse(tree, acc, fun), do: do_traverse(tree, acc, fun)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for the do_traverse btw. You can implement them all directly as clauses of traverse.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


defp do_traverse([], acc, _fun), do: acc

defp do_traverse([node | rest], acc, fun) do
acc = do_traverse(node, acc, fun)
do_traverse(rest, acc, fun)
end

defp do_traverse({tag, attrs, children}, acc, fun) do
acc = do_traverse(children, acc, fun)
fun.({tag, attrs, children}, acc)
end

defp do_traverse(node, acc, fun) do
fun.(node, acc)
end

@doc """
Performs a depth-first, post-order traversal of the given tree.

The mapper `fun` can return a list of nodes to replace the given
node. In order to remove a node, return an empty list.
"""
Expand Down
27 changes: 27 additions & 0 deletions test/lazy_html/tree_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,33 @@ defmodule LazyHTML.TreeTest do
end
end

describe "traverse/3" do
test "does post-order traversal of the nodes and accumulates results" do
tree = [
{:comment, "Hello world"},
{"div", [{"class", "root"}],
[
{"span", [], ["Hello"]},
{:comment, "intersection"},
{"span", [], ["world"]}
]}
]

nodes = LazyHTML.Tree.traverse(tree, [], fn node, acc -> [node | acc] end)

assert nodes == [
{"div", [{"class", "root"}],
[{"span", [], ["Hello"]}, {:comment, "intersection"}, {"span", [], ["world"]}]},
{"span", [], ["world"]},
"world",
{:comment, "intersection"},
{"span", [], ["Hello"]},
"Hello",
{:comment, "Hello world"}
]
end
end

describe "postwalk/3" do
test "does post-order traversal of the nodes and accumulates results" do
tree = [
Expand Down