axtree: fix skip children for head

This commit is contained in:
Pierre Tachoire
2025-12-05 12:53:43 +01:00
parent b3b43c873c
commit ff871fc443

View File

@@ -49,7 +49,10 @@ pub const Writer = struct {
fn toJSON(self: *const Writer, node: *const Node, w: anytype) !void { fn toJSON(self: *const Writer, node: *const Node, w: anytype) !void {
try w.beginArray(); try w.beginArray();
try self.writeNode(node, w); if (try self.writeNode(node, w)) {
try w.endArray();
return;
}
const walker = Walker{}; const walker = Walker{};
var next: ?*parser.Node = null; var next: ?*parser.Node = null;
@@ -63,13 +66,7 @@ pub const Writer = struct {
} }
const n = try self.registry.register(next.?); const n = try self.registry.register(next.?);
try self.writeNode(n, w); skip_children = try self.writeNode(n, w);
const tag = try parser.elementTag(@ptrCast(next.?));
skip_children = switch (tag) {
.head => true,
else => false,
};
} }
try w.endArray(); try w.endArray();
@@ -194,13 +191,16 @@ pub const Writer = struct {
} }
// write a node. returns true if children must be skipped. // write a node. returns true if children must be skipped.
fn writeNode(self: *const Writer, node: *const Node, w: anytype) !void { fn writeNode(self: *const Writer, node: *const Node, w: anytype) !bool {
try w.beginObject(); try w.beginObject();
const axn = try AXNode.fromNode(node._node); const axn = try AXNode.fromNode(node._node);
try w.objectField("nodeId"); try w.objectField("nodeId");
try w.write(node.id); try w.write(node.id);
try w.objectField("backendDOMNodeId");
try w.write(node.id);
try w.objectField("role"); try w.objectField("role");
try self.writeAXValue(.{ .type = .role, .value = .{ .string = try axn.getRole() } }, w); try self.writeAXValue(.{ .type = .role, .value = .{ .string = try axn.getRole() } }, w);
@@ -249,28 +249,34 @@ pub const Writer = struct {
} }
// Children // Children
const skip_children = try axn.ignoreChildren();
try w.objectField("childIds"); try w.objectField("childIds");
var registry = self.registry;
const child_nodes = try parser.nodeGetChildNodes(n);
const child_count = parser.nodeListLength(child_nodes);
var i: usize = 0;
try w.beginArray(); try w.beginArray();
for (0..child_count) |_| { if (!skip_children) {
defer i += 1; var registry = self.registry;
const child = (parser.nodeListItem(child_nodes, @intCast(i))) orelse break; const child_nodes = try parser.nodeGetChildNodes(n);
const child_count = parser.nodeListLength(child_nodes);
// ignore non-elements var i: usize = 0;
if (parser.nodeType(child) != .element) { for (0..child_count) |_| {
continue; defer i += 1;
const child = (parser.nodeListItem(child_nodes, @intCast(i))) orelse break;
// ignore non-elements
if (parser.nodeType(child) != .element) {
continue;
}
const child_node = try registry.register(child);
try w.write(child_node.id);
} }
const child_node = try registry.register(child);
try w.write(child_node.id);
} }
try w.endArray(); try w.endArray();
try w.endObject(); try w.endObject();
return skip_children;
} }
}; };
@@ -328,11 +334,11 @@ pub const AXRole = enum(u8) {
term, term,
textbox, textbox,
time, time,
WebRootArea, RootWebArea,
fn fromNode(node: *parser.Node) !AXRole { fn fromNode(node: *parser.Node) !AXRole {
switch (parser.nodeType(node)) { switch (parser.nodeType(node)) {
.document => return .WebRootArea, // Chrome specific. .document => return .RootWebArea, // Chrome specific.
.element => {}, .element => {},
else => { else => {
log.debug(.cdp, "invalid tag", .{ .node_type = parser.nodeType(node) }); log.debug(.cdp, "invalid tag", .{ .node_type = parser.nodeType(node) });
@@ -660,6 +666,22 @@ fn isHidden(elt: *parser.Element) !bool {
return false; return false;
} }
fn ignoreChildren(self: AXNode) !bool {
const node = self._node;
if (parser.nodeType(node) == .document) {
return false;
}
std.debug.assert(parser.nodeType(node) == .element);
const elt: *parser.Element = @ptrCast(node);
const tag = try parser.elementTag(elt);
return switch (tag) {
.head => true,
else => false,
};
}
fn isIgnore(self: AXNode) !bool { fn isIgnore(self: AXNode) !bool {
const node = self._node; const node = self._node;
const role_attr = self.role_attr; const role_attr = self.role_attr;