From 151cefe0ec47fbe567312fb931273668a6106a83 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Wed, 11 Feb 2026 20:53:13 +0800 Subject: [PATCH] Ability to remove a type from the global's iterable list. Some types, like AbortController, shouldn't be iterable on the window. This commit (a) adds the ability to control this in the snapshot, and sets the iterability based on the dom/interface-objects.html wpt test list. --- src/browser/js/Snapshot.zig | 8 ++++++-- src/browser/webapi/AbortController.zig | 1 + src/browser/webapi/AbortSignal.zig | 1 + src/browser/webapi/CData.zig | 1 + src/browser/webapi/DOMImplementation.zig | 1 + src/browser/webapi/DOMNodeIterator.zig | 1 + src/browser/webapi/DOMTreeWalker.zig | 1 + src/browser/webapi/Document.zig | 1 + src/browser/webapi/DocumentFragment.zig | 1 + src/browser/webapi/DocumentType.zig | 1 + src/browser/webapi/Element.zig | 1 + src/browser/webapi/Event.zig | 1 + src/browser/webapi/EventTarget.zig | 1 + src/browser/webapi/Node.zig | 1 + src/browser/webapi/NodeFilter.zig | 1 + src/browser/webapi/cdata/Comment.zig | 1 + src/browser/webapi/cdata/ProcessingInstruction.zig | 1 + src/browser/webapi/cdata/Text.zig | 1 + src/browser/webapi/collections/DOMTokenList.zig | 1 + src/browser/webapi/collections/HTMLCollection.zig | 1 + src/browser/webapi/collections/NodeList.zig | 1 + src/browser/webapi/element/Attribute.zig | 5 +---- src/browser/webapi/event/CustomEvent.zig | 1 + 23 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/browser/js/Snapshot.zig b/src/browser/js/Snapshot.zig index e38f30a2..6610fb7c 100644 --- a/src/browser/js/Snapshot.zig +++ b/src/browser/js/Snapshot.zig @@ -202,12 +202,16 @@ pub fn create() !Snapshot { const name = JsApi.Meta.name; const illegal_class_name = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len)); var maybe_result2: v8.MaybeBool = undefined; - v8.v8__Object__Set(global_obj, context, illegal_class_name, func, &maybe_result2); + v8.v8__Object__DefineOwnProperty(global_obj, context, illegal_class_name, func, 0, &maybe_result2); } else { const name = JsApi.Meta.name; const v8_class_name = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len)); var maybe_result: v8.MaybeBool = undefined; - v8.v8__Object__Set(global_obj, context, v8_class_name, func, &maybe_result); + var properties: v8.PropertyAttribute = v8.None; + if (@hasDecl(JsApi.Meta, "enumerable") and JsApi.Meta.enumerable == false) { + properties |= v8.DontEnum; + } + v8.v8__Object__DefineOwnProperty(global_obj, context, v8_class_name, func, properties, &maybe_result); } } } diff --git a/src/browser/webapi/AbortController.zig b/src/browser/webapi/AbortController.zig index 0c251a47..0c22bd4d 100644 --- a/src/browser/webapi/AbortController.zig +++ b/src/browser/webapi/AbortController.zig @@ -49,6 +49,7 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const constructor = bridge.constructor(AbortController.init, .{}); diff --git a/src/browser/webapi/AbortSignal.zig b/src/browser/webapi/AbortSignal.zig index 6472299c..8eb61062 100644 --- a/src/browser/webapi/AbortSignal.zig +++ b/src/browser/webapi/AbortSignal.zig @@ -157,6 +157,7 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const Prototype = EventTarget; diff --git a/src/browser/webapi/CData.zig b/src/browser/webapi/CData.zig index 6f04e0ae..b7b6d371 100644 --- a/src/browser/webapi/CData.zig +++ b/src/browser/webapi/CData.zig @@ -273,6 +273,7 @@ pub const JsApi = struct { pub const name = "CharacterData"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const data = bridge.accessor(CData.getData, CData.setData, .{}); diff --git a/src/browser/webapi/DOMImplementation.zig b/src/browser/webapi/DOMImplementation.zig index 82405cdd..baee5fd4 100644 --- a/src/browser/webapi/DOMImplementation.zig +++ b/src/browser/webapi/DOMImplementation.zig @@ -99,6 +99,7 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; pub const empty_with_no_proto = true; + pub const enumerable = false; }; pub const createDocumentType = bridge.function(DOMImplementation.createDocumentType, .{ .dom_exception = true }); diff --git a/src/browser/webapi/DOMNodeIterator.zig b/src/browser/webapi/DOMNodeIterator.zig index a4956ca7..d492039e 100644 --- a/src/browser/webapi/DOMNodeIterator.zig +++ b/src/browser/webapi/DOMNodeIterator.zig @@ -192,6 +192,7 @@ pub const JsApi = struct { pub const name = "NodeIterator"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const root = bridge.accessor(DOMNodeIterator.getRoot, null, .{}); diff --git a/src/browser/webapi/DOMTreeWalker.zig b/src/browser/webapi/DOMTreeWalker.zig index 5b9e9a2c..46b5ef3e 100644 --- a/src/browser/webapi/DOMTreeWalker.zig +++ b/src/browser/webapi/DOMTreeWalker.zig @@ -344,6 +344,7 @@ pub const JsApi = struct { pub const name = "TreeWalker"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const root = bridge.accessor(DOMTreeWalker.getRoot, null, .{}); diff --git a/src/browser/webapi/Document.zig b/src/browser/webapi/Document.zig index 18102a98..d03bbb30 100644 --- a/src/browser/webapi/Document.zig +++ b/src/browser/webapi/Document.zig @@ -934,6 +934,7 @@ pub const JsApi = struct { pub const name = "Document"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const constructor = bridge.constructor(_constructor, .{}); diff --git a/src/browser/webapi/DocumentFragment.zig b/src/browser/webapi/DocumentFragment.zig index 74099104..0967879a 100644 --- a/src/browser/webapi/DocumentFragment.zig +++ b/src/browser/webapi/DocumentFragment.zig @@ -233,6 +233,7 @@ pub const JsApi = struct { pub const name = "DocumentFragment"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const constructor = bridge.constructor(DocumentFragment.init, .{}); diff --git a/src/browser/webapi/DocumentType.zig b/src/browser/webapi/DocumentType.zig index babda434..c70fc907 100644 --- a/src/browser/webapi/DocumentType.zig +++ b/src/browser/webapi/DocumentType.zig @@ -81,6 +81,7 @@ pub const JsApi = struct { pub const name = "DocumentType"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const name = bridge.accessor(DocumentType.getName, null, .{}); diff --git a/src/browser/webapi/Element.zig b/src/browser/webapi/Element.zig index fd8bd820..3be094e9 100644 --- a/src/browser/webapi/Element.zig +++ b/src/browser/webapi/Element.zig @@ -1425,6 +1425,7 @@ pub const JsApi = struct { pub const name = "Element"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const tagName = bridge.accessor(_tagName, null, .{}); diff --git a/src/browser/webapi/Event.zig b/src/browser/webapi/Event.zig index ffb3edc5..569e5f70 100644 --- a/src/browser/webapi/Event.zig +++ b/src/browser/webapi/Event.zig @@ -409,6 +409,7 @@ pub const JsApi = struct { pub var class_id: bridge.ClassId = undefined; pub const weak = true; pub const finalizer = bridge.finalizer(Event.deinit); + pub const enumerable = false; }; pub const constructor = bridge.constructor(Event.init, .{}); diff --git a/src/browser/webapi/EventTarget.zig b/src/browser/webapi/EventTarget.zig index 39613f67..ceb682d5 100644 --- a/src/browser/webapi/EventTarget.zig +++ b/src/browser/webapi/EventTarget.zig @@ -162,6 +162,7 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const constructor = bridge.constructor(EventTarget.init, .{}); diff --git a/src/browser/webapi/Node.zig b/src/browser/webapi/Node.zig index bcf0ac1b..8a63fc22 100644 --- a/src/browser/webapi/Node.zig +++ b/src/browser/webapi/Node.zig @@ -879,6 +879,7 @@ pub const JsApi = struct { pub const name = "Node"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const ELEMENT_NODE = bridge.property(1, .{ .template = true }); diff --git a/src/browser/webapi/NodeFilter.zig b/src/browser/webapi/NodeFilter.zig index 69ef3a16..acd0da58 100644 --- a/src/browser/webapi/NodeFilter.zig +++ b/src/browser/webapi/NodeFilter.zig @@ -88,6 +88,7 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; pub const empty_with_no_proto = true; + pub const enumerable = false; }; pub const FILTER_ACCEPT = bridge.property(NodeFilter.FILTER_ACCEPT, .{ .template = true }); diff --git a/src/browser/webapi/cdata/Comment.zig b/src/browser/webapi/cdata/Comment.zig index dca43b25..39282d69 100644 --- a/src/browser/webapi/cdata/Comment.zig +++ b/src/browser/webapi/cdata/Comment.zig @@ -37,6 +37,7 @@ pub const JsApi = struct { pub const name = "Comment"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const constructor = bridge.constructor(Comment.init, .{}); diff --git a/src/browser/webapi/cdata/ProcessingInstruction.zig b/src/browser/webapi/cdata/ProcessingInstruction.zig index 97024d4e..84cc711b 100644 --- a/src/browser/webapi/cdata/ProcessingInstruction.zig +++ b/src/browser/webapi/cdata/ProcessingInstruction.zig @@ -36,6 +36,7 @@ pub const JsApi = struct { pub const name = "ProcessingInstruction"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const target = bridge.accessor(ProcessingInstruction.getTarget, null, .{}); diff --git a/src/browser/webapi/cdata/Text.zig b/src/browser/webapi/cdata/Text.zig index 8037db2e..310edb32 100644 --- a/src/browser/webapi/cdata/Text.zig +++ b/src/browser/webapi/cdata/Text.zig @@ -69,6 +69,7 @@ pub const JsApi = struct { pub const name = "Text"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const constructor = bridge.constructor(Text.init, .{}); diff --git a/src/browser/webapi/collections/DOMTokenList.zig b/src/browser/webapi/collections/DOMTokenList.zig index a9f31812..2976fb65 100644 --- a/src/browser/webapi/collections/DOMTokenList.zig +++ b/src/browser/webapi/collections/DOMTokenList.zig @@ -251,6 +251,7 @@ pub const JsApi = struct { pub const name = "DOMTokenList"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const length = bridge.accessor(DOMTokenList.length, null, .{}); diff --git a/src/browser/webapi/collections/HTMLCollection.zig b/src/browser/webapi/collections/HTMLCollection.zig index f0d342ef..1e2c9bc2 100644 --- a/src/browser/webapi/collections/HTMLCollection.zig +++ b/src/browser/webapi/collections/HTMLCollection.zig @@ -127,6 +127,7 @@ pub const JsApi = struct { pub const name = "HTMLCollection"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const length = bridge.accessor(HTMLCollection.length, null, .{}); diff --git a/src/browser/webapi/collections/NodeList.zig b/src/browser/webapi/collections/NodeList.zig index 1e20fb5b..ad6a4bd6 100644 --- a/src/browser/webapi/collections/NodeList.zig +++ b/src/browser/webapi/collections/NodeList.zig @@ -117,6 +117,7 @@ pub const JsApi = struct { pub const name = "NodeList"; pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const length = bridge.accessor(NodeList.length, null, .{}); diff --git a/src/browser/webapi/element/Attribute.zig b/src/browser/webapi/element/Attribute.zig index 5a86454d..e12fde69 100644 --- a/src/browser/webapi/element/Attribute.zig +++ b/src/browser/webapi/element/Attribute.zig @@ -94,12 +94,9 @@ pub const JsApi = struct { pub const Meta = struct { pub const name = "Attr"; - // we _never_ hold a reference to this, so the JS layer doesn't need to - // persist the value. It can pass it to QuickJS and let it fully manage it - // (TODO: we probably _should_ hold a refernece, because calling getAttributeNode - // on the same element + name should return the same instance) pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; + pub const enumerable = false; }; pub const name = bridge.accessor(Attribute.getName, null, .{}); diff --git a/src/browser/webapi/event/CustomEvent.zig b/src/browser/webapi/event/CustomEvent.zig index 579afb81..808e6ed2 100644 --- a/src/browser/webapi/event/CustomEvent.zig +++ b/src/browser/webapi/event/CustomEvent.zig @@ -97,6 +97,7 @@ pub const JsApi = struct { pub var class_id: bridge.ClassId = undefined; pub const weak = true; pub const finalizer = bridge.finalizer(CustomEvent.deinit); + pub const enumerable = false; }; pub const constructor = bridge.constructor(CustomEvent.init, .{});