webapi: Headers.getSetCookie, customElements.getName, Element.part

Three one-accessor gaps: getSetCookie returns Set-Cookie values
unjoined, getName maps a constructor back to its tag, part is a
DOMTokenList over the part attribute like relList.
This commit is contained in:
Adrià Arrufat committed 2026-09-01 10:17:14 +02:00
1 parent a43db3cbd2
commit 223a7ef728
7 files changed
+79

No files matched your search

+1
View File
@@ -145,6 +145,7 @@ _element_computed_styles: Element.ComputedStyleLookup = .empty,
_element_datasets: Element.DatasetLookup = .empty,
_element_class_lists: Element.ClassListLookup = .empty,
_element_rel_lists: Element.RelListLookup = .empty,
_element_part_lists: Element.PartListLookup = .empty,
_element_token_lists: Element.TokenListLookup = .empty,
_element_shadow_roots: Element.ShadowRootLookup = .empty,
_node_owner_documents: Node.OwnerDocumentLookup = .empty,
@@ -149,3 +149,12 @@
testing.expectEqual(1, constructorCalled);
}
</script>
<script id=getName>
{
class NamedElement extends HTMLElement {}
customElements.define('named-element', NamedElement);
testing.expectEqual('named-element', customElements.getName(NamedElement));
testing.expectEqual(null, customElements.getName(class extends HTMLElement {}));
}
</script>
+24
View File
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<script src="../testing.js"></script>
<div id=d1 part="label primary"></div>
<div id=d2></div>
<script id=part>
{
const part = $('#d1').part;
testing.expectEqual(true, part instanceof DOMTokenList);
testing.expectEqual(part, $('#d1').part);
testing.expectEqual(2, part.length);
testing.expectEqual(true, part.contains('primary'));
part.add('active');
testing.expectEqual('label primary active', $('#d1').getAttribute('part'));
part.remove('label');
testing.expectEqual('primary active', $('#d1').getAttribute('part'));
testing.expectEqual(0, $('#d2').part.length);
$('#d2').part.add('x');
testing.expectEqual('x', $('#d2').getAttribute('part'));
}
</script>
+16
View File
@@ -364,3 +364,19 @@
testing.expectEqual(1, authEntries.length);
}
</script>
<script id=getSetCookie>
{
const headers = new Headers();
testing.expectEqual(0, headers.getSetCookie().length);
headers.append('Set-Cookie', 'a=1; Path=/');
headers.append('set-cookie', 'b=2; HttpOnly');
// get() joins, which corrupts cookies that themselves contain commas.
testing.expectEqual('a=1; Path=/, b=2; HttpOnly', headers.get('Set-Cookie'));
const cookies = headers.getSetCookie();
testing.expectEqual(2, cookies.length);
testing.expectEqual('a=1; Path=/', cookies[0]);
testing.expectEqual('b=2; HttpOnly', cookies[1]);
}
</script>
@@ -137,6 +137,16 @@ pub fn get(self: *CustomElementRegistry, name: []const u8) ?js.Function.Global {
return definition.constructor;
}
pub fn getName(self: *CustomElementRegistry, constructor: js.Function) ?[]const u8 {
var it = self._definitions.iterator();
while (it.next()) |entry| {
if (entry.value_ptr.*.constructor.isEqual(constructor)) {
return entry.key_ptr.*;
}
}
return null;
}
pub fn upgrade(self: *CustomElementRegistry, root: *Node, frame: *Frame) !void {
try upgradeNode(self, root, frame);
}
@@ -319,6 +329,7 @@ pub const JsApi = struct {
pub const define = bridge.function(CustomElementRegistry.define, .{ .ce_reactions = true });
pub const get = bridge.function(CustomElementRegistry.get, .{ .null_as_undefined = true });
pub const getName = bridge.function(CustomElementRegistry.getName, .{});
pub const upgrade = bridge.function(CustomElementRegistry.upgrade, .{ .ce_reactions = true });
pub const whenDefined = bridge.function(CustomElementRegistry.whenDefined, .{});
};
+13
View File
@@ -79,6 +79,7 @@ pub const PseudoElement = enum {
pub const ClassListLookup = std.AutoHashMapUnmanaged(*Element, *collections.DOMTokenList);
pub const RelListLookup = std.AutoHashMapUnmanaged(*Element, *collections.DOMTokenList);
pub const PartListLookup = std.AutoHashMapUnmanaged(*Element, *collections.DOMTokenList);
pub const ShadowRootLookup = std.AutoHashMapUnmanaged(*Element, *ShadowRoot);
pub const NamespaceUriLookup = std.AutoHashMapUnmanaged(*Element, []const u8);
@@ -1026,6 +1027,17 @@ pub fn setClassList(self: *Element, value: String, frame: *Frame) !void {
try class_list.setValue(value, frame);
}
pub fn getPartList(self: *Element, frame: *Frame) !*collections.DOMTokenList {
const gop = try frame._element_part_lists.getOrPut(frame.arena, self);
if (!gop.found_existing) {
gop.value_ptr.* = try frame._factory.create(collections.DOMTokenList{
._element = self,
._attribute_name = comptime .wrap("part"),
});
}
return gop.value_ptr.*;
}
pub fn getRelList(self: *Element, frame: *Frame) !*collections.DOMTokenList {
const gop = try frame._element_rel_lists.getOrPut(frame.arena, self);
if (!gop.found_existing) {
@@ -2431,6 +2443,7 @@ pub const JsApi = struct {
pub const dir = bridge.accessor(Element.getDir, Element.setDir, .{ .ce_reactions = true });
pub const className = bridge.accessor(Element.getClassName, Element.setClassName, .{ .ce_reactions = true });
pub const classList = bridge.accessor(Element.getClassList, Element.setClassList, .{ .ce_reactions = true });
pub const part = bridge.accessor(Element.getPartList, null, .{});
pub const dataset = bridge.accessor(Element.getDataset, null, .{});
pub const style = bridge.accessor(Element.getOrCreateStyle, Element.setStyle, .{});
pub const attributes = bridge.accessor(Element.getAttributeNamedNodeMap, null, .{});
+5
View File
@@ -65,6 +65,10 @@ pub fn get(self: *const Headers, name: []const u8, exec: *const Execution) !?[]c
return try std.mem.join(exec.local_arena, ", ", all_values);
}
pub fn getSetCookie(self: *const Headers, exec: *const Execution) ![]const []const u8 {
return self._list.getAll(exec.local_arena, "set-cookie");
}
pub fn has(self: *const Headers, name: []const u8, exec: *const Execution) bool {
const normalized_name = normalizeHeaderName(name, exec.buf);
return self._list.has(normalized_name, null);
@@ -143,6 +147,7 @@ pub const JsApi = struct {
pub const append = bridge.function(Headers.append, .{});
pub const delete = bridge.function(Headers.delete, .{});
pub const get = bridge.function(Headers.get, .{});
pub const getSetCookie = bridge.function(Headers.getSetCookie, .{});
pub const has = bridge.function(Headers.has, .{});
pub const set = bridge.function(Headers.set, .{});
pub const keys = bridge.function(Headers.keys, .{});