diff --git a/extensions/crypto/01_crypto.js b/extensions/crypto/01_crypto.js index 0f8f72937e..e8ae65ef30 100644 --- a/extensions/crypto/01_crypto.js +++ b/extensions/crypto/01_crypto.js @@ -158,10 +158,7 @@ } } - Object.defineProperty(Crypto.prototype, "subtle", { - configurable: true, - enumerable: true, - }); + webidl.configurePrototype(Crypto); window.__bootstrap.crypto = { SubtleCrypto, diff --git a/extensions/fetch/20_headers.js b/extensions/fetch/20_headers.js index 8259c0cca4..5f865749ae 100644 --- a/extensions/fetch/20_headers.js +++ b/extensions/fetch/20_headers.js @@ -392,6 +392,8 @@ webidl.mixinPairIterable("Headers", Headers, _iterableHeaders, 0, 1); + webidl.configurePrototype(Headers); + webidl.converters["sequence"] = webidl .createSequenceConverter(webidl.converters["ByteString"]); webidl.converters["sequence>"] = webidl diff --git a/extensions/fetch/21_formdata.js b/extensions/fetch/21_formdata.js index a178025b75..beae69aca7 100644 --- a/extensions/fetch/21_formdata.js +++ b/extensions/fetch/21_formdata.js @@ -241,6 +241,8 @@ webidl.mixinPairIterable("FormData", FormData, entryList, "name", "value"); + webidl.configurePrototype(FormData); + class MultipartBuilder { /** * @param {FormData} formData diff --git a/extensions/fetch/23_request.js b/extensions/fetch/23_request.js index 29eddcf22b..d030236873 100644 --- a/extensions/fetch/23_request.js +++ b/extensions/fetch/23_request.js @@ -384,31 +384,7 @@ mixinBody(Request, _body, _mimeType); - Object.defineProperty(Request.prototype, "method", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Request.prototype, "url", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Request.prototype, "headers", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Request.prototype, "redirect", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Request.prototype, "signal", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Request.prototype, "clone", { - enumerable: true, - writable: true, - configurable: true, - }); + webidl.configurePrototype(Request); webidl.converters["Request"] = webidl.createInterfaceConverter( "Request", diff --git a/extensions/fetch/23_response.js b/extensions/fetch/23_response.js index 4d843829b4..b1b037187a 100644 --- a/extensions/fetch/23_response.js +++ b/extensions/fetch/23_response.js @@ -377,39 +377,7 @@ mixinBody(Response, _body, _mimeType); - Object.defineProperty(Response.prototype, "type", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Response.prototype, "url", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Response.prototype, "redirected", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Response.prototype, "status", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Response.prototype, "ok", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Response.prototype, "statusText", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Response.prototype, "headers", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(Response.prototype, "clone", { - enumerable: true, - writable: true, - configurable: true, - }); + webidl.configurePrototype(Response); webidl.converters["Response"] = webidl.createInterfaceConverter( "Response", diff --git a/extensions/file/01_file.js b/extensions/file/01_file.js index c9c66127fe..42298c3a1a 100644 --- a/extensions/file/01_file.js +++ b/extensions/file/01_file.js @@ -291,6 +291,8 @@ } } + webidl.configurePrototype(Blob); + webidl.converters["Blob"] = webidl.createInterfaceConverter("Blob", Blob); webidl.converters["BlobPart"] = (V, opts) => { // Union for ((ArrayBuffer or ArrayBufferView) or Blob or USVString) @@ -392,6 +394,8 @@ } } + webidl.configurePrototype(File); + webidl.converters["FilePropertyBag"] = webidl.createDictionaryConverter( "FilePropertyBag", blobPropertyBagDictionary, diff --git a/extensions/file/02_filereader.js b/extensions/file/02_filereader.js index c7ca3d980c..7cc40f7a59 100644 --- a/extensions/file/02_filereader.js +++ b/extensions/file/02_filereader.js @@ -328,6 +328,8 @@ } } + webidl.configurePrototype(FileReader); + Object.defineProperty(FileReader, "EMPTY", { writable: false, enumerable: true, diff --git a/extensions/web/01_dom_exception.js b/extensions/web/01_dom_exception.js index f5bd3289bf..e4bcb9fbaa 100644 --- a/extensions/web/01_dom_exception.js +++ b/extensions/web/01_dom_exception.js @@ -105,9 +105,7 @@ } } - defineProperty(DOMException.prototype, "message", { enumerable: true }); - defineProperty(DOMException.prototype, "name", { enumerable: true }); - defineProperty(DOMException.prototype, "code", { enumerable: true }); + webidl.configurePrototype(DOMException); for ( const [key, value] of Object.entries({ diff --git a/extensions/web/03_abort_signal.js b/extensions/web/03_abort_signal.js index 5d7e10bb2d..6551380da5 100644 --- a/extensions/web/03_abort_signal.js +++ b/extensions/web/03_abort_signal.js @@ -60,6 +60,9 @@ } } defineEventHandler(AbortSignal.prototype, "abort"); + + webidl.configurePrototype(AbortSignal); + class AbortController { #signal = new AbortSignal(illegalConstructorKey); @@ -76,6 +79,8 @@ } } + webidl.configurePrototype(AbortController); + const handlerSymbol = Symbol("eventHandlers"); function makeWrappedHandler(handler) { diff --git a/extensions/web/08_text_encoding.js b/extensions/web/08_text_encoding.js index be66e4981b..0ba1bb582e 100644 --- a/extensions/web/08_text_encoding.js +++ b/extensions/web/08_text_encoding.js @@ -121,23 +121,7 @@ } } - Object.defineProperty(TextDecoder.prototype, "encoding", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(TextDecoder.prototype, "fatal", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(TextDecoder.prototype, "ignoreBOM", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(TextDecoder.prototype, "decode", { - enumerable: true, - writable: true, - configurable: true, - }); + webidl.configurePrototype(TextDecoder); class TextEncoder { constructor() { @@ -189,20 +173,7 @@ } } - Object.defineProperty(TextEncoder.prototype, "encoding", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(TextEncoder.prototype, "encode", { - enumerable: true, - writable: true, - configurable: true, - }); - Object.defineProperty(TextEncoder.prototype, "encodeInto", { - enumerable: true, - writable: true, - configurable: true, - }); + webidl.configurePrototype(TextEncoder); class TextDecoderStream { /** @type {TextDecoder} */ @@ -293,26 +264,7 @@ } } - Object.defineProperty(TextDecoderStream.prototype, "encoding", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(TextDecoderStream.prototype, "fatal", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(TextDecoderStream.prototype, "ignoreBOM", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(TextDecoderStream.prototype, "readable", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(TextDecoderStream.prototype, "writable", { - enumerable: true, - configurable: true, - }); + webidl.configurePrototype(TextDecoderStream); class TextEncoderStream { /** @type {string | null} */ @@ -382,18 +334,7 @@ } } - Object.defineProperty(TextEncoderStream.prototype, "encoding", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(TextEncoderStream.prototype, "readable", { - enumerable: true, - configurable: true, - }); - Object.defineProperty(TextEncoderStream.prototype, "writable", { - enumerable: true, - configurable: true, - }); + webidl.configurePrototype(TextEncoderStream); webidl.converters.TextDecoderOptions = webidl.createDictionaryConverter( "TextDecoderOptions", diff --git a/extensions/webidl/00_webidl.js b/extensions/webidl/00_webidl.js index ed777b8e59..49f5861353 100644 --- a/extensions/webidl/00_webidl.js +++ b/extensions/webidl/00_webidl.js @@ -897,6 +897,26 @@ return Object.assign(prototype.prototype, methods); } + function configurePrototype(prototype) { + const descriptors = Object.getOwnPropertyDescriptors(prototype.prototype); + for (const key in descriptors) { + if (key === "constructor") continue; + const descriptor = descriptors[key]; + if ("value" in descriptor && typeof descriptor.value === "function") { + Object.defineProperty(prototype.prototype, key, { + enumerable: true, + writable: true, + configurable: true, + }); + } else if ("get" in descriptor) { + Object.defineProperty(prototype.prototype, key, { + enumerable: true, + configurable: true, + }); + } + } + } + window.__bootstrap ??= {}; window.__bootstrap.webidl = { makeException, @@ -913,5 +933,6 @@ assertBranded, illegalConstructor, mixinPairIterable, + configurePrototype, }; })(this); diff --git a/extensions/webidl/internal.d.ts b/extensions/webidl/internal.d.ts index ca72566a57..2d23f0ed2d 100644 --- a/extensions/webidl/internal.d.ts +++ b/extensions/webidl/internal.d.ts @@ -298,6 +298,11 @@ declare namespace globalThis { keyKey: string | number | symbol, valueKey: string | number | symbol, ): void; + + /** + * Configure prototype properties enumerability / writability / configurability. + */ + declare function configurePrototype(prototype: any); } } } diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 21e11c38ef..933fc57d6f 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -75,7 +75,6 @@ "Non-secure context window does not have access to SubtleCrypto" ], "idlharness.https.any.html": [ - "Crypto interface: operation getRandomValues(ArrayBufferView)", "CryptoKey interface: existence and properties of interface object", "CryptoKey interface object length", "CryptoKey interface object name", @@ -1028,11 +1027,6 @@ "redirect-to-dataurl.any.html": true }, "idlharness.any.html": [ - "Headers interface: operation append(ByteString, ByteString)", - "Headers interface: operation delete(ByteString)", - "Headers interface: operation get(ByteString)", - "Headers interface: operation has(ByteString)", - "Headers interface: operation set(ByteString, ByteString)", "Headers interface: iterable", "Request interface: attribute destination", "Request interface: attribute referrer",