summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2021-06-16 18:40:35 +0200
committerGitHub <noreply@github.com>2021-06-16 18:40:35 +0200
commit2a66d5de01b584b7138084eb427c9ac09c254986 (patch)
tree0708f419e7ed2d9669678eb8d75029941a205c23
parent718cb6dad733fb7afb1ae8c49485dc85e1fa0e0b (diff)
fix: align URL / URLSearchParams to spec (#11005)
-rw-r--r--Cargo.lock1
-rw-r--r--extensions/fetch/20_headers.js11
-rw-r--r--extensions/url/00_url.js426
-rw-r--r--extensions/url/Cargo.toml1
-rw-r--r--extensions/url/benches/url_ops.rs1
-rw-r--r--extensions/webidl/00_webidl.js97
-rw-r--r--tools/wpt/expectation.json30
7 files changed, 349 insertions, 218 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 61176425b..b882fa43d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -766,6 +766,7 @@ version = "0.9.0"
dependencies = [
"deno_bench_util",
"deno_core",
+ "deno_webidl",
"idna",
"percent-encoding",
"serde",
diff --git a/extensions/fetch/20_headers.js b/extensions/fetch/20_headers.js
index a0c001480..26500b602 100644
--- a/extensions/fetch/20_headers.js
+++ b/extensions/fetch/20_headers.js
@@ -387,18 +387,9 @@
webidl.configurePrototype(Headers);
- webidl.converters["sequence<ByteString>"] = webidl
- .createSequenceConverter(webidl.converters["ByteString"]);
- webidl.converters["sequence<sequence<ByteString>>"] = webidl
- .createSequenceConverter(webidl.converters["sequence<ByteString>"]);
- webidl.converters["record<ByteString, ByteString>"] = webidl
- .createRecordConverter(
- webidl.converters["ByteString"],
- webidl.converters["ByteString"],
- );
webidl.converters["HeadersInit"] = (V, opts) => {
// Union for (sequence<sequence<ByteString>> or record<ByteString, ByteString>)
- if (typeof V === "object" && V !== null) {
+ if (webidl.type(V) === "Object" && V !== null) {
if (V[Symbol.iterator] !== undefined) {
return webidl.converters["sequence<sequence<ByteString>>"](V, opts);
}
diff --git a/extensions/url/00_url.js b/extensions/url/00_url.js
index f6f3335dd..1c66c9d57 100644
--- a/extensions/url/00_url.js
+++ b/extensions/url/00_url.js
@@ -3,23 +3,24 @@
((window) => {
const core = window.Deno.core;
+ const webidl = window.__bootstrap.webidl;
- function requiredArguments(name, length, required) {
- if (length < required) {
- const errMsg = `${name} requires at least ${required} argument${
- required === 1 ? "" : "s"
- }, but only ${length} present`;
- throw new TypeError(errMsg);
- }
- }
-
- const paramLists = new WeakMap();
- const urls = new WeakMap();
+ const _list = Symbol("list");
+ const _urlObject = Symbol("url object");
class URLSearchParams {
- #params = [];
+ [_list];
+ [_urlObject] = null;
constructor(init = "") {
+ const prefix = "Failed to construct 'URL'";
+ init = webidl.converters
+ ["sequence<sequence<USVString>> or record<USVString, USVString> or USVString"](
+ init,
+ { prefix, context: "Argument 1" },
+ );
+ this[webidl.brand] = webidl.brand;
+
if (typeof init === "string") {
// Overload: USVString
// If init is a string and starts with U+003F (?),
@@ -27,59 +28,65 @@
if (init[0] == "?") {
init = init.slice(1);
}
-
- this.#params = core.opSync("op_url_parse_search_params", init);
- } else if (
- Array.isArray(init) ||
- typeof init?.[Symbol.iterator] == "function"
- ) {
+ this[_list] = core.opSync("op_url_parse_search_params", init);
+ } else if (Array.isArray(init)) {
// Overload: sequence<sequence<USVString>>
- for (const pair of init) {
- // If pair does not contain exactly two items, then throw a TypeError.
+ this[_list] = init.map((pair, i) => {
if (pair.length !== 2) {
throw new TypeError(
- "URLSearchParams.constructor sequence argument must only contain pair elements",
+ `${prefix}: Item ${i +
+ 0} in the parameter list does have length 2 exactly.`,
);
}
- this.#params.push([String(pair[0]), String(pair[1])]);
- }
- } else if (Object(init) !== init) {
- // pass
- } else if (init instanceof URLSearchParams) {
- this.#params = [...init.#params];
+ return [pair[0], pair[1]];
+ });
} else {
// Overload: record<USVString, USVString>
- for (const key of Object.keys(init)) {
- this.#params.push([key, String(init[key])]);
- }
+ this[_list] = Object.keys(init).map((key) => [key, init[key]]);
}
-
- paramLists.set(this, this.#params);
- urls.set(this, null);
}
#updateUrlSearch() {
- const url = urls.get(this);
- if (url == null) {
+ const url = this[_urlObject];
+ if (url === null) {
return;
}
- const parseArgs = { href: url.href, setSearch: this.toString() };
- parts.set(url, core.opSync("op_url_parse", parseArgs));
+ const parts = core.opSync("op_url_parse", {
+ href: url.href,
+ setSearch: this.toString(),
+ });
+ url[_url] = parts;
}
append(name, value) {
- requiredArguments("URLSearchParams.append", arguments.length, 2);
- this.#params.push([String(name), String(value)]);
+ webidl.assertBranded(this, URLSearchParams);
+ const prefix = "Failed to execute 'append' on 'URLSearchParams'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ name = webidl.converters.USVString(name, {
+ prefix,
+ context: "Argument 1",
+ });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 2",
+ });
+ this[_list].push([name, value]);
this.#updateUrlSearch();
}
delete(name) {
- requiredArguments("URLSearchParams.delete", arguments.length, 1);
- name = String(name);
+ webidl.assertBranded(this, URLSearchParams);
+ const prefix = "Failed to execute 'append' on 'URLSearchParams'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ name = webidl.converters.USVString(name, {
+ prefix,
+ context: "Argument 1",
+ });
+ const list = this[_list];
let i = 0;
- while (i < this.#params.length) {
- if (this.#params[i][0] === name) {
- this.#params.splice(i, 1);
+ while (i < list.length) {
+ if (list[i][0] === name) {
+ list.splice(i, 1);
} else {
i++;
}
@@ -88,54 +95,77 @@
}
getAll(name) {
- requiredArguments("URLSearchParams.getAll", arguments.length, 1);
- name = String(name);
+ webidl.assertBranded(this, URLSearchParams);
+ const prefix = "Failed to execute 'getAll' on 'URLSearchParams'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ name = webidl.converters.USVString(name, {
+ prefix,
+ context: "Argument 1",
+ });
const values = [];
- for (const entry of this.#params) {
+ for (const entry of this[_list]) {
if (entry[0] === name) {
values.push(entry[1]);
}
}
-
return values;
}
get(name) {
- requiredArguments("URLSearchParams.get", arguments.length, 1);
- name = String(name);
- for (const entry of this.#params) {
+ webidl.assertBranded(this, URLSearchParams);
+ const prefix = "Failed to execute 'get' on 'URLSearchParams'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ name = webidl.converters.USVString(name, {
+ prefix,
+ context: "Argument 1",
+ });
+ for (const entry of this[_list]) {
if (entry[0] === name) {
return entry[1];
}
}
-
return null;
}
has(name) {
- requiredArguments("URLSearchParams.has", arguments.length, 1);
- name = String(name);
- return this.#params.some((entry) => entry[0] === name);
+ webidl.assertBranded(this, URLSearchParams);
+ const prefix = "Failed to execute 'has' on 'URLSearchParams'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ name = webidl.converters.USVString(name, {
+ prefix,
+ context: "Argument 1",
+ });
+ return this[_list].some((entry) => entry[0] === name);
}
set(name, value) {
- requiredArguments("URLSearchParams.set", arguments.length, 2);
+ webidl.assertBranded(this, URLSearchParams);
+ const prefix = "Failed to execute 'set' on 'URLSearchParams'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ name = webidl.converters.USVString(name, {
+ prefix,
+ context: "Argument 1",
+ });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 2",
+ });
+
+ const list = this[_list];
// If there are any name-value pairs whose name is name, in list,
// set the value of the first such name-value pair to value
// and remove the others.
- name = String(name);
- value = String(value);
let found = false;
let i = 0;
- while (i < this.#params.length) {
- if (this.#params[i][0] === name) {
+ while (i < list.length) {
+ if (list[i][0] === name) {
if (!found) {
- this.#params[i][1] = value;
+ list[i][1] = value;
found = true;
i++;
} else {
- this.#params.splice(i, 1);
+ list.splice(i, 1);
}
} else {
i++;
@@ -145,69 +175,51 @@
// Otherwise, append a new name-value pair whose name is name
// and value is value, to list.
if (!found) {
- this.#params.push([String(name), String(value)]);
+ list.push([name, value]);
}
this.#updateUrlSearch();
}
sort() {
- this.#params.sort((a, b) => (a[0] === b[0] ? 0 : a[0] > b[0] ? 1 : -1));
+ webidl.assertBranded(this, URLSearchParams);
+ this[_list].sort((a, b) => (a[0] === b[0] ? 0 : a[0] > b[0] ? 1 : -1));
this.#updateUrlSearch();
}
- forEach(callbackfn, thisArg) {
- requiredArguments("URLSearchParams.forEach", arguments.length, 1);
-
- if (typeof thisArg !== "undefined") {
- callbackfn = callbackfn.bind(thisArg);
- }
-
- for (const [key, value] of this.#params) {
- callbackfn(value, key, this);
- }
- }
-
- *keys() {
- for (const [key] of this.#params) {
- yield key;
- }
- }
-
- *values() {
- for (const [, value] of this.#params) {
- yield value;
- }
- }
-
- *entries() {
- yield* this.#params;
- }
-
- *[Symbol.iterator]() {
- yield* this.#params;
+ toString() {
+ webidl.assertBranded(this, URLSearchParams);
+ return core.opSync("op_url_stringify_search_params", this[_list]);
}
- toString() {
- return core.opSync("op_url_stringify_search_params", this.#params);
+ get [Symbol.toStringTag]() {
+ return "URLSearchParams";
}
}
- const parts = new WeakMap();
+ webidl.mixinPairIterable("URLSearchParams", URLSearchParams, _list, 0, 1);
- class URL {
- #searchParams = null;
+ webidl.configurePrototype(URLSearchParams);
- constructor(url, base) {
- new.target;
+ const _url = Symbol("url");
- if (url instanceof URL && base === undefined) {
- parts.set(this, parts.get(url));
- } else {
- base = base !== undefined ? String(base) : base;
- const parseArgs = { href: String(url), baseHref: base };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
+ class URL {
+ [_url];
+ #queryObject = null;
+
+ constructor(url, base = undefined) {
+ const prefix = "Failed to construct 'URL'";
+ url = webidl.converters.USVString(url, { prefix, context: "Argument 1" });
+ if (base !== undefined) {
+ base = webidl.converters.USVString(base, {
+ prefix,
+ context: "Argument 2",
+ });
}
+ this[webidl.brand] = webidl.brand;
+
+ const parts = core.opSync("op_url_parse", { href: url, baseHref: base });
+ this[_url] = parts;
}
[Symbol.for("Deno.customInspect")](inspect) {
@@ -228,8 +240,8 @@
}
#updateSearchParams() {
- if (this.#searchParams != null) {
- const params = paramLists.get(this.#searchParams);
+ if (this.#queryObject !== null) {
+ const params = this.#queryObject[_list];
const newParams = core.opSync(
"op_url_parse_search_params",
this.search.slice(1),
@@ -239,122 +251,208 @@
}
get hash() {
- return parts.get(this).hash;
+ webidl.assertBranded(this, URL);
+ return this[_url].hash;
}
set hash(value) {
+ webidl.assertBranded(this, URL);
+ const prefix = "Failed to set 'hash' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 1",
+ });
try {
- const parseArgs = { href: this.href, setHash: String(value) };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
+ this[_url] = core.opSync("op_url_parse", {
+ href: this.href,
+ setHash: value,
+ });
} catch {
/* pass */
}
}
get host() {
- return parts.get(this).host;
+ webidl.assertBranded(this, URL);
+ return this[_url].host;
}
set host(value) {
+ webidl.assertBranded(this, URL);
+ const prefix = "Failed to set 'host' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 1",
+ });
try {
- const parseArgs = { href: this.href, setHost: String(value) };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
+ this[_url] = core.opSync("op_url_parse", {
+ href: this.href,
+ setHost: value,
+ });
} catch {
/* pass */
}
}
get hostname() {
- return parts.get(this).hostname;
+ webidl.assertBranded(this, URL);
+ return this[_url].hostname;
}
set hostname(value) {
+ webidl.assertBranded(this, URL);
+ const prefix = "Failed to set 'hostname' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 1",
+ });
try {
- const parseArgs = { href: this.href, setHostname: String(value) };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
+ this[_url] = core.opSync("op_url_parse", {
+ href: this.href,
+ setHostname: value,
+ });
} catch {
/* pass */
}
}
get href() {
- return parts.get(this).href;
+ webidl.assertBranded(this, URL);
+ return this[_url].href;
}
set href(value) {
- try {
- const parseArgs = { href: String(value) };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
- } catch {
- throw new TypeError("Invalid URL");
- }
+ webidl.assertBranded(this, URL);
+ const prefix = "Failed to set 'href' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ this[_url] = core.opSync("op_url_parse", {
+ href: value,
+ });
this.#updateSearchParams();
}
get origin() {
- return parts.get(this).origin;
+ webidl.assertBranded(this, URL);
+ return this[_url].origin;
}
get password() {
- return parts.get(this).password;
+ webidl.assertBranded(this, URL);
+ return this[_url].password;
}
set password(value) {
+ webidl.assertBranded(this, URL);
+ const prefix = "Failed to set 'password' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 1",
+ });
try {
- const parseArgs = { href: this.href, setPassword: String(value) };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
+ this[_url] = core.opSync("op_url_parse", {
+ href: this.href,
+ setPassword: value,
+ });
} catch {
/* pass */
}
}
get pathname() {
- return parts.get(this).pathname;
+ webidl.assertBranded(this, URL);
+ return this[_url].pathname;
}
set pathname(value) {
+ webidl.assertBranded(this, URL);
+ const prefix = "Failed to set 'pathname' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 1",
+ });
try {
- const parseArgs = { href: this.href, setPathname: String(value) };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
+ this[_url] = core.opSync("op_url_parse", {
+ href: this.href,
+ setPathname: value,
+ });
} catch {
/* pass */
}
}
get port() {
- return parts.get(this).port;
+ webidl.assertBranded(this, URL);
+ return this[_url].port;
}
set port(value) {
+ webidl.assertBranded(this, URL);
+ const prefix = "Failed to set 'port' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 1",
+ });
try {
- const parseArgs = { href: this.href, setPort: String(value) };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
+ this[_url] = core.opSync("op_url_parse", {
+ href: this.href,
+ setPort: value,
+ });
} catch {
/* pass */
}
}
get protocol() {
- return parts.get(this).protocol;
+ webidl.assertBranded(this, URL);
+ return this[_url].protocol;
}
set protocol(value) {
+ webidl.assertBranded(this, URL);
+ const prefix = "Failed to set 'protocol' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 1",
+ });
try {
- const parseArgs = { href: this.href, setProtocol: String(value) };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
+ this[_url] = core.opSync("op_url_parse", {
+ href: this.href,
+ setProtocol: value,
+ });
} catch {
/* pass */
}
}
get search() {
- return parts.get(this).search;
+ webidl.assertBranded(this, URL);
+ return this[_url].search;
}
set search(value) {
+ webidl.assertBranded(this, URL);
+ const prefix = "Failed to set 'search' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 1",
+ });
try {
- const parseArgs = { href: this.href, setSearch: String(value) };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
+ this[_url] = core.opSync("op_url_parse", {
+ href: this.href,
+ setSearch: value,
+ });
this.#updateSearchParams();
} catch {
/* pass */
@@ -362,35 +460,53 @@
}
get username() {
- return parts.get(this).username;
+ webidl.assertBranded(this, URL);
+ return this[_url].username;
}
set username(value) {
+ webidl.assertBranded(this, URL);
+ const prefix = "Failed to set 'username' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.USVString(value, {
+ prefix,
+ context: "Argument 1",
+ });
try {
- const parseArgs = { href: this.href, setUsername: String(value) };
- parts.set(this, core.opSync("op_url_parse", parseArgs));
+ this[_url] = core.opSync("op_url_parse", {
+ href: this.href,
+ setUsername: value,
+ });
} catch {
/* pass */
}
}
get searchParams() {
- if (this.#searchParams == null) {
- this.#searchParams = new URLSearchParams(this.search);
- urls.set(this.#searchParams, this);
+ if (this.#queryObject == null) {
+ this.#queryObject = new URLSearchParams(this.search);
+ this.#queryObject[_urlObject] = this;
}
- return this.#searchParams;
+ return this.#queryObject;
}
toString() {
+ webidl.assertBranded(this, URL);
return this.href;
}
toJSON() {
+ webidl.assertBranded(this, URL);
return this.href;
}
+
+ get [Symbol.toStringTag]() {
+ return "URL";
+ }
}
+ webidl.configurePrototype(URL);
+
/**
* This function implements application/x-www-form-urlencoded parsing.
* https://url.spec.whatwg.org/#concept-urlencoded-parser
@@ -401,6 +517,20 @@
return core.opSync("op_url_parse_search_params", null, bytes);
}
+ webidl
+ .converters[
+ "sequence<sequence<USVString>> or record<USVString, USVString> or USVString"
+ ] = (V, opts) => {
+ // Union for (sequence<sequence<USVString>> or record<USVString, USVString> or USVString)
+ if (webidl.type(V) === "Object" && V !== null) {
+ if (V[Symbol.iterator] !== undefined) {
+ return webidl.converters["sequence<sequence<ByteString>>"](V, opts);
+ }
+ return webidl.converters["record<ByteString, ByteString>"](V, opts);
+ }
+ return webidl.converters.USVString(V, opts);
+ };
+
window.__bootstrap.url = {
URL,
URLSearchParams,
diff --git a/extensions/url/Cargo.toml b/extensions/url/Cargo.toml
index 17ba8c7f1..6434531bf 100644
--- a/extensions/url/Cargo.toml
+++ b/extensions/url/Cargo.toml
@@ -21,6 +21,7 @@ serde = { version = "1.0.125", features = ["derive"] }
[dev-dependencies]
deno_bench_util = { version = "0.3.0", path = "../../bench_util" }
+deno_webidl = { version = "0.9.0", path = "../webidl" }
[[bench]]
name = "url_ops"
diff --git a/extensions/url/benches/url_ops.rs b/extensions/url/benches/url_ops.rs
index c390af0d8..ed27b6f80 100644
--- a/extensions/url/benches/url_ops.rs
+++ b/extensions/url/benches/url_ops.rs
@@ -6,6 +6,7 @@ use deno_core::Extension;
fn setup() -> Vec<Extension> {
vec![
+ deno_webidl::init(),
deno_url::init(),
Extension::builder()
.js(vec![(
diff --git a/extensions/webidl/00_webidl.js b/extensions/webidl/00_webidl.js
index a54d2fe6e..e6cda92d4 100644
--- a/extensions/webidl/00_webidl.js
+++ b/extensions/webidl/00_webidl.js
@@ -568,6 +568,17 @@
);
converters["Promise<undefined>"] = createPromiseConverter(() => undefined);
+ converters["sequence<ByteString>"] = createSequenceConverter(
+ converters.ByteString,
+ );
+ converters["sequence<sequence<ByteString>>"] = createSequenceConverter(
+ converters["sequence<ByteString>"],
+ );
+ converters["record<ByteString, ByteString>"] = createRecordConverter(
+ converters.ByteString,
+ converters.ByteString,
+ );
+
function requiredArguments(length, required, opts = {}) {
if (length < required) {
const errMsg = `${
@@ -708,7 +719,7 @@
// https://heycam.github.io/webidl/#es-sequence
function createSequenceConverter(converter) {
return function (V, opts = {}) {
- if (typeof V !== "object") {
+ if (type(V) !== "Object") {
throw makeException(
TypeError,
"can not be converted to sequence.",
@@ -746,7 +757,7 @@
function createRecordConverter(keyConverter, valueConverter) {
return (V, opts) => {
- if (typeof V !== "object") {
+ if (type(V) !== "Object") {
throw makeException(
TypeError,
"can not be converted to dictionary.",
@@ -879,41 +890,64 @@
return iterator;
}
- const methods = {
- entries() {
- assertBranded(this, prototype);
- return createDefaultIterator(this, "key+value");
+ function entries() {
+ assertBranded(this, prototype);
+ return createDefaultIterator(this, "key+value");
+ }
+
+ const properties = {
+ entries: {
+ value: entries,
+ writable: true,
+ enumerable: true,
+ configurable: true,
},
- [Symbol.iterator]() {
- assertBranded(this, prototype);
- return createDefaultIterator(this, "key+value");
+ [Symbol.iterator]: {
+ value: entries,
+ writable: true,
+ enumerable: false,
+ configurable: true,
},
- keys() {
- assertBranded(this, prototype);
- return createDefaultIterator(this, "key");
+ keys: {
+ value: function keys() {
+ assertBranded(this, prototype);
+ return createDefaultIterator(this, "key");
+ },
+ writable: true,
+ enumerable: true,
+ configurable: true,
},
- values() {
- assertBranded(this, prototype);
- return createDefaultIterator(this, "value");
+ values: {
+ value: function values() {
+ assertBranded(this, prototype);
+ return createDefaultIterator(this, "value");
+ },
+ writable: true,
+ enumerable: true,
+ configurable: true,
},
- forEach(idlCallback, thisArg) {
- assertBranded(this, prototype);
- const prefix = `Failed to execute 'forEach' on '${name}'`;
- requiredArguments(arguments.length, 1, { prefix });
- idlCallback = converters["Function"](idlCallback, {
- prefix,
- context: "Argument 1",
- });
- idlCallback = idlCallback.bind(thisArg ?? globalThis);
- const pairs = this[dataSymbol];
- for (let i = 0; i < pairs.length; i++) {
- const entry = pairs[i];
- idlCallback(entry[valueKey], entry[keyKey], this);
- }
+ forEach: {
+ value: function forEach(idlCallback, thisArg = undefined) {
+ assertBranded(this, prototype);
+ const prefix = `Failed to execute 'forEach' on '${name}'`;
+ requiredArguments(arguments.length, 1, { prefix });
+ idlCallback = converters["Function"](idlCallback, {
+ prefix,
+ context: "Argument 1",
+ });
+ idlCallback = idlCallback.bind(thisArg ?? globalThis);
+ const pairs = this[dataSymbol];
+ for (let i = 0; i < pairs.length; i++) {
+ const entry = pairs[i];
+ idlCallback(entry[valueKey], entry[keyKey], this);
+ }
+ },
+ writable: true,
+ enumerable: true,
+ configurable: true,
},
};
-
- return Object.assign(prototype.prototype, methods);
+ return Object.defineProperties(prototype.prototype, properties);
}
function configurePrototype(prototype) {
@@ -938,6 +972,7 @@
window.__bootstrap ??= {};
window.__bootstrap.webidl = {
+ type,
makeException,
converters,
requiredArguments,
diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json
index e4ce77f9b..54e8fe7d0 100644
--- a/tools/wpt/expectation.json
+++ b/tools/wpt/expectation.json
@@ -586,34 +586,7 @@
"historical.any.html": [
"<a> and <area>.searchParams should be undefined"
],
- "idlharness.any.html": [
- "URL interface object length",
- "URL interface: attribute href",
- "URL interface: stringifier",
- "URL interface: attribute origin",
- "URL interface: attribute protocol",
- "URL interface: attribute username",
- "URL interface: attribute password",
- "URL interface: attribute host",
- "URL interface: attribute hostname",
- "URL interface: attribute port",
- "URL interface: attribute pathname",
- "URL interface: attribute search",
- "URL interface: attribute searchParams",
- "URL interface: attribute hash",
- "URL interface: operation toJSON()",
- "Stringification of new URL(\"http://foo\")",
- "URLSearchParams interface: operation append(USVString, USVString)",
- "URLSearchParams interface: operation delete(USVString)",
- "URLSearchParams interface: operation get(USVString)",
- "URLSearchParams interface: operation getAll(USVString)",
- "URLSearchParams interface: operation has(USVString)",
- "URLSearchParams interface: operation set(USVString, USVString)",
- "URLSearchParams interface: operation sort()",
- "URLSearchParams interface: iterable<USVString, USVString>",
- "URLSearchParams interface: stringifier",
- "Stringification of new URLSearchParams(\"hi=there&thank=you\")"
- ],
+ "idlharness.any.html": true,
"url-constructor.any.html": [
"Parsing: <file://%43%7C> against <about:blank>",
"Parsing: <file://%43|> against <about:blank>",
@@ -879,7 +852,6 @@
"redirect-to-dataurl.any.html": true
},
"idlharness.any.html": [
- "Headers interface: iterable<ByteString, ByteString>",
"Request interface: attribute destination",
"Request interface: attribute referrer",
"Request interface: attribute referrerPolicy",