An empty anchor should return empty strings for its getters

document.createElement('a').host  or .href or .. should return an empty string.

However, URL.constructor(document.createElement('a')) should fail.

Because HTMLAnchorElement uses URL.constructor, we have the wrong behavior.

This adds a guard for an empty anchor. This might not cover all of the cases
which are valid for an anchor but invalid for a URL.constructor, but it's
the most common.
This commit is contained in:
Karl Seguin
2025-07-04 19:23:19 +08:00
parent 22a644ba01
commit d7155e6662
2 changed files with 19 additions and 2 deletions

View File

@@ -271,8 +271,18 @@ pub const HTMLAnchorElement = struct {
return try parser.nodeSetTextContent(parser.anchorToNode(self), v);
}
inline fn url(self: *parser.Anchor, page: *Page) !URL {
return URL.constructor(.{ .element = @alignCast(@ptrCast(self)) }, null, page); // TODO inject base url
fn url(self: *parser.Anchor, page: *Page) !URL {
// Although the URL.constructor union accepts an .{.element = X}, we
// can't use this here because the behavior is different.
// new URL(document.createElement('a')
// should fail (a.href isn't a valid URL)
// But
// document.createElement('a').host
// should not fail, it should return an empty string
if (try parser.elementGetAttribute(@alignCast(@ptrCast(self)), "href")) |href| {
return URL.constructor(.{ .string = href }, null, page); // TODO inject base url
}
return .empty;
}
// TODO return a disposable string
@@ -1559,6 +1569,8 @@ test "Browser.HTML.Element" {
try runner.testCases(&.{
.{ "let a = document.createElement('a');", null },
.{ "a.href", "" },
.{ "a.host", "" },
.{ "a.href = 'about'", null },
.{ "a.href", "https://lightpanda.io/opensource-browser/about" },
}, .{});

View File

@@ -54,6 +54,11 @@ pub const URL = struct {
uri: std.Uri,
search_params: URLSearchParams,
pub const empty = URL{
.uri = .{ .scheme = "" },
.search_params = .{},
};
const URLArg = union(enum) {
url: *URL,
element: *parser.ElementHTML,