Merge pull request #1503 from lightpanda-io/node_iterator

Fix 3 WPT cases for NodeIterator
This commit is contained in:
Pierre Tachoire
2026-02-09 15:39:24 +01:00
committed by GitHub
5 changed files with 58 additions and 9 deletions

View File

@@ -336,6 +336,7 @@ fn handleError(self: *Caller, comptime T: type, comptime F: type, err: anyerror,
}
const js_err: *const v8.Value = switch (err) {
error.TryCatchRethrow => return,
error.InvalidArgument => isolate.createTypeError("invalid argument"),
error.OutOfMemory => isolate.createError("out of memory"),
error.IllegalConstructor => isolate.createError("Illegal Contructor"),

View File

@@ -69,7 +69,15 @@ pub fn newInstance(self: *const Function, caught: *js.TryCatch.Caught) !js.Objec
pub fn call(self: *const Function, comptime T: type, args: anytype) !T {
var caught: js.TryCatch.Caught = undefined;
return self._tryCallWithThis(T, self.getThis(), args, &caught) catch |err| {
return self._tryCallWithThis(T, self.getThis(), args, &caught, .{}) catch |err| {
log.warn(.js, "call caught", .{ .err = err, .caught = caught });
return err;
};
}
pub fn callRethrow(self: *const Function, comptime T: type, args: anytype) !T {
var caught: js.TryCatch.Caught = undefined;
return self._tryCallWithThis(T, self.getThis(), args, &caught, .{ .rethrow = true }) catch |err| {
log.warn(.js, "call caught", .{ .err = err, .caught = caught });
return err;
};
@@ -77,21 +85,24 @@ pub fn call(self: *const Function, comptime T: type, args: anytype) !T {
pub fn callWithThis(self: *const Function, comptime T: type, this: anytype, args: anytype) !T {
var caught: js.TryCatch.Caught = undefined;
return self._tryCallWithThis(T, this, args, &caught) catch |err| {
return self._tryCallWithThis(T, this, args, &caught, .{}) catch |err| {
log.warn(.js, "callWithThis caught", .{ .err = err, .caught = caught });
return err;
};
}
pub fn tryCall(self: *const Function, comptime T: type, args: anytype, caught: *js.TryCatch.Caught) !T {
return self._tryCallWithThis(T, self.getThis(), args, caught);
return self._tryCallWithThis(T, self.getThis(), args, caught, .{});
}
pub fn tryCallWithThis(self: *const Function, comptime T: type, this: anytype, args: anytype, caught: *js.TryCatch.Caught) !T {
return self._tryCallWithThis(T, this, args, caught);
return self._tryCallWithThis(T, this, args, caught, .{});
}
pub fn _tryCallWithThis(self: *const Function, comptime T: type, this: anytype, args: anytype, caught: *js.TryCatch.Caught) !T {
const CallOpts = struct {
rethrow: bool = false,
};
fn _tryCallWithThis(self: *const Function, comptime T: type, this: anytype, args: anytype, caught: *js.TryCatch.Caught, comptime opts: CallOpts) !T {
caught.* = .{};
const local = self.local;
@@ -145,6 +156,10 @@ pub fn _tryCallWithThis(self: *const Function, comptime T: type, this: anytype,
defer try_catch.deinit();
const handle = v8.v8__Function__Call(self.handle, local.handle, js_this.handle, @as(c_int, @intCast(js_args.len)), c_args) orelse {
if ((comptime opts.rethrow) and try_catch.hasCaught()) {
try_catch.rethrow();
return error.TryCatchRethrow;
}
caught.* = try_catch.caughtOrError(local.call_arena, error.JSExecCallback);
return error.JSExecCallback;
};

View File

@@ -20,6 +20,8 @@ const std = @import("std");
const js = @import("js.zig");
const v8 = js.v8;
const IS_DEBUG = @import("builtin").mode == .Debug;
const Allocator = std.mem.Allocator;
const TryCatch = @This();
@@ -32,8 +34,19 @@ pub fn init(self: *TryCatch, l: *const js.Local) void {
v8.v8__TryCatch__CONSTRUCT(&self.handle, l.isolate.handle);
}
pub fn hasCaught(self: TryCatch) bool {
return v8.v8__TryCatch__HasCaught(&self.handle);
}
pub fn rethrow(self: *TryCatch) void {
if (comptime IS_DEBUG) {
std.debug.assert(self.hasCaught());
}
_ = v8.v8__TryCatch__ReThrow(&self.handle);
}
pub fn caught(self: TryCatch, allocator: Allocator) ?Caught {
if (!v8.v8__TryCatch__HasCaught(&self.handle)) {
if (self.hasCaught() == false) {
return null;
}

View File

@@ -31,6 +31,7 @@ _what_to_show: u32,
_filter: NodeFilter,
_reference_node: *Node,
_pointer_before_reference_node: bool,
_active: bool = false,
pub fn init(root: *Node, what_to_show: u32, filter: ?FilterOpts, page: *Page) !*DOMNodeIterator {
const node_filter = try NodeFilter.init(filter);
@@ -64,6 +65,13 @@ pub fn getFilter(self: *const DOMNodeIterator) ?FilterOpts {
}
pub fn nextNode(self: *DOMNodeIterator, page: *Page) !?*Node {
if (self._active) {
return error.InvalidStateError;
}
self._active = true;
defer self._active = false;
var node = self._reference_node;
var before_node = self._pointer_before_reference_node;
@@ -95,6 +103,13 @@ pub fn nextNode(self: *DOMNodeIterator, page: *Page) !?*Node {
}
pub fn previousNode(self: *DOMNodeIterator, page: *Page) !?*Node {
if (self._active) {
return error.InvalidStateError;
}
self._active = true;
defer self._active = false;
var node = self._reference_node;
var before_node = self._pointer_before_reference_node;
@@ -119,6 +134,10 @@ pub fn previousNode(self: *DOMNodeIterator, page: *Page) !?*Node {
}
}
pub fn detach(_: *const DOMNodeIterator) void {
// no-op legacy
}
fn filterNode(self: *const DOMNodeIterator, node: *Node, page: *Page) !i32 {
// First check whatToShow
if (!NodeFilter.shouldShow(node, self._what_to_show)) {
@@ -181,6 +200,7 @@ pub const JsApi = struct {
pub const whatToShow = bridge.accessor(DOMNodeIterator.getWhatToShow, null, .{});
pub const filter = bridge.accessor(DOMNodeIterator.getFilter, null, .{});
pub const nextNode = bridge.function(DOMNodeIterator.nextNode, .{});
pub const previousNode = bridge.function(DOMNodeIterator.previousNode, .{});
pub const nextNode = bridge.function(DOMNodeIterator.nextNode, .{ .dom_exception = true });
pub const previousNode = bridge.function(DOMNodeIterator.previousNode, .{ .dom_exception = true });
pub const detach = bridge.function(DOMNodeIterator.detach, .{});
};

View File

@@ -67,7 +67,7 @@ pub const SHOW_NOTATION: u32 = 0x800;
pub fn acceptNode(self: *const NodeFilter, node: *Node, local: *const js.Local) !i32 {
const func = self._func orelse return FILTER_ACCEPT;
return local.toLocal(func).call(i32, .{node});
return local.toLocal(func).callRethrow(i32, .{node});
}
pub fn shouldShow(node: *const Node, what_to_show: u32) bool {