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
pub fn appendNew(self: *Page, parent: *Node, child: Node.NodeOrText) !void {
// TODO: should some of this be pushed into appendNode... ?
const node = switch (child) {
.node => |n| n,
.text => |txt| blk: {

View File

@@ -24,6 +24,7 @@ const Slot = @import("webapi/element/html/Slot.zig");
pub const RootOpts = struct {
with_base: bool = false,
strip: Opts.Strip = .{},
shadow: Opts.Shadow = .rendered,
};
pub const Opts = struct {
@@ -48,10 +49,10 @@ pub const Opts = struct {
};
};
pub fn root(opts: RootOpts, writer: *std.Io.Writer, page: *Page) !void {
const doc = page.document;
pub fn root(doc: *Node.Document, opts: RootOpts, writer: *std.Io.Writer, page: *Page) !void {
if (opts.with_base) {
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 base = try doc.createElement("base", null, 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 {
@@ -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_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),
.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 {
_ = public_id;
_ = system_id;
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 };
};
}
fn _appendDoctypeToDocument(self: *Parser, name: []const u8) !void {
_ = self;
_ = name;
fn _appendDoctypeToDocument(self: *Parser, name: []const u8, public_id: []const u8, system_id: []const u8) !void {
const page = self.page;
// 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 {

View File

@@ -8,6 +8,7 @@
</body>
<script id=document>
testing.expectEqual(10, document.childNodes[0].nodeType);
testing.expectEqual(null, document.parentNode);
testing.expectEqual(undefined, document.getCurrentScript);
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 {
_ = self;
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();
}

View File

@@ -64,7 +64,7 @@ pub fn fetch(app: *App, url: [:0]const u8, opts: FetchOpts) !void {
_ = session.fetchWait(opts.wait_ms);
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();
}