Merge pull request #558 from lightpanda-io/node_is_equal

Implement custom isEqualNode
This commit is contained in:
Pierre Tachoire
2025-04-23 09:50:43 +02:00
committed by GitHub
4 changed files with 116 additions and 0 deletions

View File

@@ -97,6 +97,21 @@ pub const CharacterData = struct {
pub fn _substringData(self: *parser.CharacterData, offset: u32, count: u32) ![]const u8 { pub fn _substringData(self: *parser.CharacterData, offset: u32, count: u32) ![]const u8 {
return try parser.characterDataSubstringData(self, offset, count); return try parser.characterDataSubstringData(self, offset, count);
} }
// netsurf's CharacterData (text, comment) doesn't implement the
// dom_node_get_attributes and thus will crash if we try to call nodeIsEqualNode.
pub fn _isEqualNode(self: *parser.CharacterData, other_node: *parser.Node) !bool {
if (try parser.nodeType(@ptrCast(self)) != try parser.nodeType(other_node)) {
return false;
}
const other: *parser.CharacterData = @ptrCast(other_node);
if (std.mem.eql(u8, try get_data(self), try get_data(other)) == false) {
return false;
}
return true;
}
}; };
// Tests // Tests
@@ -163,4 +178,9 @@ test "Browser.DOM.CharacterData" {
.{ "cdata.substringData('OK'.length-1, 'replaced'.length) == 'replaced'", "true" }, .{ "cdata.substringData('OK'.length-1, 'replaced'.length) == 'replaced'", "true" },
.{ "cdata.substringData('OK'.length-1, 0) == ''", "true" }, .{ "cdata.substringData('OK'.length-1, 0) == ''", "true" },
}, .{}); }, .{});
try runner.testCases(&.{
.{ "cdata.substringData('OK'.length-1, 'replaced'.length) == 'replaced'", "true" },
.{ "cdata.substringData('OK'.length-1, 0) == ''", "true" },
}, .{});
} }

View File

@@ -34,6 +34,15 @@ pub const DocumentFragment = struct {
parser.documentHTMLToDocument(state.document.?), parser.documentHTMLToDocument(state.document.?),
); );
} }
pub fn _isEqualNode(self: *parser.DocumentFragment, other_node: *parser.Node) !bool {
const other_type = try parser.nodeType(other_node);
if (other_type != .document_fragment) {
return false;
}
_ = self;
return true;
}
}; };
const testing = @import("../../testing.zig"); const testing = @import("../../testing.zig");
@@ -45,4 +54,11 @@ test "Browser.DOM.DocumentFragment" {
.{ "const dc = new DocumentFragment()", "undefined" }, .{ "const dc = new DocumentFragment()", "undefined" },
.{ "dc.constructor.name", "DocumentFragment" }, .{ "dc.constructor.name", "DocumentFragment" },
}, .{}); }, .{});
try runner.testCases(&.{
.{ "const dc1 = new DocumentFragment()", "undefined" },
.{ "const dc2 = new DocumentFragment()", "undefined" },
.{ "dc1.isEqualNode(dc1)", "true" },
.{ "dc1.isEqualNode(dc2)", "true" },
}, .{});
} }

View File

@@ -39,4 +39,42 @@ pub const DocumentType = struct {
pub fn get_systemId(self: *parser.DocumentType) ![]const u8 { pub fn get_systemId(self: *parser.DocumentType) ![]const u8 {
return try parser.documentTypeGetSystemId(self); return try parser.documentTypeGetSystemId(self);
} }
// netsurf's DocumentType doesn't implement the dom_node_get_attributes
// and thus will crash if we try to call nodeIsEqualNode.
pub fn _isEqualNode(self: *parser.DocumentType, other_node: *parser.Node) !bool {
if (try parser.nodeType(other_node) != .document_type) {
return false;
}
const other: *parser.DocumentType = @ptrCast(other_node);
if (std.mem.eql(u8, try get_name(self), try get_name(other)) == false) {
return false;
}
if (std.mem.eql(u8, try get_publicId(self), try get_publicId(other)) == false) {
return false;
}
if (std.mem.eql(u8, try get_systemId(self), try get_systemId(other)) == false) {
return false;
}
return true;
}
}; };
const testing = @import("../../testing.zig");
test "Browser.DOM.DocumentType" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
defer runner.deinit();
try runner.testCases(&.{
.{ "let dt1 = document.implementation.createDocumentType('qname1', 'pid1', 'sys1');", "undefined" },
.{ "let dt2 = document.implementation.createDocumentType('qname2', 'pid2', 'sys2');", "undefined" },
.{ "let dt3 = document.implementation.createDocumentType('qname1', 'pid1', 'sys1');", "undefined" },
.{ "dt1.isEqualNode(dt1)", "true" },
.{ "dt1.isEqualNode(dt3)", "true" },
.{ "dt1.isEqualNode(dt2)", "false" },
.{ "dt2.isEqualNode(dt3)", "false" },
.{ "dt1.isEqualNode(document)", "false" },
.{ "document.isEqualNode(dt1)", "false" },
}, .{});
}

View File

@@ -46,6 +46,36 @@ pub const ProcessingInstruction = struct {
pub fn set_data(self: *parser.ProcessingInstruction, data: []u8) !void { pub fn set_data(self: *parser.ProcessingInstruction, data: []u8) !void {
try parser.nodeSetValue(parser.processingInstructionToNode(self), data); try parser.nodeSetValue(parser.processingInstructionToNode(self), data);
} }
// netsurf's ProcessInstruction doesn't implement the dom_node_get_attributes
// and thus will crash if we try to call nodeIsEqualNode.
pub fn _isEqualNode(self: *parser.ProcessingInstruction, other_node: *parser.Node) !bool {
if (try parser.nodeType(other_node) != .processing_instruction) {
return false;
}
const other: *parser.ProcessingInstruction = @ptrCast(other_node);
if (std.mem.eql(u8, try get_target(self), try get_target(other)) == false) {
return false;
}
{
const self_data = try get_data(self);
const other_data = try get_data(other);
if (self_data == null and other_data != null) {
return false;
}
if (self_data != null and other_data == null) {
return false;
}
if (std.mem.eql(u8, self_data.?, other_data.?) == false) {
return false;
}
}
return true;
}
}; };
const testing = @import("../../testing.zig"); const testing = @import("../../testing.zig");
@@ -62,4 +92,16 @@ test "Browser.DOM.ProcessingInstruction" {
.{ "let pi2 = pi.cloneNode()", "undefined" }, .{ "let pi2 = pi.cloneNode()", "undefined" },
}, .{}); }, .{});
try runner.testCases(&.{
.{ "let pi11 = document.createProcessingInstruction('target1', 'data1');", "undefined" },
.{ "let pi12 = document.createProcessingInstruction('target2', 'data2');", "undefined" },
.{ "let pi13 = document.createProcessingInstruction('target1', 'data1');", "undefined" },
.{ "pi11.isEqualNode(pi11)", "true" },
.{ "pi11.isEqualNode(pi13)", "true" },
.{ "pi11.isEqualNode(pi12)", "false" },
.{ "pi12.isEqualNode(pi13)", "false" },
.{ "pi11.isEqualNode(document)", "false" },
.{ "document.isEqualNode(pi11)", "false" },
}, .{});
} }