add parsed DocType to document (and handle dumping it)

This commit is contained in:
Karl Seguin
2025-12-09 16:38:56 +08:00
parent 0e1b966dce
commit 47b4b68e60
6 changed files with 49 additions and 14 deletions

View File

@@ -868,7 +868,6 @@ fn notifyNetworkAlmostIdle(self: *Page) void {
// called from the parser // called from the parser
pub fn appendNew(self: *Page, parent: *Node, child: Node.NodeOrText) !void { pub fn appendNew(self: *Page, parent: *Node, child: Node.NodeOrText) !void {
// TODO: should some of this be pushed into appendNode... ?
const node = switch (child) { const node = switch (child) {
.node => |n| n, .node => |n| n,
.text => |txt| blk: { .text => |txt| blk: {

View File

@@ -24,6 +24,7 @@ const Slot = @import("webapi/element/html/Slot.zig");
pub const RootOpts = struct { pub const RootOpts = struct {
with_base: bool = false, with_base: bool = false,
strip: Opts.Strip = .{}, strip: Opts.Strip = .{},
shadow: Opts.Shadow = .rendered,
}; };
pub const Opts = struct { pub const Opts = struct {
@@ -48,10 +49,10 @@ pub const Opts = struct {
}; };
}; };
pub fn root(opts: RootOpts, writer: *std.Io.Writer, page: *Page) !void { pub fn root(doc: *Node.Document, opts: RootOpts, writer: *std.Io.Writer, page: *Page) !void {
const doc = page.document;
if (opts.with_base) { if (opts.with_base) {
if (doc.is(Node.Document.HTMLDocument)) |html_doc| { if (doc.is(Node.Document.HTMLDocument)) |html_doc| {
try writer.writeAll("<!DOCTYPE html>");
const parent = if (html_doc.getHead()) |head| head.asNode() else doc.asNode(); const parent = if (html_doc.getHead()) |head| head.asNode() else doc.asNode();
const base = try doc.createElement("base", null, page); const base = try doc.createElement("base", null, page);
try base.setAttributeSafe("base", page.url, page); try base.setAttributeSafe("base", page.url, page);
@@ -59,7 +60,7 @@ pub fn root(opts: RootOpts, writer: *std.Io.Writer, page: *Page) !void {
} }
} }
return deep(doc.asNode(), .{ .strip = opts.strip }, writer, page); return deep(doc.asNode(), .{ .strip = opts.strip, .shadow = opts.shadow }, writer, page);
} }
pub fn deep(node: *Node, opts: Opts, writer: *std.Io.Writer, page: *Page) error{WriteFailed}!void { pub fn deep(node: *Node, opts: Opts, writer: *std.Io.Writer, page: *Page) error{WriteFailed}!void {
@@ -130,7 +131,29 @@ fn _deep(node: *Node, opts: Opts, comptime force_slot: bool, writer: *std.Io.Wri
} }
}, },
.document => try children(node, opts, writer, page), .document => try children(node, opts, writer, page),
.document_type => {}, .document_type => |dt| {
try writer.writeAll("<!DOCTYPE ");
try writer.writeAll(dt.getName());
const public_id = dt.getPublicId();
const system_id = dt.getSystemId();
if (public_id.len != 0 and system_id.len != 0) {
try writer.writeAll(" PUBLIC \"");
try writeEscapedText(public_id, writer);
try writer.writeAll("\" \"");
try writeEscapedText(system_id, writer);
try writer.writeByte('"');
} else if (public_id.len != 0) {
try writer.writeAll(" PUBLIC \"");
try writeEscapedText(public_id, writer);
try writer.writeByte('"');
} else if (system_id.len != 0) {
try writer.writeAll(" SYSTEM \"");
try writeEscapedText(system_id, writer);
try writer.writeByte('"');
}
try writer.writeAll(">\n");
},
.document_fragment => try children(node, opts, writer, page), .document_fragment => try children(node, opts, writer, page),
.attribute => unreachable, .attribute => unreachable,
} }

View File

@@ -219,17 +219,25 @@ fn _createCommentCallback(self: *Parser, str: []const u8) !*anyopaque {
} }
fn appendDoctypeToDocument(ctx: *anyopaque, name: h5e.StringSlice, public_id: h5e.StringSlice, system_id: h5e.StringSlice) callconv(.c) void { fn appendDoctypeToDocument(ctx: *anyopaque, name: h5e.StringSlice, public_id: h5e.StringSlice, system_id: h5e.StringSlice) callconv(.c) void {
_ = public_id;
_ = system_id;
const self: *Parser = @ptrCast(@alignCast(ctx)); const self: *Parser = @ptrCast(@alignCast(ctx));
self._appendDoctypeToDocument(name.slice()) catch |err| { self._appendDoctypeToDocument(name.slice(), public_id.slice(), system_id.slice()) catch |err| {
self.err = .{ .err = err, .source = .append_doctype_to_document }; self.err = .{ .err = err, .source = .append_doctype_to_document };
}; };
} }
fn _appendDoctypeToDocument(self: *Parser, name: []const u8) !void { fn _appendDoctypeToDocument(self: *Parser, name: []const u8, public_id: []const u8, system_id: []const u8) !void {
_ = self; const page = self.page;
_ = name;
// Create the DocumentType node
const DocumentType = @import("../webapi/DocumentType.zig");
const doctype = try page._factory.node(DocumentType{
._proto = undefined,
._name = try page.dupeString(name),
._public_id = try page.dupeString(public_id),
._system_id = try page.dupeString(system_id),
});
// Append it to the document
try page.appendNew(self.container.node, .{ .node = doctype.asNode() });
} }
fn addAttrsIfMissingCallback(ctx: *anyopaque, target_ref: *anyopaque, attributes: h5e.AttributeIterator) callconv(.c) void { fn addAttrsIfMissingCallback(ctx: *anyopaque, target_ref: *anyopaque, attributes: h5e.AttributeIterator) callconv(.c) void {

View File

@@ -8,6 +8,7 @@
</body> </body>
<script id=document> <script id=document>
testing.expectEqual(10, document.childNodes[0].nodeType);
testing.expectEqual(null, document.parentNode); testing.expectEqual(null, document.parentNode);
testing.expectEqual(undefined, document.getCurrentScript); testing.expectEqual(undefined, document.getCurrentScript);
testing.expectEqual("http://127.0.0.1:9582/src/browser/tests/document/document.html", document.URL); testing.expectEqual("http://127.0.0.1:9582/src/browser/tests/document/document.html", document.URL);

View File

@@ -32,7 +32,11 @@ pub fn init() XMLSerializer {
pub fn serializeToString(self: *const XMLSerializer, node: *Node, page: *Page) ![]const u8 { pub fn serializeToString(self: *const XMLSerializer, node: *Node, page: *Page) ![]const u8 {
_ = self; _ = self;
var buf = std.Io.Writer.Allocating.init(page.call_arena); var buf = std.Io.Writer.Allocating.init(page.call_arena);
try dump.deep(node, .{ .shadow = .skip }, &buf.writer, page); if (node.is(Node.Document)) |doc| {
try dump.root(doc, .{ .shadow = .skip }, &buf.writer, page);
} else {
try dump.deep(node, .{ .shadow = .skip }, &buf.writer, page);
}
return buf.written(); return buf.written();
} }

View File

@@ -64,7 +64,7 @@ pub fn fetch(app: *App, url: [:0]const u8, opts: FetchOpts) !void {
_ = session.fetchWait(opts.wait_ms); _ = session.fetchWait(opts.wait_ms);
const writer = opts.writer orelse return; const writer = opts.writer orelse return;
try dump.root(opts.dump, writer, page); try dump.root(page.window._document, opts.dump, writer, page);
try writer.flush(); try writer.flush();
} }