diff --git a/src/SemanticTree.zig b/src/SemanticTree.zig index f6b2fca5..94a63616 100644 --- a/src/SemanticTree.zig +++ b/src/SemanticTree.zig @@ -49,7 +49,13 @@ pub fn jsonStringify(self: @This(), jw: *std.json.Stringify) error{WriteFailed}! }; var visibility_cache: Element.VisibilityCache = .empty; var pointer_events_cache: Element.PointerEventsCache = .empty; - self.walk(self.dom_node, &xpath_buffer, null, &visitor, 1, listener_targets, &visibility_cache, &pointer_events_cache, 0) catch |err| { + var ctx: WalkContext = .{ + .xpath_buffer = &xpath_buffer, + .listener_targets = listener_targets, + .visibility_cache = &visibility_cache, + .pointer_events_cache = &pointer_events_cache, + }; + self.walk(&ctx, self.dom_node, null, &visitor, 1, 0) catch |err| { log.err(.app, "semantic tree json dump failed", .{ .err = err }); return error.WriteFailed; }; @@ -64,7 +70,13 @@ pub fn textStringify(self: @This(), writer: *std.Io.Writer) error{WriteFailed}!v }; var visibility_cache: Element.VisibilityCache = .empty; var pointer_events_cache: Element.PointerEventsCache = .empty; - self.walk(self.dom_node, &xpath_buffer, null, &visitor, 1, listener_targets, &visibility_cache, &pointer_events_cache, 0) catch |err| { + var ctx: WalkContext = .{ + .xpath_buffer = &xpath_buffer, + .listener_targets = listener_targets, + .visibility_cache = &visibility_cache, + .pointer_events_cache = &pointer_events_cache, + }; + self.walk(&ctx, self.dom_node, null, &visitor, 1, 0) catch |err| { log.err(.app, "semantic tree text dump failed", .{ .err = err }); return error.WriteFailed; }; @@ -88,7 +100,22 @@ const NodeData = struct { node_name: []const u8, }; -fn walk(self: @This(), node: *Node, xpath_buffer: *std.ArrayList(u8), parent_name: ?[]const u8, visitor: anytype, index: usize, listener_targets: interactive.ListenerTargetMap, visibility_cache: ?*Element.VisibilityCache, pointer_events_cache: ?*Element.PointerEventsCache, current_depth: u32) !void { +const WalkContext = struct { + xpath_buffer: *std.ArrayList(u8), + listener_targets: interactive.ListenerTargetMap, + visibility_cache: *Element.VisibilityCache, + pointer_events_cache: *Element.PointerEventsCache, +}; + +fn walk( + self: @This(), + ctx: *WalkContext, + node: *Node, + parent_name: ?[]const u8, + visitor: anytype, + index: usize, + current_depth: u32, +) !void { if (current_depth > self.max_depth) return; // 1. Skip non-content nodes @@ -100,7 +127,7 @@ fn walk(self: @This(), node: *Node, xpath_buffer: *std.ArrayList(u8), parent_nam if (tag == .datalist or tag == .option or tag == .optgroup) return; // Check visibility using the engine's checkVisibility which handles CSS display: none - if (!el.checkVisibilityCached(visibility_cache, self.page)) { + if (!el.checkVisibilityCached(ctx.visibility_cache, self.page)) { return; } @@ -141,7 +168,7 @@ fn walk(self: @This(), node: *Node, xpath_buffer: *std.ArrayList(u8), parent_nam } if (el.is(Element.Html)) |html_el| { - if (interactive.classifyInteractivity(self.page, el, html_el, listener_targets, pointer_events_cache) != null) { + if (interactive.classifyInteractivity(self.page, el, html_el, ctx.listener_targets, ctx.pointer_events_cache) != null) { is_interactive = true; } } @@ -149,9 +176,9 @@ fn walk(self: @This(), node: *Node, xpath_buffer: *std.ArrayList(u8), parent_nam node_name = "root"; } - const initial_xpath_len = xpath_buffer.items.len; - try appendXPathSegment(node, xpath_buffer.writer(self.arena), index); - const xpath = xpath_buffer.items; + const initial_xpath_len = ctx.xpath_buffer.items.len; + try appendXPathSegment(node, ctx.xpath_buffer.writer(self.arena), index); + const xpath = ctx.xpath_buffer.items; var name = try axn.getName(self.page, self.arena); @@ -237,7 +264,7 @@ fn walk(self: @This(), node: *Node, xpath_buffer: *std.ArrayList(u8), parent_nam } gop.value_ptr.* += 1; - try self.walk(child, xpath_buffer, name, visitor, gop.value_ptr.*, listener_targets, visibility_cache, pointer_events_cache, current_depth + 1); + try self.walk(ctx, child, name, visitor, gop.value_ptr.*, current_depth + 1); } } @@ -245,7 +272,7 @@ fn walk(self: @This(), node: *Node, xpath_buffer: *std.ArrayList(u8), parent_nam try visitor.leave(); } - xpath_buffer.shrinkRetainingCapacity(initial_xpath_len); + ctx.xpath_buffer.shrinkRetainingCapacity(initial_xpath_len); } fn extractSelectOptions(node: *Node, page: *Page, arena: std.mem.Allocator) ![]OptionData {