NodeList index fix + Node.childNode fix

An index out of range request to a nodelist , e.g. childNodes[1000] now properly
returns a error.NotHandled error, which is given to v8 as a non-intercepted
property.

When a ChildNode node list is created from Node.childNode, we store the *Node
rather than its children. ChildNode is meant to be live, so if the node's
children changes, we should capture that.
This commit is contained in:
Karl Seguin
2026-02-14 14:51:33 +08:00
parent bbff64bc96
commit f25e972594
4 changed files with 14 additions and 8 deletions

View File

@@ -22,6 +22,8 @@
testing.expectEqual(undefined, children[-1]);
testing.expectEqual(['p1', 'p2'], Array.from(children).map((n) => n.id));
testing.expectEqual(false, 10 in children);
</script>
<script id=values>

View File

@@ -249,8 +249,8 @@ pub fn appendChild(self: *Node, child: *Node, page: *Page) !*Node {
return child;
}
pub fn childNodes(self: *const Node, page: *Page) !*collections.ChildNodes {
return collections.ChildNodes.init(self._children, page);
pub fn childNodes(self: *Node, page: *Page) !*collections.ChildNodes {
return collections.ChildNodes.init(self, page);
}
pub fn getTextContent(self: *Node, writer: *std.Io.Writer) error{WriteFailed}!void {

View File

@@ -30,18 +30,18 @@ _last_index: usize,
_last_length: ?u32,
_last_node: ?*std.DoublyLinkedList.Node,
_cached_version: usize,
_children: ?*Node.Children,
_node: *Node,
pub const KeyIterator = GenericIterator(Iterator, "0");
pub const ValueIterator = GenericIterator(Iterator, "1");
pub const EntryIterator = GenericIterator(Iterator, null);
pub fn init(children: ?*Node.Children, page: *Page) !*ChildNodes {
pub fn init(node: *Node, page: *Page) !*ChildNodes {
return page._factory.create(ChildNodes{
._node = node,
._last_index = 0,
._last_node = null,
._last_length = null,
._children = children,
._cached_version = page.version,
});
}
@@ -52,7 +52,7 @@ pub fn length(self: *ChildNodes, page: *Page) !u32 {
return cached_length;
}
}
const children = self._children orelse return 0;
const children = self._node._children orelse return 0;
// O(N)
const len = children.len();
@@ -86,7 +86,7 @@ pub fn getAtIndex(self: *ChildNodes, index: usize, page: *Page) !?*Node {
}
pub fn first(self: *const ChildNodes) ?*std.DoublyLinkedList.Node {
return &(self._children orelse return null).first()._child_link;
return &(self._node._children orelse return null).first()._child_link;
}
pub fn keys(self: *ChildNodes, page: *Page) !*KeyIterator {

View File

@@ -53,6 +53,10 @@ pub fn length(self: *NodeList, page: *Page) !u32 {
};
}
pub fn indexedGet(self: *NodeList, index: usize, page: *Page) !*Node {
return try self.getAtIndex(index, page) orelse return error.NotHandled;
}
pub fn getAtIndex(self: *NodeList, index: usize, page: *Page) !?*Node {
return switch (self.data) {
.child_nodes => |impl| impl.getAtIndex(index, page),
@@ -121,7 +125,7 @@ pub const JsApi = struct {
};
pub const length = bridge.accessor(NodeList.length, null, .{});
pub const @"[]" = bridge.indexed(NodeList.getAtIndex, .{ .null_as_undefined = true });
pub const @"[]" = bridge.indexed(NodeList.indexedGet, .{ .null_as_undefined = true });
pub const item = bridge.function(NodeList.getAtIndex, .{});
pub const keys = bridge.function(NodeList.keys, .{});
pub const values = bridge.function(NodeList.values, .{});