From 7dc3add5fdf749c24bf57716704325c00d341816 Mon Sep 17 00:00:00 2001 From: sjorsdonkers <72333389+sjorsdonkers@users.noreply.github.com> Date: Mon, 7 Apr 2025 19:42:59 +0200 Subject: [PATCH 1/5] reolveNode WIP --- src/cdp/domains/dom.zig | 109 ++++++++++++++++++++++++++++++++++++++++ vendor/zig-js-runtime | 2 +- 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/cdp/domains/dom.zig b/src/cdp/domains/dom.zig index 97cdc40d..9d1e6b02 100644 --- a/src/cdp/domains/dom.zig +++ b/src/cdp/domains/dom.zig @@ -28,6 +28,7 @@ pub fn processMessage(cmd: anytype) !void { performSearch, getSearchResults, discardSearchResults, + resolveNode, }, cmd.input.action) orelse return error.UnknownMethod; switch (action) { @@ -36,6 +37,7 @@ pub fn processMessage(cmd: anytype) !void { .performSearch => return performSearch(cmd), .getSearchResults => return getSearchResults(cmd), .discardSearchResults => return discardSearchResults(cmd), + .resolveNode => return resolveNode(cmd), } } @@ -115,6 +117,113 @@ fn getSearchResults(cmd: anytype) !void { return cmd.sendResult(.{ .nodeIds = node_ids[params.fromIndex..params.toIndex] }, .{}); } +fn resolveNode(cmd: anytype) !void { + const params = (try cmd.params(struct { + nodeId: ?Node.Id = null, + backendNodeId: ?u32 = null, + objectGroup: ?[]const u8 = null, + executionContextId: ?u32 = null, + })) orelse return error.InvalidParams; + if (params.nodeId == null or params.backendNodeId != null or params.objectGroup != null or params.executionContextId != null) { + return error.NotYetImplementedParams; + } + + const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded; + const node = bc.node_registry.lookup_by_id.get(params.nodeId.?).?; + + // How best to do this? Create a functions that takes a functions(wrapObject), does all the switching at every level and applies the given function to the leav object? + const remote_object = try switch (try parser.nodeType(node._node)) { + .element => blk: { + const elem: *align(@alignOf(*parser.Element)) parser.Element = @alignCast(@as(*parser.Element, @ptrCast(node._node))); + const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(elem))); + break :blk switch (tag) { + .abbr, .acronym, .address, .article, .aside, .b, .basefont, .bdi, .bdo, .bgsound, .big, .center, .cite, .code, .dd, .details, .dfn, .dt, .em, .figcaption, .figure, .footer, .header, .hgroup, .i, .isindex, .keygen, .kbd, .main, .mark, .marquee, .menu, .menuitem, .nav, .nobr, .noframes, .noscript, .rp, .rt, .ruby, .s, .samp, .section, .small, .spacer, .strike, .strong, .sub, .summary, .sup, .tt, .u, .wbr, ._var => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.ElementHTML, @ptrCast(elem))), + .a => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Anchor, @ptrCast(elem))), + .applet => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Applet, @ptrCast(elem))), + .area => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Area, @ptrCast(elem))), + .audio => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Audio, @ptrCast(elem))), + .base => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Base, @ptrCast(elem))), + .body => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Body, @ptrCast(elem))), + .br => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.BR, @ptrCast(elem))), + .button => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Button, @ptrCast(elem))), + .canvas => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Canvas, @ptrCast(elem))), + .dl => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.DList, @ptrCast(elem))), + .data => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Data, @ptrCast(elem))), + .datalist => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.DataList, @ptrCast(elem))), + .dialog => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Dialog, @ptrCast(elem))), + .dir => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Directory, @ptrCast(elem))), + .div => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Div, @ptrCast(elem))), + .embed => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Embed, @ptrCast(elem))), + .fieldset => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.FieldSet, @ptrCast(elem))), + .font => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Font, @ptrCast(elem))), + .form => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Form, @ptrCast(elem))), + .frame => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Frame, @ptrCast(elem))), + .frameset => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.FrameSet, @ptrCast(elem))), + .hr => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.HR, @ptrCast(elem))), + .head => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Head, @ptrCast(elem))), + .h1, .h2, .h3, .h4, .h5, .h6 => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Heading, @ptrCast(elem))), + .html => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Html, @ptrCast(elem))), + .iframe => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.IFrame, @ptrCast(elem))), + .img => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Image, @ptrCast(elem))), + .input => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Input, @ptrCast(elem))), + .li => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.LI, @ptrCast(elem))), + .label => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Label, @ptrCast(elem))), + .legend => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Legend, @ptrCast(elem))), + .link => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Link, @ptrCast(elem))), + .map => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Map, @ptrCast(elem))), + .meta => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Meta, @ptrCast(elem))), + .meter => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Meter, @ptrCast(elem))), + .ins, .del => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Mod, @ptrCast(elem))), + .ol => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.OList, @ptrCast(elem))), + .object => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Object, @ptrCast(elem))), + .optgroup => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.OptGroup, @ptrCast(elem))), + .option => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Option, @ptrCast(elem))), + .output => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Output, @ptrCast(elem))), + .p => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Paragraph, @ptrCast(elem))), + .param => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Param, @ptrCast(elem))), + .picture => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Picture, @ptrCast(elem))), + .pre => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Pre, @ptrCast(elem))), + .progress => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Progress, @ptrCast(elem))), + .blockquote, .q => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Quote, @ptrCast(elem))), + .script => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Script, @ptrCast(elem))), + .select => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Select, @ptrCast(elem))), + .source => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Source, @ptrCast(elem))), + .span => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Span, @ptrCast(elem))), + .style => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Style, @ptrCast(elem))), + .table => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Table, @ptrCast(elem))), + .caption => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TableCaption, @ptrCast(elem))), + .th, .td => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TableCell, @ptrCast(elem))), + .col, .colgroup => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TableCol, @ptrCast(elem))), + .tr => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TableRow, @ptrCast(elem))), + .thead, .tbody, .tfoot => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TableSection, @ptrCast(elem))), + .template => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Template, @ptrCast(elem))), + .textarea => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TextArea, @ptrCast(elem))), + .time => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Time, @ptrCast(elem))), + .title => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Title, @ptrCast(elem))), + .track => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Track, @ptrCast(elem))), + .ul => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.UList, @ptrCast(elem))), + .video => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Video, @ptrCast(elem))), + .undef => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Unknown, @ptrCast(elem))), + }; + }, + .comment => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Comment, @ptrCast(node._node))), // TODO sub types + .text => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Text, @ptrCast(node._node))), + .cdata_section => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.CDATASection, @ptrCast(node._node))), + .processing_instruction => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.ProcessingInstruction, @ptrCast(node._node))), + .document => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.DocumentHTML, @ptrCast(node._node))), + .document_type => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.DocumentType, @ptrCast(node._node))), + .attribute => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Attribute, @ptrCast(node._node))), + .document_fragment => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.DocumentFragment, @ptrCast(node._node))), + else => @panic("node type not handled"), + }; + defer remote_object.deinit(); + + var arena = std.heap.ArenaAllocator.init(cmd.cdp.allocator); + const alloc = arena.allocator(); + defer arena.deinit(); + return cmd.sendResult(.{ .object = .{ .type = try remote_object.getType(alloc), .subtype = try remote_object.getSubtype(alloc), .className = try remote_object.getClassName(alloc), .description = try remote_object.getDescription(alloc), .objectId = try remote_object.getObjectId(alloc) } }, .{}); +} + const testing = @import("../testing.zig"); test "cdp.dom: getSearchResults unknown search id" { diff --git a/vendor/zig-js-runtime b/vendor/zig-js-runtime index f3a9e3d4..a4900182 160000 --- a/vendor/zig-js-runtime +++ b/vendor/zig-js-runtime @@ -1 +1 @@ -Subproject commit f3a9e3d448cd56a709ec2d101c05507e894d8e6f +Subproject commit a49001825c72e596cd571f24c473bd3ec4c18c5e From 2f47e04de7a74cfe2f7492c81d45fcb25c12facb Mon Sep 17 00:00:00 2001 From: sjorsdonkers <72333389+sjorsdonkers@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:16:59 +0200 Subject: [PATCH 2/5] Use findOrAddValue for precise JsValue --- src/cdp/domains/dom.zig | 103 +++++----------------------------------- 1 file changed, 11 insertions(+), 92 deletions(-) diff --git a/src/cdp/domains/dom.zig b/src/cdp/domains/dom.zig index 9d1e6b02..360fff85 100644 --- a/src/cdp/domains/dom.zig +++ b/src/cdp/domains/dom.zig @@ -20,6 +20,7 @@ const std = @import("std"); const parser = @import("netsurf"); const Node = @import("../Node.zig"); const css = @import("../../dom/css.zig"); +const dom_node = @import("../../dom/node.zig"); pub fn processMessage(cmd: anytype) !void { const action = std.meta.stringToEnum(enum { @@ -129,99 +130,17 @@ fn resolveNode(cmd: anytype) !void { } const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded; - const node = bc.node_registry.lookup_by_id.get(params.nodeId.?).?; - - // How best to do this? Create a functions that takes a functions(wrapObject), does all the switching at every level and applies the given function to the leav object? - const remote_object = try switch (try parser.nodeType(node._node)) { - .element => blk: { - const elem: *align(@alignOf(*parser.Element)) parser.Element = @alignCast(@as(*parser.Element, @ptrCast(node._node))); - const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(elem))); - break :blk switch (tag) { - .abbr, .acronym, .address, .article, .aside, .b, .basefont, .bdi, .bdo, .bgsound, .big, .center, .cite, .code, .dd, .details, .dfn, .dt, .em, .figcaption, .figure, .footer, .header, .hgroup, .i, .isindex, .keygen, .kbd, .main, .mark, .marquee, .menu, .menuitem, .nav, .nobr, .noframes, .noscript, .rp, .rt, .ruby, .s, .samp, .section, .small, .spacer, .strike, .strong, .sub, .summary, .sup, .tt, .u, .wbr, ._var => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.ElementHTML, @ptrCast(elem))), - .a => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Anchor, @ptrCast(elem))), - .applet => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Applet, @ptrCast(elem))), - .area => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Area, @ptrCast(elem))), - .audio => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Audio, @ptrCast(elem))), - .base => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Base, @ptrCast(elem))), - .body => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Body, @ptrCast(elem))), - .br => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.BR, @ptrCast(elem))), - .button => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Button, @ptrCast(elem))), - .canvas => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Canvas, @ptrCast(elem))), - .dl => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.DList, @ptrCast(elem))), - .data => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Data, @ptrCast(elem))), - .datalist => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.DataList, @ptrCast(elem))), - .dialog => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Dialog, @ptrCast(elem))), - .dir => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Directory, @ptrCast(elem))), - .div => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Div, @ptrCast(elem))), - .embed => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Embed, @ptrCast(elem))), - .fieldset => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.FieldSet, @ptrCast(elem))), - .font => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Font, @ptrCast(elem))), - .form => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Form, @ptrCast(elem))), - .frame => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Frame, @ptrCast(elem))), - .frameset => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.FrameSet, @ptrCast(elem))), - .hr => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.HR, @ptrCast(elem))), - .head => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Head, @ptrCast(elem))), - .h1, .h2, .h3, .h4, .h5, .h6 => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Heading, @ptrCast(elem))), - .html => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Html, @ptrCast(elem))), - .iframe => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.IFrame, @ptrCast(elem))), - .img => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Image, @ptrCast(elem))), - .input => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Input, @ptrCast(elem))), - .li => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.LI, @ptrCast(elem))), - .label => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Label, @ptrCast(elem))), - .legend => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Legend, @ptrCast(elem))), - .link => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Link, @ptrCast(elem))), - .map => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Map, @ptrCast(elem))), - .meta => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Meta, @ptrCast(elem))), - .meter => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Meter, @ptrCast(elem))), - .ins, .del => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Mod, @ptrCast(elem))), - .ol => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.OList, @ptrCast(elem))), - .object => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Object, @ptrCast(elem))), - .optgroup => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.OptGroup, @ptrCast(elem))), - .option => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Option, @ptrCast(elem))), - .output => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Output, @ptrCast(elem))), - .p => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Paragraph, @ptrCast(elem))), - .param => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Param, @ptrCast(elem))), - .picture => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Picture, @ptrCast(elem))), - .pre => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Pre, @ptrCast(elem))), - .progress => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Progress, @ptrCast(elem))), - .blockquote, .q => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Quote, @ptrCast(elem))), - .script => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Script, @ptrCast(elem))), - .select => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Select, @ptrCast(elem))), - .source => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Source, @ptrCast(elem))), - .span => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Span, @ptrCast(elem))), - .style => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Style, @ptrCast(elem))), - .table => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Table, @ptrCast(elem))), - .caption => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TableCaption, @ptrCast(elem))), - .th, .td => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TableCell, @ptrCast(elem))), - .col, .colgroup => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TableCol, @ptrCast(elem))), - .tr => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TableRow, @ptrCast(elem))), - .thead, .tbody, .tfoot => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TableSection, @ptrCast(elem))), - .template => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Template, @ptrCast(elem))), - .textarea => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.TextArea, @ptrCast(elem))), - .time => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Time, @ptrCast(elem))), - .title => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Title, @ptrCast(elem))), - .track => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Track, @ptrCast(elem))), - .ul => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.UList, @ptrCast(elem))), - .video => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Video, @ptrCast(elem))), - .undef => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Unknown, @ptrCast(elem))), - }; - }, - .comment => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Comment, @ptrCast(node._node))), // TODO sub types - .text => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Text, @ptrCast(node._node))), - .cdata_section => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.CDATASection, @ptrCast(node._node))), - .processing_instruction => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.ProcessingInstruction, @ptrCast(node._node))), - .document => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.DocumentHTML, @ptrCast(node._node))), - .document_type => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.DocumentType, @ptrCast(node._node))), - .attribute => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.Attribute, @ptrCast(node._node))), - .document_fragment => bc.session.inspector.wrapObject(&bc.session.env, @as(*parser.DocumentFragment, @ptrCast(node._node))), - else => @panic("node type not handled"), - }; - defer remote_object.deinit(); + const node = bc.node_registry.lookup_by_id.get(params.nodeId.?) orelse return error.UnknownNode; + + // node._node is a *parder.Node we need this to be able to find its most derived type e.g. Node -> Element -> HTMLElement + // So we use the Node.Union when retrieve the value from the environment + const jsValue = try bc.session.env.findOrAddValue(try dom_node.Node.toInterface(node._node)); + const groupName = "AGroupName"; // Temporary default, most likely the same as objectGroup + const remoteObject = try bc.session.inspector.getRemoteObject(&bc.session.env, jsValue, groupName); + defer remoteObject.deinit(); - var arena = std.heap.ArenaAllocator.init(cmd.cdp.allocator); - const alloc = arena.allocator(); - defer arena.deinit(); - return cmd.sendResult(.{ .object = .{ .type = try remote_object.getType(alloc), .subtype = try remote_object.getSubtype(alloc), .className = try remote_object.getClassName(alloc), .description = try remote_object.getDescription(alloc), .objectId = try remote_object.getObjectId(alloc) } }, .{}); + const arena = cmd.arena; + return cmd.sendResult(.{ .object = .{ .type = try remoteObject.getType(arena), .subtype = try remoteObject.getSubtype(arena), .className = try remoteObject.getClassName(arena), .description = try remoteObject.getDescription(arena), .objectId = try remoteObject.getObjectId(arena) } }, .{}); } const testing = @import("../testing.zig"); From 3a7da6665f24445e099fa4afa7b591fe4a9ba739 Mon Sep 17 00:00:00 2001 From: sjorsdonkers <72333389+sjorsdonkers@users.noreply.github.com> Date: Wed, 9 Apr 2025 11:20:33 +0200 Subject: [PATCH 3/5] unittest scaffolding --- src/cdp/testing.zig | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/cdp/testing.zig b/src/cdp/testing.zig index c9ce2ebb..35e9332b 100644 --- a/src/cdp/testing.zig +++ b/src/cdp/testing.zig @@ -60,6 +60,8 @@ const Browser = struct { self.session.?.* = .{ .page = null, .arena = arena, + .env = Env{}, + .inspector = Inspector{}, }; return self.session.?; } @@ -75,6 +77,8 @@ const Browser = struct { const Session = struct { page: ?Page = null, arena: Allocator, + env: Env, + inspector: Inspector, pub fn currentPage(self: *Session) ?*Page { return &(self.page orelse return null); @@ -102,6 +106,54 @@ const Session = struct { } }; +const Env = struct { + pub fn findOrAddValue(self: *Env, value: anytype) !@TypeOf(value) { // ? + _ = self; + return value; + } +}; + +const Inspector = struct { + pub fn getRemoteObject(self: Inspector, env: *Env, jsValue: anytype, groupName: []const u8) !RemoteObject { + _ = self; + _ = env; + _ = jsValue; + _ = groupName; + return RemoteObject{}; + } +}; + +const RemoteObject = struct { + pub fn deinit(self: RemoteObject) void { + _ = self; + } + pub fn getType(self: RemoteObject, alloc: std.mem.Allocator) ![:0]const u8 { + _ = self; + _ = alloc; + return "TheType"; + } + pub fn getSubtype(self: RemoteObject, alloc: std.mem.Allocator) ![:0]const u8 { + _ = self; + _ = alloc; + return "TheSubtype"; + } + pub fn getClassName(self: RemoteObject, alloc: std.mem.Allocator) ![:0]const u8 { + _ = self; + _ = alloc; + return "TheClassName"; + } + pub fn getDescription(self: RemoteObject, alloc: std.mem.Allocator) ![:0]const u8 { + _ = self; + _ = alloc; + return "TheDescription"; + } + pub fn getObjectId(self: RemoteObject, alloc: std.mem.Allocator) ![:0]const u8 { + _ = self; + _ = alloc; + return "TheObjectId"; + } +}; + const Page = struct { session: *Session, rawuri: []const u8, From 32d9fc0d32896fb10d0c498b9028b089a6c9d3fc Mon Sep 17 00:00:00 2001 From: sjorsdonkers <72333389+sjorsdonkers@users.noreply.github.com> Date: Wed, 9 Apr 2025 13:40:00 +0200 Subject: [PATCH 4/5] Pass objectGroup as groupName --- src/cdp/domains/dom.zig | 13 +++++++++---- vendor/zig-js-runtime | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/cdp/domains/dom.zig b/src/cdp/domains/dom.zig index 360fff85..cb7bcd41 100644 --- a/src/cdp/domains/dom.zig +++ b/src/cdp/domains/dom.zig @@ -125,7 +125,7 @@ fn resolveNode(cmd: anytype) !void { objectGroup: ?[]const u8 = null, executionContextId: ?u32 = null, })) orelse return error.InvalidParams; - if (params.nodeId == null or params.backendNodeId != null or params.objectGroup != null or params.executionContextId != null) { + if (params.nodeId == null or params.backendNodeId != null or params.executionContextId != null) { return error.NotYetImplementedParams; } @@ -135,12 +135,17 @@ fn resolveNode(cmd: anytype) !void { // node._node is a *parder.Node we need this to be able to find its most derived type e.g. Node -> Element -> HTMLElement // So we use the Node.Union when retrieve the value from the environment const jsValue = try bc.session.env.findOrAddValue(try dom_node.Node.toInterface(node._node)); - const groupName = "AGroupName"; // Temporary default, most likely the same as objectGroup - const remoteObject = try bc.session.inspector.getRemoteObject(&bc.session.env, jsValue, groupName); + const remoteObject = try bc.session.inspector.getRemoteObject(&bc.session.env, jsValue, params.objectGroup orelse ""); defer remoteObject.deinit(); const arena = cmd.arena; - return cmd.sendResult(.{ .object = .{ .type = try remoteObject.getType(arena), .subtype = try remoteObject.getSubtype(arena), .className = try remoteObject.getClassName(arena), .description = try remoteObject.getDescription(arena), .objectId = try remoteObject.getObjectId(arena) } }, .{}); + return cmd.sendResult(.{ .object = .{ + .type = try remoteObject.getType(arena), + .subtype = try remoteObject.getSubtype(arena), + .className = try remoteObject.getClassName(arena), + .description = try remoteObject.getDescription(arena), + .objectId = try remoteObject.getObjectId(arena), + } }, .{}); } const testing = @import("../testing.zig"); diff --git a/vendor/zig-js-runtime b/vendor/zig-js-runtime index a4900182..9b87782f 160000 --- a/vendor/zig-js-runtime +++ b/vendor/zig-js-runtime @@ -1 +1 @@ -Subproject commit a49001825c72e596cd571f24c473bd3ec4c18c5e +Subproject commit 9b87782f1edc0a3c4541f771d4ff443820fa38ac From bc1a83d04aeae1f53a09f4afde7cc9fc254417f3 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Wed, 9 Apr 2025 14:46:53 +0200 Subject: [PATCH 5/5] Update src/cdp/domains/dom.zig --- src/cdp/domains/dom.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdp/domains/dom.zig b/src/cdp/domains/dom.zig index cb7bcd41..80e6b96b 100644 --- a/src/cdp/domains/dom.zig +++ b/src/cdp/domains/dom.zig @@ -132,7 +132,7 @@ fn resolveNode(cmd: anytype) !void { const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded; const node = bc.node_registry.lookup_by_id.get(params.nodeId.?) orelse return error.UnknownNode; - // node._node is a *parder.Node we need this to be able to find its most derived type e.g. Node -> Element -> HTMLElement + // node._node is a *parser.Node we need this to be able to find its most derived type e.g. Node -> Element -> HTMLElement // So we use the Node.Union when retrieve the value from the environment const jsValue = try bc.session.env.findOrAddValue(try dom_node.Node.toInterface(node._node)); const remoteObject = try bc.session.inspector.getRemoteObject(&bc.session.env, jsValue, params.objectGroup orelse "");