From f2832447d471a69b421cb9553477f03fab5f6d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Fri, 6 Mar 2026 16:12:57 +0900 Subject: [PATCH] SemanticTree: optimize tag and role filtering * Refactored tag ignoring logic to use the el.getTag() enum switch instead of string comparisons, improving performance and safety. * Replaced string comparisons for interactive roles with std.StaticStringMap. * Renamed internal dumpNode method to dump for brevity. --- src/SemanticTree.zig | 47 ++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/src/SemanticTree.zig b/src/SemanticTree.zig index 4f80addd..815f22d9 100644 --- a/src/SemanticTree.zig +++ b/src/SemanticTree.zig @@ -31,13 +31,27 @@ const CDPNode = @import("cdp/Node.zig"); const Self = @This(); +const interactive_roles = std.StaticStringMap(void).initComptime(.{ + .{ "button", {} }, + .{ "link", {} }, + .{ "checkbox", {} }, + .{ "radio", {} }, + .{ "textbox", {} }, + .{ "combobox", {} }, + .{ "searchbox", {} }, + .{ "slider", {} }, + .{ "spinbutton", {} }, + .{ "switch", {} }, + .{ "menuitem", {} }, +}); + dom_node: *Node, registry: *CDPNode.Registry, page: *Page, arena: std.mem.Allocator, pub fn jsonStringify(self: @This(), jw: *std.json.Stringify) error{WriteFailed}!void { - self.dumpNode(self.dom_node, jw, "") catch |err| { + self.dump(self.dom_node, jw, "") catch |err| { log.err(.cdp, "semantic tree dump failed", .{ .err = err }); return error.WriteFailed; }; @@ -76,20 +90,12 @@ fn getXPathSegment(self: @This(), node: *Node) ![]const u8 { return ""; } -fn dumpNode(self: Self, node: *Node, jw: *std.json.Stringify, parent_xpath: []const u8) !void { +fn dump(self: Self, node: *Node, jw: *std.json.Stringify, parent_xpath: []const u8) !void { // 1. Skip non-content nodes if (node.is(Element)) |el| { - const tag = el.getTagNameLower(); - if (std.mem.eql(u8, tag, "script") or - std.mem.eql(u8, tag, "style") or - std.mem.eql(u8, tag, "meta") or - std.mem.eql(u8, tag, "link") or - std.mem.eql(u8, tag, "noscript") or - std.mem.eql(u8, tag, "svg") or - std.mem.eql(u8, tag, "head") or - std.mem.eql(u8, tag, "title")) - { - return; + switch (el.getTag()) { + .script, .style, .meta, .link, .noscript, .svg, .head, .title => return, + else => {}, } // CSS display: none visibility check (inline style only for now) @@ -125,18 +131,7 @@ fn dumpNode(self: Self, node: *Node, jw: *std.json.Stringify, parent_xpath: []co if (node.is(Element)) |el| { node_name = el.getTagNameLower(); - if (std.mem.eql(u8, role, "button") or - std.mem.eql(u8, role, "link") or - std.mem.eql(u8, role, "checkbox") or - std.mem.eql(u8, role, "radio") or - std.mem.eql(u8, role, "textbox") or - std.mem.eql(u8, role, "combobox") or - std.mem.eql(u8, role, "searchbox") or - std.mem.eql(u8, role, "slider") or - std.mem.eql(u8, role, "spinbutton") or - std.mem.eql(u8, role, "switch") or - std.mem.eql(u8, role, "menuitem")) - { + if (interactive_roles.has(role)) { is_interactive = true; } @@ -218,7 +213,7 @@ fn dumpNode(self: Self, node: *Node, jw: *std.json.Stringify, parent_xpath: []co try jw.beginArray(); var it = node.childrenIterator(); while (it.next()) |child| { - try self.dumpNode(child, jw, xpath); + try self.dump(child, jw, xpath); } try jw.endArray();