Skip to content

Conversation

@mookums
Copy link
Contributor

@mookums mookums commented May 19, 2025

This introduces the TreeWalker and related NodeFilter.

Copy link
Collaborator

@karlseguin karlseguin left a comment

Choose a reason for hiding this comment

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

This looks ok, but it seems like the implementation is missing a lot, e.g. the filter and whatToShow fields aren't being used. That's fine, but I just wanted to make sure that was the intention.

return Node.replaceChildren(parser.documentToNode(self), nodes);
}

pub fn _createTreeWalker(_: *parser.Document, root: *parser.Node, whatToShow: ?u32, filter: ?Env.Callback) TreeWalker {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
pub fn _createTreeWalker(_: *parser.Document, root: *parser.Node, whatToShow: ?u32, filter: ?Env.Callback) TreeWalker {
pub fn _createTreeWalker(_: *parser.Document, root: *parser.Node, what_to_show: ?u32, filter: ?Env.Callback) TreeWalker {

whatToShow: u32,
filter: ?Env.Callback,

pub fn init(node: *parser.Node, whatToShow: ?u32, filter: ?Env.Callback) TreeWalker {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
pub fn init(node: *parser.Node, whatToShow: ?u32, filter: ?Env.Callback) TreeWalker {
pub fn init(node: *parser.Node, what_to_show: ?u32, filter: ?Env.Callback) TreeWalker {

pub const TreeWalker = struct {
root: *parser.Node,
currentNode: *parser.Node,
whatToShow: u32,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
whatToShow: u32,
what_to_show: u32,

// https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
pub const TreeWalker = struct {
root: *parser.Node,
currentNode: *parser.Node,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
currentNode: *parser.Node,
current_node: *parser.Node,

return .{
.root = node,
.currentNode = node,
.whatToShow = whatToShow orelse std.math.maxInt(u32),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would improve readability to use NodeFilter._SHOW_ALL, or at least a comment saying the orelse is show all.

}

pub fn _firstChild(self: *TreeWalker) ?*parser.Node {
const first_child = parser.nodeFirstChild(self.currentNode) catch return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm dom_node_get_first_child increments the ref_count, walker.zig says we should be deiniting these Nodes.
Though I don't see us doing that in the rest of the code.
Worst case they would be cleaned up when the page is removed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Because everything is in an mimalloc arena. Wonder if we took out all the refcnt++ and refcnt-- from libdom if we'd shave a few µs.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea, may want to remove to comments from walker.zig.
Or actually maybe this PR can replace the whole thing, maybe.

@mookums mookums force-pushed the treewalker branch 2 times, most recently from 59a9cf8 to 8bbe69d Compare May 20, 2025 17:07
Because jsValueToStruct is now used in union probing, it shouldn't fail on a
mismatch, but rather return null. It's up to the caller to decide whether that's
an error or not.
const child = (try parser.nodeListItem(children, index)) orelse return null;

if (!try self.verify_what_to_show(child)) continue;
if (!try self.verify_filter(child)) continue;
Copy link
Collaborator

Choose a reason for hiding this comment

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

since you always call verify_filter and verify_what_to_show together, I wonder combining them, or having a helper that calls both is worthwhile.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I collapsed these into a single verify function.

}

pub fn _previousNode(self: *TreeWalker) !?*parser.Node {
return self._parentNode();
Copy link
Collaborator

Choose a reason for hiding this comment

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

same as nextNode..is it really always the parent? It can't be a previous sibling?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed this too, moving in document order.

if (!try self.verify_what_to_show(child)) continue;
if (!try self.verify_filter(child)) continue;

self.depth += 1;
Copy link
Collaborator

Choose a reason for hiding this comment

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

does every node you visit necessarily increase the depth? I'm thinking if child is a sibling of current_node, it shouldn't increase the depth.

Maybe I don't understand..but if I'm right, it seems like depth is going to get tricky to keep track of. If depth is only used in _parentNode to protect against going outside the tree, maybe there's a better way (like comparing against the root node?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ditched depth in favor of just comparing against the self.root when we are moving up the tree.

@mookums
Copy link
Contributor Author

mookums commented May 22, 2025

Just as a note, some newly passing WPT tests:
dom/nodes/Document-createTreeWalker.html
dom/traversal/TreeWalker-traversal-skip-most.html
dom/traversal/TreeWalker-traversal-reject.html
dom/traversal/TreeWalker-previousNodeLastChildReject.html
dom/traversal/TreeWalker-walking-outside-a-tree.html
dom/traversal/TreeWalker-traversal-skip.html

@karlseguin
Copy link
Collaborator

LGTM

@karlseguin karlseguin merged commit eae9f9c into main May 26, 2025
9 checks passed
@karlseguin karlseguin deleted the treewalker branch May 26, 2025 03:06
@github-actions github-actions bot locked and limited conversation to collaborators May 26, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants