dom: document first element can be null

This commit is contained in:
Pierre Tachoire
2023-12-13 13:12:01 +01:00
parent edff9f7444
commit 82c836c80d
3 changed files with 45 additions and 31 deletions

View File

@@ -34,9 +34,10 @@ pub const Document = struct {
return DOMImplementation{}; return DOMImplementation{};
} }
pub fn get_documentElement(self: *parser.Document) !ElementUnion { pub fn get_documentElement(self: *parser.Document) !?ElementUnion {
const e = try parser.documentGetDocumentElement(self); const e = try parser.documentGetDocumentElement(self);
return try Element.toInterface(e); if (e == null) return null;
return try Element.toInterface(e.?);
} }
pub fn get_documentURI(self: *parser.Document) ![]const u8 { pub fn get_documentURI(self: *parser.Document) ![]const u8 {
@@ -105,13 +106,12 @@ pub const Document = struct {
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
tag_name: []const u8, tag_name: []const u8,
) !collection.HTMLCollection { ) !collection.HTMLCollection {
const root = try parser.documentGetDocumentElement(self); var elt: ?*parser.Node = null;
return try collection.HTMLCollectionByTagName( if (try parser.documentGetDocumentElement(self)) |root| {
alloc, elt = parser.elementToNode(root);
parser.elementToNode(root), }
tag_name,
true, return try collection.HTMLCollectionByTagName(alloc, elt, tag_name, true);
);
} }
pub fn _getElementsByClassName( pub fn _getElementsByClassName(
@@ -119,13 +119,12 @@ pub const Document = struct {
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
classNames: []const u8, classNames: []const u8,
) !collection.HTMLCollection { ) !collection.HTMLCollection {
const root = try parser.documentGetDocumentElement(self); var elt: ?*parser.Node = null;
return try collection.HTMLCollectionByClassName( if (try parser.documentGetDocumentElement(self)) |root| {
alloc, elt = parser.elementToNode(root);
parser.elementToNode(root), }
classNames,
true, return try collection.HTMLCollectionByClassName(alloc, elt, classNames, true);
);
} }
pub fn _createDocumentFragment(self: *parser.Document) !*parser.DocumentFragment { pub fn _createDocumentFragment(self: *parser.Document) !*parser.DocumentFragment {
@@ -169,8 +168,11 @@ pub const Document = struct {
// ParentNode // ParentNode
// https://dom.spec.whatwg.org/#parentnode // https://dom.spec.whatwg.org/#parentnode
pub fn get_children(self: *parser.Document) !collection.HTMLCollection { pub fn get_children(self: *parser.Document) !collection.HTMLCollection {
const root = try parser.documentGetDocumentElement(self); var elt: ?*parser.Node = null;
return try collection.HTMLCollectionChildren(parser.elementToNode(root), true); if (try parser.documentGetDocumentElement(self)) |root| {
elt = parser.elementToNode(root);
}
return try collection.HTMLCollectionChildren(elt, true);
} }
pub fn deinit(_: *parser.Document, _: std.mem.Allocator) void {} pub fn deinit(_: *parser.Document, _: std.mem.Allocator) void {}
@@ -188,6 +190,12 @@ pub fn testExecFn(
.{ .src = "document.__proto__.__proto__.constructor.name", .ex = "Document" }, .{ .src = "document.__proto__.__proto__.constructor.name", .ex = "Document" },
.{ .src = "document.__proto__.__proto__.__proto__.constructor.name", .ex = "Node" }, .{ .src = "document.__proto__.__proto__.__proto__.constructor.name", .ex = "Node" },
.{ .src = "document.__proto__.__proto__.__proto__.__proto__.constructor.name", .ex = "EventTarget" }, .{ .src = "document.__proto__.__proto__.__proto__.__proto__.constructor.name", .ex = "EventTarget" },
.{ .src = "let newdoc = new Document()", .ex = "undefined" },
.{ .src = "newdoc.documentElement", .ex = "null" },
.{ .src = "newdoc.children.length", .ex = "0" },
.{ .src = "newdoc.getElementsByTagName('*').length", .ex = "0" },
.{ .src = "newdoc.getElementsByTagName('*').item(0)", .ex = "null" },
}; };
try checkCases(js_env, &constructor); try checkCases(js_env, &constructor);

View File

@@ -57,7 +57,7 @@ pub const MatchByTagName = struct {
pub fn HTMLCollectionByTagName( pub fn HTMLCollectionByTagName(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
root: *parser.Node, root: ?*parser.Node,
tag_name: []const u8, tag_name: []const u8,
include_root: bool, include_root: bool,
) !HTMLCollection { ) !HTMLCollection {
@@ -101,7 +101,7 @@ pub const MatchByClassName = struct {
pub fn HTMLCollectionByClassName( pub fn HTMLCollectionByClassName(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
root: *parser.Node, root: ?*parser.Node,
classNames: []const u8, classNames: []const u8,
include_root: bool, include_root: bool,
) !HTMLCollection { ) !HTMLCollection {
@@ -116,7 +116,7 @@ pub fn HTMLCollectionByClassName(
} }
pub fn HTMLCollectionChildren( pub fn HTMLCollectionChildren(
root: *parser.Node, root: ?*parser.Node,
include_root: bool, include_root: bool,
) !HTMLCollection { ) !HTMLCollection {
return HTMLCollection{ return HTMLCollection{
@@ -219,7 +219,7 @@ pub const HTMLCollection = struct {
matcher: Matcher, matcher: Matcher,
walker: Walker, walker: Walker,
root: *parser.Node, root: ?*parser.Node,
// By default the HTMLCollection walk on the root's descendant only. // By default the HTMLCollection walk on the root's descendant only.
// But on somes cases, like for dom document, we want to walk over the root // But on somes cases, like for dom document, we want to walk over the root
@@ -232,17 +232,21 @@ pub const HTMLCollection = struct {
// start returns the first node to walk on. // start returns the first node to walk on.
fn start(self: HTMLCollection) !?*parser.Node { fn start(self: HTMLCollection) !?*parser.Node {
if (self.root == null) return null;
if (self.include_root) { if (self.include_root) {
return self.root; return self.root.?;
} }
return try self.walker.get_next(self.root, null); return try self.walker.get_next(self.root.?, null);
} }
/// get_length computes the collection's length dynamically according to /// get_length computes the collection's length dynamically according to
/// the current root structure. /// the current root structure.
// TODO: nodes retrieved must be de-referenced. // TODO: nodes retrieved must be de-referenced.
pub fn get_length(self: *HTMLCollection) !u32 { pub fn get_length(self: *HTMLCollection) !u32 {
if (self.root == null) return 0;
var len: u32 = 0; var len: u32 = 0;
var node = try self.start() orelse return 0; var node = try self.start() orelse return 0;
@@ -253,13 +257,15 @@ pub const HTMLCollection = struct {
} }
} }
node = try self.walker.get_next(self.root, node) orelse break; node = try self.walker.get_next(self.root.?, node) orelse break;
} }
return len; return len;
} }
pub fn _item(self: *HTMLCollection, index: u32) !?Union { pub fn _item(self: *HTMLCollection, index: u32) !?Union {
if (self.root == null) return null;
var i: u32 = 0; var i: u32 = 0;
var node: *parser.Node = undefined; var node: *parser.Node = undefined;
@@ -288,16 +294,15 @@ pub const HTMLCollection = struct {
} }
} }
node = try self.walker.get_next(self.root, node) orelse break; node = try self.walker.get_next(self.root.?, node) orelse break;
} }
return null; return null;
} }
pub fn _namedItem(self: *HTMLCollection, name: []const u8) !?Union { pub fn _namedItem(self: *HTMLCollection, name: []const u8) !?Union {
if (name.len == 0) { if (self.root == null) return null;
return null; if (name.len == 0) return null;
}
var node = try self.start() orelse return null; var node = try self.start() orelse return null;
@@ -320,7 +325,7 @@ pub const HTMLCollection = struct {
} }
} }
node = try self.walker.get_next(self.root, node) orelse break; node = try self.walker.get_next(self.root.?, node) orelse break;
} }
return null; return null;

View File

@@ -1150,10 +1150,11 @@ pub inline fn documentGetElementsByTagName(doc: *Document, tagname: []const u8)
} }
// documentGetDocumentElement returns the root document element. // documentGetDocumentElement returns the root document element.
pub inline fn documentGetDocumentElement(doc: *Document) !*Element { pub inline fn documentGetDocumentElement(doc: *Document) !?*Element {
var elem: ?*Element = undefined; var elem: ?*Element = undefined;
const err = documentVtable(doc).dom_document_get_document_element.?(doc, &elem); const err = documentVtable(doc).dom_document_get_document_element.?(doc, &elem);
try DOMErr(err); try DOMErr(err);
if (elem == null) return null;
return elem.?; return elem.?;
} }