summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/broadcast_channel/01_broadcast_channel.js235
-rw-r--r--ext/broadcast_channel/lib.rs2
-rw-r--r--ext/cache/01_cache.js516
-rw-r--r--ext/cache/lib.rs2
-rw-r--r--ext/console/01_colors.js209
-rw-r--r--ext/console/02_console.js4288
-rw-r--r--ext/console/internal.d.ts16
-rw-r--r--ext/console/lib.rs2
-rw-r--r--ext/crypto/00_crypto.js7914
-rw-r--r--ext/crypto/01_webidl.js937
-rw-r--r--ext/crypto/lib.rs2
-rw-r--r--ext/fetch/01_fetch_util.js22
-rw-r--r--ext/fetch/20_headers.js808
-rw-r--r--ext/fetch/21_formdata.js888
-rw-r--r--ext/fetch/22_body.js820
-rw-r--r--ext/fetch/22_http_client.js54
-rw-r--r--ext/fetch/23_request.js1161
-rw-r--r--ext/fetch/23_response.js918
-rw-r--r--ext/fetch/26_fetch.js1033
-rw-r--r--ext/fetch/internal.d.ts188
-rw-r--r--ext/fetch/lib.rs3
-rw-r--r--ext/ffi/00_ffi.js885
-rw-r--r--ext/ffi/lib.rs2
-rw-r--r--ext/flash/01_http.js1337
-rw-r--r--ext/flash/lib.rs2
-rw-r--r--ext/http/01_http.js815
-rw-r--r--ext/http/lib.rs2
-rw-r--r--ext/net/01_net.js708
-rw-r--r--ext/net/02_tls.js166
-rw-r--r--ext/net/lib.rs2
-rw-r--r--ext/node/01_node.js229
-rw-r--r--ext/node/02_require.js1593
-rw-r--r--ext/node/lib.rs2
-rw-r--r--ext/url/00_url.js1407
-rw-r--r--ext/url/01_urlpattern.js453
-rw-r--r--ext/url/benches/url_ops.rs8
-rw-r--r--ext/url/internal.d.ts20
-rw-r--r--ext/url/lib.rs2
-rw-r--r--ext/web/00_infra.js605
-rw-r--r--ext/web/01_dom_exception.js373
-rw-r--r--ext/web/01_mimesniff.js420
-rw-r--r--ext/web/02_event.js2559
-rw-r--r--ext/web/02_structured_clone.js239
-rw-r--r--ext/web/02_timers.js691
-rw-r--r--ext/web/03_abort_signal.js335
-rw-r--r--ext/web/04_global_interfaces.js124
-rw-r--r--ext/web/05_base64.js110
-rw-r--r--ext/web/06_streams.js11235
-rw-r--r--ext/web/08_text_encoding.js777
-rw-r--r--ext/web/09_file.js1108
-rw-r--r--ext/web/10_filereader.js845
-rw-r--r--ext/web/11_blob_url.js84
-rw-r--r--ext/web/12_location.js729
-rw-r--r--ext/web/13_message_port.js609
-rw-r--r--ext/web/14_compression.js227
-rw-r--r--ext/web/15_performance.js1032
-rw-r--r--ext/web/benches/encoding.rs9
-rw-r--r--ext/web/benches/timers_ops.rs7
-rw-r--r--ext/web/internal.d.ts201
-rw-r--r--ext/web/lib.rs2
-rw-r--r--ext/webgpu/src/01_webgpu.js9615
-rw-r--r--ext/webgpu/src/02_idl_types.js4034
-rw-r--r--ext/webgpu/src/03_surface.js251
-rw-r--r--ext/webgpu/src/04_surface_idl_types.js142
-rw-r--r--ext/webgpu/src/lib.rs2
-rw-r--r--ext/webgpu/src/surface.rs4
-rw-r--r--ext/webidl/00_webidl.js1992
-rw-r--r--ext/webidl/benches/dict.js7
-rw-r--r--ext/webidl/benches/dict.rs2
-rw-r--r--ext/webidl/internal.d.ts630
-rw-r--r--ext/webidl/lib.rs2
-rw-r--r--ext/websocket/01_websocket.js1017
-rw-r--r--ext/websocket/02_websocketstream.js778
-rw-r--r--ext/websocket/lib.rs2
-rw-r--r--ext/webstorage/01_webstorage.js348
-rw-r--r--ext/webstorage/lib.rs2
76 files changed, 34307 insertions, 34493 deletions
diff --git a/ext/broadcast_channel/01_broadcast_channel.js b/ext/broadcast_channel/01_broadcast_channel.js
index 82bede8b0..fb23554bf 100644
--- a/ext/broadcast_channel/01_broadcast_channel.js
+++ b/ext/broadcast_channel/01_broadcast_channel.js
@@ -2,150 +2,149 @@
/// <reference path="../../core/internal.d.ts" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const { MessageEvent, defineEventHandler, setTarget } =
- window.__bootstrap.event;
- const { EventTarget } = window.__bootstrap.eventTarget;
- const { DOMException } = window.__bootstrap.domException;
- const {
- ArrayPrototypeIndexOf,
- ArrayPrototypeSplice,
- ArrayPrototypePush,
- Symbol,
- Uint8Array,
- } = window.__bootstrap.primordials;
-
- const _name = Symbol("[[name]]");
- const _closed = Symbol("[[closed]]");
-
- const channels = [];
- let rid = null;
-
- async function recv() {
- while (channels.length > 0) {
- const message = await core.opAsync("op_broadcast_recv", rid);
-
- if (message === null) {
- break;
- }
-
- const { 0: name, 1: data } = message;
- dispatch(null, name, new Uint8Array(data));
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import {
+ defineEventHandler,
+ EventTarget,
+ setTarget,
+} from "internal:ext/web/02_event.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeIndexOf,
+ ArrayPrototypeSplice,
+ ArrayPrototypePush,
+ Symbol,
+ Uint8Array,
+} = primordials;
+
+const _name = Symbol("[[name]]");
+const _closed = Symbol("[[closed]]");
+
+const channels = [];
+let rid = null;
+
+async function recv() {
+ while (channels.length > 0) {
+ const message = await core.opAsync("op_broadcast_recv", rid);
+
+ if (message === null) {
+ break;
}
- core.close(rid);
- rid = null;
+ const { 0: name, 1: data } = message;
+ dispatch(null, name, new Uint8Array(data));
}
- function dispatch(source, name, data) {
- for (let i = 0; i < channels.length; ++i) {
- const channel = channels[i];
-
- if (channel === source) continue; // Don't self-send.
- if (channel[_name] !== name) continue;
- if (channel[_closed]) continue;
-
- const go = () => {
- if (channel[_closed]) return;
- const event = new MessageEvent("message", {
- data: core.deserialize(data), // TODO(bnoordhuis) Cache immutables.
- origin: "http://127.0.0.1",
- });
- setTarget(event, channel);
- channel.dispatchEvent(event);
- };
-
- defer(go);
- }
- }
+ core.close(rid);
+ rid = null;
+}
- // Defer to avoid starving the event loop. Not using queueMicrotask()
- // for that reason: it lets promises make forward progress but can
- // still starve other parts of the event loop.
- function defer(go) {
- setTimeout(go, 1);
- }
+function dispatch(source, name, data) {
+ for (let i = 0; i < channels.length; ++i) {
+ const channel = channels[i];
- class BroadcastChannel extends EventTarget {
- [_name];
- [_closed] = false;
+ if (channel === source) continue; // Don't self-send.
+ if (channel[_name] !== name) continue;
+ if (channel[_closed]) continue;
- get name() {
- return this[_name];
- }
+ const go = () => {
+ if (channel[_closed]) return;
+ const event = new MessageEvent("message", {
+ data: core.deserialize(data), // TODO(bnoordhuis) Cache immutables.
+ origin: "http://127.0.0.1",
+ });
+ setTarget(event, channel);
+ channel.dispatchEvent(event);
+ };
- constructor(name) {
- super();
+ defer(go);
+ }
+}
- const prefix = "Failed to construct 'BroadcastChannel'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
+// Defer to avoid starving the event loop. Not using queueMicrotask()
+// for that reason: it lets promises make forward progress but can
+// still starve other parts of the event loop.
+function defer(go) {
+ setTimeout(go, 1);
+}
- this[_name] = webidl.converters["DOMString"](name, {
- prefix,
- context: "Argument 1",
- });
+class BroadcastChannel extends EventTarget {
+ [_name];
+ [_closed] = false;
- this[webidl.brand] = webidl.brand;
+ get name() {
+ return this[_name];
+ }
- ArrayPrototypePush(channels, this);
+ constructor(name) {
+ super();
- if (rid === null) {
- // Create the rid immediately, otherwise there is a time window (and a
- // race condition) where messages can get lost, because recv() is async.
- rid = ops.op_broadcast_subscribe();
- recv();
- }
- }
+ const prefix = "Failed to construct 'BroadcastChannel'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
- postMessage(message) {
- webidl.assertBranded(this, BroadcastChannelPrototype);
+ this[_name] = webidl.converters["DOMString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
- const prefix = "Failed to execute 'postMessage' on 'BroadcastChannel'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
+ this[webidl.brand] = webidl.brand;
- if (this[_closed]) {
- throw new DOMException("Already closed", "InvalidStateError");
- }
+ ArrayPrototypePush(channels, this);
- if (typeof message === "function" || typeof message === "symbol") {
- throw new DOMException("Uncloneable value", "DataCloneError");
- }
+ if (rid === null) {
+ // Create the rid immediately, otherwise there is a time window (and a
+ // race condition) where messages can get lost, because recv() is async.
+ rid = ops.op_broadcast_subscribe();
+ recv();
+ }
+ }
- const data = core.serialize(message);
+ postMessage(message) {
+ webidl.assertBranded(this, BroadcastChannelPrototype);
- // Send to other listeners in this VM.
- dispatch(this, this[_name], new Uint8Array(data));
+ const prefix = "Failed to execute 'postMessage' on 'BroadcastChannel'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
- // Send to listeners in other VMs.
- defer(() => {
- if (!this[_closed]) {
- core.opAsync("op_broadcast_send", rid, this[_name], data);
- }
- });
+ if (this[_closed]) {
+ throw new DOMException("Already closed", "InvalidStateError");
}
- close() {
- webidl.assertBranded(this, BroadcastChannelPrototype);
- this[_closed] = true;
+ if (typeof message === "function" || typeof message === "symbol") {
+ throw new DOMException("Uncloneable value", "DataCloneError");
+ }
- const index = ArrayPrototypeIndexOf(channels, this);
- if (index === -1) return;
+ const data = core.serialize(message);
- ArrayPrototypeSplice(channels, index, 1);
- if (channels.length === 0) {
- ops.op_broadcast_unsubscribe(rid);
+ // Send to other listeners in this VM.
+ dispatch(this, this[_name], new Uint8Array(data));
+
+ // Send to listeners in other VMs.
+ defer(() => {
+ if (!this[_closed]) {
+ core.opAsync("op_broadcast_send", rid, this[_name], data);
}
+ });
+ }
+
+ close() {
+ webidl.assertBranded(this, BroadcastChannelPrototype);
+ this[_closed] = true;
+
+ const index = ArrayPrototypeIndexOf(channels, this);
+ if (index === -1) return;
+
+ ArrayPrototypeSplice(channels, index, 1);
+ if (channels.length === 0) {
+ ops.op_broadcast_unsubscribe(rid);
}
}
+}
- defineEventHandler(BroadcastChannel.prototype, "message");
- defineEventHandler(BroadcastChannel.prototype, "messageerror");
- const BroadcastChannelPrototype = BroadcastChannel.prototype;
+defineEventHandler(BroadcastChannel.prototype, "message");
+defineEventHandler(BroadcastChannel.prototype, "messageerror");
+const BroadcastChannelPrototype = BroadcastChannel.prototype;
- window.__bootstrap.broadcastChannel = { BroadcastChannel };
-})(this);
+export { BroadcastChannel };
diff --git a/ext/broadcast_channel/lib.rs b/ext/broadcast_channel/lib.rs
index 674d2414d..0cd17a026 100644
--- a/ext/broadcast_channel/lib.rs
+++ b/ext/broadcast_channel/lib.rs
@@ -112,7 +112,7 @@ pub fn init<BC: BroadcastChannel + 'static>(
) -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_webidl", "deno_web"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/broadcast_channel",
"01_broadcast_channel.js",
))
diff --git a/ext/cache/01_cache.js b/ext/cache/01_cache.js
index bf0243e3c..f49db3b84 100644
--- a/ext/cache/01_cache.js
+++ b/ext/cache/01_cache.js
@@ -1,296 +1,292 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-((window) => {
- const core = window.__bootstrap.core;
- const webidl = window.__bootstrap.webidl;
- const {
- Symbol,
- TypeError,
- ObjectPrototypeIsPrototypeOf,
- } = window.__bootstrap.primordials;
- const {
- Request,
- toInnerResponse,
- toInnerRequest,
- } = window.__bootstrap.fetch;
- const { URLPrototype } = window.__bootstrap.url;
- const RequestPrototype = Request.prototype;
- const { getHeader } = window.__bootstrap.headers;
- const { readableStreamForRid } = window.__bootstrap.streams;
+const core = globalThis.Deno.core;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ Symbol,
+ TypeError,
+ ObjectPrototypeIsPrototypeOf,
+} = primordials;
+import {
+ Request,
+ RequestPrototype,
+ toInnerRequest,
+} from "internal:ext/fetch/23_request.js";
+import { toInnerResponse } from "internal:ext/fetch/23_response.js";
+import { URLPrototype } from "internal:ext/url/00_url.js";
+import { getHeader } from "internal:ext/fetch/20_headers.js";
+import { readableStreamForRid } from "internal:ext/web/06_streams.js";
- class CacheStorage {
- constructor() {
- webidl.illegalConstructor();
- }
+class CacheStorage {
+ constructor() {
+ webidl.illegalConstructor();
+ }
- async open(cacheName) {
- webidl.assertBranded(this, CacheStoragePrototype);
- const prefix = "Failed to execute 'open' on 'CacheStorage'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- cacheName = webidl.converters["DOMString"](cacheName, {
- prefix,
- context: "Argument 1",
- });
- const cacheId = await core.opAsync("op_cache_storage_open", cacheName);
- const cache = webidl.createBranded(Cache);
- cache[_id] = cacheId;
- return cache;
- }
+ async open(cacheName) {
+ webidl.assertBranded(this, CacheStoragePrototype);
+ const prefix = "Failed to execute 'open' on 'CacheStorage'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ cacheName = webidl.converters["DOMString"](cacheName, {
+ prefix,
+ context: "Argument 1",
+ });
+ const cacheId = await core.opAsync("op_cache_storage_open", cacheName);
+ const cache = webidl.createBranded(Cache);
+ cache[_id] = cacheId;
+ return cache;
+ }
- async has(cacheName) {
- webidl.assertBranded(this, CacheStoragePrototype);
- const prefix = "Failed to execute 'has' on 'CacheStorage'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- cacheName = webidl.converters["DOMString"](cacheName, {
- prefix,
- context: "Argument 1",
- });
- return await core.opAsync("op_cache_storage_has", cacheName);
- }
+ async has(cacheName) {
+ webidl.assertBranded(this, CacheStoragePrototype);
+ const prefix = "Failed to execute 'has' on 'CacheStorage'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ cacheName = webidl.converters["DOMString"](cacheName, {
+ prefix,
+ context: "Argument 1",
+ });
+ return await core.opAsync("op_cache_storage_has", cacheName);
+ }
- async delete(cacheName) {
- webidl.assertBranded(this, CacheStoragePrototype);
- const prefix = "Failed to execute 'delete' on 'CacheStorage'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- cacheName = webidl.converters["DOMString"](cacheName, {
- prefix,
- context: "Argument 1",
- });
- return await core.opAsync("op_cache_storage_delete", cacheName);
- }
+ async delete(cacheName) {
+ webidl.assertBranded(this, CacheStoragePrototype);
+ const prefix = "Failed to execute 'delete' on 'CacheStorage'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ cacheName = webidl.converters["DOMString"](cacheName, {
+ prefix,
+ context: "Argument 1",
+ });
+ return await core.opAsync("op_cache_storage_delete", cacheName);
}
+}
- const _matchAll = Symbol("[[matchAll]]");
- const _id = Symbol("id");
+const _matchAll = Symbol("[[matchAll]]");
+const _id = Symbol("id");
- class Cache {
- /** @type {number} */
- [_id];
+class Cache {
+ /** @type {number} */
+ [_id];
- constructor() {
- webidl.illegalConstructor();
- }
+ constructor() {
+ webidl.illegalConstructor();
+ }
- /** See https://w3c.github.io/ServiceWorker/#dom-cache-put */
- async put(request, response) {
- webidl.assertBranded(this, CachePrototype);
- const prefix = "Failed to execute 'put' on 'Cache'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- request = webidl.converters["RequestInfo_DOMString"](request, {
- prefix,
- context: "Argument 1",
- });
- response = webidl.converters["Response"](response, {
- prefix,
- context: "Argument 2",
- });
- // Step 1.
- let innerRequest = null;
- // Step 2.
- if (ObjectPrototypeIsPrototypeOf(RequestPrototype, request)) {
- innerRequest = toInnerRequest(request);
- } else {
- // Step 3.
- innerRequest = toInnerRequest(new Request(request));
- }
- // Step 4.
- const reqUrl = new URL(innerRequest.url());
- if (reqUrl.protocol !== "http:" && reqUrl.protocol !== "https:") {
- throw new TypeError(
- "Request url protocol must be 'http:' or 'https:'",
- );
- }
- if (innerRequest.method !== "GET") {
- throw new TypeError("Request method must be GET");
- }
- // Step 5.
- const innerResponse = toInnerResponse(response);
- // Step 6.
- if (innerResponse.status === 206) {
- throw new TypeError("Response status must not be 206");
- }
- // Step 7.
- const varyHeader = getHeader(innerResponse.headerList, "vary");
- if (varyHeader) {
- const fieldValues = varyHeader.split(",");
- for (let i = 0; i < fieldValues.length; ++i) {
- const field = fieldValues[i];
- if (field.trim() === "*") {
- throw new TypeError("Vary header must not contain '*'");
- }
+ /** See https://w3c.github.io/ServiceWorker/#dom-cache-put */
+ async put(request, response) {
+ webidl.assertBranded(this, CachePrototype);
+ const prefix = "Failed to execute 'put' on 'Cache'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ request = webidl.converters["RequestInfo_DOMString"](request, {
+ prefix,
+ context: "Argument 1",
+ });
+ response = webidl.converters["Response"](response, {
+ prefix,
+ context: "Argument 2",
+ });
+ // Step 1.
+ let innerRequest = null;
+ // Step 2.
+ if (ObjectPrototypeIsPrototypeOf(RequestPrototype, request)) {
+ innerRequest = toInnerRequest(request);
+ } else {
+ // Step 3.
+ innerRequest = toInnerRequest(new Request(request));
+ }
+ // Step 4.
+ const reqUrl = new URL(innerRequest.url());
+ if (reqUrl.protocol !== "http:" && reqUrl.protocol !== "https:") {
+ throw new TypeError(
+ "Request url protocol must be 'http:' or 'https:'",
+ );
+ }
+ if (innerRequest.method !== "GET") {
+ throw new TypeError("Request method must be GET");
+ }
+ // Step 5.
+ const innerResponse = toInnerResponse(response);
+ // Step 6.
+ if (innerResponse.status === 206) {
+ throw new TypeError("Response status must not be 206");
+ }
+ // Step 7.
+ const varyHeader = getHeader(innerResponse.headerList, "vary");
+ if (varyHeader) {
+ const fieldValues = varyHeader.split(",");
+ for (let i = 0; i < fieldValues.length; ++i) {
+ const field = fieldValues[i];
+ if (field.trim() === "*") {
+ throw new TypeError("Vary header must not contain '*'");
}
}
+ }
- // Step 8.
- if (innerResponse.body !== null && innerResponse.body.unusable()) {
- throw new TypeError("Response body is already used");
- }
- // acquire lock before async op
- const reader = innerResponse.body?.stream.getReader();
+ // Step 8.
+ if (innerResponse.body !== null && innerResponse.body.unusable()) {
+ throw new TypeError("Response body is already used");
+ }
+ // acquire lock before async op
+ const reader = innerResponse.body?.stream.getReader();
- // Remove fragment from request URL before put.
- reqUrl.hash = "";
+ // Remove fragment from request URL before put.
+ reqUrl.hash = "";
- // Step 9-11.
- const rid = await core.opAsync(
- "op_cache_put",
- {
- cacheId: this[_id],
- requestUrl: reqUrl.toString(),
- responseHeaders: innerResponse.headerList,
- requestHeaders: innerRequest.headerList,
- responseHasBody: innerResponse.body !== null,
- responseStatus: innerResponse.status,
- responseStatusText: innerResponse.statusMessage,
- },
- );
- if (reader) {
- try {
- while (true) {
- const { value, done } = await reader.read();
- if (done) {
- await core.shutdown(rid);
- break;
- }
- await core.writeAll(rid, value);
+ // Step 9-11.
+ const rid = await core.opAsync(
+ "op_cache_put",
+ {
+ cacheId: this[_id],
+ requestUrl: reqUrl.toString(),
+ responseHeaders: innerResponse.headerList,
+ requestHeaders: innerRequest.headerList,
+ responseHasBody: innerResponse.body !== null,
+ responseStatus: innerResponse.status,
+ responseStatusText: innerResponse.statusMessage,
+ },
+ );
+ if (reader) {
+ try {
+ while (true) {
+ const { value, done } = await reader.read();
+ if (done) {
+ await core.shutdown(rid);
+ break;
}
- } finally {
- core.close(rid);
+ await core.writeAll(rid, value);
}
+ } finally {
+ core.close(rid);
}
- // Step 12-19: TODO(@satyarohith): do the insertion in background.
}
+ // Step 12-19: TODO(@satyarohith): do the insertion in background.
+ }
- /** See https://w3c.github.io/ServiceWorker/#cache-match */
- async match(request, options) {
- webidl.assertBranded(this, CachePrototype);
- const prefix = "Failed to execute 'match' on 'Cache'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- request = webidl.converters["RequestInfo_DOMString"](request, {
- prefix,
- context: "Argument 1",
- });
- const p = await this[_matchAll](request, options);
- if (p.length > 0) {
- return p[0];
- } else {
- return undefined;
- }
+ /** See https://w3c.github.io/ServiceWorker/#cache-match */
+ async match(request, options) {
+ webidl.assertBranded(this, CachePrototype);
+ const prefix = "Failed to execute 'match' on 'Cache'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ request = webidl.converters["RequestInfo_DOMString"](request, {
+ prefix,
+ context: "Argument 1",
+ });
+ const p = await this[_matchAll](request, options);
+ if (p.length > 0) {
+ return p[0];
+ } else {
+ return undefined;
}
+ }
- /** See https://w3c.github.io/ServiceWorker/#cache-delete */
- async delete(request, _options) {
- webidl.assertBranded(this, CachePrototype);
- const prefix = "Failed to execute 'delete' on 'Cache'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- request = webidl.converters["RequestInfo_DOMString"](request, {
- prefix,
- context: "Argument 1",
- });
- // Step 1.
- let r = null;
- // Step 2.
- if (ObjectPrototypeIsPrototypeOf(RequestPrototype, request)) {
- r = request;
- if (request.method !== "GET") {
- return false;
- }
- } else if (
- typeof request === "string" ||
- ObjectPrototypeIsPrototypeOf(URLPrototype, request)
- ) {
- r = new Request(request);
+ /** See https://w3c.github.io/ServiceWorker/#cache-delete */
+ async delete(request, _options) {
+ webidl.assertBranded(this, CachePrototype);
+ const prefix = "Failed to execute 'delete' on 'Cache'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ request = webidl.converters["RequestInfo_DOMString"](request, {
+ prefix,
+ context: "Argument 1",
+ });
+ // Step 1.
+ let r = null;
+ // Step 2.
+ if (ObjectPrototypeIsPrototypeOf(RequestPrototype, request)) {
+ r = request;
+ if (request.method !== "GET") {
+ return false;
}
- return await core.opAsync("op_cache_delete", {
- cacheId: this[_id],
- requestUrl: r.url,
- });
+ } else if (
+ typeof request === "string" ||
+ ObjectPrototypeIsPrototypeOf(URLPrototype, request)
+ ) {
+ r = new Request(request);
}
+ return await core.opAsync("op_cache_delete", {
+ cacheId: this[_id],
+ requestUrl: r.url,
+ });
+ }
- /** See https://w3c.github.io/ServiceWorker/#cache-matchall
- *
- * Note: the function is private as we don't want to expose
- * this API to the public yet.
- *
- * The function will return an array of responses.
- */
- async [_matchAll](request, _options) {
- // Step 1.
- let r = null;
- // Step 2.
- if (ObjectPrototypeIsPrototypeOf(RequestPrototype, request)) {
- r = request;
- if (request.method !== "GET") {
- return [];
- }
- } else if (
- typeof request === "string" ||
- ObjectPrototypeIsPrototypeOf(URLPrototype, request)
- ) {
- r = new Request(request);
+ /** See https://w3c.github.io/ServiceWorker/#cache-matchall
+ *
+ * Note: the function is private as we don't want to expose
+ * this API to the public yet.
+ *
+ * The function will return an array of responses.
+ */
+ async [_matchAll](request, _options) {
+ // Step 1.
+ let r = null;
+ // Step 2.
+ if (ObjectPrototypeIsPrototypeOf(RequestPrototype, request)) {
+ r = request;
+ if (request.method !== "GET") {
+ return [];
}
+ } else if (
+ typeof request === "string" ||
+ ObjectPrototypeIsPrototypeOf(URLPrototype, request)
+ ) {
+ r = new Request(request);
+ }
- // Step 5.
- const responses = [];
- // Step 5.2
- if (r === null) {
- // Step 5.3
- // Note: we have to return all responses in the cache when
- // the request is null.
- // We deviate from the spec here and return an empty array
- // as we don't expose matchAll() API.
- return responses;
- } else {
- // Remove the fragment from the request URL.
- const url = new URL(r.url);
- url.hash = "";
- const innerRequest = toInnerRequest(r);
- const matchResult = await core.opAsync(
- "op_cache_match",
+ // Step 5.
+ const responses = [];
+ // Step 5.2
+ if (r === null) {
+ // Step 5.3
+ // Note: we have to return all responses in the cache when
+ // the request is null.
+ // We deviate from the spec here and return an empty array
+ // as we don't expose matchAll() API.
+ return responses;
+ } else {
+ // Remove the fragment from the request URL.
+ const url = new URL(r.url);
+ url.hash = "";
+ const innerRequest = toInnerRequest(r);
+ const matchResult = await core.opAsync(
+ "op_cache_match",
+ {
+ cacheId: this[_id],
+ requestUrl: url.toString(),
+ requestHeaders: innerRequest.headerList,
+ },
+ );
+ if (matchResult) {
+ const { 0: meta, 1: responseBodyRid } = matchResult;
+ let body = null;
+ if (responseBodyRid !== null) {
+ body = readableStreamForRid(responseBodyRid);
+ }
+ const response = new Response(
+ body,
{
- cacheId: this[_id],
- requestUrl: url.toString(),
- requestHeaders: innerRequest.headerList,
+ headers: meta.responseHeaders,
+ status: meta.responseStatus,
+ statusText: meta.responseStatusText,
},
);
- if (matchResult) {
- const { 0: meta, 1: responseBodyRid } = matchResult;
- let body = null;
- if (responseBodyRid !== null) {
- body = readableStreamForRid(responseBodyRid);
- }
- const response = new Response(
- body,
- {
- headers: meta.responseHeaders,
- status: meta.responseStatus,
- statusText: meta.responseStatusText,
- },
- );
- responses.push(response);
- }
+ responses.push(response);
}
- // Step 5.4-5.5: don't apply in this context.
-
- return responses;
}
+ // Step 5.4-5.5: don't apply in this context.
+
+ return responses;
}
+}
- webidl.configurePrototype(CacheStorage);
- webidl.configurePrototype(Cache);
- const CacheStoragePrototype = CacheStorage.prototype;
- const CachePrototype = Cache.prototype;
+webidl.configurePrototype(CacheStorage);
+webidl.configurePrototype(Cache);
+const CacheStoragePrototype = CacheStorage.prototype;
+const CachePrototype = Cache.prototype;
- let cacheStorage;
- window.__bootstrap.caches = {
- CacheStorage,
- Cache,
- cacheStorage() {
- if (!cacheStorage) {
- cacheStorage = webidl.createBranded(CacheStorage);
- }
- return cacheStorage;
- },
- };
-})(this);
+let cacheStorageStorage;
+function cacheStorage() {
+ if (!cacheStorageStorage) {
+ cacheStorageStorage = webidl.createBranded(CacheStorage);
+ }
+ return cacheStorageStorage;
+}
+
+export { Cache, CacheStorage, cacheStorage };
diff --git a/ext/cache/lib.rs b/ext/cache/lib.rs
index 888407153..a35ac6246 100644
--- a/ext/cache/lib.rs
+++ b/ext/cache/lib.rs
@@ -27,7 +27,7 @@ pub fn init<CA: Cache + 'static>(
) -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_webidl", "deno_web", "deno_url", "deno_fetch"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/cache",
"01_cache.js",
))
diff --git a/ext/console/01_colors.js b/ext/console/01_colors.js
index 00425f08b..d01edd247 100644
--- a/ext/console/01_colors.js
+++ b/ext/console/01_colors.js
@@ -2,110 +2,107 @@
/// <reference path="../../core/internal.d.ts" />
-"use strict";
-
-((window) => {
- const {
- RegExp,
- StringPrototypeReplace,
- ArrayPrototypeJoin,
- } = window.__bootstrap.primordials;
-
- let noColor = false;
-
- function setNoColor(value) {
- noColor = value;
- }
-
- function getNoColor() {
- return noColor;
- }
-
- function code(open, close) {
- return {
- open: `\x1b[${open}m`,
- close: `\x1b[${close}m`,
- regexp: new RegExp(`\\x1b\\[${close}m`, "g"),
- };
- }
-
- function run(str, code) {
- return `${code.open}${
- StringPrototypeReplace(str, code.regexp, code.open)
- }${code.close}`;
- }
-
- function bold(str) {
- return run(str, code(1, 22));
- }
-
- function italic(str) {
- return run(str, code(3, 23));
- }
-
- function yellow(str) {
- return run(str, code(33, 39));
- }
-
- function cyan(str) {
- return run(str, code(36, 39));
- }
-
- function red(str) {
- return run(str, code(31, 39));
- }
-
- function green(str) {
- return run(str, code(32, 39));
- }
-
- function bgRed(str) {
- return run(str, code(41, 49));
- }
-
- function white(str) {
- return run(str, code(37, 39));
- }
-
- function gray(str) {
- return run(str, code(90, 39));
- }
-
- function magenta(str) {
- return run(str, code(35, 39));
- }
-
- // https://github.com/chalk/ansi-regex/blob/02fa893d619d3da85411acc8fd4e2eea0e95a9d9/index.js
- const ANSI_PATTERN = new RegExp(
- ArrayPrototypeJoin([
- "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
- "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))",
- ], "|"),
- "g",
- );
-
- function stripColor(string) {
- return StringPrototypeReplace(string, ANSI_PATTERN, "");
- }
-
- function maybeColor(fn) {
- return !noColor ? fn : (s) => s;
- }
-
- window.__bootstrap.colors = {
- bold,
- italic,
- yellow,
- cyan,
- red,
- green,
- bgRed,
- white,
- gray,
- magenta,
- stripColor,
- maybeColor,
- setNoColor,
- getNoColor,
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ RegExp,
+ StringPrototypeReplace,
+ ArrayPrototypeJoin,
+} = primordials;
+
+let noColor = false;
+
+function setNoColor(value) {
+ noColor = value;
+}
+
+function getNoColor() {
+ return noColor;
+}
+
+function code(open, close) {
+ return {
+ open: `\x1b[${open}m`,
+ close: `\x1b[${close}m`,
+ regexp: new RegExp(`\\x1b\\[${close}m`, "g"),
};
-})(this);
+}
+
+function run(str, code) {
+ return `${code.open}${
+ StringPrototypeReplace(str, code.regexp, code.open)
+ }${code.close}`;
+}
+
+function bold(str) {
+ return run(str, code(1, 22));
+}
+
+function italic(str) {
+ return run(str, code(3, 23));
+}
+
+function yellow(str) {
+ return run(str, code(33, 39));
+}
+
+function cyan(str) {
+ return run(str, code(36, 39));
+}
+
+function red(str) {
+ return run(str, code(31, 39));
+}
+
+function green(str) {
+ return run(str, code(32, 39));
+}
+
+function bgRed(str) {
+ return run(str, code(41, 49));
+}
+
+function white(str) {
+ return run(str, code(37, 39));
+}
+
+function gray(str) {
+ return run(str, code(90, 39));
+}
+
+function magenta(str) {
+ return run(str, code(35, 39));
+}
+
+// https://github.com/chalk/ansi-regex/blob/02fa893d619d3da85411acc8fd4e2eea0e95a9d9/index.js
+const ANSI_PATTERN = new RegExp(
+ ArrayPrototypeJoin([
+ "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
+ "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))",
+ ], "|"),
+ "g",
+);
+
+function stripColor(string) {
+ return StringPrototypeReplace(string, ANSI_PATTERN, "");
+}
+
+function maybeColor(fn) {
+ return !noColor ? fn : (s) => s;
+}
+
+export {
+ bgRed,
+ bold,
+ cyan,
+ getNoColor,
+ gray,
+ green,
+ italic,
+ magenta,
+ maybeColor,
+ red,
+ setNoColor,
+ stripColor,
+ white,
+ yellow,
+};
diff --git a/ext/console/02_console.js b/ext/console/02_console.js
index a9ec52488..22524e6b9 100644
--- a/ext/console/02_console.js
+++ b/ext/console/02_console.js
@@ -2,2385 +2,2379 @@
/// <reference path="../../core/internal.d.ts" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const colors = window.__bootstrap.colors;
- const {
- AggregateErrorPrototype,
- ArrayPrototypeUnshift,
- isNaN,
- DatePrototype,
- DateNow,
- DatePrototypeGetTime,
- DatePrototypeToISOString,
- Boolean,
- BooleanPrototype,
- BooleanPrototypeToString,
- ObjectKeys,
- ObjectCreate,
- ObjectAssign,
- ObjectIs,
- ObjectValues,
- ObjectFromEntries,
- ObjectGetPrototypeOf,
- ObjectGetOwnPropertyDescriptor,
- ObjectGetOwnPropertySymbols,
- ObjectPrototypeHasOwnProperty,
- ObjectPrototypeIsPrototypeOf,
- ObjectPrototypePropertyIsEnumerable,
- PromisePrototype,
- String,
- StringPrototype,
- StringPrototypeRepeat,
- StringPrototypeReplace,
- StringPrototypeReplaceAll,
- StringPrototypeSplit,
- StringPrototypeSlice,
- StringPrototypeCodePointAt,
- StringPrototypeCharCodeAt,
- StringPrototypeNormalize,
- StringPrototypeMatch,
- StringPrototypePadStart,
- StringPrototypeLocaleCompare,
- StringPrototypeToString,
- StringPrototypeTrim,
- StringPrototypeIncludes,
- StringPrototypeStartsWith,
- TypeError,
- NumberParseInt,
- RegExp,
- RegExpPrototype,
- RegExpPrototypeTest,
- RegExpPrototypeToString,
- SafeArrayIterator,
- SafeStringIterator,
- SafeSet,
- SetPrototype,
- SetPrototypeEntries,
- SetPrototypeGetSize,
- Symbol,
- SymbolPrototype,
- SymbolPrototypeToString,
- SymbolPrototypeValueOf,
- SymbolToStringTag,
- SymbolHasInstance,
- SymbolFor,
- Array,
- ArrayIsArray,
- ArrayPrototypeJoin,
- ArrayPrototypeMap,
- ArrayPrototypeReduce,
- ArrayPrototypeEntries,
- ArrayPrototypePush,
- ArrayPrototypePop,
- ArrayPrototypeSort,
- ArrayPrototypeSlice,
- ArrayPrototypeShift,
- ArrayPrototypeIncludes,
- ArrayPrototypeFill,
- ArrayPrototypeFilter,
- ArrayPrototypeFind,
- FunctionPrototypeBind,
- FunctionPrototypeToString,
- Map,
- MapPrototype,
- MapPrototypeHas,
- MapPrototypeGet,
- MapPrototypeSet,
- MapPrototypeDelete,
- MapPrototypeEntries,
- MapPrototypeForEach,
- MapPrototypeGetSize,
- Error,
- ErrorPrototype,
- ErrorCaptureStackTrace,
- MathAbs,
- MathMax,
- MathMin,
- MathSqrt,
- MathRound,
- MathFloor,
- Number,
- NumberPrototype,
- NumberPrototypeToString,
- NumberPrototypeValueOf,
- BigIntPrototype,
- BigIntPrototypeToString,
- Proxy,
- ReflectGet,
- ReflectGetOwnPropertyDescriptor,
- ReflectGetPrototypeOf,
- ReflectHas,
- TypedArrayPrototypeGetLength,
- TypedArrayPrototypeGetSymbolToStringTag,
- WeakMapPrototype,
- WeakSetPrototype,
- } = window.__bootstrap.primordials;
-
- function isInvalidDate(x) {
- return isNaN(DatePrototypeGetTime(x));
- }
-
- function hasOwnProperty(obj, v) {
- if (obj == null) {
- return false;
- }
- return ObjectPrototypeHasOwnProperty(obj, v);
- }
-
- function propertyIsEnumerable(obj, prop) {
- if (
- obj == null ||
- typeof obj.propertyIsEnumerable !== "function"
- ) {
- return false;
- }
-
- return ObjectPrototypePropertyIsEnumerable(obj, prop);
+const core = globalThis.Deno.core;
+const internals = globalThis.__bootstrap.internals;
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ AggregateErrorPrototype,
+ ArrayPrototypeUnshift,
+ isNaN,
+ DatePrototype,
+ DateNow,
+ DatePrototypeGetTime,
+ DatePrototypeToISOString,
+ Boolean,
+ BooleanPrototype,
+ BooleanPrototypeToString,
+ ObjectKeys,
+ ObjectCreate,
+ ObjectAssign,
+ ObjectIs,
+ ObjectValues,
+ ObjectFromEntries,
+ ObjectGetPrototypeOf,
+ ObjectGetOwnPropertyDescriptor,
+ ObjectGetOwnPropertySymbols,
+ ObjectPrototypeHasOwnProperty,
+ ObjectPrototypeIsPrototypeOf,
+ ObjectPrototypePropertyIsEnumerable,
+ PromisePrototype,
+ String,
+ StringPrototype,
+ StringPrototypeRepeat,
+ StringPrototypeReplace,
+ StringPrototypeReplaceAll,
+ StringPrototypeSplit,
+ StringPrototypeSlice,
+ StringPrototypeCodePointAt,
+ StringPrototypeCharCodeAt,
+ StringPrototypeNormalize,
+ StringPrototypeMatch,
+ StringPrototypePadStart,
+ StringPrototypeLocaleCompare,
+ StringPrototypeToString,
+ StringPrototypeTrim,
+ StringPrototypeIncludes,
+ StringPrototypeStartsWith,
+ TypeError,
+ NumberParseInt,
+ RegExp,
+ RegExpPrototype,
+ RegExpPrototypeTest,
+ RegExpPrototypeToString,
+ SafeArrayIterator,
+ SafeStringIterator,
+ SafeSet,
+ SetPrototype,
+ SetPrototypeEntries,
+ SetPrototypeGetSize,
+ Symbol,
+ SymbolPrototype,
+ SymbolPrototypeToString,
+ SymbolPrototypeValueOf,
+ SymbolToStringTag,
+ SymbolHasInstance,
+ SymbolFor,
+ Array,
+ ArrayIsArray,
+ ArrayPrototypeJoin,
+ ArrayPrototypeMap,
+ ArrayPrototypeReduce,
+ ArrayPrototypeEntries,
+ ArrayPrototypePush,
+ ArrayPrototypePop,
+ ArrayPrototypeSort,
+ ArrayPrototypeSlice,
+ ArrayPrototypeShift,
+ ArrayPrototypeIncludes,
+ ArrayPrototypeFill,
+ ArrayPrototypeFilter,
+ ArrayPrototypeFind,
+ FunctionPrototypeBind,
+ FunctionPrototypeToString,
+ Map,
+ MapPrototype,
+ MapPrototypeHas,
+ MapPrototypeGet,
+ MapPrototypeSet,
+ MapPrototypeDelete,
+ MapPrototypeEntries,
+ MapPrototypeForEach,
+ MapPrototypeGetSize,
+ Error,
+ ErrorPrototype,
+ ErrorCaptureStackTrace,
+ MathAbs,
+ MathMax,
+ MathMin,
+ MathSqrt,
+ MathRound,
+ MathFloor,
+ Number,
+ NumberPrototype,
+ NumberPrototypeToString,
+ NumberPrototypeValueOf,
+ BigIntPrototype,
+ BigIntPrototypeToString,
+ Proxy,
+ ReflectGet,
+ ReflectGetOwnPropertyDescriptor,
+ ReflectGetPrototypeOf,
+ ReflectHas,
+ TypedArrayPrototypeGetLength,
+ TypedArrayPrototypeGetSymbolToStringTag,
+ WeakMapPrototype,
+ WeakSetPrototype,
+} = primordials;
+import * as colors from "internal:ext/console/01_colors.js";
+
+function isInvalidDate(x) {
+ return isNaN(DatePrototypeGetTime(x));
+}
+
+function hasOwnProperty(obj, v) {
+ if (obj == null) {
+ return false;
}
+ return ObjectPrototypeHasOwnProperty(obj, v);
+}
- // Copyright Joyent, Inc. and other Node contributors. MIT license.
- // Forked from Node's lib/internal/cli_table.js
-
- function isTypedArray(x) {
- return TypedArrayPrototypeGetSymbolToStringTag(x) !== undefined;
+function propertyIsEnumerable(obj, prop) {
+ if (
+ obj == null ||
+ typeof obj.propertyIsEnumerable !== "function"
+ ) {
+ return false;
}
- const tableChars = {
- middleMiddle: "─",
- rowMiddle: "┼",
- topRight: "┐",
- topLeft: "┌",
- leftMiddle: "├",
- topMiddle: "┬",
- bottomRight: "┘",
- bottomLeft: "└",
- bottomMiddle: "┴",
- rightMiddle: "┤",
- left: "│ ",
- right: " │",
- middle: " │ ",
- };
-
- function isFullWidthCodePoint(code) {
- // Code points are partially derived from:
- // http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt
- return (
- code >= 0x1100 &&
- (code <= 0x115f || // Hangul Jamo
- code === 0x2329 || // LEFT-POINTING ANGLE BRACKET
- code === 0x232a || // RIGHT-POINTING ANGLE BRACKET
- // CJK Radicals Supplement .. Enclosed CJK Letters and Months
- (code >= 0x2e80 && code <= 0x3247 && code !== 0x303f) ||
- // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A
- (code >= 0x3250 && code <= 0x4dbf) ||
- // CJK Unified Ideographs .. Yi Radicals
- (code >= 0x4e00 && code <= 0xa4c6) ||
- // Hangul Jamo Extended-A
- (code >= 0xa960 && code <= 0xa97c) ||
- // Hangul Syllables
- (code >= 0xac00 && code <= 0xd7a3) ||
- // CJK Compatibility Ideographs
- (code >= 0xf900 && code <= 0xfaff) ||
- // Vertical Forms
- (code >= 0xfe10 && code <= 0xfe19) ||
- // CJK Compatibility Forms .. Small Form Variants
- (code >= 0xfe30 && code <= 0xfe6b) ||
- // Halfwidth and Fullwidth Forms
- (code >= 0xff01 && code <= 0xff60) ||
- (code >= 0xffe0 && code <= 0xffe6) ||
- // Kana Supplement
- (code >= 0x1b000 && code <= 0x1b001) ||
- // Enclosed Ideographic Supplement
- (code >= 0x1f200 && code <= 0x1f251) ||
- // Miscellaneous Symbols and Pictographs 0x1f300 - 0x1f5ff
- // Emoticons 0x1f600 - 0x1f64f
- (code >= 0x1f300 && code <= 0x1f64f) ||
- // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane
- (code >= 0x20000 && code <= 0x3fffd))
- );
+ return ObjectPrototypePropertyIsEnumerable(obj, prop);
+}
+
+// Copyright Joyent, Inc. and other Node contributors. MIT license.
+// Forked from Node's lib/internal/cli_table.js
+
+function isTypedArray(x) {
+ return TypedArrayPrototypeGetSymbolToStringTag(x) !== undefined;
+}
+
+const tableChars = {
+ middleMiddle: "─",
+ rowMiddle: "┼",
+ topRight: "┐",
+ topLeft: "┌",
+ leftMiddle: "├",
+ topMiddle: "┬",
+ bottomRight: "┘",
+ bottomLeft: "└",
+ bottomMiddle: "┴",
+ rightMiddle: "┤",
+ left: "│ ",
+ right: " │",
+ middle: " │ ",
+};
+
+function isFullWidthCodePoint(code) {
+ // Code points are partially derived from:
+ // http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt
+ return (
+ code >= 0x1100 &&
+ (code <= 0x115f || // Hangul Jamo
+ code === 0x2329 || // LEFT-POINTING ANGLE BRACKET
+ code === 0x232a || // RIGHT-POINTING ANGLE BRACKET
+ // CJK Radicals Supplement .. Enclosed CJK Letters and Months
+ (code >= 0x2e80 && code <= 0x3247 && code !== 0x303f) ||
+ // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A
+ (code >= 0x3250 && code <= 0x4dbf) ||
+ // CJK Unified Ideographs .. Yi Radicals
+ (code >= 0x4e00 && code <= 0xa4c6) ||
+ // Hangul Jamo Extended-A
+ (code >= 0xa960 && code <= 0xa97c) ||
+ // Hangul Syllables
+ (code >= 0xac00 && code <= 0xd7a3) ||
+ // CJK Compatibility Ideographs
+ (code >= 0xf900 && code <= 0xfaff) ||
+ // Vertical Forms
+ (code >= 0xfe10 && code <= 0xfe19) ||
+ // CJK Compatibility Forms .. Small Form Variants
+ (code >= 0xfe30 && code <= 0xfe6b) ||
+ // Halfwidth and Fullwidth Forms
+ (code >= 0xff01 && code <= 0xff60) ||
+ (code >= 0xffe0 && code <= 0xffe6) ||
+ // Kana Supplement
+ (code >= 0x1b000 && code <= 0x1b001) ||
+ // Enclosed Ideographic Supplement
+ (code >= 0x1f200 && code <= 0x1f251) ||
+ // Miscellaneous Symbols and Pictographs 0x1f300 - 0x1f5ff
+ // Emoticons 0x1f600 - 0x1f64f
+ (code >= 0x1f300 && code <= 0x1f64f) ||
+ // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane
+ (code >= 0x20000 && code <= 0x3fffd))
+ );
+}
+
+function getStringWidth(str) {
+ str = StringPrototypeNormalize(colors.stripColor(str), "NFC");
+ let width = 0;
+
+ for (const ch of new SafeStringIterator(str)) {
+ width += isFullWidthCodePoint(StringPrototypeCodePointAt(ch, 0)) ? 2 : 1;
}
- function getStringWidth(str) {
- str = StringPrototypeNormalize(colors.stripColor(str), "NFC");
- let width = 0;
-
- for (const ch of new SafeStringIterator(str)) {
- width += isFullWidthCodePoint(StringPrototypeCodePointAt(ch, 0)) ? 2 : 1;
+ return width;
+}
+
+function renderRow(row, columnWidths, columnRightAlign) {
+ let out = tableChars.left;
+ for (let i = 0; i < row.length; i++) {
+ const cell = row[i];
+ const len = getStringWidth(cell);
+ const padding = StringPrototypeRepeat(" ", columnWidths[i] - len);
+ if (columnRightAlign?.[i]) {
+ out += `${padding}${cell}`;
+ } else {
+ out += `${cell}${padding}`;
+ }
+ if (i !== row.length - 1) {
+ out += tableChars.middle;
}
-
- return width;
}
-
- function renderRow(row, columnWidths, columnRightAlign) {
- let out = tableChars.left;
- for (let i = 0; i < row.length; i++) {
- const cell = row[i];
- const len = getStringWidth(cell);
- const padding = StringPrototypeRepeat(" ", columnWidths[i] - len);
- if (columnRightAlign?.[i]) {
- out += `${padding}${cell}`;
- } else {
- out += `${cell}${padding}`;
- }
- if (i !== row.length - 1) {
- out += tableChars.middle;
+ out += tableChars.right;
+ return out;
+}
+
+function canRightAlign(value) {
+ const isNumber = !isNaN(value);
+ return isNumber;
+}
+
+function cliTable(head, columns) {
+ const rows = [];
+ const columnWidths = ArrayPrototypeMap(head, (h) => getStringWidth(h));
+ const longestColumn = ArrayPrototypeReduce(
+ columns,
+ (n, a) => MathMax(n, a.length),
+ 0,
+ );
+ const columnRightAlign = new Array(columnWidths.length).fill(true);
+
+ for (let i = 0; i < head.length; i++) {
+ const column = columns[i];
+ for (let j = 0; j < longestColumn; j++) {
+ if (rows[j] === undefined) {
+ rows[j] = [];
}
+ const value = (rows[j][i] = hasOwnProperty(column, j) ? column[j] : "");
+ const width = columnWidths[i] || 0;
+ const counted = getStringWidth(value);
+ columnWidths[i] = MathMax(width, counted);
+ columnRightAlign[i] &= canRightAlign(value);
}
- out += tableChars.right;
- return out;
}
- function canRightAlign(value) {
- const isNumber = !isNaN(value);
- return isNumber;
+ const divider = ArrayPrototypeMap(
+ columnWidths,
+ (i) => StringPrototypeRepeat(tableChars.middleMiddle, i + 2),
+ );
+
+ let result =
+ `${tableChars.topLeft}${
+ ArrayPrototypeJoin(divider, tableChars.topMiddle)
+ }` +
+ `${tableChars.topRight}\n${renderRow(head, columnWidths)}\n` +
+ `${tableChars.leftMiddle}${
+ ArrayPrototypeJoin(divider, tableChars.rowMiddle)
+ }` +
+ `${tableChars.rightMiddle}\n`;
+
+ for (let i = 0; i < rows.length; ++i) {
+ const row = rows[i];
+ result += `${renderRow(row, columnWidths, columnRightAlign)}\n`;
}
- function cliTable(head, columns) {
- const rows = [];
- const columnWidths = ArrayPrototypeMap(head, (h) => getStringWidth(h));
- const longestColumn = ArrayPrototypeReduce(
- columns,
- (n, a) => MathMax(n, a.length),
- 0,
- );
- const columnRightAlign = new Array(columnWidths.length).fill(true);
-
- for (let i = 0; i < head.length; i++) {
- const column = columns[i];
- for (let j = 0; j < longestColumn; j++) {
- if (rows[j] === undefined) {
- rows[j] = [];
- }
- const value = (rows[j][i] = hasOwnProperty(column, j) ? column[j] : "");
- const width = columnWidths[i] || 0;
- const counted = getStringWidth(value);
- columnWidths[i] = MathMax(width, counted);
- columnRightAlign[i] &= canRightAlign(value);
- }
- }
+ result +=
+ `${tableChars.bottomLeft}${
+ ArrayPrototypeJoin(divider, tableChars.bottomMiddle)
+ }` +
+ tableChars.bottomRight;
+
+ return result;
+}
+/* End of forked part */
+
+const DEFAULT_INSPECT_OPTIONS = {
+ depth: 4,
+ indentLevel: 0,
+ sorted: false,
+ trailingComma: false,
+ compact: true,
+ iterableLimit: 100,
+ showProxy: false,
+ colors: false,
+ getters: false,
+ showHidden: false,
+ strAbbreviateSize: 100,
+};
+
+const DEFAULT_INDENT = " "; // Default indent string
+
+const LINE_BREAKING_LENGTH = 80;
+const MIN_GROUP_LENGTH = 6;
+const STR_ABBREVIATE_SIZE = 100;
+
+const PROMISE_STRING_BASE_LENGTH = 12;
+
+class CSI {
+ static kClear = "\x1b[1;1H";
+ static kClearScreenDown = "\x1b[0J";
+}
+
+function getClassInstanceName(instance) {
+ if (typeof instance != "object") {
+ return "";
+ }
+ const constructor = instance?.constructor;
+ if (typeof constructor == "function") {
+ return constructor.name ?? "";
+ }
+ return "";
+}
+
+function maybeColor(fn, inspectOptions) {
+ return inspectOptions.colors ? fn : (s) => s;
+}
+
+function inspectFunction(value, inspectOptions) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ if (
+ ReflectHas(value, customInspect) &&
+ typeof value[customInspect] === "function"
+ ) {
+ return String(value[customInspect](inspect, inspectOptions));
+ }
+ // Might be Function/AsyncFunction/GeneratorFunction/AsyncGeneratorFunction
+ let cstrName = ObjectGetPrototypeOf(value)?.constructor?.name;
+ if (!cstrName) {
+ // If prototype is removed or broken,
+ // use generic 'Function' instead.
+ cstrName = "Function";
+ }
+ const stringValue = FunctionPrototypeToString(value);
+ // Might be Class
+ if (StringPrototypeStartsWith(stringValue, "class")) {
+ cstrName = "Class";
+ }
- const divider = ArrayPrototypeMap(
- columnWidths,
- (i) => StringPrototypeRepeat(tableChars.middleMiddle, i + 2),
+ // Our function may have properties, so we want to format those
+ // as if our function was an object
+ // If we didn't find any properties, we will just append an
+ // empty suffix.
+ let suffix = ``;
+ let refStr = "";
+ if (
+ ObjectKeys(value).length > 0 ||
+ ObjectGetOwnPropertySymbols(value).length > 0
+ ) {
+ const { 0: propString, 1: refIndex } = inspectRawObject(
+ value,
+ inspectOptions,
);
-
- let result =
- `${tableChars.topLeft}${
- ArrayPrototypeJoin(divider, tableChars.topMiddle)
- }` +
- `${tableChars.topRight}\n${renderRow(head, columnWidths)}\n` +
- `${tableChars.leftMiddle}${
- ArrayPrototypeJoin(divider, tableChars.rowMiddle)
- }` +
- `${tableChars.rightMiddle}\n`;
-
- for (let i = 0; i < rows.length; ++i) {
- const row = rows[i];
- result += `${renderRow(row, columnWidths, columnRightAlign)}\n`;
+ refStr = refIndex;
+ // Filter out the empty string for the case we only have
+ // non-enumerable symbols.
+ if (
+ propString.length > 0 &&
+ propString !== "{}"
+ ) {
+ suffix = ` ${propString}`;
}
-
- result +=
- `${tableChars.bottomLeft}${
- ArrayPrototypeJoin(divider, tableChars.bottomMiddle)
- }` +
- tableChars.bottomRight;
-
- return result;
- }
- /* End of forked part */
-
- const DEFAULT_INSPECT_OPTIONS = {
- depth: 4,
- indentLevel: 0,
- sorted: false,
- trailingComma: false,
- compact: true,
- iterableLimit: 100,
- showProxy: false,
- colors: false,
- getters: false,
- showHidden: false,
- strAbbreviateSize: 100,
- };
-
- const DEFAULT_INDENT = " "; // Default indent string
-
- const LINE_BREAKING_LENGTH = 80;
- const MIN_GROUP_LENGTH = 6;
- const STR_ABBREVIATE_SIZE = 100;
-
- const PROMISE_STRING_BASE_LENGTH = 12;
-
- class CSI {
- static kClear = "\x1b[1;1H";
- static kClearScreenDown = "\x1b[0J";
}
- function getClassInstanceName(instance) {
- if (typeof instance != "object") {
- return "";
- }
- const constructor = instance?.constructor;
- if (typeof constructor == "function") {
- return constructor.name ?? "";
- }
- return "";
+ if (value.name && value.name !== "anonymous") {
+ // from MDN spec
+ return cyan(`${refStr}[${cstrName}: ${value.name}]`) + suffix;
}
-
- function maybeColor(fn, inspectOptions) {
- return inspectOptions.colors ? fn : (s) => s;
+ return cyan(`${refStr}[${cstrName}]`) + suffix;
+}
+
+function inspectIterable(
+ value,
+ options,
+ inspectOptions,
+) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ if (inspectOptions.indentLevel >= inspectOptions.depth) {
+ return cyan(`[${options.typeName}]`);
}
- function inspectFunction(value, inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- if (
- ReflectHas(value, customInspect) &&
- typeof value[customInspect] === "function"
- ) {
- return String(value[customInspect](inspect, inspectOptions));
- }
- // Might be Function/AsyncFunction/GeneratorFunction/AsyncGeneratorFunction
- let cstrName = ObjectGetPrototypeOf(value)?.constructor?.name;
- if (!cstrName) {
- // If prototype is removed or broken,
- // use generic 'Function' instead.
- cstrName = "Function";
- }
- const stringValue = FunctionPrototypeToString(value);
- // Might be Class
- if (StringPrototypeStartsWith(stringValue, "class")) {
- cstrName = "Class";
- }
+ const entries = [];
+ let iter;
+ let valueIsTypedArray = false;
+ let entriesLength;
+
+ switch (options.typeName) {
+ case "Map":
+ iter = MapPrototypeEntries(value);
+ entriesLength = MapPrototypeGetSize(value);
+ break;
+ case "Set":
+ iter = SetPrototypeEntries(value);
+ entriesLength = SetPrototypeGetSize(value);
+ break;
+ case "Array":
+ entriesLength = value.length;
+ break;
+ default:
+ if (isTypedArray(value)) {
+ entriesLength = TypedArrayPrototypeGetLength(value);
+ iter = ArrayPrototypeEntries(value);
+ valueIsTypedArray = true;
+ } else {
+ throw new TypeError("unreachable");
+ }
+ }
- // Our function may have properties, so we want to format those
- // as if our function was an object
- // If we didn't find any properties, we will just append an
- // empty suffix.
- let suffix = ``;
- let refStr = "";
- if (
- ObjectKeys(value).length > 0 ||
- ObjectGetOwnPropertySymbols(value).length > 0
+ let entriesLengthWithoutEmptyItems = entriesLength;
+ if (options.typeName === "Array") {
+ for (
+ let i = 0, j = 0;
+ i < entriesLength && j < inspectOptions.iterableLimit;
+ i++, j++
) {
- const { 0: propString, 1: refIndex } = inspectRawObject(
- value,
+ inspectOptions.indentLevel++;
+ const { entry, skipTo } = options.entryHandler(
+ [i, value[i]],
inspectOptions,
);
- refStr = refIndex;
- // Filter out the empty string for the case we only have
- // non-enumerable symbols.
- if (
- propString.length > 0 &&
- propString !== "{}"
- ) {
- suffix = ` ${propString}`;
- }
- }
-
- if (value.name && value.name !== "anonymous") {
- // from MDN spec
- return cyan(`${refStr}[${cstrName}: ${value.name}]`) + suffix;
- }
- return cyan(`${refStr}[${cstrName}]`) + suffix;
- }
+ ArrayPrototypePush(entries, entry);
+ inspectOptions.indentLevel--;
- function inspectIterable(
- value,
- options,
- inspectOptions,
- ) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- if (inspectOptions.indentLevel >= inspectOptions.depth) {
- return cyan(`[${options.typeName}]`);
+ if (skipTo) {
+ // subtract skipped (empty) items
+ entriesLengthWithoutEmptyItems -= skipTo - i;
+ i = skipTo;
+ }
}
-
- const entries = [];
- let iter;
- let valueIsTypedArray = false;
- let entriesLength;
-
- switch (options.typeName) {
- case "Map":
- iter = MapPrototypeEntries(value);
- entriesLength = MapPrototypeGetSize(value);
- break;
- case "Set":
- iter = SetPrototypeEntries(value);
- entriesLength = SetPrototypeGetSize(value);
- break;
- case "Array":
- entriesLength = value.length;
- break;
- default:
- if (isTypedArray(value)) {
- entriesLength = TypedArrayPrototypeGetLength(value);
- iter = ArrayPrototypeEntries(value);
- valueIsTypedArray = true;
- } else {
- throw new TypeError("unreachable");
+ } else {
+ let i = 0;
+ while (true) {
+ let el;
+ try {
+ const res = iter.next();
+ if (res.done) {
+ break;
}
- }
-
- let entriesLengthWithoutEmptyItems = entriesLength;
- if (options.typeName === "Array") {
- for (
- let i = 0, j = 0;
- i < entriesLength && j < inspectOptions.iterableLimit;
- i++, j++
- ) {
+ el = res.value;
+ } catch (err) {
+ if (valueIsTypedArray) {
+ // TypedArray.prototype.entries doesn't throw, unless the ArrayBuffer
+ // is detached. We don't want to show the exception in that case, so
+ // we catch it here and pretend the ArrayBuffer has no entries (like
+ // Chrome DevTools does).
+ break;
+ }
+ throw err;
+ }
+ if (i < inspectOptions.iterableLimit) {
inspectOptions.indentLevel++;
- const { entry, skipTo } = options.entryHandler(
- [i, value[i]],
- inspectOptions,
+ ArrayPrototypePush(
+ entries,
+ options.entryHandler(
+ el,
+ inspectOptions,
+ ),
);
- ArrayPrototypePush(entries, entry);
inspectOptions.indentLevel--;
-
- if (skipTo) {
- // subtract skipped (empty) items
- entriesLengthWithoutEmptyItems -= skipTo - i;
- i = skipTo;
- }
- }
- } else {
- let i = 0;
- while (true) {
- let el;
- try {
- const res = iter.next();
- if (res.done) {
- break;
- }
- el = res.value;
- } catch (err) {
- if (valueIsTypedArray) {
- // TypedArray.prototype.entries doesn't throw, unless the ArrayBuffer
- // is detached. We don't want to show the exception in that case, so
- // we catch it here and pretend the ArrayBuffer has no entries (like
- // Chrome DevTools does).
- break;
- }
- throw err;
- }
- if (i < inspectOptions.iterableLimit) {
- inspectOptions.indentLevel++;
- ArrayPrototypePush(
- entries,
- options.entryHandler(
- el,
- inspectOptions,
- ),
- );
- inspectOptions.indentLevel--;
- } else {
- break;
- }
- i++;
+ } else {
+ break;
}
+ i++;
}
+ }
- if (options.sort) {
- ArrayPrototypeSort(entries);
- }
-
- if (entriesLengthWithoutEmptyItems > inspectOptions.iterableLimit) {
- const nmore = entriesLengthWithoutEmptyItems -
- inspectOptions.iterableLimit;
- ArrayPrototypePush(entries, `... ${nmore} more items`);
- }
+ if (options.sort) {
+ ArrayPrototypeSort(entries);
+ }
- const iPrefix = `${options.displayName ? options.displayName + " " : ""}`;
+ if (entriesLengthWithoutEmptyItems > inspectOptions.iterableLimit) {
+ const nmore = entriesLengthWithoutEmptyItems -
+ inspectOptions.iterableLimit;
+ ArrayPrototypePush(entries, `... ${nmore} more items`);
+ }
- const level = inspectOptions.indentLevel;
- const initIndentation = `\n${
- StringPrototypeRepeat(DEFAULT_INDENT, level + 1)
- }`;
- const entryIndentation = `,\n${
- StringPrototypeRepeat(DEFAULT_INDENT, level + 1)
- }`;
- const closingDelimIndentation = StringPrototypeRepeat(
- DEFAULT_INDENT,
- level,
- );
- const closingIndentation = `${
- inspectOptions.trailingComma ? "," : ""
- }\n${closingDelimIndentation}`;
-
- let iContent;
- if (entries.length === 0 && !inspectOptions.compact) {
- iContent = `\n${closingDelimIndentation}`;
- } else if (options.group && entries.length > MIN_GROUP_LENGTH) {
- const groups = groupEntries(entries, level, value);
+ const iPrefix = `${options.displayName ? options.displayName + " " : ""}`;
+
+ const level = inspectOptions.indentLevel;
+ const initIndentation = `\n${
+ StringPrototypeRepeat(DEFAULT_INDENT, level + 1)
+ }`;
+ const entryIndentation = `,\n${
+ StringPrototypeRepeat(DEFAULT_INDENT, level + 1)
+ }`;
+ const closingDelimIndentation = StringPrototypeRepeat(
+ DEFAULT_INDENT,
+ level,
+ );
+ const closingIndentation = `${
+ inspectOptions.trailingComma ? "," : ""
+ }\n${closingDelimIndentation}`;
+
+ let iContent;
+ if (entries.length === 0 && !inspectOptions.compact) {
+ iContent = `\n${closingDelimIndentation}`;
+ } else if (options.group && entries.length > MIN_GROUP_LENGTH) {
+ const groups = groupEntries(entries, level, value);
+ iContent = `${initIndentation}${
+ ArrayPrototypeJoin(groups, entryIndentation)
+ }${closingIndentation}`;
+ } else {
+ iContent = entries.length === 0
+ ? ""
+ : ` ${ArrayPrototypeJoin(entries, ", ")} `;
+ if (
+ colors.stripColor(iContent).length > LINE_BREAKING_LENGTH ||
+ !inspectOptions.compact
+ ) {
iContent = `${initIndentation}${
- ArrayPrototypeJoin(groups, entryIndentation)
+ ArrayPrototypeJoin(entries, entryIndentation)
}${closingIndentation}`;
- } else {
- iContent = entries.length === 0
- ? ""
- : ` ${ArrayPrototypeJoin(entries, ", ")} `;
- if (
- colors.stripColor(iContent).length > LINE_BREAKING_LENGTH ||
- !inspectOptions.compact
- ) {
- iContent = `${initIndentation}${
- ArrayPrototypeJoin(entries, entryIndentation)
- }${closingIndentation}`;
- }
}
-
- return `${iPrefix}${options.delims[0]}${iContent}${options.delims[1]}`;
}
- // Ported from Node.js
- // Copyright Node.js contributors. All rights reserved.
- function groupEntries(
- entries,
- level,
- value,
- iterableLimit = 100,
+ return `${iPrefix}${options.delims[0]}${iContent}${options.delims[1]}`;
+}
+
+// Ported from Node.js
+// Copyright Node.js contributors. All rights reserved.
+function groupEntries(
+ entries,
+ level,
+ value,
+ iterableLimit = 100,
+) {
+ let totalLength = 0;
+ let maxLength = 0;
+ let entriesLength = entries.length;
+ if (iterableLimit < entriesLength) {
+ // This makes sure the "... n more items" part is not taken into account.
+ entriesLength--;
+ }
+ const separatorSpace = 2; // Add 1 for the space and 1 for the separator.
+ const dataLen = new Array(entriesLength);
+ // Calculate the total length of all output entries and the individual max
+ // entries length of all output entries.
+ // IN PROGRESS: Colors are being taken into account.
+ for (let i = 0; i < entriesLength; i++) {
+ // Taking colors into account: removing the ANSI color
+ // codes from the string before measuring its length
+ const len = colors.stripColor(entries[i]).length;
+ dataLen[i] = len;
+ totalLength += len + separatorSpace;
+ if (maxLength < len) maxLength = len;
+ }
+ // Add two to `maxLength` as we add a single whitespace character plus a comma
+ // in-between two entries.
+ const actualMax = maxLength + separatorSpace;
+ // Check if at least three entries fit next to each other and prevent grouping
+ // of arrays that contains entries of very different length (i.e., if a single
+ // entry is longer than 1/5 of all other entries combined). Otherwise the
+ // space in-between small entries would be enormous.
+ if (
+ actualMax * 3 + (level + 1) < LINE_BREAKING_LENGTH &&
+ (totalLength / actualMax > 5 || maxLength <= 6)
) {
- let totalLength = 0;
- let maxLength = 0;
- let entriesLength = entries.length;
- if (iterableLimit < entriesLength) {
- // This makes sure the "... n more items" part is not taken into account.
- entriesLength--;
- }
- const separatorSpace = 2; // Add 1 for the space and 1 for the separator.
- const dataLen = new Array(entriesLength);
- // Calculate the total length of all output entries and the individual max
- // entries length of all output entries.
- // IN PROGRESS: Colors are being taken into account.
- for (let i = 0; i < entriesLength; i++) {
- // Taking colors into account: removing the ANSI color
- // codes from the string before measuring its length
- const len = colors.stripColor(entries[i]).length;
- dataLen[i] = len;
- totalLength += len + separatorSpace;
- if (maxLength < len) maxLength = len;
- }
- // Add two to `maxLength` as we add a single whitespace character plus a comma
- // in-between two entries.
- const actualMax = maxLength + separatorSpace;
- // Check if at least three entries fit next to each other and prevent grouping
- // of arrays that contains entries of very different length (i.e., if a single
- // entry is longer than 1/5 of all other entries combined). Otherwise the
- // space in-between small entries would be enormous.
- if (
- actualMax * 3 + (level + 1) < LINE_BREAKING_LENGTH &&
- (totalLength / actualMax > 5 || maxLength <= 6)
- ) {
- const approxCharHeights = 2.5;
- const averageBias = MathSqrt(actualMax - totalLength / entries.length);
- const biasedMax = MathMax(actualMax - 3 - averageBias, 1);
- // Dynamically check how many columns seem possible.
- const columns = MathMin(
- // Ideally a square should be drawn. We expect a character to be about 2.5
- // times as high as wide. This is the area formula to calculate a square
- // which contains n rectangles of size `actualMax * approxCharHeights`.
- // Divide that by `actualMax` to receive the correct number of columns.
- // The added bias increases the columns for short entries.
- MathRound(
- MathSqrt(approxCharHeights * biasedMax * entriesLength) / biasedMax,
- ),
- // Do not exceed the breakLength.
- MathFloor((LINE_BREAKING_LENGTH - (level + 1)) / actualMax),
- // Limit the columns to a maximum of fifteen.
- 15,
- );
- // Return with the original output if no grouping should happen.
- if (columns <= 1) {
- return entries;
- }
- const tmp = [];
- const maxLineLength = [];
- for (let i = 0; i < columns; i++) {
- let lineMaxLength = 0;
- for (let j = i; j < entries.length; j += columns) {
- if (dataLen[j] > lineMaxLength) lineMaxLength = dataLen[j];
- }
- lineMaxLength += separatorSpace;
- maxLineLength[i] = lineMaxLength;
+ const approxCharHeights = 2.5;
+ const averageBias = MathSqrt(actualMax - totalLength / entries.length);
+ const biasedMax = MathMax(actualMax - 3 - averageBias, 1);
+ // Dynamically check how many columns seem possible.
+ const columns = MathMin(
+ // Ideally a square should be drawn. We expect a character to be about 2.5
+ // times as high as wide. This is the area formula to calculate a square
+ // which contains n rectangles of size `actualMax * approxCharHeights`.
+ // Divide that by `actualMax` to receive the correct number of columns.
+ // The added bias increases the columns for short entries.
+ MathRound(
+ MathSqrt(approxCharHeights * biasedMax * entriesLength) / biasedMax,
+ ),
+ // Do not exceed the breakLength.
+ MathFloor((LINE_BREAKING_LENGTH - (level + 1)) / actualMax),
+ // Limit the columns to a maximum of fifteen.
+ 15,
+ );
+ // Return with the original output if no grouping should happen.
+ if (columns <= 1) {
+ return entries;
+ }
+ const tmp = [];
+ const maxLineLength = [];
+ for (let i = 0; i < columns; i++) {
+ let lineMaxLength = 0;
+ for (let j = i; j < entries.length; j += columns) {
+ if (dataLen[j] > lineMaxLength) lineMaxLength = dataLen[j];
}
- let order = "padStart";
- if (value !== undefined) {
- for (let i = 0; i < entries.length; i++) {
- if (
- typeof value[i] !== "number" &&
- typeof value[i] !== "bigint"
- ) {
- order = "padEnd";
- break;
- }
+ lineMaxLength += separatorSpace;
+ maxLineLength[i] = lineMaxLength;
+ }
+ let order = "padStart";
+ if (value !== undefined) {
+ for (let i = 0; i < entries.length; i++) {
+ if (
+ typeof value[i] !== "number" &&
+ typeof value[i] !== "bigint"
+ ) {
+ order = "padEnd";
+ break;
}
}
- // Each iteration creates a single line of grouped entries.
- for (let i = 0; i < entriesLength; i += columns) {
- // The last lines may contain less entries than columns.
- const max = MathMin(i + columns, entriesLength);
- let str = "";
- let j = i;
- for (; j < max - 1; j++) {
- const lengthOfColorCodes = entries[j].length - dataLen[j];
- const padding = maxLineLength[j - i] + lengthOfColorCodes;
- str += `${entries[j]}, `[order](padding, " ");
- }
- if (order === "padStart") {
- const lengthOfColorCodes = entries[j].length - dataLen[j];
- const padding = maxLineLength[j - i] +
- lengthOfColorCodes -
- separatorSpace;
- str += StringPrototypePadStart(entries[j], padding, " ");
- } else {
- str += entries[j];
- }
- ArrayPrototypePush(tmp, str);
+ }
+ // Each iteration creates a single line of grouped entries.
+ for (let i = 0; i < entriesLength; i += columns) {
+ // The last lines may contain less entries than columns.
+ const max = MathMin(i + columns, entriesLength);
+ let str = "";
+ let j = i;
+ for (; j < max - 1; j++) {
+ const lengthOfColorCodes = entries[j].length - dataLen[j];
+ const padding = maxLineLength[j - i] + lengthOfColorCodes;
+ str += `${entries[j]}, `[order](padding, " ");
}
- if (iterableLimit < entries.length) {
- ArrayPrototypePush(tmp, entries[entriesLength]);
+ if (order === "padStart") {
+ const lengthOfColorCodes = entries[j].length - dataLen[j];
+ const padding = maxLineLength[j - i] +
+ lengthOfColorCodes -
+ separatorSpace;
+ str += StringPrototypePadStart(entries[j], padding, " ");
+ } else {
+ str += entries[j];
}
- entries = tmp;
+ ArrayPrototypePush(tmp, str);
+ }
+ if (iterableLimit < entries.length) {
+ ArrayPrototypePush(tmp, entries[entriesLength]);
}
- return entries;
+ entries = tmp;
}
-
- let circular;
- function handleCircular(value, cyan) {
- let index = 1;
- if (circular === undefined) {
- circular = new Map();
+ return entries;
+}
+
+let circular;
+function handleCircular(value, cyan) {
+ let index = 1;
+ if (circular === undefined) {
+ circular = new Map();
+ MapPrototypeSet(circular, value, index);
+ } else {
+ index = MapPrototypeGet(circular, value);
+ if (index === undefined) {
+ index = circular.size + 1;
MapPrototypeSet(circular, value, index);
- } else {
- index = MapPrototypeGet(circular, value);
- if (index === undefined) {
- index = circular.size + 1;
- MapPrototypeSet(circular, value, index);
- }
}
- // Circular string is cyan
- return cyan(`[Circular *${index}]`);
+ }
+ // Circular string is cyan
+ return cyan(`[Circular *${index}]`);
+}
+
+function _inspectValue(
+ value,
+ inspectOptions,
+) {
+ const proxyDetails = core.getProxyDetails(value);
+ if (proxyDetails != null && inspectOptions.showProxy) {
+ return inspectProxy(proxyDetails, inspectOptions);
}
- function _inspectValue(
- value,
- inspectOptions,
- ) {
- const proxyDetails = core.getProxyDetails(value);
- if (proxyDetails != null && inspectOptions.showProxy) {
- return inspectProxy(proxyDetails, inspectOptions);
- }
-
- const green = maybeColor(colors.green, inspectOptions);
- const yellow = maybeColor(colors.yellow, inspectOptions);
- const gray = maybeColor(colors.gray, inspectOptions);
- const cyan = maybeColor(colors.cyan, inspectOptions);
- const bold = maybeColor(colors.bold, inspectOptions);
- const red = maybeColor(colors.red, inspectOptions);
-
- switch (typeof value) {
- case "string":
- return green(quoteString(value));
- case "number": // Numbers are yellow
- // Special handling of -0
- return yellow(ObjectIs(value, -0) ? "-0" : `${value}`);
- case "boolean": // booleans are yellow
- return yellow(String(value));
- case "undefined": // undefined is gray
- return gray(String(value));
- case "symbol": // Symbols are green
- return green(maybeQuoteSymbol(value));
- case "bigint": // Bigints are yellow
- return yellow(`${value}n`);
- case "function": // Function string is cyan
- if (ctxHas(value)) {
- // Circular string is cyan
- return handleCircular(value, cyan);
- }
+ const green = maybeColor(colors.green, inspectOptions);
+ const yellow = maybeColor(colors.yellow, inspectOptions);
+ const gray = maybeColor(colors.gray, inspectOptions);
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ const bold = maybeColor(colors.bold, inspectOptions);
+ const red = maybeColor(colors.red, inspectOptions);
+
+ switch (typeof value) {
+ case "string":
+ return green(quoteString(value));
+ case "number": // Numbers are yellow
+ // Special handling of -0
+ return yellow(ObjectIs(value, -0) ? "-0" : `${value}`);
+ case "boolean": // booleans are yellow
+ return yellow(String(value));
+ case "undefined": // undefined is gray
+ return gray(String(value));
+ case "symbol": // Symbols are green
+ return green(maybeQuoteSymbol(value));
+ case "bigint": // Bigints are yellow
+ return yellow(`${value}n`);
+ case "function": // Function string is cyan
+ if (ctxHas(value)) {
+ // Circular string is cyan
+ return handleCircular(value, cyan);
+ }
- return inspectFunction(value, inspectOptions);
- case "object": // null is bold
- if (value === null) {
- return bold("null");
- }
+ return inspectFunction(value, inspectOptions);
+ case "object": // null is bold
+ if (value === null) {
+ return bold("null");
+ }
- if (ctxHas(value)) {
- return handleCircular(value, cyan);
- }
+ if (ctxHas(value)) {
+ return handleCircular(value, cyan);
+ }
- return inspectObject(
- value,
- inspectOptions,
- proxyDetails,
- );
- default:
- // Not implemented is red
- return red("[Not Implemented]");
- }
+ return inspectObject(
+ value,
+ inspectOptions,
+ proxyDetails,
+ );
+ default:
+ // Not implemented is red
+ return red("[Not Implemented]");
}
-
- function inspectValue(
- value,
- inspectOptions,
- ) {
- ArrayPrototypePush(CTX_STACK, value);
- let x;
- try {
- x = _inspectValue(value, inspectOptions);
- } finally {
- ArrayPrototypePop(CTX_STACK);
- }
- return x;
- }
-
- // We can match Node's quoting behavior exactly by swapping the double quote and
- // single quote in this array. That would give preference to single quotes.
- // However, we prefer double quotes as the default.
- const QUOTES = ['"', "'", "`"];
-
- /** Surround the string in quotes.
- *
- * The quote symbol is chosen by taking the first of the `QUOTES` array which
- * does not occur in the string. If they all occur, settle with `QUOTES[0]`.
- *
- * Insert a backslash before any occurrence of the chosen quote symbol and
- * before any backslash.
- */
- function quoteString(string) {
- const quote =
- ArrayPrototypeFind(QUOTES, (c) => !StringPrototypeIncludes(string, c)) ??
- QUOTES[0];
- const escapePattern = new RegExp(`(?=[${quote}\\\\])`, "g");
- string = StringPrototypeReplace(string, escapePattern, "\\");
- string = replaceEscapeSequences(string);
- return `${quote}${string}${quote}`;
- }
-
- // Replace escape sequences that can modify output.
- function replaceEscapeSequences(string) {
- const escapeMap = {
- "\b": "\\b",
- "\f": "\\f",
- "\n": "\\n",
- "\r": "\\r",
- "\t": "\\t",
- "\v": "\\v",
- };
-
- return StringPrototypeReplace(
- StringPrototypeReplace(
- string,
- /([\b\f\n\r\t\v])/g,
- (c) => escapeMap[c],
- ),
- // deno-lint-ignore no-control-regex
- /[\x00-\x1f\x7f-\x9f]/g,
- (c) =>
- "\\x" +
- StringPrototypePadStart(
- NumberPrototypeToString(StringPrototypeCharCodeAt(c, 0), 16),
- 2,
- "0",
- ),
- );
+}
+
+function inspectValue(
+ value,
+ inspectOptions,
+) {
+ ArrayPrototypePush(CTX_STACK, value);
+ let x;
+ try {
+ x = _inspectValue(value, inspectOptions);
+ } finally {
+ ArrayPrototypePop(CTX_STACK);
}
+ return x;
+}
+
+// We can match Node's quoting behavior exactly by swapping the double quote and
+// single quote in this array. That would give preference to single quotes.
+// However, we prefer double quotes as the default.
+const QUOTES = ['"', "'", "`"];
+
+/** Surround the string in quotes.
+ *
+ * The quote symbol is chosen by taking the first of the `QUOTES` array which
+ * does not occur in the string. If they all occur, settle with `QUOTES[0]`.
+ *
+ * Insert a backslash before any occurrence of the chosen quote symbol and
+ * before any backslash.
+ */
+function quoteString(string) {
+ const quote =
+ ArrayPrototypeFind(QUOTES, (c) => !StringPrototypeIncludes(string, c)) ??
+ QUOTES[0];
+ const escapePattern = new RegExp(`(?=[${quote}\\\\])`, "g");
+ string = StringPrototypeReplace(string, escapePattern, "\\");
+ string = replaceEscapeSequences(string);
+ return `${quote}${string}${quote}`;
+}
+
+// Replace escape sequences that can modify output.
+function replaceEscapeSequences(string) {
+ const escapeMap = {
+ "\b": "\\b",
+ "\f": "\\f",
+ "\n": "\\n",
+ "\r": "\\r",
+ "\t": "\\t",
+ "\v": "\\v",
+ };
- // Surround a string with quotes when it is required (e.g the string not a valid identifier).
- function maybeQuoteString(string) {
- if (RegExpPrototypeTest(/^[a-zA-Z_][a-zA-Z_0-9]*$/, string)) {
- return replaceEscapeSequences(string);
- }
+ return StringPrototypeReplace(
+ StringPrototypeReplace(
+ string,
+ /([\b\f\n\r\t\v])/g,
+ (c) => escapeMap[c],
+ ),
+ // deno-lint-ignore no-control-regex
+ /[\x00-\x1f\x7f-\x9f]/g,
+ (c) =>
+ "\\x" +
+ StringPrototypePadStart(
+ NumberPrototypeToString(StringPrototypeCharCodeAt(c, 0), 16),
+ 2,
+ "0",
+ ),
+ );
+}
- return quoteString(string);
+// Surround a string with quotes when it is required (e.g the string not a valid identifier).
+function maybeQuoteString(string) {
+ if (RegExpPrototypeTest(/^[a-zA-Z_][a-zA-Z_0-9]*$/, string)) {
+ return replaceEscapeSequences(string);
}
- // Surround a symbol's description in quotes when it is required (e.g the description has non printable characters).
- function maybeQuoteSymbol(symbol) {
- if (symbol.description === undefined) {
- return SymbolPrototypeToString(symbol);
- }
-
- if (RegExpPrototypeTest(/^[a-zA-Z_][a-zA-Z_.0-9]*$/, symbol.description)) {
- return SymbolPrototypeToString(symbol);
- }
+ return quoteString(string);
+}
- return `Symbol(${quoteString(symbol.description)})`;
+// Surround a symbol's description in quotes when it is required (e.g the description has non printable characters).
+function maybeQuoteSymbol(symbol) {
+ if (symbol.description === undefined) {
+ return SymbolPrototypeToString(symbol);
}
- const CTX_STACK = [];
- function ctxHas(x) {
- // Only check parent contexts
- return ArrayPrototypeIncludes(
- ArrayPrototypeSlice(CTX_STACK, 0, CTX_STACK.length - 1),
- x,
- );
+ if (RegExpPrototypeTest(/^[a-zA-Z_][a-zA-Z_.0-9]*$/, symbol.description)) {
+ return SymbolPrototypeToString(symbol);
}
- // Print strings when they are inside of arrays or objects with quotes
- function inspectValueWithQuotes(
- value,
- inspectOptions,
- ) {
- const abbreviateSize =
- typeof inspectOptions.strAbbreviateSize === "undefined"
- ? STR_ABBREVIATE_SIZE
- : inspectOptions.strAbbreviateSize;
- const green = maybeColor(colors.green, inspectOptions);
- switch (typeof value) {
- case "string": {
- const trunc = value.length > abbreviateSize
- ? StringPrototypeSlice(value, 0, abbreviateSize) + "..."
- : value;
- return green(quoteString(trunc)); // Quoted strings are green
- }
- default:
- return inspectValue(value, inspectOptions);
- }
+ return `Symbol(${quoteString(symbol.description)})`;
+}
+
+const CTX_STACK = [];
+function ctxHas(x) {
+ // Only check parent contexts
+ return ArrayPrototypeIncludes(
+ ArrayPrototypeSlice(CTX_STACK, 0, CTX_STACK.length - 1),
+ x,
+ );
+}
+
+// Print strings when they are inside of arrays or objects with quotes
+function inspectValueWithQuotes(
+ value,
+ inspectOptions,
+) {
+ const abbreviateSize = typeof inspectOptions.strAbbreviateSize === "undefined"
+ ? STR_ABBREVIATE_SIZE
+ : inspectOptions.strAbbreviateSize;
+ const green = maybeColor(colors.green, inspectOptions);
+ switch (typeof value) {
+ case "string": {
+ const trunc = value.length > abbreviateSize
+ ? StringPrototypeSlice(value, 0, abbreviateSize) + "..."
+ : value;
+ return green(quoteString(trunc)); // Quoted strings are green
+ }
+ default:
+ return inspectValue(value, inspectOptions);
}
-
- function inspectArray(
- value,
- inspectOptions,
- ) {
- const gray = maybeColor(colors.gray, inspectOptions);
- let lastValidIndex = 0;
- let keys;
- const options = {
- typeName: "Array",
- displayName: "",
- delims: ["[", "]"],
- entryHandler: (entry, inspectOptions) => {
- const { 0: index, 1: val } = entry;
- let i = index;
- lastValidIndex = index;
- if (!ObjectPrototypeHasOwnProperty(value, i)) {
- let skipTo;
- keys = keys || ObjectKeys(value);
- i = value.length;
- if (keys.length === 0) {
- // fast path, all items are empty
- skipTo = i;
- } else {
- // Not all indexes are empty or there's a non-index property
- // Find first non-empty array index
- while (keys.length) {
- const key = ArrayPrototypeShift(keys);
- // check if it's a valid array index
- if (key > lastValidIndex && key < 2 ** 32 - 1) {
- i = Number(key);
- break;
- }
+}
+
+function inspectArray(
+ value,
+ inspectOptions,
+) {
+ const gray = maybeColor(colors.gray, inspectOptions);
+ let lastValidIndex = 0;
+ let keys;
+ const options = {
+ typeName: "Array",
+ displayName: "",
+ delims: ["[", "]"],
+ entryHandler: (entry, inspectOptions) => {
+ const { 0: index, 1: val } = entry;
+ let i = index;
+ lastValidIndex = index;
+ if (!ObjectPrototypeHasOwnProperty(value, i)) {
+ let skipTo;
+ keys = keys || ObjectKeys(value);
+ i = value.length;
+ if (keys.length === 0) {
+ // fast path, all items are empty
+ skipTo = i;
+ } else {
+ // Not all indexes are empty or there's a non-index property
+ // Find first non-empty array index
+ while (keys.length) {
+ const key = ArrayPrototypeShift(keys);
+ // check if it's a valid array index
+ if (key > lastValidIndex && key < 2 ** 32 - 1) {
+ i = Number(key);
+ break;
}
-
- skipTo = i - 1;
}
- const emptyItems = i - index;
- const ending = emptyItems > 1 ? "s" : "";
- return {
- entry: gray(`<${emptyItems} empty item${ending}>`),
- skipTo,
- };
- } else {
- return { entry: inspectValueWithQuotes(val, inspectOptions) };
- }
- },
- group: inspectOptions.compact,
- sort: false,
- };
- return inspectIterable(value, options, inspectOptions);
- }
- function inspectTypedArray(
- typedArrayName,
- value,
- inspectOptions,
- ) {
- const valueLength = value.length;
- const options = {
- typeName: typedArrayName,
- displayName: `${typedArrayName}(${valueLength})`,
- delims: ["[", "]"],
- entryHandler: (entry, inspectOptions) => {
- const val = entry[1];
- inspectOptions.indentLevel++;
- const inspectedValue = inspectValueWithQuotes(val, inspectOptions);
- inspectOptions.indentLevel--;
- return inspectedValue;
- },
- group: inspectOptions.compact,
- sort: false,
- };
- return inspectIterable(value, options, inspectOptions);
- }
-
- function inspectSet(
- value,
- inspectOptions,
- ) {
- const options = {
- typeName: "Set",
- displayName: "Set",
- delims: ["{", "}"],
- entryHandler: (entry, inspectOptions) => {
- const val = entry[1];
- inspectOptions.indentLevel++;
- const inspectedValue = inspectValueWithQuotes(val, inspectOptions);
- inspectOptions.indentLevel--;
- return inspectedValue;
- },
- group: false,
- sort: inspectOptions.sorted,
- };
- return inspectIterable(value, options, inspectOptions);
- }
-
- function inspectMap(
+ skipTo = i - 1;
+ }
+ const emptyItems = i - index;
+ const ending = emptyItems > 1 ? "s" : "";
+ return {
+ entry: gray(`<${emptyItems} empty item${ending}>`),
+ skipTo,
+ };
+ } else {
+ return { entry: inspectValueWithQuotes(val, inspectOptions) };
+ }
+ },
+ group: inspectOptions.compact,
+ sort: false,
+ };
+ return inspectIterable(value, options, inspectOptions);
+}
+
+function inspectTypedArray(
+ typedArrayName,
+ value,
+ inspectOptions,
+) {
+ const valueLength = value.length;
+ const options = {
+ typeName: typedArrayName,
+ displayName: `${typedArrayName}(${valueLength})`,
+ delims: ["[", "]"],
+ entryHandler: (entry, inspectOptions) => {
+ const val = entry[1];
+ inspectOptions.indentLevel++;
+ const inspectedValue = inspectValueWithQuotes(val, inspectOptions);
+ inspectOptions.indentLevel--;
+ return inspectedValue;
+ },
+ group: inspectOptions.compact,
+ sort: false,
+ };
+ return inspectIterable(value, options, inspectOptions);
+}
+
+function inspectSet(
+ value,
+ inspectOptions,
+) {
+ const options = {
+ typeName: "Set",
+ displayName: "Set",
+ delims: ["{", "}"],
+ entryHandler: (entry, inspectOptions) => {
+ const val = entry[1];
+ inspectOptions.indentLevel++;
+ const inspectedValue = inspectValueWithQuotes(val, inspectOptions);
+ inspectOptions.indentLevel--;
+ return inspectedValue;
+ },
+ group: false,
+ sort: inspectOptions.sorted,
+ };
+ return inspectIterable(value, options, inspectOptions);
+}
+
+function inspectMap(
+ value,
+ inspectOptions,
+) {
+ const options = {
+ typeName: "Map",
+ displayName: "Map",
+ delims: ["{", "}"],
+ entryHandler: (entry, inspectOptions) => {
+ const { 0: key, 1: val } = entry;
+ inspectOptions.indentLevel++;
+ const inspectedValue = `${
+ inspectValueWithQuotes(key, inspectOptions)
+ } => ${inspectValueWithQuotes(val, inspectOptions)}`;
+ inspectOptions.indentLevel--;
+ return inspectedValue;
+ },
+ group: false,
+ sort: inspectOptions.sorted,
+ };
+ return inspectIterable(
value,
+ options,
inspectOptions,
- ) {
- const options = {
- typeName: "Map",
- displayName: "Map",
- delims: ["{", "}"],
- entryHandler: (entry, inspectOptions) => {
- const { 0: key, 1: val } = entry;
- inspectOptions.indentLevel++;
- const inspectedValue = `${
- inspectValueWithQuotes(key, inspectOptions)
- } => ${inspectValueWithQuotes(val, inspectOptions)}`;
- inspectOptions.indentLevel--;
- return inspectedValue;
- },
- group: false,
- sort: inspectOptions.sorted,
- };
- return inspectIterable(
- value,
- options,
- inspectOptions,
- );
- }
-
- function inspectWeakSet(inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return `WeakSet { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color
- }
-
- function inspectWeakMap(inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return `WeakMap { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color
- }
-
- function inspectDate(value, inspectOptions) {
- // without quotes, ISO format, in magenta like before
- const magenta = maybeColor(colors.magenta, inspectOptions);
- return magenta(
- isInvalidDate(value) ? "Invalid Date" : DatePrototypeToISOString(value),
- );
+ );
+}
+
+function inspectWeakSet(inspectOptions) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ return `WeakSet { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color
+}
+
+function inspectWeakMap(inspectOptions) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ return `WeakMap { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color
+}
+
+function inspectDate(value, inspectOptions) {
+ // without quotes, ISO format, in magenta like before
+ const magenta = maybeColor(colors.magenta, inspectOptions);
+ return magenta(
+ isInvalidDate(value) ? "Invalid Date" : DatePrototypeToISOString(value),
+ );
+}
+
+function inspectRegExp(value, inspectOptions) {
+ const red = maybeColor(colors.red, inspectOptions);
+ return red(RegExpPrototypeToString(value)); // RegExps are red
+}
+
+function inspectError(value, cyan) {
+ const causes = [value];
+
+ let err = value;
+ while (err.cause) {
+ if (ArrayPrototypeIncludes(causes, err.cause)) {
+ ArrayPrototypePush(causes, handleCircular(err.cause, cyan));
+ break;
+ } else {
+ ArrayPrototypePush(causes, err.cause);
+ err = err.cause;
+ }
}
- function inspectRegExp(value, inspectOptions) {
- const red = maybeColor(colors.red, inspectOptions);
- return red(RegExpPrototypeToString(value)); // RegExps are red
+ const refMap = new Map();
+ for (let i = 0; i < causes.length; ++i) {
+ const cause = causes[i];
+ if (circular !== undefined) {
+ const index = MapPrototypeGet(circular, cause);
+ if (index !== undefined) {
+ MapPrototypeSet(refMap, cause, cyan(`<ref *${index}> `));
+ }
+ }
}
+ ArrayPrototypeShift(causes);
- function inspectError(value, cyan) {
- const causes = [value];
+ let finalMessage = MapPrototypeGet(refMap, value) ?? "";
- let err = value;
- while (err.cause) {
- if (ArrayPrototypeIncludes(causes, err.cause)) {
- ArrayPrototypePush(causes, handleCircular(err.cause, cyan));
+ if (ObjectPrototypeIsPrototypeOf(AggregateErrorPrototype, value)) {
+ const stackLines = StringPrototypeSplit(value.stack, "\n");
+ while (true) {
+ const line = ArrayPrototypeShift(stackLines);
+ if (RegExpPrototypeTest(/\s+at/, line)) {
+ ArrayPrototypeUnshift(stackLines, line);
+ break;
+ } else if (typeof line === "undefined") {
break;
- } else {
- ArrayPrototypePush(causes, err.cause);
- err = err.cause;
- }
- }
-
- const refMap = new Map();
- for (let i = 0; i < causes.length; ++i) {
- const cause = causes[i];
- if (circular !== undefined) {
- const index = MapPrototypeGet(circular, cause);
- if (index !== undefined) {
- MapPrototypeSet(refMap, cause, cyan(`<ref *${index}> `));
- }
}
- }
- ArrayPrototypeShift(causes);
-
- let finalMessage = MapPrototypeGet(refMap, value) ?? "";
-
- if (ObjectPrototypeIsPrototypeOf(AggregateErrorPrototype, value)) {
- const stackLines = StringPrototypeSplit(value.stack, "\n");
- while (true) {
- const line = ArrayPrototypeShift(stackLines);
- if (RegExpPrototypeTest(/\s+at/, line)) {
- ArrayPrototypeUnshift(stackLines, line);
- break;
- } else if (typeof line === "undefined") {
- break;
- }
- finalMessage += line;
- finalMessage += "\n";
- }
- const aggregateMessage = ArrayPrototypeJoin(
- ArrayPrototypeMap(
- value.errors,
- (error) =>
- StringPrototypeReplace(
- inspectArgs([error]),
- /^(?!\s*$)/gm,
- StringPrototypeRepeat(" ", 4),
- ),
- ),
- "\n",
- );
- finalMessage += aggregateMessage;
+ finalMessage += line;
finalMessage += "\n";
- finalMessage += ArrayPrototypeJoin(stackLines, "\n");
- } else {
- finalMessage += value.stack;
}
-
- finalMessage += ArrayPrototypeJoin(
+ const aggregateMessage = ArrayPrototypeJoin(
ArrayPrototypeMap(
- causes,
- (cause) =>
- "\nCaused by " + (MapPrototypeGet(refMap, cause) ?? "") +
- (cause?.stack ?? cause),
+ value.errors,
+ (error) =>
+ StringPrototypeReplace(
+ inspectArgs([error]),
+ /^(?!\s*$)/gm,
+ StringPrototypeRepeat(" ", 4),
+ ),
),
- "",
+ "\n",
);
-
- return finalMessage;
+ finalMessage += aggregateMessage;
+ finalMessage += "\n";
+ finalMessage += ArrayPrototypeJoin(stackLines, "\n");
+ } else {
+ finalMessage += value.stack;
}
- function inspectStringObject(value, inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return cyan(`[String: "${StringPrototypeToString(value)}"]`); // wrappers are in cyan
+ finalMessage += ArrayPrototypeJoin(
+ ArrayPrototypeMap(
+ causes,
+ (cause) =>
+ "\nCaused by " + (MapPrototypeGet(refMap, cause) ?? "") +
+ (cause?.stack ?? cause),
+ ),
+ "",
+ );
+
+ return finalMessage;
+}
+
+function inspectStringObject(value, inspectOptions) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ return cyan(`[String: "${StringPrototypeToString(value)}"]`); // wrappers are in cyan
+}
+
+function inspectBooleanObject(value, inspectOptions) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ return cyan(`[Boolean: ${BooleanPrototypeToString(value)}]`); // wrappers are in cyan
+}
+
+function inspectNumberObject(value, inspectOptions) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ // Special handling of -0
+ return cyan(
+ `[Number: ${
+ ObjectIs(NumberPrototypeValueOf(value), -0)
+ ? "-0"
+ : NumberPrototypeToString(value)
+ }]`,
+ ); // wrappers are in cyan
+}
+
+function inspectBigIntObject(value, inspectOptions) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ return cyan(`[BigInt: ${BigIntPrototypeToString(value)}n]`); // wrappers are in cyan
+}
+
+function inspectSymbolObject(value, inspectOptions) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ return cyan(`[Symbol: ${maybeQuoteSymbol(SymbolPrototypeValueOf(value))}]`); // wrappers are in cyan
+}
+
+const PromiseState = {
+ Pending: 0,
+ Fulfilled: 1,
+ Rejected: 2,
+};
+
+function inspectPromise(
+ value,
+ inspectOptions,
+) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
+ const red = maybeColor(colors.red, inspectOptions);
+
+ const { 0: state, 1: result } = core.getPromiseDetails(value);
+
+ if (state === PromiseState.Pending) {
+ return `Promise { ${cyan("<pending>")} }`;
}
- function inspectBooleanObject(value, inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return cyan(`[Boolean: ${BooleanPrototypeToString(value)}]`); // wrappers are in cyan
- }
+ const prefix = state === PromiseState.Fulfilled
+ ? ""
+ : `${red("<rejected>")} `;
- function inspectNumberObject(value, inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- // Special handling of -0
- return cyan(
- `[Number: ${
- ObjectIs(NumberPrototypeValueOf(value), -0)
- ? "-0"
- : NumberPrototypeToString(value)
- }]`,
- ); // wrappers are in cyan
- }
+ inspectOptions.indentLevel++;
+ const str = `${prefix}${inspectValueWithQuotes(result, inspectOptions)}`;
+ inspectOptions.indentLevel--;
- function inspectBigIntObject(value, inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return cyan(`[BigInt: ${BigIntPrototypeToString(value)}n]`); // wrappers are in cyan
+ if (str.length + PROMISE_STRING_BASE_LENGTH > LINE_BREAKING_LENGTH) {
+ return `Promise {\n${
+ StringPrototypeRepeat(DEFAULT_INDENT, inspectOptions.indentLevel + 1)
+ }${str}\n}`;
}
- function inspectSymbolObject(value, inspectOptions) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- return cyan(`[Symbol: ${maybeQuoteSymbol(SymbolPrototypeValueOf(value))}]`); // wrappers are in cyan
- }
+ return `Promise { ${str} }`;
+}
- const PromiseState = {
- Pending: 0,
- Fulfilled: 1,
- Rejected: 2,
- };
-
- function inspectPromise(
- value,
- inspectOptions,
- ) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
- const red = maybeColor(colors.red, inspectOptions);
+function inspectProxy(
+ targetAndHandler,
+ inspectOptions,
+) {
+ return `Proxy ${inspectArray(targetAndHandler, inspectOptions)}`;
+}
- const { 0: state, 1: result } = core.getPromiseDetails(value);
-
- if (state === PromiseState.Pending) {
- return `Promise { ${cyan("<pending>")} }`;
- }
-
- const prefix = state === PromiseState.Fulfilled
- ? ""
- : `${red("<rejected>")} `;
+function inspectRawObject(
+ value,
+ inspectOptions,
+) {
+ const cyan = maybeColor(colors.cyan, inspectOptions);
- inspectOptions.indentLevel++;
- const str = `${prefix}${inspectValueWithQuotes(result, inspectOptions)}`;
- inspectOptions.indentLevel--;
+ if (inspectOptions.indentLevel >= inspectOptions.depth) {
+ return [cyan("[Object]"), ""]; // wrappers are in cyan
+ }
- if (str.length + PROMISE_STRING_BASE_LENGTH > LINE_BREAKING_LENGTH) {
- return `Promise {\n${
- StringPrototypeRepeat(DEFAULT_INDENT, inspectOptions.indentLevel + 1)
- }${str}\n}`;
- }
+ let baseString;
- return `Promise { ${str} }`;
+ let shouldShowDisplayName = false;
+ let displayName = value[
+ SymbolToStringTag
+ ];
+ if (!displayName) {
+ displayName = getClassInstanceName(value);
}
-
- function inspectProxy(
- targetAndHandler,
- inspectOptions,
+ if (
+ displayName && displayName !== "Object" && displayName !== "anonymous"
) {
- return `Proxy ${inspectArray(targetAndHandler, inspectOptions)}`;
+ shouldShowDisplayName = true;
}
- function inspectRawObject(
- value,
- inspectOptions,
- ) {
- const cyan = maybeColor(colors.cyan, inspectOptions);
-
- if (inspectOptions.indentLevel >= inspectOptions.depth) {
- return [cyan("[Object]"), ""]; // wrappers are in cyan
- }
+ const entries = [];
+ const stringKeys = ObjectKeys(value);
+ const symbolKeys = ObjectGetOwnPropertySymbols(value);
+ if (inspectOptions.sorted) {
+ ArrayPrototypeSort(stringKeys);
+ ArrayPrototypeSort(
+ symbolKeys,
+ (s1, s2) =>
+ StringPrototypeLocaleCompare(
+ s1.description ?? "",
+ s2.description ?? "",
+ ),
+ );
+ }
- let baseString;
+ const red = maybeColor(colors.red, inspectOptions);
- let shouldShowDisplayName = false;
- let displayName = value[
- SymbolToStringTag
- ];
- if (!displayName) {
- displayName = getClassInstanceName(value);
- }
- if (
- displayName && displayName !== "Object" && displayName !== "anonymous"
- ) {
- shouldShowDisplayName = true;
- }
+ inspectOptions.indentLevel++;
- const entries = [];
- const stringKeys = ObjectKeys(value);
- const symbolKeys = ObjectGetOwnPropertySymbols(value);
- if (inspectOptions.sorted) {
- ArrayPrototypeSort(stringKeys);
- ArrayPrototypeSort(
- symbolKeys,
- (s1, s2) =>
- StringPrototypeLocaleCompare(
- s1.description ?? "",
- s2.description ?? "",
- ),
+ for (let i = 0; i < stringKeys.length; ++i) {
+ const key = stringKeys[i];
+ if (inspectOptions.getters) {
+ let propertyValue;
+ let error = null;
+ try {
+ propertyValue = value[key];
+ } catch (error_) {
+ error = error_;
+ }
+ const inspectedValue = error == null
+ ? inspectValueWithQuotes(propertyValue, inspectOptions)
+ : red(`[Thrown ${error.name}: ${error.message}]`);
+ ArrayPrototypePush(
+ entries,
+ `${maybeQuoteString(key)}: ${inspectedValue}`,
);
- }
-
- const red = maybeColor(colors.red, inspectOptions);
-
- inspectOptions.indentLevel++;
-
- for (let i = 0; i < stringKeys.length; ++i) {
- const key = stringKeys[i];
- if (inspectOptions.getters) {
- let propertyValue;
- let error = null;
- try {
- propertyValue = value[key];
- } catch (error_) {
- error = error_;
- }
- const inspectedValue = error == null
- ? inspectValueWithQuotes(propertyValue, inspectOptions)
- : red(`[Thrown ${error.name}: ${error.message}]`);
+ } else {
+ const descriptor = ObjectGetOwnPropertyDescriptor(value, key);
+ if (descriptor.get !== undefined && descriptor.set !== undefined) {
ArrayPrototypePush(
entries,
- `${maybeQuoteString(key)}: ${inspectedValue}`,
+ `${maybeQuoteString(key)}: [Getter/Setter]`,
);
+ } else if (descriptor.get !== undefined) {
+ ArrayPrototypePush(entries, `${maybeQuoteString(key)}: [Getter]`);
} else {
- const descriptor = ObjectGetOwnPropertyDescriptor(value, key);
- if (descriptor.get !== undefined && descriptor.set !== undefined) {
- ArrayPrototypePush(
- entries,
- `${maybeQuoteString(key)}: [Getter/Setter]`,
- );
- } else if (descriptor.get !== undefined) {
- ArrayPrototypePush(entries, `${maybeQuoteString(key)}: [Getter]`);
- } else {
- ArrayPrototypePush(
- entries,
- `${maybeQuoteString(key)}: ${
- inspectValueWithQuotes(value[key], inspectOptions)
- }`,
- );
- }
+ ArrayPrototypePush(
+ entries,
+ `${maybeQuoteString(key)}: ${
+ inspectValueWithQuotes(value[key], inspectOptions)
+ }`,
+ );
}
}
+ }
- for (let i = 0; i < symbolKeys.length; ++i) {
- const key = symbolKeys[i];
- if (
- !inspectOptions.showHidden &&
- !propertyIsEnumerable(value, key)
- ) {
- continue;
- }
+ for (let i = 0; i < symbolKeys.length; ++i) {
+ const key = symbolKeys[i];
+ if (
+ !inspectOptions.showHidden &&
+ !propertyIsEnumerable(value, key)
+ ) {
+ continue;
+ }
- if (inspectOptions.getters) {
- let propertyValue;
- let error;
- try {
- propertyValue = value[key];
- } catch (error_) {
- error = error_;
- }
- const inspectedValue = error == null
- ? inspectValueWithQuotes(propertyValue, inspectOptions)
- : red(`Thrown ${error.name}: ${error.message}`);
+ if (inspectOptions.getters) {
+ let propertyValue;
+ let error;
+ try {
+ propertyValue = value[key];
+ } catch (error_) {
+ error = error_;
+ }
+ const inspectedValue = error == null
+ ? inspectValueWithQuotes(propertyValue, inspectOptions)
+ : red(`Thrown ${error.name}: ${error.message}`);
+ ArrayPrototypePush(
+ entries,
+ `[${maybeQuoteSymbol(key)}]: ${inspectedValue}`,
+ );
+ } else {
+ const descriptor = ObjectGetOwnPropertyDescriptor(value, key);
+ if (descriptor.get !== undefined && descriptor.set !== undefined) {
ArrayPrototypePush(
entries,
- `[${maybeQuoteSymbol(key)}]: ${inspectedValue}`,
+ `[${maybeQuoteSymbol(key)}]: [Getter/Setter]`,
);
+ } else if (descriptor.get !== undefined) {
+ ArrayPrototypePush(entries, `[${maybeQuoteSymbol(key)}]: [Getter]`);
} else {
- const descriptor = ObjectGetOwnPropertyDescriptor(value, key);
- if (descriptor.get !== undefined && descriptor.set !== undefined) {
- ArrayPrototypePush(
- entries,
- `[${maybeQuoteSymbol(key)}]: [Getter/Setter]`,
- );
- } else if (descriptor.get !== undefined) {
- ArrayPrototypePush(entries, `[${maybeQuoteSymbol(key)}]: [Getter]`);
- } else {
- ArrayPrototypePush(
- entries,
- `[${maybeQuoteSymbol(key)}]: ${
- inspectValueWithQuotes(value[key], inspectOptions)
- }`,
- );
- }
+ ArrayPrototypePush(
+ entries,
+ `[${maybeQuoteSymbol(key)}]: ${
+ inspectValueWithQuotes(value[key], inspectOptions)
+ }`,
+ );
}
}
+ }
- inspectOptions.indentLevel--;
+ inspectOptions.indentLevel--;
- // Making sure color codes are ignored when calculating the total length
- const totalLength = entries.length + inspectOptions.indentLevel +
- colors.stripColor(ArrayPrototypeJoin(entries, "")).length;
+ // Making sure color codes are ignored when calculating the total length
+ const totalLength = entries.length + inspectOptions.indentLevel +
+ colors.stripColor(ArrayPrototypeJoin(entries, "")).length;
- if (entries.length === 0) {
- baseString = "{}";
- } else if (totalLength > LINE_BREAKING_LENGTH || !inspectOptions.compact) {
- const entryIndent = StringPrototypeRepeat(
- DEFAULT_INDENT,
- inspectOptions.indentLevel + 1,
- );
- const closingIndent = StringPrototypeRepeat(
- DEFAULT_INDENT,
- inspectOptions.indentLevel,
- );
- baseString = `{\n${entryIndent}${
- ArrayPrototypeJoin(entries, `,\n${entryIndent}`)
- }${inspectOptions.trailingComma ? "," : ""}\n${closingIndent}}`;
- } else {
- baseString = `{ ${ArrayPrototypeJoin(entries, ", ")} }`;
- }
+ if (entries.length === 0) {
+ baseString = "{}";
+ } else if (totalLength > LINE_BREAKING_LENGTH || !inspectOptions.compact) {
+ const entryIndent = StringPrototypeRepeat(
+ DEFAULT_INDENT,
+ inspectOptions.indentLevel + 1,
+ );
+ const closingIndent = StringPrototypeRepeat(
+ DEFAULT_INDENT,
+ inspectOptions.indentLevel,
+ );
+ baseString = `{\n${entryIndent}${
+ ArrayPrototypeJoin(entries, `,\n${entryIndent}`)
+ }${inspectOptions.trailingComma ? "," : ""}\n${closingIndent}}`;
+ } else {
+ baseString = `{ ${ArrayPrototypeJoin(entries, ", ")} }`;
+ }
- if (shouldShowDisplayName) {
- baseString = `${displayName} ${baseString}`;
- }
+ if (shouldShowDisplayName) {
+ baseString = `${displayName} ${baseString}`;
+ }
- let refIndex = "";
- if (circular !== undefined) {
- const index = MapPrototypeGet(circular, value);
- if (index !== undefined) {
- refIndex = cyan(`<ref *${index}> `);
- }
+ let refIndex = "";
+ if (circular !== undefined) {
+ const index = MapPrototypeGet(circular, value);
+ if (index !== undefined) {
+ refIndex = cyan(`<ref *${index}> `);
}
-
- return [baseString, refIndex];
}
- function inspectObject(value, inspectOptions, proxyDetails) {
- if (
- ReflectHas(value, customInspect) &&
- typeof value[customInspect] === "function"
- ) {
- return String(value[customInspect](inspect, inspectOptions));
- }
- // This non-unique symbol is used to support op_crates, ie.
- // in extensions/web we don't want to depend on public
- // Symbol.for("Deno.customInspect") symbol defined in the public API.
- // Internal only, shouldn't be used by users.
- const privateCustomInspect = SymbolFor("Deno.privateCustomInspect");
- if (
- ReflectHas(value, privateCustomInspect) &&
- typeof value[privateCustomInspect] === "function"
- ) {
- // TODO(nayeemrmn): `inspect` is passed as an argument because custom
- // inspect implementations in `extensions` need it, but may not have access
- // to the `Deno` namespace in web workers. Remove when the `Deno`
- // namespace is always enabled.
- return String(
- value[privateCustomInspect](inspect, inspectOptions),
- );
- }
- if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, value)) {
- return inspectError(value, maybeColor(colors.cyan, inspectOptions));
- } else if (ArrayIsArray(value)) {
- return inspectArray(value, inspectOptions);
- } else if (ObjectPrototypeIsPrototypeOf(NumberPrototype, value)) {
- return inspectNumberObject(value, inspectOptions);
- } else if (ObjectPrototypeIsPrototypeOf(BigIntPrototype, value)) {
- return inspectBigIntObject(value, inspectOptions);
- } else if (ObjectPrototypeIsPrototypeOf(BooleanPrototype, value)) {
- return inspectBooleanObject(value, inspectOptions);
- } else if (ObjectPrototypeIsPrototypeOf(StringPrototype, value)) {
- return inspectStringObject(value, inspectOptions);
- } else if (ObjectPrototypeIsPrototypeOf(SymbolPrototype, value)) {
- return inspectSymbolObject(value, inspectOptions);
- } else if (ObjectPrototypeIsPrototypeOf(PromisePrototype, value)) {
- return inspectPromise(value, inspectOptions);
- } else if (ObjectPrototypeIsPrototypeOf(RegExpPrototype, value)) {
- return inspectRegExp(value, inspectOptions);
- } else if (ObjectPrototypeIsPrototypeOf(DatePrototype, value)) {
- return inspectDate(
- proxyDetails ? proxyDetails[0] : value,
- inspectOptions,
- );
- } else if (ObjectPrototypeIsPrototypeOf(SetPrototype, value)) {
- return inspectSet(
- proxyDetails ? proxyDetails[0] : value,
- inspectOptions,
- );
- } else if (ObjectPrototypeIsPrototypeOf(MapPrototype, value)) {
- return inspectMap(
- proxyDetails ? proxyDetails[0] : value,
- inspectOptions,
- );
- } else if (ObjectPrototypeIsPrototypeOf(WeakSetPrototype, value)) {
- return inspectWeakSet(inspectOptions);
- } else if (ObjectPrototypeIsPrototypeOf(WeakMapPrototype, value)) {
- return inspectWeakMap(inspectOptions);
- } else if (isTypedArray(value)) {
- return inspectTypedArray(
- ObjectGetPrototypeOf(value).constructor.name,
- value,
- inspectOptions,
- );
+ return [baseString, refIndex];
+}
+
+function inspectObject(value, inspectOptions, proxyDetails) {
+ if (
+ ReflectHas(value, customInspect) &&
+ typeof value[customInspect] === "function"
+ ) {
+ return String(value[customInspect](inspect, inspectOptions));
+ }
+ // This non-unique symbol is used to support op_crates, ie.
+ // in extensions/web we don't want to depend on public
+ // Symbol.for("Deno.customInspect") symbol defined in the public API.
+ // Internal only, shouldn't be used by users.
+ const privateCustomInspect = SymbolFor("Deno.privateCustomInspect");
+ if (
+ ReflectHas(value, privateCustomInspect) &&
+ typeof value[privateCustomInspect] === "function"
+ ) {
+ // TODO(nayeemrmn): `inspect` is passed as an argument because custom
+ // inspect implementations in `extensions` need it, but may not have access
+ // to the `Deno` namespace in web workers. Remove when the `Deno`
+ // namespace is always enabled.
+ return String(
+ value[privateCustomInspect](inspect, inspectOptions),
+ );
+ }
+ if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, value)) {
+ return inspectError(value, maybeColor(colors.cyan, inspectOptions));
+ } else if (ArrayIsArray(value)) {
+ return inspectArray(value, inspectOptions);
+ } else if (ObjectPrototypeIsPrototypeOf(NumberPrototype, value)) {
+ return inspectNumberObject(value, inspectOptions);
+ } else if (ObjectPrototypeIsPrototypeOf(BigIntPrototype, value)) {
+ return inspectBigIntObject(value, inspectOptions);
+ } else if (ObjectPrototypeIsPrototypeOf(BooleanPrototype, value)) {
+ return inspectBooleanObject(value, inspectOptions);
+ } else if (ObjectPrototypeIsPrototypeOf(StringPrototype, value)) {
+ return inspectStringObject(value, inspectOptions);
+ } else if (ObjectPrototypeIsPrototypeOf(SymbolPrototype, value)) {
+ return inspectSymbolObject(value, inspectOptions);
+ } else if (ObjectPrototypeIsPrototypeOf(PromisePrototype, value)) {
+ return inspectPromise(value, inspectOptions);
+ } else if (ObjectPrototypeIsPrototypeOf(RegExpPrototype, value)) {
+ return inspectRegExp(value, inspectOptions);
+ } else if (ObjectPrototypeIsPrototypeOf(DatePrototype, value)) {
+ return inspectDate(
+ proxyDetails ? proxyDetails[0] : value,
+ inspectOptions,
+ );
+ } else if (ObjectPrototypeIsPrototypeOf(SetPrototype, value)) {
+ return inspectSet(
+ proxyDetails ? proxyDetails[0] : value,
+ inspectOptions,
+ );
+ } else if (ObjectPrototypeIsPrototypeOf(MapPrototype, value)) {
+ return inspectMap(
+ proxyDetails ? proxyDetails[0] : value,
+ inspectOptions,
+ );
+ } else if (ObjectPrototypeIsPrototypeOf(WeakSetPrototype, value)) {
+ return inspectWeakSet(inspectOptions);
+ } else if (ObjectPrototypeIsPrototypeOf(WeakMapPrototype, value)) {
+ return inspectWeakMap(inspectOptions);
+ } else if (isTypedArray(value)) {
+ return inspectTypedArray(
+ ObjectGetPrototypeOf(value).constructor.name,
+ value,
+ inspectOptions,
+ );
+ } else {
+ // Otherwise, default object formatting
+ let { 0: insp, 1: refIndex } = inspectRawObject(value, inspectOptions);
+ insp = refIndex + insp;
+ return insp;
+ }
+}
+
+const colorKeywords = new Map([
+ ["black", "#000000"],
+ ["silver", "#c0c0c0"],
+ ["gray", "#808080"],
+ ["white", "#ffffff"],
+ ["maroon", "#800000"],
+ ["red", "#ff0000"],
+ ["purple", "#800080"],
+ ["fuchsia", "#ff00ff"],
+ ["green", "#008000"],
+ ["lime", "#00ff00"],
+ ["olive", "#808000"],
+ ["yellow", "#ffff00"],
+ ["navy", "#000080"],
+ ["blue", "#0000ff"],
+ ["teal", "#008080"],
+ ["aqua", "#00ffff"],
+ ["orange", "#ffa500"],
+ ["aliceblue", "#f0f8ff"],
+ ["antiquewhite", "#faebd7"],
+ ["aquamarine", "#7fffd4"],
+ ["azure", "#f0ffff"],
+ ["beige", "#f5f5dc"],
+ ["bisque", "#ffe4c4"],
+ ["blanchedalmond", "#ffebcd"],
+ ["blueviolet", "#8a2be2"],
+ ["brown", "#a52a2a"],
+ ["burlywood", "#deb887"],
+ ["cadetblue", "#5f9ea0"],
+ ["chartreuse", "#7fff00"],
+ ["chocolate", "#d2691e"],
+ ["coral", "#ff7f50"],
+ ["cornflowerblue", "#6495ed"],
+ ["cornsilk", "#fff8dc"],
+ ["crimson", "#dc143c"],
+ ["cyan", "#00ffff"],
+ ["darkblue", "#00008b"],
+ ["darkcyan", "#008b8b"],
+ ["darkgoldenrod", "#b8860b"],
+ ["darkgray", "#a9a9a9"],
+ ["darkgreen", "#006400"],
+ ["darkgrey", "#a9a9a9"],
+ ["darkkhaki", "#bdb76b"],
+ ["darkmagenta", "#8b008b"],
+ ["darkolivegreen", "#556b2f"],
+ ["darkorange", "#ff8c00"],
+ ["darkorchid", "#9932cc"],
+ ["darkred", "#8b0000"],
+ ["darksalmon", "#e9967a"],
+ ["darkseagreen", "#8fbc8f"],
+ ["darkslateblue", "#483d8b"],
+ ["darkslategray", "#2f4f4f"],
+ ["darkslategrey", "#2f4f4f"],
+ ["darkturquoise", "#00ced1"],
+ ["darkviolet", "#9400d3"],
+ ["deeppink", "#ff1493"],
+ ["deepskyblue", "#00bfff"],
+ ["dimgray", "#696969"],
+ ["dimgrey", "#696969"],
+ ["dodgerblue", "#1e90ff"],
+ ["firebrick", "#b22222"],
+ ["floralwhite", "#fffaf0"],
+ ["forestgreen", "#228b22"],
+ ["gainsboro", "#dcdcdc"],
+ ["ghostwhite", "#f8f8ff"],
+ ["gold", "#ffd700"],
+ ["goldenrod", "#daa520"],
+ ["greenyellow", "#adff2f"],
+ ["grey", "#808080"],
+ ["honeydew", "#f0fff0"],
+ ["hotpink", "#ff69b4"],
+ ["indianred", "#cd5c5c"],
+ ["indigo", "#4b0082"],
+ ["ivory", "#fffff0"],
+ ["khaki", "#f0e68c"],
+ ["lavender", "#e6e6fa"],
+ ["lavenderblush", "#fff0f5"],
+ ["lawngreen", "#7cfc00"],
+ ["lemonchiffon", "#fffacd"],
+ ["lightblue", "#add8e6"],
+ ["lightcoral", "#f08080"],
+ ["lightcyan", "#e0ffff"],
+ ["lightgoldenrodyellow", "#fafad2"],
+ ["lightgray", "#d3d3d3"],
+ ["lightgreen", "#90ee90"],
+ ["lightgrey", "#d3d3d3"],
+ ["lightpink", "#ffb6c1"],
+ ["lightsalmon", "#ffa07a"],
+ ["lightseagreen", "#20b2aa"],
+ ["lightskyblue", "#87cefa"],
+ ["lightslategray", "#778899"],
+ ["lightslategrey", "#778899"],
+ ["lightsteelblue", "#b0c4de"],
+ ["lightyellow", "#ffffe0"],
+ ["limegreen", "#32cd32"],
+ ["linen", "#faf0e6"],
+ ["magenta", "#ff00ff"],
+ ["mediumaquamarine", "#66cdaa"],
+ ["mediumblue", "#0000cd"],
+ ["mediumorchid", "#ba55d3"],
+ ["mediumpurple", "#9370db"],
+ ["mediumseagreen", "#3cb371"],
+ ["mediumslateblue", "#7b68ee"],
+ ["mediumspringgreen", "#00fa9a"],
+ ["mediumturquoise", "#48d1cc"],
+ ["mediumvioletred", "#c71585"],
+ ["midnightblue", "#191970"],
+ ["mintcream", "#f5fffa"],
+ ["mistyrose", "#ffe4e1"],
+ ["moccasin", "#ffe4b5"],
+ ["navajowhite", "#ffdead"],
+ ["oldlace", "#fdf5e6"],
+ ["olivedrab", "#6b8e23"],
+ ["orangered", "#ff4500"],
+ ["orchid", "#da70d6"],
+ ["palegoldenrod", "#eee8aa"],
+ ["palegreen", "#98fb98"],
+ ["paleturquoise", "#afeeee"],
+ ["palevioletred", "#db7093"],
+ ["papayawhip", "#ffefd5"],
+ ["peachpuff", "#ffdab9"],
+ ["peru", "#cd853f"],
+ ["pink", "#ffc0cb"],
+ ["plum", "#dda0dd"],
+ ["powderblue", "#b0e0e6"],
+ ["rosybrown", "#bc8f8f"],
+ ["royalblue", "#4169e1"],
+ ["saddlebrown", "#8b4513"],
+ ["salmon", "#fa8072"],
+ ["sandybrown", "#f4a460"],
+ ["seagreen", "#2e8b57"],
+ ["seashell", "#fff5ee"],
+ ["sienna", "#a0522d"],
+ ["skyblue", "#87ceeb"],
+ ["slateblue", "#6a5acd"],
+ ["slategray", "#708090"],
+ ["slategrey", "#708090"],
+ ["snow", "#fffafa"],
+ ["springgreen", "#00ff7f"],
+ ["steelblue", "#4682b4"],
+ ["tan", "#d2b48c"],
+ ["thistle", "#d8bfd8"],
+ ["tomato", "#ff6347"],
+ ["turquoise", "#40e0d0"],
+ ["violet", "#ee82ee"],
+ ["wheat", "#f5deb3"],
+ ["whitesmoke", "#f5f5f5"],
+ ["yellowgreen", "#9acd32"],
+ ["rebeccapurple", "#663399"],
+]);
+
+function parseCssColor(colorString) {
+ if (MapPrototypeHas(colorKeywords, colorString)) {
+ colorString = MapPrototypeGet(colorKeywords, colorString);
+ }
+ // deno-fmt-ignore
+ const hashMatch = StringPrototypeMatch(colorString, /^#([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})?$/);
+ if (hashMatch != null) {
+ return [
+ Number(`0x${hashMatch[1]}`),
+ Number(`0x${hashMatch[2]}`),
+ Number(`0x${hashMatch[3]}`),
+ ];
+ }
+ // deno-fmt-ignore
+ const smallHashMatch = StringPrototypeMatch(colorString, /^#([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])?$/);
+ if (smallHashMatch != null) {
+ return [
+ Number(`0x${smallHashMatch[1]}0`),
+ Number(`0x${smallHashMatch[2]}0`),
+ Number(`0x${smallHashMatch[3]}0`),
+ ];
+ }
+ // deno-fmt-ignore
+ const rgbMatch = StringPrototypeMatch(colorString, /^rgba?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/);
+ if (rgbMatch != null) {
+ return [
+ MathRound(MathMax(0, MathMin(255, Number(rgbMatch[1])))),
+ MathRound(MathMax(0, MathMin(255, Number(rgbMatch[2])))),
+ MathRound(MathMax(0, MathMin(255, Number(rgbMatch[3])))),
+ ];
+ }
+ // deno-fmt-ignore
+ const hslMatch = StringPrototypeMatch(colorString, /^hsla?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)%\s*,\s*([+\-]?\d*\.?\d+)%\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/);
+ if (hslMatch != null) {
+ // https://www.rapidtables.com/convert/color/hsl-to-rgb.html
+ let h = Number(hslMatch[1]) % 360;
+ if (h < 0) {
+ h += 360;
+ }
+ const s = MathMax(0, MathMin(100, Number(hslMatch[2]))) / 100;
+ const l = MathMax(0, MathMin(100, Number(hslMatch[3]))) / 100;
+ const c = (1 - MathAbs(2 * l - 1)) * s;
+ const x = c * (1 - MathAbs((h / 60) % 2 - 1));
+ const m = l - c / 2;
+ let r_;
+ let g_;
+ let b_;
+ if (h < 60) {
+ ({ 0: r_, 1: g_, 2: b_ } = [c, x, 0]);
+ } else if (h < 120) {
+ ({ 0: r_, 1: g_, 2: b_ } = [x, c, 0]);
+ } else if (h < 180) {
+ ({ 0: r_, 1: g_, 2: b_ } = [0, c, x]);
+ } else if (h < 240) {
+ ({ 0: r_, 1: g_, 2: b_ } = [0, x, c]);
+ } else if (h < 300) {
+ ({ 0: r_, 1: g_, 2: b_ } = [x, 0, c]);
} else {
- // Otherwise, default object formatting
- let { 0: insp, 1: refIndex } = inspectRawObject(value, inspectOptions);
- insp = refIndex + insp;
- return insp;
+ ({ 0: r_, 1: g_, 2: b_ } = [c, 0, x]);
}
+ return [
+ MathRound((r_ + m) * 255),
+ MathRound((g_ + m) * 255),
+ MathRound((b_ + m) * 255),
+ ];
}
-
- const colorKeywords = new Map([
- ["black", "#000000"],
- ["silver", "#c0c0c0"],
- ["gray", "#808080"],
- ["white", "#ffffff"],
- ["maroon", "#800000"],
- ["red", "#ff0000"],
- ["purple", "#800080"],
- ["fuchsia", "#ff00ff"],
- ["green", "#008000"],
- ["lime", "#00ff00"],
- ["olive", "#808000"],
- ["yellow", "#ffff00"],
- ["navy", "#000080"],
- ["blue", "#0000ff"],
- ["teal", "#008080"],
- ["aqua", "#00ffff"],
- ["orange", "#ffa500"],
- ["aliceblue", "#f0f8ff"],
- ["antiquewhite", "#faebd7"],
- ["aquamarine", "#7fffd4"],
- ["azure", "#f0ffff"],
- ["beige", "#f5f5dc"],
- ["bisque", "#ffe4c4"],
- ["blanchedalmond", "#ffebcd"],
- ["blueviolet", "#8a2be2"],
- ["brown", "#a52a2a"],
- ["burlywood", "#deb887"],
- ["cadetblue", "#5f9ea0"],
- ["chartreuse", "#7fff00"],
- ["chocolate", "#d2691e"],
- ["coral", "#ff7f50"],
- ["cornflowerblue", "#6495ed"],
- ["cornsilk", "#fff8dc"],
- ["crimson", "#dc143c"],
- ["cyan", "#00ffff"],
- ["darkblue", "#00008b"],
- ["darkcyan", "#008b8b"],
- ["darkgoldenrod", "#b8860b"],
- ["darkgray", "#a9a9a9"],
- ["darkgreen", "#006400"],
- ["darkgrey", "#a9a9a9"],
- ["darkkhaki", "#bdb76b"],
- ["darkmagenta", "#8b008b"],
- ["darkolivegreen", "#556b2f"],
- ["darkorange", "#ff8c00"],
- ["darkorchid", "#9932cc"],
- ["darkred", "#8b0000"],
- ["darksalmon", "#e9967a"],
- ["darkseagreen", "#8fbc8f"],
- ["darkslateblue", "#483d8b"],
- ["darkslategray", "#2f4f4f"],
- ["darkslategrey", "#2f4f4f"],
- ["darkturquoise", "#00ced1"],
- ["darkviolet", "#9400d3"],
- ["deeppink", "#ff1493"],
- ["deepskyblue", "#00bfff"],
- ["dimgray", "#696969"],
- ["dimgrey", "#696969"],
- ["dodgerblue", "#1e90ff"],
- ["firebrick", "#b22222"],
- ["floralwhite", "#fffaf0"],
- ["forestgreen", "#228b22"],
- ["gainsboro", "#dcdcdc"],
- ["ghostwhite", "#f8f8ff"],
- ["gold", "#ffd700"],
- ["goldenrod", "#daa520"],
- ["greenyellow", "#adff2f"],
- ["grey", "#808080"],
- ["honeydew", "#f0fff0"],
- ["hotpink", "#ff69b4"],
- ["indianred", "#cd5c5c"],
- ["indigo", "#4b0082"],
- ["ivory", "#fffff0"],
- ["khaki", "#f0e68c"],
- ["lavender", "#e6e6fa"],
- ["lavenderblush", "#fff0f5"],
- ["lawngreen", "#7cfc00"],
- ["lemonchiffon", "#fffacd"],
- ["lightblue", "#add8e6"],
- ["lightcoral", "#f08080"],
- ["lightcyan", "#e0ffff"],
- ["lightgoldenrodyellow", "#fafad2"],
- ["lightgray", "#d3d3d3"],
- ["lightgreen", "#90ee90"],
- ["lightgrey", "#d3d3d3"],
- ["lightpink", "#ffb6c1"],
- ["lightsalmon", "#ffa07a"],
- ["lightseagreen", "#20b2aa"],
- ["lightskyblue", "#87cefa"],
- ["lightslategray", "#778899"],
- ["lightslategrey", "#778899"],
- ["lightsteelblue", "#b0c4de"],
- ["lightyellow", "#ffffe0"],
- ["limegreen", "#32cd32"],
- ["linen", "#faf0e6"],
- ["magenta", "#ff00ff"],
- ["mediumaquamarine", "#66cdaa"],
- ["mediumblue", "#0000cd"],
- ["mediumorchid", "#ba55d3"],
- ["mediumpurple", "#9370db"],
- ["mediumseagreen", "#3cb371"],
- ["mediumslateblue", "#7b68ee"],
- ["mediumspringgreen", "#00fa9a"],
- ["mediumturquoise", "#48d1cc"],
- ["mediumvioletred", "#c71585"],
- ["midnightblue", "#191970"],
- ["mintcream", "#f5fffa"],
- ["mistyrose", "#ffe4e1"],
- ["moccasin", "#ffe4b5"],
- ["navajowhite", "#ffdead"],
- ["oldlace", "#fdf5e6"],
- ["olivedrab", "#6b8e23"],
- ["orangered", "#ff4500"],
- ["orchid", "#da70d6"],
- ["palegoldenrod", "#eee8aa"],
- ["palegreen", "#98fb98"],
- ["paleturquoise", "#afeeee"],
- ["palevioletred", "#db7093"],
- ["papayawhip", "#ffefd5"],
- ["peachpuff", "#ffdab9"],
- ["peru", "#cd853f"],
- ["pink", "#ffc0cb"],
- ["plum", "#dda0dd"],
- ["powderblue", "#b0e0e6"],
- ["rosybrown", "#bc8f8f"],
- ["royalblue", "#4169e1"],
- ["saddlebrown", "#8b4513"],
- ["salmon", "#fa8072"],
- ["sandybrown", "#f4a460"],
- ["seagreen", "#2e8b57"],
- ["seashell", "#fff5ee"],
- ["sienna", "#a0522d"],
- ["skyblue", "#87ceeb"],
- ["slateblue", "#6a5acd"],
- ["slategray", "#708090"],
- ["slategrey", "#708090"],
- ["snow", "#fffafa"],
- ["springgreen", "#00ff7f"],
- ["steelblue", "#4682b4"],
- ["tan", "#d2b48c"],
- ["thistle", "#d8bfd8"],
- ["tomato", "#ff6347"],
- ["turquoise", "#40e0d0"],
- ["violet", "#ee82ee"],
- ["wheat", "#f5deb3"],
- ["whitesmoke", "#f5f5f5"],
- ["yellowgreen", "#9acd32"],
- ["rebeccapurple", "#663399"],
- ]);
-
- function parseCssColor(colorString) {
- if (MapPrototypeHas(colorKeywords, colorString)) {
- colorString = MapPrototypeGet(colorKeywords, colorString);
- }
- // deno-fmt-ignore
- const hashMatch = StringPrototypeMatch(colorString, /^#([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})?$/);
- if (hashMatch != null) {
- return [
- Number(`0x${hashMatch[1]}`),
- Number(`0x${hashMatch[2]}`),
- Number(`0x${hashMatch[3]}`),
- ];
- }
- // deno-fmt-ignore
- const smallHashMatch = StringPrototypeMatch(colorString, /^#([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])?$/);
- if (smallHashMatch != null) {
- return [
- Number(`0x${smallHashMatch[1]}0`),
- Number(`0x${smallHashMatch[2]}0`),
- Number(`0x${smallHashMatch[3]}0`),
- ];
- }
- // deno-fmt-ignore
- const rgbMatch = StringPrototypeMatch(colorString, /^rgba?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/);
- if (rgbMatch != null) {
- return [
- MathRound(MathMax(0, MathMin(255, Number(rgbMatch[1])))),
- MathRound(MathMax(0, MathMin(255, Number(rgbMatch[2])))),
- MathRound(MathMax(0, MathMin(255, Number(rgbMatch[3])))),
- ];
- }
- // deno-fmt-ignore
- const hslMatch = StringPrototypeMatch(colorString, /^hsla?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)%\s*,\s*([+\-]?\d*\.?\d+)%\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/);
- if (hslMatch != null) {
- // https://www.rapidtables.com/convert/color/hsl-to-rgb.html
- let h = Number(hslMatch[1]) % 360;
- if (h < 0) {
- h += 360;
- }
- const s = MathMax(0, MathMin(100, Number(hslMatch[2]))) / 100;
- const l = MathMax(0, MathMin(100, Number(hslMatch[3]))) / 100;
- const c = (1 - MathAbs(2 * l - 1)) * s;
- const x = c * (1 - MathAbs((h / 60) % 2 - 1));
- const m = l - c / 2;
- let r_;
- let g_;
- let b_;
- if (h < 60) {
- ({ 0: r_, 1: g_, 2: b_ } = [c, x, 0]);
- } else if (h < 120) {
- ({ 0: r_, 1: g_, 2: b_ } = [x, c, 0]);
- } else if (h < 180) {
- ({ 0: r_, 1: g_, 2: b_ } = [0, c, x]);
- } else if (h < 240) {
- ({ 0: r_, 1: g_, 2: b_ } = [0, x, c]);
- } else if (h < 300) {
- ({ 0: r_, 1: g_, 2: b_ } = [x, 0, c]);
- } else {
- ({ 0: r_, 1: g_, 2: b_ } = [c, 0, x]);
+ return null;
+}
+
+function getDefaultCss() {
+ return {
+ backgroundColor: null,
+ color: null,
+ fontWeight: null,
+ fontStyle: null,
+ textDecorationColor: null,
+ textDecorationLine: [],
+ };
+}
+
+function parseCss(cssString) {
+ const css = getDefaultCss();
+
+ const rawEntries = [];
+ let inValue = false;
+ let currentKey = null;
+ let parenthesesDepth = 0;
+ let currentPart = "";
+ for (let i = 0; i < cssString.length; i++) {
+ const c = cssString[i];
+ if (c == "(") {
+ parenthesesDepth++;
+ } else if (parenthesesDepth > 0) {
+ if (c == ")") {
+ parenthesesDepth--;
}
- return [
- MathRound((r_ + m) * 255),
- MathRound((g_ + m) * 255),
- MathRound((b_ + m) * 255),
- ];
- }
- return null;
- }
-
- function getDefaultCss() {
- return {
- backgroundColor: null,
- color: null,
- fontWeight: null,
- fontStyle: null,
- textDecorationColor: null,
- textDecorationLine: [],
- };
- }
-
- function parseCss(cssString) {
- const css = getDefaultCss();
-
- const rawEntries = [];
- let inValue = false;
- let currentKey = null;
- let parenthesesDepth = 0;
- let currentPart = "";
- for (let i = 0; i < cssString.length; i++) {
- const c = cssString[i];
- if (c == "(") {
- parenthesesDepth++;
- } else if (parenthesesDepth > 0) {
- if (c == ")") {
- parenthesesDepth--;
- }
- } else if (inValue) {
- if (c == ";") {
- const value = StringPrototypeTrim(currentPart);
- if (value != "") {
- ArrayPrototypePush(rawEntries, [currentKey, value]);
- }
- currentKey = null;
- currentPart = "";
- inValue = false;
- continue;
+ } else if (inValue) {
+ if (c == ";") {
+ const value = StringPrototypeTrim(currentPart);
+ if (value != "") {
+ ArrayPrototypePush(rawEntries, [currentKey, value]);
}
- } else if (c == ":") {
- currentKey = StringPrototypeTrim(currentPart);
+ currentKey = null;
currentPart = "";
- inValue = true;
+ inValue = false;
continue;
}
- currentPart += c;
- }
- if (inValue && parenthesesDepth == 0) {
- const value = StringPrototypeTrim(currentPart);
- if (value != "") {
- ArrayPrototypePush(rawEntries, [currentKey, value]);
- }
- currentKey = null;
+ } else if (c == ":") {
+ currentKey = StringPrototypeTrim(currentPart);
currentPart = "";
+ inValue = true;
+ continue;
+ }
+ currentPart += c;
+ }
+ if (inValue && parenthesesDepth == 0) {
+ const value = StringPrototypeTrim(currentPart);
+ if (value != "") {
+ ArrayPrototypePush(rawEntries, [currentKey, value]);
}
+ currentKey = null;
+ currentPart = "";
+ }
- for (let i = 0; i < rawEntries.length; ++i) {
- const { 0: key, 1: value } = rawEntries[i];
- if (key == "background-color") {
- if (value != null) {
- css.backgroundColor = value;
- }
- } else if (key == "color") {
- if (value != null) {
- css.color = value;
- }
- } else if (key == "font-weight") {
- if (value == "bold") {
- css.fontWeight = value;
- }
- } else if (key == "font-style") {
+ for (let i = 0; i < rawEntries.length; ++i) {
+ const { 0: key, 1: value } = rawEntries[i];
+ if (key == "background-color") {
+ if (value != null) {
+ css.backgroundColor = value;
+ }
+ } else if (key == "color") {
+ if (value != null) {
+ css.color = value;
+ }
+ } else if (key == "font-weight") {
+ if (value == "bold") {
+ css.fontWeight = value;
+ }
+ } else if (key == "font-style") {
+ if (
+ ArrayPrototypeIncludes(["italic", "oblique", "oblique 14deg"], value)
+ ) {
+ css.fontStyle = "italic";
+ }
+ } else if (key == "text-decoration-line") {
+ css.textDecorationLine = [];
+ const lineTypes = StringPrototypeSplit(value, /\s+/g);
+ for (let i = 0; i < lineTypes.length; ++i) {
+ const lineType = lineTypes[i];
if (
- ArrayPrototypeIncludes(["italic", "oblique", "oblique 14deg"], value)
+ ArrayPrototypeIncludes(
+ ["line-through", "overline", "underline"],
+ lineType,
+ )
) {
- css.fontStyle = "italic";
+ ArrayPrototypePush(css.textDecorationLine, lineType);
}
- } else if (key == "text-decoration-line") {
- css.textDecorationLine = [];
- const lineTypes = StringPrototypeSplit(value, /\s+/g);
- for (let i = 0; i < lineTypes.length; ++i) {
- const lineType = lineTypes[i];
- if (
- ArrayPrototypeIncludes(
- ["line-through", "overline", "underline"],
- lineType,
- )
- ) {
- ArrayPrototypePush(css.textDecorationLine, lineType);
- }
- }
- } else if (key == "text-decoration-color") {
- const color = parseCssColor(value);
- if (color != null) {
- css.textDecorationColor = color;
- }
- } else if (key == "text-decoration") {
- css.textDecorationColor = null;
- css.textDecorationLine = [];
- const args = StringPrototypeSplit(value, /\s+/g);
- for (let i = 0; i < args.length; ++i) {
- const arg = args[i];
- const maybeColor = parseCssColor(arg);
- if (maybeColor != null) {
- css.textDecorationColor = maybeColor;
- } else if (
- ArrayPrototypeIncludes(
- ["line-through", "overline", "underline"],
- arg,
- )
- ) {
- ArrayPrototypePush(css.textDecorationLine, arg);
- }
+ }
+ } else if (key == "text-decoration-color") {
+ const color = parseCssColor(value);
+ if (color != null) {
+ css.textDecorationColor = color;
+ }
+ } else if (key == "text-decoration") {
+ css.textDecorationColor = null;
+ css.textDecorationLine = [];
+ const args = StringPrototypeSplit(value, /\s+/g);
+ for (let i = 0; i < args.length; ++i) {
+ const arg = args[i];
+ const maybeColor = parseCssColor(arg);
+ if (maybeColor != null) {
+ css.textDecorationColor = maybeColor;
+ } else if (
+ ArrayPrototypeIncludes(
+ ["line-through", "overline", "underline"],
+ arg,
+ )
+ ) {
+ ArrayPrototypePush(css.textDecorationLine, arg);
}
}
}
+ }
- return css;
- }
-
- function colorEquals(color1, color2) {
- return color1?.[0] == color2?.[0] && color1?.[1] == color2?.[1] &&
- color1?.[2] == color2?.[2];
- }
-
- function cssToAnsi(css, prevCss = null) {
- prevCss = prevCss ?? getDefaultCss();
- let ansi = "";
- if (!colorEquals(css.backgroundColor, prevCss.backgroundColor)) {
- if (css.backgroundColor == null) {
- ansi += "\x1b[49m";
- } else if (css.backgroundColor == "black") {
- ansi += `\x1b[40m`;
- } else if (css.backgroundColor == "red") {
- ansi += `\x1b[41m`;
- } else if (css.backgroundColor == "green") {
- ansi += `\x1b[42m`;
- } else if (css.backgroundColor == "yellow") {
- ansi += `\x1b[43m`;
- } else if (css.backgroundColor == "blue") {
- ansi += `\x1b[44m`;
- } else if (css.backgroundColor == "magenta") {
- ansi += `\x1b[45m`;
- } else if (css.backgroundColor == "cyan") {
- ansi += `\x1b[46m`;
- } else if (css.backgroundColor == "white") {
- ansi += `\x1b[47m`;
+ return css;
+}
+
+function colorEquals(color1, color2) {
+ return color1?.[0] == color2?.[0] && color1?.[1] == color2?.[1] &&
+ color1?.[2] == color2?.[2];
+}
+
+function cssToAnsi(css, prevCss = null) {
+ prevCss = prevCss ?? getDefaultCss();
+ let ansi = "";
+ if (!colorEquals(css.backgroundColor, prevCss.backgroundColor)) {
+ if (css.backgroundColor == null) {
+ ansi += "\x1b[49m";
+ } else if (css.backgroundColor == "black") {
+ ansi += `\x1b[40m`;
+ } else if (css.backgroundColor == "red") {
+ ansi += `\x1b[41m`;
+ } else if (css.backgroundColor == "green") {
+ ansi += `\x1b[42m`;
+ } else if (css.backgroundColor == "yellow") {
+ ansi += `\x1b[43m`;
+ } else if (css.backgroundColor == "blue") {
+ ansi += `\x1b[44m`;
+ } else if (css.backgroundColor == "magenta") {
+ ansi += `\x1b[45m`;
+ } else if (css.backgroundColor == "cyan") {
+ ansi += `\x1b[46m`;
+ } else if (css.backgroundColor == "white") {
+ ansi += `\x1b[47m`;
+ } else {
+ if (ArrayIsArray(css.backgroundColor)) {
+ const { 0: r, 1: g, 2: b } = css.backgroundColor;
+ ansi += `\x1b[48;2;${r};${g};${b}m`;
} else {
- if (ArrayIsArray(css.backgroundColor)) {
- const { 0: r, 1: g, 2: b } = css.backgroundColor;
+ const parsed = parseCssColor(css.backgroundColor);
+ if (parsed !== null) {
+ const { 0: r, 1: g, 2: b } = parsed;
ansi += `\x1b[48;2;${r};${g};${b}m`;
} else {
- const parsed = parseCssColor(css.backgroundColor);
- if (parsed !== null) {
- const { 0: r, 1: g, 2: b } = parsed;
- ansi += `\x1b[48;2;${r};${g};${b}m`;
- } else {
- ansi += "\x1b[49m";
- }
+ ansi += "\x1b[49m";
}
}
}
- if (!colorEquals(css.color, prevCss.color)) {
- if (css.color == null) {
- ansi += "\x1b[39m";
- } else if (css.color == "black") {
- ansi += `\x1b[30m`;
- } else if (css.color == "red") {
- ansi += `\x1b[31m`;
- } else if (css.color == "green") {
- ansi += `\x1b[32m`;
- } else if (css.color == "yellow") {
- ansi += `\x1b[33m`;
- } else if (css.color == "blue") {
- ansi += `\x1b[34m`;
- } else if (css.color == "magenta") {
- ansi += `\x1b[35m`;
- } else if (css.color == "cyan") {
- ansi += `\x1b[36m`;
- } else if (css.color == "white") {
- ansi += `\x1b[37m`;
+ }
+ if (!colorEquals(css.color, prevCss.color)) {
+ if (css.color == null) {
+ ansi += "\x1b[39m";
+ } else if (css.color == "black") {
+ ansi += `\x1b[30m`;
+ } else if (css.color == "red") {
+ ansi += `\x1b[31m`;
+ } else if (css.color == "green") {
+ ansi += `\x1b[32m`;
+ } else if (css.color == "yellow") {
+ ansi += `\x1b[33m`;
+ } else if (css.color == "blue") {
+ ansi += `\x1b[34m`;
+ } else if (css.color == "magenta") {
+ ansi += `\x1b[35m`;
+ } else if (css.color == "cyan") {
+ ansi += `\x1b[36m`;
+ } else if (css.color == "white") {
+ ansi += `\x1b[37m`;
+ } else {
+ if (ArrayIsArray(css.color)) {
+ const { 0: r, 1: g, 2: b } = css.color;
+ ansi += `\x1b[38;2;${r};${g};${b}m`;
} else {
- if (ArrayIsArray(css.color)) {
- const { 0: r, 1: g, 2: b } = css.color;
+ const parsed = parseCssColor(css.color);
+ if (parsed !== null) {
+ const { 0: r, 1: g, 2: b } = parsed;
ansi += `\x1b[38;2;${r};${g};${b}m`;
} else {
- const parsed = parseCssColor(css.color);
- if (parsed !== null) {
- const { 0: r, 1: g, 2: b } = parsed;
- ansi += `\x1b[38;2;${r};${g};${b}m`;
- } else {
- ansi += "\x1b[39m";
- }
+ ansi += "\x1b[39m";
}
}
}
- if (css.fontWeight != prevCss.fontWeight) {
- if (css.fontWeight == "bold") {
- ansi += `\x1b[1m`;
- } else {
- ansi += "\x1b[22m";
- }
+ }
+ if (css.fontWeight != prevCss.fontWeight) {
+ if (css.fontWeight == "bold") {
+ ansi += `\x1b[1m`;
+ } else {
+ ansi += "\x1b[22m";
}
- if (css.fontStyle != prevCss.fontStyle) {
- if (css.fontStyle == "italic") {
- ansi += `\x1b[3m`;
- } else {
- ansi += "\x1b[23m";
- }
+ }
+ if (css.fontStyle != prevCss.fontStyle) {
+ if (css.fontStyle == "italic") {
+ ansi += `\x1b[3m`;
+ } else {
+ ansi += "\x1b[23m";
}
- if (!colorEquals(css.textDecorationColor, prevCss.textDecorationColor)) {
- if (css.textDecorationColor != null) {
- const { 0: r, 1: g, 2: b } = css.textDecorationColor;
- ansi += `\x1b[58;2;${r};${g};${b}m`;
- } else {
- ansi += "\x1b[59m";
- }
+ }
+ if (!colorEquals(css.textDecorationColor, prevCss.textDecorationColor)) {
+ if (css.textDecorationColor != null) {
+ const { 0: r, 1: g, 2: b } = css.textDecorationColor;
+ ansi += `\x1b[58;2;${r};${g};${b}m`;
+ } else {
+ ansi += "\x1b[59m";
}
- if (
- ArrayPrototypeIncludes(css.textDecorationLine, "line-through") !=
- ArrayPrototypeIncludes(prevCss.textDecorationLine, "line-through")
- ) {
- if (ArrayPrototypeIncludes(css.textDecorationLine, "line-through")) {
- ansi += "\x1b[9m";
- } else {
- ansi += "\x1b[29m";
- }
+ }
+ if (
+ ArrayPrototypeIncludes(css.textDecorationLine, "line-through") !=
+ ArrayPrototypeIncludes(prevCss.textDecorationLine, "line-through")
+ ) {
+ if (ArrayPrototypeIncludes(css.textDecorationLine, "line-through")) {
+ ansi += "\x1b[9m";
+ } else {
+ ansi += "\x1b[29m";
}
- if (
- ArrayPrototypeIncludes(css.textDecorationLine, "overline") !=
- ArrayPrototypeIncludes(prevCss.textDecorationLine, "overline")
- ) {
- if (ArrayPrototypeIncludes(css.textDecorationLine, "overline")) {
- ansi += "\x1b[53m";
- } else {
- ansi += "\x1b[55m";
- }
+ }
+ if (
+ ArrayPrototypeIncludes(css.textDecorationLine, "overline") !=
+ ArrayPrototypeIncludes(prevCss.textDecorationLine, "overline")
+ ) {
+ if (ArrayPrototypeIncludes(css.textDecorationLine, "overline")) {
+ ansi += "\x1b[53m";
+ } else {
+ ansi += "\x1b[55m";
}
- if (
- ArrayPrototypeIncludes(css.textDecorationLine, "underline") !=
- ArrayPrototypeIncludes(prevCss.textDecorationLine, "underline")
- ) {
- if (ArrayPrototypeIncludes(css.textDecorationLine, "underline")) {
- ansi += "\x1b[4m";
- } else {
- ansi += "\x1b[24m";
- }
+ }
+ if (
+ ArrayPrototypeIncludes(css.textDecorationLine, "underline") !=
+ ArrayPrototypeIncludes(prevCss.textDecorationLine, "underline")
+ ) {
+ if (ArrayPrototypeIncludes(css.textDecorationLine, "underline")) {
+ ansi += "\x1b[4m";
+ } else {
+ ansi += "\x1b[24m";
}
- return ansi;
- }
-
- function inspectArgs(args, inspectOptions = {}) {
- circular = undefined;
-
- const noColor = colors.getNoColor();
- const rInspectOptions = { ...DEFAULT_INSPECT_OPTIONS, ...inspectOptions };
- const first = args[0];
- let a = 0;
- let string = "";
-
- if (typeof first == "string" && args.length > 1) {
- a++;
- // Index of the first not-yet-appended character. Use this so we only
- // have to append to `string` when a substitution occurs / at the end.
- let appendedChars = 0;
- let usedStyle = false;
- let prevCss = null;
- for (let i = 0; i < first.length - 1; i++) {
- if (first[i] == "%") {
- const char = first[++i];
- if (a < args.length) {
- let formattedArg = null;
- if (char == "s") {
- // Format as a string.
- formattedArg = String(args[a++]);
- } else if (ArrayPrototypeIncludes(["d", "i"], char)) {
- // Format as an integer.
- const value = args[a++];
- if (typeof value == "bigint") {
- formattedArg = `${value}n`;
- } else if (typeof value == "number") {
- formattedArg = `${NumberParseInt(String(value))}`;
- } else {
- formattedArg = "NaN";
- }
- } else if (char == "f") {
- // Format as a floating point value.
- const value = args[a++];
- if (typeof value == "number") {
- formattedArg = `${value}`;
- } else {
- formattedArg = "NaN";
- }
- } else if (ArrayPrototypeIncludes(["O", "o"], char)) {
- // Format as an object.
- formattedArg = inspectValue(args[a++], rInspectOptions);
- } else if (char == "c") {
- const value = args[a++];
- if (!noColor) {
- const css = parseCss(value);
- formattedArg = cssToAnsi(css, prevCss);
- if (formattedArg != "") {
- usedStyle = true;
- prevCss = css;
- }
- } else {
- formattedArg = "";
- }
+ }
+ return ansi;
+}
+
+function inspectArgs(args, inspectOptions = {}) {
+ circular = undefined;
+
+ const noColor = colors.getNoColor();
+ const rInspectOptions = { ...DEFAULT_INSPECT_OPTIONS, ...inspectOptions };
+ const first = args[0];
+ let a = 0;
+ let string = "";
+
+ if (typeof first == "string" && args.length > 1) {
+ a++;
+ // Index of the first not-yet-appended character. Use this so we only
+ // have to append to `string` when a substitution occurs / at the end.
+ let appendedChars = 0;
+ let usedStyle = false;
+ let prevCss = null;
+ for (let i = 0; i < first.length - 1; i++) {
+ if (first[i] == "%") {
+ const char = first[++i];
+ if (a < args.length) {
+ let formattedArg = null;
+ if (char == "s") {
+ // Format as a string.
+ formattedArg = String(args[a++]);
+ } else if (ArrayPrototypeIncludes(["d", "i"], char)) {
+ // Format as an integer.
+ const value = args[a++];
+ if (typeof value == "bigint") {
+ formattedArg = `${value}n`;
+ } else if (typeof value == "number") {
+ formattedArg = `${NumberParseInt(String(value))}`;
+ } else {
+ formattedArg = "NaN";
}
-
- if (formattedArg != null) {
- string += StringPrototypeSlice(first, appendedChars, i - 1) +
- formattedArg;
- appendedChars = i + 1;
+ } else if (char == "f") {
+ // Format as a floating point value.
+ const value = args[a++];
+ if (typeof value == "number") {
+ formattedArg = `${value}`;
+ } else {
+ formattedArg = "NaN";
+ }
+ } else if (ArrayPrototypeIncludes(["O", "o"], char)) {
+ // Format as an object.
+ formattedArg = inspectValue(args[a++], rInspectOptions);
+ } else if (char == "c") {
+ const value = args[a++];
+ if (!noColor) {
+ const css = parseCss(value);
+ formattedArg = cssToAnsi(css, prevCss);
+ if (formattedArg != "") {
+ usedStyle = true;
+ prevCss = css;
+ }
+ } else {
+ formattedArg = "";
}
}
- if (char == "%") {
- string += StringPrototypeSlice(first, appendedChars, i - 1) + "%";
+
+ if (formattedArg != null) {
+ string += StringPrototypeSlice(first, appendedChars, i - 1) +
+ formattedArg;
appendedChars = i + 1;
}
}
- }
- string += StringPrototypeSlice(first, appendedChars);
- if (usedStyle) {
- string += "\x1b[0m";
+ if (char == "%") {
+ string += StringPrototypeSlice(first, appendedChars, i - 1) + "%";
+ appendedChars = i + 1;
+ }
}
}
-
- for (; a < args.length; a++) {
- if (a > 0) {
- string += " ";
- }
- if (typeof args[a] == "string") {
- string += args[a];
- } else {
- // Use default maximum depth for null or undefined arguments.
- string += inspectValue(args[a], rInspectOptions);
- }
+ string += StringPrototypeSlice(first, appendedChars);
+ if (usedStyle) {
+ string += "\x1b[0m";
}
+ }
- if (rInspectOptions.indentLevel > 0) {
- const groupIndent = StringPrototypeRepeat(
- DEFAULT_INDENT,
- rInspectOptions.indentLevel,
- );
- string = groupIndent +
- StringPrototypeReplaceAll(string, "\n", `\n${groupIndent}`);
+ for (; a < args.length; a++) {
+ if (a > 0) {
+ string += " ";
+ }
+ if (typeof args[a] == "string") {
+ string += args[a];
+ } else {
+ // Use default maximum depth for null or undefined arguments.
+ string += inspectValue(args[a], rInspectOptions);
}
+ }
- return string;
+ if (rInspectOptions.indentLevel > 0) {
+ const groupIndent = StringPrototypeRepeat(
+ DEFAULT_INDENT,
+ rInspectOptions.indentLevel,
+ );
+ string = groupIndent +
+ StringPrototypeReplaceAll(string, "\n", `\n${groupIndent}`);
}
- const countMap = new Map();
- const timerMap = new Map();
- const isConsoleInstance = Symbol("isConsoleInstance");
+ return string;
+}
- function getConsoleInspectOptions() {
- return {
- ...DEFAULT_INSPECT_OPTIONS,
- colors: !colors.getNoColor(),
- };
- }
+const countMap = new Map();
+const timerMap = new Map();
+const isConsoleInstance = Symbol("isConsoleInstance");
- class Console {
- #printFunc = null;
- [isConsoleInstance] = false;
-
- constructor(printFunc) {
- this.#printFunc = printFunc;
- this.indentLevel = 0;
- this[isConsoleInstance] = true;
-
- // ref https://console.spec.whatwg.org/#console-namespace
- // For historical web-compatibility reasons, the namespace object for
- // console must have as its [[Prototype]] an empty object, created as if
- // by ObjectCreate(%ObjectPrototype%), instead of %ObjectPrototype%.
- const console = ObjectCreate({}, {
- [SymbolToStringTag]: {
- enumerable: false,
- writable: false,
- configurable: true,
- value: "console",
- },
- });
- ObjectAssign(console, this);
- return console;
- }
+function getConsoleInspectOptions() {
+ return {
+ ...DEFAULT_INSPECT_OPTIONS,
+ colors: !colors.getNoColor(),
+ };
+}
+
+class Console {
+ #printFunc = null;
+ [isConsoleInstance] = false;
+
+ constructor(printFunc) {
+ this.#printFunc = printFunc;
+ this.indentLevel = 0;
+ this[isConsoleInstance] = true;
+
+ // ref https://console.spec.whatwg.org/#console-namespace
+ // For historical web-compatibility reasons, the namespace object for
+ // console must have as its [[Prototype]] an empty object, created as if
+ // by ObjectCreate(%ObjectPrototype%), instead of %ObjectPrototype%.
+ const console = ObjectCreate({}, {
+ [SymbolToStringTag]: {
+ enumerable: false,
+ writable: false,
+ configurable: true,
+ value: "console",
+ },
+ });
+ ObjectAssign(console, this);
+ return console;
+ }
- log = (...args) => {
- this.#printFunc(
- inspectArgs(args, {
- ...getConsoleInspectOptions(),
- indentLevel: this.indentLevel,
- }) + "\n",
- 1,
- );
- };
+ log = (...args) => {
+ this.#printFunc(
+ inspectArgs(args, {
+ ...getConsoleInspectOptions(),
+ indentLevel: this.indentLevel,
+ }) + "\n",
+ 1,
+ );
+ };
- debug = (...args) => {
- this.#printFunc(
- inspectArgs(args, {
- ...getConsoleInspectOptions(),
- indentLevel: this.indentLevel,
- }) + "\n",
- 0,
- );
- };
+ debug = (...args) => {
+ this.#printFunc(
+ inspectArgs(args, {
+ ...getConsoleInspectOptions(),
+ indentLevel: this.indentLevel,
+ }) + "\n",
+ 0,
+ );
+ };
- info = (...args) => {
- this.#printFunc(
- inspectArgs(args, {
- ...getConsoleInspectOptions(),
- indentLevel: this.indentLevel,
- }) + "\n",
- 1,
- );
- };
+ info = (...args) => {
+ this.#printFunc(
+ inspectArgs(args, {
+ ...getConsoleInspectOptions(),
+ indentLevel: this.indentLevel,
+ }) + "\n",
+ 1,
+ );
+ };
- dir = (obj = undefined, options = {}) => {
- this.#printFunc(
- inspectArgs([obj], { ...getConsoleInspectOptions(), ...options }) +
- "\n",
- 1,
- );
- };
+ dir = (obj = undefined, options = {}) => {
+ this.#printFunc(
+ inspectArgs([obj], { ...getConsoleInspectOptions(), ...options }) +
+ "\n",
+ 1,
+ );
+ };
- dirxml = this.dir;
+ dirxml = this.dir;
- warn = (...args) => {
- this.#printFunc(
- inspectArgs(args, {
- ...getConsoleInspectOptions(),
- indentLevel: this.indentLevel,
- }) + "\n",
- 2,
- );
- };
+ warn = (...args) => {
+ this.#printFunc(
+ inspectArgs(args, {
+ ...getConsoleInspectOptions(),
+ indentLevel: this.indentLevel,
+ }) + "\n",
+ 2,
+ );
+ };
- error = (...args) => {
- this.#printFunc(
- inspectArgs(args, {
- ...getConsoleInspectOptions(),
- indentLevel: this.indentLevel,
- }) + "\n",
- 3,
- );
- };
+ error = (...args) => {
+ this.#printFunc(
+ inspectArgs(args, {
+ ...getConsoleInspectOptions(),
+ indentLevel: this.indentLevel,
+ }) + "\n",
+ 3,
+ );
+ };
- assert = (condition = false, ...args) => {
- if (condition) {
- return;
- }
+ assert = (condition = false, ...args) => {
+ if (condition) {
+ return;
+ }
- if (args.length === 0) {
- this.error("Assertion failed");
- return;
- }
+ if (args.length === 0) {
+ this.error("Assertion failed");
+ return;
+ }
- const [first, ...rest] = new SafeArrayIterator(args);
+ const [first, ...rest] = new SafeArrayIterator(args);
- if (typeof first === "string") {
- this.error(
- `Assertion failed: ${first}`,
- ...new SafeArrayIterator(rest),
- );
- return;
- }
+ if (typeof first === "string") {
+ this.error(
+ `Assertion failed: ${first}`,
+ ...new SafeArrayIterator(rest),
+ );
+ return;
+ }
- this.error(`Assertion failed:`, ...new SafeArrayIterator(args));
- };
+ this.error(`Assertion failed:`, ...new SafeArrayIterator(args));
+ };
- count = (label = "default") => {
- label = String(label);
+ count = (label = "default") => {
+ label = String(label);
- if (MapPrototypeHas(countMap, label)) {
- const current = MapPrototypeGet(countMap, label) || 0;
- MapPrototypeSet(countMap, label, current + 1);
- } else {
- MapPrototypeSet(countMap, label, 1);
- }
+ if (MapPrototypeHas(countMap, label)) {
+ const current = MapPrototypeGet(countMap, label) || 0;
+ MapPrototypeSet(countMap, label, current + 1);
+ } else {
+ MapPrototypeSet(countMap, label, 1);
+ }
- this.info(`${label}: ${MapPrototypeGet(countMap, label)}`);
- };
+ this.info(`${label}: ${MapPrototypeGet(countMap, label)}`);
+ };
- countReset = (label = "default") => {
- label = String(label);
+ countReset = (label = "default") => {
+ label = String(label);
- if (MapPrototypeHas(countMap, label)) {
- MapPrototypeSet(countMap, label, 0);
- } else {
- this.warn(`Count for '${label}' does not exist`);
- }
- };
+ if (MapPrototypeHas(countMap, label)) {
+ MapPrototypeSet(countMap, label, 0);
+ } else {
+ this.warn(`Count for '${label}' does not exist`);
+ }
+ };
- table = (data = undefined, properties = undefined) => {
- if (properties !== undefined && !ArrayIsArray(properties)) {
- throw new Error(
- "The 'properties' argument must be of type Array. " +
- "Received type string",
- );
- }
+ table = (data = undefined, properties = undefined) => {
+ if (properties !== undefined && !ArrayIsArray(properties)) {
+ throw new Error(
+ "The 'properties' argument must be of type Array. " +
+ "Received type string",
+ );
+ }
- if (data === null || typeof data !== "object") {
- return this.log(data);
- }
+ if (data === null || typeof data !== "object") {
+ return this.log(data);
+ }
- const stringifyValue = (value) =>
- inspectValueWithQuotes(value, {
- ...DEFAULT_INSPECT_OPTIONS,
- depth: 1,
- });
- const toTable = (header, body) => this.log(cliTable(header, body));
-
- let resultData;
- const isSet = ObjectPrototypeIsPrototypeOf(SetPrototype, data);
- const isMap = ObjectPrototypeIsPrototypeOf(MapPrototype, data);
- const valuesKey = "Values";
- const indexKey = isSet || isMap ? "(iter idx)" : "(idx)";
-
- if (isSet) {
- resultData = [...new SafeSet(data)];
- } else if (isMap) {
- let idx = 0;
- resultData = {};
-
- MapPrototypeForEach(data, (v, k) => {
- resultData[idx] = { Key: k, Values: v };
- idx++;
- });
- } else {
- resultData = data;
- }
+ const stringifyValue = (value) =>
+ inspectValueWithQuotes(value, {
+ ...DEFAULT_INSPECT_OPTIONS,
+ depth: 1,
+ });
+ const toTable = (header, body) => this.log(cliTable(header, body));
+
+ let resultData;
+ const isSet = ObjectPrototypeIsPrototypeOf(SetPrototype, data);
+ const isMap = ObjectPrototypeIsPrototypeOf(MapPrototype, data);
+ const valuesKey = "Values";
+ const indexKey = isSet || isMap ? "(iter idx)" : "(idx)";
+
+ if (isSet) {
+ resultData = [...new SafeSet(data)];
+ } else if (isMap) {
+ let idx = 0;
+ resultData = {};
+
+ MapPrototypeForEach(data, (v, k) => {
+ resultData[idx] = { Key: k, Values: v };
+ idx++;
+ });
+ } else {
+ resultData = data;
+ }
- const keys = ObjectKeys(resultData);
- const numRows = keys.length;
+ const keys = ObjectKeys(resultData);
+ const numRows = keys.length;
- const objectValues = properties
- ? ObjectFromEntries(
- ArrayPrototypeMap(
- properties,
- (name) => [name, ArrayPrototypeFill(new Array(numRows), "")],
- ),
- )
- : {};
- const indexKeys = [];
- const values = [];
-
- let hasPrimitives = false;
- keys.forEach((k, idx) => {
- const value = resultData[k];
- const primitive = value === null ||
- (typeof value !== "function" && typeof value !== "object");
- if (properties === undefined && primitive) {
- hasPrimitives = true;
- ArrayPrototypePush(values, stringifyValue(value));
- } else {
- const valueObj = value || {};
- const keys = properties || ObjectKeys(valueObj);
- for (let i = 0; i < keys.length; ++i) {
- const k = keys[i];
- if (!primitive && ReflectHas(valueObj, k)) {
- if (!(ReflectHas(objectValues, k))) {
- objectValues[k] = ArrayPrototypeFill(new Array(numRows), "");
- }
- objectValues[k][idx] = stringifyValue(valueObj[k]);
+ const objectValues = properties
+ ? ObjectFromEntries(
+ ArrayPrototypeMap(
+ properties,
+ (name) => [name, ArrayPrototypeFill(new Array(numRows), "")],
+ ),
+ )
+ : {};
+ const indexKeys = [];
+ const values = [];
+
+ let hasPrimitives = false;
+ keys.forEach((k, idx) => {
+ const value = resultData[k];
+ const primitive = value === null ||
+ (typeof value !== "function" && typeof value !== "object");
+ if (properties === undefined && primitive) {
+ hasPrimitives = true;
+ ArrayPrototypePush(values, stringifyValue(value));
+ } else {
+ const valueObj = value || {};
+ const keys = properties || ObjectKeys(valueObj);
+ for (let i = 0; i < keys.length; ++i) {
+ const k = keys[i];
+ if (!primitive && ReflectHas(valueObj, k)) {
+ if (!(ReflectHas(objectValues, k))) {
+ objectValues[k] = ArrayPrototypeFill(new Array(numRows), "");
}
+ objectValues[k][idx] = stringifyValue(valueObj[k]);
}
- ArrayPrototypePush(values, "");
}
-
- ArrayPrototypePush(indexKeys, k);
- });
-
- const headerKeys = ObjectKeys(objectValues);
- const bodyValues = ObjectValues(objectValues);
- const headerProps = properties ||
- [
- ...new SafeArrayIterator(headerKeys),
- !isMap && hasPrimitives && valuesKey,
- ];
- const header = ArrayPrototypeFilter([
- indexKey,
- ...new SafeArrayIterator(headerProps),
- ], Boolean);
- const body = [indexKeys, ...new SafeArrayIterator(bodyValues), values];
-
- toTable(header, body);
- };
-
- time = (label = "default") => {
- label = String(label);
-
- if (MapPrototypeHas(timerMap, label)) {
- this.warn(`Timer '${label}' already exists`);
- return;
+ ArrayPrototypePush(values, "");
}
- MapPrototypeSet(timerMap, label, DateNow());
- };
+ ArrayPrototypePush(indexKeys, k);
+ });
- timeLog = (label = "default", ...args) => {
- label = String(label);
+ const headerKeys = ObjectKeys(objectValues);
+ const bodyValues = ObjectValues(objectValues);
+ const headerProps = properties ||
+ [
+ ...new SafeArrayIterator(headerKeys),
+ !isMap && hasPrimitives && valuesKey,
+ ];
+ const header = ArrayPrototypeFilter([
+ indexKey,
+ ...new SafeArrayIterator(headerProps),
+ ], Boolean);
+ const body = [indexKeys, ...new SafeArrayIterator(bodyValues), values];
- if (!MapPrototypeHas(timerMap, label)) {
- this.warn(`Timer '${label}' does not exists`);
- return;
- }
+ toTable(header, body);
+ };
- const startTime = MapPrototypeGet(timerMap, label);
- const duration = DateNow() - startTime;
+ time = (label = "default") => {
+ label = String(label);
- this.info(`${label}: ${duration}ms`, ...new SafeArrayIterator(args));
- };
+ if (MapPrototypeHas(timerMap, label)) {
+ this.warn(`Timer '${label}' already exists`);
+ return;
+ }
- timeEnd = (label = "default") => {
- label = String(label);
+ MapPrototypeSet(timerMap, label, DateNow());
+ };
- if (!MapPrototypeHas(timerMap, label)) {
- this.warn(`Timer '${label}' does not exist`);
- return;
- }
+ timeLog = (label = "default", ...args) => {
+ label = String(label);
- const startTime = MapPrototypeGet(timerMap, label);
- MapPrototypeDelete(timerMap, label);
- const duration = DateNow() - startTime;
+ if (!MapPrototypeHas(timerMap, label)) {
+ this.warn(`Timer '${label}' does not exists`);
+ return;
+ }
- this.info(`${label}: ${duration}ms`);
- };
+ const startTime = MapPrototypeGet(timerMap, label);
+ const duration = DateNow() - startTime;
- group = (...label) => {
- if (label.length > 0) {
- this.log(...new SafeArrayIterator(label));
- }
- this.indentLevel += 2;
- };
+ this.info(`${label}: ${duration}ms`, ...new SafeArrayIterator(args));
+ };
- groupCollapsed = this.group;
+ timeEnd = (label = "default") => {
+ label = String(label);
- groupEnd = () => {
- if (this.indentLevel > 0) {
- this.indentLevel -= 2;
- }
- };
-
- clear = () => {
- this.indentLevel = 0;
- this.#printFunc(CSI.kClear, 1);
- this.#printFunc(CSI.kClearScreenDown, 1);
- };
+ if (!MapPrototypeHas(timerMap, label)) {
+ this.warn(`Timer '${label}' does not exist`);
+ return;
+ }
- trace = (...args) => {
- const message = inspectArgs(
- args,
- { ...getConsoleInspectOptions(), indentLevel: 0 },
- );
- const err = {
- name: "Trace",
- message,
- };
- ErrorCaptureStackTrace(err, this.trace);
- this.error(err.stack);
- };
+ const startTime = MapPrototypeGet(timerMap, label);
+ MapPrototypeDelete(timerMap, label);
+ const duration = DateNow() - startTime;
- // These methods are noops, but when the inspector is connected, they
- // call into V8.
- profile = (_label) => {};
- profileEnd = (_label) => {};
- timeStamp = (_label) => {};
+ this.info(`${label}: ${duration}ms`);
+ };
- static [SymbolHasInstance](instance) {
- return instance[isConsoleInstance];
+ group = (...label) => {
+ if (label.length > 0) {
+ this.log(...new SafeArrayIterator(label));
}
- }
+ this.indentLevel += 2;
+ };
- const customInspect = SymbolFor("Deno.customInspect");
+ groupCollapsed = this.group;
- function inspect(
- value,
- inspectOptions = {},
- ) {
- circular = undefined;
- return inspectValue(value, {
- ...DEFAULT_INSPECT_OPTIONS,
- ...inspectOptions,
- });
- }
+ groupEnd = () => {
+ if (this.indentLevel > 0) {
+ this.indentLevel -= 2;
+ }
+ };
- /** Creates a proxy that represents a subset of the properties
- * of the original object optionally without evaluating the properties
- * in order to get the values. */
- function createFilteredInspectProxy({ object, keys, evaluate }) {
- return new Proxy({}, {
- get(_target, key) {
- if (key === SymbolToStringTag) {
- return object.constructor?.name;
- } else if (ArrayPrototypeIncludes(keys, key)) {
- return ReflectGet(object, key);
- } else {
- return undefined;
- }
- },
- getOwnPropertyDescriptor(_target, key) {
- if (!ArrayPrototypeIncludes(keys, key)) {
- return undefined;
- } else if (evaluate) {
- return getEvaluatedDescriptor(object, key);
- } else {
- return getDescendantPropertyDescriptor(object, key) ??
- getEvaluatedDescriptor(object, key);
- }
- },
- has(_target, key) {
- return ArrayPrototypeIncludes(keys, key);
- },
- ownKeys() {
- return keys;
- },
- });
+ clear = () => {
+ this.indentLevel = 0;
+ this.#printFunc(CSI.kClear, 1);
+ this.#printFunc(CSI.kClearScreenDown, 1);
+ };
- function getDescendantPropertyDescriptor(object, key) {
- let propertyDescriptor = ReflectGetOwnPropertyDescriptor(object, key);
- if (!propertyDescriptor) {
- const prototype = ReflectGetPrototypeOf(object);
- if (prototype) {
- propertyDescriptor = getDescendantPropertyDescriptor(prototype, key);
- }
- }
- return propertyDescriptor;
- }
+ trace = (...args) => {
+ const message = inspectArgs(
+ args,
+ { ...getConsoleInspectOptions(), indentLevel: 0 },
+ );
+ const err = {
+ name: "Trace",
+ message,
+ };
+ ErrorCaptureStackTrace(err, this.trace);
+ this.error(err.stack);
+ };
- function getEvaluatedDescriptor(object, key) {
- return {
- configurable: true,
- enumerable: true,
- value: object[key],
- };
- }
- }
+ // These methods are noops, but when the inspector is connected, they
+ // call into V8.
+ profile = (_label) => {};
+ profileEnd = (_label) => {};
+ timeStamp = (_label) => {};
- // A helper function that will bind our own console implementation
- // with default implementation of Console from V8. This will cause
- // console messages to be piped to inspector console.
- //
- // We are using `Deno.core.callConsole` binding to preserve proper stack
- // frames in inspector console. This has to be done because V8 considers
- // the last JS stack frame as gospel for the inspector. In our case we
- // specifically want the latest user stack frame to be the one that matters
- // though.
- //
- // Inspired by:
- // https://github.com/nodejs/node/blob/1317252dfe8824fd9cfee125d2aaa94004db2f3b/lib/internal/util/inspector.js#L39-L61
- function wrapConsole(consoleFromDeno, consoleFromV8) {
- const callConsole = core.callConsole;
-
- const keys = ObjectKeys(consoleFromV8);
- for (let i = 0; i < keys.length; ++i) {
- const key = keys[i];
- if (ObjectPrototypeHasOwnProperty(consoleFromDeno, key)) {
- consoleFromDeno[key] = FunctionPrototypeBind(
- callConsole,
- consoleFromDeno,
- consoleFromV8[key],
- consoleFromDeno[key],
- );
+ static [SymbolHasInstance](instance) {
+ return instance[isConsoleInstance];
+ }
+}
+
+const customInspect = SymbolFor("Deno.customInspect");
+
+function inspect(
+ value,
+ inspectOptions = {},
+) {
+ circular = undefined;
+ return inspectValue(value, {
+ ...DEFAULT_INSPECT_OPTIONS,
+ ...inspectOptions,
+ });
+}
+
+/** Creates a proxy that represents a subset of the properties
+ * of the original object optionally without evaluating the properties
+ * in order to get the values. */
+function createFilteredInspectProxy({ object, keys, evaluate }) {
+ return new Proxy({}, {
+ get(_target, key) {
+ if (key === SymbolToStringTag) {
+ return object.constructor?.name;
+ } else if (ArrayPrototypeIncludes(keys, key)) {
+ return ReflectGet(object, key);
+ } else {
+ return undefined;
+ }
+ },
+ getOwnPropertyDescriptor(_target, key) {
+ if (!ArrayPrototypeIncludes(keys, key)) {
+ return undefined;
+ } else if (evaluate) {
+ return getEvaluatedDescriptor(object, key);
} else {
- // Add additional console APIs from the inspector
- consoleFromDeno[key] = consoleFromV8[key];
+ return getDescendantPropertyDescriptor(object, key) ??
+ getEvaluatedDescriptor(object, key);
+ }
+ },
+ has(_target, key) {
+ return ArrayPrototypeIncludes(keys, key);
+ },
+ ownKeys() {
+ return keys;
+ },
+ });
+
+ function getDescendantPropertyDescriptor(object, key) {
+ let propertyDescriptor = ReflectGetOwnPropertyDescriptor(object, key);
+ if (!propertyDescriptor) {
+ const prototype = ReflectGetPrototypeOf(object);
+ if (prototype) {
+ propertyDescriptor = getDescendantPropertyDescriptor(prototype, key);
}
}
+ return propertyDescriptor;
}
- // Expose these fields to internalObject for tests.
- window.__bootstrap.internals = {
- ...window.__bootstrap.internals ?? {},
- Console,
- cssToAnsi,
- inspectArgs,
- parseCss,
- parseCssColor,
- };
-
- window.__bootstrap.console = {
- CSI,
- inspectArgs,
- Console,
- customInspect,
- inspect,
- wrapConsole,
- createFilteredInspectProxy,
- quoteString,
- };
-})(this);
+ function getEvaluatedDescriptor(object, key) {
+ return {
+ configurable: true,
+ enumerable: true,
+ value: object[key],
+ };
+ }
+}
+
+// A helper function that will bind our own console implementation
+// with default implementation of Console from V8. This will cause
+// console messages to be piped to inspector console.
+//
+// We are using `Deno.core.callConsole` binding to preserve proper stack
+// frames in inspector console. This has to be done because V8 considers
+// the last JS stack frame as gospel for the inspector. In our case we
+// specifically want the latest user stack frame to be the one that matters
+// though.
+//
+// Inspired by:
+// https://github.com/nodejs/node/blob/1317252dfe8824fd9cfee125d2aaa94004db2f3b/lib/internal/util/inspector.js#L39-L61
+function wrapConsole(consoleFromDeno, consoleFromV8) {
+ const callConsole = core.callConsole;
+
+ const keys = ObjectKeys(consoleFromV8);
+ for (let i = 0; i < keys.length; ++i) {
+ const key = keys[i];
+ if (ObjectPrototypeHasOwnProperty(consoleFromDeno, key)) {
+ consoleFromDeno[key] = FunctionPrototypeBind(
+ callConsole,
+ consoleFromDeno,
+ consoleFromV8[key],
+ consoleFromDeno[key],
+ );
+ } else {
+ // Add additional console APIs from the inspector
+ consoleFromDeno[key] = consoleFromV8[key];
+ }
+ }
+}
+
+// Expose these fields to internalObject for tests.
+internals.Console = Console;
+internals.cssToAnsi = cssToAnsi;
+internals.inspectArgs = inspectArgs;
+internals.parseCss = parseCss;
+internals.parseCssColor = parseCssColor;
+
+export {
+ Console,
+ createFilteredInspectProxy,
+ CSI,
+ customInspect,
+ inspect,
+ inspectArgs,
+ quoteString,
+ wrapConsole,
+};
diff --git a/ext/console/internal.d.ts b/ext/console/internal.d.ts
index 57c5d120b..965a879e7 100644
--- a/ext/console/internal.d.ts
+++ b/ext/console/internal.d.ts
@@ -3,14 +3,10 @@
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
-declare namespace globalThis {
- declare namespace __bootstrap {
- declare namespace console {
- declare function createFilteredInspectProxy<TObject>(params: {
- object: TObject;
- keys: (keyof TObject)[];
- evaluate: boolean;
- }): Record<string, unknown>;
- }
- }
+declare module "internal:ext/console/02_console.js" {
+ function createFilteredInspectProxy<TObject>(params: {
+ object: TObject;
+ keys: (keyof TObject)[];
+ evaluate: boolean;
+ }): Record<string, unknown>;
}
diff --git a/ext/console/lib.rs b/ext/console/lib.rs
index 4b3b45029..31ec884c1 100644
--- a/ext/console/lib.rs
+++ b/ext/console/lib.rs
@@ -6,7 +6,7 @@ use std::path::PathBuf;
pub fn init() -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/console",
"01_colors.js",
"02_console.js",
diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js
index 7d30dcccf..c79a1e4e8 100644
--- a/ext/crypto/00_crypto.js
+++ b/ext/crypto/00_crypto.js
@@ -6,2394 +6,2534 @@
/// <reference path="../webidl/internal.d.ts" />
/// <reference path="../web/lib.deno_web.d.ts" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const { DOMException } = window.__bootstrap.domException;
-
- const {
- ArrayBufferPrototype,
- ArrayBufferIsView,
- ArrayPrototypeEvery,
- ArrayPrototypeFind,
- ArrayPrototypeIncludes,
- BigInt64ArrayPrototype,
- BigUint64ArrayPrototype,
- Int16ArrayPrototype,
- Int32ArrayPrototype,
- Int8ArrayPrototype,
- JSONParse,
- JSONStringify,
- MathCeil,
- ObjectAssign,
- ObjectPrototypeHasOwnProperty,
- ObjectPrototypeIsPrototypeOf,
- StringPrototypeToLowerCase,
- StringPrototypeToUpperCase,
- StringPrototypeCharCodeAt,
- StringFromCharCode,
- SafeArrayIterator,
- Symbol,
- SymbolFor,
- SyntaxError,
- TypedArrayPrototypeSlice,
- TypeError,
- Uint16ArrayPrototype,
- Uint32ArrayPrototype,
- Uint8Array,
- Uint8ArrayPrototype,
- Uint8ClampedArrayPrototype,
- WeakMap,
- WeakMapPrototypeGet,
- WeakMapPrototypeSet,
- } = window.__bootstrap.primordials;
-
- // P-521 is not yet supported.
- const supportedNamedCurves = ["P-256", "P-384"];
- const recognisedUsages = [
- "encrypt",
- "decrypt",
- "sign",
- "verify",
- "deriveKey",
- "deriveBits",
- "wrapKey",
- "unwrapKey",
- ];
-
- const simpleAlgorithmDictionaries = {
- AesGcmParams: { iv: "BufferSource", additionalData: "BufferSource" },
- RsaHashedKeyGenParams: { hash: "HashAlgorithmIdentifier" },
- EcKeyGenParams: {},
- HmacKeyGenParams: { hash: "HashAlgorithmIdentifier" },
- RsaPssParams: {},
- EcdsaParams: { hash: "HashAlgorithmIdentifier" },
- HmacImportParams: { hash: "HashAlgorithmIdentifier" },
- HkdfParams: {
- hash: "HashAlgorithmIdentifier",
- salt: "BufferSource",
- info: "BufferSource",
- },
- Pbkdf2Params: { hash: "HashAlgorithmIdentifier", salt: "BufferSource" },
- RsaOaepParams: { label: "BufferSource" },
- RsaHashedImportParams: { hash: "HashAlgorithmIdentifier" },
- EcKeyImportParams: {},
- };
-
- const supportedAlgorithms = {
- "digest": {
- "SHA-1": null,
- "SHA-256": null,
- "SHA-384": null,
- "SHA-512": null,
- },
- "generateKey": {
- "RSASSA-PKCS1-v1_5": "RsaHashedKeyGenParams",
- "RSA-PSS": "RsaHashedKeyGenParams",
- "RSA-OAEP": "RsaHashedKeyGenParams",
- "ECDSA": "EcKeyGenParams",
- "ECDH": "EcKeyGenParams",
- "AES-CTR": "AesKeyGenParams",
- "AES-CBC": "AesKeyGenParams",
- "AES-GCM": "AesKeyGenParams",
- "AES-KW": "AesKeyGenParams",
- "HMAC": "HmacKeyGenParams",
- "X25519": null,
- "Ed25519": null,
- },
- "sign": {
- "RSASSA-PKCS1-v1_5": null,
- "RSA-PSS": "RsaPssParams",
- "ECDSA": "EcdsaParams",
- "HMAC": null,
- "Ed25519": null,
- },
- "verify": {
- "RSASSA-PKCS1-v1_5": null,
- "RSA-PSS": "RsaPssParams",
- "ECDSA": "EcdsaParams",
- "HMAC": null,
- "Ed25519": null,
- },
- "importKey": {
- "RSASSA-PKCS1-v1_5": "RsaHashedImportParams",
- "RSA-PSS": "RsaHashedImportParams",
- "RSA-OAEP": "RsaHashedImportParams",
- "ECDSA": "EcKeyImportParams",
- "ECDH": "EcKeyImportParams",
- "HMAC": "HmacImportParams",
- "HKDF": null,
- "PBKDF2": null,
- "AES-CTR": null,
- "AES-CBC": null,
- "AES-GCM": null,
- "AES-KW": null,
- "Ed25519": null,
- "X25519": null,
- },
- "deriveBits": {
- "HKDF": "HkdfParams",
- "PBKDF2": "Pbkdf2Params",
- "ECDH": "EcdhKeyDeriveParams",
- "X25519": "EcdhKeyDeriveParams",
- },
- "encrypt": {
- "RSA-OAEP": "RsaOaepParams",
- "AES-CBC": "AesCbcParams",
- "AES-GCM": "AesGcmParams",
- "AES-CTR": "AesCtrParams",
- },
- "decrypt": {
- "RSA-OAEP": "RsaOaepParams",
- "AES-CBC": "AesCbcParams",
- "AES-GCM": "AesGcmParams",
- "AES-CTR": "AesCtrParams",
- },
- "get key length": {
- "AES-CBC": "AesDerivedKeyParams",
- "AES-CTR": "AesDerivedKeyParams",
- "AES-GCM": "AesDerivedKeyParams",
- "AES-KW": "AesDerivedKeyParams",
- "HMAC": "HmacImportParams",
- "HKDF": null,
- "PBKDF2": null,
- },
- "wrapKey": {
- "AES-KW": null,
- },
- "unwrapKey": {
- "AES-KW": null,
- },
- };
-
- const aesJwkAlg = {
- "AES-CTR": {
- 128: "A128CTR",
- 192: "A192CTR",
- 256: "A256CTR",
- },
- "AES-CBC": {
- 128: "A128CBC",
- 192: "A192CBC",
- 256: "A256CBC",
- },
- "AES-GCM": {
- 128: "A128GCM",
- 192: "A192GCM",
- 256: "A256GCM",
- },
- "AES-KW": {
- 128: "A128KW",
- 192: "A192KW",
- 256: "A256KW",
- },
- };
+const core = globalThis.Deno.core;
+const ops = core.ops;
+const primordials = globalThis.__bootstrap.primordials;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+const {
+ ArrayBufferPrototype,
+ ArrayBufferIsView,
+ ArrayPrototypeEvery,
+ ArrayPrototypeFind,
+ ArrayPrototypeIncludes,
+ BigInt64ArrayPrototype,
+ BigUint64ArrayPrototype,
+ Int16ArrayPrototype,
+ Int32ArrayPrototype,
+ Int8ArrayPrototype,
+ JSONParse,
+ JSONStringify,
+ MathCeil,
+ ObjectAssign,
+ ObjectPrototypeHasOwnProperty,
+ ObjectPrototypeIsPrototypeOf,
+ StringPrototypeToLowerCase,
+ StringPrototypeToUpperCase,
+ StringPrototypeCharCodeAt,
+ StringFromCharCode,
+ SafeArrayIterator,
+ Symbol,
+ SymbolFor,
+ SyntaxError,
+ TypedArrayPrototypeSlice,
+ TypeError,
+ Uint16ArrayPrototype,
+ Uint32ArrayPrototype,
+ Uint8Array,
+ Uint8ArrayPrototype,
+ Uint8ClampedArrayPrototype,
+ WeakMap,
+ WeakMapPrototypeGet,
+ WeakMapPrototypeSet,
+} = primordials;
+
+// P-521 is not yet supported.
+const supportedNamedCurves = ["P-256", "P-384"];
+const recognisedUsages = [
+ "encrypt",
+ "decrypt",
+ "sign",
+ "verify",
+ "deriveKey",
+ "deriveBits",
+ "wrapKey",
+ "unwrapKey",
+];
+
+const simpleAlgorithmDictionaries = {
+ AesGcmParams: { iv: "BufferSource", additionalData: "BufferSource" },
+ RsaHashedKeyGenParams: { hash: "HashAlgorithmIdentifier" },
+ EcKeyGenParams: {},
+ HmacKeyGenParams: { hash: "HashAlgorithmIdentifier" },
+ RsaPssParams: {},
+ EcdsaParams: { hash: "HashAlgorithmIdentifier" },
+ HmacImportParams: { hash: "HashAlgorithmIdentifier" },
+ HkdfParams: {
+ hash: "HashAlgorithmIdentifier",
+ salt: "BufferSource",
+ info: "BufferSource",
+ },
+ Pbkdf2Params: { hash: "HashAlgorithmIdentifier", salt: "BufferSource" },
+ RsaOaepParams: { label: "BufferSource" },
+ RsaHashedImportParams: { hash: "HashAlgorithmIdentifier" },
+ EcKeyImportParams: {},
+};
+
+const supportedAlgorithms = {
+ "digest": {
+ "SHA-1": null,
+ "SHA-256": null,
+ "SHA-384": null,
+ "SHA-512": null,
+ },
+ "generateKey": {
+ "RSASSA-PKCS1-v1_5": "RsaHashedKeyGenParams",
+ "RSA-PSS": "RsaHashedKeyGenParams",
+ "RSA-OAEP": "RsaHashedKeyGenParams",
+ "ECDSA": "EcKeyGenParams",
+ "ECDH": "EcKeyGenParams",
+ "AES-CTR": "AesKeyGenParams",
+ "AES-CBC": "AesKeyGenParams",
+ "AES-GCM": "AesKeyGenParams",
+ "AES-KW": "AesKeyGenParams",
+ "HMAC": "HmacKeyGenParams",
+ "X25519": null,
+ "Ed25519": null,
+ },
+ "sign": {
+ "RSASSA-PKCS1-v1_5": null,
+ "RSA-PSS": "RsaPssParams",
+ "ECDSA": "EcdsaParams",
+ "HMAC": null,
+ "Ed25519": null,
+ },
+ "verify": {
+ "RSASSA-PKCS1-v1_5": null,
+ "RSA-PSS": "RsaPssParams",
+ "ECDSA": "EcdsaParams",
+ "HMAC": null,
+ "Ed25519": null,
+ },
+ "importKey": {
+ "RSASSA-PKCS1-v1_5": "RsaHashedImportParams",
+ "RSA-PSS": "RsaHashedImportParams",
+ "RSA-OAEP": "RsaHashedImportParams",
+ "ECDSA": "EcKeyImportParams",
+ "ECDH": "EcKeyImportParams",
+ "HMAC": "HmacImportParams",
+ "HKDF": null,
+ "PBKDF2": null,
+ "AES-CTR": null,
+ "AES-CBC": null,
+ "AES-GCM": null,
+ "AES-KW": null,
+ "Ed25519": null,
+ "X25519": null,
+ },
+ "deriveBits": {
+ "HKDF": "HkdfParams",
+ "PBKDF2": "Pbkdf2Params",
+ "ECDH": "EcdhKeyDeriveParams",
+ "X25519": "EcdhKeyDeriveParams",
+ },
+ "encrypt": {
+ "RSA-OAEP": "RsaOaepParams",
+ "AES-CBC": "AesCbcParams",
+ "AES-GCM": "AesGcmParams",
+ "AES-CTR": "AesCtrParams",
+ },
+ "decrypt": {
+ "RSA-OAEP": "RsaOaepParams",
+ "AES-CBC": "AesCbcParams",
+ "AES-GCM": "AesGcmParams",
+ "AES-CTR": "AesCtrParams",
+ },
+ "get key length": {
+ "AES-CBC": "AesDerivedKeyParams",
+ "AES-CTR": "AesDerivedKeyParams",
+ "AES-GCM": "AesDerivedKeyParams",
+ "AES-KW": "AesDerivedKeyParams",
+ "HMAC": "HmacImportParams",
+ "HKDF": null,
+ "PBKDF2": null,
+ },
+ "wrapKey": {
+ "AES-KW": null,
+ },
+ "unwrapKey": {
+ "AES-KW": null,
+ },
+};
+
+const aesJwkAlg = {
+ "AES-CTR": {
+ 128: "A128CTR",
+ 192: "A192CTR",
+ 256: "A256CTR",
+ },
+ "AES-CBC": {
+ 128: "A128CBC",
+ 192: "A192CBC",
+ 256: "A256CBC",
+ },
+ "AES-GCM": {
+ 128: "A128GCM",
+ 192: "A192GCM",
+ 256: "A256GCM",
+ },
+ "AES-KW": {
+ 128: "A128KW",
+ 192: "A192KW",
+ 256: "A256KW",
+ },
+};
+
+// See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm
+// 18.4.4
+function normalizeAlgorithm(algorithm, op) {
+ if (typeof algorithm == "string") {
+ return normalizeAlgorithm({ name: algorithm }, op);
+ }
- // See https://www.w3.org/TR/WebCryptoAPI/#dfn-normalize-an-algorithm
- // 18.4.4
- function normalizeAlgorithm(algorithm, op) {
- if (typeof algorithm == "string") {
- return normalizeAlgorithm({ name: algorithm }, op);
+ // 1.
+ const registeredAlgorithms = supportedAlgorithms[op];
+ // 2. 3.
+ const initialAlg = webidl.converters.Algorithm(algorithm, {
+ prefix: "Failed to normalize algorithm",
+ context: "passed algorithm",
+ });
+ // 4.
+ let algName = initialAlg.name;
+
+ // 5.
+ let desiredType = undefined;
+ for (const key in registeredAlgorithms) {
+ if (!ObjectPrototypeHasOwnProperty(registeredAlgorithms, key)) {
+ continue;
}
+ if (
+ StringPrototypeToUpperCase(key) === StringPrototypeToUpperCase(algName)
+ ) {
+ algName = key;
+ desiredType = registeredAlgorithms[key];
+ }
+ }
+ if (desiredType === undefined) {
+ throw new DOMException(
+ "Unrecognized algorithm name",
+ "NotSupportedError",
+ );
+ }
- // 1.
- const registeredAlgorithms = supportedAlgorithms[op];
- // 2. 3.
- const initialAlg = webidl.converters.Algorithm(algorithm, {
- prefix: "Failed to normalize algorithm",
- context: "passed algorithm",
- });
- // 4.
- let algName = initialAlg.name;
+ // Fast path everything below if the registered dictionary is "None".
+ if (desiredType === null) {
+ return { name: algName };
+ }
- // 5.
- let desiredType = undefined;
- for (const key in registeredAlgorithms) {
- if (!ObjectPrototypeHasOwnProperty(registeredAlgorithms, key)) {
- continue;
- }
- if (
- StringPrototypeToUpperCase(key) === StringPrototypeToUpperCase(algName)
- ) {
- algName = key;
- desiredType = registeredAlgorithms[key];
- }
+ // 6.
+ const normalizedAlgorithm = webidl.converters[desiredType](algorithm, {
+ prefix: "Failed to normalize algorithm",
+ context: "passed algorithm",
+ });
+ // 7.
+ normalizedAlgorithm.name = algName;
+
+ // 9.
+ const dict = simpleAlgorithmDictionaries[desiredType];
+ // 10.
+ for (const member in dict) {
+ if (!ObjectPrototypeHasOwnProperty(dict, member)) {
+ continue;
}
- if (desiredType === undefined) {
- throw new DOMException(
- "Unrecognized algorithm name",
- "NotSupportedError",
+ const idlType = dict[member];
+ const idlValue = normalizedAlgorithm[member];
+ // 3.
+ if (idlType === "BufferSource" && idlValue) {
+ normalizedAlgorithm[member] = TypedArrayPrototypeSlice(
+ new Uint8Array(
+ ArrayBufferIsView(idlValue) ? idlValue.buffer : idlValue,
+ idlValue.byteOffset ?? 0,
+ idlValue.byteLength,
+ ),
);
+ } else if (idlType === "HashAlgorithmIdentifier") {
+ normalizedAlgorithm[member] = normalizeAlgorithm(idlValue, "digest");
+ } else if (idlType === "AlgorithmIdentifier") {
+ // TODO(lucacasonato): implement
+ throw new TypeError("unimplemented");
}
+ }
- // Fast path everything below if the registered dictionary is "None".
- if (desiredType === null) {
- return { name: algName };
- }
-
- // 6.
- const normalizedAlgorithm = webidl.converters[desiredType](algorithm, {
- prefix: "Failed to normalize algorithm",
- context: "passed algorithm",
- });
- // 7.
- normalizedAlgorithm.name = algName;
+ return normalizedAlgorithm;
+}
+
+/**
+ * @param {ArrayBufferView | ArrayBuffer} input
+ * @returns {Uint8Array}
+ */
+function copyBuffer(input) {
+ return TypedArrayPrototypeSlice(
+ ArrayBufferIsView(input)
+ ? new Uint8Array(input.buffer, input.byteOffset, input.byteLength)
+ : new Uint8Array(input),
+ );
+}
+
+const _handle = Symbol("[[handle]]");
+const _algorithm = Symbol("[[algorithm]]");
+const _extractable = Symbol("[[extractable]]");
+const _usages = Symbol("[[usages]]");
+const _type = Symbol("[[type]]");
+
+class CryptoKey {
+ /** @type {string} */
+ [_type];
+ /** @type {boolean} */
+ [_extractable];
+ /** @type {object} */
+ [_algorithm];
+ /** @type {string[]} */
+ [_usages];
+ /** @type {object} */
+ [_handle];
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
- // 9.
- const dict = simpleAlgorithmDictionaries[desiredType];
- // 10.
- for (const member in dict) {
- if (!ObjectPrototypeHasOwnProperty(dict, member)) {
- continue;
- }
- const idlType = dict[member];
- const idlValue = normalizedAlgorithm[member];
- // 3.
- if (idlType === "BufferSource" && idlValue) {
- normalizedAlgorithm[member] = TypedArrayPrototypeSlice(
- new Uint8Array(
- ArrayBufferIsView(idlValue) ? idlValue.buffer : idlValue,
- idlValue.byteOffset ?? 0,
- idlValue.byteLength,
- ),
- );
- } else if (idlType === "HashAlgorithmIdentifier") {
- normalizedAlgorithm[member] = normalizeAlgorithm(idlValue, "digest");
- } else if (idlType === "AlgorithmIdentifier") {
- // TODO(lucacasonato): implement
- throw new TypeError("unimplemented");
- }
- }
+ /** @returns {string} */
+ get type() {
+ webidl.assertBranded(this, CryptoKeyPrototype);
+ return this[_type];
+ }
- return normalizedAlgorithm;
+ /** @returns {boolean} */
+ get extractable() {
+ webidl.assertBranded(this, CryptoKeyPrototype);
+ return this[_extractable];
}
- /**
- * @param {ArrayBufferView | ArrayBuffer} input
- * @returns {Uint8Array}
- */
- function copyBuffer(input) {
- return TypedArrayPrototypeSlice(
- ArrayBufferIsView(input)
- ? new Uint8Array(input.buffer, input.byteOffset, input.byteLength)
- : new Uint8Array(input),
- );
+ /** @returns {string[]} */
+ get usages() {
+ webidl.assertBranded(this, CryptoKeyPrototype);
+ // TODO(lucacasonato): return a SameObject copy
+ return this[_usages];
}
- const _handle = Symbol("[[handle]]");
- const _algorithm = Symbol("[[algorithm]]");
- const _extractable = Symbol("[[extractable]]");
- const _usages = Symbol("[[usages]]");
- const _type = Symbol("[[type]]");
-
- class CryptoKey {
- /** @type {string} */
- [_type];
- /** @type {boolean} */
- [_extractable];
- /** @type {object} */
- [_algorithm];
- /** @type {string[]} */
- [_usages];
- /** @type {object} */
- [_handle];
-
- constructor() {
- webidl.illegalConstructor();
- }
+ /** @returns {object} */
+ get algorithm() {
+ webidl.assertBranded(this, CryptoKeyPrototype);
+ // TODO(lucacasonato): return a SameObject copy
+ return this[_algorithm];
+ }
- /** @returns {string} */
- get type() {
- webidl.assertBranded(this, CryptoKeyPrototype);
- return this[_type];
- }
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ type: this.type,
+ extractable: this.extractable,
+ algorithm: this.algorithm,
+ usages: this.usages,
+ })
+ }`;
+ }
+}
+
+webidl.configurePrototype(CryptoKey);
+const CryptoKeyPrototype = CryptoKey.prototype;
+
+/**
+ * @param {string} type
+ * @param {boolean} extractable
+ * @param {string[]} usages
+ * @param {object} algorithm
+ * @param {object} handle
+ * @returns
+ */
+function constructKey(type, extractable, usages, algorithm, handle) {
+ const key = webidl.createBranded(CryptoKey);
+ key[_type] = type;
+ key[_extractable] = extractable;
+ key[_usages] = usages;
+ key[_algorithm] = algorithm;
+ key[_handle] = handle;
+ return key;
+}
+
+// https://w3c.github.io/webcrypto/#concept-usage-intersection
+/**
+ * @param {string[]} a
+ * @param {string[]} b
+ * @returns
+ */
+function usageIntersection(a, b) {
+ return a.filter((i) => b.includes(i));
+}
+
+// TODO(lucacasonato): this should be moved to rust
+/** @type {WeakMap<object, object>} */
+const KEY_STORE = new WeakMap();
+
+function getKeyLength(algorithm) {
+ switch (algorithm.name) {
+ case "AES-CBC":
+ case "AES-CTR":
+ case "AES-GCM":
+ case "AES-KW": {
+ // 1.
+ if (!ArrayPrototypeIncludes([128, 192, 256], algorithm.length)) {
+ throw new DOMException(
+ "length must be 128, 192, or 256",
+ "OperationError",
+ );
+ }
- /** @returns {boolean} */
- get extractable() {
- webidl.assertBranded(this, CryptoKeyPrototype);
- return this[_extractable];
+ // 2.
+ return algorithm.length;
}
+ case "HMAC": {
+ // 1.
+ let length;
+ if (algorithm.length === undefined) {
+ switch (algorithm.hash.name) {
+ case "SHA-1":
+ length = 512;
+ break;
+ case "SHA-256":
+ length = 512;
+ break;
+ case "SHA-384":
+ length = 1024;
+ break;
+ case "SHA-512":
+ length = 1024;
+ break;
+ default:
+ throw new DOMException(
+ "Unrecognized hash algorithm",
+ "NotSupportedError",
+ );
+ }
+ } else if (algorithm.length !== 0) {
+ length = algorithm.length;
+ } else {
+ throw new TypeError("Invalid length.");
+ }
- /** @returns {string[]} */
- get usages() {
- webidl.assertBranded(this, CryptoKeyPrototype);
- // TODO(lucacasonato): return a SameObject copy
- return this[_usages];
+ // 2.
+ return length;
}
-
- /** @returns {object} */
- get algorithm() {
- webidl.assertBranded(this, CryptoKeyPrototype);
- // TODO(lucacasonato): return a SameObject copy
- return this[_algorithm];
+ case "HKDF": {
+ // 1.
+ return null;
}
-
- [SymbolFor("Deno.customInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- type: this.type,
- extractable: this.extractable,
- algorithm: this.algorithm,
- usages: this.usages,
- })
- }`;
+ case "PBKDF2": {
+ // 1.
+ return null;
}
+ default:
+ throw new TypeError("unreachable");
}
+}
- webidl.configurePrototype(CryptoKey);
- const CryptoKeyPrototype = CryptoKey.prototype;
-
- /**
- * @param {string} type
- * @param {boolean} extractable
- * @param {string[]} usages
- * @param {object} algorithm
- * @param {object} handle
- * @returns
- */
- function constructKey(type, extractable, usages, algorithm, handle) {
- const key = webidl.createBranded(CryptoKey);
- key[_type] = type;
- key[_extractable] = extractable;
- key[_usages] = usages;
- key[_algorithm] = algorithm;
- key[_handle] = handle;
- return key;
+class SubtleCrypto {
+ constructor() {
+ webidl.illegalConstructor();
}
- // https://w3c.github.io/webcrypto/#concept-usage-intersection
/**
- * @param {string[]} a
- * @param {string[]} b
- * @returns
+ * @param {string} algorithm
+ * @param {BufferSource} data
+ * @returns {Promise<Uint8Array>}
*/
- function usageIntersection(a, b) {
- return a.filter((i) => b.includes(i));
- }
+ async digest(algorithm, data) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'digest' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: "Argument 1",
+ });
+ data = webidl.converters.BufferSource(data, {
+ prefix,
+ context: "Argument 2",
+ });
- // TODO(lucacasonato): this should be moved to rust
- /** @type {WeakMap<object, object>} */
- const KEY_STORE = new WeakMap();
+ data = copyBuffer(data);
- function getKeyLength(algorithm) {
- switch (algorithm.name) {
- case "AES-CBC":
- case "AES-CTR":
- case "AES-GCM":
- case "AES-KW": {
- // 1.
- if (!ArrayPrototypeIncludes([128, 192, 256], algorithm.length)) {
- throw new DOMException(
- "length must be 128, 192, or 256",
- "OperationError",
- );
- }
+ algorithm = normalizeAlgorithm(algorithm, "digest");
- // 2.
- return algorithm.length;
- }
- case "HMAC": {
- // 1.
- let length;
- if (algorithm.length === undefined) {
- switch (algorithm.hash.name) {
- case "SHA-1":
- length = 512;
- break;
- case "SHA-256":
- length = 512;
- break;
- case "SHA-384":
- length = 1024;
- break;
- case "SHA-512":
- length = 1024;
- break;
- default:
- throw new DOMException(
- "Unrecognized hash algorithm",
- "NotSupportedError",
- );
- }
- } else if (algorithm.length !== 0) {
- length = algorithm.length;
- } else {
- throw new TypeError("Invalid length.");
- }
+ const result = await core.opAsync(
+ "op_crypto_subtle_digest",
+ algorithm.name,
+ data,
+ );
- // 2.
- return length;
- }
- case "HKDF": {
- // 1.
- return null;
- }
- case "PBKDF2": {
- // 1.
- return null;
- }
- default:
- throw new TypeError("unreachable");
- }
+ return result.buffer;
}
- class SubtleCrypto {
- constructor() {
- webidl.illegalConstructor();
- }
-
- /**
- * @param {string} algorithm
- * @param {BufferSource} data
- * @returns {Promise<Uint8Array>}
- */
- async digest(algorithm, data) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'digest' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- data = webidl.converters.BufferSource(data, {
- prefix,
- context: "Argument 2",
- });
+ /**
+ * @param {string} algorithm
+ * @param {CryptoKey} key
+ * @param {BufferSource} data
+ * @returns {Promise<any>}
+ */
+ async encrypt(algorithm, key, data) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'encrypt' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: "Argument 1",
+ });
+ key = webidl.converters.CryptoKey(key, {
+ prefix,
+ context: "Argument 2",
+ });
+ data = webidl.converters.BufferSource(data, {
+ prefix,
+ context: "Argument 3",
+ });
- data = copyBuffer(data);
+ // 2.
+ data = copyBuffer(data);
- algorithm = normalizeAlgorithm(algorithm, "digest");
+ // 3.
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, "encrypt");
- const result = await core.opAsync(
- "op_crypto_subtle_digest",
- algorithm.name,
- data,
+ // 8.
+ if (normalizedAlgorithm.name !== key[_algorithm].name) {
+ throw new DOMException(
+ "Encryption algorithm doesn't match key algorithm.",
+ "InvalidAccessError",
);
+ }
- return result.buffer;
+ // 9.
+ if (!ArrayPrototypeIncludes(key[_usages], "encrypt")) {
+ throw new DOMException(
+ "Key does not support the 'encrypt' operation.",
+ "InvalidAccessError",
+ );
}
- /**
- * @param {string} algorithm
- * @param {CryptoKey} key
- * @param {BufferSource} data
- * @returns {Promise<any>}
- */
- async encrypt(algorithm, key, data) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'encrypt' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- key = webidl.converters.CryptoKey(key, {
- prefix,
- context: "Argument 2",
- });
- data = webidl.converters.BufferSource(data, {
- prefix,
- context: "Argument 3",
- });
+ return await encrypt(normalizedAlgorithm, key, data);
+ }
- // 2.
- data = copyBuffer(data);
+ /**
+ * @param {string} algorithm
+ * @param {CryptoKey} key
+ * @param {BufferSource} data
+ * @returns {Promise<any>}
+ */
+ async decrypt(algorithm, key, data) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'decrypt' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: "Argument 1",
+ });
+ key = webidl.converters.CryptoKey(key, {
+ prefix,
+ context: "Argument 2",
+ });
+ data = webidl.converters.BufferSource(data, {
+ prefix,
+ context: "Argument 3",
+ });
- // 3.
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "encrypt");
+ // 2.
+ data = copyBuffer(data);
- // 8.
- if (normalizedAlgorithm.name !== key[_algorithm].name) {
- throw new DOMException(
- "Encryption algorithm doesn't match key algorithm.",
- "InvalidAccessError",
- );
- }
+ // 3.
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, "decrypt");
- // 9.
- if (!ArrayPrototypeIncludes(key[_usages], "encrypt")) {
- throw new DOMException(
- "Key does not support the 'encrypt' operation.",
- "InvalidAccessError",
- );
- }
+ // 8.
+ if (normalizedAlgorithm.name !== key[_algorithm].name) {
+ throw new DOMException(
+ "Decryption algorithm doesn't match key algorithm.",
+ "OperationError",
+ );
+ }
- return await encrypt(normalizedAlgorithm, key, data);
+ // 9.
+ if (!ArrayPrototypeIncludes(key[_usages], "decrypt")) {
+ throw new DOMException(
+ "Key does not support the 'decrypt' operation.",
+ "InvalidAccessError",
+ );
}
- /**
- * @param {string} algorithm
- * @param {CryptoKey} key
- * @param {BufferSource} data
- * @returns {Promise<any>}
- */
- async decrypt(algorithm, key, data) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'decrypt' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- key = webidl.converters.CryptoKey(key, {
- prefix,
- context: "Argument 2",
- });
- data = webidl.converters.BufferSource(data, {
- prefix,
- context: "Argument 3",
- });
+ const handle = key[_handle];
+ const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
- // 2.
- data = copyBuffer(data);
+ switch (normalizedAlgorithm.name) {
+ case "RSA-OAEP": {
+ // 1.
+ if (key[_type] !== "private") {
+ throw new DOMException(
+ "Key type not supported",
+ "InvalidAccessError",
+ );
+ }
- // 3.
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "decrypt");
+ // 2.
+ if (normalizedAlgorithm.label) {
+ normalizedAlgorithm.label = copyBuffer(normalizedAlgorithm.label);
+ } else {
+ normalizedAlgorithm.label = new Uint8Array();
+ }
- // 8.
- if (normalizedAlgorithm.name !== key[_algorithm].name) {
- throw new DOMException(
- "Decryption algorithm doesn't match key algorithm.",
- "OperationError",
- );
- }
+ // 3-5.
+ const hashAlgorithm = key[_algorithm].hash.name;
+ const plainText = await core.opAsync("op_crypto_decrypt", {
+ key: keyData,
+ algorithm: "RSA-OAEP",
+ hash: hashAlgorithm,
+ label: normalizedAlgorithm.label,
+ }, data);
- // 9.
- if (!ArrayPrototypeIncludes(key[_usages], "decrypt")) {
- throw new DOMException(
- "Key does not support the 'decrypt' operation.",
- "InvalidAccessError",
- );
+ // 6.
+ return plainText.buffer;
}
+ case "AES-CBC": {
+ normalizedAlgorithm.iv = copyBuffer(normalizedAlgorithm.iv);
- const handle = key[_handle];
- const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
-
- switch (normalizedAlgorithm.name) {
- case "RSA-OAEP": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
+ // 1.
+ if (normalizedAlgorithm.iv.byteLength !== 16) {
+ throw new DOMException(
+ "Counter must be 16 bytes",
+ "OperationError",
+ );
+ }
- // 2.
- if (normalizedAlgorithm.label) {
- normalizedAlgorithm.label = copyBuffer(normalizedAlgorithm.label);
- } else {
- normalizedAlgorithm.label = new Uint8Array();
- }
+ const plainText = await core.opAsync("op_crypto_decrypt", {
+ key: keyData,
+ algorithm: "AES-CBC",
+ iv: normalizedAlgorithm.iv,
+ length: key[_algorithm].length,
+ }, data);
- // 3-5.
- const hashAlgorithm = key[_algorithm].hash.name;
- const plainText = await core.opAsync("op_crypto_decrypt", {
- key: keyData,
- algorithm: "RSA-OAEP",
- hash: hashAlgorithm,
- label: normalizedAlgorithm.label,
- }, data);
+ // 6.
+ return plainText.buffer;
+ }
+ case "AES-CTR": {
+ normalizedAlgorithm.counter = copyBuffer(normalizedAlgorithm.counter);
- // 6.
- return plainText.buffer;
+ // 1.
+ if (normalizedAlgorithm.counter.byteLength !== 16) {
+ throw new DOMException(
+ "Counter vector must be 16 bytes",
+ "OperationError",
+ );
}
- case "AES-CBC": {
- normalizedAlgorithm.iv = copyBuffer(normalizedAlgorithm.iv);
-
- // 1.
- if (normalizedAlgorithm.iv.byteLength !== 16) {
- throw new DOMException(
- "Counter must be 16 bytes",
- "OperationError",
- );
- }
- const plainText = await core.opAsync("op_crypto_decrypt", {
- key: keyData,
- algorithm: "AES-CBC",
- iv: normalizedAlgorithm.iv,
- length: key[_algorithm].length,
- }, data);
-
- // 6.
- return plainText.buffer;
+ // 2.
+ if (
+ normalizedAlgorithm.length === 0 || normalizedAlgorithm.length > 128
+ ) {
+ throw new DOMException(
+ "Counter length must not be 0 or greater than 128",
+ "OperationError",
+ );
}
- case "AES-CTR": {
- normalizedAlgorithm.counter = copyBuffer(normalizedAlgorithm.counter);
- // 1.
- if (normalizedAlgorithm.counter.byteLength !== 16) {
- throw new DOMException(
- "Counter vector must be 16 bytes",
- "OperationError",
- );
- }
+ // 3.
+ const cipherText = await core.opAsync("op_crypto_decrypt", {
+ key: keyData,
+ algorithm: "AES-CTR",
+ keyLength: key[_algorithm].length,
+ counter: normalizedAlgorithm.counter,
+ ctrLength: normalizedAlgorithm.length,
+ }, data);
- // 2.
- if (
- normalizedAlgorithm.length === 0 || normalizedAlgorithm.length > 128
- ) {
- throw new DOMException(
- "Counter length must not be 0 or greater than 128",
- "OperationError",
- );
- }
+ // 4.
+ return cipherText.buffer;
+ }
+ case "AES-GCM": {
+ normalizedAlgorithm.iv = copyBuffer(normalizedAlgorithm.iv);
- // 3.
- const cipherText = await core.opAsync("op_crypto_decrypt", {
- key: keyData,
- algorithm: "AES-CTR",
- keyLength: key[_algorithm].length,
- counter: normalizedAlgorithm.counter,
- ctrLength: normalizedAlgorithm.length,
- }, data);
+ // 1.
+ if (normalizedAlgorithm.tagLength === undefined) {
+ normalizedAlgorithm.tagLength = 128;
+ } else if (
+ !ArrayPrototypeIncludes(
+ [32, 64, 96, 104, 112, 120, 128],
+ normalizedAlgorithm.tagLength,
+ )
+ ) {
+ throw new DOMException(
+ "Invalid tag length",
+ "OperationError",
+ );
+ }
- // 4.
- return cipherText.buffer;
+ // 2.
+ if (data.byteLength < normalizedAlgorithm.tagLength / 8) {
+ throw new DOMException(
+ "Tag length overflows ciphertext",
+ "OperationError",
+ );
}
- case "AES-GCM": {
- normalizedAlgorithm.iv = copyBuffer(normalizedAlgorithm.iv);
- // 1.
- if (normalizedAlgorithm.tagLength === undefined) {
- normalizedAlgorithm.tagLength = 128;
- } else if (
- !ArrayPrototypeIncludes(
- [32, 64, 96, 104, 112, 120, 128],
- normalizedAlgorithm.tagLength,
- )
- ) {
- throw new DOMException(
- "Invalid tag length",
- "OperationError",
- );
- }
+ // 3. We only support 96-bit and 128-bit nonce.
+ if (
+ ArrayPrototypeIncludes(
+ [12, 16],
+ normalizedAlgorithm.iv.byteLength,
+ ) === undefined
+ ) {
+ throw new DOMException(
+ "Initialization vector length not supported",
+ "NotSupportedError",
+ );
+ }
- // 2.
- if (data.byteLength < normalizedAlgorithm.tagLength / 8) {
+ // 4.
+ if (normalizedAlgorithm.additionalData !== undefined) {
+ if (normalizedAlgorithm.additionalData.byteLength > (2 ** 64) - 1) {
throw new DOMException(
- "Tag length overflows ciphertext",
+ "Additional data too large",
"OperationError",
);
}
+ normalizedAlgorithm.additionalData = copyBuffer(
+ normalizedAlgorithm.additionalData,
+ );
+ }
- // 3. We only support 96-bit and 128-bit nonce.
- if (
- ArrayPrototypeIncludes(
- [12, 16],
- normalizedAlgorithm.iv.byteLength,
- ) === undefined
- ) {
- throw new DOMException(
- "Initialization vector length not supported",
- "NotSupportedError",
- );
- }
-
- // 4.
- if (normalizedAlgorithm.additionalData !== undefined) {
- if (normalizedAlgorithm.additionalData.byteLength > (2 ** 64) - 1) {
- throw new DOMException(
- "Additional data too large",
- "OperationError",
- );
- }
- normalizedAlgorithm.additionalData = copyBuffer(
- normalizedAlgorithm.additionalData,
- );
- }
+ // 5-8.
+ const plaintext = await core.opAsync("op_crypto_decrypt", {
+ key: keyData,
+ algorithm: "AES-GCM",
+ length: key[_algorithm].length,
+ iv: normalizedAlgorithm.iv,
+ additionalData: normalizedAlgorithm.additionalData ||
+ null,
+ tagLength: normalizedAlgorithm.tagLength,
+ }, data);
- // 5-8.
- const plaintext = await core.opAsync("op_crypto_decrypt", {
- key: keyData,
- algorithm: "AES-GCM",
- length: key[_algorithm].length,
- iv: normalizedAlgorithm.iv,
- additionalData: normalizedAlgorithm.additionalData ||
- null,
- tagLength: normalizedAlgorithm.tagLength,
- }, data);
-
- // 9.
- return plaintext.buffer;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
+ // 9.
+ return plaintext.buffer;
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
}
+ }
- /**
- * @param {string} algorithm
- * @param {CryptoKey} key
- * @param {BufferSource} data
- * @returns {Promise<any>}
- */
- async sign(algorithm, key, data) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'sign' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- key = webidl.converters.CryptoKey(key, {
- prefix,
- context: "Argument 2",
- });
- data = webidl.converters.BufferSource(data, {
- prefix,
- context: "Argument 3",
- });
+ /**
+ * @param {string} algorithm
+ * @param {CryptoKey} key
+ * @param {BufferSource} data
+ * @returns {Promise<any>}
+ */
+ async sign(algorithm, key, data) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'sign' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: "Argument 1",
+ });
+ key = webidl.converters.CryptoKey(key, {
+ prefix,
+ context: "Argument 2",
+ });
+ data = webidl.converters.BufferSource(data, {
+ prefix,
+ context: "Argument 3",
+ });
- // 1.
- data = copyBuffer(data);
+ // 1.
+ data = copyBuffer(data);
- // 2.
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "sign");
+ // 2.
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, "sign");
- const handle = key[_handle];
- const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
+ const handle = key[_handle];
+ const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
- // 8.
- if (normalizedAlgorithm.name !== key[_algorithm].name) {
- throw new DOMException(
- "Signing algorithm doesn't match key algorithm.",
- "InvalidAccessError",
- );
- }
+ // 8.
+ if (normalizedAlgorithm.name !== key[_algorithm].name) {
+ throw new DOMException(
+ "Signing algorithm doesn't match key algorithm.",
+ "InvalidAccessError",
+ );
+ }
- // 9.
- if (!ArrayPrototypeIncludes(key[_usages], "sign")) {
- throw new DOMException(
- "Key does not support the 'sign' operation.",
- "InvalidAccessError",
- );
- }
+ // 9.
+ if (!ArrayPrototypeIncludes(key[_usages], "sign")) {
+ throw new DOMException(
+ "Key does not support the 'sign' operation.",
+ "InvalidAccessError",
+ );
+ }
- switch (normalizedAlgorithm.name) {
- case "RSASSA-PKCS1-v1_5": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
+ switch (normalizedAlgorithm.name) {
+ case "RSASSA-PKCS1-v1_5": {
+ // 1.
+ if (key[_type] !== "private") {
+ throw new DOMException(
+ "Key type not supported",
+ "InvalidAccessError",
+ );
+ }
- // 2.
- const hashAlgorithm = key[_algorithm].hash.name;
- const signature = await core.opAsync("op_crypto_sign_key", {
- key: keyData,
- algorithm: "RSASSA-PKCS1-v1_5",
- hash: hashAlgorithm,
- }, data);
+ // 2.
+ const hashAlgorithm = key[_algorithm].hash.name;
+ const signature = await core.opAsync("op_crypto_sign_key", {
+ key: keyData,
+ algorithm: "RSASSA-PKCS1-v1_5",
+ hash: hashAlgorithm,
+ }, data);
- return signature.buffer;
+ return signature.buffer;
+ }
+ case "RSA-PSS": {
+ // 1.
+ if (key[_type] !== "private") {
+ throw new DOMException(
+ "Key type not supported",
+ "InvalidAccessError",
+ );
}
- case "RSA-PSS": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
- // 2.
- const hashAlgorithm = key[_algorithm].hash.name;
- const signature = await core.opAsync("op_crypto_sign_key", {
- key: keyData,
- algorithm: "RSA-PSS",
- hash: hashAlgorithm,
- saltLength: normalizedAlgorithm.saltLength,
- }, data);
+ // 2.
+ const hashAlgorithm = key[_algorithm].hash.name;
+ const signature = await core.opAsync("op_crypto_sign_key", {
+ key: keyData,
+ algorithm: "RSA-PSS",
+ hash: hashAlgorithm,
+ saltLength: normalizedAlgorithm.saltLength,
+ }, data);
- return signature.buffer;
+ return signature.buffer;
+ }
+ case "ECDSA": {
+ // 1.
+ if (key[_type] !== "private") {
+ throw new DOMException(
+ "Key type not supported",
+ "InvalidAccessError",
+ );
}
- case "ECDSA": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
- // 2.
- const hashAlgorithm = normalizedAlgorithm.hash.name;
- const namedCurve = key[_algorithm].namedCurve;
- if (!ArrayPrototypeIncludes(supportedNamedCurves, namedCurve)) {
- throw new DOMException("Curve not supported", "NotSupportedError");
- }
+ // 2.
+ const hashAlgorithm = normalizedAlgorithm.hash.name;
+ const namedCurve = key[_algorithm].namedCurve;
+ if (!ArrayPrototypeIncludes(supportedNamedCurves, namedCurve)) {
+ throw new DOMException("Curve not supported", "NotSupportedError");
+ }
- const signature = await core.opAsync("op_crypto_sign_key", {
- key: keyData,
- algorithm: "ECDSA",
- hash: hashAlgorithm,
- namedCurve,
- }, data);
+ const signature = await core.opAsync("op_crypto_sign_key", {
+ key: keyData,
+ algorithm: "ECDSA",
+ hash: hashAlgorithm,
+ namedCurve,
+ }, data);
- return signature.buffer;
- }
- case "HMAC": {
- const hashAlgorithm = key[_algorithm].hash.name;
+ return signature.buffer;
+ }
+ case "HMAC": {
+ const hashAlgorithm = key[_algorithm].hash.name;
- const signature = await core.opAsync("op_crypto_sign_key", {
- key: keyData,
- algorithm: "HMAC",
- hash: hashAlgorithm,
- }, data);
+ const signature = await core.opAsync("op_crypto_sign_key", {
+ key: keyData,
+ algorithm: "HMAC",
+ hash: hashAlgorithm,
+ }, data);
- return signature.buffer;
+ return signature.buffer;
+ }
+ case "Ed25519": {
+ // 1.
+ if (key[_type] !== "private") {
+ throw new DOMException(
+ "Key type not supported",
+ "InvalidAccessError",
+ );
}
- case "Ed25519": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
- // https://briansmith.org/rustdoc/src/ring/ec/curve25519/ed25519/signing.rs.html#260
- const SIGNATURE_LEN = 32 * 2; // ELEM_LEN + SCALAR_LEN
- const signature = new Uint8Array(SIGNATURE_LEN);
- if (!ops.op_sign_ed25519(keyData, data, signature)) {
- throw new DOMException(
- "Failed to sign",
- "OperationError",
- );
- }
- return signature.buffer;
+ // https://briansmith.org/rustdoc/src/ring/ec/curve25519/ed25519/signing.rs.html#260
+ const SIGNATURE_LEN = 32 * 2; // ELEM_LEN + SCALAR_LEN
+ const signature = new Uint8Array(SIGNATURE_LEN);
+ if (!ops.op_sign_ed25519(keyData, data, signature)) {
+ throw new DOMException(
+ "Failed to sign",
+ "OperationError",
+ );
}
+ return signature.buffer;
}
-
- throw new TypeError("unreachable");
}
- /**
- * @param {string} format
- * @param {BufferSource} keyData
- * @param {string} algorithm
- * @param {boolean} extractable
- * @param {KeyUsages[]} keyUsages
- * @returns {Promise<any>}
- */
- // deno-lint-ignore require-await
- async importKey(format, keyData, algorithm, extractable, keyUsages) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'importKey' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 4, { prefix });
- format = webidl.converters.KeyFormat(format, {
- prefix,
- context: "Argument 1",
- });
- keyData = webidl.converters["BufferSource or JsonWebKey"](keyData, {
- prefix,
- context: "Argument 2",
- });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 3",
- });
- extractable = webidl.converters.boolean(extractable, {
- prefix,
- context: "Argument 4",
- });
- keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
- prefix,
- context: "Argument 5",
- });
+ throw new TypeError("unreachable");
+ }
- // 2.
- if (format !== "jwk") {
- if (
- ArrayBufferIsView(keyData) ||
- ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, keyData)
- ) {
- keyData = copyBuffer(keyData);
- } else {
- throw new TypeError("keyData is a JsonWebKey");
- }
+ /**
+ * @param {string} format
+ * @param {BufferSource} keyData
+ * @param {string} algorithm
+ * @param {boolean} extractable
+ * @param {KeyUsages[]} keyUsages
+ * @returns {Promise<any>}
+ */
+ // deno-lint-ignore require-await
+ async importKey(format, keyData, algorithm, extractable, keyUsages) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'importKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 4, { prefix });
+ format = webidl.converters.KeyFormat(format, {
+ prefix,
+ context: "Argument 1",
+ });
+ keyData = webidl.converters["BufferSource or JsonWebKey"](keyData, {
+ prefix,
+ context: "Argument 2",
+ });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: "Argument 3",
+ });
+ extractable = webidl.converters.boolean(extractable, {
+ prefix,
+ context: "Argument 4",
+ });
+ keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
+ prefix,
+ context: "Argument 5",
+ });
+
+ // 2.
+ if (format !== "jwk") {
+ if (
+ ArrayBufferIsView(keyData) ||
+ ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, keyData)
+ ) {
+ keyData = copyBuffer(keyData);
} else {
- if (
- ArrayBufferIsView(keyData) ||
- ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, keyData)
- ) {
- throw new TypeError("keyData is not a JsonWebKey");
- }
+ throw new TypeError("keyData is a JsonWebKey");
+ }
+ } else {
+ if (
+ ArrayBufferIsView(keyData) ||
+ ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, keyData)
+ ) {
+ throw new TypeError("keyData is not a JsonWebKey");
}
+ }
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "importKey");
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, "importKey");
- const algorithmName = normalizedAlgorithm.name;
+ const algorithmName = normalizedAlgorithm.name;
- switch (algorithmName) {
- case "HMAC": {
- return importKeyHMAC(
- format,
- normalizedAlgorithm,
- keyData,
- extractable,
- keyUsages,
- );
- }
- case "ECDH":
- case "ECDSA": {
- return importKeyEC(
- format,
- normalizedAlgorithm,
- keyData,
- extractable,
- keyUsages,
- );
- }
- case "RSASSA-PKCS1-v1_5":
- case "RSA-PSS":
- case "RSA-OAEP": {
- return importKeyRSA(
- format,
- normalizedAlgorithm,
- keyData,
- extractable,
- keyUsages,
- );
- }
- case "HKDF": {
- return importKeyHKDF(format, keyData, extractable, keyUsages);
- }
- case "PBKDF2": {
- return importKeyPBKDF2(format, keyData, extractable, keyUsages);
- }
- case "AES-CTR":
- case "AES-CBC":
- case "AES-GCM": {
- return importKeyAES(
- format,
- normalizedAlgorithm,
- keyData,
- extractable,
- keyUsages,
- ["encrypt", "decrypt", "wrapKey", "unwrapKey"],
- );
- }
- case "AES-KW": {
- return importKeyAES(
- format,
- normalizedAlgorithm,
- keyData,
- extractable,
- keyUsages,
- ["wrapKey", "unwrapKey"],
- );
- }
- case "X25519": {
- return importKeyX25519(
- format,
- keyData,
- extractable,
- keyUsages,
- );
- }
- case "Ed25519": {
- return importKeyEd25519(
- format,
- keyData,
- extractable,
- keyUsages,
- );
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
+ switch (algorithmName) {
+ case "HMAC": {
+ return importKeyHMAC(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+ );
+ }
+ case "ECDH":
+ case "ECDSA": {
+ return importKeyEC(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+ );
+ }
+ case "RSASSA-PKCS1-v1_5":
+ case "RSA-PSS":
+ case "RSA-OAEP": {
+ return importKeyRSA(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+ );
+ }
+ case "HKDF": {
+ return importKeyHKDF(format, keyData, extractable, keyUsages);
+ }
+ case "PBKDF2": {
+ return importKeyPBKDF2(format, keyData, extractable, keyUsages);
+ }
+ case "AES-CTR":
+ case "AES-CBC":
+ case "AES-GCM": {
+ return importKeyAES(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+ ["encrypt", "decrypt", "wrapKey", "unwrapKey"],
+ );
+ }
+ case "AES-KW": {
+ return importKeyAES(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+ ["wrapKey", "unwrapKey"],
+ );
+ }
+ case "X25519": {
+ return importKeyX25519(
+ format,
+ keyData,
+ extractable,
+ keyUsages,
+ );
+ }
+ case "Ed25519": {
+ return importKeyEd25519(
+ format,
+ keyData,
+ extractable,
+ keyUsages,
+ );
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
}
+ }
- /**
- * @param {string} format
- * @param {CryptoKey} key
- * @returns {Promise<any>}
- */
- // deno-lint-ignore require-await
- async exportKey(format, key) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'exportKey' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- format = webidl.converters.KeyFormat(format, {
- prefix,
- context: "Argument 1",
- });
- key = webidl.converters.CryptoKey(key, {
- prefix,
- context: "Argument 2",
- });
+ /**
+ * @param {string} format
+ * @param {CryptoKey} key
+ * @returns {Promise<any>}
+ */
+ // deno-lint-ignore require-await
+ async exportKey(format, key) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'exportKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ format = webidl.converters.KeyFormat(format, {
+ prefix,
+ context: "Argument 1",
+ });
+ key = webidl.converters.CryptoKey(key, {
+ prefix,
+ context: "Argument 2",
+ });
- const handle = key[_handle];
- // 2.
- const innerKey = WeakMapPrototypeGet(KEY_STORE, handle);
+ const handle = key[_handle];
+ // 2.
+ const innerKey = WeakMapPrototypeGet(KEY_STORE, handle);
- const algorithmName = key[_algorithm].name;
+ const algorithmName = key[_algorithm].name;
- let result;
+ let result;
- switch (algorithmName) {
- case "HMAC": {
- result = exportKeyHMAC(format, key, innerKey);
- break;
- }
- case "RSASSA-PKCS1-v1_5":
- case "RSA-PSS":
- case "RSA-OAEP": {
- result = exportKeyRSA(format, key, innerKey);
- break;
- }
- case "ECDH":
- case "ECDSA": {
- result = exportKeyEC(format, key, innerKey);
- break;
- }
- case "Ed25519": {
- result = exportKeyEd25519(format, key, innerKey);
- break;
- }
- case "X25519": {
- result = exportKeyX25519(format, key, innerKey);
- break;
- }
- case "AES-CTR":
- case "AES-CBC":
- case "AES-GCM":
- case "AES-KW": {
- result = exportKeyAES(format, key, innerKey);
- break;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
+ switch (algorithmName) {
+ case "HMAC": {
+ result = exportKeyHMAC(format, key, innerKey);
+ break;
}
-
- if (key.extractable === false) {
- throw new DOMException(
- "Key is not extractable",
- "InvalidAccessError",
- );
+ case "RSASSA-PKCS1-v1_5":
+ case "RSA-PSS":
+ case "RSA-OAEP": {
+ result = exportKeyRSA(format, key, innerKey);
+ break;
+ }
+ case "ECDH":
+ case "ECDSA": {
+ result = exportKeyEC(format, key, innerKey);
+ break;
+ }
+ case "Ed25519": {
+ result = exportKeyEd25519(format, key, innerKey);
+ break;
+ }
+ case "X25519": {
+ result = exportKeyX25519(format, key, innerKey);
+ break;
+ }
+ case "AES-CTR":
+ case "AES-CBC":
+ case "AES-GCM":
+ case "AES-KW": {
+ result = exportKeyAES(format, key, innerKey);
+ break;
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
- return result;
+ if (key.extractable === false) {
+ throw new DOMException(
+ "Key is not extractable",
+ "InvalidAccessError",
+ );
}
- /**
- * @param {AlgorithmIdentifier} algorithm
- * @param {CryptoKey} baseKey
- * @param {number | null} length
- * @returns {Promise<ArrayBuffer>}
- */
- async deriveBits(algorithm, baseKey, length) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'deriveBits' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- baseKey = webidl.converters.CryptoKey(baseKey, {
+ return result;
+ }
+
+ /**
+ * @param {AlgorithmIdentifier} algorithm
+ * @param {CryptoKey} baseKey
+ * @param {number | null} length
+ * @returns {Promise<ArrayBuffer>}
+ */
+ async deriveBits(algorithm, baseKey, length) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'deriveBits' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: "Argument 1",
+ });
+ baseKey = webidl.converters.CryptoKey(baseKey, {
+ prefix,
+ context: "Argument 2",
+ });
+ if (length !== null) {
+ length = webidl.converters["unsigned long"](length, {
prefix,
- context: "Argument 2",
+ context: "Argument 3",
});
- if (length !== null) {
- length = webidl.converters["unsigned long"](length, {
- prefix,
- context: "Argument 3",
- });
- }
+ }
- // 2.
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "deriveBits");
- // 4-6.
- const result = await deriveBits(normalizedAlgorithm, baseKey, length);
- // 7.
- if (normalizedAlgorithm.name !== baseKey[_algorithm].name) {
- throw new DOMException("Invalid algorithm name", "InvalidAccessError");
- }
- // 8.
- if (!ArrayPrototypeIncludes(baseKey[_usages], "deriveBits")) {
- throw new DOMException(
- "baseKey usages does not contain `deriveBits`",
- "InvalidAccessError",
- );
- }
- // 9-10.
- return result;
+ // 2.
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, "deriveBits");
+ // 4-6.
+ const result = await deriveBits(normalizedAlgorithm, baseKey, length);
+ // 7.
+ if (normalizedAlgorithm.name !== baseKey[_algorithm].name) {
+ throw new DOMException("Invalid algorithm name", "InvalidAccessError");
}
+ // 8.
+ if (!ArrayPrototypeIncludes(baseKey[_usages], "deriveBits")) {
+ throw new DOMException(
+ "baseKey usages does not contain `deriveBits`",
+ "InvalidAccessError",
+ );
+ }
+ // 9-10.
+ return result;
+ }
- /**
- * @param {AlgorithmIdentifier} algorithm
- * @param {CryptoKey} baseKey
- * @param {number} length
- * @returns {Promise<ArrayBuffer>}
- */
- async deriveKey(
- algorithm,
- baseKey,
+ /**
+ * @param {AlgorithmIdentifier} algorithm
+ * @param {CryptoKey} baseKey
+ * @param {number} length
+ * @returns {Promise<ArrayBuffer>}
+ */
+ async deriveKey(
+ algorithm,
+ baseKey,
+ derivedKeyType,
+ extractable,
+ keyUsages,
+ ) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'deriveKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 5, { prefix });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: "Argument 1",
+ });
+ baseKey = webidl.converters.CryptoKey(baseKey, {
+ prefix,
+ context: "Argument 2",
+ });
+ derivedKeyType = webidl.converters.AlgorithmIdentifier(derivedKeyType, {
+ prefix,
+ context: "Argument 3",
+ });
+ extractable = webidl.converters["boolean"](extractable, {
+ prefix,
+ context: "Argument 4",
+ });
+ keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
+ prefix,
+ context: "Argument 5",
+ });
+
+ // 2-3.
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, "deriveBits");
+
+ // 4-5.
+ const normalizedDerivedKeyAlgorithmImport = normalizeAlgorithm(
derivedKeyType,
+ "importKey",
+ );
+
+ // 6-7.
+ const normalizedDerivedKeyAlgorithmLength = normalizeAlgorithm(
+ derivedKeyType,
+ "get key length",
+ );
+
+ // 8-10.
+
+ // 11.
+ if (normalizedAlgorithm.name !== baseKey[_algorithm].name) {
+ throw new DOMException(
+ "Invalid algorithm name",
+ "InvalidAccessError",
+ );
+ }
+
+ // 12.
+ if (!ArrayPrototypeIncludes(baseKey[_usages], "deriveKey")) {
+ throw new DOMException(
+ "baseKey usages does not contain `deriveKey`",
+ "InvalidAccessError",
+ );
+ }
+
+ // 13.
+ const length = getKeyLength(normalizedDerivedKeyAlgorithmLength);
+
+ // 14.
+ const secret = await this.deriveBits(
+ normalizedAlgorithm,
+ baseKey,
+ length,
+ );
+
+ // 15.
+ const result = await this.importKey(
+ "raw",
+ secret,
+ normalizedDerivedKeyAlgorithmImport,
extractable,
keyUsages,
+ );
+
+ // 16.
+ if (
+ ArrayPrototypeIncludes(["private", "secret"], result[_type]) &&
+ keyUsages.length == 0
) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'deriveKey' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 5, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- baseKey = webidl.converters.CryptoKey(baseKey, {
- prefix,
- context: "Argument 2",
- });
- derivedKeyType = webidl.converters.AlgorithmIdentifier(derivedKeyType, {
- prefix,
- context: "Argument 3",
- });
- extractable = webidl.converters["boolean"](extractable, {
- prefix,
- context: "Argument 4",
- });
- keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
- prefix,
- context: "Argument 5",
- });
+ throw new SyntaxError("Invalid key usages");
+ }
+ // 17.
+ return result;
+ }
- // 2-3.
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "deriveBits");
+ /**
+ * @param {string} algorithm
+ * @param {CryptoKey} key
+ * @param {BufferSource} signature
+ * @param {BufferSource} data
+ * @returns {Promise<boolean>}
+ */
+ async verify(algorithm, key, signature, data) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'verify' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 4, { prefix });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: "Argument 1",
+ });
+ key = webidl.converters.CryptoKey(key, {
+ prefix,
+ context: "Argument 2",
+ });
+ signature = webidl.converters.BufferSource(signature, {
+ prefix,
+ context: "Argument 3",
+ });
+ data = webidl.converters.BufferSource(data, {
+ prefix,
+ context: "Argument 4",
+ });
- // 4-5.
- const normalizedDerivedKeyAlgorithmImport = normalizeAlgorithm(
- derivedKeyType,
- "importKey",
+ // 2.
+ signature = copyBuffer(signature);
+
+ // 3.
+ data = copyBuffer(data);
+
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, "verify");
+
+ const handle = key[_handle];
+ const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
+
+ if (normalizedAlgorithm.name !== key[_algorithm].name) {
+ throw new DOMException(
+ "Verifying algorithm doesn't match key algorithm.",
+ "InvalidAccessError",
);
+ }
- // 6-7.
- const normalizedDerivedKeyAlgorithmLength = normalizeAlgorithm(
- derivedKeyType,
- "get key length",
+ if (!ArrayPrototypeIncludes(key[_usages], "verify")) {
+ throw new DOMException(
+ "Key does not support the 'verify' operation.",
+ "InvalidAccessError",
);
+ }
- // 8-10.
+ switch (normalizedAlgorithm.name) {
+ case "RSASSA-PKCS1-v1_5": {
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key type not supported",
+ "InvalidAccessError",
+ );
+ }
- // 11.
- if (normalizedAlgorithm.name !== baseKey[_algorithm].name) {
- throw new DOMException(
- "Invalid algorithm name",
- "InvalidAccessError",
- );
+ const hashAlgorithm = key[_algorithm].hash.name;
+ return await core.opAsync("op_crypto_verify_key", {
+ key: keyData,
+ algorithm: "RSASSA-PKCS1-v1_5",
+ hash: hashAlgorithm,
+ signature,
+ }, data);
}
+ case "RSA-PSS": {
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key type not supported",
+ "InvalidAccessError",
+ );
+ }
- // 12.
- if (!ArrayPrototypeIncludes(baseKey[_usages], "deriveKey")) {
- throw new DOMException(
- "baseKey usages does not contain `deriveKey`",
- "InvalidAccessError",
- );
+ const hashAlgorithm = key[_algorithm].hash.name;
+ return await core.opAsync("op_crypto_verify_key", {
+ key: keyData,
+ algorithm: "RSA-PSS",
+ hash: hashAlgorithm,
+ signature,
+ }, data);
}
+ case "HMAC": {
+ const hash = key[_algorithm].hash.name;
+ return await core.opAsync("op_crypto_verify_key", {
+ key: keyData,
+ algorithm: "HMAC",
+ hash,
+ signature,
+ }, data);
+ }
+ case "ECDSA": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key type not supported",
+ "InvalidAccessError",
+ );
+ }
+ // 2.
+ const hash = normalizedAlgorithm.hash.name;
- // 13.
- const length = getKeyLength(normalizedDerivedKeyAlgorithmLength);
-
- // 14.
- const secret = await this.deriveBits(
- normalizedAlgorithm,
- baseKey,
- length,
- );
-
- // 15.
- const result = await this.importKey(
- "raw",
- secret,
- normalizedDerivedKeyAlgorithmImport,
- extractable,
- keyUsages,
- );
+ // 3-8.
+ return await core.opAsync("op_crypto_verify_key", {
+ key: keyData,
+ algorithm: "ECDSA",
+ hash,
+ signature,
+ namedCurve: key[_algorithm].namedCurve,
+ }, data);
+ }
+ case "Ed25519": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key type not supported",
+ "InvalidAccessError",
+ );
+ }
- // 16.
- if (
- ArrayPrototypeIncludes(["private", "secret"], result[_type]) &&
- keyUsages.length == 0
- ) {
- throw new SyntaxError("Invalid key usages");
+ return ops.op_verify_ed25519(keyData, data, signature);
}
- // 17.
- return result;
}
- /**
- * @param {string} algorithm
- * @param {CryptoKey} key
- * @param {BufferSource} signature
- * @param {BufferSource} data
- * @returns {Promise<boolean>}
- */
- async verify(algorithm, key, signature, data) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'verify' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 4, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- key = webidl.converters.CryptoKey(key, {
- prefix,
- context: "Argument 2",
- });
- signature = webidl.converters.BufferSource(signature, {
- prefix,
- context: "Argument 3",
- });
- data = webidl.converters.BufferSource(data, {
- prefix,
- context: "Argument 4",
- });
+ throw new TypeError("unreachable");
+ }
- // 2.
- signature = copyBuffer(signature);
+ /**
+ * @param {string} algorithm
+ * @param {boolean} extractable
+ * @param {KeyUsage[]} keyUsages
+ * @returns {Promise<any>}
+ */
+ async wrapKey(format, key, wrappingKey, wrapAlgorithm) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'wrapKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 4, { prefix });
+ format = webidl.converters.KeyFormat(format, {
+ prefix,
+ context: "Argument 1",
+ });
+ key = webidl.converters.CryptoKey(key, {
+ prefix,
+ context: "Argument 2",
+ });
+ wrappingKey = webidl.converters.CryptoKey(wrappingKey, {
+ prefix,
+ context: "Argument 3",
+ });
+ wrapAlgorithm = webidl.converters.AlgorithmIdentifier(wrapAlgorithm, {
+ prefix,
+ context: "Argument 4",
+ });
+
+ let normalizedAlgorithm;
+ try {
+ // 2.
+ normalizedAlgorithm = normalizeAlgorithm(wrapAlgorithm, "wrapKey");
+ } catch (_) {
// 3.
- data = copyBuffer(data);
+ normalizedAlgorithm = normalizeAlgorithm(wrapAlgorithm, "encrypt");
+ }
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "verify");
+ // 8.
+ if (normalizedAlgorithm.name !== wrappingKey[_algorithm].name) {
+ throw new DOMException(
+ "Wrapping algorithm doesn't match key algorithm.",
+ "InvalidAccessError",
+ );
+ }
- const handle = key[_handle];
- const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
+ // 9.
+ if (!ArrayPrototypeIncludes(wrappingKey[_usages], "wrapKey")) {
+ throw new DOMException(
+ "Key does not support the 'wrapKey' operation.",
+ "InvalidAccessError",
+ );
+ }
- if (normalizedAlgorithm.name !== key[_algorithm].name) {
- throw new DOMException(
- "Verifying algorithm doesn't match key algorithm.",
- "InvalidAccessError",
- );
- }
+ // 10. NotSupportedError will be thrown in step 12.
+ // 11.
+ if (key[_extractable] === false) {
+ throw new DOMException(
+ "Key is not extractable",
+ "InvalidAccessError",
+ );
+ }
- if (!ArrayPrototypeIncludes(key[_usages], "verify")) {
- throw new DOMException(
- "Key does not support the 'verify' operation.",
- "InvalidAccessError",
- );
+ // 12.
+ const exportedKey = await this.exportKey(format, key);
+
+ let bytes;
+ // 13.
+ if (format !== "jwk") {
+ bytes = new Uint8Array(exportedKey);
+ } else {
+ const jwk = JSONStringify(exportedKey);
+ const ret = new Uint8Array(jwk.length);
+ for (let i = 0; i < jwk.length; i++) {
+ ret[i] = StringPrototypeCharCodeAt(jwk, i);
}
+ bytes = ret;
+ }
- switch (normalizedAlgorithm.name) {
- case "RSASSA-PKCS1-v1_5": {
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
+ // 14-15.
+ if (
+ supportedAlgorithms["wrapKey"][normalizedAlgorithm.name] !== undefined
+ ) {
+ const handle = wrappingKey[_handle];
+ const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
- const hashAlgorithm = key[_algorithm].hash.name;
- return await core.opAsync("op_crypto_verify_key", {
+ switch (normalizedAlgorithm.name) {
+ case "AES-KW": {
+ const cipherText = await ops.op_crypto_wrap_key({
key: keyData,
- algorithm: "RSASSA-PKCS1-v1_5",
- hash: hashAlgorithm,
- signature,
- }, data);
- }
- case "RSA-PSS": {
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
+ algorithm: normalizedAlgorithm.name,
+ }, bytes);
- const hashAlgorithm = key[_algorithm].hash.name;
- return await core.opAsync("op_crypto_verify_key", {
- key: keyData,
- algorithm: "RSA-PSS",
- hash: hashAlgorithm,
- signature,
- }, data);
+ // 4.
+ return cipherText.buffer;
}
- case "HMAC": {
- const hash = key[_algorithm].hash.name;
- return await core.opAsync("op_crypto_verify_key", {
- key: keyData,
- algorithm: "HMAC",
- hash,
- signature,
- }, data);
+ default: {
+ throw new DOMException(
+ "Not implemented",
+ "NotSupportedError",
+ );
}
- case "ECDSA": {
- // 1.
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
- // 2.
- const hash = normalizedAlgorithm.hash.name;
+ }
+ } else if (
+ supportedAlgorithms["encrypt"][normalizedAlgorithm.name] !== undefined
+ ) {
+ // must construct a new key, since keyUsages is ["wrapKey"] and not ["encrypt"]
+ return await encrypt(
+ normalizedAlgorithm,
+ constructKey(
+ wrappingKey[_type],
+ wrappingKey[_extractable],
+ ["encrypt"],
+ wrappingKey[_algorithm],
+ wrappingKey[_handle],
+ ),
+ bytes,
+ );
+ } else {
+ throw new DOMException(
+ "Algorithm not supported",
+ "NotSupportedError",
+ );
+ }
+ }
+ /**
+ * @param {string} format
+ * @param {BufferSource} wrappedKey
+ * @param {CryptoKey} unwrappingKey
+ * @param {AlgorithmIdentifier} unwrapAlgorithm
+ * @param {AlgorithmIdentifier} unwrappedKeyAlgorithm
+ * @param {boolean} extractable
+ * @param {KeyUsage[]} keyUsages
+ * @returns {Promise<CryptoKey>}
+ */
+ async unwrapKey(
+ format,
+ wrappedKey,
+ unwrappingKey,
+ unwrapAlgorithm,
+ unwrappedKeyAlgorithm,
+ extractable,
+ keyUsages,
+ ) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'unwrapKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 7, { prefix });
+ format = webidl.converters.KeyFormat(format, {
+ prefix,
+ context: "Argument 1",
+ });
+ wrappedKey = webidl.converters.BufferSource(wrappedKey, {
+ prefix,
+ context: "Argument 2",
+ });
+ unwrappingKey = webidl.converters.CryptoKey(unwrappingKey, {
+ prefix,
+ context: "Argument 3",
+ });
+ unwrapAlgorithm = webidl.converters.AlgorithmIdentifier(unwrapAlgorithm, {
+ prefix,
+ context: "Argument 4",
+ });
+ unwrappedKeyAlgorithm = webidl.converters.AlgorithmIdentifier(
+ unwrappedKeyAlgorithm,
+ {
+ prefix,
+ context: "Argument 5",
+ },
+ );
+ extractable = webidl.converters.boolean(extractable, {
+ prefix,
+ context: "Argument 6",
+ });
+ keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
+ prefix,
+ context: "Argument 7",
+ });
- // 3-8.
- return await core.opAsync("op_crypto_verify_key", {
- key: keyData,
- algorithm: "ECDSA",
- hash,
- signature,
- namedCurve: key[_algorithm].namedCurve,
- }, data);
- }
- case "Ed25519": {
- // 1.
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
+ // 2.
+ wrappedKey = copyBuffer(wrappedKey);
- return ops.op_verify_ed25519(keyData, data, signature);
- }
- }
+ let normalizedAlgorithm;
- throw new TypeError("unreachable");
+ try {
+ // 3.
+ normalizedAlgorithm = normalizeAlgorithm(unwrapAlgorithm, "unwrapKey");
+ } catch (_) {
+ // 4.
+ normalizedAlgorithm = normalizeAlgorithm(unwrapAlgorithm, "decrypt");
}
- /**
- * @param {string} algorithm
- * @param {boolean} extractable
- * @param {KeyUsage[]} keyUsages
- * @returns {Promise<any>}
- */
- async wrapKey(format, key, wrappingKey, wrapAlgorithm) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'wrapKey' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 4, { prefix });
- format = webidl.converters.KeyFormat(format, {
- prefix,
- context: "Argument 1",
- });
- key = webidl.converters.CryptoKey(key, {
- prefix,
- context: "Argument 2",
- });
- wrappingKey = webidl.converters.CryptoKey(wrappingKey, {
- prefix,
- context: "Argument 3",
- });
- wrapAlgorithm = webidl.converters.AlgorithmIdentifier(wrapAlgorithm, {
- prefix,
- context: "Argument 4",
- });
+ // 6.
+ const normalizedKeyAlgorithm = normalizeAlgorithm(
+ unwrappedKeyAlgorithm,
+ "importKey",
+ );
- let normalizedAlgorithm;
+ // 11.
+ if (normalizedAlgorithm.name !== unwrappingKey[_algorithm].name) {
+ throw new DOMException(
+ "Unwrapping algorithm doesn't match key algorithm.",
+ "InvalidAccessError",
+ );
+ }
- try {
- // 2.
- normalizedAlgorithm = normalizeAlgorithm(wrapAlgorithm, "wrapKey");
- } catch (_) {
- // 3.
- normalizedAlgorithm = normalizeAlgorithm(wrapAlgorithm, "encrypt");
- }
+ // 12.
+ if (!ArrayPrototypeIncludes(unwrappingKey[_usages], "unwrapKey")) {
+ throw new DOMException(
+ "Key does not support the 'unwrapKey' operation.",
+ "InvalidAccessError",
+ );
+ }
- // 8.
- if (normalizedAlgorithm.name !== wrappingKey[_algorithm].name) {
- throw new DOMException(
- "Wrapping algorithm doesn't match key algorithm.",
- "InvalidAccessError",
- );
- }
+ // 13.
+ let key;
+ if (
+ supportedAlgorithms["unwrapKey"][normalizedAlgorithm.name] !== undefined
+ ) {
+ const handle = unwrappingKey[_handle];
+ const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
- // 9.
- if (!ArrayPrototypeIncludes(wrappingKey[_usages], "wrapKey")) {
- throw new DOMException(
- "Key does not support the 'wrapKey' operation.",
- "InvalidAccessError",
- );
+ switch (normalizedAlgorithm.name) {
+ case "AES-KW": {
+ const plainText = await ops.op_crypto_unwrap_key({
+ key: keyData,
+ algorithm: normalizedAlgorithm.name,
+ }, wrappedKey);
+
+ // 4.
+ key = plainText.buffer;
+ break;
+ }
+ default: {
+ throw new DOMException(
+ "Not implemented",
+ "NotSupportedError",
+ );
+ }
}
+ } else if (
+ supportedAlgorithms["decrypt"][normalizedAlgorithm.name] !== undefined
+ ) {
+ // must construct a new key, since keyUsages is ["unwrapKey"] and not ["decrypt"]
+ key = await this.decrypt(
+ normalizedAlgorithm,
+ constructKey(
+ unwrappingKey[_type],
+ unwrappingKey[_extractable],
+ ["decrypt"],
+ unwrappingKey[_algorithm],
+ unwrappingKey[_handle],
+ ),
+ wrappedKey,
+ );
+ } else {
+ throw new DOMException(
+ "Algorithm not supported",
+ "NotSupportedError",
+ );
+ }
- // 10. NotSupportedError will be thrown in step 12.
- // 11.
- if (key[_extractable] === false) {
- throw new DOMException(
- "Key is not extractable",
- "InvalidAccessError",
- );
+ let bytes;
+ // 14.
+ if (format !== "jwk") {
+ bytes = key;
+ } else {
+ const k = new Uint8Array(key);
+ let str = "";
+ for (let i = 0; i < k.length; i++) {
+ str += StringFromCharCode(k[i]);
}
+ bytes = JSONParse(str);
+ }
- // 12.
- const exportedKey = await this.exportKey(format, key);
+ // 15.
+ const result = await this.importKey(
+ format,
+ bytes,
+ normalizedKeyAlgorithm,
+ extractable,
+ keyUsages,
+ );
+ // 16.
+ if (
+ (result[_type] == "secret" || result[_type] == "private") &&
+ keyUsages.length == 0
+ ) {
+ throw new SyntaxError("Invalid key type.");
+ }
+ // 17.
+ result[_extractable] = extractable;
+ // 18.
+ result[_usages] = usageIntersection(keyUsages, recognisedUsages);
+ // 19.
+ return result;
+ }
- let bytes;
- // 13.
- if (format !== "jwk") {
- bytes = new Uint8Array(exportedKey);
- } else {
- const jwk = JSONStringify(exportedKey);
- const ret = new Uint8Array(jwk.length);
- for (let i = 0; i < jwk.length; i++) {
- ret[i] = StringPrototypeCharCodeAt(jwk, i);
- }
- bytes = ret;
+ /**
+ * @param {string} algorithm
+ * @param {boolean} extractable
+ * @param {KeyUsage[]} keyUsages
+ * @returns {Promise<any>}
+ */
+ async generateKey(algorithm, extractable, keyUsages) {
+ webidl.assertBranded(this, SubtleCryptoPrototype);
+ const prefix = "Failed to execute 'generateKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: "Argument 1",
+ });
+ extractable = webidl.converters["boolean"](extractable, {
+ prefix,
+ context: "Argument 2",
+ });
+ keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
+ prefix,
+ context: "Argument 3",
+ });
+
+ const usages = keyUsages;
+
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, "generateKey");
+ const result = await generateKey(
+ normalizedAlgorithm,
+ extractable,
+ usages,
+ );
+
+ if (ObjectPrototypeIsPrototypeOf(CryptoKeyPrototype, result)) {
+ const type = result[_type];
+ if ((type === "secret" || type === "private") && usages.length === 0) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
}
+ } else if (
+ ObjectPrototypeIsPrototypeOf(CryptoKeyPrototype, result.privateKey)
+ ) {
+ if (result.privateKey[_usages].length === 0) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+ }
- // 14-15.
- if (
- supportedAlgorithms["wrapKey"][normalizedAlgorithm.name] !== undefined
- ) {
- const handle = wrappingKey[_handle];
- const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
+ return result;
+ }
+}
+const SubtleCryptoPrototype = SubtleCrypto.prototype;
- switch (normalizedAlgorithm.name) {
- case "AES-KW": {
- const cipherText = await ops.op_crypto_wrap_key({
- key: keyData,
- algorithm: normalizedAlgorithm.name,
- }, bytes);
+async function generateKey(normalizedAlgorithm, extractable, usages) {
+ const algorithmName = normalizedAlgorithm.name;
- // 4.
- return cipherText.buffer;
- }
- default: {
- throw new DOMException(
- "Not implemented",
- "NotSupportedError",
- );
- }
- }
- } else if (
- supportedAlgorithms["encrypt"][normalizedAlgorithm.name] !== undefined
+ switch (algorithmName) {
+ case "RSASSA-PKCS1-v1_5":
+ case "RSA-PSS": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ usages,
+ (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
+ ) !== undefined
) {
- // must construct a new key, since keyUsages is ["wrapKey"] and not ["encrypt"]
- return await encrypt(
- normalizedAlgorithm,
- constructKey(
- wrappingKey[_type],
- wrappingKey[_extractable],
- ["encrypt"],
- wrappingKey[_algorithm],
- wrappingKey[_handle],
- ),
- bytes,
- );
- } else {
- throw new DOMException(
- "Algorithm not supported",
- "NotSupportedError",
- );
+ throw new DOMException("Invalid key usages", "SyntaxError");
}
- }
- /**
- * @param {string} format
- * @param {BufferSource} wrappedKey
- * @param {CryptoKey} unwrappingKey
- * @param {AlgorithmIdentifier} unwrapAlgorithm
- * @param {AlgorithmIdentifier} unwrappedKeyAlgorithm
- * @param {boolean} extractable
- * @param {KeyUsage[]} keyUsages
- * @returns {Promise<CryptoKey>}
- */
- async unwrapKey(
- format,
- wrappedKey,
- unwrappingKey,
- unwrapAlgorithm,
- unwrappedKeyAlgorithm,
- extractable,
- keyUsages,
- ) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'unwrapKey' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 7, { prefix });
- format = webidl.converters.KeyFormat(format, {
- prefix,
- context: "Argument 1",
- });
- wrappedKey = webidl.converters.BufferSource(wrappedKey, {
- prefix,
- context: "Argument 2",
- });
- unwrappingKey = webidl.converters.CryptoKey(unwrappingKey, {
- prefix,
- context: "Argument 3",
- });
- unwrapAlgorithm = webidl.converters.AlgorithmIdentifier(unwrapAlgorithm, {
- prefix,
- context: "Argument 4",
- });
- unwrappedKeyAlgorithm = webidl.converters.AlgorithmIdentifier(
- unwrappedKeyAlgorithm,
+
+ // 2.
+ const keyData = await core.opAsync(
+ "op_crypto_generate_key",
{
- prefix,
- context: "Argument 5",
+ algorithm: "RSA",
+ modulusLength: normalizedAlgorithm.modulusLength,
+ publicExponent: normalizedAlgorithm.publicExponent,
},
);
- extractable = webidl.converters.boolean(extractable, {
- prefix,
- context: "Argument 6",
- });
- keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
- prefix,
- context: "Argument 7",
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "private",
+ data: keyData,
});
- // 2.
- wrappedKey = copyBuffer(wrappedKey);
+ // 4-8.
+ const algorithm = {
+ name: algorithmName,
+ modulusLength: normalizedAlgorithm.modulusLength,
+ publicExponent: normalizedAlgorithm.publicExponent,
+ hash: normalizedAlgorithm.hash,
+ };
+
+ // 9-13.
+ const publicKey = constructKey(
+ "public",
+ true,
+ usageIntersection(usages, ["verify"]),
+ algorithm,
+ handle,
+ );
- let normalizedAlgorithm;
+ // 14-18.
+ const privateKey = constructKey(
+ "private",
+ extractable,
+ usageIntersection(usages, ["sign"]),
+ algorithm,
+ handle,
+ );
- try {
- // 3.
- normalizedAlgorithm = normalizeAlgorithm(unwrapAlgorithm, "unwrapKey");
- } catch (_) {
- // 4.
- normalizedAlgorithm = normalizeAlgorithm(unwrapAlgorithm, "decrypt");
+ // 19-22.
+ return { publicKey, privateKey };
+ }
+ case "RSA-OAEP": {
+ if (
+ ArrayPrototypeFind(
+ usages,
+ (u) =>
+ !ArrayPrototypeIncludes([
+ "encrypt",
+ "decrypt",
+ "wrapKey",
+ "unwrapKey",
+ ], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
}
- // 6.
- const normalizedKeyAlgorithm = normalizeAlgorithm(
- unwrappedKeyAlgorithm,
- "importKey",
+ // 2.
+ const keyData = await core.opAsync(
+ "op_crypto_generate_key",
+ {
+ algorithm: "RSA",
+ modulusLength: normalizedAlgorithm.modulusLength,
+ publicExponent: normalizedAlgorithm.publicExponent,
+ },
);
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "private",
+ data: keyData,
+ });
- // 11.
- if (normalizedAlgorithm.name !== unwrappingKey[_algorithm].name) {
- throw new DOMException(
- "Unwrapping algorithm doesn't match key algorithm.",
- "InvalidAccessError",
- );
- }
+ // 4-8.
+ const algorithm = {
+ name: algorithmName,
+ modulusLength: normalizedAlgorithm.modulusLength,
+ publicExponent: normalizedAlgorithm.publicExponent,
+ hash: normalizedAlgorithm.hash,
+ };
+
+ // 9-13.
+ const publicKey = constructKey(
+ "public",
+ true,
+ usageIntersection(usages, ["encrypt", "wrapKey"]),
+ algorithm,
+ handle,
+ );
- // 12.
- if (!ArrayPrototypeIncludes(unwrappingKey[_usages], "unwrapKey")) {
- throw new DOMException(
- "Key does not support the 'unwrapKey' operation.",
- "InvalidAccessError",
- );
+ // 14-18.
+ const privateKey = constructKey(
+ "private",
+ extractable,
+ usageIntersection(usages, ["decrypt", "unwrapKey"]),
+ algorithm,
+ handle,
+ );
+
+ // 19-22.
+ return { publicKey, privateKey };
+ }
+ case "ECDSA": {
+ const namedCurve = normalizedAlgorithm.namedCurve;
+
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ usages,
+ (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
}
- // 13.
- let key;
+ // 2-3.
+ const handle = {};
if (
- supportedAlgorithms["unwrapKey"][normalizedAlgorithm.name] !== undefined
+ ArrayPrototypeIncludes(
+ supportedNamedCurves,
+ namedCurve,
+ )
) {
- const handle = unwrappingKey[_handle];
- const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
+ const keyData = await core.opAsync("op_crypto_generate_key", {
+ algorithm: "EC",
+ namedCurve,
+ });
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "private",
+ data: keyData,
+ });
+ } else {
+ throw new DOMException("Curve not supported", "NotSupportedError");
+ }
- switch (normalizedAlgorithm.name) {
- case "AES-KW": {
- const plainText = await ops.op_crypto_unwrap_key({
- key: keyData,
- algorithm: normalizedAlgorithm.name,
- }, wrappedKey);
+ // 4-6.
+ const algorithm = {
+ name: algorithmName,
+ namedCurve,
+ };
+
+ // 7-11.
+ const publicKey = constructKey(
+ "public",
+ true,
+ usageIntersection(usages, ["verify"]),
+ algorithm,
+ handle,
+ );
- // 4.
- key = plainText.buffer;
- break;
- }
- default: {
- throw new DOMException(
- "Not implemented",
- "NotSupportedError",
- );
- }
- }
- } else if (
- supportedAlgorithms["decrypt"][normalizedAlgorithm.name] !== undefined
+ // 12-16.
+ const privateKey = constructKey(
+ "private",
+ extractable,
+ usageIntersection(usages, ["sign"]),
+ algorithm,
+ handle,
+ );
+
+ // 17-20.
+ return { publicKey, privateKey };
+ }
+ case "ECDH": {
+ const namedCurve = normalizedAlgorithm.namedCurve;
+
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ usages,
+ (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
+ ) !== undefined
) {
- // must construct a new key, since keyUsages is ["unwrapKey"] and not ["decrypt"]
- key = await this.decrypt(
- normalizedAlgorithm,
- constructKey(
- unwrappingKey[_type],
- unwrappingKey[_extractable],
- ["decrypt"],
- unwrappingKey[_algorithm],
- unwrappingKey[_handle],
- ),
- wrappedKey,
- );
- } else {
- throw new DOMException(
- "Algorithm not supported",
- "NotSupportedError",
- );
+ throw new DOMException("Invalid key usages", "SyntaxError");
}
- let bytes;
- // 14.
- if (format !== "jwk") {
- bytes = key;
+ // 2-3.
+ const handle = {};
+ if (
+ ArrayPrototypeIncludes(
+ supportedNamedCurves,
+ namedCurve,
+ )
+ ) {
+ const keyData = await core.opAsync("op_crypto_generate_key", {
+ algorithm: "EC",
+ namedCurve,
+ });
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "private",
+ data: keyData,
+ });
} else {
- const k = new Uint8Array(key);
- let str = "";
- for (let i = 0; i < k.length; i++) {
- str += StringFromCharCode(k[i]);
- }
- bytes = JSONParse(str);
+ throw new DOMException("Curve not supported", "NotSupportedError");
}
- // 15.
- const result = await this.importKey(
- format,
- bytes,
- normalizedKeyAlgorithm,
+ // 4-6.
+ const algorithm = {
+ name: algorithmName,
+ namedCurve,
+ };
+
+ // 7-11.
+ const publicKey = constructKey(
+ "public",
+ true,
+ usageIntersection(usages, []),
+ algorithm,
+ handle,
+ );
+
+ // 12-16.
+ const privateKey = constructKey(
+ "private",
extractable,
- keyUsages,
+ usageIntersection(usages, ["deriveKey", "deriveBits"]),
+ algorithm,
+ handle,
);
- // 16.
+
+ // 17-20.
+ return { publicKey, privateKey };
+ }
+ case "AES-CTR":
+ case "AES-CBC":
+ case "AES-GCM": {
+ // 1.
if (
- (result[_type] == "secret" || result[_type] == "private") &&
- keyUsages.length == 0
+ ArrayPrototypeFind(
+ usages,
+ (u) =>
+ !ArrayPrototypeIncludes([
+ "encrypt",
+ "decrypt",
+ "wrapKey",
+ "unwrapKey",
+ ], u),
+ ) !== undefined
) {
- throw new SyntaxError("Invalid key type.");
- }
- // 17.
- result[_extractable] = extractable;
- // 18.
- result[_usages] = usageIntersection(keyUsages, recognisedUsages);
- // 19.
- return result;
- }
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- /**
- * @param {string} algorithm
- * @param {boolean} extractable
- * @param {KeyUsage[]} keyUsages
- * @returns {Promise<any>}
- */
- async generateKey(algorithm, extractable, keyUsages) {
- webidl.assertBranded(this, SubtleCryptoPrototype);
- const prefix = "Failed to execute 'generateKey' on 'SubtleCrypto'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
- prefix,
- context: "Argument 1",
- });
- extractable = webidl.converters["boolean"](extractable, {
- prefix,
- context: "Argument 2",
- });
- keyUsages = webidl.converters["sequence<KeyUsage>"](keyUsages, {
- prefix,
- context: "Argument 3",
- });
+ return generateKeyAES(normalizedAlgorithm, extractable, usages);
+ }
+ case "AES-KW": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ usages,
+ (u) => !ArrayPrototypeIncludes(["wrapKey", "unwrapKey"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- const usages = keyUsages;
+ return generateKeyAES(normalizedAlgorithm, extractable, usages);
+ }
+ case "X25519": {
+ if (
+ ArrayPrototypeFind(
+ usages,
+ (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+ const privateKeyData = new Uint8Array(32);
+ const publicKeyData = new Uint8Array(32);
+ ops.op_generate_x25519_keypair(privateKeyData, publicKeyData);
+
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
+
+ const publicHandle = {};
+ WeakMapPrototypeSet(KEY_STORE, publicHandle, publicKeyData);
+
+ const algorithm = {
+ name: algorithmName,
+ };
+
+ const publicKey = constructKey(
+ "public",
+ true,
+ usageIntersection(usages, []),
+ algorithm,
+ publicHandle,
+ );
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, "generateKey");
- const result = await generateKey(
- normalizedAlgorithm,
+ const privateKey = constructKey(
+ "private",
extractable,
- usages,
+ usageIntersection(usages, ["deriveKey", "deriveBits"]),
+ algorithm,
+ handle,
);
- if (ObjectPrototypeIsPrototypeOf(CryptoKeyPrototype, result)) {
- const type = result[_type];
- if ((type === "secret" || type === "private") && usages.length === 0) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- } else if (
- ObjectPrototypeIsPrototypeOf(CryptoKeyPrototype, result.privateKey)
+ return { publicKey, privateKey };
+ }
+ case "Ed25519": {
+ if (
+ ArrayPrototypeFind(
+ usages,
+ (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
+ ) !== undefined
) {
- if (result.privateKey[_usages].length === 0) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
+ throw new DOMException("Invalid key usages", "SyntaxError");
}
- return result;
- }
- }
- const SubtleCryptoPrototype = SubtleCrypto.prototype;
+ const ED25519_SEED_LEN = 32;
+ const ED25519_PUBLIC_KEY_LEN = 32;
+ const privateKeyData = new Uint8Array(ED25519_SEED_LEN);
+ const publicKeyData = new Uint8Array(ED25519_PUBLIC_KEY_LEN);
+ if (
+ !ops.op_generate_ed25519_keypair(privateKeyData, publicKeyData)
+ ) {
+ throw new DOMException("Failed to generate key", "OperationError");
+ }
- async function generateKey(normalizedAlgorithm, extractable, usages) {
- const algorithmName = normalizedAlgorithm.name;
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
- switch (algorithmName) {
- case "RSASSA-PKCS1-v1_5":
- case "RSA-PSS": {
- // 1.
- if (
- ArrayPrototypeFind(
- usages,
- (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
+ const publicHandle = {};
+ WeakMapPrototypeSet(KEY_STORE, publicHandle, publicKeyData);
- // 2.
- const keyData = await core.opAsync(
- "op_crypto_generate_key",
- {
- algorithm: "RSA",
- modulusLength: normalizedAlgorithm.modulusLength,
- publicExponent: normalizedAlgorithm.publicExponent,
- },
- );
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "private",
- data: keyData,
- });
-
- // 4-8.
- const algorithm = {
- name: algorithmName,
- modulusLength: normalizedAlgorithm.modulusLength,
- publicExponent: normalizedAlgorithm.publicExponent,
- hash: normalizedAlgorithm.hash,
- };
+ const algorithm = {
+ name: algorithmName,
+ };
- // 9-13.
- const publicKey = constructKey(
- "public",
- true,
- usageIntersection(usages, ["verify"]),
- algorithm,
- handle,
- );
+ const publicKey = constructKey(
+ "public",
+ true,
+ usageIntersection(usages, ["verify"]),
+ algorithm,
+ publicHandle,
+ );
- // 14-18.
- const privateKey = constructKey(
- "private",
- extractable,
- usageIntersection(usages, ["sign"]),
- algorithm,
- handle,
- );
+ const privateKey = constructKey(
+ "private",
+ extractable,
+ usageIntersection(usages, ["sign"]),
+ algorithm,
+ handle,
+ );
- // 19-22.
- return { publicKey, privateKey };
+ return { publicKey, privateKey };
+ }
+ case "HMAC": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ usages,
+ (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
}
- case "RSA-OAEP": {
- if (
- ArrayPrototypeFind(
- usages,
- (u) =>
- !ArrayPrototypeIncludes([
- "encrypt",
- "decrypt",
- "wrapKey",
- "unwrapKey",
- ], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- // 2.
- const keyData = await core.opAsync(
- "op_crypto_generate_key",
- {
- algorithm: "RSA",
- modulusLength: normalizedAlgorithm.modulusLength,
- publicExponent: normalizedAlgorithm.publicExponent,
- },
- );
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "private",
- data: keyData,
- });
+ // 2.
+ let length;
+ if (normalizedAlgorithm.length === undefined) {
+ length = null;
+ } else if (normalizedAlgorithm.length !== 0) {
+ length = normalizedAlgorithm.length;
+ } else {
+ throw new DOMException("Invalid length", "OperationError");
+ }
- // 4-8.
- const algorithm = {
- name: algorithmName,
- modulusLength: normalizedAlgorithm.modulusLength,
- publicExponent: normalizedAlgorithm.publicExponent,
- hash: normalizedAlgorithm.hash,
- };
+ // 3-4.
+ const keyData = await core.opAsync("op_crypto_generate_key", {
+ algorithm: "HMAC",
+ hash: normalizedAlgorithm.hash.name,
+ length,
+ });
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "secret",
+ data: keyData,
+ });
- // 9-13.
- const publicKey = constructKey(
- "public",
- true,
- usageIntersection(usages, ["encrypt", "wrapKey"]),
- algorithm,
- handle,
- );
+ // 6-10.
+ const algorithm = {
+ name: algorithmName,
+ hash: {
+ name: normalizedAlgorithm.hash.name,
+ },
+ length: keyData.byteLength * 8,
+ };
- // 14-18.
- const privateKey = constructKey(
- "private",
- extractable,
- usageIntersection(usages, ["decrypt", "unwrapKey"]),
- algorithm,
- handle,
- );
+ // 5, 11-13.
+ const key = constructKey(
+ "secret",
+ extractable,
+ usages,
+ algorithm,
+ handle,
+ );
- // 19-22.
- return { publicKey, privateKey };
+ // 14.
+ return key;
+ }
+ }
+}
+
+function importKeyEd25519(
+ format,
+ keyData,
+ extractable,
+ keyUsages,
+) {
+ switch (format) {
+ case "raw": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["verify"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
}
- case "ECDSA": {
- const namedCurve = normalizedAlgorithm.namedCurve;
- // 1.
- if (
- ArrayPrototypeFind(
- usages,
- (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, keyData);
- // 2-3.
- const handle = {};
- if (
- ArrayPrototypeIncludes(
- supportedNamedCurves,
- namedCurve,
- )
- ) {
- const keyData = await core.opAsync("op_crypto_generate_key", {
- algorithm: "EC",
- namedCurve,
- });
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "private",
- data: keyData,
- });
- } else {
- throw new DOMException("Curve not supported", "NotSupportedError");
- }
+ // 2-3.
+ const algorithm = {
+ name: "Ed25519",
+ };
- // 4-6.
- const algorithm = {
- name: algorithmName,
- namedCurve,
- };
+ // 4-6.
+ return constructKey(
+ "public",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+ }
+ case "spki": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["verify"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- // 7-11.
- const publicKey = constructKey(
- "public",
- true,
- usageIntersection(usages, ["verify"]),
- algorithm,
- handle,
- );
+ const publicKeyData = new Uint8Array(32);
+ if (!ops.op_import_spki_ed25519(keyData, publicKeyData)) {
+ throw new DOMException("Invalid key data", "DataError");
+ }
- // 12-16.
- const privateKey = constructKey(
- "private",
- extractable,
- usageIntersection(usages, ["sign"]),
- algorithm,
- handle,
- );
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
- // 17-20.
- return { publicKey, privateKey };
+ const algorithm = {
+ name: "Ed25519",
+ };
+
+ return constructKey(
+ "public",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+ }
+ case "pkcs8": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["sign"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
}
- case "ECDH": {
- const namedCurve = normalizedAlgorithm.namedCurve;
- // 1.
- if (
- ArrayPrototypeFind(
- usages,
- (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
+ const privateKeyData = new Uint8Array(32);
+ if (!ops.op_import_pkcs8_ed25519(keyData, privateKeyData)) {
+ throw new DOMException("Invalid key data", "DataError");
+ }
- // 2-3.
- const handle = {};
- if (
- ArrayPrototypeIncludes(
- supportedNamedCurves,
- namedCurve,
- )
- ) {
- const keyData = await core.opAsync("op_crypto_generate_key", {
- algorithm: "EC",
- namedCurve,
- });
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "private",
- data: keyData,
- });
- } else {
- throw new DOMException("Curve not supported", "NotSupportedError");
- }
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
- // 4-6.
- const algorithm = {
- name: algorithmName,
- namedCurve,
- };
+ const algorithm = {
+ name: "Ed25519",
+ };
- // 7-11.
- const publicKey = constructKey(
- "public",
- true,
- usageIntersection(usages, []),
- algorithm,
- handle,
- );
-
- // 12-16.
- const privateKey = constructKey(
- "private",
- extractable,
- usageIntersection(usages, ["deriveKey", "deriveBits"]),
- algorithm,
- handle,
- );
+ return constructKey(
+ "private",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+ }
+ case "jwk": {
+ // 1.
+ const jwk = keyData;
- // 17-20.
- return { publicKey, privateKey };
- }
- case "AES-CTR":
- case "AES-CBC":
- case "AES-GCM": {
- // 1.
+ // 2.
+ if (jwk.d !== undefined) {
if (
ArrayPrototypeFind(
- usages,
+ keyUsages,
(u) =>
- !ArrayPrototypeIncludes([
- "encrypt",
- "decrypt",
- "wrapKey",
- "unwrapKey",
- ], u),
+ !ArrayPrototypeIncludes(
+ ["sign"],
+ u,
+ ),
) !== undefined
) {
throw new DOMException("Invalid key usages", "SyntaxError");
}
-
- return generateKeyAES(normalizedAlgorithm, extractable, usages);
- }
- case "AES-KW": {
- // 1.
+ } else {
if (
ArrayPrototypeFind(
- usages,
- (u) => !ArrayPrototypeIncludes(["wrapKey", "unwrapKey"], u),
+ keyUsages,
+ (u) =>
+ !ArrayPrototypeIncludes(
+ ["verify"],
+ u,
+ ),
) !== undefined
) {
throw new DOMException("Invalid key usages", "SyntaxError");
}
-
- return generateKeyAES(normalizedAlgorithm, extractable, usages);
}
- case "X25519": {
- if (
- ArrayPrototypeFind(
- usages,
- (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- const privateKeyData = new Uint8Array(32);
- const publicKeyData = new Uint8Array(32);
- ops.op_generate_x25519_keypair(privateKeyData, publicKeyData);
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
-
- const publicHandle = {};
- WeakMapPrototypeSet(KEY_STORE, publicHandle, publicKeyData);
-
- const algorithm = {
- name: algorithmName,
- };
+ // 3.
+ if (jwk.kty !== "OKP") {
+ throw new DOMException("Invalid key type", "DataError");
+ }
- const publicKey = constructKey(
- "public",
- true,
- usageIntersection(usages, []),
- algorithm,
- publicHandle,
- );
+ // 4.
+ if (jwk.crv !== "Ed25519") {
+ throw new DOMException("Invalid curve", "DataError");
+ }
- const privateKey = constructKey(
- "private",
- extractable,
- usageIntersection(usages, ["deriveKey", "deriveBits"]),
- algorithm,
- handle,
- );
+ // 5.
+ if (jwk.alg !== undefined && jwk.alg !== "EdDSA") {
+ throw new DOMException("Invalid algorithm", "DataError");
+ }
- return { publicKey, privateKey };
+ // 6.
+ if (
+ keyUsages.length > 0 && jwk.use !== undefined && jwk.use !== "sig"
+ ) {
+ throw new DOMException("Invalid key usage", "DataError");
}
- case "Ed25519": {
+
+ // 7.
+ if (jwk.key_ops !== undefined) {
if (
ArrayPrototypeFind(
- usages,
- (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
+ jwk.key_ops,
+ (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
) !== undefined
) {
- throw new DOMException("Invalid key usages", "SyntaxError");
+ throw new DOMException(
+ "'key_ops' property of JsonWebKey is invalid",
+ "DataError",
+ );
}
- const ED25519_SEED_LEN = 32;
- const ED25519_PUBLIC_KEY_LEN = 32;
- const privateKeyData = new Uint8Array(ED25519_SEED_LEN);
- const publicKeyData = new Uint8Array(ED25519_PUBLIC_KEY_LEN);
if (
- !ops.op_generate_ed25519_keypair(privateKeyData, publicKeyData)
+ !ArrayPrototypeEvery(
+ jwk.key_ops,
+ (u) => ArrayPrototypeIncludes(keyUsages, u),
+ )
) {
- throw new DOMException("Failed to generate key", "OperationError");
+ throw new DOMException(
+ "'key_ops' property of JsonWebKey is invalid",
+ "DataError",
+ );
}
+ }
+
+ // 8.
+ if (jwk.ext !== undefined && jwk.ext === false && extractable) {
+ throw new DOMException("Invalid key extractability", "DataError");
+ }
+
+ // 9.
+ if (jwk.d !== undefined) {
+ // https://www.rfc-editor.org/rfc/rfc8037#section-2
+ const privateKeyData = ops.op_crypto_base64url_decode(jwk.d);
const handle = {};
WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
- const publicHandle = {};
- WeakMapPrototypeSet(KEY_STORE, publicHandle, publicKeyData);
-
const algorithm = {
- name: algorithmName,
+ name: "Ed25519",
};
- const publicKey = constructKey(
- "public",
- true,
- usageIntersection(usages, ["verify"]),
- algorithm,
- publicHandle,
- );
-
- const privateKey = constructKey(
+ return constructKey(
"private",
extractable,
- usageIntersection(usages, ["sign"]),
+ usageIntersection(keyUsages, recognisedUsages),
algorithm,
handle,
);
+ } else {
+ // https://www.rfc-editor.org/rfc/rfc8037#section-2
+ const publicKeyData = ops.op_crypto_base64url_decode(jwk.x);
- return { publicKey, privateKey };
- }
- case "HMAC": {
- // 1.
- if (
- ArrayPrototypeFind(
- usages,
- (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- // 2.
- let length;
- if (normalizedAlgorithm.length === undefined) {
- length = null;
- } else if (normalizedAlgorithm.length !== 0) {
- length = normalizedAlgorithm.length;
- } else {
- throw new DOMException("Invalid length", "OperationError");
- }
-
- // 3-4.
- const keyData = await core.opAsync("op_crypto_generate_key", {
- algorithm: "HMAC",
- hash: normalizedAlgorithm.hash.name,
- length,
- });
const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "secret",
- data: keyData,
- });
+ WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
- // 6-10.
const algorithm = {
- name: algorithmName,
- hash: {
- name: normalizedAlgorithm.hash.name,
- },
- length: keyData.byteLength * 8,
+ name: "Ed25519",
};
- // 5, 11-13.
- const key = constructKey(
- "secret",
+ return constructKey(
+ "public",
extractable,
- usages,
+ usageIntersection(keyUsages, recognisedUsages),
algorithm,
handle,
);
-
- // 14.
- return key;
}
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
}
+}
+
+function importKeyX25519(
+ format,
+ keyData,
+ extractable,
+ keyUsages,
+) {
+ switch (format) {
+ case "raw": {
+ // 1.
+ if (keyUsages.length > 0) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- function importKeyEd25519(
- format,
- keyData,
- extractable,
- keyUsages,
- ) {
- switch (format) {
- case "raw": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, keyData);
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, keyData);
+ // 2-3.
+ const algorithm = {
+ name: "X25519",
+ };
- // 2-3.
- const algorithm = {
- name: "Ed25519",
- };
+ // 4-6.
+ return constructKey(
+ "public",
+ extractable,
+ [],
+ algorithm,
+ handle,
+ );
+ }
+ case "spki": {
+ // 1.
+ if (keyUsages.length > 0) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- // 4-6.
- return constructKey(
- "public",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
+ const publicKeyData = new Uint8Array(32);
+ if (!ops.op_import_spki_x25519(keyData, publicKeyData)) {
+ throw new DOMException("Invalid key data", "DataError");
}
- case "spki": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- const publicKeyData = new Uint8Array(32);
- if (!ops.op_import_spki_ed25519(keyData, publicKeyData)) {
- throw new DOMException("Invalid key data", "DataError");
- }
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
+ const algorithm = {
+ name: "X25519",
+ };
- const algorithm = {
- name: "Ed25519",
- };
+ return constructKey(
+ "public",
+ extractable,
+ [],
+ algorithm,
+ handle,
+ );
+ }
+ case "pkcs8": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- return constructKey(
- "public",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
+ const privateKeyData = new Uint8Array(32);
+ if (!ops.op_import_pkcs8_x25519(keyData, privateKeyData)) {
+ throw new DOMException("Invalid key data", "DataError");
}
- case "pkcs8": {
- // 1.
+
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
+
+ const algorithm = {
+ name: "X25519",
+ };
+
+ return constructKey(
+ "private",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+ }
+ case "jwk": {
+ // 1.
+ const jwk = keyData;
+
+ // 2.
+ if (jwk.d !== undefined) {
if (
ArrayPrototypeFind(
keyUsages,
- (u) => !ArrayPrototypeIncludes(["sign"], u),
+ (u) =>
+ !ArrayPrototypeIncludes(
+ ["deriveKey", "deriveBits"],
+ u,
+ ),
) !== undefined
) {
throw new DOMException("Invalid key usages", "SyntaxError");
}
-
- const privateKeyData = new Uint8Array(32);
- if (!ops.op_import_pkcs8_ed25519(keyData, privateKeyData)) {
- throw new DOMException("Invalid key data", "DataError");
- }
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
-
- const algorithm = {
- name: "Ed25519",
- };
-
- return constructKey(
- "private",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
}
- case "jwk": {
- // 1.
- const jwk = keyData;
- // 2.
- if (jwk.d !== undefined) {
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes(
- ["sign"],
- u,
- ),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- } else {
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes(
- ["verify"],
- u,
- ),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- }
+ // 3.
+ if (jwk.d === undefined && keyUsages.length > 0) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- // 3.
- if (jwk.kty !== "OKP") {
- throw new DOMException("Invalid key type", "DataError");
- }
+ // 4.
+ if (jwk.kty !== "OKP") {
+ throw new DOMException("Invalid key type", "DataError");
+ }
- // 4.
- if (jwk.crv !== "Ed25519") {
- throw new DOMException("Invalid curve", "DataError");
- }
+ // 5.
+ if (jwk.crv !== "X25519") {
+ throw new DOMException("Invalid curve", "DataError");
+ }
- // 5.
- if (jwk.alg !== undefined && jwk.alg !== "EdDSA") {
- throw new DOMException("Invalid algorithm", "DataError");
+ // 6.
+ if (keyUsages.length > 0 && jwk.use !== undefined) {
+ if (jwk.use !== "enc") {
+ throw new DOMException("Invalid key use", "DataError");
}
+ }
- // 6.
+ // 7.
+ if (jwk.key_ops !== undefined) {
if (
- keyUsages.length > 0 && jwk.use !== undefined && jwk.use !== "sig"
+ ArrayPrototypeFind(
+ jwk.key_ops,
+ (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
+ ) !== undefined
) {
- throw new DOMException("Invalid key usage", "DataError");
- }
-
- // 7.
- if (jwk.key_ops !== undefined) {
- if (
- ArrayPrototypeFind(
- jwk.key_ops,
- (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
- ) !== undefined
- ) {
- throw new DOMException(
- "'key_ops' property of JsonWebKey is invalid",
- "DataError",
- );
- }
-
- if (
- !ArrayPrototypeEvery(
- jwk.key_ops,
- (u) => ArrayPrototypeIncludes(keyUsages, u),
- )
- ) {
- throw new DOMException(
- "'key_ops' property of JsonWebKey is invalid",
- "DataError",
- );
- }
- }
-
- // 8.
- if (jwk.ext !== undefined && jwk.ext === false && extractable) {
- throw new DOMException("Invalid key extractability", "DataError");
+ throw new DOMException(
+ "'key_ops' property of JsonWebKey is invalid",
+ "DataError",
+ );
}
- // 9.
- if (jwk.d !== undefined) {
- // https://www.rfc-editor.org/rfc/rfc8037#section-2
- const privateKeyData = ops.op_crypto_base64url_decode(jwk.d);
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
-
- const algorithm = {
- name: "Ed25519",
- };
-
- return constructKey(
- "private",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
- } else {
- // https://www.rfc-editor.org/rfc/rfc8037#section-2
- const publicKeyData = ops.op_crypto_base64url_decode(jwk.x);
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
-
- const algorithm = {
- name: "Ed25519",
- };
-
- return constructKey(
- "public",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
+ if (
+ !ArrayPrototypeEvery(
+ jwk.key_ops,
+ (u) => ArrayPrototypeIncludes(keyUsages, u),
+ )
+ ) {
+ throw new DOMException(
+ "'key_ops' property of JsonWebKey is invalid",
+ "DataError",
);
}
}
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- function importKeyX25519(
- format,
- keyData,
- extractable,
- keyUsages,
- ) {
- switch (format) {
- case "raw": {
- // 1.
- if (keyUsages.length > 0) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
+ // 8.
+ if (jwk.ext !== undefined && jwk.ext === false && extractable) {
+ throw new DOMException("Invalid key extractability", "DataError");
+ }
+
+ // 9.
+ if (jwk.d !== undefined) {
+ // https://www.rfc-editor.org/rfc/rfc8037#section-2
+ const privateKeyData = ops.op_crypto_base64url_decode(jwk.d);
const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, keyData);
+ WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
- // 2-3.
const algorithm = {
name: "X25519",
};
- // 4-6.
return constructKey(
- "public",
+ "private",
extractable,
- [],
+ usageIntersection(keyUsages, ["deriveKey", "deriveBits"]),
algorithm,
handle,
);
- }
- case "spki": {
- // 1.
- if (keyUsages.length > 0) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- const publicKeyData = new Uint8Array(32);
- if (!ops.op_import_spki_x25519(keyData, publicKeyData)) {
- throw new DOMException("Invalid key data", "DataError");
- }
+ } else {
+ // https://www.rfc-editor.org/rfc/rfc8037#section-2
+ const publicKeyData = ops.op_crypto_base64url_decode(jwk.x);
const handle = {};
WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
@@ -2410,600 +2550,538 @@
handle,
);
}
- case "pkcs8": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
+ }
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+}
+
+function exportKeyAES(
+ format,
+ key,
+ innerKey,
+) {
+ switch (format) {
+ // 2.
+ case "raw": {
+ // 1.
+ const data = innerKey.data;
+ // 2.
+ return data.buffer;
+ }
+ case "jwk": {
+ // 1-2.
+ const jwk = {
+ kty: "oct",
+ };
- const privateKeyData = new Uint8Array(32);
- if (!ops.op_import_pkcs8_x25519(keyData, privateKeyData)) {
- throw new DOMException("Invalid key data", "DataError");
- }
+ // 3.
+ const data = ops.op_crypto_export_key({
+ format: "jwksecret",
+ algorithm: "AES",
+ }, innerKey);
+ ObjectAssign(jwk, data);
+
+ // 4.
+ const algorithm = key[_algorithm];
+ switch (algorithm.length) {
+ case 128:
+ jwk.alg = aesJwkAlg[algorithm.name][128];
+ break;
+ case 192:
+ jwk.alg = aesJwkAlg[algorithm.name][192];
+ break;
+ case 256:
+ jwk.alg = aesJwkAlg[algorithm.name][256];
+ break;
+ default:
+ throw new DOMException(
+ "Invalid key length",
+ "NotSupportedError",
+ );
+ }
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
+ // 5.
+ jwk.key_ops = key.usages;
- const algorithm = {
- name: "X25519",
- };
+ // 6.
+ jwk.ext = key[_extractable];
- return constructKey(
- "private",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
+ // 7.
+ return jwk;
+ }
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+}
+
+function importKeyAES(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+ supportedKeyUsages,
+) {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(supportedKeyUsages, u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+
+ const algorithmName = normalizedAlgorithm.name;
+
+ // 2.
+ let data = keyData;
+
+ switch (format) {
+ case "raw": {
+ // 2.
+ if (
+ !ArrayPrototypeIncludes([128, 192, 256], keyData.byteLength * 8)
+ ) {
+ throw new DOMException("Invalid key length", "Datarror");
}
- case "jwk": {
- // 1.
- const jwk = keyData;
- // 2.
- if (jwk.d !== undefined) {
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes(
- ["deriveKey", "deriveBits"],
- u,
- ),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- }
+ break;
+ }
+ case "jwk": {
+ // 1.
+ const jwk = keyData;
- // 3.
- if (jwk.d === undefined && keyUsages.length > 0) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
+ // 2.
+ if (jwk.kty !== "oct") {
+ throw new DOMException(
+ "'kty' property of JsonWebKey must be 'oct'",
+ "DataError",
+ );
+ }
- // 4.
- if (jwk.kty !== "OKP") {
- throw new DOMException("Invalid key type", "DataError");
- }
+ // Section 6.4.1 of RFC7518
+ if (jwk.k === undefined) {
+ throw new DOMException(
+ "'k' property of JsonWebKey must be present",
+ "DataError",
+ );
+ }
- // 5.
- if (jwk.crv !== "X25519") {
- throw new DOMException("Invalid curve", "DataError");
- }
+ // 4.
+ const { rawData } = ops.op_crypto_import_key(
+ { algorithm: "AES" },
+ { jwkSecret: jwk },
+ );
+ data = rawData.data;
- // 6.
- if (keyUsages.length > 0 && jwk.use !== undefined) {
- if (jwk.use !== "enc") {
- throw new DOMException("Invalid key use", "DataError");
+ // 5.
+ switch (data.byteLength * 8) {
+ case 128:
+ if (
+ jwk.alg !== undefined &&
+ jwk.alg !== aesJwkAlg[algorithmName][128]
+ ) {
+ throw new DOMException("Invalid algorithm", "DataError");
}
- }
-
- // 7.
- if (jwk.key_ops !== undefined) {
+ break;
+ case 192:
if (
- ArrayPrototypeFind(
- jwk.key_ops,
- (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
- ) !== undefined
+ jwk.alg !== undefined &&
+ jwk.alg !== aesJwkAlg[algorithmName][192]
) {
- throw new DOMException(
- "'key_ops' property of JsonWebKey is invalid",
- "DataError",
- );
+ throw new DOMException("Invalid algorithm", "DataError");
}
-
+ break;
+ case 256:
if (
- !ArrayPrototypeEvery(
- jwk.key_ops,
- (u) => ArrayPrototypeIncludes(keyUsages, u),
- )
+ jwk.alg !== undefined &&
+ jwk.alg !== aesJwkAlg[algorithmName][256]
) {
- throw new DOMException(
- "'key_ops' property of JsonWebKey is invalid",
- "DataError",
- );
+ throw new DOMException("Invalid algorithm", "DataError");
}
- }
-
- // 8.
- if (jwk.ext !== undefined && jwk.ext === false && extractable) {
- throw new DOMException("Invalid key extractability", "DataError");
- }
-
- // 9.
- if (jwk.d !== undefined) {
- // https://www.rfc-editor.org/rfc/rfc8037#section-2
- const privateKeyData = ops.op_crypto_base64url_decode(jwk.d);
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData);
-
- const algorithm = {
- name: "X25519",
- };
-
- return constructKey(
- "private",
- extractable,
- usageIntersection(keyUsages, ["deriveKey", "deriveBits"]),
- algorithm,
- handle,
- );
- } else {
- // https://www.rfc-editor.org/rfc/rfc8037#section-2
- const publicKeyData = ops.op_crypto_base64url_decode(jwk.x);
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData);
-
- const algorithm = {
- name: "X25519",
- };
-
- return constructKey(
- "public",
- extractable,
- [],
- algorithm,
- handle,
+ break;
+ default:
+ throw new DOMException(
+ "Invalid key length",
+ "DataError",
);
- }
}
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- function exportKeyAES(
- format,
- key,
- innerKey,
- ) {
- switch (format) {
- // 2.
- case "raw": {
- // 1.
- const data = innerKey.data;
- // 2.
- return data.buffer;
+ // 6.
+ if (
+ keyUsages.length > 0 && jwk.use !== undefined && jwk.use !== "enc"
+ ) {
+ throw new DOMException("Invalid key usages", "DataError");
}
- case "jwk": {
- // 1-2.
- const jwk = {
- kty: "oct",
- };
-
- // 3.
- const data = ops.op_crypto_export_key({
- format: "jwksecret",
- algorithm: "AES",
- }, innerKey);
- ObjectAssign(jwk, data);
- // 4.
- const algorithm = key[_algorithm];
- switch (algorithm.length) {
- case 128:
- jwk.alg = aesJwkAlg[algorithm.name][128];
- break;
- case 192:
- jwk.alg = aesJwkAlg[algorithm.name][192];
- break;
- case 256:
- jwk.alg = aesJwkAlg[algorithm.name][256];
- break;
- default:
- throw new DOMException(
- "Invalid key length",
- "NotSupportedError",
- );
+ // 7.
+ // Section 4.3 of RFC7517
+ if (jwk.key_ops !== undefined) {
+ if (
+ ArrayPrototypeFind(
+ jwk.key_ops,
+ (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
+ ) !== undefined
+ ) {
+ throw new DOMException(
+ "'key_ops' property of JsonWebKey is invalid",
+ "DataError",
+ );
}
- // 5.
- jwk.key_ops = key.usages;
-
- // 6.
- jwk.ext = key[_extractable];
+ if (
+ !ArrayPrototypeEvery(
+ jwk.key_ops,
+ (u) => ArrayPrototypeIncludes(keyUsages, u),
+ )
+ ) {
+ throw new DOMException(
+ "'key_ops' property of JsonWebKey is invalid",
+ "DataError",
+ );
+ }
+ }
- // 7.
- return jwk;
+ // 8.
+ if (jwk.ext === false && extractable === true) {
+ throw new DOMException(
+ "'ext' property of JsonWebKey must not be false if extractable is true",
+ "DataError",
+ );
}
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
+
+ break;
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
}
- function importKeyAES(
- format,
- normalizedAlgorithm,
- keyData,
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "secret",
+ data,
+ });
+
+ // 4-7.
+ const algorithm = {
+ name: algorithmName,
+ length: data.byteLength * 8,
+ };
+
+ const key = constructKey(
+ "secret",
extractable,
- keyUsages,
- supportedKeyUsages,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ // 8.
+ return key;
+}
+
+function importKeyHMAC(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+) {
+ // 2.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
+ ) !== undefined
) {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(supportedKeyUsages, u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- const algorithmName = normalizedAlgorithm.name;
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- // 2.
- let data = keyData;
+ // 3.
+ let hash;
+ let data;
- switch (format) {
- case "raw": {
- // 2.
- if (
- !ArrayPrototypeIncludes([128, 192, 256], keyData.byteLength * 8)
- ) {
- throw new DOMException("Invalid key length", "Datarror");
- }
+ // 4. https://w3c.github.io/webcrypto/#hmac-operations
+ switch (format) {
+ case "raw": {
+ data = keyData;
+ hash = normalizedAlgorithm.hash;
+ break;
+ }
+ case "jwk": {
+ const jwk = keyData;
- break;
+ // 2.
+ if (jwk.kty !== "oct") {
+ throw new DOMException(
+ "'kty' property of JsonWebKey must be 'oct'",
+ "DataError",
+ );
}
- case "jwk": {
- // 1.
- const jwk = keyData;
- // 2.
- if (jwk.kty !== "oct") {
- throw new DOMException(
- "'kty' property of JsonWebKey must be 'oct'",
- "DataError",
- );
- }
+ // Section 6.4.1 of RFC7518
+ if (jwk.k === undefined) {
+ throw new DOMException(
+ "'k' property of JsonWebKey must be present",
+ "DataError",
+ );
+ }
- // Section 6.4.1 of RFC7518
- if (jwk.k === undefined) {
- throw new DOMException(
- "'k' property of JsonWebKey must be present",
- "DataError",
- );
- }
+ // 4.
+ const { rawData } = ops.op_crypto_import_key(
+ { algorithm: "HMAC" },
+ { jwkSecret: jwk },
+ );
+ data = rawData.data;
- // 4.
- const { rawData } = ops.op_crypto_import_key(
- { algorithm: "AES" },
- { jwkSecret: jwk },
- );
- data = rawData.data;
+ // 5.
+ hash = normalizedAlgorithm.hash;
- // 5.
- switch (data.byteLength * 8) {
- case 128:
- if (
- jwk.alg !== undefined &&
- jwk.alg !== aesJwkAlg[algorithmName][128]
- ) {
- throw new DOMException("Invalid algorithm", "DataError");
- }
- break;
- case 192:
- if (
- jwk.alg !== undefined &&
- jwk.alg !== aesJwkAlg[algorithmName][192]
- ) {
- throw new DOMException("Invalid algorithm", "DataError");
- }
- break;
- case 256:
- if (
- jwk.alg !== undefined &&
- jwk.alg !== aesJwkAlg[algorithmName][256]
- ) {
- throw new DOMException("Invalid algorithm", "DataError");
- }
- break;
- default:
+ // 6.
+ switch (hash.name) {
+ case "SHA-1": {
+ if (jwk.alg !== undefined && jwk.alg !== "HS1") {
throw new DOMException(
- "Invalid key length",
+ "'alg' property of JsonWebKey must be 'HS1'",
"DataError",
);
+ }
+ break;
}
-
- // 6.
- if (
- keyUsages.length > 0 && jwk.use !== undefined && jwk.use !== "enc"
- ) {
- throw new DOMException("Invalid key usages", "DataError");
- }
-
- // 7.
- // Section 4.3 of RFC7517
- if (jwk.key_ops !== undefined) {
- if (
- ArrayPrototypeFind(
- jwk.key_ops,
- (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
- ) !== undefined
- ) {
+ case "SHA-256": {
+ if (jwk.alg !== undefined && jwk.alg !== "HS256") {
throw new DOMException(
- "'key_ops' property of JsonWebKey is invalid",
+ "'alg' property of JsonWebKey must be 'HS256'",
"DataError",
);
}
-
- if (
- !ArrayPrototypeEvery(
- jwk.key_ops,
- (u) => ArrayPrototypeIncludes(keyUsages, u),
- )
- ) {
+ break;
+ }
+ case "SHA-384": {
+ if (jwk.alg !== undefined && jwk.alg !== "HS384") {
throw new DOMException(
- "'key_ops' property of JsonWebKey is invalid",
+ "'alg' property of JsonWebKey must be 'HS384'",
"DataError",
);
}
+ break;
}
-
- // 8.
- if (jwk.ext === false && extractable === true) {
- throw new DOMException(
- "'ext' property of JsonWebKey must not be false if extractable is true",
- "DataError",
- );
+ case "SHA-512": {
+ if (jwk.alg !== undefined && jwk.alg !== "HS512") {
+ throw new DOMException(
+ "'alg' property of JsonWebKey must be 'HS512'",
+ "DataError",
+ );
+ }
+ break;
}
-
- break;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "secret",
- data,
- });
-
- // 4-7.
- const algorithm = {
- name: algorithmName,
- length: data.byteLength * 8,
- };
-
- const key = constructKey(
- "secret",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
-
- // 8.
- return key;
- }
-
- function importKeyHMAC(
- format,
- normalizedAlgorithm,
- keyData,
- extractable,
- keyUsages,
- ) {
- // 2.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["sign", "verify"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- // 3.
- let hash;
- let data;
-
- // 4. https://w3c.github.io/webcrypto/#hmac-operations
- switch (format) {
- case "raw": {
- data = keyData;
- hash = normalizedAlgorithm.hash;
- break;
+ default:
+ throw new TypeError("unreachable");
}
- case "jwk": {
- const jwk = keyData;
-
- // 2.
- if (jwk.kty !== "oct") {
- throw new DOMException(
- "'kty' property of JsonWebKey must be 'oct'",
- "DataError",
- );
- }
-
- // Section 6.4.1 of RFC7518
- if (jwk.k === undefined) {
- throw new DOMException(
- "'k' property of JsonWebKey must be present",
- "DataError",
- );
- }
- // 4.
- const { rawData } = ops.op_crypto_import_key(
- { algorithm: "HMAC" },
- { jwkSecret: jwk },
+ // 7.
+ if (
+ keyUsages.length > 0 && jwk.use !== undefined && jwk.use !== "sig"
+ ) {
+ throw new DOMException(
+ "'use' property of JsonWebKey must be 'sig'",
+ "DataError",
);
- data = rawData.data;
-
- // 5.
- hash = normalizedAlgorithm.hash;
-
- // 6.
- switch (hash.name) {
- case "SHA-1": {
- if (jwk.alg !== undefined && jwk.alg !== "HS1") {
- throw new DOMException(
- "'alg' property of JsonWebKey must be 'HS1'",
- "DataError",
- );
- }
- break;
- }
- case "SHA-256": {
- if (jwk.alg !== undefined && jwk.alg !== "HS256") {
- throw new DOMException(
- "'alg' property of JsonWebKey must be 'HS256'",
- "DataError",
- );
- }
- break;
- }
- case "SHA-384": {
- if (jwk.alg !== undefined && jwk.alg !== "HS384") {
- throw new DOMException(
- "'alg' property of JsonWebKey must be 'HS384'",
- "DataError",
- );
- }
- break;
- }
- case "SHA-512": {
- if (jwk.alg !== undefined && jwk.alg !== "HS512") {
- throw new DOMException(
- "'alg' property of JsonWebKey must be 'HS512'",
- "DataError",
- );
- }
- break;
- }
- default:
- throw new TypeError("unreachable");
- }
+ }
- // 7.
+ // 8.
+ // Section 4.3 of RFC7517
+ if (jwk.key_ops !== undefined) {
if (
- keyUsages.length > 0 && jwk.use !== undefined && jwk.use !== "sig"
+ ArrayPrototypeFind(
+ jwk.key_ops,
+ (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
+ ) !== undefined
) {
throw new DOMException(
- "'use' property of JsonWebKey must be 'sig'",
+ "'key_ops' property of JsonWebKey is invalid",
"DataError",
);
}
- // 8.
- // Section 4.3 of RFC7517
- if (jwk.key_ops !== undefined) {
- if (
- ArrayPrototypeFind(
- jwk.key_ops,
- (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
- ) !== undefined
- ) {
- throw new DOMException(
- "'key_ops' property of JsonWebKey is invalid",
- "DataError",
- );
- }
-
- if (
- !ArrayPrototypeEvery(
- jwk.key_ops,
- (u) => ArrayPrototypeIncludes(keyUsages, u),
- )
- ) {
- throw new DOMException(
- "'key_ops' property of JsonWebKey is invalid",
- "DataError",
- );
- }
- }
-
- // 9.
- if (jwk.ext === false && extractable === true) {
+ if (
+ !ArrayPrototypeEvery(
+ jwk.key_ops,
+ (u) => ArrayPrototypeIncludes(keyUsages, u),
+ )
+ ) {
throw new DOMException(
- "'ext' property of JsonWebKey must not be false if extractable is true",
+ "'key_ops' property of JsonWebKey is invalid",
"DataError",
);
}
+ }
- break;
+ // 9.
+ if (jwk.ext === false && extractable === true) {
+ throw new DOMException(
+ "'ext' property of JsonWebKey must not be false if extractable is true",
+ "DataError",
+ );
}
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
+
+ break;
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
- // 5.
- let length = data.byteLength * 8;
- // 6.
- if (length === 0) {
- throw new DOMException("Key length is zero", "DataError");
+ // 5.
+ let length = data.byteLength * 8;
+ // 6.
+ if (length === 0) {
+ throw new DOMException("Key length is zero", "DataError");
+ }
+ // 7.
+ if (normalizedAlgorithm.length !== undefined) {
+ if (
+ normalizedAlgorithm.length > length ||
+ normalizedAlgorithm.length <= (length - 8)
+ ) {
+ throw new DOMException(
+ "Key length is invalid",
+ "DataError",
+ );
}
- // 7.
- if (normalizedAlgorithm.length !== undefined) {
+ length = normalizedAlgorithm.length;
+ }
+
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "secret",
+ data,
+ });
+
+ const algorithm = {
+ name: "HMAC",
+ length,
+ hash,
+ };
+
+ const key = constructKey(
+ "secret",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ return key;
+}
+
+function importKeyEC(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+) {
+ const supportedUsages = SUPPORTED_KEY_USAGES[normalizedAlgorithm.name];
+
+ switch (format) {
+ case "raw": {
+ // 1.
if (
- normalizedAlgorithm.length > length ||
- normalizedAlgorithm.length <= (length - 8)
+ !ArrayPrototypeIncludes(
+ supportedNamedCurves,
+ normalizedAlgorithm.namedCurve,
+ )
) {
throw new DOMException(
- "Key length is invalid",
+ "Invalid namedCurve",
"DataError",
);
}
- length = normalizedAlgorithm.length;
- }
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "secret",
- data,
- });
+ // 2.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) =>
+ !ArrayPrototypeIncludes(
+ SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].public,
+ u,
+ ),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- const algorithm = {
- name: "HMAC",
- length,
- hash,
- };
+ // 3.
+ const { rawData } = ops.op_crypto_import_key({
+ algorithm: normalizedAlgorithm.name,
+ namedCurve: normalizedAlgorithm.namedCurve,
+ }, { raw: keyData });
- const key = constructKey(
- "secret",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, rawData);
- return key;
- }
+ // 4-5.
+ const algorithm = {
+ name: normalizedAlgorithm.name,
+ namedCurve: normalizedAlgorithm.namedCurve,
+ };
+
+ // 6-8.
+ const key = constructKey(
+ "public",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
- function importKeyEC(
- format,
- normalizedAlgorithm,
- keyData,
- extractable,
- keyUsages,
- ) {
- const supportedUsages = SUPPORTED_KEY_USAGES[normalizedAlgorithm.name];
+ return key;
+ }
+ case "pkcs8": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) =>
+ !ArrayPrototypeIncludes(
+ SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].private,
+ u,
+ ),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- switch (format) {
- case "raw": {
- // 1.
- if (
- !ArrayPrototypeIncludes(
- supportedNamedCurves,
- normalizedAlgorithm.namedCurve,
- )
- ) {
- throw new DOMException(
- "Invalid namedCurve",
- "DataError",
- );
- }
+ // 2-9.
+ const { rawData } = ops.op_crypto_import_key({
+ algorithm: normalizedAlgorithm.name,
+ namedCurve: normalizedAlgorithm.namedCurve,
+ }, { pkcs8: keyData });
- // 2.
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, rawData);
+
+ const algorithm = {
+ name: normalizedAlgorithm.name,
+ namedCurve: normalizedAlgorithm.namedCurve,
+ };
+
+ const key = constructKey(
+ "private",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ return key;
+ }
+ case "spki": {
+ // 1.
+ if (normalizedAlgorithm.name == "ECDSA") {
if (
ArrayPrototypeFind(
keyUsages,
@@ -3016,53 +3094,159 @@
) {
throw new DOMException("Invalid key usages", "SyntaxError");
}
+ } else if (keyUsages.length != 0) {
+ throw new DOMException("Key usage must be empty", "SyntaxError");
+ }
- // 3.
- const { rawData } = ops.op_crypto_import_key({
- algorithm: normalizedAlgorithm.name,
- namedCurve: normalizedAlgorithm.namedCurve,
- }, { raw: keyData });
+ // 2-12
+ const { rawData } = ops.op_crypto_import_key({
+ algorithm: normalizedAlgorithm.name,
+ namedCurve: normalizedAlgorithm.namedCurve,
+ }, { spki: keyData });
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, rawData);
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, rawData);
- // 4-5.
- const algorithm = {
- name: normalizedAlgorithm.name,
- namedCurve: normalizedAlgorithm.namedCurve,
- };
+ const algorithm = {
+ name: normalizedAlgorithm.name,
+ namedCurve: normalizedAlgorithm.namedCurve,
+ };
- // 6-8.
- const key = constructKey(
- "public",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
+ // 6-8.
+ const key = constructKey(
+ "public",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ return key;
+ }
+ case "jwk": {
+ const jwk = keyData;
+
+ const keyType = (jwk.d !== undefined) ? "private" : "public";
+
+ // 2.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(supportedUsages[keyType], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+
+ // 3.
+ if (jwk.kty !== "EC") {
+ throw new DOMException(
+ "'kty' property of JsonWebKey must be 'EC'",
+ "DataError",
);
+ }
- return key;
+ // 4.
+ if (
+ keyUsages.length > 0 && jwk.use !== undefined &&
+ jwk.use !== supportedUsages.jwkUse
+ ) {
+ throw new DOMException(
+ `'use' property of JsonWebKey must be '${supportedUsages.jwkUse}'`,
+ "DataError",
+ );
}
- case "pkcs8": {
- // 1.
+
+ // 5.
+ // Section 4.3 of RFC7517
+ if (jwk.key_ops !== undefined) {
if (
ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes(
- SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].private,
- u,
- ),
+ jwk.key_ops,
+ (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
) !== undefined
) {
- throw new DOMException("Invalid key usages", "SyntaxError");
+ throw new DOMException(
+ "'key_ops' member of JsonWebKey is invalid",
+ "DataError",
+ );
+ }
+
+ if (
+ !ArrayPrototypeEvery(
+ jwk.key_ops,
+ (u) => ArrayPrototypeIncludes(keyUsages, u),
+ )
+ ) {
+ throw new DOMException(
+ "'key_ops' member of JsonWebKey is invalid",
+ "DataError",
+ );
+ }
+ }
+
+ // 6.
+ if (jwk.ext === false && extractable === true) {
+ throw new DOMException(
+ "'ext' property of JsonWebKey must not be false if extractable is true",
+ "DataError",
+ );
+ }
+
+ // 9.
+ if (jwk.alg !== undefined && normalizedAlgorithm.name == "ECDSA") {
+ let algNamedCurve;
+
+ switch (jwk.alg) {
+ case "ES256": {
+ algNamedCurve = "P-256";
+ break;
+ }
+ case "ES384": {
+ algNamedCurve = "P-384";
+ break;
+ }
+ case "ES512": {
+ algNamedCurve = "P-521";
+ break;
+ }
+ default:
+ throw new DOMException(
+ "Curve algorithm not supported",
+ "DataError",
+ );
}
- // 2-9.
+ if (algNamedCurve) {
+ if (algNamedCurve !== normalizedAlgorithm.namedCurve) {
+ throw new DOMException(
+ "Mismatched curve algorithm",
+ "DataError",
+ );
+ }
+ }
+ }
+
+ // Validate that this is a valid public key.
+ if (jwk.x === undefined) {
+ throw new DOMException(
+ "'x' property of JsonWebKey is required for EC keys",
+ "DataError",
+ );
+ }
+ if (jwk.y === undefined) {
+ throw new DOMException(
+ "'y' property of JsonWebKey is required for EC keys",
+ "DataError",
+ );
+ }
+
+ if (jwk.d !== undefined) {
+ // it's also a Private key
const { rawData } = ops.op_crypto_import_key({
algorithm: normalizedAlgorithm.name,
namedCurve: normalizedAlgorithm.namedCurve,
- }, { pkcs8: keyData });
+ }, { jwkPrivateEc: jwk });
const handle = {};
WeakMapPrototypeSet(KEY_STORE, handle, rawData);
@@ -3081,31 +3265,11 @@
);
return key;
- }
- case "spki": {
- // 1.
- if (normalizedAlgorithm.name == "ECDSA") {
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes(
- SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].public,
- u,
- ),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- } else if (keyUsages.length != 0) {
- throw new DOMException("Key usage must be empty", "SyntaxError");
- }
-
- // 2-12
+ } else {
const { rawData } = ops.op_crypto_import_key({
algorithm: normalizedAlgorithm.name,
namedCurve: normalizedAlgorithm.namedCurve,
- }, { spki: keyData });
+ }, { jwkPublicEc: jwk });
const handle = {};
WeakMapPrototypeSet(KEY_STORE, handle, rawData);
@@ -3115,7 +3279,6 @@
namedCurve: normalizedAlgorithm.namedCurve,
};
- // 6-8.
const key = constructKey(
"public",
extractable,
@@ -3126,238 +3289,367 @@
return key;
}
- case "jwk": {
- const jwk = keyData;
+ }
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+}
+
+const SUPPORTED_KEY_USAGES = {
+ "RSASSA-PKCS1-v1_5": {
+ public: ["verify"],
+ private: ["sign"],
+ jwkUse: "sig",
+ },
+ "RSA-PSS": {
+ public: ["verify"],
+ private: ["sign"],
+ jwkUse: "sig",
+ },
+ "RSA-OAEP": {
+ public: ["encrypt", "wrapKey"],
+ private: ["decrypt", "unwrapKey"],
+ jwkUse: "enc",
+ },
+ "ECDSA": {
+ public: ["verify"],
+ private: ["sign"],
+ jwkUse: "sig",
+ },
+ "ECDH": {
+ public: [],
+ private: ["deriveKey", "deriveBits"],
+ jwkUse: "enc",
+ },
+};
+
+function importKeyRSA(
+ format,
+ normalizedAlgorithm,
+ keyData,
+ extractable,
+ keyUsages,
+) {
+ switch (format) {
+ case "pkcs8": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) =>
+ !ArrayPrototypeIncludes(
+ SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].private,
+ u,
+ ),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- const keyType = (jwk.d !== undefined) ? "private" : "public";
+ // 2-9.
+ const { modulusLength, publicExponent, rawData } = ops
+ .op_crypto_import_key(
+ {
+ algorithm: normalizedAlgorithm.name,
+ // Needed to perform step 7 without normalization.
+ hash: normalizedAlgorithm.hash.name,
+ },
+ { pkcs8: keyData },
+ );
- // 2.
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, rawData);
+
+ const algorithm = {
+ name: normalizedAlgorithm.name,
+ modulusLength,
+ publicExponent,
+ hash: normalizedAlgorithm.hash,
+ };
+
+ const key = constructKey(
+ "private",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ return key;
+ }
+ case "spki": {
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) =>
+ !ArrayPrototypeIncludes(
+ SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].public,
+ u,
+ ),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
+
+ // 2-9.
+ const { modulusLength, publicExponent, rawData } = ops
+ .op_crypto_import_key(
+ {
+ algorithm: normalizedAlgorithm.name,
+ // Needed to perform step 7 without normalization.
+ hash: normalizedAlgorithm.hash.name,
+ },
+ { spki: keyData },
+ );
+
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, rawData);
+
+ const algorithm = {
+ name: normalizedAlgorithm.name,
+ modulusLength,
+ publicExponent,
+ hash: normalizedAlgorithm.hash,
+ };
+
+ const key = constructKey(
+ "public",
+ extractable,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ return key;
+ }
+ case "jwk": {
+ // 1.
+ const jwk = keyData;
+
+ // 2.
+ if (jwk.d !== undefined) {
if (
ArrayPrototypeFind(
keyUsages,
- (u) => !ArrayPrototypeIncludes(supportedUsages[keyType], u),
+ (u) =>
+ !ArrayPrototypeIncludes(
+ SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].private,
+ u,
+ ),
) !== undefined
) {
throw new DOMException("Invalid key usages", "SyntaxError");
}
+ } else if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) =>
+ !ArrayPrototypeIncludes(
+ SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].public,
+ u,
+ ),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- // 3.
- if (jwk.kty !== "EC") {
+ // 3.
+ if (StringPrototypeToUpperCase(jwk.kty) !== "RSA") {
+ throw new DOMException(
+ "'kty' property of JsonWebKey must be 'RSA'",
+ "DataError",
+ );
+ }
+
+ // 4.
+ if (
+ keyUsages.length > 0 && jwk.use !== undefined &&
+ StringPrototypeToLowerCase(jwk.use) !==
+ SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].jwkUse
+ ) {
+ throw new DOMException(
+ `'use' property of JsonWebKey must be '${
+ SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].jwkUse
+ }'`,
+ "DataError",
+ );
+ }
+
+ // 5.
+ if (jwk.key_ops !== undefined) {
+ if (
+ ArrayPrototypeFind(
+ jwk.key_ops,
+ (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
+ ) !== undefined
+ ) {
throw new DOMException(
- "'kty' property of JsonWebKey must be 'EC'",
+ "'key_ops' property of JsonWebKey is invalid",
"DataError",
);
}
- // 4.
if (
- keyUsages.length > 0 && jwk.use !== undefined &&
- jwk.use !== supportedUsages.jwkUse
+ !ArrayPrototypeEvery(
+ jwk.key_ops,
+ (u) => ArrayPrototypeIncludes(keyUsages, u),
+ )
) {
throw new DOMException(
- `'use' property of JsonWebKey must be '${supportedUsages.jwkUse}'`,
+ "'key_ops' property of JsonWebKey is invalid",
"DataError",
);
}
+ }
- // 5.
- // Section 4.3 of RFC7517
- if (jwk.key_ops !== undefined) {
- if (
- ArrayPrototypeFind(
- jwk.key_ops,
- (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
- ) !== undefined
- ) {
+ if (jwk.ext === false && extractable === true) {
+ throw new DOMException(
+ "'ext' property of JsonWebKey must not be false if extractable is true",
+ "DataError",
+ );
+ }
+
+ // 7.
+ let hash;
+
+ // 8.
+ if (normalizedAlgorithm.name === "RSASSA-PKCS1-v1_5") {
+ switch (jwk.alg) {
+ case undefined:
+ hash = undefined;
+ break;
+ case "RS1":
+ hash = "SHA-1";
+ break;
+ case "RS256":
+ hash = "SHA-256";
+ break;
+ case "RS384":
+ hash = "SHA-384";
+ break;
+ case "RS512":
+ hash = "SHA-512";
+ break;
+ default:
throw new DOMException(
- "'key_ops' member of JsonWebKey is invalid",
+ `'alg' property of JsonWebKey must be one of 'RS1', 'RS256', 'RS384', 'RS512'`,
"DataError",
);
- }
-
- if (
- !ArrayPrototypeEvery(
- jwk.key_ops,
- (u) => ArrayPrototypeIncludes(keyUsages, u),
- )
- ) {
+ }
+ } else if (normalizedAlgorithm.name === "RSA-PSS") {
+ switch (jwk.alg) {
+ case undefined:
+ hash = undefined;
+ break;
+ case "PS1":
+ hash = "SHA-1";
+ break;
+ case "PS256":
+ hash = "SHA-256";
+ break;
+ case "PS384":
+ hash = "SHA-384";
+ break;
+ case "PS512":
+ hash = "SHA-512";
+ break;
+ default:
throw new DOMException(
- "'key_ops' member of JsonWebKey is invalid",
+ `'alg' property of JsonWebKey must be one of 'PS1', 'PS256', 'PS384', 'PS512'`,
"DataError",
);
- }
}
-
- // 6.
- if (jwk.ext === false && extractable === true) {
- throw new DOMException(
- "'ext' property of JsonWebKey must not be false if extractable is true",
- "DataError",
- );
+ } else {
+ switch (jwk.alg) {
+ case undefined:
+ hash = undefined;
+ break;
+ case "RSA-OAEP":
+ hash = "SHA-1";
+ break;
+ case "RSA-OAEP-256":
+ hash = "SHA-256";
+ break;
+ case "RSA-OAEP-384":
+ hash = "SHA-384";
+ break;
+ case "RSA-OAEP-512":
+ hash = "SHA-512";
+ break;
+ default:
+ throw new DOMException(
+ `'alg' property of JsonWebKey must be one of 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', or 'RSA-OAEP-512'`,
+ "DataError",
+ );
}
+ }
- // 9.
- if (jwk.alg !== undefined && normalizedAlgorithm.name == "ECDSA") {
- let algNamedCurve;
-
- switch (jwk.alg) {
- case "ES256": {
- algNamedCurve = "P-256";
- break;
- }
- case "ES384": {
- algNamedCurve = "P-384";
- break;
- }
- case "ES512": {
- algNamedCurve = "P-521";
- break;
- }
- default:
- throw new DOMException(
- "Curve algorithm not supported",
- "DataError",
- );
- }
-
- if (algNamedCurve) {
- if (algNamedCurve !== normalizedAlgorithm.namedCurve) {
- throw new DOMException(
- "Mismatched curve algorithm",
- "DataError",
- );
- }
- }
- }
+ // 9.
+ if (hash !== undefined) {
+ // 9.1.
+ const normalizedHash = normalizeAlgorithm(hash, "digest");
- // Validate that this is a valid public key.
- if (jwk.x === undefined) {
- throw new DOMException(
- "'x' property of JsonWebKey is required for EC keys",
- "DataError",
- );
- }
- if (jwk.y === undefined) {
+ // 9.2.
+ if (normalizedHash.name !== normalizedAlgorithm.hash.name) {
throw new DOMException(
- "'y' property of JsonWebKey is required for EC keys",
+ `'alg' property of JsonWebKey must be '${normalizedAlgorithm.name}'`,
"DataError",
);
}
+ }
- if (jwk.d !== undefined) {
- // it's also a Private key
- const { rawData } = ops.op_crypto_import_key({
- algorithm: normalizedAlgorithm.name,
- namedCurve: normalizedAlgorithm.namedCurve,
- }, { jwkPrivateEc: jwk });
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, rawData);
-
- const algorithm = {
- name: normalizedAlgorithm.name,
- namedCurve: normalizedAlgorithm.namedCurve,
- };
-
- const key = constructKey(
- "private",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
-
- return key;
+ // 10.
+ if (jwk.d !== undefined) {
+ // Private key
+ const optimizationsPresent = jwk.p !== undefined ||
+ jwk.q !== undefined || jwk.dp !== undefined ||
+ jwk.dq !== undefined || jwk.qi !== undefined;
+ if (optimizationsPresent) {
+ if (jwk.q === undefined) {
+ throw new DOMException(
+ "'q' property of JsonWebKey is required for private keys",
+ "DataError",
+ );
+ }
+ if (jwk.dp === undefined) {
+ throw new DOMException(
+ "'dp' property of JsonWebKey is required for private keys",
+ "DataError",
+ );
+ }
+ if (jwk.dq === undefined) {
+ throw new DOMException(
+ "'dq' property of JsonWebKey is required for private keys",
+ "DataError",
+ );
+ }
+ if (jwk.qi === undefined) {
+ throw new DOMException(
+ "'qi' property of JsonWebKey is required for private keys",
+ "DataError",
+ );
+ }
+ if (jwk.oth !== undefined) {
+ throw new DOMException(
+ "'oth' property of JsonWebKey is not supported",
+ "NotSupportedError",
+ );
+ }
} else {
- const { rawData } = ops.op_crypto_import_key({
- algorithm: normalizedAlgorithm.name,
- namedCurve: normalizedAlgorithm.namedCurve,
- }, { jwkPublicEc: jwk });
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, rawData);
-
- const algorithm = {
- name: normalizedAlgorithm.name,
- namedCurve: normalizedAlgorithm.namedCurve,
- };
-
- const key = constructKey(
- "public",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
+ throw new DOMException(
+ "only optimized private keys are supported",
+ "NotSupportedError",
);
-
- return key;
- }
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
-
- const SUPPORTED_KEY_USAGES = {
- "RSASSA-PKCS1-v1_5": {
- public: ["verify"],
- private: ["sign"],
- jwkUse: "sig",
- },
- "RSA-PSS": {
- public: ["verify"],
- private: ["sign"],
- jwkUse: "sig",
- },
- "RSA-OAEP": {
- public: ["encrypt", "wrapKey"],
- private: ["decrypt", "unwrapKey"],
- jwkUse: "enc",
- },
- "ECDSA": {
- public: ["verify"],
- private: ["sign"],
- jwkUse: "sig",
- },
- "ECDH": {
- public: [],
- private: ["deriveKey", "deriveBits"],
- jwkUse: "enc",
- },
- };
-
- function importKeyRSA(
- format,
- normalizedAlgorithm,
- keyData,
- extractable,
- keyUsages,
- ) {
- switch (format) {
- case "pkcs8": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes(
- SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].private,
- u,
- ),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
}
- // 2-9.
const { modulusLength, publicExponent, rawData } = ops
.op_crypto_import_key(
{
algorithm: normalizedAlgorithm.name,
- // Needed to perform step 7 without normalization.
hash: normalizedAlgorithm.hash.name,
},
- { pkcs8: keyData },
+ { jwkPrivateRsa: jwk },
);
const handle = {};
@@ -3379,31 +3671,28 @@
);
return key;
- }
- case "spki": {
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes(
- SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].public,
- u,
- ),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
+ } else {
+ // Validate that this is a valid public key.
+ if (jwk.n === undefined) {
+ throw new DOMException(
+ "'n' property of JsonWebKey is required for public keys",
+ "DataError",
+ );
+ }
+ if (jwk.e === undefined) {
+ throw new DOMException(
+ "'e' property of JsonWebKey is required for public keys",
+ "DataError",
+ );
}
- // 2-9.
const { modulusLength, publicExponent, rawData } = ops
.op_crypto_import_key(
{
algorithm: normalizedAlgorithm.name,
- // Needed to perform step 7 without normalization.
hash: normalizedAlgorithm.hash.name,
},
- { spki: keyData },
+ { jwkPublicRsa: jwk },
);
const handle = {};
@@ -3426,453 +3715,241 @@
return key;
}
- case "jwk": {
- // 1.
- const jwk = keyData;
-
- // 2.
- if (jwk.d !== undefined) {
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes(
- SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].private,
- u,
- ),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
- } else if (
- ArrayPrototypeFind(
- keyUsages,
- (u) =>
- !ArrayPrototypeIncludes(
- SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].public,
- u,
- ),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
-
- // 3.
- if (StringPrototypeToUpperCase(jwk.kty) !== "RSA") {
- throw new DOMException(
- "'kty' property of JsonWebKey must be 'RSA'",
- "DataError",
- );
- }
-
- // 4.
- if (
- keyUsages.length > 0 && jwk.use !== undefined &&
- StringPrototypeToLowerCase(jwk.use) !==
- SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].jwkUse
- ) {
- throw new DOMException(
- `'use' property of JsonWebKey must be '${
- SUPPORTED_KEY_USAGES[normalizedAlgorithm.name].jwkUse
- }'`,
- "DataError",
- );
- }
-
- // 5.
- if (jwk.key_ops !== undefined) {
- if (
- ArrayPrototypeFind(
- jwk.key_ops,
- (u) => !ArrayPrototypeIncludes(recognisedUsages, u),
- ) !== undefined
- ) {
- throw new DOMException(
- "'key_ops' property of JsonWebKey is invalid",
- "DataError",
- );
- }
-
- if (
- !ArrayPrototypeEvery(
- jwk.key_ops,
- (u) => ArrayPrototypeIncludes(keyUsages, u),
- )
- ) {
- throw new DOMException(
- "'key_ops' property of JsonWebKey is invalid",
- "DataError",
- );
- }
- }
-
- if (jwk.ext === false && extractable === true) {
- throw new DOMException(
- "'ext' property of JsonWebKey must not be false if extractable is true",
- "DataError",
- );
- }
-
- // 7.
- let hash;
-
- // 8.
- if (normalizedAlgorithm.name === "RSASSA-PKCS1-v1_5") {
- switch (jwk.alg) {
- case undefined:
- hash = undefined;
- break;
- case "RS1":
- hash = "SHA-1";
- break;
- case "RS256":
- hash = "SHA-256";
- break;
- case "RS384":
- hash = "SHA-384";
- break;
- case "RS512":
- hash = "SHA-512";
- break;
- default:
- throw new DOMException(
- `'alg' property of JsonWebKey must be one of 'RS1', 'RS256', 'RS384', 'RS512'`,
- "DataError",
- );
- }
- } else if (normalizedAlgorithm.name === "RSA-PSS") {
- switch (jwk.alg) {
- case undefined:
- hash = undefined;
- break;
- case "PS1":
- hash = "SHA-1";
- break;
- case "PS256":
- hash = "SHA-256";
- break;
- case "PS384":
- hash = "SHA-384";
- break;
- case "PS512":
- hash = "SHA-512";
- break;
- default:
- throw new DOMException(
- `'alg' property of JsonWebKey must be one of 'PS1', 'PS256', 'PS384', 'PS512'`,
- "DataError",
- );
- }
- } else {
- switch (jwk.alg) {
- case undefined:
- hash = undefined;
- break;
- case "RSA-OAEP":
- hash = "SHA-1";
- break;
- case "RSA-OAEP-256":
- hash = "SHA-256";
- break;
- case "RSA-OAEP-384":
- hash = "SHA-384";
- break;
- case "RSA-OAEP-512":
- hash = "SHA-512";
- break;
- default:
- throw new DOMException(
- `'alg' property of JsonWebKey must be one of 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', or 'RSA-OAEP-512'`,
- "DataError",
- );
- }
- }
-
- // 9.
- if (hash !== undefined) {
- // 9.1.
- const normalizedHash = normalizeAlgorithm(hash, "digest");
-
- // 9.2.
- if (normalizedHash.name !== normalizedAlgorithm.hash.name) {
- throw new DOMException(
- `'alg' property of JsonWebKey must be '${normalizedAlgorithm.name}'`,
- "DataError",
- );
- }
- }
-
- // 10.
- if (jwk.d !== undefined) {
- // Private key
- const optimizationsPresent = jwk.p !== undefined ||
- jwk.q !== undefined || jwk.dp !== undefined ||
- jwk.dq !== undefined || jwk.qi !== undefined;
- if (optimizationsPresent) {
- if (jwk.q === undefined) {
- throw new DOMException(
- "'q' property of JsonWebKey is required for private keys",
- "DataError",
- );
- }
- if (jwk.dp === undefined) {
- throw new DOMException(
- "'dp' property of JsonWebKey is required for private keys",
- "DataError",
- );
- }
- if (jwk.dq === undefined) {
- throw new DOMException(
- "'dq' property of JsonWebKey is required for private keys",
- "DataError",
- );
- }
- if (jwk.qi === undefined) {
- throw new DOMException(
- "'qi' property of JsonWebKey is required for private keys",
- "DataError",
- );
- }
- if (jwk.oth !== undefined) {
- throw new DOMException(
- "'oth' property of JsonWebKey is not supported",
- "NotSupportedError",
- );
- }
- } else {
- throw new DOMException(
- "only optimized private keys are supported",
- "NotSupportedError",
- );
- }
-
- const { modulusLength, publicExponent, rawData } = ops
- .op_crypto_import_key(
- {
- algorithm: normalizedAlgorithm.name,
- hash: normalizedAlgorithm.hash.name,
- },
- { jwkPrivateRsa: jwk },
- );
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, rawData);
-
- const algorithm = {
- name: normalizedAlgorithm.name,
- modulusLength,
- publicExponent,
- hash: normalizedAlgorithm.hash,
- };
-
- const key = constructKey(
- "private",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
-
- return key;
- } else {
- // Validate that this is a valid public key.
- if (jwk.n === undefined) {
- throw new DOMException(
- "'n' property of JsonWebKey is required for public keys",
- "DataError",
- );
- }
- if (jwk.e === undefined) {
- throw new DOMException(
- "'e' property of JsonWebKey is required for public keys",
- "DataError",
- );
- }
-
- const { modulusLength, publicExponent, rawData } = ops
- .op_crypto_import_key(
- {
- algorithm: normalizedAlgorithm.name,
- hash: normalizedAlgorithm.hash.name,
- },
- { jwkPublicRsa: jwk },
- );
-
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, rawData);
-
- const algorithm = {
- name: normalizedAlgorithm.name,
- modulusLength,
- publicExponent,
- hash: normalizedAlgorithm.hash,
- };
-
- const key = constructKey(
- "public",
- extractable,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
-
- return key;
- }
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+}
+
+function importKeyHKDF(
+ format,
+ keyData,
+ extractable,
+ keyUsages,
+) {
+ if (format !== "raw") {
+ throw new DOMException("Format not supported", "NotSupportedError");
}
- function importKeyHKDF(
- format,
- keyData,
- extractable,
- keyUsages,
+ // 1.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
+ ) !== undefined
) {
- if (format !== "raw") {
- throw new DOMException("Format not supported", "NotSupportedError");
- }
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- // 1.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
+ // 2.
+ if (extractable !== false) {
+ throw new DOMException(
+ "Key must not be extractable",
+ "SyntaxError",
+ );
+ }
- // 2.
- if (extractable !== false) {
- throw new DOMException(
- "Key must not be extractable",
- "SyntaxError",
- );
- }
+ // 3.
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "secret",
+ data: keyData,
+ });
- // 3.
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "secret",
- data: keyData,
- });
+ // 4-8.
+ const algorithm = {
+ name: "HKDF",
+ };
+ const key = constructKey(
+ "secret",
+ false,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ // 9.
+ return key;
+}
+
+function importKeyPBKDF2(
+ format,
+ keyData,
+ extractable,
+ keyUsages,
+) {
+ // 1.
+ if (format !== "raw") {
+ throw new DOMException("Format not supported", "NotSupportedError");
+ }
- // 4-8.
- const algorithm = {
- name: "HKDF",
- };
- const key = constructKey(
- "secret",
- false,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
+ // 2.
+ if (
+ ArrayPrototypeFind(
+ keyUsages,
+ (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
+ ) !== undefined
+ ) {
+ throw new DOMException("Invalid key usages", "SyntaxError");
+ }
- // 9.
- return key;
+ // 3.
+ if (extractable !== false) {
+ throw new DOMException(
+ "Key must not be extractable",
+ "SyntaxError",
+ );
}
- function importKeyPBKDF2(
- format,
- keyData,
- extractable,
- keyUsages,
- ) {
- // 1.
- if (format !== "raw") {
- throw new DOMException("Format not supported", "NotSupportedError");
- }
+ // 4.
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "secret",
+ data: keyData,
+ });
- // 2.
- if (
- ArrayPrototypeFind(
- keyUsages,
- (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
- ) !== undefined
- ) {
- throw new DOMException("Invalid key usages", "SyntaxError");
- }
+ // 5-9.
+ const algorithm = {
+ name: "PBKDF2",
+ };
+ const key = constructKey(
+ "secret",
+ false,
+ usageIntersection(keyUsages, recognisedUsages),
+ algorithm,
+ handle,
+ );
+
+ // 10.
+ return key;
+}
+
+function exportKeyHMAC(format, key, innerKey) {
+ // 1.
+ if (innerKey == null) {
+ throw new DOMException("Key is not available", "OperationError");
+ }
+ switch (format) {
// 3.
- if (extractable !== false) {
- throw new DOMException(
- "Key must not be extractable",
- "SyntaxError",
- );
+ case "raw": {
+ const bits = innerKey.data;
+ for (let _i = 7 & (8 - bits.length % 8); _i > 0; _i--) {
+ bits.push(0);
+ }
+ // 4-5.
+ return bits.buffer;
}
+ case "jwk": {
+ // 1-2.
+ const jwk = {
+ kty: "oct",
+ };
- // 4.
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "secret",
- data: keyData,
- });
+ // 3.
+ const data = ops.op_crypto_export_key({
+ format: "jwksecret",
+ algorithm: key[_algorithm].name,
+ }, innerKey);
+ jwk.k = data.k;
+
+ // 4.
+ const algorithm = key[_algorithm];
+ // 5.
+ const hash = algorithm.hash;
+ // 6.
+ switch (hash.name) {
+ case "SHA-1":
+ jwk.alg = "HS1";
+ break;
+ case "SHA-256":
+ jwk.alg = "HS256";
+ break;
+ case "SHA-384":
+ jwk.alg = "HS384";
+ break;
+ case "SHA-512":
+ jwk.alg = "HS512";
+ break;
+ default:
+ throw new DOMException(
+ "Hash algorithm not supported",
+ "NotSupportedError",
+ );
+ }
+ // 7.
+ jwk.key_ops = key.usages;
+ // 8.
+ jwk.ext = key[_extractable];
+ // 9.
+ return jwk;
+ }
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+}
- // 5-9.
- const algorithm = {
- name: "PBKDF2",
- };
- const key = constructKey(
- "secret",
- false,
- usageIntersection(keyUsages, recognisedUsages),
- algorithm,
- handle,
- );
+function exportKeyRSA(format, key, innerKey) {
+ switch (format) {
+ case "pkcs8": {
+ // 1.
+ if (key[_type] !== "private") {
+ throw new DOMException(
+ "Key is not a private key",
+ "InvalidAccessError",
+ );
+ }
- // 10.
- return key;
- }
+ // 2.
+ const data = ops.op_crypto_export_key({
+ algorithm: key[_algorithm].name,
+ format: "pkcs8",
+ }, innerKey);
- function exportKeyHMAC(format, key, innerKey) {
- // 1.
- if (innerKey == null) {
- throw new DOMException("Key is not available", "OperationError");
+ // 3.
+ return data.buffer;
}
+ case "spki": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
+ );
+ }
+
+ // 2.
+ const data = ops.op_crypto_export_key({
+ algorithm: key[_algorithm].name,
+ format: "spki",
+ }, innerKey);
- switch (format) {
// 3.
- case "raw": {
- const bits = innerKey.data;
- for (let _i = 7 & (8 - bits.length % 8); _i > 0; _i--) {
- bits.push(0);
- }
- // 4-5.
- return bits.buffer;
- }
- case "jwk": {
- // 1-2.
- const jwk = {
- kty: "oct",
- };
+ return data.buffer;
+ }
+ case "jwk": {
+ // 1-2.
+ const jwk = {
+ kty: "RSA",
+ };
- // 3.
- const data = ops.op_crypto_export_key({
- format: "jwksecret",
- algorithm: key[_algorithm].name,
- }, innerKey);
- jwk.k = data.k;
+ // 3.
+ const hash = key[_algorithm].hash.name;
- // 4.
- const algorithm = key[_algorithm];
- // 5.
- const hash = algorithm.hash;
- // 6.
- switch (hash.name) {
+ // 4.
+ if (key[_algorithm].name === "RSASSA-PKCS1-v1_5") {
+ switch (hash) {
case "SHA-1":
- jwk.alg = "HS1";
+ jwk.alg = "RS1";
break;
case "SHA-256":
- jwk.alg = "HS256";
+ jwk.alg = "RS256";
break;
case "SHA-384":
- jwk.alg = "HS384";
+ jwk.alg = "RS384";
break;
case "SHA-512":
- jwk.alg = "HS512";
+ jwk.alg = "RS512";
break;
default:
throw new DOMException(
@@ -3880,848 +3957,763 @@
"NotSupportedError",
);
}
- // 7.
- jwk.key_ops = key.usages;
- // 8.
- jwk.ext = key[_extractable];
- // 9.
- return jwk;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
-
- function exportKeyRSA(format, key, innerKey) {
- switch (format) {
- case "pkcs8": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key is not a private key",
- "InvalidAccessError",
- );
+ } else if (key[_algorithm].name === "RSA-PSS") {
+ switch (hash) {
+ case "SHA-1":
+ jwk.alg = "PS1";
+ break;
+ case "SHA-256":
+ jwk.alg = "PS256";
+ break;
+ case "SHA-384":
+ jwk.alg = "PS384";
+ break;
+ case "SHA-512":
+ jwk.alg = "PS512";
+ break;
+ default:
+ throw new DOMException(
+ "Hash algorithm not supported",
+ "NotSupportedError",
+ );
}
-
- // 2.
- const data = ops.op_crypto_export_key({
- algorithm: key[_algorithm].name,
- format: "pkcs8",
- }, innerKey);
-
- // 3.
- return data.buffer;
- }
- case "spki": {
- // 1.
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key is not a public key",
- "InvalidAccessError",
- );
+ } else {
+ switch (hash) {
+ case "SHA-1":
+ jwk.alg = "RSA-OAEP";
+ break;
+ case "SHA-256":
+ jwk.alg = "RSA-OAEP-256";
+ break;
+ case "SHA-384":
+ jwk.alg = "RSA-OAEP-384";
+ break;
+ case "SHA-512":
+ jwk.alg = "RSA-OAEP-512";
+ break;
+ default:
+ throw new DOMException(
+ "Hash algorithm not supported",
+ "NotSupportedError",
+ );
}
-
- // 2.
- const data = ops.op_crypto_export_key({
- algorithm: key[_algorithm].name,
- format: "spki",
- }, innerKey);
-
- // 3.
- return data.buffer;
}
- case "jwk": {
- // 1-2.
- const jwk = {
- kty: "RSA",
- };
- // 3.
- const hash = key[_algorithm].hash.name;
-
- // 4.
- if (key[_algorithm].name === "RSASSA-PKCS1-v1_5") {
- switch (hash) {
- case "SHA-1":
- jwk.alg = "RS1";
- break;
- case "SHA-256":
- jwk.alg = "RS256";
- break;
- case "SHA-384":
- jwk.alg = "RS384";
- break;
- case "SHA-512":
- jwk.alg = "RS512";
- break;
- default:
- throw new DOMException(
- "Hash algorithm not supported",
- "NotSupportedError",
- );
- }
- } else if (key[_algorithm].name === "RSA-PSS") {
- switch (hash) {
- case "SHA-1":
- jwk.alg = "PS1";
- break;
- case "SHA-256":
- jwk.alg = "PS256";
- break;
- case "SHA-384":
- jwk.alg = "PS384";
- break;
- case "SHA-512":
- jwk.alg = "PS512";
- break;
- default:
- throw new DOMException(
- "Hash algorithm not supported",
- "NotSupportedError",
- );
- }
- } else {
- switch (hash) {
- case "SHA-1":
- jwk.alg = "RSA-OAEP";
- break;
- case "SHA-256":
- jwk.alg = "RSA-OAEP-256";
- break;
- case "SHA-384":
- jwk.alg = "RSA-OAEP-384";
- break;
- case "SHA-512":
- jwk.alg = "RSA-OAEP-512";
- break;
- default:
- throw new DOMException(
- "Hash algorithm not supported",
- "NotSupportedError",
- );
- }
- }
-
- // 5-6.
- const data = ops.op_crypto_export_key({
- format: key[_type] === "private" ? "jwkprivate" : "jwkpublic",
- algorithm: key[_algorithm].name,
- }, innerKey);
- ObjectAssign(jwk, data);
+ // 5-6.
+ const data = ops.op_crypto_export_key({
+ format: key[_type] === "private" ? "jwkprivate" : "jwkpublic",
+ algorithm: key[_algorithm].name,
+ }, innerKey);
+ ObjectAssign(jwk, data);
- // 7.
- jwk.key_ops = key.usages;
+ // 7.
+ jwk.key_ops = key.usages;
- // 8.
- jwk.ext = key[_extractable];
+ // 8.
+ jwk.ext = key[_extractable];
- return jwk;
- }
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
+ return jwk;
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
}
+}
- function exportKeyEd25519(format, key, innerKey) {
- switch (format) {
- case "raw": {
- // 1.
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key is not a public key",
- "InvalidAccessError",
- );
- }
-
- // 2-3.
- return innerKey.buffer;
+function exportKeyEd25519(format, key, innerKey) {
+ switch (format) {
+ case "raw": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
+ );
}
- case "spki": {
- // 1.
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key is not a public key",
- "InvalidAccessError",
- );
- }
- const spkiDer = ops.op_export_spki_ed25519(innerKey);
- return spkiDer.buffer;
+ // 2-3.
+ return innerKey.buffer;
+ }
+ case "spki": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
+ );
}
- case "pkcs8": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key is not a public key",
- "InvalidAccessError",
- );
- }
- const pkcs8Der = ops.op_export_pkcs8_ed25519(
- new Uint8Array([0x04, 0x22, ...new SafeArrayIterator(innerKey)]),
+ const spkiDer = ops.op_export_spki_ed25519(innerKey);
+ return spkiDer.buffer;
+ }
+ case "pkcs8": {
+ // 1.
+ if (key[_type] !== "private") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
);
- pkcs8Der[15] = 0x20;
- return pkcs8Der.buffer;
}
- case "jwk": {
- const x = key[_type] === "private"
- ? ops.op_jwk_x_ed25519(innerKey)
- : ops.op_crypto_base64url_encode(innerKey);
- const jwk = {
- kty: "OKP",
- alg: "EdDSA",
- crv: "Ed25519",
- x,
- "key_ops": key.usages,
- ext: key[_extractable],
- };
- if (key[_type] === "private") {
- jwk.d = ops.op_crypto_base64url_encode(innerKey);
- }
- return jwk;
+
+ const pkcs8Der = ops.op_export_pkcs8_ed25519(
+ new Uint8Array([0x04, 0x22, ...new SafeArrayIterator(innerKey)]),
+ );
+ pkcs8Der[15] = 0x20;
+ return pkcs8Der.buffer;
+ }
+ case "jwk": {
+ const x = key[_type] === "private"
+ ? ops.op_jwk_x_ed25519(innerKey)
+ : ops.op_crypto_base64url_encode(innerKey);
+ const jwk = {
+ kty: "OKP",
+ alg: "EdDSA",
+ crv: "Ed25519",
+ x,
+ "key_ops": key.usages,
+ ext: key[_extractable],
+ };
+ if (key[_type] === "private") {
+ jwk.d = ops.op_crypto_base64url_encode(innerKey);
}
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
+ return jwk;
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
}
+}
- function exportKeyX25519(format, key, innerKey) {
- switch (format) {
- case "raw": {
- // 1.
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key is not a public key",
- "InvalidAccessError",
- );
- }
-
- // 2-3.
- return innerKey.buffer;
+function exportKeyX25519(format, key, innerKey) {
+ switch (format) {
+ case "raw": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
+ );
}
- case "spki": {
- // 1.
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key is not a public key",
- "InvalidAccessError",
- );
- }
- const spkiDer = ops.op_export_spki_x25519(innerKey);
- return spkiDer.buffer;
+ // 2-3.
+ return innerKey.buffer;
+ }
+ case "spki": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
+ );
}
- case "pkcs8": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key is not a public key",
- "InvalidAccessError",
- );
- }
- const pkcs8Der = ops.op_export_pkcs8_x25519(
- new Uint8Array([0x04, 0x22, ...new SafeArrayIterator(innerKey)]),
+ const spkiDer = ops.op_export_spki_x25519(innerKey);
+ return spkiDer.buffer;
+ }
+ case "pkcs8": {
+ // 1.
+ if (key[_type] !== "private") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
);
- pkcs8Der[15] = 0x20;
- return pkcs8Der.buffer;
- }
- case "jwk": {
- if (key[_type] === "private") {
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- const x = ops.op_crypto_base64url_encode(innerKey);
- const jwk = {
- kty: "OKP",
- crv: "X25519",
- x,
- "key_ops": key.usages,
- ext: key[_extractable],
- };
- return jwk;
}
- default:
+
+ const pkcs8Der = ops.op_export_pkcs8_x25519(
+ new Uint8Array([0x04, 0x22, ...new SafeArrayIterator(innerKey)]),
+ );
+ pkcs8Der[15] = 0x20;
+ return pkcs8Der.buffer;
+ }
+ case "jwk": {
+ if (key[_type] === "private") {
throw new DOMException("Not implemented", "NotSupportedError");
+ }
+ const x = ops.op_crypto_base64url_encode(innerKey);
+ const jwk = {
+ kty: "OKP",
+ crv: "X25519",
+ x,
+ "key_ops": key.usages,
+ ext: key[_extractable],
+ };
+ return jwk;
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
}
+}
- function exportKeyEC(format, key, innerKey) {
- switch (format) {
- case "raw": {
- // 1.
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key is not a public key",
- "InvalidAccessError",
- );
- }
+function exportKeyEC(format, key, innerKey) {
+ switch (format) {
+ case "raw": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
+ );
+ }
- // 2.
- const data = ops.op_crypto_export_key({
- algorithm: key[_algorithm].name,
- namedCurve: key[_algorithm].namedCurve,
- format: "raw",
- }, innerKey);
+ // 2.
+ const data = ops.op_crypto_export_key({
+ algorithm: key[_algorithm].name,
+ namedCurve: key[_algorithm].namedCurve,
+ format: "raw",
+ }, innerKey);
- return data.buffer;
+ return data.buffer;
+ }
+ case "pkcs8": {
+ // 1.
+ if (key[_type] !== "private") {
+ throw new DOMException(
+ "Key is not a private key",
+ "InvalidAccessError",
+ );
}
- case "pkcs8": {
- // 1.
- if (key[_type] !== "private") {
- throw new DOMException(
- "Key is not a private key",
- "InvalidAccessError",
- );
- }
- // 2.
- const data = ops.op_crypto_export_key({
- algorithm: key[_algorithm].name,
- namedCurve: key[_algorithm].namedCurve,
- format: "pkcs8",
- }, innerKey);
+ // 2.
+ const data = ops.op_crypto_export_key({
+ algorithm: key[_algorithm].name,
+ namedCurve: key[_algorithm].namedCurve,
+ format: "pkcs8",
+ }, innerKey);
- return data.buffer;
+ return data.buffer;
+ }
+ case "spki": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key is not a public key",
+ "InvalidAccessError",
+ );
}
- case "spki": {
- // 1.
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key is not a public key",
- "InvalidAccessError",
- );
+
+ // 2.
+ const data = ops.op_crypto_export_key({
+ algorithm: key[_algorithm].name,
+ namedCurve: key[_algorithm].namedCurve,
+ format: "spki",
+ }, innerKey);
+
+ return data.buffer;
+ }
+ case "jwk": {
+ if (key[_algorithm].name == "ECDSA") {
+ // 1-2.
+ const jwk = {
+ kty: "EC",
+ };
+
+ // 3.1
+ jwk.crv = key[_algorithm].namedCurve;
+
+ // Missing from spec
+ let algNamedCurve;
+
+ switch (key[_algorithm].namedCurve) {
+ case "P-256": {
+ algNamedCurve = "ES256";
+ break;
+ }
+ case "P-384": {
+ algNamedCurve = "ES384";
+ break;
+ }
+ case "P-521": {
+ algNamedCurve = "ES512";
+ break;
+ }
+ default:
+ throw new DOMException(
+ "Curve algorithm not supported",
+ "DataError",
+ );
}
- // 2.
+ jwk.alg = algNamedCurve;
+
+ // 3.2 - 3.4.
const data = ops.op_crypto_export_key({
+ format: key[_type] === "private" ? "jwkprivate" : "jwkpublic",
algorithm: key[_algorithm].name,
namedCurve: key[_algorithm].namedCurve,
- format: "spki",
}, innerKey);
+ ObjectAssign(jwk, data);
- return data.buffer;
- }
- case "jwk": {
- if (key[_algorithm].name == "ECDSA") {
- // 1-2.
- const jwk = {
- kty: "EC",
- };
-
- // 3.1
- jwk.crv = key[_algorithm].namedCurve;
-
- // Missing from spec
- let algNamedCurve;
-
- switch (key[_algorithm].namedCurve) {
- case "P-256": {
- algNamedCurve = "ES256";
- break;
- }
- case "P-384": {
- algNamedCurve = "ES384";
- break;
- }
- case "P-521": {
- algNamedCurve = "ES512";
- break;
- }
- default:
- throw new DOMException(
- "Curve algorithm not supported",
- "DataError",
- );
- }
-
- jwk.alg = algNamedCurve;
-
- // 3.2 - 3.4.
- const data = ops.op_crypto_export_key({
- format: key[_type] === "private" ? "jwkprivate" : "jwkpublic",
- algorithm: key[_algorithm].name,
- namedCurve: key[_algorithm].namedCurve,
- }, innerKey);
- ObjectAssign(jwk, data);
-
- // 4.
- jwk.key_ops = key.usages;
+ // 4.
+ jwk.key_ops = key.usages;
- // 5.
- jwk.ext = key[_extractable];
+ // 5.
+ jwk.ext = key[_extractable];
- return jwk;
- } else { // ECDH
- // 1-2.
- const jwk = {
- kty: "EC",
- };
+ return jwk;
+ } else { // ECDH
+ // 1-2.
+ const jwk = {
+ kty: "EC",
+ };
- // missing step from spec
- jwk.alg = "ECDH";
+ // missing step from spec
+ jwk.alg = "ECDH";
- // 3.1
- jwk.crv = key[_algorithm].namedCurve;
+ // 3.1
+ jwk.crv = key[_algorithm].namedCurve;
- // 3.2 - 3.4
- const data = ops.op_crypto_export_key({
- format: key[_type] === "private" ? "jwkprivate" : "jwkpublic",
- algorithm: key[_algorithm].name,
- namedCurve: key[_algorithm].namedCurve,
- }, innerKey);
- ObjectAssign(jwk, data);
+ // 3.2 - 3.4
+ const data = ops.op_crypto_export_key({
+ format: key[_type] === "private" ? "jwkprivate" : "jwkpublic",
+ algorithm: key[_algorithm].name,
+ namedCurve: key[_algorithm].namedCurve,
+ }, innerKey);
+ ObjectAssign(jwk, data);
- // 4.
- jwk.key_ops = key.usages;
+ // 4.
+ jwk.key_ops = key.usages;
- // 5.
- jwk.ext = key[_extractable];
+ // 5.
+ jwk.ext = key[_extractable];
- return jwk;
- }
+ return jwk;
}
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
}
+}
- async function generateKeyAES(normalizedAlgorithm, extractable, usages) {
- const algorithmName = normalizedAlgorithm.name;
-
- // 2.
- if (!ArrayPrototypeIncludes([128, 192, 256], normalizedAlgorithm.length)) {
- throw new DOMException("Invalid key length", "OperationError");
- }
+async function generateKeyAES(normalizedAlgorithm, extractable, usages) {
+ const algorithmName = normalizedAlgorithm.name;
- // 3.
- const keyData = await core.opAsync("op_crypto_generate_key", {
- algorithm: "AES",
- length: normalizedAlgorithm.length,
- });
- const handle = {};
- WeakMapPrototypeSet(KEY_STORE, handle, {
- type: "secret",
- data: keyData,
- });
+ // 2.
+ if (!ArrayPrototypeIncludes([128, 192, 256], normalizedAlgorithm.length)) {
+ throw new DOMException("Invalid key length", "OperationError");
+ }
- // 6-8.
- const algorithm = {
- name: algorithmName,
- length: normalizedAlgorithm.length,
- };
+ // 3.
+ const keyData = await core.opAsync("op_crypto_generate_key", {
+ algorithm: "AES",
+ length: normalizedAlgorithm.length,
+ });
+ const handle = {};
+ WeakMapPrototypeSet(KEY_STORE, handle, {
+ type: "secret",
+ data: keyData,
+ });
+
+ // 6-8.
+ const algorithm = {
+ name: algorithmName,
+ length: normalizedAlgorithm.length,
+ };
- // 9-11.
- const key = constructKey(
- "secret",
- extractable,
- usages,
- algorithm,
- handle,
- );
+ // 9-11.
+ const key = constructKey(
+ "secret",
+ extractable,
+ usages,
+ algorithm,
+ handle,
+ );
+
+ // 12.
+ return key;
+}
+
+async function deriveBits(normalizedAlgorithm, baseKey, length) {
+ switch (normalizedAlgorithm.name) {
+ case "PBKDF2": {
+ // 1.
+ if (length == null || length == 0 || length % 8 !== 0) {
+ throw new DOMException("Invalid length", "OperationError");
+ }
- // 12.
- return key;
- }
+ if (normalizedAlgorithm.iterations == 0) {
+ throw new DOMException(
+ "iterations must not be zero",
+ "OperationError",
+ );
+ }
- async function deriveBits(normalizedAlgorithm, baseKey, length) {
- switch (normalizedAlgorithm.name) {
- case "PBKDF2": {
- // 1.
- if (length == null || length == 0 || length % 8 !== 0) {
- throw new DOMException("Invalid length", "OperationError");
- }
+ const handle = baseKey[_handle];
+ const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
- if (normalizedAlgorithm.iterations == 0) {
- throw new DOMException(
- "iterations must not be zero",
- "OperationError",
- );
- }
+ normalizedAlgorithm.salt = copyBuffer(normalizedAlgorithm.salt);
- const handle = baseKey[_handle];
- const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
+ const buf = await core.opAsync("op_crypto_derive_bits", {
+ key: keyData,
+ algorithm: "PBKDF2",
+ hash: normalizedAlgorithm.hash.name,
+ iterations: normalizedAlgorithm.iterations,
+ length,
+ }, normalizedAlgorithm.salt);
- normalizedAlgorithm.salt = copyBuffer(normalizedAlgorithm.salt);
+ return buf.buffer;
+ }
+ case "ECDH": {
+ // 1.
+ if (baseKey[_type] !== "private") {
+ throw new DOMException("Invalid key type", "InvalidAccessError");
+ }
+ // 2.
+ const publicKey = normalizedAlgorithm.public;
+ // 3.
+ if (publicKey[_type] !== "public") {
+ throw new DOMException("Invalid key type", "InvalidAccessError");
+ }
+ // 4.
+ if (publicKey[_algorithm].name !== baseKey[_algorithm].name) {
+ throw new DOMException(
+ "Algorithm mismatch",
+ "InvalidAccessError",
+ );
+ }
+ // 5.
+ if (
+ publicKey[_algorithm].namedCurve !== baseKey[_algorithm].namedCurve
+ ) {
+ throw new DOMException(
+ "namedCurve mismatch",
+ "InvalidAccessError",
+ );
+ }
+ // 6.
+ if (
+ ArrayPrototypeIncludes(
+ supportedNamedCurves,
+ publicKey[_algorithm].namedCurve,
+ )
+ ) {
+ const baseKeyhandle = baseKey[_handle];
+ const baseKeyData = WeakMapPrototypeGet(KEY_STORE, baseKeyhandle);
+ const publicKeyhandle = publicKey[_handle];
+ const publicKeyData = WeakMapPrototypeGet(KEY_STORE, publicKeyhandle);
const buf = await core.opAsync("op_crypto_derive_bits", {
- key: keyData,
- algorithm: "PBKDF2",
- hash: normalizedAlgorithm.hash.name,
- iterations: normalizedAlgorithm.iterations,
+ key: baseKeyData,
+ publicKey: publicKeyData,
+ algorithm: "ECDH",
+ namedCurve: publicKey[_algorithm].namedCurve,
length,
- }, normalizedAlgorithm.salt);
+ });
- return buf.buffer;
- }
- case "ECDH": {
- // 1.
- if (baseKey[_type] !== "private") {
- throw new DOMException("Invalid key type", "InvalidAccessError");
- }
- // 2.
- const publicKey = normalizedAlgorithm.public;
- // 3.
- if (publicKey[_type] !== "public") {
- throw new DOMException("Invalid key type", "InvalidAccessError");
- }
- // 4.
- if (publicKey[_algorithm].name !== baseKey[_algorithm].name) {
- throw new DOMException(
- "Algorithm mismatch",
- "InvalidAccessError",
- );
- }
- // 5.
- if (
- publicKey[_algorithm].namedCurve !== baseKey[_algorithm].namedCurve
- ) {
- throw new DOMException(
- "namedCurve mismatch",
- "InvalidAccessError",
- );
- }
- // 6.
- if (
- ArrayPrototypeIncludes(
- supportedNamedCurves,
- publicKey[_algorithm].namedCurve,
- )
- ) {
- const baseKeyhandle = baseKey[_handle];
- const baseKeyData = WeakMapPrototypeGet(KEY_STORE, baseKeyhandle);
- const publicKeyhandle = publicKey[_handle];
- const publicKeyData = WeakMapPrototypeGet(KEY_STORE, publicKeyhandle);
-
- const buf = await core.opAsync("op_crypto_derive_bits", {
- key: baseKeyData,
- publicKey: publicKeyData,
- algorithm: "ECDH",
- namedCurve: publicKey[_algorithm].namedCurve,
- length,
- });
-
- // 8.
- if (length === null) {
- return buf.buffer;
- } else if (buf.buffer.byteLength * 8 < length) {
- throw new DOMException("Invalid length", "OperationError");
- } else {
- return buf.buffer.slice(0, MathCeil(length / 8));
- }
+ // 8.
+ if (length === null) {
+ return buf.buffer;
+ } else if (buf.buffer.byteLength * 8 < length) {
+ throw new DOMException("Invalid length", "OperationError");
} else {
- throw new DOMException("Not implemented", "NotSupportedError");
+ return buf.buffer.slice(0, MathCeil(length / 8));
}
+ } else {
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+ }
+ case "HKDF": {
+ // 1.
+ if (length === null || length === 0 || length % 8 !== 0) {
+ throw new DOMException("Invalid length", "OperationError");
}
- case "HKDF": {
- // 1.
- if (length === null || length === 0 || length % 8 !== 0) {
- throw new DOMException("Invalid length", "OperationError");
- }
- const handle = baseKey[_handle];
- const keyDerivationKey = WeakMapPrototypeGet(KEY_STORE, handle);
+ const handle = baseKey[_handle];
+ const keyDerivationKey = WeakMapPrototypeGet(KEY_STORE, handle);
- normalizedAlgorithm.salt = copyBuffer(normalizedAlgorithm.salt);
+ normalizedAlgorithm.salt = copyBuffer(normalizedAlgorithm.salt);
- normalizedAlgorithm.info = copyBuffer(normalizedAlgorithm.info);
+ normalizedAlgorithm.info = copyBuffer(normalizedAlgorithm.info);
- const buf = await core.opAsync("op_crypto_derive_bits", {
- key: keyDerivationKey,
- algorithm: "HKDF",
- hash: normalizedAlgorithm.hash.name,
- info: normalizedAlgorithm.info,
- length,
- }, normalizedAlgorithm.salt);
+ const buf = await core.opAsync("op_crypto_derive_bits", {
+ key: keyDerivationKey,
+ algorithm: "HKDF",
+ hash: normalizedAlgorithm.hash.name,
+ info: normalizedAlgorithm.info,
+ length,
+ }, normalizedAlgorithm.salt);
- return buf.buffer;
+ return buf.buffer;
+ }
+ case "X25519": {
+ // 1.
+ if (baseKey[_type] !== "private") {
+ throw new DOMException("Invalid key type", "InvalidAccessError");
+ }
+ // 2.
+ const publicKey = normalizedAlgorithm.public;
+ // 3.
+ if (publicKey[_type] !== "public") {
+ throw new DOMException("Invalid key type", "InvalidAccessError");
+ }
+ // 4.
+ if (publicKey[_algorithm].name !== baseKey[_algorithm].name) {
+ throw new DOMException(
+ "Algorithm mismatch",
+ "InvalidAccessError",
+ );
}
- case "X25519": {
- // 1.
- if (baseKey[_type] !== "private") {
- throw new DOMException("Invalid key type", "InvalidAccessError");
- }
- // 2.
- const publicKey = normalizedAlgorithm.public;
- // 3.
- if (publicKey[_type] !== "public") {
- throw new DOMException("Invalid key type", "InvalidAccessError");
- }
- // 4.
- if (publicKey[_algorithm].name !== baseKey[_algorithm].name) {
- throw new DOMException(
- "Algorithm mismatch",
- "InvalidAccessError",
- );
- }
- // 5.
- const kHandle = baseKey[_handle];
- const k = WeakMapPrototypeGet(KEY_STORE, kHandle);
+ // 5.
+ const kHandle = baseKey[_handle];
+ const k = WeakMapPrototypeGet(KEY_STORE, kHandle);
- const uHandle = publicKey[_handle];
- const u = WeakMapPrototypeGet(KEY_STORE, uHandle);
+ const uHandle = publicKey[_handle];
+ const u = WeakMapPrototypeGet(KEY_STORE, uHandle);
- const secret = new Uint8Array(32);
- const isIdentity = ops.op_derive_bits_x25519(k, u, secret);
+ const secret = new Uint8Array(32);
+ const isIdentity = ops.op_derive_bits_x25519(k, u, secret);
- // 6.
- if (isIdentity) {
- throw new DOMException("Invalid key", "OperationError");
- }
+ // 6.
+ if (isIdentity) {
+ throw new DOMException("Invalid key", "OperationError");
+ }
- // 7.
- if (length === null) {
- return secret.buffer;
- } else if (
- secret.buffer.byteLength * 8 < length
- ) {
- throw new DOMException("Invalid length", "OperationError");
- } else {
- return secret.buffer.slice(0, MathCeil(length / 8));
- }
+ // 7.
+ if (length === null) {
+ return secret.buffer;
+ } else if (
+ secret.buffer.byteLength * 8 < length
+ ) {
+ throw new DOMException("Invalid length", "OperationError");
+ } else {
+ return secret.buffer.slice(0, MathCeil(length / 8));
}
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
}
+}
- async function encrypt(normalizedAlgorithm, key, data) {
- const handle = key[_handle];
- const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
-
- switch (normalizedAlgorithm.name) {
- case "RSA-OAEP": {
- // 1.
- if (key[_type] !== "public") {
- throw new DOMException(
- "Key type not supported",
- "InvalidAccessError",
- );
- }
-
- // 2.
- if (normalizedAlgorithm.label) {
- normalizedAlgorithm.label = copyBuffer(normalizedAlgorithm.label);
- } else {
- normalizedAlgorithm.label = new Uint8Array();
- }
+async function encrypt(normalizedAlgorithm, key, data) {
+ const handle = key[_handle];
+ const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
- // 3-5.
- const hashAlgorithm = key[_algorithm].hash.name;
- const cipherText = await core.opAsync("op_crypto_encrypt", {
- key: keyData,
- algorithm: "RSA-OAEP",
- hash: hashAlgorithm,
- label: normalizedAlgorithm.label,
- }, data);
+ switch (normalizedAlgorithm.name) {
+ case "RSA-OAEP": {
+ // 1.
+ if (key[_type] !== "public") {
+ throw new DOMException(
+ "Key type not supported",
+ "InvalidAccessError",
+ );
+ }
- // 6.
- return cipherText.buffer;
+ // 2.
+ if (normalizedAlgorithm.label) {
+ normalizedAlgorithm.label = copyBuffer(normalizedAlgorithm.label);
+ } else {
+ normalizedAlgorithm.label = new Uint8Array();
}
- case "AES-CBC": {
- normalizedAlgorithm.iv = copyBuffer(normalizedAlgorithm.iv);
- // 1.
- if (normalizedAlgorithm.iv.byteLength !== 16) {
- throw new DOMException(
- "Initialization vector must be 16 bytes",
- "OperationError",
- );
- }
+ // 3-5.
+ const hashAlgorithm = key[_algorithm].hash.name;
+ const cipherText = await core.opAsync("op_crypto_encrypt", {
+ key: keyData,
+ algorithm: "RSA-OAEP",
+ hash: hashAlgorithm,
+ label: normalizedAlgorithm.label,
+ }, data);
- // 2.
- const cipherText = await core.opAsync("op_crypto_encrypt", {
- key: keyData,
- algorithm: "AES-CBC",
- length: key[_algorithm].length,
- iv: normalizedAlgorithm.iv,
- }, data);
+ // 6.
+ return cipherText.buffer;
+ }
+ case "AES-CBC": {
+ normalizedAlgorithm.iv = copyBuffer(normalizedAlgorithm.iv);
- // 4.
- return cipherText.buffer;
+ // 1.
+ if (normalizedAlgorithm.iv.byteLength !== 16) {
+ throw new DOMException(
+ "Initialization vector must be 16 bytes",
+ "OperationError",
+ );
}
- case "AES-CTR": {
- normalizedAlgorithm.counter = copyBuffer(normalizedAlgorithm.counter);
- // 1.
- if (normalizedAlgorithm.counter.byteLength !== 16) {
- throw new DOMException(
- "Counter vector must be 16 bytes",
- "OperationError",
- );
- }
-
- // 2.
- if (
- normalizedAlgorithm.length == 0 || normalizedAlgorithm.length > 128
- ) {
- throw new DOMException(
- "Counter length must not be 0 or greater than 128",
- "OperationError",
- );
- }
+ // 2.
+ const cipherText = await core.opAsync("op_crypto_encrypt", {
+ key: keyData,
+ algorithm: "AES-CBC",
+ length: key[_algorithm].length,
+ iv: normalizedAlgorithm.iv,
+ }, data);
+
+ // 4.
+ return cipherText.buffer;
+ }
+ case "AES-CTR": {
+ normalizedAlgorithm.counter = copyBuffer(normalizedAlgorithm.counter);
- // 3.
- const cipherText = await core.opAsync("op_crypto_encrypt", {
- key: keyData,
- algorithm: "AES-CTR",
- keyLength: key[_algorithm].length,
- counter: normalizedAlgorithm.counter,
- ctrLength: normalizedAlgorithm.length,
- }, data);
+ // 1.
+ if (normalizedAlgorithm.counter.byteLength !== 16) {
+ throw new DOMException(
+ "Counter vector must be 16 bytes",
+ "OperationError",
+ );
+ }
- // 4.
- return cipherText.buffer;
+ // 2.
+ if (
+ normalizedAlgorithm.length == 0 || normalizedAlgorithm.length > 128
+ ) {
+ throw new DOMException(
+ "Counter length must not be 0 or greater than 128",
+ "OperationError",
+ );
}
- case "AES-GCM": {
- normalizedAlgorithm.iv = copyBuffer(normalizedAlgorithm.iv);
- // 1.
- if (data.byteLength > (2 ** 39) - 256) {
- throw new DOMException(
- "Plaintext too large",
- "OperationError",
- );
- }
+ // 3.
+ const cipherText = await core.opAsync("op_crypto_encrypt", {
+ key: keyData,
+ algorithm: "AES-CTR",
+ keyLength: key[_algorithm].length,
+ counter: normalizedAlgorithm.counter,
+ ctrLength: normalizedAlgorithm.length,
+ }, data);
+
+ // 4.
+ return cipherText.buffer;
+ }
+ case "AES-GCM": {
+ normalizedAlgorithm.iv = copyBuffer(normalizedAlgorithm.iv);
- // 2.
- // We only support 96-bit and 128-bit nonce.
- if (
- ArrayPrototypeIncludes(
- [12, 16],
- normalizedAlgorithm.iv.byteLength,
- ) === undefined
- ) {
- throw new DOMException(
- "Initialization vector length not supported",
- "NotSupportedError",
- );
- }
+ // 1.
+ if (data.byteLength > (2 ** 39) - 256) {
+ throw new DOMException(
+ "Plaintext too large",
+ "OperationError",
+ );
+ }
- // 3.
- if (normalizedAlgorithm.additionalData !== undefined) {
- if (normalizedAlgorithm.additionalData.byteLength > (2 ** 64) - 1) {
- throw new DOMException(
- "Additional data too large",
- "OperationError",
- );
- }
- }
+ // 2.
+ // We only support 96-bit and 128-bit nonce.
+ if (
+ ArrayPrototypeIncludes(
+ [12, 16],
+ normalizedAlgorithm.iv.byteLength,
+ ) === undefined
+ ) {
+ throw new DOMException(
+ "Initialization vector length not supported",
+ "NotSupportedError",
+ );
+ }
- // 4.
- if (normalizedAlgorithm.tagLength == undefined) {
- normalizedAlgorithm.tagLength = 128;
- } else if (
- !ArrayPrototypeIncludes(
- [32, 64, 96, 104, 112, 120, 128],
- normalizedAlgorithm.tagLength,
- )
- ) {
+ // 3.
+ if (normalizedAlgorithm.additionalData !== undefined) {
+ if (normalizedAlgorithm.additionalData.byteLength > (2 ** 64) - 1) {
throw new DOMException(
- "Invalid tag length",
+ "Additional data too large",
"OperationError",
);
}
- // 5.
- if (normalizedAlgorithm.additionalData) {
- normalizedAlgorithm.additionalData = copyBuffer(
- normalizedAlgorithm.additionalData,
- );
- }
- // 6-7.
- const cipherText = await core.opAsync("op_crypto_encrypt", {
- key: keyData,
- algorithm: "AES-GCM",
- length: key[_algorithm].length,
- iv: normalizedAlgorithm.iv,
- additionalData: normalizedAlgorithm.additionalData || null,
- tagLength: normalizedAlgorithm.tagLength,
- }, data);
-
- // 8.
- return cipherText.buffer;
}
- default:
- throw new DOMException("Not implemented", "NotSupportedError");
- }
- }
- webidl.configurePrototype(SubtleCrypto);
- const subtle = webidl.createBranded(SubtleCrypto);
-
- class Crypto {
- constructor() {
- webidl.illegalConstructor();
- }
-
- getRandomValues(arrayBufferView) {
- webidl.assertBranded(this, CryptoPrototype);
- const prefix = "Failed to execute 'getRandomValues' on 'Crypto'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- // Fast path for Uint8Array
- if (ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, arrayBufferView)) {
- ops.op_crypto_get_random_values(arrayBufferView);
- return arrayBufferView;
- }
- arrayBufferView = webidl.converters.ArrayBufferView(arrayBufferView, {
- prefix,
- context: "Argument 1",
- });
- if (
- !(
- ObjectPrototypeIsPrototypeOf(Int8ArrayPrototype, arrayBufferView) ||
- ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, arrayBufferView) ||
- ObjectPrototypeIsPrototypeOf(
- Uint8ClampedArrayPrototype,
- arrayBufferView,
- ) ||
- ObjectPrototypeIsPrototypeOf(Int16ArrayPrototype, arrayBufferView) ||
- ObjectPrototypeIsPrototypeOf(Uint16ArrayPrototype, arrayBufferView) ||
- ObjectPrototypeIsPrototypeOf(Int32ArrayPrototype, arrayBufferView) ||
- ObjectPrototypeIsPrototypeOf(Uint32ArrayPrototype, arrayBufferView) ||
- ObjectPrototypeIsPrototypeOf(
- BigInt64ArrayPrototype,
- arrayBufferView,
- ) ||
- ObjectPrototypeIsPrototypeOf(BigUint64ArrayPrototype, arrayBufferView)
+ // 4.
+ if (normalizedAlgorithm.tagLength == undefined) {
+ normalizedAlgorithm.tagLength = 128;
+ } else if (
+ !ArrayPrototypeIncludes(
+ [32, 64, 96, 104, 112, 120, 128],
+ normalizedAlgorithm.tagLength,
)
) {
throw new DOMException(
- "The provided ArrayBufferView is not an integer array type",
- "TypeMismatchError",
+ "Invalid tag length",
+ "OperationError",
);
}
- const ui8 = new Uint8Array(
- arrayBufferView.buffer,
- arrayBufferView.byteOffset,
- arrayBufferView.byteLength,
- );
- ops.op_crypto_get_random_values(ui8);
- return arrayBufferView;
- }
+ // 5.
+ if (normalizedAlgorithm.additionalData) {
+ normalizedAlgorithm.additionalData = copyBuffer(
+ normalizedAlgorithm.additionalData,
+ );
+ }
+ // 6-7.
+ const cipherText = await core.opAsync("op_crypto_encrypt", {
+ key: keyData,
+ algorithm: "AES-GCM",
+ length: key[_algorithm].length,
+ iv: normalizedAlgorithm.iv,
+ additionalData: normalizedAlgorithm.additionalData || null,
+ tagLength: normalizedAlgorithm.tagLength,
+ }, data);
- randomUUID() {
- webidl.assertBranded(this, CryptoPrototype);
- return ops.op_crypto_random_uuid();
+ // 8.
+ return cipherText.buffer;
}
+ default:
+ throw new DOMException("Not implemented", "NotSupportedError");
+ }
+}
- get subtle() {
- webidl.assertBranded(this, CryptoPrototype);
- return subtle;
- }
+webidl.configurePrototype(SubtleCrypto);
+const subtle = webidl.createBranded(SubtleCrypto);
- [SymbolFor("Deno.customInspect")](inspect) {
- return `${this.constructor.name} ${inspect({})}`;
+class Crypto {
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ getRandomValues(arrayBufferView) {
+ webidl.assertBranded(this, CryptoPrototype);
+ const prefix = "Failed to execute 'getRandomValues' on 'Crypto'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ // Fast path for Uint8Array
+ if (ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, arrayBufferView)) {
+ ops.op_crypto_get_random_values(arrayBufferView);
+ return arrayBufferView;
}
+ arrayBufferView = webidl.converters.ArrayBufferView(arrayBufferView, {
+ prefix,
+ context: "Argument 1",
+ });
+ if (
+ !(
+ ObjectPrototypeIsPrototypeOf(Int8ArrayPrototype, arrayBufferView) ||
+ ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, arrayBufferView) ||
+ ObjectPrototypeIsPrototypeOf(
+ Uint8ClampedArrayPrototype,
+ arrayBufferView,
+ ) ||
+ ObjectPrototypeIsPrototypeOf(Int16ArrayPrototype, arrayBufferView) ||
+ ObjectPrototypeIsPrototypeOf(Uint16ArrayPrototype, arrayBufferView) ||
+ ObjectPrototypeIsPrototypeOf(Int32ArrayPrototype, arrayBufferView) ||
+ ObjectPrototypeIsPrototypeOf(Uint32ArrayPrototype, arrayBufferView) ||
+ ObjectPrototypeIsPrototypeOf(
+ BigInt64ArrayPrototype,
+ arrayBufferView,
+ ) ||
+ ObjectPrototypeIsPrototypeOf(BigUint64ArrayPrototype, arrayBufferView)
+ )
+ ) {
+ throw new DOMException(
+ "The provided ArrayBufferView is not an integer array type",
+ "TypeMismatchError",
+ );
+ }
+ const ui8 = new Uint8Array(
+ arrayBufferView.buffer,
+ arrayBufferView.byteOffset,
+ arrayBufferView.byteLength,
+ );
+ ops.op_crypto_get_random_values(ui8);
+ return arrayBufferView;
}
- webidl.configurePrototype(Crypto);
- const CryptoPrototype = Crypto.prototype;
+ randomUUID() {
+ webidl.assertBranded(this, CryptoPrototype);
+ return ops.op_crypto_random_uuid();
+ }
- window.__bootstrap.crypto = {
- SubtleCrypto,
- crypto: webidl.createBranded(Crypto),
- Crypto,
- CryptoKey,
- };
-})(this);
+ get subtle() {
+ webidl.assertBranded(this, CryptoPrototype);
+ return subtle;
+ }
+
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${inspect({})}`;
+ }
+}
+
+webidl.configurePrototype(Crypto);
+const CryptoPrototype = Crypto.prototype;
+
+const crypto = webidl.createBranded(Crypto);
+export { Crypto, crypto, CryptoKey, SubtleCrypto };
diff --git a/ext/crypto/01_webidl.js b/ext/crypto/01_webidl.js
index d381672fd..86d50f8a5 100644
--- a/ext/crypto/01_webidl.js
+++ b/ext/crypto/01_webidl.js
@@ -4,484 +4,481 @@
/// <reference path="../../core/lib.deno_core.d.ts" />
/// <reference path="../webidl/internal.d.ts" />
-"use strict";
-
-((window) => {
- const webidl = window.__bootstrap.webidl;
- const { CryptoKey } = window.__bootstrap.crypto;
- const {
- ArrayBufferIsView,
- ArrayBufferPrototype,
- ObjectPrototypeIsPrototypeOf,
- SafeArrayIterator,
- } = window.__bootstrap.primordials;
-
- webidl.converters.AlgorithmIdentifier = (V, opts) => {
- // Union for (object or DOMString)
- if (webidl.type(V) == "Object") {
- return webidl.converters.object(V, opts);
- }
- return webidl.converters.DOMString(V, opts);
- };
-
- webidl.converters["BufferSource or JsonWebKey"] = (V, opts) => {
- // Union for (BufferSource or JsonWebKey)
- if (
- ArrayBufferIsView(V) ||
- ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V)
- ) {
- return webidl.converters.BufferSource(V, opts);
- }
- return webidl.converters.JsonWebKey(V, opts);
- };
-
- webidl.converters.KeyType = webidl.createEnumConverter("KeyType", [
- "public",
- "private",
- "secret",
- ]);
-
- webidl.converters.KeyFormat = webidl.createEnumConverter("KeyFormat", [
- "raw",
- "pkcs8",
- "spki",
- "jwk",
- ]);
-
- webidl.converters.KeyUsage = webidl.createEnumConverter("KeyUsage", [
- "encrypt",
- "decrypt",
- "sign",
- "verify",
- "deriveKey",
- "deriveBits",
- "wrapKey",
- "unwrapKey",
- ]);
-
- webidl.converters["sequence<KeyUsage>"] = webidl.createSequenceConverter(
- webidl.converters.KeyUsage,
- );
+const primordials = globalThis.__bootstrap.primordials;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { CryptoKey } from "internal:ext/crypto/00_crypto.js";
+const {
+ ArrayBufferIsView,
+ ArrayBufferPrototype,
+ ObjectPrototypeIsPrototypeOf,
+ SafeArrayIterator,
+} = primordials;
+
+webidl.converters.AlgorithmIdentifier = (V, opts) => {
+ // Union for (object or DOMString)
+ if (webidl.type(V) == "Object") {
+ return webidl.converters.object(V, opts);
+ }
+ return webidl.converters.DOMString(V, opts);
+};
+
+webidl.converters["BufferSource or JsonWebKey"] = (V, opts) => {
+ // Union for (BufferSource or JsonWebKey)
+ if (
+ ArrayBufferIsView(V) ||
+ ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V)
+ ) {
+ return webidl.converters.BufferSource(V, opts);
+ }
+ return webidl.converters.JsonWebKey(V, opts);
+};
+
+webidl.converters.KeyType = webidl.createEnumConverter("KeyType", [
+ "public",
+ "private",
+ "secret",
+]);
+
+webidl.converters.KeyFormat = webidl.createEnumConverter("KeyFormat", [
+ "raw",
+ "pkcs8",
+ "spki",
+ "jwk",
+]);
+
+webidl.converters.KeyUsage = webidl.createEnumConverter("KeyUsage", [
+ "encrypt",
+ "decrypt",
+ "sign",
+ "verify",
+ "deriveKey",
+ "deriveBits",
+ "wrapKey",
+ "unwrapKey",
+]);
+
+webidl.converters["sequence<KeyUsage>"] = webidl.createSequenceConverter(
+ webidl.converters.KeyUsage,
+);
+
+webidl.converters.HashAlgorithmIdentifier =
+ webidl.converters.AlgorithmIdentifier;
+
+/** @type {webidl.Dictionary} */
+const dictAlgorithm = [{
+ key: "name",
+ converter: webidl.converters.DOMString,
+ required: true,
+}];
+
+webidl.converters.Algorithm = webidl
+ .createDictionaryConverter("Algorithm", dictAlgorithm);
+
+webidl.converters.BigInteger = webidl.converters.Uint8Array;
+
+/** @type {webidl.Dictionary} */
+const dictRsaKeyGenParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "modulusLength",
+ converter: (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
+ required: true,
+ },
+ {
+ key: "publicExponent",
+ converter: webidl.converters.BigInteger,
+ required: true,
+ },
+];
- webidl.converters.HashAlgorithmIdentifier =
- webidl.converters.AlgorithmIdentifier;
+webidl.converters.RsaKeyGenParams = webidl
+ .createDictionaryConverter("RsaKeyGenParams", dictRsaKeyGenParams);
- /** @type {__bootstrap.webidl.Dictionary} */
- const dictAlgorithm = [{
- key: "name",
- converter: webidl.converters.DOMString,
+const dictRsaHashedKeyGenParams = [
+ ...new SafeArrayIterator(dictRsaKeyGenParams),
+ {
+ key: "hash",
+ converter: webidl.converters.HashAlgorithmIdentifier,
required: true,
- }];
-
- webidl.converters.Algorithm = webidl
- .createDictionaryConverter("Algorithm", dictAlgorithm);
-
- webidl.converters.BigInteger = webidl.converters.Uint8Array;
-
- /** @type {__bootstrap.webidl.Dictionary} */
- const dictRsaKeyGenParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "modulusLength",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- required: true,
- },
- {
- key: "publicExponent",
- converter: webidl.converters.BigInteger,
- required: true,
- },
- ];
-
- webidl.converters.RsaKeyGenParams = webidl
- .createDictionaryConverter("RsaKeyGenParams", dictRsaKeyGenParams);
-
- const dictRsaHashedKeyGenParams = [
- ...new SafeArrayIterator(dictRsaKeyGenParams),
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- ];
-
- webidl.converters.RsaHashedKeyGenParams = webidl.createDictionaryConverter(
- "RsaHashedKeyGenParams",
- dictRsaHashedKeyGenParams,
- );
+ },
+];
+
+webidl.converters.RsaHashedKeyGenParams = webidl.createDictionaryConverter(
+ "RsaHashedKeyGenParams",
+ dictRsaHashedKeyGenParams,
+);
+
+const dictRsaHashedImportParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "hash",
+ converter: webidl.converters.HashAlgorithmIdentifier,
+ required: true,
+ },
+];
- const dictRsaHashedImportParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- ];
-
- webidl.converters.RsaHashedImportParams = webidl.createDictionaryConverter(
- "RsaHashedImportParams",
- dictRsaHashedImportParams,
- );
+webidl.converters.RsaHashedImportParams = webidl.createDictionaryConverter(
+ "RsaHashedImportParams",
+ dictRsaHashedImportParams,
+);
- webidl.converters.NamedCurve = webidl.converters.DOMString;
+webidl.converters.NamedCurve = webidl.converters.DOMString;
+
+const dictEcKeyImportParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "namedCurve",
+ converter: webidl.converters.NamedCurve,
+ required: true,
+ },
+];
+
+webidl.converters.EcKeyImportParams = webidl.createDictionaryConverter(
+ "EcKeyImportParams",
+ dictEcKeyImportParams,
+);
+
+const dictEcKeyGenParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "namedCurve",
+ converter: webidl.converters.NamedCurve,
+ required: true,
+ },
+];
+
+webidl.converters.EcKeyGenParams = webidl
+ .createDictionaryConverter("EcKeyGenParams", dictEcKeyGenParams);
+
+const dictAesKeyGenParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "length",
+ converter: (V, opts) =>
+ webidl.converters["unsigned short"](V, { ...opts, enforceRange: true }),
+ required: true,
+ },
+];
- const dictEcKeyImportParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "namedCurve",
- converter: webidl.converters.NamedCurve,
- required: true,
- },
- ];
+webidl.converters.AesKeyGenParams = webidl
+ .createDictionaryConverter("AesKeyGenParams", dictAesKeyGenParams);
- webidl.converters.EcKeyImportParams = webidl.createDictionaryConverter(
- "EcKeyImportParams",
- dictEcKeyImportParams,
- );
+const dictHmacKeyGenParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "hash",
+ converter: webidl.converters.HashAlgorithmIdentifier,
+ required: true,
+ },
+ {
+ key: "length",
+ converter: (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
+ },
+];
+
+webidl.converters.HmacKeyGenParams = webidl
+ .createDictionaryConverter("HmacKeyGenParams", dictHmacKeyGenParams);
+
+const dictRsaPssParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "saltLength",
+ converter: (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
+ required: true,
+ },
+];
+
+webidl.converters.RsaPssParams = webidl
+ .createDictionaryConverter("RsaPssParams", dictRsaPssParams);
+
+const dictRsaOaepParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "label",
+ converter: webidl.converters["BufferSource"],
+ },
+];
+
+webidl.converters.RsaOaepParams = webidl
+ .createDictionaryConverter("RsaOaepParams", dictRsaOaepParams);
+
+const dictEcdsaParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "hash",
+ converter: webidl.converters.HashAlgorithmIdentifier,
+ required: true,
+ },
+];
- const dictEcKeyGenParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "namedCurve",
- converter: webidl.converters.NamedCurve,
- required: true,
- },
- ];
-
- webidl.converters.EcKeyGenParams = webidl
- .createDictionaryConverter("EcKeyGenParams", dictEcKeyGenParams);
-
- const dictAesKeyGenParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "length",
- converter: (V, opts) =>
- webidl.converters["unsigned short"](V, { ...opts, enforceRange: true }),
- required: true,
- },
- ];
-
- webidl.converters.AesKeyGenParams = webidl
- .createDictionaryConverter("AesKeyGenParams", dictAesKeyGenParams);
-
- const dictHmacKeyGenParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- {
- key: "length",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- },
- ];
-
- webidl.converters.HmacKeyGenParams = webidl
- .createDictionaryConverter("HmacKeyGenParams", dictHmacKeyGenParams);
-
- const dictRsaPssParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "saltLength",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- required: true,
- },
- ];
-
- webidl.converters.RsaPssParams = webidl
- .createDictionaryConverter("RsaPssParams", dictRsaPssParams);
-
- const dictRsaOaepParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "label",
- converter: webidl.converters["BufferSource"],
- },
- ];
-
- webidl.converters.RsaOaepParams = webidl
- .createDictionaryConverter("RsaOaepParams", dictRsaOaepParams);
-
- const dictEcdsaParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- ];
-
- webidl.converters["EcdsaParams"] = webidl
- .createDictionaryConverter("EcdsaParams", dictEcdsaParams);
-
- const dictHmacImportParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- {
- key: "length",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- },
- ];
-
- webidl.converters.HmacImportParams = webidl
- .createDictionaryConverter("HmacImportParams", dictHmacImportParams);
-
- const dictRsaOtherPrimesInfo = [
- {
- key: "r",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "d",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "t",
- converter: webidl.converters["DOMString"],
- },
- ];
-
- webidl.converters.RsaOtherPrimesInfo = webidl.createDictionaryConverter(
- "RsaOtherPrimesInfo",
- dictRsaOtherPrimesInfo,
- );
- webidl.converters["sequence<RsaOtherPrimesInfo>"] = webidl
- .createSequenceConverter(
- webidl.converters.RsaOtherPrimesInfo,
- );
-
- const dictJsonWebKey = [
- // Sections 4.2 and 4.3 of RFC7517.
- // https://datatracker.ietf.org/doc/html/rfc7517#section-4
- {
- key: "kty",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "use",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "key_ops",
- converter: webidl.converters["sequence<DOMString>"],
- },
- {
- key: "alg",
- converter: webidl.converters["DOMString"],
- },
- // JSON Web Key Parameters Registration
- {
- key: "ext",
- converter: webidl.converters["boolean"],
- },
- // Section 6 of RFC7518 JSON Web Algorithms
- // https://datatracker.ietf.org/doc/html/rfc7518#section-6
- {
- key: "crv",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "x",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "y",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "d",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "n",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "e",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "p",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "q",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "dp",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "dq",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "qi",
- converter: webidl.converters["DOMString"],
- },
- {
- key: "oth",
- converter: webidl.converters["sequence<RsaOtherPrimesInfo>"],
- },
- {
- key: "k",
- converter: webidl.converters["DOMString"],
- },
- ];
-
- webidl.converters.JsonWebKey = webidl.createDictionaryConverter(
- "JsonWebKey",
- dictJsonWebKey,
- );
+webidl.converters["EcdsaParams"] = webidl
+ .createDictionaryConverter("EcdsaParams", dictEcdsaParams);
- const dictHkdfParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- {
- key: "salt",
- converter: webidl.converters["BufferSource"],
- required: true,
- },
- {
- key: "info",
- converter: webidl.converters["BufferSource"],
- required: true,
- },
- ];
-
- webidl.converters.HkdfParams = webidl
- .createDictionaryConverter("HkdfParams", dictHkdfParams);
-
- const dictPbkdf2Params = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "hash",
- converter: webidl.converters.HashAlgorithmIdentifier,
- required: true,
- },
- {
- key: "iterations",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- required: true,
- },
- {
- key: "salt",
- converter: webidl.converters["BufferSource"],
- required: true,
- },
- ];
-
- webidl.converters.Pbkdf2Params = webidl
- .createDictionaryConverter("Pbkdf2Params", dictPbkdf2Params);
-
- const dictAesDerivedKeyParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "length",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- required: true,
- },
- ];
-
- const dictAesCbcParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "iv",
- converter: webidl.converters["BufferSource"],
- required: true,
- },
- ];
-
- const dictAesGcmParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "iv",
- converter: webidl.converters["BufferSource"],
- required: true,
- },
- {
- key: "tagLength",
- converter: (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
- },
- {
- key: "additionalData",
- converter: webidl.converters["BufferSource"],
- },
- ];
-
- const dictAesCtrParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "counter",
- converter: webidl.converters["BufferSource"],
- required: true,
- },
- {
- key: "length",
- converter: (V, opts) =>
- webidl.converters["unsigned short"](V, { ...opts, enforceRange: true }),
- required: true,
- },
- ];
-
- webidl.converters.AesDerivedKeyParams = webidl
- .createDictionaryConverter("AesDerivedKeyParams", dictAesDerivedKeyParams);
-
- webidl.converters.AesCbcParams = webidl
- .createDictionaryConverter("AesCbcParams", dictAesCbcParams);
-
- webidl.converters.AesGcmParams = webidl
- .createDictionaryConverter("AesGcmParams", dictAesGcmParams);
-
- webidl.converters.AesCtrParams = webidl
- .createDictionaryConverter("AesCtrParams", dictAesCtrParams);
-
- webidl.converters.CryptoKey = webidl.createInterfaceConverter(
- "CryptoKey",
- CryptoKey.prototype,
+const dictHmacImportParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "hash",
+ converter: webidl.converters.HashAlgorithmIdentifier,
+ required: true,
+ },
+ {
+ key: "length",
+ converter: (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
+ },
+];
+
+webidl.converters.HmacImportParams = webidl
+ .createDictionaryConverter("HmacImportParams", dictHmacImportParams);
+
+const dictRsaOtherPrimesInfo = [
+ {
+ key: "r",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "d",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "t",
+ converter: webidl.converters["DOMString"],
+ },
+];
+
+webidl.converters.RsaOtherPrimesInfo = webidl.createDictionaryConverter(
+ "RsaOtherPrimesInfo",
+ dictRsaOtherPrimesInfo,
+);
+webidl.converters["sequence<RsaOtherPrimesInfo>"] = webidl
+ .createSequenceConverter(
+ webidl.converters.RsaOtherPrimesInfo,
);
- const dictCryptoKeyPair = [
- {
- key: "publicKey",
- converter: webidl.converters.CryptoKey,
- },
- {
- key: "privateKey",
- converter: webidl.converters.CryptoKey,
- },
- ];
-
- webidl.converters.CryptoKeyPair = webidl
- .createDictionaryConverter("CryptoKeyPair", dictCryptoKeyPair);
-
- const dictEcdhKeyDeriveParams = [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: "public",
- converter: webidl.converters.CryptoKey,
- required: true,
- },
- ];
-
- webidl.converters.EcdhKeyDeriveParams = webidl
- .createDictionaryConverter("EcdhKeyDeriveParams", dictEcdhKeyDeriveParams);
-})(this);
+const dictJsonWebKey = [
+ // Sections 4.2 and 4.3 of RFC7517.
+ // https://datatracker.ietf.org/doc/html/rfc7517#section-4
+ {
+ key: "kty",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "use",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "key_ops",
+ converter: webidl.converters["sequence<DOMString>"],
+ },
+ {
+ key: "alg",
+ converter: webidl.converters["DOMString"],
+ },
+ // JSON Web Key Parameters Registration
+ {
+ key: "ext",
+ converter: webidl.converters["boolean"],
+ },
+ // Section 6 of RFC7518 JSON Web Algorithms
+ // https://datatracker.ietf.org/doc/html/rfc7518#section-6
+ {
+ key: "crv",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "x",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "y",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "d",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "n",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "e",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "p",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "q",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "dp",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "dq",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "qi",
+ converter: webidl.converters["DOMString"],
+ },
+ {
+ key: "oth",
+ converter: webidl.converters["sequence<RsaOtherPrimesInfo>"],
+ },
+ {
+ key: "k",
+ converter: webidl.converters["DOMString"],
+ },
+];
+
+webidl.converters.JsonWebKey = webidl.createDictionaryConverter(
+ "JsonWebKey",
+ dictJsonWebKey,
+);
+
+const dictHkdfParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "hash",
+ converter: webidl.converters.HashAlgorithmIdentifier,
+ required: true,
+ },
+ {
+ key: "salt",
+ converter: webidl.converters["BufferSource"],
+ required: true,
+ },
+ {
+ key: "info",
+ converter: webidl.converters["BufferSource"],
+ required: true,
+ },
+];
+
+webidl.converters.HkdfParams = webidl
+ .createDictionaryConverter("HkdfParams", dictHkdfParams);
+
+const dictPbkdf2Params = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "hash",
+ converter: webidl.converters.HashAlgorithmIdentifier,
+ required: true,
+ },
+ {
+ key: "iterations",
+ converter: (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
+ required: true,
+ },
+ {
+ key: "salt",
+ converter: webidl.converters["BufferSource"],
+ required: true,
+ },
+];
+
+webidl.converters.Pbkdf2Params = webidl
+ .createDictionaryConverter("Pbkdf2Params", dictPbkdf2Params);
+
+const dictAesDerivedKeyParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "length",
+ converter: (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
+ required: true,
+ },
+];
+
+const dictAesCbcParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "iv",
+ converter: webidl.converters["BufferSource"],
+ required: true,
+ },
+];
+
+const dictAesGcmParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "iv",
+ converter: webidl.converters["BufferSource"],
+ required: true,
+ },
+ {
+ key: "tagLength",
+ converter: (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }),
+ },
+ {
+ key: "additionalData",
+ converter: webidl.converters["BufferSource"],
+ },
+];
+
+const dictAesCtrParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "counter",
+ converter: webidl.converters["BufferSource"],
+ required: true,
+ },
+ {
+ key: "length",
+ converter: (V, opts) =>
+ webidl.converters["unsigned short"](V, { ...opts, enforceRange: true }),
+ required: true,
+ },
+];
+
+webidl.converters.AesDerivedKeyParams = webidl
+ .createDictionaryConverter("AesDerivedKeyParams", dictAesDerivedKeyParams);
+
+webidl.converters.AesCbcParams = webidl
+ .createDictionaryConverter("AesCbcParams", dictAesCbcParams);
+
+webidl.converters.AesGcmParams = webidl
+ .createDictionaryConverter("AesGcmParams", dictAesGcmParams);
+
+webidl.converters.AesCtrParams = webidl
+ .createDictionaryConverter("AesCtrParams", dictAesCtrParams);
+
+webidl.converters.CryptoKey = webidl.createInterfaceConverter(
+ "CryptoKey",
+ CryptoKey.prototype,
+);
+
+const dictCryptoKeyPair = [
+ {
+ key: "publicKey",
+ converter: webidl.converters.CryptoKey,
+ },
+ {
+ key: "privateKey",
+ converter: webidl.converters.CryptoKey,
+ },
+];
+
+webidl.converters.CryptoKeyPair = webidl
+ .createDictionaryConverter("CryptoKeyPair", dictCryptoKeyPair);
+
+const dictEcdhKeyDeriveParams = [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: "public",
+ converter: webidl.converters.CryptoKey,
+ required: true,
+ },
+];
+
+webidl.converters.EcdhKeyDeriveParams = webidl
+ .createDictionaryConverter("EcdhKeyDeriveParams", dictEcdhKeyDeriveParams);
diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs
index 906e7d06f..de47e467b 100644
--- a/ext/crypto/lib.rs
+++ b/ext/crypto/lib.rs
@@ -75,7 +75,7 @@ use crate::shared::RawKeyData;
pub fn init(maybe_seed: Option<u64>) -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_webidl", "deno_web"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/crypto",
"00_crypto.js",
"01_webidl.js",
diff --git a/ext/fetch/01_fetch_util.js b/ext/fetch/01_fetch_util.js
deleted file mode 100644
index 3ed554ecb..000000000
--- a/ext/fetch/01_fetch_util.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const { TypeError } = window.__bootstrap.primordials;
- 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);
- }
- }
-
- window.__bootstrap.fetchUtil = {
- requiredArguments,
- };
-})(this);
diff --git a/ext/fetch/20_headers.js b/ext/fetch/20_headers.js
index 54e635522..9790bb69f 100644
--- a/ext/fetch/20_headers.js
+++ b/ext/fetch/20_headers.js
@@ -8,472 +8,470 @@
/// <reference path="../web/06_streams_types.d.ts" />
/// <reference path="./lib.deno_fetch.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-
-((window) => {
- const webidl = window.__bootstrap.webidl;
- const {
- HTTP_TAB_OR_SPACE_PREFIX_RE,
- HTTP_TAB_OR_SPACE_SUFFIX_RE,
- HTTP_TOKEN_CODE_POINT_RE,
- byteLowerCase,
- collectSequenceOfCodepoints,
- collectHttpQuotedString,
- httpTrim,
- } = window.__bootstrap.infra;
- const {
- ArrayIsArray,
- ArrayPrototypeMap,
- ArrayPrototypePush,
- ArrayPrototypeSort,
- ArrayPrototypeJoin,
- ArrayPrototypeSplice,
- ArrayPrototypeFilter,
- ObjectPrototypeHasOwnProperty,
- ObjectEntries,
- RegExpPrototypeTest,
- SafeArrayIterator,
- Symbol,
- SymbolFor,
- SymbolIterator,
- StringPrototypeReplaceAll,
- TypeError,
- } = window.__bootstrap.primordials;
-
- const _headerList = Symbol("header list");
- const _iterableHeaders = Symbol("iterable headers");
- const _guard = Symbol("guard");
-
- /**
- * @typedef Header
- * @type {[string, string]}
- */
- /**
- * @typedef HeaderList
- * @type {Header[]}
- */
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import {
+ byteLowerCase,
+ collectHttpQuotedString,
+ collectSequenceOfCodepoints,
+ HTTP_TAB_OR_SPACE_PREFIX_RE,
+ HTTP_TAB_OR_SPACE_SUFFIX_RE,
+ HTTP_TOKEN_CODE_POINT_RE,
+ httpTrim,
+} from "internal:ext/web/00_infra.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayIsArray,
+ ArrayPrototypeMap,
+ ArrayPrototypePush,
+ ArrayPrototypeSort,
+ ArrayPrototypeJoin,
+ ArrayPrototypeSplice,
+ ArrayPrototypeFilter,
+ ObjectPrototypeHasOwnProperty,
+ ObjectEntries,
+ RegExpPrototypeTest,
+ SafeArrayIterator,
+ Symbol,
+ SymbolFor,
+ SymbolIterator,
+ StringPrototypeReplaceAll,
+ TypeError,
+} = primordials;
+
+const _headerList = Symbol("header list");
+const _iterableHeaders = Symbol("iterable headers");
+const _guard = Symbol("guard");
+
+/**
+ * @typedef Header
+ * @type {[string, string]}
+ */
+
+/**
+ * @typedef HeaderList
+ * @type {Header[]}
+ */
+
+/**
+ * @param {string} potentialValue
+ * @returns {string}
+ */
+function normalizeHeaderValue(potentialValue) {
+ return httpTrim(potentialValue);
+}
+
+/**
+ * @param {Headers} headers
+ * @param {HeadersInit} object
+ */
+function fillHeaders(headers, object) {
+ if (ArrayIsArray(object)) {
+ for (let i = 0; i < object.length; ++i) {
+ const header = object[i];
+ if (header.length !== 2) {
+ throw new TypeError(
+ `Invalid header. Length must be 2, but is ${header.length}`,
+ );
+ }
+ appendHeader(headers, header[0], header[1]);
+ }
+ } else {
+ for (const key in object) {
+ if (!ObjectPrototypeHasOwnProperty(object, key)) {
+ continue;
+ }
+ appendHeader(headers, key, object[key]);
+ }
+ }
+}
+
+// Regex matching illegal chars in a header value
+// deno-lint-ignore no-control-regex
+const ILLEGAL_VALUE_CHARS = /[\x00\x0A\x0D]/;
+
+/**
+ * https://fetch.spec.whatwg.org/#concept-headers-append
+ * @param {Headers} headers
+ * @param {string} name
+ * @param {string} value
+ */
+function appendHeader(headers, name, value) {
+ // 1.
+ value = normalizeHeaderValue(value);
+
+ // 2.
+ if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
+ throw new TypeError("Header name is not valid.");
+ }
+ if (RegExpPrototypeTest(ILLEGAL_VALUE_CHARS, value)) {
+ throw new TypeError("Header value is not valid.");
+ }
- /**
- * @param {string} potentialValue
- * @returns {string}
- */
- function normalizeHeaderValue(potentialValue) {
- return httpTrim(potentialValue);
+ // 3.
+ if (headers[_guard] == "immutable") {
+ throw new TypeError("Headers are immutable.");
}
- /**
- * @param {Headers} headers
- * @param {HeadersInit} object
- */
- function fillHeaders(headers, object) {
- if (ArrayIsArray(object)) {
- for (let i = 0; i < object.length; ++i) {
- const header = object[i];
- if (header.length !== 2) {
- throw new TypeError(
- `Invalid header. Length must be 2, but is ${header.length}`,
- );
+ // 7.
+ const list = headers[_headerList];
+ const lowercaseName = byteLowerCase(name);
+ for (let i = 0; i < list.length; i++) {
+ if (byteLowerCase(list[i][0]) === lowercaseName) {
+ name = list[i][0];
+ break;
+ }
+ }
+ ArrayPrototypePush(list, [name, value]);
+}
+
+/**
+ * https://fetch.spec.whatwg.org/#concept-header-list-get
+ * @param {HeaderList} list
+ * @param {string} name
+ */
+function getHeader(list, name) {
+ const lowercaseName = byteLowerCase(name);
+ const entries = ArrayPrototypeMap(
+ ArrayPrototypeFilter(
+ list,
+ (entry) => byteLowerCase(entry[0]) === lowercaseName,
+ ),
+ (entry) => entry[1],
+ );
+ if (entries.length === 0) {
+ return null;
+ } else {
+ return ArrayPrototypeJoin(entries, "\x2C\x20");
+ }
+}
+
+/**
+ * https://fetch.spec.whatwg.org/#concept-header-list-get-decode-split
+ * @param {HeaderList} list
+ * @param {string} name
+ * @returns {string[] | null}
+ */
+function getDecodeSplitHeader(list, name) {
+ const initialValue = getHeader(list, name);
+ if (initialValue === null) return null;
+ const input = initialValue;
+ let position = 0;
+ const values = [];
+ let value = "";
+ while (position < initialValue.length) {
+ // 7.1. collect up to " or ,
+ const res = collectSequenceOfCodepoints(
+ initialValue,
+ position,
+ (c) => c !== "\u0022" && c !== "\u002C",
+ );
+ value += res.result;
+ position = res.position;
+
+ if (position < initialValue.length) {
+ if (input[position] === "\u0022") {
+ const res = collectHttpQuotedString(input, position, false);
+ value += res.result;
+ position = res.position;
+ if (position < initialValue.length) {
+ continue;
}
- appendHeader(headers, header[0], header[1]);
+ } else {
+ if (input[position] !== "\u002C") throw new TypeError("Unreachable");
+ position += 1;
}
- } else {
- for (const key in object) {
- if (!ObjectPrototypeHasOwnProperty(object, key)) {
- continue;
+ }
+
+ value = StringPrototypeReplaceAll(value, HTTP_TAB_OR_SPACE_PREFIX_RE, "");
+ value = StringPrototypeReplaceAll(value, HTTP_TAB_OR_SPACE_SUFFIX_RE, "");
+
+ ArrayPrototypePush(values, value);
+ value = "";
+ }
+ return values;
+}
+
+class Headers {
+ /** @type {HeaderList} */
+ [_headerList] = [];
+ /** @type {"immutable" | "request" | "request-no-cors" | "response" | "none"} */
+ [_guard];
+
+ get [_iterableHeaders]() {
+ const list = this[_headerList];
+
+ // The order of steps are not similar to the ones suggested by the
+ // spec but produce the same result.
+ const headers = {};
+ const cookies = [];
+ for (let i = 0; i < list.length; ++i) {
+ const entry = list[i];
+ const name = byteLowerCase(entry[0]);
+ const value = entry[1];
+ if (value === null) throw new TypeError("Unreachable");
+ // The following if statement is not spec compliant.
+ // `set-cookie` is the only header that can not be concatenated,
+ // so must be given to the user as multiple headers.
+ // The else block of the if statement is spec compliant again.
+ if (name === "set-cookie") {
+ ArrayPrototypePush(cookies, [name, value]);
+ } else {
+ // The following code has the same behaviour as getHeader()
+ // at the end of loop. But it avoids looping through the entire
+ // list to combine multiple values with same header name. It
+ // instead gradually combines them as they are found.
+ let header = headers[name];
+ if (header && header.length > 0) {
+ header += "\x2C\x20" + value;
+ } else {
+ header = value;
}
- appendHeader(headers, key, object[key]);
+ headers[name] = header;
}
}
+
+ return ArrayPrototypeSort(
+ [
+ ...new SafeArrayIterator(ObjectEntries(headers)),
+ ...new SafeArrayIterator(cookies),
+ ],
+ (a, b) => {
+ const akey = a[0];
+ const bkey = b[0];
+ if (akey > bkey) return 1;
+ if (akey < bkey) return -1;
+ return 0;
+ },
+ );
}
- // Regex matching illegal chars in a header value
- // deno-lint-ignore no-control-regex
- const ILLEGAL_VALUE_CHARS = /[\x00\x0A\x0D]/;
+ /** @param {HeadersInit} [init] */
+ constructor(init = undefined) {
+ const prefix = "Failed to construct 'Headers'";
+ if (init !== undefined) {
+ init = webidl.converters["HeadersInit"](init, {
+ prefix,
+ context: "Argument 1",
+ });
+ }
+
+ this[webidl.brand] = webidl.brand;
+ this[_guard] = "none";
+ if (init !== undefined) {
+ fillHeaders(this, init);
+ }
+ }
/**
- * https://fetch.spec.whatwg.org/#concept-headers-append
- * @param {Headers} headers
* @param {string} name
* @param {string} value
*/
- function appendHeader(headers, name, value) {
- // 1.
- value = normalizeHeaderValue(value);
+ append(name, value) {
+ webidl.assertBranded(this, HeadersPrototype);
+ const prefix = "Failed to execute 'append' on 'Headers'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ name = webidl.converters["ByteString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+ value = webidl.converters["ByteString"](value, {
+ prefix,
+ context: "Argument 2",
+ });
+ appendHeader(this, name, value);
+ }
+
+ /**
+ * @param {string} name
+ */
+ delete(name) {
+ const prefix = "Failed to execute 'delete' on 'Headers'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ name = webidl.converters["ByteString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
- // 2.
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
throw new TypeError("Header name is not valid.");
}
- if (RegExpPrototypeTest(ILLEGAL_VALUE_CHARS, value)) {
- throw new TypeError("Header value is not valid.");
- }
-
- // 3.
- if (headers[_guard] == "immutable") {
+ if (this[_guard] == "immutable") {
throw new TypeError("Headers are immutable.");
}
- // 7.
- const list = headers[_headerList];
+ const list = this[_headerList];
const lowercaseName = byteLowerCase(name);
for (let i = 0; i < list.length; i++) {
if (byteLowerCase(list[i][0]) === lowercaseName) {
- name = list[i][0];
- break;
+ ArrayPrototypeSplice(list, i, 1);
+ i--;
}
}
- ArrayPrototypePush(list, [name, value]);
}
/**
- * https://fetch.spec.whatwg.org/#concept-header-list-get
- * @param {HeaderList} list
* @param {string} name
*/
- function getHeader(list, name) {
- const lowercaseName = byteLowerCase(name);
- const entries = ArrayPrototypeMap(
- ArrayPrototypeFilter(
- list,
- (entry) => byteLowerCase(entry[0]) === lowercaseName,
- ),
- (entry) => entry[1],
- );
- if (entries.length === 0) {
- return null;
- } else {
- return ArrayPrototypeJoin(entries, "\x2C\x20");
+ get(name) {
+ const prefix = "Failed to execute 'get' on 'Headers'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ name = webidl.converters["ByteString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
+ throw new TypeError("Header name is not valid.");
}
+
+ const list = this[_headerList];
+ return getHeader(list, name);
}
/**
- * https://fetch.spec.whatwg.org/#concept-header-list-get-decode-split
- * @param {HeaderList} list
* @param {string} name
- * @returns {string[] | null}
*/
- function getDecodeSplitHeader(list, name) {
- const initialValue = getHeader(list, name);
- if (initialValue === null) return null;
- const input = initialValue;
- let position = 0;
- const values = [];
- let value = "";
- while (position < initialValue.length) {
- // 7.1. collect up to " or ,
- const res = collectSequenceOfCodepoints(
- initialValue,
- position,
- (c) => c !== "\u0022" && c !== "\u002C",
- );
- value += res.result;
- position = res.position;
-
- if (position < initialValue.length) {
- if (input[position] === "\u0022") {
- const res = collectHttpQuotedString(input, position, false);
- value += res.result;
- position = res.position;
- if (position < initialValue.length) {
- continue;
- }
- } else {
- if (input[position] !== "\u002C") throw new TypeError("Unreachable");
- position += 1;
- }
- }
-
- value = StringPrototypeReplaceAll(value, HTTP_TAB_OR_SPACE_PREFIX_RE, "");
- value = StringPrototypeReplaceAll(value, HTTP_TAB_OR_SPACE_SUFFIX_RE, "");
+ has(name) {
+ const prefix = "Failed to execute 'has' on 'Headers'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ name = webidl.converters["ByteString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
- ArrayPrototypePush(values, value);
- value = "";
+ if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
+ throw new TypeError("Header name is not valid.");
}
- return values;
- }
- class Headers {
- /** @type {HeaderList} */
- [_headerList] = [];
- /** @type {"immutable" | "request" | "request-no-cors" | "response" | "none"} */
- [_guard];
-
- get [_iterableHeaders]() {
- const list = this[_headerList];
-
- // The order of steps are not similar to the ones suggested by the
- // spec but produce the same result.
- const headers = {};
- const cookies = [];
- for (let i = 0; i < list.length; ++i) {
- const entry = list[i];
- const name = byteLowerCase(entry[0]);
- const value = entry[1];
- if (value === null) throw new TypeError("Unreachable");
- // The following if statement is not spec compliant.
- // `set-cookie` is the only header that can not be concatenated,
- // so must be given to the user as multiple headers.
- // The else block of the if statement is spec compliant again.
- if (name === "set-cookie") {
- ArrayPrototypePush(cookies, [name, value]);
- } else {
- // The following code has the same behaviour as getHeader()
- // at the end of loop. But it avoids looping through the entire
- // list to combine multiple values with same header name. It
- // instead gradually combines them as they are found.
- let header = headers[name];
- if (header && header.length > 0) {
- header += "\x2C\x20" + value;
- } else {
- header = value;
- }
- headers[name] = header;
- }
+ const list = this[_headerList];
+ const lowercaseName = byteLowerCase(name);
+ for (let i = 0; i < list.length; i++) {
+ if (byteLowerCase(list[i][0]) === lowercaseName) {
+ return true;
}
-
- return ArrayPrototypeSort(
- [
- ...new SafeArrayIterator(ObjectEntries(headers)),
- ...new SafeArrayIterator(cookies),
- ],
- (a, b) => {
- const akey = a[0];
- const bkey = b[0];
- if (akey > bkey) return 1;
- if (akey < bkey) return -1;
- return 0;
- },
- );
}
+ return false;
+ }
- /** @param {HeadersInit} [init] */
- constructor(init = undefined) {
- const prefix = "Failed to construct 'Headers'";
- if (init !== undefined) {
- init = webidl.converters["HeadersInit"](init, {
- prefix,
- context: "Argument 1",
- });
- }
+ /**
+ * @param {string} name
+ * @param {string} value
+ */
+ set(name, value) {
+ webidl.assertBranded(this, HeadersPrototype);
+ const prefix = "Failed to execute 'set' on 'Headers'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ name = webidl.converters["ByteString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+ value = webidl.converters["ByteString"](value, {
+ prefix,
+ context: "Argument 2",
+ });
- this[webidl.brand] = webidl.brand;
- this[_guard] = "none";
- if (init !== undefined) {
- fillHeaders(this, init);
- }
- }
+ value = normalizeHeaderValue(value);
- /**
- * @param {string} name
- * @param {string} value
- */
- append(name, value) {
- webidl.assertBranded(this, HeadersPrototype);
- const prefix = "Failed to execute 'append' on 'Headers'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- name = webidl.converters["ByteString"](name, {
- prefix,
- context: "Argument 1",
- });
- value = webidl.converters["ByteString"](value, {
- prefix,
- context: "Argument 2",
- });
- appendHeader(this, name, value);
+ // 2.
+ if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
+ throw new TypeError("Header name is not valid.");
}
-
- /**
- * @param {string} name
- */
- delete(name) {
- const prefix = "Failed to execute 'delete' on 'Headers'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- name = webidl.converters["ByteString"](name, {
- prefix,
- context: "Argument 1",
- });
-
- if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
- throw new TypeError("Header name is not valid.");
- }
- if (this[_guard] == "immutable") {
- throw new TypeError("Headers are immutable.");
- }
-
- const list = this[_headerList];
- const lowercaseName = byteLowerCase(name);
- for (let i = 0; i < list.length; i++) {
- if (byteLowerCase(list[i][0]) === lowercaseName) {
- ArrayPrototypeSplice(list, i, 1);
- i--;
- }
- }
+ if (RegExpPrototypeTest(ILLEGAL_VALUE_CHARS, value)) {
+ throw new TypeError("Header value is not valid.");
}
- /**
- * @param {string} name
- */
- get(name) {
- const prefix = "Failed to execute 'get' on 'Headers'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- name = webidl.converters["ByteString"](name, {
- prefix,
- context: "Argument 1",
- });
-
- if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
- throw new TypeError("Header name is not valid.");
- }
-
- const list = this[_headerList];
- return getHeader(list, name);
+ if (this[_guard] == "immutable") {
+ throw new TypeError("Headers are immutable.");
}
- /**
- * @param {string} name
- */
- has(name) {
- const prefix = "Failed to execute 'has' on 'Headers'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- name = webidl.converters["ByteString"](name, {
- prefix,
- context: "Argument 1",
- });
-
- if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
- throw new TypeError("Header name is not valid.");
- }
-
- const list = this[_headerList];
- const lowercaseName = byteLowerCase(name);
- for (let i = 0; i < list.length; i++) {
- if (byteLowerCase(list[i][0]) === lowercaseName) {
- return true;
+ const list = this[_headerList];
+ const lowercaseName = byteLowerCase(name);
+ let added = false;
+ for (let i = 0; i < list.length; i++) {
+ if (byteLowerCase(list[i][0]) === lowercaseName) {
+ if (!added) {
+ list[i][1] = value;
+ added = true;
+ } else {
+ ArrayPrototypeSplice(list, i, 1);
+ i--;
}
}
- return false;
}
-
- /**
- * @param {string} name
- * @param {string} value
- */
- set(name, value) {
- webidl.assertBranded(this, HeadersPrototype);
- const prefix = "Failed to execute 'set' on 'Headers'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- name = webidl.converters["ByteString"](name, {
- prefix,
- context: "Argument 1",
- });
- value = webidl.converters["ByteString"](value, {
- prefix,
- context: "Argument 2",
- });
-
- value = normalizeHeaderValue(value);
-
- // 2.
- if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
- throw new TypeError("Header name is not valid.");
- }
- if (RegExpPrototypeTest(ILLEGAL_VALUE_CHARS, value)) {
- throw new TypeError("Header value is not valid.");
- }
-
- if (this[_guard] == "immutable") {
- throw new TypeError("Headers are immutable.");
- }
-
- const list = this[_headerList];
- const lowercaseName = byteLowerCase(name);
- let added = false;
- for (let i = 0; i < list.length; i++) {
- if (byteLowerCase(list[i][0]) === lowercaseName) {
- if (!added) {
- list[i][1] = value;
- added = true;
- } else {
- ArrayPrototypeSplice(list, i, 1);
- i--;
- }
- }
- }
- if (!added) {
- ArrayPrototypePush(list, [name, value]);
- }
+ if (!added) {
+ ArrayPrototypePush(list, [name, value]);
}
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- const headers = {};
- // deno-lint-ignore prefer-primordials
- for (const header of this) {
- headers[header[0]] = header[1];
- }
- return `Headers ${inspect(headers)}`;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ const headers = {};
+ // deno-lint-ignore prefer-primordials
+ for (const header of this) {
+ headers[header[0]] = header[1];
}
+ return `Headers ${inspect(headers)}`;
}
+}
- webidl.mixinPairIterable("Headers", Headers, _iterableHeaders, 0, 1);
+webidl.mixinPairIterable("Headers", Headers, _iterableHeaders, 0, 1);
- webidl.configurePrototype(Headers);
- const HeadersPrototype = Headers.prototype;
+webidl.configurePrototype(Headers);
+const HeadersPrototype = Headers.prototype;
- webidl.converters["HeadersInit"] = (V, opts) => {
- // Union for (sequence<sequence<ByteString>> or record<ByteString, ByteString>)
- if (webidl.type(V) === "Object" && V !== null) {
- if (V[SymbolIterator] !== undefined) {
- return webidl.converters["sequence<sequence<ByteString>>"](V, opts);
- }
- return webidl.converters["record<ByteString, ByteString>"](V, opts);
+webidl.converters["HeadersInit"] = (V, opts) => {
+ // Union for (sequence<sequence<ByteString>> or record<ByteString, ByteString>)
+ if (webidl.type(V) === "Object" && V !== null) {
+ if (V[SymbolIterator] !== undefined) {
+ return webidl.converters["sequence<sequence<ByteString>>"](V, opts);
}
- throw webidl.makeException(
- TypeError,
- "The provided value is not of type '(sequence<sequence<ByteString>> or record<ByteString, ByteString>)'",
- opts,
- );
- };
- webidl.converters["Headers"] = webidl.createInterfaceConverter(
- "Headers",
- Headers.prototype,
- );
-
- /**
- * @param {HeaderList} list
- * @param {"immutable" | "request" | "request-no-cors" | "response" | "none"} guard
- * @returns {Headers}
- */
- function headersFromHeaderList(list, guard) {
- const headers = webidl.createBranded(Headers);
- headers[_headerList] = list;
- headers[_guard] = guard;
- return headers;
+ return webidl.converters["record<ByteString, ByteString>"](V, opts);
}
-
- /**
- * @param {Headers}
- * @returns {HeaderList}
- */
- function headerListFromHeaders(headers) {
- return headers[_headerList];
- }
-
- /**
- * @param {Headers}
- * @returns {"immutable" | "request" | "request-no-cors" | "response" | "none"}
- */
- function guardFromHeaders(headers) {
- return headers[_guard];
- }
-
- window.__bootstrap.headers = {
- headersFromHeaderList,
- headerListFromHeaders,
- getDecodeSplitHeader,
- guardFromHeaders,
- fillHeaders,
- getHeader,
- Headers,
- };
-})(this);
+ throw webidl.makeException(
+ TypeError,
+ "The provided value is not of type '(sequence<sequence<ByteString>> or record<ByteString, ByteString>)'",
+ opts,
+ );
+};
+webidl.converters["Headers"] = webidl.createInterfaceConverter(
+ "Headers",
+ Headers.prototype,
+);
+
+/**
+ * @param {HeaderList} list
+ * @param {"immutable" | "request" | "request-no-cors" | "response" | "none"} guard
+ * @returns {Headers}
+ */
+function headersFromHeaderList(list, guard) {
+ const headers = webidl.createBranded(Headers);
+ headers[_headerList] = list;
+ headers[_guard] = guard;
+ return headers;
+}
+
+/**
+ * @param {Headers} headers
+ * @returns {HeaderList}
+ */
+function headerListFromHeaders(headers) {
+ return headers[_headerList];
+}
+
+/**
+ * @param {Headers} headers
+ * @returns {"immutable" | "request" | "request-no-cors" | "response" | "none"}
+ */
+function guardFromHeaders(headers) {
+ return headers[_guard];
+}
+
+export {
+ fillHeaders,
+ getDecodeSplitHeader,
+ getHeader,
+ guardFromHeaders,
+ headerListFromHeaders,
+ Headers,
+ headersFromHeaderList,
+};
diff --git a/ext/fetch/21_formdata.js b/ext/fetch/21_formdata.js
index d253976ef..1639646e0 100644
--- a/ext/fetch/21_formdata.js
+++ b/ext/fetch/21_formdata.js
@@ -8,516 +8,518 @@
/// <reference path="../web/06_streams_types.d.ts" />
/// <reference path="./lib.deno_fetch.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const webidl = globalThis.__bootstrap.webidl;
- const { Blob, BlobPrototype, File, FilePrototype } =
- globalThis.__bootstrap.file;
- const {
- ArrayPrototypePush,
- ArrayPrototypeSlice,
- ArrayPrototypeSplice,
- Map,
- MapPrototypeGet,
- MapPrototypeSet,
- MathRandom,
- ObjectPrototypeIsPrototypeOf,
- Symbol,
- StringFromCharCode,
- StringPrototypeTrim,
- StringPrototypeSlice,
- StringPrototypeSplit,
- StringPrototypeReplace,
- StringPrototypeIndexOf,
- StringPrototypePadStart,
- StringPrototypeCodePointAt,
- StringPrototypeReplaceAll,
- TypeError,
- TypedArrayPrototypeSubarray,
- } = window.__bootstrap.primordials;
-
- const entryList = Symbol("entry list");
- /**
- * @param {string} name
- * @param {string | Blob} value
- * @param {string | undefined} filename
- * @returns {FormDataEntry}
- */
- function createEntry(name, value, filename) {
- if (
- ObjectPrototypeIsPrototypeOf(BlobPrototype, value) &&
- !ObjectPrototypeIsPrototypeOf(FilePrototype, value)
- ) {
- value = new File([value], "blob", { type: value.type });
- }
- if (
- ObjectPrototypeIsPrototypeOf(FilePrototype, value) &&
- filename !== undefined
- ) {
- value = new File([value], filename, {
- type: value.type,
- lastModified: value.lastModified,
- });
+const core = globalThis.Deno.core;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import {
+ Blob,
+ BlobPrototype,
+ File,
+ FilePrototype,
+} from "internal:ext/web/09_file.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypePush,
+ ArrayPrototypeSlice,
+ ArrayPrototypeSplice,
+ Map,
+ MapPrototypeGet,
+ MapPrototypeSet,
+ MathRandom,
+ ObjectPrototypeIsPrototypeOf,
+ Symbol,
+ StringFromCharCode,
+ StringPrototypeTrim,
+ StringPrototypeSlice,
+ StringPrototypeSplit,
+ StringPrototypeReplace,
+ StringPrototypeIndexOf,
+ StringPrototypePadStart,
+ StringPrototypeCodePointAt,
+ StringPrototypeReplaceAll,
+ TypeError,
+ TypedArrayPrototypeSubarray,
+} = primordials;
+
+const entryList = Symbol("entry list");
+
+/**
+ * @param {string} name
+ * @param {string | Blob} value
+ * @param {string | undefined} filename
+ * @returns {FormDataEntry}
+ */
+function createEntry(name, value, filename) {
+ if (
+ ObjectPrototypeIsPrototypeOf(BlobPrototype, value) &&
+ !ObjectPrototypeIsPrototypeOf(FilePrototype, value)
+ ) {
+ value = new File([value], "blob", { type: value.type });
+ }
+ if (
+ ObjectPrototypeIsPrototypeOf(FilePrototype, value) &&
+ filename !== undefined
+ ) {
+ value = new File([value], filename, {
+ type: value.type,
+ lastModified: value.lastModified,
+ });
+ }
+ return {
+ name,
+ // @ts-expect-error because TS is not smart enough
+ value,
+ };
+}
+
+/**
+ * @typedef FormDataEntry
+ * @property {string} name
+ * @property {FormDataEntryValue} value
+ */
+
+class FormData {
+ /** @type {FormDataEntry[]} */
+ [entryList] = [];
+
+ /** @param {void} form */
+ constructor(form) {
+ if (form !== undefined) {
+ webidl.illegalConstructor();
}
- return {
- name,
- // @ts-expect-error because TS is not smart enough
- value,
- };
+ this[webidl.brand] = webidl.brand;
}
/**
- * @typedef FormDataEntry
- * @property {string} name
- * @property {FormDataEntryValue} value
+ * @param {string} name
+ * @param {string | Blob} valueOrBlobValue
+ * @param {string} [filename]
+ * @returns {void}
*/
-
- class FormData {
- /** @type {FormDataEntry[]} */
- [entryList] = [];
-
- /** @param {void} form */
- constructor(form) {
- if (form !== undefined) {
- webidl.illegalConstructor();
- }
- this[webidl.brand] = webidl.brand;
- }
-
- /**
- * @param {string} name
- * @param {string | Blob} valueOrBlobValue
- * @param {string} [filename]
- * @returns {void}
- */
- append(name, valueOrBlobValue, filename) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'append' on 'FormData'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
-
- name = webidl.converters["USVString"](name, {
+ append(name, valueOrBlobValue, filename) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'append' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+ if (ObjectPrototypeIsPrototypeOf(BlobPrototype, valueOrBlobValue)) {
+ valueOrBlobValue = webidl.converters["Blob"](valueOrBlobValue, {
prefix,
- context: "Argument 1",
+ context: "Argument 2",
});
- if (ObjectPrototypeIsPrototypeOf(BlobPrototype, valueOrBlobValue)) {
- valueOrBlobValue = webidl.converters["Blob"](valueOrBlobValue, {
- prefix,
- context: "Argument 2",
- });
- if (filename !== undefined) {
- filename = webidl.converters["USVString"](filename, {
- prefix,
- context: "Argument 3",
- });
- }
- } else {
- valueOrBlobValue = webidl.converters["USVString"](valueOrBlobValue, {
+ if (filename !== undefined) {
+ filename = webidl.converters["USVString"](filename, {
prefix,
- context: "Argument 2",
+ context: "Argument 3",
});
}
-
- const entry = createEntry(name, valueOrBlobValue, filename);
-
- ArrayPrototypePush(this[entryList], entry);
- }
-
- /**
- * @param {string} name
- * @returns {void}
- */
- delete(name) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'name' on 'FormData'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
-
- name = webidl.converters["USVString"](name, {
+ } else {
+ valueOrBlobValue = webidl.converters["USVString"](valueOrBlobValue, {
prefix,
- context: "Argument 1",
+ context: "Argument 2",
});
-
- const list = this[entryList];
- for (let i = 0; i < list.length; i++) {
- if (list[i].name === name) {
- ArrayPrototypeSplice(list, i, 1);
- i--;
- }
- }
}
- /**
- * @param {string} name
- * @returns {FormDataEntryValue | null}
- */
- get(name) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'get' on 'FormData'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
+ const entry = createEntry(name, valueOrBlobValue, filename);
- name = webidl.converters["USVString"](name, {
- prefix,
- context: "Argument 1",
- });
+ ArrayPrototypePush(this[entryList], entry);
+ }
- const entries = this[entryList];
- for (let i = 0; i < entries.length; ++i) {
- const entry = entries[i];
- if (entry.name === name) return entry.value;
+ /**
+ * @param {string} name
+ * @returns {void}
+ */
+ delete(name) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'name' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ const list = this[entryList];
+ for (let i = 0; i < list.length; i++) {
+ if (list[i].name === name) {
+ ArrayPrototypeSplice(list, i, 1);
+ i--;
}
- return null;
}
+ }
- /**
- * @param {string} name
- * @returns {FormDataEntryValue[]}
- */
- getAll(name) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'getAll' on 'FormData'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
-
- name = webidl.converters["USVString"](name, {
- prefix,
- context: "Argument 1",
- });
+ /**
+ * @param {string} name
+ * @returns {FormDataEntryValue | null}
+ */
+ get(name) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'get' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
- const returnList = [];
- const entries = this[entryList];
- for (let i = 0; i < entries.length; ++i) {
- const entry = entries[i];
- if (entry.name === name) ArrayPrototypePush(returnList, entry.value);
- }
- return returnList;
+ const entries = this[entryList];
+ for (let i = 0; i < entries.length; ++i) {
+ const entry = entries[i];
+ if (entry.name === name) return entry.value;
}
+ return null;
+ }
- /**
- * @param {string} name
- * @returns {boolean}
- */
- has(name) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'has' on 'FormData'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
+ /**
+ * @param {string} name
+ * @returns {FormDataEntryValue[]}
+ */
+ getAll(name) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'getAll' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
- name = webidl.converters["USVString"](name, {
- prefix,
- context: "Argument 1",
- });
+ const returnList = [];
+ const entries = this[entryList];
+ for (let i = 0; i < entries.length; ++i) {
+ const entry = entries[i];
+ if (entry.name === name) ArrayPrototypePush(returnList, entry.value);
+ }
+ return returnList;
+ }
- const entries = this[entryList];
- for (let i = 0; i < entries.length; ++i) {
- const entry = entries[i];
- if (entry.name === name) return true;
- }
- return false;
+ /**
+ * @param {string} name
+ * @returns {boolean}
+ */
+ has(name) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'has' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ const entries = this[entryList];
+ for (let i = 0; i < entries.length; ++i) {
+ const entry = entries[i];
+ if (entry.name === name) return true;
}
+ return false;
+ }
- /**
- * @param {string} name
- * @param {string | Blob} valueOrBlobValue
- * @param {string} [filename]
- * @returns {void}
- */
- set(name, valueOrBlobValue, filename) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'set' on 'FormData'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
-
- name = webidl.converters["USVString"](name, {
+ /**
+ * @param {string} name
+ * @param {string | Blob} valueOrBlobValue
+ * @param {string} [filename]
+ * @returns {void}
+ */
+ set(name, valueOrBlobValue, filename) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'set' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+ if (ObjectPrototypeIsPrototypeOf(BlobPrototype, valueOrBlobValue)) {
+ valueOrBlobValue = webidl.converters["Blob"](valueOrBlobValue, {
prefix,
- context: "Argument 1",
+ context: "Argument 2",
});
- if (ObjectPrototypeIsPrototypeOf(BlobPrototype, valueOrBlobValue)) {
- valueOrBlobValue = webidl.converters["Blob"](valueOrBlobValue, {
- prefix,
- context: "Argument 2",
- });
- if (filename !== undefined) {
- filename = webidl.converters["USVString"](filename, {
- prefix,
- context: "Argument 3",
- });
- }
- } else {
- valueOrBlobValue = webidl.converters["USVString"](valueOrBlobValue, {
+ if (filename !== undefined) {
+ filename = webidl.converters["USVString"](filename, {
prefix,
- context: "Argument 2",
+ context: "Argument 3",
});
}
+ } else {
+ valueOrBlobValue = webidl.converters["USVString"](valueOrBlobValue, {
+ prefix,
+ context: "Argument 2",
+ });
+ }
- const entry = createEntry(name, valueOrBlobValue, filename);
+ const entry = createEntry(name, valueOrBlobValue, filename);
- const list = this[entryList];
- let added = false;
- for (let i = 0; i < list.length; i++) {
- if (list[i].name === name) {
- if (!added) {
- list[i] = entry;
- added = true;
- } else {
- ArrayPrototypeSplice(list, i, 1);
- i--;
- }
+ const list = this[entryList];
+ let added = false;
+ for (let i = 0; i < list.length; i++) {
+ if (list[i].name === name) {
+ if (!added) {
+ list[i] = entry;
+ added = true;
+ } else {
+ ArrayPrototypeSplice(list, i, 1);
+ i--;
}
}
- if (!added) {
- ArrayPrototypePush(list, entry);
- }
+ }
+ if (!added) {
+ ArrayPrototypePush(list, entry);
}
}
+}
- webidl.mixinPairIterable("FormData", FormData, entryList, "name", "value");
+webidl.mixinPairIterable("FormData", FormData, entryList, "name", "value");
- webidl.configurePrototype(FormData);
- const FormDataPrototype = FormData.prototype;
+webidl.configurePrototype(FormData);
+const FormDataPrototype = FormData.prototype;
- const escape = (str, isFilename) => {
- const escapeMap = {
- "\n": "%0A",
- "\r": "%0D",
- '"': "%22",
- };
-
- return StringPrototypeReplace(
- isFilename ? str : StringPrototypeReplace(str, /\r?\n|\r/g, "\r\n"),
- /([\n\r"])/g,
- (c) => escapeMap[c],
- );
+const escape = (str, isFilename) => {
+ const escapeMap = {
+ "\n": "%0A",
+ "\r": "%0D",
+ '"': "%22",
};
- /**
- * convert FormData to a Blob synchronous without reading all of the files
- * @param {globalThis.FormData} formData
- */
- function formDataToBlob(formData) {
- const boundary = StringPrototypePadStart(
- StringPrototypeSlice(
- StringPrototypeReplaceAll(`${MathRandom()}${MathRandom()}`, ".", ""),
- -28,
- ),
- 32,
- "-",
- );
- const chunks = [];
- const prefix = `--${boundary}\r\nContent-Disposition: form-data; name="`;
-
- // deno-lint-ignore prefer-primordials
- for (const { 0: name, 1: value } of formData) {
- if (typeof value === "string") {
- ArrayPrototypePush(
- chunks,
- prefix + escape(name) + '"' + CRLF + CRLF +
- StringPrototypeReplace(value, /\r(?!\n)|(?<!\r)\n/g, CRLF) + CRLF,
- );
- } else {
- ArrayPrototypePush(
- chunks,
- prefix + escape(name) + `"; filename="${escape(value.name, true)}"` +
- CRLF +
- `Content-Type: ${value.type || "application/octet-stream"}\r\n\r\n`,
- value,
- CRLF,
- );
- }
+ return StringPrototypeReplace(
+ isFilename ? str : StringPrototypeReplace(str, /\r?\n|\r/g, "\r\n"),
+ /([\n\r"])/g,
+ (c) => escapeMap[c],
+ );
+};
+
+/**
+ * convert FormData to a Blob synchronous without reading all of the files
+ * @param {globalThis.FormData} formData
+ */
+function formDataToBlob(formData) {
+ const boundary = StringPrototypePadStart(
+ StringPrototypeSlice(
+ StringPrototypeReplaceAll(`${MathRandom()}${MathRandom()}`, ".", ""),
+ -28,
+ ),
+ 32,
+ "-",
+ );
+ const chunks = [];
+ const prefix = `--${boundary}\r\nContent-Disposition: form-data; name="`;
+
+ // deno-lint-ignore prefer-primordials
+ for (const { 0: name, 1: value } of formData) {
+ if (typeof value === "string") {
+ ArrayPrototypePush(
+ chunks,
+ prefix + escape(name) + '"' + CRLF + CRLF +
+ StringPrototypeReplace(value, /\r(?!\n)|(?<!\r)\n/g, CRLF) + CRLF,
+ );
+ } else {
+ ArrayPrototypePush(
+ chunks,
+ prefix + escape(name) + `"; filename="${escape(value.name, true)}"` +
+ CRLF +
+ `Content-Type: ${value.type || "application/octet-stream"}\r\n\r\n`,
+ value,
+ CRLF,
+ );
}
+ }
- ArrayPrototypePush(chunks, `--${boundary}--`);
-
- return new Blob(chunks, {
- type: "multipart/form-data; boundary=" + boundary,
- });
+ ArrayPrototypePush(chunks, `--${boundary}--`);
+
+ return new Blob(chunks, {
+ type: "multipart/form-data; boundary=" + boundary,
+ });
+}
+
+/**
+ * @param {string} value
+ * @returns {Map<string, string>}
+ */
+function parseContentDisposition(value) {
+ /** @type {Map<string, string>} */
+ const params = new Map();
+ // Forced to do so for some Map constructor param mismatch
+ const values = ArrayPrototypeSlice(StringPrototypeSplit(value, ";"), 1);
+ for (let i = 0; i < values.length; i++) {
+ const entries = StringPrototypeSplit(StringPrototypeTrim(values[i]), "=");
+ if (entries.length > 1) {
+ MapPrototypeSet(
+ params,
+ entries[0],
+ StringPrototypeReplace(entries[1], /^"([^"]*)"$/, "$1"),
+ );
+ }
}
+ return params;
+}
+const CRLF = "\r\n";
+const LF = StringPrototypeCodePointAt(CRLF, 1);
+const CR = StringPrototypeCodePointAt(CRLF, 0);
+
+class MultipartParser {
/**
- * @param {string} value
- * @returns {Map<string, string>}
+ * @param {Uint8Array} body
+ * @param {string | undefined} boundary
*/
- function parseContentDisposition(value) {
- /** @type {Map<string, string>} */
- const params = new Map();
- // Forced to do so for some Map constructor param mismatch
- const values = ArrayPrototypeSlice(StringPrototypeSplit(value, ";"), 1);
- for (let i = 0; i < values.length; i++) {
- const entries = StringPrototypeSplit(StringPrototypeTrim(values[i]), "=");
- if (entries.length > 1) {
- MapPrototypeSet(
- params,
- entries[0],
- StringPrototypeReplace(entries[1], /^"([^"]*)"$/, "$1"),
- );
- }
+ constructor(body, boundary) {
+ if (!boundary) {
+ throw new TypeError("multipart/form-data must provide a boundary");
}
- return params;
+
+ this.boundary = `--${boundary}`;
+ this.body = body;
+ this.boundaryChars = core.encode(this.boundary);
}
- const CRLF = "\r\n";
- const LF = StringPrototypeCodePointAt(CRLF, 1);
- const CR = StringPrototypeCodePointAt(CRLF, 0);
-
- class MultipartParser {
- /**
- * @param {Uint8Array} body
- * @param {string | undefined} boundary
- */
- constructor(body, boundary) {
- if (!boundary) {
- throw new TypeError("multipart/form-data must provide a boundary");
+ /**
+ * @param {string} headersText
+ * @returns {{ headers: Headers, disposition: Map<string, string> }}
+ */
+ #parseHeaders(headersText) {
+ const headers = new Headers();
+ const rawHeaders = StringPrototypeSplit(headersText, "\r\n");
+ for (let i = 0; i < rawHeaders.length; ++i) {
+ const rawHeader = rawHeaders[i];
+ const sepIndex = StringPrototypeIndexOf(rawHeader, ":");
+ if (sepIndex < 0) {
+ continue; // Skip this header
}
-
- this.boundary = `--${boundary}`;
- this.body = body;
- this.boundaryChars = core.encode(this.boundary);
+ const key = StringPrototypeSlice(rawHeader, 0, sepIndex);
+ const value = StringPrototypeSlice(rawHeader, sepIndex + 1);
+ headers.set(key, value);
}
- /**
- * @param {string} headersText
- * @returns {{ headers: Headers, disposition: Map<string, string> }}
- */
- #parseHeaders(headersText) {
- const headers = new Headers();
- const rawHeaders = StringPrototypeSplit(headersText, "\r\n");
- for (let i = 0; i < rawHeaders.length; ++i) {
- const rawHeader = rawHeaders[i];
- const sepIndex = StringPrototypeIndexOf(rawHeader, ":");
- if (sepIndex < 0) {
- continue; // Skip this header
- }
- const key = StringPrototypeSlice(rawHeader, 0, sepIndex);
- const value = StringPrototypeSlice(rawHeader, sepIndex + 1);
- headers.set(key, value);
- }
-
- const disposition = parseContentDisposition(
- headers.get("Content-Disposition") ?? "",
- );
+ const disposition = parseContentDisposition(
+ headers.get("Content-Disposition") ?? "",
+ );
- return { headers, disposition };
- }
+ return { headers, disposition };
+ }
- /**
- * @returns {FormData}
- */
- parse() {
- // To have fields body must be at least 2 boundaries + \r\n + --
- // on the last boundary.
- if (this.body.length < (this.boundary.length * 2) + 4) {
- const decodedBody = core.decode(this.body);
- const lastBoundary = this.boundary + "--";
- // check if it's an empty valid form data
- if (
- decodedBody === lastBoundary ||
- decodedBody === lastBoundary + "\r\n"
- ) {
- return new FormData();
- }
- throw new TypeError("Unable to parse body as form data.");
+ /**
+ * @returns {FormData}
+ */
+ parse() {
+ // To have fields body must be at least 2 boundaries + \r\n + --
+ // on the last boundary.
+ if (this.body.length < (this.boundary.length * 2) + 4) {
+ const decodedBody = core.decode(this.body);
+ const lastBoundary = this.boundary + "--";
+ // check if it's an empty valid form data
+ if (
+ decodedBody === lastBoundary ||
+ decodedBody === lastBoundary + "\r\n"
+ ) {
+ return new FormData();
}
+ throw new TypeError("Unable to parse body as form data.");
+ }
- const formData = new FormData();
- let headerText = "";
- let boundaryIndex = 0;
- let state = 0;
- let fileStart = 0;
+ const formData = new FormData();
+ let headerText = "";
+ let boundaryIndex = 0;
+ let state = 0;
+ let fileStart = 0;
- for (let i = 0; i < this.body.length; i++) {
- const byte = this.body[i];
- const prevByte = this.body[i - 1];
- const isNewLine = byte === LF && prevByte === CR;
+ for (let i = 0; i < this.body.length; i++) {
+ const byte = this.body[i];
+ const prevByte = this.body[i - 1];
+ const isNewLine = byte === LF && prevByte === CR;
- if (state === 1 || state === 2 || state == 3) {
- headerText += StringFromCharCode(byte);
- }
- if (state === 0 && isNewLine) {
- state = 1;
- } else if (state === 1 && isNewLine) {
- state = 2;
- const headersDone = this.body[i + 1] === CR &&
- this.body[i + 2] === LF;
-
- if (headersDone) {
- state = 3;
- }
- } else if (state === 2 && isNewLine) {
+ if (state === 1 || state === 2 || state == 3) {
+ headerText += StringFromCharCode(byte);
+ }
+ if (state === 0 && isNewLine) {
+ state = 1;
+ } else if (state === 1 && isNewLine) {
+ state = 2;
+ const headersDone = this.body[i + 1] === CR &&
+ this.body[i + 2] === LF;
+
+ if (headersDone) {
state = 3;
- } else if (state === 3 && isNewLine) {
- state = 4;
- fileStart = i + 1;
- } else if (state === 4) {
- if (this.boundaryChars[boundaryIndex] !== byte) {
- boundaryIndex = 0;
- } else {
- boundaryIndex++;
+ }
+ } else if (state === 2 && isNewLine) {
+ state = 3;
+ } else if (state === 3 && isNewLine) {
+ state = 4;
+ fileStart = i + 1;
+ } else if (state === 4) {
+ if (this.boundaryChars[boundaryIndex] !== byte) {
+ boundaryIndex = 0;
+ } else {
+ boundaryIndex++;
+ }
+
+ if (boundaryIndex >= this.boundary.length) {
+ const { headers, disposition } = this.#parseHeaders(headerText);
+ const content = TypedArrayPrototypeSubarray(
+ this.body,
+ fileStart,
+ i - boundaryIndex - 1,
+ );
+ // https://fetch.spec.whatwg.org/#ref-for-dom-body-formdata
+ const filename = MapPrototypeGet(disposition, "filename");
+ const name = MapPrototypeGet(disposition, "name");
+
+ state = 5;
+ // Reset
+ boundaryIndex = 0;
+ headerText = "";
+
+ if (!name) {
+ continue; // Skip, unknown name
}
- if (boundaryIndex >= this.boundary.length) {
- const { headers, disposition } = this.#parseHeaders(headerText);
- const content = TypedArrayPrototypeSubarray(
- this.body,
- fileStart,
- i - boundaryIndex - 1,
- );
- // https://fetch.spec.whatwg.org/#ref-for-dom-body-formdata
- const filename = MapPrototypeGet(disposition, "filename");
- const name = MapPrototypeGet(disposition, "name");
-
- state = 5;
- // Reset
- boundaryIndex = 0;
- headerText = "";
-
- if (!name) {
- continue; // Skip, unknown name
- }
-
- if (filename) {
- const blob = new Blob([content], {
- type: headers.get("Content-Type") || "application/octet-stream",
- });
- formData.append(name, blob, filename);
- } else {
- formData.append(name, core.decode(content));
- }
+ if (filename) {
+ const blob = new Blob([content], {
+ type: headers.get("Content-Type") || "application/octet-stream",
+ });
+ formData.append(name, blob, filename);
+ } else {
+ formData.append(name, core.decode(content));
}
- } else if (state === 5 && isNewLine) {
- state = 1;
}
+ } else if (state === 5 && isNewLine) {
+ state = 1;
}
-
- return formData;
}
- }
-
- /**
- * @param {Uint8Array} body
- * @param {string | undefined} boundary
- * @returns {FormData}
- */
- function parseFormData(body, boundary) {
- const parser = new MultipartParser(body, boundary);
- return parser.parse();
- }
- /**
- * @param {FormDataEntry[]} entries
- * @returns {FormData}
- */
- function formDataFromEntries(entries) {
- const fd = new FormData();
- fd[entryList] = entries;
- return fd;
+ return formData;
}
-
- webidl.converters["FormData"] = webidl
- .createInterfaceConverter("FormData", FormDataPrototype);
-
- globalThis.__bootstrap.formData = {
- FormData,
- FormDataPrototype,
- formDataToBlob,
- parseFormData,
- formDataFromEntries,
- };
-})(globalThis);
+}
+
+/**
+ * @param {Uint8Array} body
+ * @param {string | undefined} boundary
+ * @returns {FormData}
+ */
+function parseFormData(body, boundary) {
+ const parser = new MultipartParser(body, boundary);
+ return parser.parse();
+}
+
+/**
+ * @param {FormDataEntry[]} entries
+ * @returns {FormData}
+ */
+function formDataFromEntries(entries) {
+ const fd = new FormData();
+ fd[entryList] = entries;
+ return fd;
+}
+
+webidl.converters["FormData"] = webidl
+ .createInterfaceConverter("FormData", FormDataPrototype);
+
+export {
+ FormData,
+ formDataFromEntries,
+ FormDataPrototype,
+ formDataToBlob,
+ parseFormData,
+};
diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js
index bea1abce2..48819650a 100644
--- a/ext/fetch/22_body.js
+++ b/ext/fetch/22_body.js
@@ -10,462 +10,462 @@
/// <reference path="../web/06_streams_types.d.ts" />
/// <reference path="./lib.deno_fetch.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-((window) => {
- const core = window.Deno.core;
- const webidl = globalThis.__bootstrap.webidl;
- const { parseUrlEncoded } = globalThis.__bootstrap.url;
- const { URLSearchParamsPrototype } = globalThis.__bootstrap.url;
- const {
- parseFormData,
- formDataFromEntries,
- formDataToBlob,
- FormDataPrototype,
- } = globalThis.__bootstrap.formData;
- const mimesniff = globalThis.__bootstrap.mimesniff;
- const { BlobPrototype } = globalThis.__bootstrap.file;
- const {
- isReadableStreamDisturbed,
- errorReadableStream,
- readableStreamClose,
- readableStreamDisturb,
- readableStreamCollectIntoUint8Array,
- readableStreamThrowIfErrored,
- createProxy,
- ReadableStreamPrototype,
- } = globalThis.__bootstrap.streams;
- const {
- ArrayBufferPrototype,
- ArrayBufferIsView,
- ArrayPrototypeMap,
- JSONParse,
- ObjectDefineProperties,
- ObjectPrototypeIsPrototypeOf,
- // TODO(lucacasonato): add SharedArrayBuffer to primordials
- // SharedArrayBufferPrototype
- TypedArrayPrototypeSlice,
- TypeError,
- Uint8Array,
- Uint8ArrayPrototype,
- } = window.__bootstrap.primordials;
+const core = globalThis.Deno.core;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import {
+ parseUrlEncoded,
+ URLSearchParamsPrototype,
+} from "internal:ext/url/00_url.js";
+import {
+ formDataFromEntries,
+ FormDataPrototype,
+ formDataToBlob,
+ parseFormData,
+} from "internal:ext/fetch/21_formdata.js";
+import * as mimesniff from "internal:ext/web/01_mimesniff.js";
+import { BlobPrototype } from "internal:ext/web/09_file.js";
+import {
+ createProxy,
+ errorReadableStream,
+ isReadableStreamDisturbed,
+ readableStreamClose,
+ readableStreamCollectIntoUint8Array,
+ readableStreamDisturb,
+ ReadableStreamPrototype,
+ readableStreamThrowIfErrored,
+} from "internal:ext/web/06_streams.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayBufferPrototype,
+ ArrayBufferIsView,
+ ArrayPrototypeMap,
+ JSONParse,
+ ObjectDefineProperties,
+ ObjectPrototypeIsPrototypeOf,
+ // TODO(lucacasonato): add SharedArrayBuffer to primordials
+ // SharedArrayBufferPrototype
+ TypedArrayPrototypeSlice,
+ TypeError,
+ Uint8Array,
+ Uint8ArrayPrototype,
+} = primordials;
- /**
- * @param {Uint8Array | string} chunk
- * @returns {Uint8Array}
- */
- function chunkToU8(chunk) {
- return typeof chunk === "string" ? core.encode(chunk) : chunk;
- }
+/**
+ * @param {Uint8Array | string} chunk
+ * @returns {Uint8Array}
+ */
+function chunkToU8(chunk) {
+ return typeof chunk === "string" ? core.encode(chunk) : chunk;
+}
+/**
+ * @param {Uint8Array | string} chunk
+ * @returns {string}
+ */
+function chunkToString(chunk) {
+ return typeof chunk === "string" ? chunk : core.decode(chunk);
+}
+
+class InnerBody {
/**
- * @param {Uint8Array | string} chunk
- * @returns {string}
+ * @param {ReadableStream<Uint8Array> | { body: Uint8Array | string, consumed: boolean }} stream
*/
- function chunkToString(chunk) {
- return typeof chunk === "string" ? chunk : core.decode(chunk);
+ constructor(stream) {
+ /** @type {ReadableStream<Uint8Array> | { body: Uint8Array | string, consumed: boolean }} */
+ this.streamOrStatic = stream ??
+ { body: new Uint8Array(), consumed: false };
+ /** @type {null | Uint8Array | string | Blob | FormData} */
+ this.source = null;
+ /** @type {null | number} */
+ this.length = null;
}
- class InnerBody {
- /**
- * @param {ReadableStream<Uint8Array> | { body: Uint8Array | string, consumed: boolean }} stream
- */
- constructor(stream) {
- /** @type {ReadableStream<Uint8Array> | { body: Uint8Array | string, consumed: boolean }} */
- this.streamOrStatic = stream ??
- { body: new Uint8Array(), consumed: false };
- /** @type {null | Uint8Array | string | Blob | FormData} */
- this.source = null;
- /** @type {null | number} */
- this.length = null;
- }
-
- get stream() {
- if (
- !ObjectPrototypeIsPrototypeOf(
- ReadableStreamPrototype,
- this.streamOrStatic,
- )
- ) {
- const { body, consumed } = this.streamOrStatic;
- if (consumed) {
- this.streamOrStatic = new ReadableStream();
- this.streamOrStatic.getReader();
- readableStreamDisturb(this.streamOrStatic);
- readableStreamClose(this.streamOrStatic);
- } else {
- this.streamOrStatic = new ReadableStream({
- start(controller) {
- controller.enqueue(chunkToU8(body));
- controller.close();
- },
- });
- }
- }
- return this.streamOrStatic;
- }
-
- /**
- * https://fetch.spec.whatwg.org/#body-unusable
- * @returns {boolean}
- */
- unusable() {
- if (
- ObjectPrototypeIsPrototypeOf(
- ReadableStreamPrototype,
- this.streamOrStatic,
- )
- ) {
- return this.streamOrStatic.locked ||
- isReadableStreamDisturbed(this.streamOrStatic);
+ get stream() {
+ if (
+ !ObjectPrototypeIsPrototypeOf(
+ ReadableStreamPrototype,
+ this.streamOrStatic,
+ )
+ ) {
+ const { body, consumed } = this.streamOrStatic;
+ if (consumed) {
+ this.streamOrStatic = new ReadableStream();
+ this.streamOrStatic.getReader();
+ readableStreamDisturb(this.streamOrStatic);
+ readableStreamClose(this.streamOrStatic);
+ } else {
+ this.streamOrStatic = new ReadableStream({
+ start(controller) {
+ controller.enqueue(chunkToU8(body));
+ controller.close();
+ },
+ });
}
- return this.streamOrStatic.consumed;
}
+ return this.streamOrStatic;
+ }
- /**
- * @returns {boolean}
- */
- consumed() {
- if (
- ObjectPrototypeIsPrototypeOf(
- ReadableStreamPrototype,
- this.streamOrStatic,
- )
- ) {
- return isReadableStreamDisturbed(this.streamOrStatic);
- }
- return this.streamOrStatic.consumed;
+ /**
+ * https://fetch.spec.whatwg.org/#body-unusable
+ * @returns {boolean}
+ */
+ unusable() {
+ if (
+ ObjectPrototypeIsPrototypeOf(
+ ReadableStreamPrototype,
+ this.streamOrStatic,
+ )
+ ) {
+ return this.streamOrStatic.locked ||
+ isReadableStreamDisturbed(this.streamOrStatic);
}
+ return this.streamOrStatic.consumed;
+ }
- /**
- * https://fetch.spec.whatwg.org/#concept-body-consume-body
- * @returns {Promise<Uint8Array>}
- */
- consume() {
- if (this.unusable()) throw new TypeError("Body already consumed.");
- if (
- ObjectPrototypeIsPrototypeOf(
- ReadableStreamPrototype,
- this.streamOrStatic,
- )
- ) {
- readableStreamThrowIfErrored(this.stream);
- return readableStreamCollectIntoUint8Array(this.stream);
- } else {
- this.streamOrStatic.consumed = true;
- return this.streamOrStatic.body;
- }
+ /**
+ * @returns {boolean}
+ */
+ consumed() {
+ if (
+ ObjectPrototypeIsPrototypeOf(
+ ReadableStreamPrototype,
+ this.streamOrStatic,
+ )
+ ) {
+ return isReadableStreamDisturbed(this.streamOrStatic);
}
+ return this.streamOrStatic.consumed;
+ }
- cancel(error) {
- if (
- ObjectPrototypeIsPrototypeOf(
- ReadableStreamPrototype,
- this.streamOrStatic,
- )
- ) {
- this.streamOrStatic.cancel(error);
- } else {
- this.streamOrStatic.consumed = true;
- }
+ /**
+ * https://fetch.spec.whatwg.org/#concept-body-consume-body
+ * @returns {Promise<Uint8Array>}
+ */
+ consume() {
+ if (this.unusable()) throw new TypeError("Body already consumed.");
+ if (
+ ObjectPrototypeIsPrototypeOf(
+ ReadableStreamPrototype,
+ this.streamOrStatic,
+ )
+ ) {
+ readableStreamThrowIfErrored(this.stream);
+ return readableStreamCollectIntoUint8Array(this.stream);
+ } else {
+ this.streamOrStatic.consumed = true;
+ return this.streamOrStatic.body;
}
+ }
- error(error) {
- if (
- ObjectPrototypeIsPrototypeOf(
- ReadableStreamPrototype,
- this.streamOrStatic,
- )
- ) {
- errorReadableStream(this.streamOrStatic, error);
- } else {
- this.streamOrStatic.consumed = true;
- }
+ cancel(error) {
+ if (
+ ObjectPrototypeIsPrototypeOf(
+ ReadableStreamPrototype,
+ this.streamOrStatic,
+ )
+ ) {
+ this.streamOrStatic.cancel(error);
+ } else {
+ this.streamOrStatic.consumed = true;
}
+ }
- /**
- * @returns {InnerBody}
- */
- clone() {
- const { 0: out1, 1: out2 } = this.stream.tee();
- this.streamOrStatic = out1;
- const second = new InnerBody(out2);
- second.source = core.deserialize(core.serialize(this.source));
- second.length = this.length;
- return second;
+ error(error) {
+ if (
+ ObjectPrototypeIsPrototypeOf(
+ ReadableStreamPrototype,
+ this.streamOrStatic,
+ )
+ ) {
+ errorReadableStream(this.streamOrStatic, error);
+ } else {
+ this.streamOrStatic.consumed = true;
}
+ }
- /**
- * @returns {InnerBody}
- */
- createProxy() {
- let proxyStreamOrStatic;
- if (
- ObjectPrototypeIsPrototypeOf(
- ReadableStreamPrototype,
- this.streamOrStatic,
- )
- ) {
- proxyStreamOrStatic = createProxy(this.streamOrStatic);
- } else {
- proxyStreamOrStatic = { ...this.streamOrStatic };
- this.streamOrStatic.consumed = true;
- }
- const proxy = new InnerBody(proxyStreamOrStatic);
- proxy.source = this.source;
- proxy.length = this.length;
- return proxy;
- }
+ /**
+ * @returns {InnerBody}
+ */
+ clone() {
+ const { 0: out1, 1: out2 } = this.stream.tee();
+ this.streamOrStatic = out1;
+ const second = new InnerBody(out2);
+ second.source = core.deserialize(core.serialize(this.source));
+ second.length = this.length;
+ return second;
}
/**
- * @param {any} prototype
- * @param {symbol} bodySymbol
- * @param {symbol} mimeTypeSymbol
- * @returns {void}
+ * @returns {InnerBody}
*/
- function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
- async function consumeBody(object, type) {
- webidl.assertBranded(object, prototype);
+ createProxy() {
+ let proxyStreamOrStatic;
+ if (
+ ObjectPrototypeIsPrototypeOf(
+ ReadableStreamPrototype,
+ this.streamOrStatic,
+ )
+ ) {
+ proxyStreamOrStatic = createProxy(this.streamOrStatic);
+ } else {
+ proxyStreamOrStatic = { ...this.streamOrStatic };
+ this.streamOrStatic.consumed = true;
+ }
+ const proxy = new InnerBody(proxyStreamOrStatic);
+ proxy.source = this.source;
+ proxy.length = this.length;
+ return proxy;
+ }
+}
- const body = object[bodySymbol] !== null
- ? await object[bodySymbol].consume()
- : new Uint8Array();
+/**
+ * @param {any} prototype
+ * @param {symbol} bodySymbol
+ * @param {symbol} mimeTypeSymbol
+ * @returns {void}
+ */
+function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
+ async function consumeBody(object, type) {
+ webidl.assertBranded(object, prototype);
- const mimeType = type === "Blob" || type === "FormData"
- ? object[mimeTypeSymbol]
- : null;
- return packageData(body, type, mimeType);
- }
+ const body = object[bodySymbol] !== null
+ ? await object[bodySymbol].consume()
+ : new Uint8Array();
- /** @type {PropertyDescriptorMap} */
- const mixin = {
- body: {
- /**
- * @returns {ReadableStream<Uint8Array> | null}
- */
- get() {
- webidl.assertBranded(this, prototype);
- if (this[bodySymbol] === null) {
- return null;
- } else {
- return this[bodySymbol].stream;
- }
- },
- configurable: true,
- enumerable: true,
+ const mimeType = type === "Blob" || type === "FormData"
+ ? object[mimeTypeSymbol]
+ : null;
+ return packageData(body, type, mimeType);
+ }
+
+ /** @type {PropertyDescriptorMap} */
+ const mixin = {
+ body: {
+ /**
+ * @returns {ReadableStream<Uint8Array> | null}
+ */
+ get() {
+ webidl.assertBranded(this, prototype);
+ if (this[bodySymbol] === null) {
+ return null;
+ } else {
+ return this[bodySymbol].stream;
+ }
},
- bodyUsed: {
- /**
- * @returns {boolean}
- */
- get() {
- webidl.assertBranded(this, prototype);
- if (this[bodySymbol] !== null) {
- return this[bodySymbol].consumed();
- }
- return false;
- },
- configurable: true,
- enumerable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ bodyUsed: {
+ /**
+ * @returns {boolean}
+ */
+ get() {
+ webidl.assertBranded(this, prototype);
+ if (this[bodySymbol] !== null) {
+ return this[bodySymbol].consumed();
+ }
+ return false;
},
- arrayBuffer: {
- /** @returns {Promise<ArrayBuffer>} */
- value: function arrayBuffer() {
- return consumeBody(this, "ArrayBuffer");
- },
- writable: true,
- configurable: true,
- enumerable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ arrayBuffer: {
+ /** @returns {Promise<ArrayBuffer>} */
+ value: function arrayBuffer() {
+ return consumeBody(this, "ArrayBuffer");
},
- blob: {
- /** @returns {Promise<Blob>} */
- value: function blob() {
- return consumeBody(this, "Blob");
- },
- writable: true,
- configurable: true,
- enumerable: true,
+ writable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ blob: {
+ /** @returns {Promise<Blob>} */
+ value: function blob() {
+ return consumeBody(this, "Blob");
},
- formData: {
- /** @returns {Promise<FormData>} */
- value: function formData() {
- return consumeBody(this, "FormData");
- },
- writable: true,
- configurable: true,
- enumerable: true,
+ writable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ formData: {
+ /** @returns {Promise<FormData>} */
+ value: function formData() {
+ return consumeBody(this, "FormData");
},
- json: {
- /** @returns {Promise<any>} */
- value: function json() {
- return consumeBody(this, "JSON");
- },
- writable: true,
- configurable: true,
- enumerable: true,
+ writable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ json: {
+ /** @returns {Promise<any>} */
+ value: function json() {
+ return consumeBody(this, "JSON");
},
- text: {
- /** @returns {Promise<string>} */
- value: function text() {
- return consumeBody(this, "text");
- },
- writable: true,
- configurable: true,
- enumerable: true,
+ writable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ text: {
+ /** @returns {Promise<string>} */
+ value: function text() {
+ return consumeBody(this, "text");
},
- };
- return ObjectDefineProperties(prototype, mixin);
- }
+ writable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ };
+ return ObjectDefineProperties(prototype, mixin);
+}
- /**
- * https://fetch.spec.whatwg.org/#concept-body-package-data
- * @param {Uint8Array | string} bytes
- * @param {"ArrayBuffer" | "Blob" | "FormData" | "JSON" | "text"} type
- * @param {MimeType | null} [mimeType]
- */
- function packageData(bytes, type, mimeType) {
- switch (type) {
- case "ArrayBuffer":
- return chunkToU8(bytes).buffer;
- case "Blob":
- return new Blob([bytes], {
- type: mimeType !== null ? mimesniff.serializeMimeType(mimeType) : "",
- });
- case "FormData": {
- if (mimeType !== null) {
- const essence = mimesniff.essence(mimeType);
- if (essence === "multipart/form-data") {
- const boundary = mimeType.parameters.get("boundary");
- if (boundary === null) {
- throw new TypeError(
- "Missing boundary parameter in mime type of multipart formdata.",
- );
- }
- return parseFormData(chunkToU8(bytes), boundary);
- } else if (essence === "application/x-www-form-urlencoded") {
- // TODO(@AaronO): pass as-is with StringOrBuffer in op-layer
- const entries = parseUrlEncoded(chunkToU8(bytes));
- return formDataFromEntries(
- ArrayPrototypeMap(
- entries,
- (x) => ({ name: x[0], value: x[1] }),
- ),
+/**
+ * https://fetch.spec.whatwg.org/#concept-body-package-data
+ * @param {Uint8Array | string} bytes
+ * @param {"ArrayBuffer" | "Blob" | "FormData" | "JSON" | "text"} type
+ * @param {MimeType | null} [mimeType]
+ */
+function packageData(bytes, type, mimeType) {
+ switch (type) {
+ case "ArrayBuffer":
+ return chunkToU8(bytes).buffer;
+ case "Blob":
+ return new Blob([bytes], {
+ type: mimeType !== null ? mimesniff.serializeMimeType(mimeType) : "",
+ });
+ case "FormData": {
+ if (mimeType !== null) {
+ const essence = mimesniff.essence(mimeType);
+ if (essence === "multipart/form-data") {
+ const boundary = mimeType.parameters.get("boundary");
+ if (boundary === null) {
+ throw new TypeError(
+ "Missing boundary parameter in mime type of multipart formdata.",
);
}
- throw new TypeError("Body can not be decoded as form data");
+ return parseFormData(chunkToU8(bytes), boundary);
+ } else if (essence === "application/x-www-form-urlencoded") {
+ // TODO(@AaronO): pass as-is with StringOrBuffer in op-layer
+ const entries = parseUrlEncoded(chunkToU8(bytes));
+ return formDataFromEntries(
+ ArrayPrototypeMap(
+ entries,
+ (x) => ({ name: x[0], value: x[1] }),
+ ),
+ );
}
- throw new TypeError("Missing content type");
+ throw new TypeError("Body can not be decoded as form data");
}
- case "JSON":
- return JSONParse(chunkToString(bytes));
- case "text":
- return chunkToString(bytes);
+ throw new TypeError("Missing content type");
}
+ case "JSON":
+ return JSONParse(chunkToString(bytes));
+ case "text":
+ return chunkToString(bytes);
}
+}
- /**
- * @param {BodyInit} object
- * @returns {{body: InnerBody, contentType: string | null}}
- */
- function extractBody(object) {
- /** @type {ReadableStream<Uint8Array> | { body: Uint8Array | string, consumed: boolean }} */
- let stream;
- let source = null;
- let length = null;
- let contentType = null;
- if (typeof object === "string") {
- source = object;
- contentType = "text/plain;charset=UTF-8";
- } else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, object)) {
- stream = object.stream();
- source = object;
- length = object.size;
- if (object.type.length !== 0) {
- contentType = object.type;
- }
- } else if (ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, object)) {
- // Fast(er) path for common case of Uint8Array
- const copy = TypedArrayPrototypeSlice(object, 0, object.byteLength);
- source = copy;
- } else if (
- ArrayBufferIsView(object) ||
- ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, object)
- ) {
- const u8 = ArrayBufferIsView(object)
- ? new Uint8Array(
- object.buffer,
- object.byteOffset,
- object.byteLength,
- )
- : new Uint8Array(object);
- const copy = TypedArrayPrototypeSlice(u8, 0, u8.byteLength);
- source = copy;
- } else if (ObjectPrototypeIsPrototypeOf(FormDataPrototype, object)) {
- const res = formDataToBlob(object);
- stream = res.stream();
- source = res;
- length = res.size;
- contentType = res.type;
- } else if (
- ObjectPrototypeIsPrototypeOf(URLSearchParamsPrototype, object)
- ) {
- // TODO(@satyarohith): not sure what primordial here.
- source = object.toString();
- contentType = "application/x-www-form-urlencoded;charset=UTF-8";
- } else if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, object)) {
- stream = object;
- if (object.locked || isReadableStreamDisturbed(object)) {
- throw new TypeError("ReadableStream is locked or disturbed");
- }
+/**
+ * @param {BodyInit} object
+ * @returns {{body: InnerBody, contentType: string | null}}
+ */
+function extractBody(object) {
+ /** @type {ReadableStream<Uint8Array> | { body: Uint8Array | string, consumed: boolean }} */
+ let stream;
+ let source = null;
+ let length = null;
+ let contentType = null;
+ if (typeof object === "string") {
+ source = object;
+ contentType = "text/plain;charset=UTF-8";
+ } else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, object)) {
+ stream = object.stream();
+ source = object;
+ length = object.size;
+ if (object.type.length !== 0) {
+ contentType = object.type;
}
- if (typeof source === "string") {
- // WARNING: this deviates from spec (expects length to be set)
- // https://fetch.spec.whatwg.org/#bodyinit > 7.
- // no observable side-effect for users so far, but could change
- stream = { body: source, consumed: false };
- length = null; // NOTE: string length != byte length
- } else if (ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, source)) {
- stream = { body: source, consumed: false };
- length = source.byteLength;
+ } else if (ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, object)) {
+ // Fast(er) path for common case of Uint8Array
+ const copy = TypedArrayPrototypeSlice(object, 0, object.byteLength);
+ source = copy;
+ } else if (
+ ArrayBufferIsView(object) ||
+ ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, object)
+ ) {
+ const u8 = ArrayBufferIsView(object)
+ ? new Uint8Array(
+ object.buffer,
+ object.byteOffset,
+ object.byteLength,
+ )
+ : new Uint8Array(object);
+ const copy = TypedArrayPrototypeSlice(u8, 0, u8.byteLength);
+ source = copy;
+ } else if (ObjectPrototypeIsPrototypeOf(FormDataPrototype, object)) {
+ const res = formDataToBlob(object);
+ stream = res.stream();
+ source = res;
+ length = res.size;
+ contentType = res.type;
+ } else if (
+ ObjectPrototypeIsPrototypeOf(URLSearchParamsPrototype, object)
+ ) {
+ // TODO(@satyarohith): not sure what primordial here.
+ source = object.toString();
+ contentType = "application/x-www-form-urlencoded;charset=UTF-8";
+ } else if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, object)) {
+ stream = object;
+ if (object.locked || isReadableStreamDisturbed(object)) {
+ throw new TypeError("ReadableStream is locked or disturbed");
}
- const body = new InnerBody(stream);
- body.source = source;
- body.length = length;
- return { body, contentType };
}
+ if (typeof source === "string") {
+ // WARNING: this deviates from spec (expects length to be set)
+ // https://fetch.spec.whatwg.org/#bodyinit > 7.
+ // no observable side-effect for users so far, but could change
+ stream = { body: source, consumed: false };
+ length = null; // NOTE: string length != byte length
+ } else if (ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, source)) {
+ stream = { body: source, consumed: false };
+ length = source.byteLength;
+ }
+ const body = new InnerBody(stream);
+ body.source = source;
+ body.length = length;
+ return { body, contentType };
+}
- webidl.converters["BodyInit_DOMString"] = (V, opts) => {
- // Union for (ReadableStream or Blob or ArrayBufferView or ArrayBuffer or FormData or URLSearchParams or USVString)
- if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, V)) {
- return webidl.converters["ReadableStream"](V, opts);
- } else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) {
- return webidl.converters["Blob"](V, opts);
- } else if (ObjectPrototypeIsPrototypeOf(FormDataPrototype, V)) {
- return webidl.converters["FormData"](V, opts);
- } else if (ObjectPrototypeIsPrototypeOf(URLSearchParamsPrototype, V)) {
- return webidl.converters["URLSearchParams"](V, opts);
+webidl.converters["BodyInit_DOMString"] = (V, opts) => {
+ // Union for (ReadableStream or Blob or ArrayBufferView or ArrayBuffer or FormData or URLSearchParams or USVString)
+ if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, V)) {
+ return webidl.converters["ReadableStream"](V, opts);
+ } else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) {
+ return webidl.converters["Blob"](V, opts);
+ } else if (ObjectPrototypeIsPrototypeOf(FormDataPrototype, V)) {
+ return webidl.converters["FormData"](V, opts);
+ } else if (ObjectPrototypeIsPrototypeOf(URLSearchParamsPrototype, V)) {
+ return webidl.converters["URLSearchParams"](V, opts);
+ }
+ if (typeof V === "object") {
+ if (
+ ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V) ||
+ // deno-lint-ignore prefer-primordials
+ ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V)
+ ) {
+ return webidl.converters["ArrayBuffer"](V, opts);
}
- if (typeof V === "object") {
- if (
- ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V) ||
- // deno-lint-ignore prefer-primordials
- ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V)
- ) {
- return webidl.converters["ArrayBuffer"](V, opts);
- }
- if (ArrayBufferIsView(V)) {
- return webidl.converters["ArrayBufferView"](V, opts);
- }
+ if (ArrayBufferIsView(V)) {
+ return webidl.converters["ArrayBufferView"](V, opts);
}
- // BodyInit conversion is passed to extractBody(), which calls core.encode().
- // core.encode() will UTF-8 encode strings with replacement, being equivalent to the USV normalization.
- // Therefore we can convert to DOMString instead of USVString and avoid a costly redundant conversion.
- return webidl.converters["DOMString"](V, opts);
- };
- webidl.converters["BodyInit_DOMString?"] = webidl.createNullableConverter(
- webidl.converters["BodyInit_DOMString"],
- );
+ }
+ // BodyInit conversion is passed to extractBody(), which calls core.encode().
+ // core.encode() will UTF-8 encode strings with replacement, being equivalent to the USV normalization.
+ // Therefore we can convert to DOMString instead of USVString and avoid a costly redundant conversion.
+ return webidl.converters["DOMString"](V, opts);
+};
+webidl.converters["BodyInit_DOMString?"] = webidl.createNullableConverter(
+ webidl.converters["BodyInit_DOMString"],
+);
- window.__bootstrap.fetchBody = { mixinBody, InnerBody, extractBody };
-})(globalThis);
+export { extractBody, InnerBody, mixinBody };
diff --git a/ext/fetch/22_http_client.js b/ext/fetch/22_http_client.js
index 7b9f5c446..9d37f1b7f 100644
--- a/ext/fetch/22_http_client.js
+++ b/ext/fetch/22_http_client.js
@@ -9,40 +9,34 @@
/// <reference path="../web/06_streams_types.d.ts" />
/// <reference path="./lib.deno_fetch.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
+const core = globalThis.Deno.core;
+const ops = core.ops;
+/**
+ * @param {Deno.CreateHttpClientOptions} options
+ * @returns {HttpClient}
+ */
+function createHttpClient(options) {
+ options.caCerts ??= [];
+ return new HttpClient(
+ ops.op_fetch_custom_client(
+ options,
+ ),
+ );
+}
+
+class HttpClient {
/**
- * @param {Deno.CreateHttpClientOptions} options
- * @returns {HttpClient}
+ * @param {number} rid
*/
- function createHttpClient(options) {
- options.caCerts ??= [];
- return new HttpClient(
- ops.op_fetch_custom_client(
- options,
- ),
- );
+ constructor(rid) {
+ this.rid = rid;
}
-
- class HttpClient {
- /**
- * @param {number} rid
- */
- constructor(rid) {
- this.rid = rid;
- }
- close() {
- core.close(this.rid);
- }
+ close() {
+ core.close(this.rid);
}
- const HttpClientPrototype = HttpClient.prototype;
+}
+const HttpClientPrototype = HttpClient.prototype;
- window.__bootstrap.fetch ??= {};
- window.__bootstrap.fetch.createHttpClient = createHttpClient;
- window.__bootstrap.fetch.HttpClient = HttpClient;
- window.__bootstrap.fetch.HttpClientPrototype = HttpClientPrototype;
-})(globalThis);
+export { createHttpClient, HttpClient, HttpClientPrototype };
diff --git a/ext/fetch/23_request.js b/ext/fetch/23_request.js
index e266a7e44..1e8d5c1ec 100644
--- a/ext/fetch/23_request.js
+++ b/ext/fetch/23_request.js
@@ -8,657 +8,664 @@
/// <reference path="../web/06_streams_types.d.ts" />
/// <reference path="./lib.deno_fetch.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-
-((window) => {
- const webidl = window.__bootstrap.webidl;
- const consoleInternal = window.__bootstrap.console;
- const { HTTP_TOKEN_CODE_POINT_RE, byteUpperCase } = window.__bootstrap.infra;
- const { URL } = window.__bootstrap.url;
- const { guardFromHeaders } = window.__bootstrap.headers;
- const { mixinBody, extractBody, InnerBody } = window.__bootstrap.fetchBody;
- const { getLocationHref } = window.__bootstrap.location;
- const { extractMimeType } = window.__bootstrap.mimesniff;
- const { blobFromObjectUrl } = window.__bootstrap.file;
- const {
- headersFromHeaderList,
- headerListFromHeaders,
- fillHeaders,
- getDecodeSplitHeader,
- } = window.__bootstrap.headers;
- const { HttpClientPrototype } = window.__bootstrap.fetch;
- const abortSignal = window.__bootstrap.abortSignal;
- const {
- ArrayPrototypeMap,
- ArrayPrototypeSlice,
- ArrayPrototypeSplice,
- ObjectKeys,
- ObjectPrototypeIsPrototypeOf,
- RegExpPrototypeTest,
- Symbol,
- SymbolFor,
- TypeError,
- } = window.__bootstrap.primordials;
-
- const _request = Symbol("request");
- const _headers = Symbol("headers");
- const _getHeaders = Symbol("get headers");
- const _headersCache = Symbol("headers cache");
- const _signal = Symbol("signal");
- const _mimeType = Symbol("mime type");
- const _body = Symbol("body");
- const _flash = Symbol("flash");
- const _url = Symbol("url");
- const _method = Symbol("method");
- /**
- * @param {(() => string)[]} urlList
- * @param {string[]} urlListProcessed
- */
- function processUrlList(urlList, urlListProcessed) {
- for (let i = 0; i < urlList.length; i++) {
- if (urlListProcessed[i] === undefined) {
- urlListProcessed[i] = urlList[i]();
- }
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { createFilteredInspectProxy } from "internal:ext/console/02_console.js";
+import {
+ byteUpperCase,
+ HTTP_TOKEN_CODE_POINT_RE,
+} from "internal:ext/web/00_infra.js";
+import { URL } from "internal:ext/url/00_url.js";
+import {
+ extractBody,
+ InnerBody,
+ mixinBody,
+} from "internal:ext/fetch/22_body.js";
+import { getLocationHref } from "internal:ext/web/12_location.js";
+import { extractMimeType } from "internal:ext/web/01_mimesniff.js";
+import { blobFromObjectUrl } from "internal:ext/web/09_file.js";
+import {
+ fillHeaders,
+ getDecodeSplitHeader,
+ guardFromHeaders,
+ headerListFromHeaders,
+ headersFromHeaderList,
+} from "internal:ext/fetch/20_headers.js";
+import { HttpClientPrototype } from "internal:ext/fetch/22_http_client.js";
+import * as abortSignal from "internal:ext/web/03_abort_signal.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeMap,
+ ArrayPrototypeSlice,
+ ArrayPrototypeSplice,
+ ObjectKeys,
+ ObjectPrototypeIsPrototypeOf,
+ RegExpPrototypeTest,
+ Symbol,
+ SymbolFor,
+ TypeError,
+} = primordials;
+
+const _request = Symbol("request");
+const _headers = Symbol("headers");
+const _getHeaders = Symbol("get headers");
+const _headersCache = Symbol("headers cache");
+const _signal = Symbol("signal");
+const _mimeType = Symbol("mime type");
+const _body = Symbol("body");
+const _flash = Symbol("flash");
+const _url = Symbol("url");
+const _method = Symbol("method");
+
+/**
+ * @param {(() => string)[]} urlList
+ * @param {string[]} urlListProcessed
+ */
+function processUrlList(urlList, urlListProcessed) {
+ for (let i = 0; i < urlList.length; i++) {
+ if (urlListProcessed[i] === undefined) {
+ urlListProcessed[i] = urlList[i]();
}
- return urlListProcessed;
}
+ return urlListProcessed;
+}
+
+/**
+ * @typedef InnerRequest
+ * @property {() => string} method
+ * @property {() => string} url
+ * @property {() => string} currentUrl
+ * @property {() => [string, string][]} headerList
+ * @property {null | typeof __window.bootstrap.fetchBody.InnerBody} body
+ * @property {"follow" | "error" | "manual"} redirectMode
+ * @property {number} redirectCount
+ * @property {(() => string)[]} urlList
+ * @property {string[]} urlListProcessed
+ * @property {number | null} clientRid NOTE: non standard extension for `Deno.HttpClient`.
+ * @property {Blob | null} blobUrlEntry
+ */
+
+/**
+ * @param {() => string} method
+ * @param {string | () => string} url
+ * @param {() => [string, string][]} headerList
+ * @param {typeof __window.bootstrap.fetchBody.InnerBody} body
+ * @param {boolean} maybeBlob
+ * @returns {InnerRequest}
+ */
+function newInnerRequest(method, url, headerList, body, maybeBlob) {
+ let blobUrlEntry = null;
+ if (maybeBlob && typeof url === "string" && url.startsWith("blob:")) {
+ blobUrlEntry = blobFromObjectUrl(url);
+ }
+ return {
+ methodInner: null,
+ get method() {
+ if (this.methodInner === null) {
+ try {
+ this.methodInner = method();
+ } catch {
+ throw new TypeError("cannot read method: request closed");
+ }
+ }
+ return this.methodInner;
+ },
+ set method(value) {
+ this.methodInner = value;
+ },
+ headerListInner: null,
+ get headerList() {
+ if (this.headerListInner === null) {
+ try {
+ this.headerListInner = headerList();
+ } catch {
+ throw new TypeError("cannot read headers: request closed");
+ }
+ }
+ return this.headerListInner;
+ },
+ set headerList(value) {
+ this.headerListInner = value;
+ },
+ body,
+ redirectMode: "follow",
+ redirectCount: 0,
+ urlList: [typeof url === "string" ? () => url : url],
+ urlListProcessed: [],
+ clientRid: null,
+ blobUrlEntry,
+ url() {
+ if (this.urlListProcessed[0] === undefined) {
+ try {
+ this.urlListProcessed[0] = this.urlList[0]();
+ } catch {
+ throw new TypeError("cannot read url: request closed");
+ }
+ }
+ return this.urlListProcessed[0];
+ },
+ currentUrl() {
+ const currentIndex = this.urlList.length - 1;
+ if (this.urlListProcessed[currentIndex] === undefined) {
+ try {
+ this.urlListProcessed[currentIndex] = this.urlList[currentIndex]();
+ } catch {
+ throw new TypeError("cannot read url: request closed");
+ }
+ }
+ return this.urlListProcessed[currentIndex];
+ },
+ };
+}
+
+/**
+ * https://fetch.spec.whatwg.org/#concept-request-clone
+ * @param {InnerRequest} request
+ * @param {boolean} skipBody
+ * @param {boolean} flash
+ * @returns {InnerRequest}
+ */
+function cloneInnerRequest(request, skipBody = false, flash = false) {
+ const headerList = ArrayPrototypeMap(
+ request.headerList,
+ (x) => [x[0], x[1]],
+ );
- /**
- * @typedef InnerRequest
- * @property {() => string} method
- * @property {() => string} url
- * @property {() => string} currentUrl
- * @property {() => [string, string][]} headerList
- * @property {null | typeof __window.bootstrap.fetchBody.InnerBody} body
- * @property {"follow" | "error" | "manual"} redirectMode
- * @property {number} redirectCount
- * @property {(() => string)[]} urlList
- * @property {string[]} urlListProcessed
- * @property {number | null} clientRid NOTE: non standard extension for `Deno.HttpClient`.
- * @property {Blob | null} blobUrlEntry
- */
+ let body = null;
+ if (request.body !== null && !skipBody) {
+ body = request.body.clone();
+ }
- /**
- * @param {() => string} method
- * @param {string | () => string} url
- * @param {() => [string, string][]} headerList
- * @param {typeof __window.bootstrap.fetchBody.InnerBody} body
- * @param {boolean} maybeBlob
- * @returns {InnerRequest}
- */
- function newInnerRequest(method, url, headerList, body, maybeBlob) {
- let blobUrlEntry = null;
- if (maybeBlob && typeof url === "string" && url.startsWith("blob:")) {
- blobUrlEntry = blobFromObjectUrl(url);
- }
+ if (flash) {
return {
- methodInner: null,
- get method() {
- if (this.methodInner === null) {
- try {
- this.methodInner = method();
- } catch {
- throw new TypeError("cannot read method: request closed");
- }
- }
- return this.methodInner;
- },
- set method(value) {
- this.methodInner = value;
- },
- headerListInner: null,
- get headerList() {
- if (this.headerListInner === null) {
- try {
- this.headerListInner = headerList();
- } catch {
- throw new TypeError("cannot read headers: request closed");
- }
- }
- return this.headerListInner;
- },
- set headerList(value) {
- this.headerListInner = value;
- },
body,
+ methodCb: request.methodCb,
+ urlCb: request.urlCb,
+ headerList: request.headerList,
+ streamRid: request.streamRid,
+ serverId: request.serverId,
redirectMode: "follow",
redirectCount: 0,
- urlList: [typeof url === "string" ? () => url : url],
- urlListProcessed: [],
- clientRid: null,
- blobUrlEntry,
- url() {
- if (this.urlListProcessed[0] === undefined) {
- try {
- this.urlListProcessed[0] = this.urlList[0]();
- } catch {
- throw new TypeError("cannot read url: request closed");
- }
- }
- return this.urlListProcessed[0];
- },
- currentUrl() {
- const currentIndex = this.urlList.length - 1;
- if (this.urlListProcessed[currentIndex] === undefined) {
- try {
- this.urlListProcessed[currentIndex] = this.urlList[currentIndex]();
- } catch {
- throw new TypeError("cannot read url: request closed");
- }
- }
- return this.urlListProcessed[currentIndex];
- },
};
}
- /**
- * https://fetch.spec.whatwg.org/#concept-request-clone
- * @param {InnerRequest} request
- * @param {boolean} skipBody
- * @param {boolean} flash
- * @returns {InnerRequest}
- */
- function cloneInnerRequest(request, skipBody = false, flash = false) {
- const headerList = ArrayPrototypeMap(
- request.headerList,
- (x) => [x[0], x[1]],
- );
-
- let body = null;
- if (request.body !== null && !skipBody) {
- body = request.body.clone();
- }
-
- if (flash) {
- return {
- body,
- methodCb: request.methodCb,
- urlCb: request.urlCb,
- headerList: request.headerList,
- streamRid: request.streamRid,
- serverId: request.serverId,
- redirectMode: "follow",
- redirectCount: 0,
- };
- }
-
- return {
- method: request.method,
- headerList,
- body,
- redirectMode: request.redirectMode,
- redirectCount: request.redirectCount,
- urlList: request.urlList,
- urlListProcessed: request.urlListProcessed,
- clientRid: request.clientRid,
- blobUrlEntry: request.blobUrlEntry,
- url() {
- if (this.urlListProcessed[0] === undefined) {
- try {
- this.urlListProcessed[0] = this.urlList[0]();
- } catch {
- throw new TypeError("cannot read url: request closed");
- }
+ return {
+ method: request.method,
+ headerList,
+ body,
+ redirectMode: request.redirectMode,
+ redirectCount: request.redirectCount,
+ urlList: request.urlList,
+ urlListProcessed: request.urlListProcessed,
+ clientRid: request.clientRid,
+ blobUrlEntry: request.blobUrlEntry,
+ url() {
+ if (this.urlListProcessed[0] === undefined) {
+ try {
+ this.urlListProcessed[0] = this.urlList[0]();
+ } catch {
+ throw new TypeError("cannot read url: request closed");
}
- return this.urlListProcessed[0];
- },
- currentUrl() {
- const currentIndex = this.urlList.length - 1;
- if (this.urlListProcessed[currentIndex] === undefined) {
- try {
- this.urlListProcessed[currentIndex] = this.urlList[currentIndex]();
- } catch {
- throw new TypeError("cannot read url: request closed");
- }
+ }
+ return this.urlListProcessed[0];
+ },
+ currentUrl() {
+ const currentIndex = this.urlList.length - 1;
+ if (this.urlListProcessed[currentIndex] === undefined) {
+ try {
+ this.urlListProcessed[currentIndex] = this.urlList[currentIndex]();
+ } catch {
+ throw new TypeError("cannot read url: request closed");
}
- return this.urlListProcessed[currentIndex];
- },
- };
+ }
+ return this.urlListProcessed[currentIndex];
+ },
+ };
+}
+
+/**
+ * @param {string} m
+ * @returns {boolean}
+ */
+function isKnownMethod(m) {
+ return (
+ m === "DELETE" ||
+ m === "GET" ||
+ m === "HEAD" ||
+ m === "OPTIONS" ||
+ m === "POST" ||
+ m === "PUT"
+ );
+}
+/**
+ * @param {string} m
+ * @returns {string}
+ */
+function validateAndNormalizeMethod(m) {
+ // Fast path for well-known methods
+ if (isKnownMethod(m)) {
+ return m;
}
- /**
- * @param {string} m
- * @returns {boolean}
- */
- function isKnownMethod(m) {
- return (
- m === "DELETE" ||
- m === "GET" ||
- m === "HEAD" ||
- m === "OPTIONS" ||
- m === "POST" ||
- m === "PUT"
- );
+ // Regular path
+ if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, m)) {
+ throw new TypeError("Method is not valid.");
}
- /**
- * @param {string} m
- * @returns {string}
- */
- function validateAndNormalizeMethod(m) {
- // Fast path for well-known methods
- if (isKnownMethod(m)) {
- return m;
+ const upperCase = byteUpperCase(m);
+ if (
+ upperCase === "CONNECT" || upperCase === "TRACE" || upperCase === "TRACK"
+ ) {
+ throw new TypeError("Method is forbidden.");
+ }
+ return upperCase;
+}
+
+class Request {
+ /** @type {InnerRequest} */
+ [_request];
+ /** @type {Headers} */
+ [_headersCache];
+ [_getHeaders];
+
+ /** @type {Headers} */
+ get [_headers]() {
+ if (this[_headersCache] === undefined) {
+ this[_headersCache] = this[_getHeaders]();
}
+ return this[_headersCache];
+ }
- // Regular path
- if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, m)) {
- throw new TypeError("Method is not valid.");
- }
- const upperCase = byteUpperCase(m);
- if (
- upperCase === "CONNECT" || upperCase === "TRACE" || upperCase === "TRACK"
- ) {
- throw new TypeError("Method is forbidden.");
+ set [_headers](value) {
+ this[_headersCache] = value;
+ }
+
+ /** @type {AbortSignal} */
+ [_signal];
+ get [_mimeType]() {
+ const values = getDecodeSplitHeader(
+ headerListFromHeaders(this[_headers]),
+ "Content-Type",
+ );
+ return extractMimeType(values);
+ }
+ get [_body]() {
+ if (this[_flash]) {
+ return this[_flash].body;
+ } else {
+ return this[_request].body;
}
- return upperCase;
}
- class Request {
+ /**
+ * https://fetch.spec.whatwg.org/#dom-request
+ * @param {RequestInfo} input
+ * @param {RequestInit} init
+ */
+ constructor(input, init = {}) {
+ const prefix = "Failed to construct 'Request'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ input = webidl.converters["RequestInfo_DOMString"](input, {
+ prefix,
+ context: "Argument 1",
+ });
+ init = webidl.converters["RequestInit"](init, {
+ prefix,
+ context: "Argument 2",
+ });
+
+ this[webidl.brand] = webidl.brand;
+
/** @type {InnerRequest} */
- [_request];
- /** @type {Headers} */
- [_headersCache];
- [_getHeaders];
-
- /** @type {Headers} */
- get [_headers]() {
- if (this[_headersCache] === undefined) {
- this[_headersCache] = this[_getHeaders]();
+ let request;
+ const baseURL = getLocationHref();
+
+ // 4.
+ let signal = null;
+
+ // 5.
+ if (typeof input === "string") {
+ const parsedURL = new URL(input, baseURL);
+ request = newInnerRequest(
+ () => "GET",
+ parsedURL.href,
+ () => [],
+ null,
+ true,
+ );
+ } else { // 6.
+ if (!ObjectPrototypeIsPrototypeOf(RequestPrototype, input)) {
+ throw new TypeError("Unreachable");
}
- return this[_headersCache];
+ const originalReq = input[_request];
+ // fold in of step 12 from below
+ request = cloneInnerRequest(originalReq, true);
+ request.redirectCount = 0; // reset to 0 - cloneInnerRequest copies the value
+ signal = input[_signal];
}
- set [_headers](value) {
- this[_headersCache] = value;
+ // 12. is folded into the else statement of step 6 above.
+
+ // 22.
+ if (init.redirect !== undefined) {
+ request.redirectMode = init.redirect;
}
- /** @type {AbortSignal} */
- [_signal];
- get [_mimeType]() {
- const values = getDecodeSplitHeader(
- headerListFromHeaders(this[_headers]),
- "Content-Type",
- );
- return extractMimeType(values);
+ // 25.
+ if (init.method !== undefined) {
+ let method = init.method;
+ method = validateAndNormalizeMethod(method);
+ request.method = method;
}
- get [_body]() {
- if (this[_flash]) {
- return this[_flash].body;
- } else {
- return this[_request].body;
- }
+
+ // 26.
+ if (init.signal !== undefined) {
+ signal = init.signal;
}
- /**
- * https://fetch.spec.whatwg.org/#dom-request
- * @param {RequestInfo} input
- * @param {RequestInit} init
- */
- constructor(input, init = {}) {
- const prefix = "Failed to construct 'Request'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- input = webidl.converters["RequestInfo_DOMString"](input, {
- prefix,
- context: "Argument 1",
- });
- init = webidl.converters["RequestInit"](init, {
- prefix,
- context: "Argument 2",
- });
-
- this[webidl.brand] = webidl.brand;
-
- /** @type {InnerRequest} */
- let request;
- const baseURL = getLocationHref();
-
- // 4.
- let signal = null;
-
- // 5.
- if (typeof input === "string") {
- const parsedURL = new URL(input, baseURL);
- request = newInnerRequest(
- () => "GET",
- parsedURL.href,
- () => [],
- null,
- true,
+ // NOTE: non standard extension. This handles Deno.HttpClient parameter
+ if (init.client !== undefined) {
+ if (
+ init.client !== null &&
+ !ObjectPrototypeIsPrototypeOf(HttpClientPrototype, init.client)
+ ) {
+ throw webidl.makeException(
+ TypeError,
+ "`client` must be a Deno.HttpClient",
+ { prefix, context: "Argument 2" },
);
- } else { // 6.
- if (!ObjectPrototypeIsPrototypeOf(RequestPrototype, input)) {
- throw new TypeError("Unreachable");
- }
- const originalReq = input[_request];
- // fold in of step 12 from below
- request = cloneInnerRequest(originalReq, true);
- request.redirectCount = 0; // reset to 0 - cloneInnerRequest copies the value
- signal = input[_signal];
}
+ request.clientRid = init.client?.rid ?? null;
+ }
- // 12. is folded into the else statement of step 6 above.
+ // 27.
+ this[_request] = request;
- // 22.
- if (init.redirect !== undefined) {
- request.redirectMode = init.redirect;
- }
+ // 28.
+ this[_signal] = abortSignal.newSignal();
- // 25.
- if (init.method !== undefined) {
- let method = init.method;
- method = validateAndNormalizeMethod(method);
- request.method = method;
- }
+ // 29.
+ if (signal !== null) {
+ abortSignal.follow(this[_signal], signal);
+ }
- // 26.
- if (init.signal !== undefined) {
- signal = init.signal;
- }
+ // 30.
+ this[_headers] = headersFromHeaderList(request.headerList, "request");
- // NOTE: non standard extension. This handles Deno.HttpClient parameter
- if (init.client !== undefined) {
- if (
- init.client !== null &&
- !ObjectPrototypeIsPrototypeOf(HttpClientPrototype, init.client)
- ) {
- throw webidl.makeException(
- TypeError,
- "`client` must be a Deno.HttpClient",
- { prefix, context: "Argument 2" },
- );
- }
- request.clientRid = init.client?.rid ?? null;
+ // 32.
+ if (ObjectKeys(init).length > 0) {
+ let headers = ArrayPrototypeSlice(
+ headerListFromHeaders(this[_headers]),
+ 0,
+ headerListFromHeaders(this[_headers]).length,
+ );
+ if (init.headers !== undefined) {
+ headers = init.headers;
}
+ ArrayPrototypeSplice(
+ headerListFromHeaders(this[_headers]),
+ 0,
+ headerListFromHeaders(this[_headers]).length,
+ );
+ fillHeaders(this[_headers], headers);
+ }
- // 27.
- this[_request] = request;
-
- // 28.
- this[_signal] = abortSignal.newSignal();
-
- // 29.
- if (signal !== null) {
- abortSignal.follow(this[_signal], signal);
- }
+ // 33.
+ let inputBody = null;
+ if (ObjectPrototypeIsPrototypeOf(RequestPrototype, input)) {
+ inputBody = input[_body];
+ }
- // 30.
- this[_headers] = headersFromHeaderList(request.headerList, "request");
+ // 34.
+ if (
+ (request.method === "GET" || request.method === "HEAD") &&
+ ((init.body !== undefined && init.body !== null) ||
+ inputBody !== null)
+ ) {
+ throw new TypeError("Request with GET/HEAD method cannot have body.");
+ }
- // 32.
- if (ObjectKeys(init).length > 0) {
- let headers = ArrayPrototypeSlice(
- headerListFromHeaders(this[_headers]),
- 0,
- headerListFromHeaders(this[_headers]).length,
- );
- if (init.headers !== undefined) {
- headers = init.headers;
- }
- ArrayPrototypeSplice(
- headerListFromHeaders(this[_headers]),
- 0,
- headerListFromHeaders(this[_headers]).length,
- );
- fillHeaders(this[_headers], headers);
- }
+ // 35.
+ let initBody = null;
- // 33.
- let inputBody = null;
- if (ObjectPrototypeIsPrototypeOf(RequestPrototype, input)) {
- inputBody = input[_body];
+ // 36.
+ if (init.body !== undefined && init.body !== null) {
+ const res = extractBody(init.body);
+ initBody = res.body;
+ if (res.contentType !== null && !this[_headers].has("content-type")) {
+ this[_headers].append("Content-Type", res.contentType);
}
+ }
- // 34.
- if (
- (request.method === "GET" || request.method === "HEAD") &&
- ((init.body !== undefined && init.body !== null) ||
- inputBody !== null)
- ) {
- throw new TypeError("Request with GET/HEAD method cannot have body.");
- }
+ // 37.
+ const inputOrInitBody = initBody ?? inputBody;
- // 35.
- let initBody = null;
+ // 39.
+ let finalBody = inputOrInitBody;
- // 36.
- if (init.body !== undefined && init.body !== null) {
- const res = extractBody(init.body);
- initBody = res.body;
- if (res.contentType !== null && !this[_headers].has("content-type")) {
- this[_headers].append("Content-Type", res.contentType);
- }
+ // 40.
+ if (initBody === null && inputBody !== null) {
+ if (input[_body] && input[_body].unusable()) {
+ throw new TypeError("Input request's body is unusable.");
}
+ finalBody = inputBody.createProxy();
+ }
- // 37.
- const inputOrInitBody = initBody ?? inputBody;
-
- // 39.
- let finalBody = inputOrInitBody;
-
- // 40.
- if (initBody === null && inputBody !== null) {
- if (input[_body] && input[_body].unusable()) {
- throw new TypeError("Input request's body is unusable.");
- }
- finalBody = inputBody.createProxy();
- }
+ // 41.
+ request.body = finalBody;
+ }
- // 41.
- request.body = finalBody;
+ get method() {
+ webidl.assertBranded(this, RequestPrototype);
+ if (this[_method]) {
+ return this[_method];
}
-
- get method() {
- webidl.assertBranded(this, RequestPrototype);
- if (this[_method]) {
- return this[_method];
- }
- if (this[_flash]) {
- this[_method] = this[_flash].methodCb();
- return this[_method];
- } else {
- this[_method] = this[_request].method;
- return this[_method];
- }
+ if (this[_flash]) {
+ this[_method] = this[_flash].methodCb();
+ return this[_method];
+ } else {
+ this[_method] = this[_request].method;
+ return this[_method];
}
+ }
- get url() {
- webidl.assertBranded(this, RequestPrototype);
- if (this[_url]) {
- return this[_url];
- }
-
- if (this[_flash]) {
- this[_url] = this[_flash].urlCb();
- return this[_url];
- } else {
- this[_url] = this[_request].url();
- return this[_url];
- }
+ get url() {
+ webidl.assertBranded(this, RequestPrototype);
+ if (this[_url]) {
+ return this[_url];
}
- get headers() {
- webidl.assertBranded(this, RequestPrototype);
- return this[_headers];
+ if (this[_flash]) {
+ this[_url] = this[_flash].urlCb();
+ return this[_url];
+ } else {
+ this[_url] = this[_request].url();
+ return this[_url];
}
+ }
- get redirect() {
- webidl.assertBranded(this, RequestPrototype);
- if (this[_flash]) {
- return this[_flash].redirectMode;
- }
- return this[_request].redirectMode;
- }
+ get headers() {
+ webidl.assertBranded(this, RequestPrototype);
+ return this[_headers];
+ }
- get signal() {
- webidl.assertBranded(this, RequestPrototype);
- return this[_signal];
+ get redirect() {
+ webidl.assertBranded(this, RequestPrototype);
+ if (this[_flash]) {
+ return this[_flash].redirectMode;
}
+ return this[_request].redirectMode;
+ }
- clone() {
- webidl.assertBranded(this, RequestPrototype);
- if (this[_body] && this[_body].unusable()) {
- throw new TypeError("Body is unusable.");
- }
- let newReq;
- if (this[_flash]) {
- newReq = cloneInnerRequest(this[_flash], false, true);
- } else {
- newReq = cloneInnerRequest(this[_request]);
- }
- const newSignal = abortSignal.newSignal();
+ get signal() {
+ webidl.assertBranded(this, RequestPrototype);
+ return this[_signal];
+ }
- if (this[_signal]) {
- abortSignal.follow(newSignal, this[_signal]);
- }
+ clone() {
+ webidl.assertBranded(this, RequestPrototype);
+ if (this[_body] && this[_body].unusable()) {
+ throw new TypeError("Body is unusable.");
+ }
+ let newReq;
+ if (this[_flash]) {
+ newReq = cloneInnerRequest(this[_flash], false, true);
+ } else {
+ newReq = cloneInnerRequest(this[_request]);
+ }
+ const newSignal = abortSignal.newSignal();
- if (this[_flash]) {
- return fromInnerRequest(
- newReq,
- newSignal,
- guardFromHeaders(this[_headers]),
- true,
- );
- }
+ if (this[_signal]) {
+ abortSignal.follow(newSignal, this[_signal]);
+ }
+ if (this[_flash]) {
return fromInnerRequest(
newReq,
newSignal,
guardFromHeaders(this[_headers]),
- false,
+ true,
);
}
- [SymbolFor("Deno.customInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(RequestPrototype, this),
- keys: [
- "bodyUsed",
- "headers",
- "method",
- "redirect",
- "url",
- ],
- }));
- }
+ return fromInnerRequest(
+ newReq,
+ newSignal,
+ guardFromHeaders(this[_headers]),
+ false,
+ );
}
- webidl.configurePrototype(Request);
- const RequestPrototype = Request.prototype;
- mixinBody(RequestPrototype, _body, _mimeType);
-
- webidl.converters["Request"] = webidl.createInterfaceConverter(
- "Request",
- RequestPrototype,
- );
- webidl.converters["RequestInfo_DOMString"] = (V, opts) => {
- // Union for (Request or USVString)
- if (typeof V == "object") {
- if (ObjectPrototypeIsPrototypeOf(RequestPrototype, V)) {
- return webidl.converters["Request"](V, opts);
- }
- }
- // Passed to new URL(...) which implicitly converts DOMString -> USVString
- return webidl.converters["DOMString"](V, opts);
- };
- webidl.converters["RequestRedirect"] = webidl.createEnumConverter(
- "RequestRedirect",
- [
- "follow",
- "error",
- "manual",
- ],
- );
- webidl.converters["RequestInit"] = webidl.createDictionaryConverter(
- "RequestInit",
- [
- { key: "method", converter: webidl.converters["ByteString"] },
- { key: "headers", converter: webidl.converters["HeadersInit"] },
- {
- key: "body",
- converter: webidl.createNullableConverter(
- webidl.converters["BodyInit_DOMString"],
- ),
- },
- { key: "redirect", converter: webidl.converters["RequestRedirect"] },
- {
- key: "signal",
- converter: webidl.createNullableConverter(
- webidl.converters["AbortSignal"],
- ),
- },
- { key: "client", converter: webidl.converters.any },
- ],
- );
-
- /**
- * @param {Request} request
- * @returns {InnerRequest}
- */
- function toInnerRequest(request) {
- return request[_request];
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(RequestPrototype, this),
+ keys: [
+ "bodyUsed",
+ "headers",
+ "method",
+ "redirect",
+ "url",
+ ],
+ }));
}
-
- /**
- * @param {InnerRequest} inner
- * @param {AbortSignal} signal
- * @param {"request" | "immutable" | "request-no-cors" | "response" | "none"} guard
- * @param {boolean} flash
- * @returns {Request}
- */
- function fromInnerRequest(inner, signal, guard, flash) {
- const request = webidl.createBranded(Request);
- if (flash) {
- request[_flash] = inner;
- } else {
- request[_request] = inner;
+}
+
+webidl.configurePrototype(Request);
+const RequestPrototype = Request.prototype;
+mixinBody(RequestPrototype, _body, _mimeType);
+
+webidl.converters["Request"] = webidl.createInterfaceConverter(
+ "Request",
+ RequestPrototype,
+);
+webidl.converters["RequestInfo_DOMString"] = (V, opts) => {
+ // Union for (Request or USVString)
+ if (typeof V == "object") {
+ if (ObjectPrototypeIsPrototypeOf(RequestPrototype, V)) {
+ return webidl.converters["Request"](V, opts);
}
- request[_signal] = signal;
- request[_getHeaders] = flash
- ? () => headersFromHeaderList(inner.headerList(), guard)
- : () => headersFromHeaderList(inner.headerList, guard);
- return request;
}
-
- /**
- * @param {number} serverId
- * @param {number} streamRid
- * @param {ReadableStream} body
- * @param {() => string} methodCb
- * @param {() => string} urlCb
- * @param {() => [string, string][]} headersCb
- * @returns {Request}
- */
- function fromFlashRequest(
- serverId,
- streamRid,
- body,
+ // Passed to new URL(...) which implicitly converts DOMString -> USVString
+ return webidl.converters["DOMString"](V, opts);
+};
+webidl.converters["RequestRedirect"] = webidl.createEnumConverter(
+ "RequestRedirect",
+ [
+ "follow",
+ "error",
+ "manual",
+ ],
+);
+webidl.converters["RequestInit"] = webidl.createDictionaryConverter(
+ "RequestInit",
+ [
+ { key: "method", converter: webidl.converters["ByteString"] },
+ { key: "headers", converter: webidl.converters["HeadersInit"] },
+ {
+ key: "body",
+ converter: webidl.createNullableConverter(
+ webidl.converters["BodyInit_DOMString"],
+ ),
+ },
+ { key: "redirect", converter: webidl.converters["RequestRedirect"] },
+ {
+ key: "signal",
+ converter: webidl.createNullableConverter(
+ webidl.converters["AbortSignal"],
+ ),
+ },
+ { key: "client", converter: webidl.converters.any },
+ ],
+);
+
+/**
+ * @param {Request} request
+ * @returns {InnerRequest}
+ */
+function toInnerRequest(request) {
+ return request[_request];
+}
+
+/**
+ * @param {InnerRequest} inner
+ * @param {AbortSignal} signal
+ * @param {"request" | "immutable" | "request-no-cors" | "response" | "none"} guard
+ * @param {boolean} flash
+ * @returns {Request}
+ */
+function fromInnerRequest(inner, signal, guard, flash) {
+ const request = webidl.createBranded(Request);
+ if (flash) {
+ request[_flash] = inner;
+ } else {
+ request[_request] = inner;
+ }
+ request[_signal] = signal;
+ request[_getHeaders] = flash
+ ? () => headersFromHeaderList(inner.headerList(), guard)
+ : () => headersFromHeaderList(inner.headerList, guard);
+ return request;
+}
+
+/**
+ * @param {number} serverId
+ * @param {number} streamRid
+ * @param {ReadableStream} body
+ * @param {() => string} methodCb
+ * @param {() => string} urlCb
+ * @param {() => [string, string][]} headersCb
+ * @returns {Request}
+ */
+function fromFlashRequest(
+ serverId,
+ streamRid,
+ body,
+ methodCb,
+ urlCb,
+ headersCb,
+) {
+ const request = webidl.createBranded(Request);
+ request[_flash] = {
+ body: body !== null ? new InnerBody(body) : null,
methodCb,
urlCb,
- headersCb,
- ) {
- const request = webidl.createBranded(Request);
- request[_flash] = {
- body: body !== null ? new InnerBody(body) : null,
- methodCb,
- urlCb,
- headerList: headersCb,
- streamRid,
- serverId,
- redirectMode: "follow",
- redirectCount: 0,
- };
- request[_getHeaders] = () => headersFromHeaderList(headersCb(), "request");
- return request;
- }
-
- window.__bootstrap.fetch ??= {};
- window.__bootstrap.fetch.Request = Request;
- window.__bootstrap.fetch.toInnerRequest = toInnerRequest;
- window.__bootstrap.fetch.fromFlashRequest = fromFlashRequest;
- window.__bootstrap.fetch.fromInnerRequest = fromInnerRequest;
- window.__bootstrap.fetch.newInnerRequest = newInnerRequest;
- window.__bootstrap.fetch.processUrlList = processUrlList;
- window.__bootstrap.fetch._flash = _flash;
-})(globalThis);
+ headerList: headersCb,
+ streamRid,
+ serverId,
+ redirectMode: "follow",
+ redirectCount: 0,
+ };
+ request[_getHeaders] = () => headersFromHeaderList(headersCb(), "request");
+ return request;
+}
+
+export {
+ _flash,
+ fromFlashRequest,
+ fromInnerRequest,
+ newInnerRequest,
+ processUrlList,
+ Request,
+ RequestPrototype,
+ toInnerRequest,
+};
diff --git a/ext/fetch/23_response.js b/ext/fetch/23_response.js
index 070068d28..46912135a 100644
--- a/ext/fetch/23_response.js
+++ b/ext/fetch/23_response.js
@@ -9,510 +9,510 @@
/// <reference path="../web/06_streams_types.d.ts" />
/// <reference path="./lib.deno_fetch.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-
-((window) => {
- const { isProxy } = Deno.core;
- const webidl = window.__bootstrap.webidl;
- const consoleInternal = window.__bootstrap.console;
- const {
- byteLowerCase,
- } = window.__bootstrap.infra;
- const { HTTP_TAB_OR_SPACE, regexMatcher, serializeJSValueToJSONString } =
- window.__bootstrap.infra;
- const { extractBody, mixinBody } = window.__bootstrap.fetchBody;
- const { getLocationHref } = window.__bootstrap.location;
- const { extractMimeType } = window.__bootstrap.mimesniff;
- const { URL } = window.__bootstrap.url;
- const {
- getDecodeSplitHeader,
- headerListFromHeaders,
- headersFromHeaderList,
- guardFromHeaders,
- fillHeaders,
- } = window.__bootstrap.headers;
- const {
- ArrayPrototypeMap,
- ArrayPrototypePush,
- ObjectDefineProperties,
- ObjectPrototypeIsPrototypeOf,
- RangeError,
- RegExp,
- RegExpPrototypeTest,
- SafeArrayIterator,
- Symbol,
- SymbolFor,
- TypeError,
- } = window.__bootstrap.primordials;
-
- const VCHAR = ["\x21-\x7E"];
- const OBS_TEXT = ["\x80-\xFF"];
-
- const REASON_PHRASE = [
- ...new SafeArrayIterator(HTTP_TAB_OR_SPACE),
- ...new SafeArrayIterator(VCHAR),
- ...new SafeArrayIterator(OBS_TEXT),
- ];
- const REASON_PHRASE_MATCHER = regexMatcher(REASON_PHRASE);
- const REASON_PHRASE_RE = new RegExp(`^[${REASON_PHRASE_MATCHER}]*$`);
-
- const _response = Symbol("response");
- const _headers = Symbol("headers");
- const _mimeType = Symbol("mime type");
- const _body = Symbol("body");
+
+const core = globalThis.Deno.core;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { createFilteredInspectProxy } from "internal:ext/console/02_console.js";
+import {
+ byteLowerCase,
+ HTTP_TAB_OR_SPACE,
+ regexMatcher,
+ serializeJSValueToJSONString,
+} from "internal:ext/web/00_infra.js";
+import { extractBody, mixinBody } from "internal:ext/fetch/22_body.js";
+import { getLocationHref } from "internal:ext/web/12_location.js";
+import { extractMimeType } from "internal:ext/web/01_mimesniff.js";
+import { URL } from "internal:ext/url/00_url.js";
+import {
+ fillHeaders,
+ getDecodeSplitHeader,
+ guardFromHeaders,
+ headerListFromHeaders,
+ headersFromHeaderList,
+} from "internal:ext/fetch/20_headers.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeMap,
+ ArrayPrototypePush,
+ ObjectDefineProperties,
+ ObjectPrototypeIsPrototypeOf,
+ RangeError,
+ RegExp,
+ RegExpPrototypeTest,
+ SafeArrayIterator,
+ Symbol,
+ SymbolFor,
+ TypeError,
+} = primordials;
+
+const VCHAR = ["\x21-\x7E"];
+const OBS_TEXT = ["\x80-\xFF"];
+
+const REASON_PHRASE = [
+ ...new SafeArrayIterator(HTTP_TAB_OR_SPACE),
+ ...new SafeArrayIterator(VCHAR),
+ ...new SafeArrayIterator(OBS_TEXT),
+];
+const REASON_PHRASE_MATCHER = regexMatcher(REASON_PHRASE);
+const REASON_PHRASE_RE = new RegExp(`^[${REASON_PHRASE_MATCHER}]*$`);
+
+const _response = Symbol("response");
+const _headers = Symbol("headers");
+const _mimeType = Symbol("mime type");
+const _body = Symbol("body");
+
+/**
+ * @typedef InnerResponse
+ * @property {"basic" | "cors" | "default" | "error" | "opaque" | "opaqueredirect"} type
+ * @property {() => string | null} url
+ * @property {string[]} urlList
+ * @property {number} status
+ * @property {string} statusMessage
+ * @property {[string, string][]} headerList
+ * @property {null | typeof __window.bootstrap.fetchBody.InnerBody} body
+ * @property {boolean} aborted
+ * @property {string} [error]
+ */
+
+/**
+ * @param {number} status
+ * @returns {boolean}
+ */
+function nullBodyStatus(status) {
+ return status === 101 || status === 204 || status === 205 || status === 304;
+}
+
+/**
+ * @param {number} status
+ * @returns {boolean}
+ */
+function redirectStatus(status) {
+ return status === 301 || status === 302 || status === 303 ||
+ status === 307 || status === 308;
+}
+
+/**
+ * https://fetch.spec.whatwg.org/#concept-response-clone
+ * @param {InnerResponse} response
+ * @returns {InnerResponse}
+ */
+function cloneInnerResponse(response) {
+ const urlList = [...new SafeArrayIterator(response.urlList)];
+ const headerList = ArrayPrototypeMap(
+ response.headerList,
+ (x) => [x[0], x[1]],
+ );
+
+ let body = null;
+ if (response.body !== null) {
+ body = response.body.clone();
+ }
+
+ return {
+ type: response.type,
+ body,
+ headerList,
+ urlList,
+ status: response.status,
+ statusMessage: response.statusMessage,
+ aborted: response.aborted,
+ url() {
+ if (this.urlList.length == 0) return null;
+ return this.urlList[this.urlList.length - 1];
+ },
+ };
+}
+
+/**
+ * @returns {InnerResponse}
+ */
+function newInnerResponse(status = 200, statusMessage = "") {
+ return {
+ type: "default",
+ body: null,
+ headerList: [],
+ urlList: [],
+ status,
+ statusMessage,
+ aborted: false,
+ url() {
+ if (this.urlList.length == 0) return null;
+ return this.urlList[this.urlList.length - 1];
+ },
+ };
+}
+
+/**
+ * @param {string} error
+ * @returns {InnerResponse}
+ */
+function networkError(error) {
+ const resp = newInnerResponse(0);
+ resp.type = "error";
+ resp.error = error;
+ return resp;
+}
+
+/**
+ * @returns {InnerResponse}
+ */
+function abortedNetworkError() {
+ const resp = networkError("aborted");
+ resp.aborted = true;
+ return resp;
+}
+
+/**
+ * https://fetch.spec.whatwg.org#initialize-a-response
+ * @param {Response} response
+ * @param {ResponseInit} init
+ * @param {{ body: fetchBody.InnerBody, contentType: string | null } | null} bodyWithType
+ */
+function initializeAResponse(response, init, bodyWithType) {
+ // 1.
+ if ((init.status < 200 || init.status > 599) && init.status != 101) {
+ throw new RangeError(
+ `The status provided (${init.status}) is not equal to 101 and outside the range [200, 599].`,
+ );
+ }
+
+ // 2.
+ if (
+ init.statusText &&
+ !RegExpPrototypeTest(REASON_PHRASE_RE, init.statusText)
+ ) {
+ throw new TypeError("Status text is not valid.");
+ }
+
+ // 3.
+ response[_response].status = init.status;
+
+ // 4.
+ response[_response].statusMessage = init.statusText;
+ // 5.
+ /** @type {headers.Headers} */
+ const headers = response[_headers];
+ if (init.headers) {
+ fillHeaders(headers, init.headers);
+ }
+
+ // 6.
+ if (bodyWithType !== null) {
+ if (nullBodyStatus(response[_response].status)) {
+ throw new TypeError(
+ "Response with null body status cannot have body",
+ );
+ }
+
+ const { body, contentType } = bodyWithType;
+ response[_response].body = body;
+
+ if (contentType !== null) {
+ let hasContentType = false;
+ const list = headerListFromHeaders(headers);
+ for (let i = 0; i < list.length; i++) {
+ if (byteLowerCase(list[i][0]) === "content-type") {
+ hasContentType = true;
+ break;
+ }
+ }
+ if (!hasContentType) {
+ ArrayPrototypePush(list, ["Content-Type", contentType]);
+ }
+ }
+ }
+}
+
+class Response {
+ get [_mimeType]() {
+ const values = getDecodeSplitHeader(
+ headerListFromHeaders(this[_headers]),
+ "Content-Type",
+ );
+ return extractMimeType(values);
+ }
+ get [_body]() {
+ return this[_response].body;
+ }
/**
- * @typedef InnerResponse
- * @property {"basic" | "cors" | "default" | "error" | "opaque" | "opaqueredirect"} type
- * @property {() => string | null} url
- * @property {string[]} urlList
- * @property {number} status
- * @property {string} statusMessage
- * @property {[string, string][]} headerList
- * @property {null | typeof __window.bootstrap.fetchBody.InnerBody} body
- * @property {boolean} aborted
- * @property {string} [error]
+ * @returns {Response}
*/
+ static error() {
+ const inner = newInnerResponse(0);
+ inner.type = "error";
+ const response = webidl.createBranded(Response);
+ response[_response] = inner;
+ response[_headers] = headersFromHeaderList(
+ response[_response].headerList,
+ "immutable",
+ );
+ return response;
+ }
/**
+ * @param {string} url
* @param {number} status
- * @returns {boolean}
+ * @returns {Response}
*/
- function nullBodyStatus(status) {
- return status === 101 || status === 204 || status === 205 || status === 304;
+ static redirect(url, status = 302) {
+ const prefix = "Failed to call 'Response.redirect'";
+ url = webidl.converters["USVString"](url, {
+ prefix,
+ context: "Argument 1",
+ });
+ status = webidl.converters["unsigned short"](status, {
+ prefix,
+ context: "Argument 2",
+ });
+
+ const baseURL = getLocationHref();
+ const parsedURL = new URL(url, baseURL);
+ if (!redirectStatus(status)) {
+ throw new RangeError("Invalid redirect status code.");
+ }
+ const inner = newInnerResponse(status);
+ inner.type = "default";
+ ArrayPrototypePush(inner.headerList, ["Location", parsedURL.href]);
+ const response = webidl.createBranded(Response);
+ response[_response] = inner;
+ response[_headers] = headersFromHeaderList(
+ response[_response].headerList,
+ "immutable",
+ );
+ return response;
}
/**
- * @param {number} status
- * @returns {boolean}
+ * @param {any} data
+ * @param {ResponseInit} init
+ * @returns {Response}
*/
- function redirectStatus(status) {
- return status === 301 || status === 302 || status === 303 ||
- status === 307 || status === 308;
+ static json(data = undefined, init = {}) {
+ const prefix = "Failed to call 'Response.json'";
+ data = webidl.converters.any(data);
+ init = webidl.converters["ResponseInit_fast"](init, {
+ prefix,
+ context: "Argument 2",
+ });
+
+ const str = serializeJSValueToJSONString(data);
+ const res = extractBody(str);
+ res.contentType = "application/json";
+ const response = webidl.createBranded(Response);
+ response[_response] = newInnerResponse();
+ response[_headers] = headersFromHeaderList(
+ response[_response].headerList,
+ "response",
+ );
+ initializeAResponse(response, init, res);
+ return response;
}
/**
- * https://fetch.spec.whatwg.org/#concept-response-clone
- * @param {InnerResponse} response
- * @returns {InnerResponse}
+ * @param {BodyInit | null} body
+ * @param {ResponseInit} init
*/
- function cloneInnerResponse(response) {
- const urlList = [...new SafeArrayIterator(response.urlList)];
- const headerList = ArrayPrototypeMap(
- response.headerList,
- (x) => [x[0], x[1]],
+ constructor(body = null, init = undefined) {
+ const prefix = "Failed to construct 'Response'";
+ body = webidl.converters["BodyInit_DOMString?"](body, {
+ prefix,
+ context: "Argument 1",
+ });
+ init = webidl.converters["ResponseInit_fast"](init, {
+ prefix,
+ context: "Argument 2",
+ });
+
+ this[_response] = newInnerResponse();
+ this[_headers] = headersFromHeaderList(
+ this[_response].headerList,
+ "response",
);
- let body = null;
- if (response.body !== null) {
- body = response.body.clone();
+ let bodyWithType = null;
+ if (body !== null) {
+ bodyWithType = extractBody(body);
}
-
- return {
- type: response.type,
- body,
- headerList,
- urlList,
- status: response.status,
- statusMessage: response.statusMessage,
- aborted: response.aborted,
- url() {
- if (this.urlList.length == 0) return null;
- return this.urlList[this.urlList.length - 1];
- },
- };
+ initializeAResponse(this, init, bodyWithType);
+ this[webidl.brand] = webidl.brand;
}
/**
- * @returns {InnerResponse}
+ * @returns {"basic" | "cors" | "default" | "error" | "opaque" | "opaqueredirect"}
*/
- function newInnerResponse(status = 200, statusMessage = "") {
- return {
- type: "default",
- body: null,
- headerList: [],
- urlList: [],
- status,
- statusMessage,
- aborted: false,
- url() {
- if (this.urlList.length == 0) return null;
- return this.urlList[this.urlList.length - 1];
- },
- };
+ get type() {
+ webidl.assertBranded(this, ResponsePrototype);
+ return this[_response].type;
}
/**
- * @param {string} error
- * @returns {InnerResponse}
+ * @returns {string}
*/
- function networkError(error) {
- const resp = newInnerResponse(0);
- resp.type = "error";
- resp.error = error;
- return resp;
+ get url() {
+ webidl.assertBranded(this, ResponsePrototype);
+ const url = this[_response].url();
+ if (url === null) return "";
+ const newUrl = new URL(url);
+ newUrl.hash = "";
+ return newUrl.href;
}
/**
- * @returns {InnerResponse}
+ * @returns {boolean}
*/
- function abortedNetworkError() {
- const resp = networkError("aborted");
- resp.aborted = true;
- return resp;
+ get redirected() {
+ webidl.assertBranded(this, ResponsePrototype);
+ return this[_response].urlList.length > 1;
}
/**
- * https://fetch.spec.whatwg.org#initialize-a-response
- * @param {Response} response
- * @param {ResponseInit} init
- * @param {{ body: __bootstrap.fetchBody.InnerBody, contentType: string | null } | null} bodyWithType
+ * @returns {number}
*/
- function initializeAResponse(response, init, bodyWithType) {
- // 1.
- if ((init.status < 200 || init.status > 599) && init.status != 101) {
- throw new RangeError(
- `The status provided (${init.status}) is not equal to 101 and outside the range [200, 599].`,
- );
- }
-
- // 2.
- if (
- init.statusText &&
- !RegExpPrototypeTest(REASON_PHRASE_RE, init.statusText)
- ) {
- throw new TypeError("Status text is not valid.");
- }
-
- // 3.
- response[_response].status = init.status;
-
- // 4.
- response[_response].statusMessage = init.statusText;
- // 5.
- /** @type {__bootstrap.headers.Headers} */
- const headers = response[_headers];
- if (init.headers) {
- fillHeaders(headers, init.headers);
- }
-
- // 6.
- if (bodyWithType !== null) {
- if (nullBodyStatus(response[_response].status)) {
- throw new TypeError(
- "Response with null body status cannot have body",
- );
- }
-
- const { body, contentType } = bodyWithType;
- response[_response].body = body;
-
- if (contentType !== null) {
- let hasContentType = false;
- const list = headerListFromHeaders(headers);
- for (let i = 0; i < list.length; i++) {
- if (byteLowerCase(list[i][0]) === "content-type") {
- hasContentType = true;
- break;
- }
- }
- if (!hasContentType) {
- ArrayPrototypePush(list, ["Content-Type", contentType]);
- }
- }
- }
+ get status() {
+ webidl.assertBranded(this, ResponsePrototype);
+ return this[_response].status;
}
- class Response {
- get [_mimeType]() {
- const values = getDecodeSplitHeader(
- headerListFromHeaders(this[_headers]),
- "Content-Type",
- );
- return extractMimeType(values);
- }
- get [_body]() {
- return this[_response].body;
- }
-
- /**
- * @returns {Response}
- */
- static error() {
- const inner = newInnerResponse(0);
- inner.type = "error";
- const response = webidl.createBranded(Response);
- response[_response] = inner;
- response[_headers] = headersFromHeaderList(
- response[_response].headerList,
- "immutable",
- );
- return response;
- }
-
- /**
- * @param {string} url
- * @param {number} status
- * @returns {Response}
- */
- static redirect(url, status = 302) {
- const prefix = "Failed to call 'Response.redirect'";
- url = webidl.converters["USVString"](url, {
- prefix,
- context: "Argument 1",
- });
- status = webidl.converters["unsigned short"](status, {
- prefix,
- context: "Argument 2",
- });
-
- const baseURL = getLocationHref();
- const parsedURL = new URL(url, baseURL);
- if (!redirectStatus(status)) {
- throw new RangeError("Invalid redirect status code.");
- }
- const inner = newInnerResponse(status);
- inner.type = "default";
- ArrayPrototypePush(inner.headerList, ["Location", parsedURL.href]);
- const response = webidl.createBranded(Response);
- response[_response] = inner;
- response[_headers] = headersFromHeaderList(
- response[_response].headerList,
- "immutable",
- );
- return response;
- }
-
- /**
- * @param {any} data
- * @param {ResponseInit} init
- * @returns {Response}
- */
- static json(data = undefined, init = {}) {
- const prefix = "Failed to call 'Response.json'";
- data = webidl.converters.any(data);
- init = webidl.converters["ResponseInit_fast"](init, {
- prefix,
- context: "Argument 2",
- });
-
- const str = serializeJSValueToJSONString(data);
- const res = extractBody(str);
- res.contentType = "application/json";
- const response = webidl.createBranded(Response);
- response[_response] = newInnerResponse();
- response[_headers] = headersFromHeaderList(
- response[_response].headerList,
- "response",
- );
- initializeAResponse(response, init, res);
- return response;
- }
-
- /**
- * @param {BodyInit | null} body
- * @param {ResponseInit} init
- */
- constructor(body = null, init = undefined) {
- const prefix = "Failed to construct 'Response'";
- body = webidl.converters["BodyInit_DOMString?"](body, {
- prefix,
- context: "Argument 1",
- });
- init = webidl.converters["ResponseInit_fast"](init, {
- prefix,
- context: "Argument 2",
- });
-
- this[_response] = newInnerResponse();
- this[_headers] = headersFromHeaderList(
- this[_response].headerList,
- "response",
- );
-
- let bodyWithType = null;
- if (body !== null) {
- bodyWithType = extractBody(body);
- }
- initializeAResponse(this, init, bodyWithType);
- this[webidl.brand] = webidl.brand;
- }
-
- /**
- * @returns {"basic" | "cors" | "default" | "error" | "opaque" | "opaqueredirect"}
- */
- get type() {
- webidl.assertBranded(this, ResponsePrototype);
- return this[_response].type;
- }
-
- /**
- * @returns {string}
- */
- get url() {
- webidl.assertBranded(this, ResponsePrototype);
- const url = this[_response].url();
- if (url === null) return "";
- const newUrl = new URL(url);
- newUrl.hash = "";
- return newUrl.href;
- }
-
- /**
- * @returns {boolean}
- */
- get redirected() {
- webidl.assertBranded(this, ResponsePrototype);
- return this[_response].urlList.length > 1;
- }
-
- /**
- * @returns {number}
- */
- get status() {
- webidl.assertBranded(this, ResponsePrototype);
- return this[_response].status;
- }
-
- /**
- * @returns {boolean}
- */
- get ok() {
- webidl.assertBranded(this, ResponsePrototype);
- const status = this[_response].status;
- return status >= 200 && status <= 299;
- }
-
- /**
- * @returns {string}
- */
- get statusText() {
- webidl.assertBranded(this, ResponsePrototype);
- return this[_response].statusMessage;
- }
-
- /**
- * @returns {Headers}
- */
- get headers() {
- webidl.assertBranded(this, ResponsePrototype);
- return this[_headers];
- }
-
- /**
- * @returns {Response}
- */
- clone() {
- webidl.assertBranded(this, ResponsePrototype);
- if (this[_body] && this[_body].unusable()) {
- throw new TypeError("Body is unusable.");
- }
- const second = webidl.createBranded(Response);
- const newRes = cloneInnerResponse(this[_response]);
- second[_response] = newRes;
- second[_headers] = headersFromHeaderList(
- newRes.headerList,
- guardFromHeaders(this[_headers]),
- );
- return second;
- }
-
- [SymbolFor("Deno.customInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(ResponsePrototype, this),
- keys: [
- "body",
- "bodyUsed",
- "headers",
- "ok",
- "redirected",
- "status",
- "statusText",
- "url",
- ],
- }));
- }
+ /**
+ * @returns {boolean}
+ */
+ get ok() {
+ webidl.assertBranded(this, ResponsePrototype);
+ const status = this[_response].status;
+ return status >= 200 && status <= 299;
}
- webidl.configurePrototype(Response);
- ObjectDefineProperties(Response, {
- json: { enumerable: true },
- redirect: { enumerable: true },
- error: { enumerable: true },
- });
- const ResponsePrototype = Response.prototype;
- mixinBody(ResponsePrototype, _body, _mimeType);
-
- webidl.converters["Response"] = webidl.createInterfaceConverter(
- "Response",
- ResponsePrototype,
- );
- webidl.converters["ResponseInit"] = webidl.createDictionaryConverter(
- "ResponseInit",
- [{
- key: "status",
- defaultValue: 200,
- converter: webidl.converters["unsigned short"],
- }, {
- key: "statusText",
- defaultValue: "",
- converter: webidl.converters["ByteString"],
- }, {
- key: "headers",
- converter: webidl.converters["HeadersInit"],
- }],
- );
- webidl.converters["ResponseInit_fast"] = function (init, opts) {
- if (init === undefined || init === null) {
- return { status: 200, statusText: "", headers: undefined };
- }
- // Fast path, if not a proxy
- if (typeof init === "object" && !isProxy(init)) {
- // Not a proxy fast path
- const status = init.status !== undefined
- ? webidl.converters["unsigned short"](init.status)
- : 200;
- const statusText = init.statusText !== undefined
- ? webidl.converters["ByteString"](init.statusText)
- : "";
- const headers = init.headers !== undefined
- ? webidl.converters["HeadersInit"](init.headers)
- : undefined;
- return { status, statusText, headers };
- }
- // Slow default path
- return webidl.converters["ResponseInit"](init, opts);
- };
+ /**
+ * @returns {string}
+ */
+ get statusText() {
+ webidl.assertBranded(this, ResponsePrototype);
+ return this[_response].statusMessage;
+ }
/**
- * @param {Response} response
- * @returns {InnerResponse}
+ * @returns {Headers}
*/
- function toInnerResponse(response) {
- return response[_response];
+ get headers() {
+ webidl.assertBranded(this, ResponsePrototype);
+ return this[_headers];
}
/**
- * @param {InnerResponse} inner
- * @param {"request" | "immutable" | "request-no-cors" | "response" | "none"} guard
* @returns {Response}
*/
- function fromInnerResponse(inner, guard) {
- const response = webidl.createBranded(Response);
- response[_response] = inner;
- response[_headers] = headersFromHeaderList(inner.headerList, guard);
- return response;
+ clone() {
+ webidl.assertBranded(this, ResponsePrototype);
+ if (this[_body] && this[_body].unusable()) {
+ throw new TypeError("Body is unusable.");
+ }
+ const second = webidl.createBranded(Response);
+ const newRes = cloneInnerResponse(this[_response]);
+ second[_response] = newRes;
+ second[_headers] = headersFromHeaderList(
+ newRes.headerList,
+ guardFromHeaders(this[_headers]),
+ );
+ return second;
}
- window.__bootstrap.fetch ??= {};
- window.__bootstrap.fetch.Response = Response;
- window.__bootstrap.fetch.ResponsePrototype = ResponsePrototype;
- window.__bootstrap.fetch.newInnerResponse = newInnerResponse;
- window.__bootstrap.fetch.toInnerResponse = toInnerResponse;
- window.__bootstrap.fetch.fromInnerResponse = fromInnerResponse;
- window.__bootstrap.fetch.redirectStatus = redirectStatus;
- window.__bootstrap.fetch.nullBodyStatus = nullBodyStatus;
- window.__bootstrap.fetch.networkError = networkError;
- window.__bootstrap.fetch.abortedNetworkError = abortedNetworkError;
-})(globalThis);
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(ResponsePrototype, this),
+ keys: [
+ "body",
+ "bodyUsed",
+ "headers",
+ "ok",
+ "redirected",
+ "status",
+ "statusText",
+ "url",
+ ],
+ }));
+ }
+}
+
+webidl.configurePrototype(Response);
+ObjectDefineProperties(Response, {
+ json: { enumerable: true },
+ redirect: { enumerable: true },
+ error: { enumerable: true },
+});
+const ResponsePrototype = Response.prototype;
+mixinBody(ResponsePrototype, _body, _mimeType);
+
+webidl.converters["Response"] = webidl.createInterfaceConverter(
+ "Response",
+ ResponsePrototype,
+);
+webidl.converters["ResponseInit"] = webidl.createDictionaryConverter(
+ "ResponseInit",
+ [{
+ key: "status",
+ defaultValue: 200,
+ converter: webidl.converters["unsigned short"],
+ }, {
+ key: "statusText",
+ defaultValue: "",
+ converter: webidl.converters["ByteString"],
+ }, {
+ key: "headers",
+ converter: webidl.converters["HeadersInit"],
+ }],
+);
+webidl.converters["ResponseInit_fast"] = function (init, opts) {
+ if (init === undefined || init === null) {
+ return { status: 200, statusText: "", headers: undefined };
+ }
+ // Fast path, if not a proxy
+ if (typeof init === "object" && !core.isProxy(init)) {
+ // Not a proxy fast path
+ const status = init.status !== undefined
+ ? webidl.converters["unsigned short"](init.status)
+ : 200;
+ const statusText = init.statusText !== undefined
+ ? webidl.converters["ByteString"](init.statusText)
+ : "";
+ const headers = init.headers !== undefined
+ ? webidl.converters["HeadersInit"](init.headers)
+ : undefined;
+ return { status, statusText, headers };
+ }
+ // Slow default path
+ return webidl.converters["ResponseInit"](init, opts);
+};
+
+/**
+ * @param {Response} response
+ * @returns {InnerResponse}
+ */
+function toInnerResponse(response) {
+ return response[_response];
+}
+
+/**
+ * @param {InnerResponse} inner
+ * @param {"request" | "immutable" | "request-no-cors" | "response" | "none"} guard
+ * @returns {Response}
+ */
+function fromInnerResponse(inner, guard) {
+ const response = webidl.createBranded(Response);
+ response[_response] = inner;
+ response[_headers] = headersFromHeaderList(inner.headerList, guard);
+ return response;
+}
+
+export {
+ abortedNetworkError,
+ fromInnerResponse,
+ networkError,
+ newInnerResponse,
+ nullBodyStatus,
+ redirectStatus,
+ Response,
+ ResponsePrototype,
+ toInnerResponse,
+};
diff --git a/ext/fetch/26_fetch.js b/ext/fetch/26_fetch.js
index ddb023a37..9c136f242 100644
--- a/ext/fetch/26_fetch.js
+++ b/ext/fetch/26_fetch.js
@@ -9,578 +9,577 @@
/// <reference path="./internal.d.ts" />
/// <reference path="./lib.deno_fetch.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const { byteLowerCase } = window.__bootstrap.infra;
- const { BlobPrototype } = window.__bootstrap.file;
- const { errorReadableStream, ReadableStreamPrototype, readableStreamForRid } =
- window.__bootstrap.streams;
- const { InnerBody, extractBody } = window.__bootstrap.fetchBody;
- const {
- toInnerRequest,
- toInnerResponse,
- fromInnerResponse,
- redirectStatus,
- nullBodyStatus,
- networkError,
- abortedNetworkError,
- processUrlList,
- } = window.__bootstrap.fetch;
- const abortSignal = window.__bootstrap.abortSignal;
- const {
- ArrayPrototypePush,
- ArrayPrototypeSplice,
- ArrayPrototypeFilter,
- ArrayPrototypeIncludes,
- ObjectPrototypeIsPrototypeOf,
- Promise,
- PromisePrototypeThen,
- PromisePrototypeCatch,
- SafeArrayIterator,
- String,
- StringPrototypeStartsWith,
- StringPrototypeToLowerCase,
- TypeError,
- Uint8Array,
- Uint8ArrayPrototype,
- WeakMap,
- WeakMapPrototypeDelete,
- WeakMapPrototypeGet,
- WeakMapPrototypeHas,
- WeakMapPrototypeSet,
- } = window.__bootstrap.primordials;
-
- const REQUEST_BODY_HEADER_NAMES = [
- "content-encoding",
- "content-language",
- "content-location",
- "content-type",
- ];
-
- const requestBodyReaders = new WeakMap();
-
- /**
- * @param {{ method: string, url: string, headers: [string, string][], clientRid: number | null, hasBody: boolean }} args
- * @param {Uint8Array | null} body
- * @returns {{ requestRid: number, requestBodyRid: number | null }}
- */
- function opFetch(method, url, headers, clientRid, hasBody, bodyLength, body) {
- return ops.op_fetch(
- method,
- url,
- headers,
- clientRid,
- hasBody,
- bodyLength,
- body,
- );
- }
- /**
- * @param {number} rid
- * @returns {Promise<{ status: number, statusText: string, headers: [string, string][], url: string, responseRid: number }>}
- */
- function opFetchSend(rid) {
- return core.opAsync("op_fetch_send", rid);
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { byteLowerCase } from "internal:ext/web/00_infra.js";
+import { BlobPrototype } from "internal:ext/web/09_file.js";
+import {
+ errorReadableStream,
+ readableStreamForRid,
+ ReadableStreamPrototype,
+} from "internal:ext/web/06_streams.js";
+import { extractBody, InnerBody } from "internal:ext/fetch/22_body.js";
+import {
+ processUrlList,
+ toInnerRequest,
+} from "internal:ext/fetch/23_request.js";
+import {
+ abortedNetworkError,
+ fromInnerResponse,
+ networkError,
+ nullBodyStatus,
+ redirectStatus,
+ toInnerResponse,
+} from "internal:ext/fetch/23_response.js";
+import * as abortSignal from "internal:ext/web/03_abort_signal.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypePush,
+ ArrayPrototypeSplice,
+ ArrayPrototypeFilter,
+ ArrayPrototypeIncludes,
+ ObjectPrototypeIsPrototypeOf,
+ Promise,
+ PromisePrototypeThen,
+ PromisePrototypeCatch,
+ SafeArrayIterator,
+ String,
+ StringPrototypeStartsWith,
+ StringPrototypeToLowerCase,
+ TypeError,
+ Uint8Array,
+ Uint8ArrayPrototype,
+ WeakMap,
+ WeakMapPrototypeDelete,
+ WeakMapPrototypeGet,
+ WeakMapPrototypeHas,
+ WeakMapPrototypeSet,
+} = primordials;
+
+const REQUEST_BODY_HEADER_NAMES = [
+ "content-encoding",
+ "content-language",
+ "content-location",
+ "content-type",
+];
+
+const requestBodyReaders = new WeakMap();
+
+/**
+ * @param {{ method: string, url: string, headers: [string, string][], clientRid: number | null, hasBody: boolean }} args
+ * @param {Uint8Array | null} body
+ * @returns {{ requestRid: number, requestBodyRid: number | null }}
+ */
+function opFetch(method, url, headers, clientRid, hasBody, bodyLength, body) {
+ return ops.op_fetch(
+ method,
+ url,
+ headers,
+ clientRid,
+ hasBody,
+ bodyLength,
+ body,
+ );
+}
+
+/**
+ * @param {number} rid
+ * @returns {Promise<{ status: number, statusText: string, headers: [string, string][], url: string, responseRid: number }>}
+ */
+function opFetchSend(rid) {
+ return core.opAsync("op_fetch_send", rid);
+}
+
+/**
+ * @param {number} responseBodyRid
+ * @param {AbortSignal} [terminator]
+ * @returns {ReadableStream<Uint8Array>}
+ */
+function createResponseBodyStream(responseBodyRid, terminator) {
+ const readable = readableStreamForRid(responseBodyRid);
+
+ function onAbort() {
+ errorReadableStream(readable, terminator.reason);
+ core.tryClose(responseBodyRid);
}
- /**
- * @param {number} responseBodyRid
- * @param {AbortSignal} [terminator]
- * @returns {ReadableStream<Uint8Array>}
- */
- function createResponseBodyStream(responseBodyRid, terminator) {
- const readable = readableStreamForRid(responseBodyRid);
-
- function onAbort() {
- errorReadableStream(readable, terminator.reason);
- core.tryClose(responseBodyRid);
+ // TODO(lucacasonato): clean up registration
+ terminator[abortSignal.add](onAbort);
+
+ return readable;
+}
+
+/**
+ * @param {InnerRequest} req
+ * @param {boolean} recursive
+ * @param {AbortSignal} terminator
+ * @returns {Promise<InnerResponse>}
+ */
+async function mainFetch(req, recursive, terminator) {
+ if (req.blobUrlEntry !== null) {
+ if (req.method !== "GET") {
+ throw new TypeError("Blob URL fetch only supports GET method.");
}
- // TODO(lucacasonato): clean up registration
- terminator[abortSignal.add](onAbort);
+ const body = new InnerBody(req.blobUrlEntry.stream());
+ terminator[abortSignal.add](() => body.error(terminator.reason));
+ processUrlList(req.urlList, req.urlListProcessed);
- return readable;
+ return {
+ headerList: [
+ ["content-length", String(req.blobUrlEntry.size)],
+ ["content-type", req.blobUrlEntry.type],
+ ],
+ status: 200,
+ statusMessage: "OK",
+ body,
+ type: "basic",
+ url() {
+ if (this.urlList.length == 0) return null;
+ return this.urlList[this.urlList.length - 1];
+ },
+ urlList: recursive
+ ? []
+ : [...new SafeArrayIterator(req.urlListProcessed)],
+ };
}
- /**
- * @param {InnerRequest} req
- * @param {boolean} recursive
- * @param {AbortSignal} terminator
- * @returns {Promise<InnerResponse>}
- */
- async function mainFetch(req, recursive, terminator) {
- if (req.blobUrlEntry !== null) {
- if (req.method !== "GET") {
- throw new TypeError("Blob URL fetch only supports GET method.");
- }
-
- const body = new InnerBody(req.blobUrlEntry.stream());
- terminator[abortSignal.add](() => body.error(terminator.reason));
- processUrlList(req.urlList, req.urlListProcessed);
-
- return {
- headerList: [
- ["content-length", String(req.blobUrlEntry.size)],
- ["content-type", req.blobUrlEntry.type],
- ],
- status: 200,
- statusMessage: "OK",
- body,
- type: "basic",
- url() {
- if (this.urlList.length == 0) return null;
- return this.urlList[this.urlList.length - 1];
- },
- urlList: recursive
- ? []
- : [...new SafeArrayIterator(req.urlListProcessed)],
- };
- }
+ /** @type {ReadableStream<Uint8Array> | Uint8Array | null} */
+ let reqBody = null;
- /** @type {ReadableStream<Uint8Array> | Uint8Array | null} */
- let reqBody = null;
-
- if (req.body !== null) {
+ if (req.body !== null) {
+ if (
+ ObjectPrototypeIsPrototypeOf(
+ ReadableStreamPrototype,
+ req.body.streamOrStatic,
+ )
+ ) {
if (
- ObjectPrototypeIsPrototypeOf(
- ReadableStreamPrototype,
- req.body.streamOrStatic,
- )
+ req.body.length === null ||
+ ObjectPrototypeIsPrototypeOf(BlobPrototype, req.body.source)
) {
- if (
- req.body.length === null ||
- ObjectPrototypeIsPrototypeOf(BlobPrototype, req.body.source)
- ) {
- reqBody = req.body.stream;
+ reqBody = req.body.stream;
+ } else {
+ const reader = req.body.stream.getReader();
+ WeakMapPrototypeSet(requestBodyReaders, req, reader);
+ const r1 = await reader.read();
+ if (r1.done) {
+ reqBody = new Uint8Array(0);
} else {
- const reader = req.body.stream.getReader();
- WeakMapPrototypeSet(requestBodyReaders, req, reader);
- const r1 = await reader.read();
- if (r1.done) {
- reqBody = new Uint8Array(0);
- } else {
- reqBody = r1.value;
- const r2 = await reader.read();
- if (!r2.done) throw new TypeError("Unreachable");
- }
- WeakMapPrototypeDelete(requestBodyReaders, req);
+ reqBody = r1.value;
+ const r2 = await reader.read();
+ if (!r2.done) throw new TypeError("Unreachable");
}
- } else {
- req.body.streamOrStatic.consumed = true;
- reqBody = req.body.streamOrStatic.body;
- // TODO(@AaronO): plumb support for StringOrBuffer all the way
- reqBody = typeof reqBody === "string" ? core.encode(reqBody) : reqBody;
+ WeakMapPrototypeDelete(requestBodyReaders, req);
}
+ } else {
+ req.body.streamOrStatic.consumed = true;
+ reqBody = req.body.streamOrStatic.body;
+ // TODO(@AaronO): plumb support for StringOrBuffer all the way
+ reqBody = typeof reqBody === "string" ? core.encode(reqBody) : reqBody;
}
+ }
- const { requestRid, requestBodyRid, cancelHandleRid } = opFetch(
- req.method,
- req.currentUrl(),
- req.headerList,
- req.clientRid,
- reqBody !== null,
- req.body?.length,
- ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, reqBody)
- ? reqBody
- : null,
- );
-
- function onAbort() {
- if (cancelHandleRid !== null) {
- core.tryClose(cancelHandleRid);
- }
- if (requestBodyRid !== null) {
- core.tryClose(requestBodyRid);
- }
+ const { requestRid, requestBodyRid, cancelHandleRid } = opFetch(
+ req.method,
+ req.currentUrl(),
+ req.headerList,
+ req.clientRid,
+ reqBody !== null,
+ req.body?.length,
+ ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, reqBody) ? reqBody : null,
+ );
+
+ function onAbort() {
+ if (cancelHandleRid !== null) {
+ core.tryClose(cancelHandleRid);
}
- terminator[abortSignal.add](onAbort);
-
- let requestSendError;
- let requestSendErrorSet = false;
if (requestBodyRid !== null) {
- if (
- reqBody === null ||
- !ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, reqBody)
- ) {
- throw new TypeError("Unreachable");
+ core.tryClose(requestBodyRid);
+ }
+ }
+ terminator[abortSignal.add](onAbort);
+
+ let requestSendError;
+ let requestSendErrorSet = false;
+ if (requestBodyRid !== null) {
+ if (
+ reqBody === null ||
+ !ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, reqBody)
+ ) {
+ throw new TypeError("Unreachable");
+ }
+ const reader = reqBody.getReader();
+ WeakMapPrototypeSet(requestBodyReaders, req, reader);
+ (async () => {
+ let done = false;
+ while (!done) {
+ let val;
+ try {
+ const res = await reader.read();
+ done = res.done;
+ val = res.value;
+ } catch (err) {
+ if (terminator.aborted) break;
+ // TODO(lucacasonato): propagate error into response body stream
+ requestSendError = err;
+ requestSendErrorSet = true;
+ break;
+ }
+ if (done) break;
+ if (!ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, val)) {
+ const error = new TypeError(
+ "Item in request body ReadableStream is not a Uint8Array",
+ );
+ await reader.cancel(error);
+ // TODO(lucacasonato): propagate error into response body stream
+ requestSendError = error;
+ requestSendErrorSet = true;
+ break;
+ }
+ try {
+ await core.writeAll(requestBodyRid, val);
+ } catch (err) {
+ if (terminator.aborted) break;
+ await reader.cancel(err);
+ // TODO(lucacasonato): propagate error into response body stream
+ requestSendError = err;
+ requestSendErrorSet = true;
+ break;
+ }
}
- const reader = reqBody.getReader();
- WeakMapPrototypeSet(requestBodyReaders, req, reader);
- (async () => {
- let done = false;
- while (!done) {
- let val;
- try {
- const res = await reader.read();
- done = res.done;
- val = res.value;
- } catch (err) {
- if (terminator.aborted) break;
- // TODO(lucacasonato): propagate error into response body stream
+ if (done && !terminator.aborted) {
+ try {
+ await core.shutdown(requestBodyRid);
+ } catch (err) {
+ if (!terminator.aborted) {
requestSendError = err;
requestSendErrorSet = true;
- break;
- }
- if (done) break;
- if (!ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, val)) {
- const error = new TypeError(
- "Item in request body ReadableStream is not a Uint8Array",
- );
- await reader.cancel(error);
- // TODO(lucacasonato): propagate error into response body stream
- requestSendError = error;
- requestSendErrorSet = true;
- break;
- }
- try {
- await core.writeAll(requestBodyRid, val);
- } catch (err) {
- if (terminator.aborted) break;
- await reader.cancel(err);
- // TODO(lucacasonato): propagate error into response body stream
- requestSendError = err;
- requestSendErrorSet = true;
- break;
}
}
- if (done && !terminator.aborted) {
- try {
- await core.shutdown(requestBodyRid);
- } catch (err) {
- if (!terminator.aborted) {
- requestSendError = err;
- requestSendErrorSet = true;
- }
- }
- }
- WeakMapPrototypeDelete(requestBodyReaders, req);
- core.tryClose(requestBodyRid);
- })();
- }
- let resp;
- try {
- resp = await opFetchSend(requestRid);
- } catch (err) {
- if (terminator.aborted) return;
- if (requestSendErrorSet) {
- // if the request body stream errored, we want to propagate that error
- // instead of the original error from opFetchSend
- throw new TypeError("Failed to fetch: request body stream errored", {
- cause: requestSendError,
- });
- }
- throw err;
- } finally {
- if (cancelHandleRid !== null) {
- core.tryClose(cancelHandleRid);
}
+ WeakMapPrototypeDelete(requestBodyReaders, req);
+ core.tryClose(requestBodyRid);
+ })();
+ }
+ let resp;
+ try {
+ resp = await opFetchSend(requestRid);
+ } catch (err) {
+ if (terminator.aborted) return;
+ if (requestSendErrorSet) {
+ // if the request body stream errored, we want to propagate that error
+ // instead of the original error from opFetchSend
+ throw new TypeError("Failed to fetch: request body stream errored", {
+ cause: requestSendError,
+ });
}
- if (terminator.aborted) return abortedNetworkError();
-
- processUrlList(req.urlList, req.urlListProcessed);
-
- /** @type {InnerResponse} */
- const response = {
- headerList: resp.headers,
- status: resp.status,
- body: null,
- statusMessage: resp.statusText,
- type: "basic",
- url() {
- if (this.urlList.length == 0) return null;
- return this.urlList[this.urlList.length - 1];
- },
- urlList: req.urlListProcessed,
- };
- if (redirectStatus(resp.status)) {
- switch (req.redirectMode) {
- case "error":
- core.close(resp.responseRid);
- return networkError(
- "Encountered redirect while redirect mode is set to 'error'",
- );
- case "follow":
- core.close(resp.responseRid);
- return httpRedirectFetch(req, response, terminator);
- case "manual":
- break;
- }
+ throw err;
+ } finally {
+ if (cancelHandleRid !== null) {
+ core.tryClose(cancelHandleRid);
+ }
+ }
+ if (terminator.aborted) return abortedNetworkError();
+
+ processUrlList(req.urlList, req.urlListProcessed);
+
+ /** @type {InnerResponse} */
+ const response = {
+ headerList: resp.headers,
+ status: resp.status,
+ body: null,
+ statusMessage: resp.statusText,
+ type: "basic",
+ url() {
+ if (this.urlList.length == 0) return null;
+ return this.urlList[this.urlList.length - 1];
+ },
+ urlList: req.urlListProcessed,
+ };
+ if (redirectStatus(resp.status)) {
+ switch (req.redirectMode) {
+ case "error":
+ core.close(resp.responseRid);
+ return networkError(
+ "Encountered redirect while redirect mode is set to 'error'",
+ );
+ case "follow":
+ core.close(resp.responseRid);
+ return httpRedirectFetch(req, response, terminator);
+ case "manual":
+ break;
}
+ }
- if (nullBodyStatus(response.status)) {
+ if (nullBodyStatus(response.status)) {
+ core.close(resp.responseRid);
+ } else {
+ if (req.method === "HEAD" || req.method === "CONNECT") {
+ response.body = null;
core.close(resp.responseRid);
} else {
- if (req.method === "HEAD" || req.method === "CONNECT") {
- response.body = null;
- core.close(resp.responseRid);
- } else {
- response.body = new InnerBody(
- createResponseBodyStream(resp.responseRid, terminator),
- );
- }
+ response.body = new InnerBody(
+ createResponseBodyStream(resp.responseRid, terminator),
+ );
}
+ }
- if (recursive) return response;
+ if (recursive) return response;
- if (response.urlList.length === 0) {
- processUrlList(req.urlList, req.urlListProcessed);
- response.urlList = [...new SafeArrayIterator(req.urlListProcessed)];
- }
+ if (response.urlList.length === 0) {
+ processUrlList(req.urlList, req.urlListProcessed);
+ response.urlList = [...new SafeArrayIterator(req.urlListProcessed)];
+ }
+ return response;
+}
+
+/**
+ * @param {InnerRequest} request
+ * @param {InnerResponse} response
+ * @param {AbortSignal} terminator
+ * @returns {Promise<InnerResponse>}
+ */
+function httpRedirectFetch(request, response, terminator) {
+ const locationHeaders = ArrayPrototypeFilter(
+ response.headerList,
+ (entry) => byteLowerCase(entry[0]) === "location",
+ );
+ if (locationHeaders.length === 0) {
return response;
}
-
- /**
- * @param {InnerRequest} request
- * @param {InnerResponse} response
- * @param {AbortSignal} terminator
- * @returns {Promise<InnerResponse>}
- */
- function httpRedirectFetch(request, response, terminator) {
- const locationHeaders = ArrayPrototypeFilter(
- response.headerList,
- (entry) => byteLowerCase(entry[0]) === "location",
- );
- if (locationHeaders.length === 0) {
- return response;
- }
- const locationURL = new URL(
- locationHeaders[0][1],
- response.url() ?? undefined,
+ const locationURL = new URL(
+ locationHeaders[0][1],
+ response.url() ?? undefined,
+ );
+ if (locationURL.hash === "") {
+ locationURL.hash = request.currentUrl().hash;
+ }
+ if (locationURL.protocol !== "https:" && locationURL.protocol !== "http:") {
+ return networkError("Can not redirect to a non HTTP(s) url");
+ }
+ if (request.redirectCount === 20) {
+ return networkError("Maximum number of redirects (20) reached");
+ }
+ request.redirectCount++;
+ if (
+ response.status !== 303 &&
+ request.body !== null &&
+ request.body.source === null
+ ) {
+ return networkError(
+ "Can not redeliver a streaming request body after a redirect",
);
- if (locationURL.hash === "") {
- locationURL.hash = request.currentUrl().hash;
- }
- if (locationURL.protocol !== "https:" && locationURL.protocol !== "http:") {
- return networkError("Can not redirect to a non HTTP(s) url");
- }
- if (request.redirectCount === 20) {
- return networkError("Maximum number of redirects (20) reached");
- }
- request.redirectCount++;
- if (
- response.status !== 303 &&
- request.body !== null &&
- request.body.source === null
- ) {
- return networkError(
- "Can not redeliver a streaming request body after a redirect",
- );
- }
- if (
- ((response.status === 301 || response.status === 302) &&
- request.method === "POST") ||
- (response.status === 303 &&
- request.method !== "GET" &&
- request.method !== "HEAD")
- ) {
- request.method = "GET";
- request.body = null;
- for (let i = 0; i < request.headerList.length; i++) {
- if (
- ArrayPrototypeIncludes(
- REQUEST_BODY_HEADER_NAMES,
- byteLowerCase(request.headerList[i][0]),
- )
- ) {
- ArrayPrototypeSplice(request.headerList, i, 1);
- i--;
- }
+ }
+ if (
+ ((response.status === 301 || response.status === 302) &&
+ request.method === "POST") ||
+ (response.status === 303 &&
+ request.method !== "GET" &&
+ request.method !== "HEAD")
+ ) {
+ request.method = "GET";
+ request.body = null;
+ for (let i = 0; i < request.headerList.length; i++) {
+ if (
+ ArrayPrototypeIncludes(
+ REQUEST_BODY_HEADER_NAMES,
+ byteLowerCase(request.headerList[i][0]),
+ )
+ ) {
+ ArrayPrototypeSplice(request.headerList, i, 1);
+ i--;
}
}
- if (request.body !== null) {
- const res = extractBody(request.body.source);
- request.body = res.body;
- }
- ArrayPrototypePush(request.urlList, () => locationURL.href);
- return mainFetch(request, true, terminator);
}
+ if (request.body !== null) {
+ const res = extractBody(request.body.source);
+ request.body = res.body;
+ }
+ ArrayPrototypePush(request.urlList, () => locationURL.href);
+ return mainFetch(request, true, terminator);
+}
+
+/**
+ * @param {RequestInfo} input
+ * @param {RequestInit} init
+ */
+function fetch(input, init = {}) {
+ // There is an async dispatch later that causes a stack trace disconnect.
+ // We reconnect it by assigning the result of that dispatch to `opPromise`,
+ // awaiting `opPromise` in an inner function also named `fetch()` and
+ // returning the result from that.
+ let opPromise = undefined;
+ // 1.
+ const result = new Promise((resolve, reject) => {
+ const prefix = "Failed to call 'fetch'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ // 2.
+ const requestObject = new Request(input, init);
+ // 3.
+ const request = toInnerRequest(requestObject);
+ // 4.
+ if (requestObject.signal.aborted) {
+ reject(abortFetch(request, null, requestObject.signal.reason));
+ return;
+ }
- /**
- * @param {RequestInfo} input
- * @param {RequestInit} init
- */
- function fetch(input, init = {}) {
- // There is an async dispatch later that causes a stack trace disconnect.
- // We reconnect it by assigning the result of that dispatch to `opPromise`,
- // awaiting `opPromise` in an inner function also named `fetch()` and
- // returning the result from that.
- let opPromise = undefined;
- // 1.
- const result = new Promise((resolve, reject) => {
- const prefix = "Failed to call 'fetch'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- // 2.
- const requestObject = new Request(input, init);
- // 3.
- const request = toInnerRequest(requestObject);
- // 4.
- if (requestObject.signal.aborted) {
- reject(abortFetch(request, null, requestObject.signal.reason));
- return;
- }
-
- // 7.
- let responseObject = null;
- // 9.
- let locallyAborted = false;
- // 10.
- function onabort() {
- locallyAborted = true;
- reject(
- abortFetch(request, responseObject, requestObject.signal.reason),
- );
- }
- requestObject.signal[abortSignal.add](onabort);
+ // 7.
+ let responseObject = null;
+ // 9.
+ let locallyAborted = false;
+ // 10.
+ function onabort() {
+ locallyAborted = true;
+ reject(
+ abortFetch(request, responseObject, requestObject.signal.reason),
+ );
+ }
+ requestObject.signal[abortSignal.add](onabort);
- if (!requestObject.headers.has("Accept")) {
- ArrayPrototypePush(request.headerList, ["Accept", "*/*"]);
- }
+ if (!requestObject.headers.has("Accept")) {
+ ArrayPrototypePush(request.headerList, ["Accept", "*/*"]);
+ }
- if (!requestObject.headers.has("Accept-Language")) {
- ArrayPrototypePush(request.headerList, ["Accept-Language", "*"]);
- }
+ if (!requestObject.headers.has("Accept-Language")) {
+ ArrayPrototypePush(request.headerList, ["Accept-Language", "*"]);
+ }
- // 12.
- opPromise = PromisePrototypeCatch(
- PromisePrototypeThen(
- mainFetch(request, false, requestObject.signal),
- (response) => {
- // 12.1.
- if (locallyAborted) return;
- // 12.2.
- if (response.aborted) {
- reject(
- abortFetch(
- request,
- responseObject,
- requestObject.signal.reason,
- ),
- );
- requestObject.signal[abortSignal.remove](onabort);
- return;
- }
- // 12.3.
- if (response.type === "error") {
- const err = new TypeError(
- "Fetch failed: " + (response.error ?? "unknown error"),
- );
- reject(err);
- requestObject.signal[abortSignal.remove](onabort);
- return;
- }
- responseObject = fromInnerResponse(response, "immutable");
- resolve(responseObject);
+ // 12.
+ opPromise = PromisePrototypeCatch(
+ PromisePrototypeThen(
+ mainFetch(request, false, requestObject.signal),
+ (response) => {
+ // 12.1.
+ if (locallyAborted) return;
+ // 12.2.
+ if (response.aborted) {
+ reject(
+ abortFetch(
+ request,
+ responseObject,
+ requestObject.signal.reason,
+ ),
+ );
requestObject.signal[abortSignal.remove](onabort);
- },
- ),
- (err) => {
- reject(err);
+ return;
+ }
+ // 12.3.
+ if (response.type === "error") {
+ const err = new TypeError(
+ "Fetch failed: " + (response.error ?? "unknown error"),
+ );
+ reject(err);
+ requestObject.signal[abortSignal.remove](onabort);
+ return;
+ }
+ responseObject = fromInnerResponse(response, "immutable");
+ resolve(responseObject);
requestObject.signal[abortSignal.remove](onabort);
},
- );
- });
- if (opPromise) {
- PromisePrototypeCatch(result, () => {});
- return (async function fetch() {
- await opPromise;
- return result;
- })();
- }
- return result;
+ ),
+ (err) => {
+ reject(err);
+ requestObject.signal[abortSignal.remove](onabort);
+ },
+ );
+ });
+ if (opPromise) {
+ PromisePrototypeCatch(result, () => {});
+ return (async function fetch() {
+ await opPromise;
+ return result;
+ })();
}
+ return result;
+}
- function abortFetch(request, responseObject, error) {
- if (request.body !== null) {
- if (WeakMapPrototypeHas(requestBodyReaders, request)) {
- WeakMapPrototypeGet(requestBodyReaders, request).cancel(error);
- } else {
- request.body.cancel(error);
- }
- }
- if (responseObject !== null) {
- const response = toInnerResponse(responseObject);
- if (response.body !== null) response.body.error(error);
+function abortFetch(request, responseObject, error) {
+ if (request.body !== null) {
+ if (WeakMapPrototypeHas(requestBodyReaders, request)) {
+ WeakMapPrototypeGet(requestBodyReaders, request).cancel(error);
+ } else {
+ request.body.cancel(error);
}
- return error;
}
+ if (responseObject !== null) {
+ const response = toInnerResponse(responseObject);
+ if (response.body !== null) response.body.error(error);
+ }
+ return error;
+}
+
+/**
+ * Handle the Response argument to the WebAssembly streaming APIs, after
+ * resolving if it was passed as a promise. This function should be registered
+ * through `Deno.core.setWasmStreamingCallback`.
+ *
+ * @param {any} source The source parameter that the WebAssembly streaming API
+ * was called with. If it was called with a Promise, `source` is the resolved
+ * value of that promise.
+ * @param {number} rid An rid that represents the wasm streaming resource.
+ */
+function handleWasmStreaming(source, rid) {
+ // This implements part of
+ // https://webassembly.github.io/spec/web-api/#compile-a-potential-webassembly-response
+ try {
+ const res = webidl.converters["Response"](source, {
+ prefix: "Failed to call 'WebAssembly.compileStreaming'",
+ context: "Argument 1",
+ });
- /**
- * Handle the Response argument to the WebAssembly streaming APIs, after
- * resolving if it was passed as a promise. This function should be registered
- * through `Deno.core.setWasmStreamingCallback`.
- *
- * @param {any} source The source parameter that the WebAssembly streaming API
- * was called with. If it was called with a Promise, `source` is the resolved
- * value of that promise.
- * @param {number} rid An rid that represents the wasm streaming resource.
- */
- function handleWasmStreaming(source, rid) {
- // This implements part of
- // https://webassembly.github.io/spec/web-api/#compile-a-potential-webassembly-response
- try {
- const res = webidl.converters["Response"](source, {
- prefix: "Failed to call 'WebAssembly.compileStreaming'",
- context: "Argument 1",
- });
-
- // 2.3.
- // The spec is ambiguous here, see
- // https://github.com/WebAssembly/spec/issues/1138. The WPT tests expect
- // the raw value of the Content-Type attribute lowercased. We ignore this
- // for file:// because file fetches don't have a Content-Type.
- if (!StringPrototypeStartsWith(res.url, "file://")) {
- const contentType = res.headers.get("Content-Type");
- if (
- typeof contentType !== "string" ||
- StringPrototypeToLowerCase(contentType) !== "application/wasm"
- ) {
- throw new TypeError("Invalid WebAssembly content type.");
- }
+ // 2.3.
+ // The spec is ambiguous here, see
+ // https://github.com/WebAssembly/spec/issues/1138. The WPT tests expect
+ // the raw value of the Content-Type attribute lowercased. We ignore this
+ // for file:// because file fetches don't have a Content-Type.
+ if (!StringPrototypeStartsWith(res.url, "file://")) {
+ const contentType = res.headers.get("Content-Type");
+ if (
+ typeof contentType !== "string" ||
+ StringPrototypeToLowerCase(contentType) !== "application/wasm"
+ ) {
+ throw new TypeError("Invalid WebAssembly content type.");
}
+ }
- // 2.5.
- if (!res.ok) {
- throw new TypeError(`HTTP status code ${res.status}`);
- }
+ // 2.5.
+ if (!res.ok) {
+ throw new TypeError(`HTTP status code ${res.status}`);
+ }
- // Pass the resolved URL to v8.
- ops.op_wasm_streaming_set_url(rid, res.url);
-
- if (res.body !== null) {
- // 2.6.
- // Rather than consuming the body as an ArrayBuffer, this passes each
- // chunk to the feed as soon as it's available.
- PromisePrototypeThen(
- (async () => {
- const reader = res.body.getReader();
- while (true) {
- const { value: chunk, done } = await reader.read();
- if (done) break;
- ops.op_wasm_streaming_feed(rid, chunk);
- }
- })(),
- // 2.7
- () => core.close(rid),
- // 2.8
- (err) => core.abortWasmStreaming(rid, err),
- );
- } else {
+ // Pass the resolved URL to v8.
+ ops.op_wasm_streaming_set_url(rid, res.url);
+
+ if (res.body !== null) {
+ // 2.6.
+ // Rather than consuming the body as an ArrayBuffer, this passes each
+ // chunk to the feed as soon as it's available.
+ PromisePrototypeThen(
+ (async () => {
+ const reader = res.body.getReader();
+ while (true) {
+ const { value: chunk, done } = await reader.read();
+ if (done) break;
+ ops.op_wasm_streaming_feed(rid, chunk);
+ }
+ })(),
// 2.7
- core.close(rid);
- }
- } catch (err) {
- // 2.8
- core.abortWasmStreaming(rid, err);
+ () => core.close(rid),
+ // 2.8
+ (err) => core.abortWasmStreaming(rid, err),
+ );
+ } else {
+ // 2.7
+ core.close(rid);
}
+ } catch (err) {
+ // 2.8
+ core.abortWasmStreaming(rid, err);
}
+}
- window.__bootstrap.fetch ??= {};
- window.__bootstrap.fetch.fetch = fetch;
- window.__bootstrap.fetch.handleWasmStreaming = handleWasmStreaming;
-})(this);
+export { fetch, handleWasmStreaming };
diff --git a/ext/fetch/internal.d.ts b/ext/fetch/internal.d.ts
index 13a91d2d0..596e3ffcb 100644
--- a/ext/fetch/internal.d.ts
+++ b/ext/fetch/internal.d.ts
@@ -5,106 +5,98 @@
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
-declare namespace globalThis {
- declare namespace __bootstrap {
- declare var fetchUtil: {
- requiredArguments(name: string, length: number, required: number): void;
- };
+declare var domIterable: {
+ DomIterableMixin(base: any, dataSymbol: symbol): any;
+};
- declare var domIterable: {
- DomIterableMixin(base: any, dataSymbol: symbol): any;
- };
-
- declare namespace headers {
- class Headers {
- }
- type HeaderList = [string, string][];
- function headersFromHeaderList(
- list: HeaderList,
- guard:
- | "immutable"
- | "request"
- | "request-no-cors"
- | "response"
- | "none",
- ): Headers;
- function headerListFromHeaders(headers: Headers): HeaderList;
- function fillHeaders(headers: Headers, object: HeadersInit): void;
- function getDecodeSplitHeader(
- list: HeaderList,
- name: string,
- ): string[] | null;
- function guardFromHeaders(
- headers: Headers,
- ): "immutable" | "request" | "request-no-cors" | "response" | "none";
- }
-
- declare namespace formData {
- declare type FormData = typeof FormData;
- declare function formDataToBlob(
- formData: globalThis.FormData,
- ): Blob;
- declare function parseFormData(
- body: Uint8Array,
- boundary: string | undefined,
- ): FormData;
- declare function formDataFromEntries(entries: FormDataEntry[]): FormData;
- }
+declare module "internal:ext/fetch/20_headers.js" {
+ class Headers {
+ }
+ type HeaderList = [string, string][];
+ function headersFromHeaderList(
+ list: HeaderList,
+ guard:
+ | "immutable"
+ | "request"
+ | "request-no-cors"
+ | "response"
+ | "none",
+ ): Headers;
+ function headerListFromHeaders(headers: Headers): HeaderList;
+ function fillHeaders(headers: Headers, object: HeadersInit): void;
+ function getDecodeSplitHeader(
+ list: HeaderList,
+ name: string,
+ ): string[] | null;
+ function guardFromHeaders(
+ headers: Headers,
+ ): "immutable" | "request" | "request-no-cors" | "response" | "none";
+}
- declare namespace fetchBody {
- function mixinBody(
- prototype: any,
- bodySymbol: symbol,
- mimeTypeSymbol: symbol,
- ): void;
- class InnerBody {
- constructor(stream?: ReadableStream<Uint8Array>);
- stream: ReadableStream<Uint8Array>;
- source: null | Uint8Array | Blob | FormData;
- length: null | number;
- unusable(): boolean;
- consume(): Promise<Uint8Array>;
- clone(): InnerBody;
- }
- function extractBody(object: BodyInit): {
- body: InnerBody;
- contentType: string | null;
- };
- }
+declare module "internal:ext/fetch/21_formdata.js" {
+ type FormData = typeof FormData;
+ function formDataToBlob(
+ formData: FormData,
+ ): Blob;
+ function parseFormData(
+ body: Uint8Array,
+ boundary: string | undefined,
+ ): FormData;
+ function formDataFromEntries(entries: FormDataEntry[]): FormData;
+}
- declare namespace fetch {
- function toInnerRequest(request: Request): InnerRequest;
- function fromInnerRequest(
- inner: InnerRequest,
- signal: AbortSignal | null,
- guard:
- | "request"
- | "immutable"
- | "request-no-cors"
- | "response"
- | "none",
- skipBody: boolean,
- flash: boolean,
- ): Request;
- function redirectStatus(status: number): boolean;
- function nullBodyStatus(status: number): boolean;
- function newInnerRequest(
- method: string,
- url: any,
- headerList?: [string, string][],
- body?: globalThis.__bootstrap.fetchBody.InnerBody,
- ): InnerResponse;
- function toInnerResponse(response: Response): InnerResponse;
- function fromInnerResponse(
- inner: InnerResponse,
- guard:
- | "request"
- | "immutable"
- | "request-no-cors"
- | "response"
- | "none",
- ): Response;
- function networkError(error: string): InnerResponse;
- }
+declare module "internal:ext/fetch/22_body.js" {
+ function mixinBody(
+ prototype: any,
+ bodySymbol: symbol,
+ mimeTypeSymbol: symbol,
+ ): void;
+ class InnerBody {
+ constructor(stream?: ReadableStream<Uint8Array>);
+ stream: ReadableStream<Uint8Array>;
+ source: null | Uint8Array | Blob | FormData;
+ length: null | number;
+ unusable(): boolean;
+ consume(): Promise<Uint8Array>;
+ clone(): InnerBody;
}
+ function extractBody(object: BodyInit): {
+ body: InnerBody;
+ contentType: string | null;
+ };
+}
+
+declare module "internal:ext/fetch/26_fetch.js" {
+ function toInnerRequest(request: Request): InnerRequest;
+ function fromInnerRequest(
+ inner: InnerRequest,
+ signal: AbortSignal | null,
+ guard:
+ | "request"
+ | "immutable"
+ | "request-no-cors"
+ | "response"
+ | "none",
+ skipBody: boolean,
+ flash: boolean,
+ ): Request;
+ function redirectStatus(status: number): boolean;
+ function nullBodyStatus(status: number): boolean;
+ function newInnerRequest(
+ method: string,
+ url: any,
+ headerList?: [string, string][],
+ body?: fetchBody.InnerBody,
+ ): InnerResponse;
+ function toInnerResponse(response: Response): InnerResponse;
+ function fromInnerResponse(
+ inner: InnerResponse,
+ guard:
+ | "request"
+ | "immutable"
+ | "request-no-cors"
+ | "response"
+ | "none",
+ ): Response;
+ function networkError(error: string): InnerResponse;
}
diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs
index 78a42cd84..93c624dd6 100644
--- a/ext/fetch/lib.rs
+++ b/ext/fetch/lib.rs
@@ -97,9 +97,8 @@ where
{
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_webidl", "deno_web", "deno_url", "deno_console"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/fetch",
- "01_fetch_util.js",
"20_headers.js",
"21_formdata.js",
"22_body.js",
diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js
index ce2e72370..6864fd638 100644
--- a/ext/ffi/00_ffi.js
+++ b/ext/ffi/00_ffi.js
@@ -1,510 +1,509 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const __bootstrap = window.__bootstrap;
- const {
- ArrayPrototypeMap,
- ArrayPrototypeJoin,
- ObjectDefineProperty,
- ObjectPrototypeHasOwnProperty,
- ObjectPrototypeIsPrototypeOf,
- Number,
- NumberIsSafeInteger,
- TypeError,
- Uint8Array,
- Int32Array,
- Uint32Array,
- BigInt64Array,
- BigUint64Array,
- Function,
- ReflectHas,
- PromisePrototypeThen,
- MathMax,
- MathCeil,
- SafeMap,
- SafeArrayIterator,
- } = window.__bootstrap.primordials;
-
- const U32_BUFFER = new Uint32Array(2);
- const U64_BUFFER = new BigUint64Array(U32_BUFFER.buffer);
- const I64_BUFFER = new BigInt64Array(U32_BUFFER.buffer);
- class UnsafePointerView {
- pointer;
-
- constructor(pointer) {
- this.pointer = pointer;
- }
-
- getBool(offset = 0) {
- return ops.op_ffi_read_bool(
- this.pointer,
- offset,
- );
- }
- getUint8(offset = 0) {
- return ops.op_ffi_read_u8(
- this.pointer,
- offset,
- );
- }
+const core = globalThis.Deno.core;
+const ops = core.ops;
+const internals = globalThis.__bootstrap.internals;
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeMap,
+ ArrayPrototypeJoin,
+ ObjectDefineProperty,
+ ObjectPrototypeHasOwnProperty,
+ ObjectPrototypeIsPrototypeOf,
+ Number,
+ NumberIsSafeInteger,
+ TypeError,
+ Uint8Array,
+ Int32Array,
+ Uint32Array,
+ BigInt64Array,
+ BigUint64Array,
+ Function,
+ ReflectHas,
+ PromisePrototypeThen,
+ MathMax,
+ MathCeil,
+ SafeMap,
+ SafeArrayIterator,
+} = primordials;
+
+const U32_BUFFER = new Uint32Array(2);
+const U64_BUFFER = new BigUint64Array(U32_BUFFER.buffer);
+const I64_BUFFER = new BigInt64Array(U32_BUFFER.buffer);
+class UnsafePointerView {
+ pointer;
+
+ constructor(pointer) {
+ this.pointer = pointer;
+ }
- getInt8(offset = 0) {
- return ops.op_ffi_read_i8(
- this.pointer,
- offset,
- );
- }
+ getBool(offset = 0) {
+ return ops.op_ffi_read_bool(
+ this.pointer,
+ offset,
+ );
+ }
- getUint16(offset = 0) {
- return ops.op_ffi_read_u16(
- this.pointer,
- offset,
- );
- }
+ getUint8(offset = 0) {
+ return ops.op_ffi_read_u8(
+ this.pointer,
+ offset,
+ );
+ }
- getInt16(offset = 0) {
- return ops.op_ffi_read_i16(
- this.pointer,
- offset,
- );
- }
+ getInt8(offset = 0) {
+ return ops.op_ffi_read_i8(
+ this.pointer,
+ offset,
+ );
+ }
- getUint32(offset = 0) {
- return ops.op_ffi_read_u32(
- this.pointer,
- offset,
- );
- }
+ getUint16(offset = 0) {
+ return ops.op_ffi_read_u16(
+ this.pointer,
+ offset,
+ );
+ }
- getInt32(offset = 0) {
- return ops.op_ffi_read_i32(
- this.pointer,
- offset,
- );
- }
+ getInt16(offset = 0) {
+ return ops.op_ffi_read_i16(
+ this.pointer,
+ offset,
+ );
+ }
- getBigUint64(offset = 0) {
- ops.op_ffi_read_u64(
- this.pointer,
- offset,
- U32_BUFFER,
- );
- return U64_BUFFER[0];
- }
+ getUint32(offset = 0) {
+ return ops.op_ffi_read_u32(
+ this.pointer,
+ offset,
+ );
+ }
- getBigInt64(offset = 0) {
- ops.op_ffi_read_i64(
- this.pointer,
- offset,
- U32_BUFFER,
- );
- return I64_BUFFER[0];
- }
+ getInt32(offset = 0) {
+ return ops.op_ffi_read_i32(
+ this.pointer,
+ offset,
+ );
+ }
- getFloat32(offset = 0) {
- return ops.op_ffi_read_f32(
- this.pointer,
- offset,
- );
- }
+ getBigUint64(offset = 0) {
+ ops.op_ffi_read_u64(
+ this.pointer,
+ offset,
+ U32_BUFFER,
+ );
+ return U64_BUFFER[0];
+ }
- getFloat64(offset = 0) {
- return ops.op_ffi_read_f64(
- this.pointer,
- offset,
- );
- }
+ getBigInt64(offset = 0) {
+ ops.op_ffi_read_i64(
+ this.pointer,
+ offset,
+ U32_BUFFER,
+ );
+ return I64_BUFFER[0];
+ }
- getCString(offset = 0) {
- return ops.op_ffi_cstr_read(
- this.pointer,
- offset,
- );
- }
+ getFloat32(offset = 0) {
+ return ops.op_ffi_read_f32(
+ this.pointer,
+ offset,
+ );
+ }
- static getCString(pointer, offset = 0) {
- return ops.op_ffi_cstr_read(
- pointer,
- offset,
- );
- }
+ getFloat64(offset = 0) {
+ return ops.op_ffi_read_f64(
+ this.pointer,
+ offset,
+ );
+ }
- getArrayBuffer(byteLength, offset = 0) {
- return ops.op_ffi_get_buf(
- this.pointer,
- offset,
- byteLength,
- );
- }
+ getCString(offset = 0) {
+ return ops.op_ffi_cstr_read(
+ this.pointer,
+ offset,
+ );
+ }
- static getArrayBuffer(pointer, byteLength, offset = 0) {
- return ops.op_ffi_get_buf(
- pointer,
- offset,
- byteLength,
- );
- }
+ static getCString(pointer, offset = 0) {
+ return ops.op_ffi_cstr_read(
+ pointer,
+ offset,
+ );
+ }
- copyInto(destination, offset = 0) {
- ops.op_ffi_buf_copy_into(
- this.pointer,
- offset,
- destination,
- destination.byteLength,
- );
- }
+ getArrayBuffer(byteLength, offset = 0) {
+ return ops.op_ffi_get_buf(
+ this.pointer,
+ offset,
+ byteLength,
+ );
+ }
- static copyInto(pointer, destination, offset = 0) {
- ops.op_ffi_buf_copy_into(
- pointer,
- offset,
- destination,
- destination.byteLength,
- );
- }
+ static getArrayBuffer(pointer, byteLength, offset = 0) {
+ return ops.op_ffi_get_buf(
+ pointer,
+ offset,
+ byteLength,
+ );
}
- const OUT_BUFFER = new Uint32Array(2);
- const OUT_BUFFER_64 = new BigInt64Array(OUT_BUFFER.buffer);
- class UnsafePointer {
- static of(value) {
- if (ObjectPrototypeIsPrototypeOf(UnsafeCallbackPrototype, value)) {
- return value.pointer;
- }
- ops.op_ffi_ptr_of(value, OUT_BUFFER);
- const result = OUT_BUFFER[0] + 2 ** 32 * OUT_BUFFER[1];
- if (NumberIsSafeInteger(result)) {
- return result;
- }
- return OUT_BUFFER_64[0];
- }
+ copyInto(destination, offset = 0) {
+ ops.op_ffi_buf_copy_into(
+ this.pointer,
+ offset,
+ destination,
+ destination.byteLength,
+ );
}
- class UnsafeFnPointer {
- pointer;
- definition;
- #structSize;
-
- constructor(pointer, definition) {
- this.pointer = pointer;
- this.definition = definition;
- this.#structSize = isStruct(definition.result)
- ? getTypeSizeAndAlignment(definition.result)[0]
- : null;
+ static copyInto(pointer, destination, offset = 0) {
+ ops.op_ffi_buf_copy_into(
+ pointer,
+ offset,
+ destination,
+ destination.byteLength,
+ );
+ }
+}
+
+const OUT_BUFFER = new Uint32Array(2);
+const OUT_BUFFER_64 = new BigInt64Array(OUT_BUFFER.buffer);
+class UnsafePointer {
+ static of(value) {
+ if (ObjectPrototypeIsPrototypeOf(UnsafeCallbackPrototype, value)) {
+ return value.pointer;
}
+ ops.op_ffi_ptr_of(value, OUT_BUFFER);
+ const result = OUT_BUFFER[0] + 2 ** 32 * OUT_BUFFER[1];
+ if (NumberIsSafeInteger(result)) {
+ return result;
+ }
+ return OUT_BUFFER_64[0];
+ }
+}
+
+class UnsafeFnPointer {
+ pointer;
+ definition;
+ #structSize;
+
+ constructor(pointer, definition) {
+ this.pointer = pointer;
+ this.definition = definition;
+ this.#structSize = isStruct(definition.result)
+ ? getTypeSizeAndAlignment(definition.result)[0]
+ : null;
+ }
- call(...parameters) {
- if (this.definition.nonblocking) {
- if (this.#structSize === null) {
- return core.opAsync(
- "op_ffi_call_ptr_nonblocking",
- this.pointer,
- this.definition,
- parameters,
- );
- } else {
- const buffer = new Uint8Array(this.#structSize);
- return PromisePrototypeThen(
- core.opAsync(
- "op_ffi_call_ptr_nonblocking",
- this.pointer,
- this.definition,
- parameters,
- buffer,
- ),
- () => buffer,
- );
- }
+ call(...parameters) {
+ if (this.definition.nonblocking) {
+ if (this.#structSize === null) {
+ return core.opAsync(
+ "op_ffi_call_ptr_nonblocking",
+ this.pointer,
+ this.definition,
+ parameters,
+ );
} else {
- if (this.#structSize === null) {
- return ops.op_ffi_call_ptr(
- this.pointer,
- this.definition,
- parameters,
- );
- } else {
- const buffer = new Uint8Array(this.#structSize);
- ops.op_ffi_call_ptr(
+ const buffer = new Uint8Array(this.#structSize);
+ return PromisePrototypeThen(
+ core.opAsync(
+ "op_ffi_call_ptr_nonblocking",
this.pointer,
this.definition,
parameters,
buffer,
- );
- return buffer;
- }
+ ),
+ () => buffer,
+ );
+ }
+ } else {
+ if (this.#structSize === null) {
+ return ops.op_ffi_call_ptr(
+ this.pointer,
+ this.definition,
+ parameters,
+ );
+ } else {
+ const buffer = new Uint8Array(this.#structSize);
+ ops.op_ffi_call_ptr(
+ this.pointer,
+ this.definition,
+ parameters,
+ buffer,
+ );
+ return buffer;
}
}
}
-
- function isReturnedAsBigInt(type) {
- return type === "buffer" || type === "pointer" || type === "function" ||
- type === "u64" || type === "i64" ||
- type === "usize" || type === "isize";
- }
-
- function isI64(type) {
- return type === "i64" || type === "isize";
- }
-
- function isStruct(type) {
- return typeof type === "object" && type !== null &&
- typeof type.struct === "object";
- }
-
- function getTypeSizeAndAlignment(type, cache = new SafeMap()) {
- if (isStruct(type)) {
- const cached = cache.get(type);
- if (cached !== undefined) {
- if (cached === null) {
- throw new TypeError("Recursive struct definition");
- }
- return cached;
+}
+
+function isReturnedAsBigInt(type) {
+ return type === "buffer" || type === "pointer" || type === "function" ||
+ type === "u64" || type === "i64" ||
+ type === "usize" || type === "isize";
+}
+
+function isI64(type) {
+ return type === "i64" || type === "isize";
+}
+
+function isStruct(type) {
+ return typeof type === "object" && type !== null &&
+ typeof type.struct === "object";
+}
+
+function getTypeSizeAndAlignment(type, cache = new SafeMap()) {
+ if (isStruct(type)) {
+ const cached = cache.get(type);
+ if (cached !== undefined) {
+ if (cached === null) {
+ throw new TypeError("Recursive struct definition");
}
- cache.set(type, null);
- let size = 0;
- let alignment = 1;
- for (const field of new SafeArrayIterator(type.struct)) {
- const { 0: fieldSize, 1: fieldAlign } = getTypeSizeAndAlignment(
- field,
- cache,
- );
- alignment = MathMax(alignment, fieldAlign);
- size = MathCeil(size / fieldAlign) * fieldAlign;
- size += fieldSize;
- }
- size = MathCeil(size / alignment) * alignment;
- cache.set(type, size);
- return [size, alignment];
+ return cached;
}
-
- switch (type) {
- case "bool":
- case "u8":
- case "i8":
- return [1, 1];
- case "u16":
- case "i16":
- return [2, 2];
- case "u32":
- case "i32":
- case "f32":
- return [4, 4];
- case "u64":
- case "i64":
- case "f64":
- case "pointer":
- case "buffer":
- case "function":
- case "usize":
- case "isize":
- return [8, 8];
- default:
- throw new TypeError(`Unsupported type: ${type}`);
+ cache.set(type, null);
+ let size = 0;
+ let alignment = 1;
+ for (const field of new SafeArrayIterator(type.struct)) {
+ const { 0: fieldSize, 1: fieldAlign } = getTypeSizeAndAlignment(
+ field,
+ cache,
+ );
+ alignment = MathMax(alignment, fieldAlign);
+ size = MathCeil(size / fieldAlign) * fieldAlign;
+ size += fieldSize;
}
+ size = MathCeil(size / alignment) * alignment;
+ cache.set(type, size);
+ return [size, alignment];
}
- class UnsafeCallback {
- #refcount;
- // Internal promise only meant to keep Deno from exiting
- #refpromise;
- #rid;
- definition;
- callback;
- pointer;
-
- constructor(definition, callback) {
- if (definition.nonblocking) {
- throw new TypeError(
- "Invalid UnsafeCallback, cannot be nonblocking",
- );
- }
- const { 0: rid, 1: pointer } = ops.op_ffi_unsafe_callback_create(
- definition,
- callback,
+ switch (type) {
+ case "bool":
+ case "u8":
+ case "i8":
+ return [1, 1];
+ case "u16":
+ case "i16":
+ return [2, 2];
+ case "u32":
+ case "i32":
+ case "f32":
+ return [4, 4];
+ case "u64":
+ case "i64":
+ case "f64":
+ case "pointer":
+ case "buffer":
+ case "function":
+ case "usize":
+ case "isize":
+ return [8, 8];
+ default:
+ throw new TypeError(`Unsupported type: ${type}`);
+ }
+}
+
+class UnsafeCallback {
+ #refcount;
+ // Internal promise only meant to keep Deno from exiting
+ #refpromise;
+ #rid;
+ definition;
+ callback;
+ pointer;
+
+ constructor(definition, callback) {
+ if (definition.nonblocking) {
+ throw new TypeError(
+ "Invalid UnsafeCallback, cannot be nonblocking",
);
- this.#refcount = 0;
- this.#rid = rid;
- this.pointer = pointer;
- this.definition = definition;
- this.callback = callback;
}
+ const { 0: rid, 1: pointer } = ops.op_ffi_unsafe_callback_create(
+ definition,
+ callback,
+ );
+ this.#refcount = 0;
+ this.#rid = rid;
+ this.pointer = pointer;
+ this.definition = definition;
+ this.callback = callback;
+ }
- ref() {
- if (this.#refcount++ === 0) {
- this.#refpromise = core.opAsync(
- "op_ffi_unsafe_callback_ref",
- this.#rid,
- );
- }
- return this.#refcount;
+ ref() {
+ if (this.#refcount++ === 0) {
+ this.#refpromise = core.opAsync(
+ "op_ffi_unsafe_callback_ref",
+ this.#rid,
+ );
}
+ return this.#refcount;
+ }
- unref() {
- // Only decrement refcount if it is positive, and only
- // unref the callback if refcount reaches zero.
- if (this.#refcount > 0 && --this.#refcount === 0) {
- ops.op_ffi_unsafe_callback_unref(this.#rid);
- }
- return this.#refcount;
+ unref() {
+ // Only decrement refcount if it is positive, and only
+ // unref the callback if refcount reaches zero.
+ if (this.#refcount > 0 && --this.#refcount === 0) {
+ ops.op_ffi_unsafe_callback_unref(this.#rid);
}
+ return this.#refcount;
+ }
- close() {
- this.#refcount = 0;
- core.close(this.#rid);
- }
+ close() {
+ this.#refcount = 0;
+ core.close(this.#rid);
}
+}
- const UnsafeCallbackPrototype = UnsafeCallback.prototype;
+const UnsafeCallbackPrototype = UnsafeCallback.prototype;
- class DynamicLibrary {
- #rid;
- symbols = {};
+class DynamicLibrary {
+ #rid;
+ symbols = {};
- constructor(path, symbols) {
- ({ 0: this.#rid, 1: this.symbols } = ops.op_ffi_load({ path, symbols }));
- for (const symbol in symbols) {
- if (!ObjectPrototypeHasOwnProperty(symbols, symbol)) {
- continue;
- }
+ constructor(path, symbols) {
+ ({ 0: this.#rid, 1: this.symbols } = ops.op_ffi_load({ path, symbols }));
+ for (const symbol in symbols) {
+ if (!ObjectPrototypeHasOwnProperty(symbols, symbol)) {
+ continue;
+ }
- if (ReflectHas(symbols[symbol], "type")) {
- const type = symbols[symbol].type;
- if (type === "void") {
- throw new TypeError(
- "Foreign symbol of type 'void' is not supported.",
- );
- }
-
- const name = symbols[symbol].name || symbol;
- const value = ops.op_ffi_get_static(
- this.#rid,
- name,
- type,
+ if (ReflectHas(symbols[symbol], "type")) {
+ const type = symbols[symbol].type;
+ if (type === "void") {
+ throw new TypeError(
+ "Foreign symbol of type 'void' is not supported.",
);
- ObjectDefineProperty(
- this.symbols,
- symbol,
- {
- configurable: false,
- enumerable: true,
- value,
- writable: false,
- },
- );
- continue;
}
- const resultType = symbols[symbol].result;
- const isStructResult = isStruct(resultType);
- const structSize = isStructResult
- ? getTypeSizeAndAlignment(resultType)[0]
- : 0;
- const needsUnpacking = isReturnedAsBigInt(resultType);
-
- const isNonBlocking = symbols[symbol].nonblocking;
- if (isNonBlocking) {
- ObjectDefineProperty(
- this.symbols,
- symbol,
- {
- configurable: false,
- enumerable: true,
- value: (...parameters) => {
- if (isStructResult) {
- const buffer = new Uint8Array(structSize);
- const ret = core.opAsync(
- "op_ffi_call_nonblocking",
- this.#rid,
- symbol,
- parameters,
- buffer,
- );
- return PromisePrototypeThen(
- ret,
- () => buffer,
- );
- } else {
- return core.opAsync(
- "op_ffi_call_nonblocking",
- this.#rid,
- symbol,
- parameters,
- );
- }
- },
- writable: false,
+
+ const name = symbols[symbol].name || symbol;
+ const value = ops.op_ffi_get_static(
+ this.#rid,
+ name,
+ type,
+ );
+ ObjectDefineProperty(
+ this.symbols,
+ symbol,
+ {
+ configurable: false,
+ enumerable: true,
+ value,
+ writable: false,
+ },
+ );
+ continue;
+ }
+ const resultType = symbols[symbol].result;
+ const isStructResult = isStruct(resultType);
+ const structSize = isStructResult
+ ? getTypeSizeAndAlignment(resultType)[0]
+ : 0;
+ const needsUnpacking = isReturnedAsBigInt(resultType);
+
+ const isNonBlocking = symbols[symbol].nonblocking;
+ if (isNonBlocking) {
+ ObjectDefineProperty(
+ this.symbols,
+ symbol,
+ {
+ configurable: false,
+ enumerable: true,
+ value: (...parameters) => {
+ if (isStructResult) {
+ const buffer = new Uint8Array(structSize);
+ const ret = core.opAsync(
+ "op_ffi_call_nonblocking",
+ this.#rid,
+ symbol,
+ parameters,
+ buffer,
+ );
+ return PromisePrototypeThen(
+ ret,
+ () => buffer,
+ );
+ } else {
+ return core.opAsync(
+ "op_ffi_call_nonblocking",
+ this.#rid,
+ symbol,
+ parameters,
+ );
+ }
},
- );
- }
+ writable: false,
+ },
+ );
+ }
- if (needsUnpacking && !isNonBlocking) {
- const call = this.symbols[symbol];
- const parameters = symbols[symbol].parameters;
- const vi = new Int32Array(2);
- const vui = new Uint32Array(vi.buffer);
- const b = new BigInt64Array(vi.buffer);
+ if (needsUnpacking && !isNonBlocking) {
+ const call = this.symbols[symbol];
+ const parameters = symbols[symbol].parameters;
+ const vi = new Int32Array(2);
+ const vui = new Uint32Array(vi.buffer);
+ const b = new BigInt64Array(vi.buffer);
- const params = ArrayPrototypeJoin(
- ArrayPrototypeMap(parameters, (_, index) => `p${index}`),
- ", ",
- );
- // Make sure V8 has no excuse to not optimize this function.
- this.symbols[symbol] = new Function(
- "vi",
- "vui",
- "b",
- "call",
- "NumberIsSafeInteger",
- "Number",
- `return function (${params}) {
+ const params = ArrayPrototypeJoin(
+ ArrayPrototypeMap(parameters, (_, index) => `p${index}`),
+ ", ",
+ );
+ // Make sure V8 has no excuse to not optimize this function.
+ this.symbols[symbol] = new Function(
+ "vi",
+ "vui",
+ "b",
+ "call",
+ "NumberIsSafeInteger",
+ "Number",
+ `return function (${params}) {
call(${params}${parameters.length > 0 ? ", " : ""}vi);
${
- isI64(resultType)
- ? `const n1 = Number(b[0])`
- : `const n1 = vui[0] + 2 ** 32 * vui[1]` // Faster path for u64
- };
+ isI64(resultType)
+ ? `const n1 = Number(b[0])`
+ : `const n1 = vui[0] + 2 ** 32 * vui[1]` // Faster path for u64
+ };
if (NumberIsSafeInteger(n1)) return n1;
return b[0];
}`,
- )(vi, vui, b, call, NumberIsSafeInteger, Number);
- } else if (isStructResult && !isNonBlocking) {
- const call = this.symbols[symbol];
- const parameters = symbols[symbol].parameters;
- const params = ArrayPrototypeJoin(
- ArrayPrototypeMap(parameters, (_, index) => `p${index}`),
- ", ",
- );
- this.symbols[symbol] = new Function(
- "call",
- `return function (${params}) {
+ )(vi, vui, b, call, NumberIsSafeInteger, Number);
+ } else if (isStructResult && !isNonBlocking) {
+ const call = this.symbols[symbol];
+ const parameters = symbols[symbol].parameters;
+ const params = ArrayPrototypeJoin(
+ ArrayPrototypeMap(parameters, (_, index) => `p${index}`),
+ ", ",
+ );
+ this.symbols[symbol] = new Function(
+ "call",
+ `return function (${params}) {
const buffer = new Uint8Array(${structSize});
call(${params}${parameters.length > 0 ? ", " : ""}buffer);
return buffer;
}`,
- )(call);
- }
+ )(call);
}
}
-
- close() {
- core.close(this.#rid);
- }
}
- function dlopen(path, symbols) {
- // URL support is progressively enhanced by util in `runtime/js`.
- const pathFromURL = __bootstrap.util.pathFromURL ?? ((p) => p);
- return new DynamicLibrary(pathFromURL(path), symbols);
+ close() {
+ core.close(this.#rid);
}
-
- window.__bootstrap.ffi = {
- dlopen,
- UnsafeCallback,
- UnsafePointer,
- UnsafePointerView,
- UnsafeFnPointer,
- };
-})(this);
+}
+
+function dlopen(path, symbols) {
+ // TODO(@crowlKats): remove me
+ // URL support is progressively enhanced by util in `runtime/js`.
+ const pathFromURL = internals.pathFromURL ?? ((p) => p);
+ return new DynamicLibrary(pathFromURL(path), symbols);
+}
+
+export {
+ dlopen,
+ UnsafeCallback,
+ UnsafeFnPointer,
+ UnsafePointer,
+ UnsafePointerView,
+};
diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs
index 88e788457..0034a0d33 100644
--- a/ext/ffi/lib.rs
+++ b/ext/ffi/lib.rs
@@ -84,7 +84,7 @@ pub(crate) struct FfiState {
pub fn init<P: FfiPermissions + 'static>(unstable: bool) -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/ffi",
"00_ffi.js",
))
diff --git a/ext/flash/01_http.js b/ext/flash/01_http.js
index 357bdfbe2..d2f967ada 100644
--- a/ext/flash/01_http.js
+++ b/ext/flash/01_http.js
@@ -1,611 +1,596 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const { BlobPrototype } = window.__bootstrap.file;
- const { TcpConn } = window.__bootstrap.net;
- const { fromFlashRequest, toInnerResponse, _flash } =
- window.__bootstrap.fetch;
- const core = window.Deno.core;
- const { Event } = window.__bootstrap.event;
- const {
- ReadableStream,
- ReadableStreamPrototype,
- getReadableStreamResourceBacking,
- readableStreamClose,
- _state,
- } = window.__bootstrap.streams;
- const {
- WebSocket,
- _rid,
- _readyState,
- _eventLoop,
- _protocol,
- _idleTimeoutDuration,
- _idleTimeoutTimeout,
- _serverHandleIdleTimeout,
- } = window.__bootstrap.webSocket;
- const { _ws } = window.__bootstrap.http;
- const {
- ObjectPrototypeIsPrototypeOf,
- PromisePrototype,
- PromisePrototypeCatch,
- PromisePrototypeThen,
- SafePromiseAll,
- TypedArrayPrototypeSubarray,
- TypeError,
- Uint8Array,
- Uint8ArrayPrototype,
- } = window.__bootstrap.primordials;
-
- const statusCodes = {
- 100: "Continue",
- 101: "Switching Protocols",
- 102: "Processing",
- 200: "OK",
- 201: "Created",
- 202: "Accepted",
- 203: "Non Authoritative Information",
- 204: "No Content",
- 205: "Reset Content",
- 206: "Partial Content",
- 207: "Multi-Status",
- 208: "Already Reported",
- 226: "IM Used",
- 300: "Multiple Choices",
- 301: "Moved Permanently",
- 302: "Found",
- 303: "See Other",
- 304: "Not Modified",
- 305: "Use Proxy",
- 307: "Temporary Redirect",
- 308: "Permanent Redirect",
- 400: "Bad Request",
- 401: "Unauthorized",
- 402: "Payment Required",
- 403: "Forbidden",
- 404: "Not Found",
- 405: "Method Not Allowed",
- 406: "Not Acceptable",
- 407: "Proxy Authentication Required",
- 408: "Request Timeout",
- 409: "Conflict",
- 410: "Gone",
- 411: "Length Required",
- 412: "Precondition Failed",
- 413: "Payload Too Large",
- 414: "URI Too Long",
- 415: "Unsupported Media Type",
- 416: "Range Not Satisfiable",
- 418: "I'm a teapot",
- 421: "Misdirected Request",
- 422: "Unprocessable Entity",
- 423: "Locked",
- 424: "Failed Dependency",
- 426: "Upgrade Required",
- 428: "Precondition Required",
- 429: "Too Many Requests",
- 431: "Request Header Fields Too Large",
- 451: "Unavailable For Legal Reasons",
- 500: "Internal Server Error",
- 501: "Not Implemented",
- 502: "Bad Gateway",
- 503: "Service Unavailable",
- 504: "Gateway Timeout",
- 505: "HTTP Version Not Supported",
- 506: "Variant Also Negotiates",
- 507: "Insufficient Storage",
- 508: "Loop Detected",
- 510: "Not Extended",
- 511: "Network Authentication Required",
- };
-
- const methods = {
- 0: "GET",
- 1: "HEAD",
- 2: "CONNECT",
- 3: "PUT",
- 4: "DELETE",
- 5: "OPTIONS",
- 6: "TRACE",
- 7: "POST",
- 8: "PATCH",
- };
-
- let dateInterval;
- let date;
-
- // Construct an HTTP response message.
- // All HTTP/1.1 messages consist of a start-line followed by a sequence
- // of octets.
- //
- // HTTP-message = start-line
- // *( header-field CRLF )
- // CRLF
- // [ message-body ]
+const core = globalThis.Deno.core;
+const ops = core.ops;
+const primordials = globalThis.__bootstrap.primordials;
+import { BlobPrototype } from "internal:ext/web/09_file.js";
+import { TcpConn } from "internal:ext/net/01_net.js";
+import { toInnerResponse } from "internal:ext/fetch/23_response.js";
+import { _flash, fromFlashRequest } from "internal:ext/fetch/23_request.js";
+import { Event } from "internal:ext/web/02_event.js";
+import {
+ _state,
+ getReadableStreamResourceBacking,
+ ReadableStream,
+ readableStreamClose,
+ ReadableStreamPrototype,
+} from "internal:ext/web/06_streams.js";
+import {
+ _eventLoop,
+ _idleTimeoutDuration,
+ _idleTimeoutTimeout,
+ _protocol,
+ _readyState,
+ _rid,
+ _serverHandleIdleTimeout,
+ WebSocket,
+} from "internal:ext/websocket/01_websocket.js";
+import { _ws } from "internal:ext/http/01_http.js";
+const {
+ ObjectPrototypeIsPrototypeOf,
+ PromisePrototype,
+ PromisePrototypeCatch,
+ PromisePrototypeThen,
+ SafePromiseAll,
+ TypedArrayPrototypeSubarray,
+ TypeError,
+ Uint8Array,
+ Uint8ArrayPrototype,
+} = primordials;
+
+const statusCodes = {
+ 100: "Continue",
+ 101: "Switching Protocols",
+ 102: "Processing",
+ 200: "OK",
+ 201: "Created",
+ 202: "Accepted",
+ 203: "Non Authoritative Information",
+ 204: "No Content",
+ 205: "Reset Content",
+ 206: "Partial Content",
+ 207: "Multi-Status",
+ 208: "Already Reported",
+ 226: "IM Used",
+ 300: "Multiple Choices",
+ 301: "Moved Permanently",
+ 302: "Found",
+ 303: "See Other",
+ 304: "Not Modified",
+ 305: "Use Proxy",
+ 307: "Temporary Redirect",
+ 308: "Permanent Redirect",
+ 400: "Bad Request",
+ 401: "Unauthorized",
+ 402: "Payment Required",
+ 403: "Forbidden",
+ 404: "Not Found",
+ 405: "Method Not Allowed",
+ 406: "Not Acceptable",
+ 407: "Proxy Authentication Required",
+ 408: "Request Timeout",
+ 409: "Conflict",
+ 410: "Gone",
+ 411: "Length Required",
+ 412: "Precondition Failed",
+ 413: "Payload Too Large",
+ 414: "URI Too Long",
+ 415: "Unsupported Media Type",
+ 416: "Range Not Satisfiable",
+ 418: "I'm a teapot",
+ 421: "Misdirected Request",
+ 422: "Unprocessable Entity",
+ 423: "Locked",
+ 424: "Failed Dependency",
+ 426: "Upgrade Required",
+ 428: "Precondition Required",
+ 429: "Too Many Requests",
+ 431: "Request Header Fields Too Large",
+ 451: "Unavailable For Legal Reasons",
+ 500: "Internal Server Error",
+ 501: "Not Implemented",
+ 502: "Bad Gateway",
+ 503: "Service Unavailable",
+ 504: "Gateway Timeout",
+ 505: "HTTP Version Not Supported",
+ 506: "Variant Also Negotiates",
+ 507: "Insufficient Storage",
+ 508: "Loop Detected",
+ 510: "Not Extended",
+ 511: "Network Authentication Required",
+};
+
+const methods = {
+ 0: "GET",
+ 1: "HEAD",
+ 2: "CONNECT",
+ 3: "PUT",
+ 4: "DELETE",
+ 5: "OPTIONS",
+ 6: "TRACE",
+ 7: "POST",
+ 8: "PATCH",
+};
+
+let dateInterval;
+let date;
+
+// Construct an HTTP response message.
+// All HTTP/1.1 messages consist of a start-line followed by a sequence
+// of octets.
+//
+// HTTP-message = start-line
+// *( header-field CRLF )
+// CRLF
+// [ message-body ]
+//
+function http1Response(
+ method,
+ status,
+ headerList,
+ body,
+ bodyLen,
+ earlyEnd = false,
+) {
+ // HTTP uses a "<major>.<minor>" numbering scheme
+ // HTTP-version = HTTP-name "/" DIGIT "." DIGIT
+ // HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive
//
- function http1Response(
- method,
- status,
- headerList,
- body,
- bodyLen,
- earlyEnd = false,
- ) {
- // HTTP uses a "<major>.<minor>" numbering scheme
- // HTTP-version = HTTP-name "/" DIGIT "." DIGIT
- // HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive
- //
- // status-line = HTTP-version SP status-code SP reason-phrase CRLF
- // Date header: https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.1.2
- let str = `HTTP/1.1 ${status} ${statusCodes[status]}\r\nDate: ${date}\r\n`;
- for (let i = 0; i < headerList.length; ++i) {
- const { 0: name, 1: value } = headerList[i];
- // header-field = field-name ":" OWS field-value OWS
- str += `${name}: ${value}\r\n`;
- }
-
- // https://datatracker.ietf.org/doc/html/rfc7231#section-6.3.6
- if (status === 205 || status === 304) {
- // MUST NOT generate a payload in a 205 response.
- // indicate a zero-length body for the response by
- // including a Content-Length header field with a value of 0.
- str += "Content-Length: 0\r\n\r\n";
- return str;
- }
-
- // MUST NOT send Content-Length or Transfer-Encoding if status code is 1xx or 204.
- if (status === 204 || status < 200) {
- str += "\r\n";
- return str;
- }
-
- if (earlyEnd === true) {
- return str;
- }
-
- // null body status is validated by inititalizeAResponse in ext/fetch
- if (body !== null && body !== undefined) {
- str += `Content-Length: ${bodyLen}\r\n\r\n`;
- } else {
- str += "Transfer-Encoding: chunked\r\n\r\n";
- return str;
- }
-
- // A HEAD request.
- if (method === 1) return str;
+ // status-line = HTTP-version SP status-code SP reason-phrase CRLF
+ // Date header: https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.1.2
+ let str = `HTTP/1.1 ${status} ${statusCodes[status]}\r\nDate: ${date}\r\n`;
+ for (let i = 0; i < headerList.length; ++i) {
+ const { 0: name, 1: value } = headerList[i];
+ // header-field = field-name ":" OWS field-value OWS
+ str += `${name}: ${value}\r\n`;
+ }
- if (typeof body === "string") {
- str += body ?? "";
- } else {
- const head = core.encode(str);
- const response = new Uint8Array(head.byteLength + body.byteLength);
- response.set(head, 0);
- response.set(body, head.byteLength);
- return response;
- }
+ // https://datatracker.ietf.org/doc/html/rfc7231#section-6.3.6
+ if (status === 205 || status === 304) {
+ // MUST NOT generate a payload in a 205 response.
+ // indicate a zero-length body for the response by
+ // including a Content-Length header field with a value of 0.
+ str += "Content-Length: 0\r\n\r\n";
+ return str;
+ }
+ // MUST NOT send Content-Length or Transfer-Encoding if status code is 1xx or 204.
+ if (status === 204 || status < 200) {
+ str += "\r\n";
return str;
}
- function prepareFastCalls() {
- return core.ops.op_flash_make_request();
+ if (earlyEnd === true) {
+ return str;
}
- function hostnameForDisplay(hostname) {
- // If the hostname is "0.0.0.0", we display "localhost" in console
- // because browsers in Windows don't resolve "0.0.0.0".
- // See the discussion in https://github.com/denoland/deno_std/issues/1165
- return hostname === "0.0.0.0" ? "localhost" : hostname;
+ // null body status is validated by inititalizeAResponse in ext/fetch
+ if (body !== null && body !== undefined) {
+ str += `Content-Length: ${bodyLen}\r\n\r\n`;
+ } else {
+ str += "Transfer-Encoding: chunked\r\n\r\n";
+ return str;
}
- function writeFixedResponse(
- server,
- requestId,
- response,
- responseLen,
- end,
- respondFast,
- ) {
- let nwritten = 0;
- // TypedArray
- if (typeof response !== "string") {
- nwritten = respondFast(requestId, response, end);
- } else {
- // string
- nwritten = core.ops.op_flash_respond(
- server,
- requestId,
- response,
- end,
- );
- }
+ // A HEAD request.
+ if (method === 1) return str;
+
+ if (typeof body === "string") {
+ str += body ?? "";
+ } else {
+ const head = core.encode(str);
+ const response = new Uint8Array(head.byteLength + body.byteLength);
+ response.set(head, 0);
+ response.set(body, head.byteLength);
+ return response;
+ }
- if (nwritten < responseLen) {
- core.opAsync(
- "op_flash_respond_async",
- server,
- requestId,
- response.slice(nwritten),
- end,
- );
- }
+ return str;
+}
+
+function prepareFastCalls() {
+ return ops.op_flash_make_request();
+}
+
+function hostnameForDisplay(hostname) {
+ // If the hostname is "0.0.0.0", we display "localhost" in console
+ // because browsers in Windows don't resolve "0.0.0.0".
+ // See the discussion in https://github.com/denoland/deno_std/issues/1165
+ return hostname === "0.0.0.0" ? "localhost" : hostname;
+}
+
+function writeFixedResponse(
+ server,
+ requestId,
+ response,
+ responseLen,
+ end,
+ respondFast,
+) {
+ let nwritten = 0;
+ // TypedArray
+ if (typeof response !== "string") {
+ nwritten = respondFast(requestId, response, end);
+ } else {
+ // string
+ nwritten = ops.op_flash_respond(
+ server,
+ requestId,
+ response,
+ end,
+ );
}
- // TODO(@littledivy): Woah woah, cut down the number of arguments.
- async function handleResponse(
- req,
- resp,
- body,
- hasBody,
- method,
- serverId,
- i,
- respondFast,
- respondChunked,
- tryRespondChunked,
- ) {
- // there might've been an HTTP upgrade.
- if (resp === undefined) {
- return;
- }
- const innerResp = toInnerResponse(resp);
- // If response body length is known, it will be sent synchronously in a
- // single op, in other case a "response body" resource will be created and
- // we'll be streaming it.
- /** @type {ReadableStream<Uint8Array> | Uint8Array | null} */
- let respBody = null;
- let isStreamingResponseBody = false;
- if (innerResp.body !== null) {
- if (typeof innerResp.body.streamOrStatic?.body === "string") {
- if (innerResp.body.streamOrStatic.consumed === true) {
- throw new TypeError("Body is unusable.");
- }
- innerResp.body.streamOrStatic.consumed = true;
- respBody = innerResp.body.streamOrStatic.body;
- isStreamingResponseBody = false;
- } else if (
+ if (nwritten < responseLen) {
+ core.opAsync(
+ "op_flash_respond_async",
+ server,
+ requestId,
+ response.slice(nwritten),
+ end,
+ );
+ }
+}
+
+// TODO(@littledivy): Woah woah, cut down the number of arguments.
+async function handleResponse(
+ req,
+ resp,
+ body,
+ hasBody,
+ method,
+ serverId,
+ i,
+ respondFast,
+ respondChunked,
+ tryRespondChunked,
+) {
+ // there might've been an HTTP upgrade.
+ if (resp === undefined) {
+ return;
+ }
+ const innerResp = toInnerResponse(resp);
+ // If response body length is known, it will be sent synchronously in a
+ // single op, in other case a "response body" resource will be created and
+ // we'll be streaming it.
+ /** @type {ReadableStream<Uint8Array> | Uint8Array | null} */
+ let respBody = null;
+ let isStreamingResponseBody = false;
+ if (innerResp.body !== null) {
+ if (typeof innerResp.body.streamOrStatic?.body === "string") {
+ if (innerResp.body.streamOrStatic.consumed === true) {
+ throw new TypeError("Body is unusable.");
+ }
+ innerResp.body.streamOrStatic.consumed = true;
+ respBody = innerResp.body.streamOrStatic.body;
+ isStreamingResponseBody = false;
+ } else if (
+ ObjectPrototypeIsPrototypeOf(
+ ReadableStreamPrototype,
+ innerResp.body.streamOrStatic,
+ )
+ ) {
+ if (innerResp.body.unusable()) {
+ throw new TypeError("Body is unusable.");
+ }
+ if (
+ innerResp.body.length === null ||
ObjectPrototypeIsPrototypeOf(
- ReadableStreamPrototype,
- innerResp.body.streamOrStatic,
+ BlobPrototype,
+ innerResp.body.source,
)
) {
- if (innerResp.body.unusable()) {
- throw new TypeError("Body is unusable.");
- }
- if (
- innerResp.body.length === null ||
- ObjectPrototypeIsPrototypeOf(
- BlobPrototype,
- innerResp.body.source,
- )
- ) {
- respBody = innerResp.body.stream;
- } else {
- const reader = innerResp.body.stream.getReader();
- const r1 = await reader.read();
- if (r1.done) {
- respBody = new Uint8Array(0);
- } else {
- respBody = r1.value;
- const r2 = await reader.read();
- if (!r2.done) throw new TypeError("Unreachable");
- }
- }
- isStreamingResponseBody = !(
- typeof respBody === "string" ||
- ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, respBody)
- );
+ respBody = innerResp.body.stream;
} else {
- if (innerResp.body.streamOrStatic.consumed === true) {
- throw new TypeError("Body is unusable.");
+ const reader = innerResp.body.stream.getReader();
+ const r1 = await reader.read();
+ if (r1.done) {
+ respBody = new Uint8Array(0);
+ } else {
+ respBody = r1.value;
+ const r2 = await reader.read();
+ if (!r2.done) throw new TypeError("Unreachable");
}
- innerResp.body.streamOrStatic.consumed = true;
- respBody = innerResp.body.streamOrStatic.body;
}
+ isStreamingResponseBody = !(
+ typeof respBody === "string" ||
+ ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, respBody)
+ );
} else {
- respBody = new Uint8Array(0);
+ if (innerResp.body.streamOrStatic.consumed === true) {
+ throw new TypeError("Body is unusable.");
+ }
+ innerResp.body.streamOrStatic.consumed = true;
+ respBody = innerResp.body.streamOrStatic.body;
}
+ } else {
+ respBody = new Uint8Array(0);
+ }
- const ws = resp[_ws];
- if (isStreamingResponseBody === false) {
- const length = respBody.byteLength || core.byteLength(respBody);
- const responseStr = http1Response(
- method,
- innerResp.status ?? 200,
- innerResp.headerList,
- respBody,
- length,
- );
- writeFixedResponse(
- serverId,
- i,
- responseStr,
- length,
- !ws, // Don't close socket if there is a deferred websocket upgrade.
- respondFast,
- );
- }
+ const ws = resp[_ws];
+ if (isStreamingResponseBody === false) {
+ const length = respBody.byteLength || core.byteLength(respBody);
+ const responseStr = http1Response(
+ method,
+ innerResp.status ?? 200,
+ innerResp.headerList,
+ respBody,
+ length,
+ );
+ writeFixedResponse(
+ serverId,
+ i,
+ responseStr,
+ length,
+ !ws, // Don't close socket if there is a deferred websocket upgrade.
+ respondFast,
+ );
+ }
- return (async () => {
- if (!ws) {
- if (hasBody && body[_state] !== "closed") {
- // TODO(@littledivy): Optimize by draining in a single op.
- try {
- await req.arrayBuffer();
- } catch { /* pass */ }
- }
+ return (async () => {
+ if (!ws) {
+ if (hasBody && body[_state] !== "closed") {
+ // TODO(@littledivy): Optimize by draining in a single op.
+ try {
+ await req.arrayBuffer();
+ } catch { /* pass */ }
}
+ }
- if (isStreamingResponseBody === true) {
- const resourceBacking = getReadableStreamResourceBacking(respBody);
- if (resourceBacking) {
- if (respBody.locked) {
- throw new TypeError("ReadableStream is locked.");
- }
- const reader = respBody.getReader(); // Aquire JS lock.
- try {
- PromisePrototypeThen(
- core.opAsync(
- "op_flash_write_resource",
- http1Response(
- method,
- innerResp.status ?? 200,
- innerResp.headerList,
- 0, // Content-Length will be set by the op.
- null,
- true,
- ),
- serverId,
- i,
- resourceBacking.rid,
- resourceBacking.autoClose,
+ if (isStreamingResponseBody === true) {
+ const resourceBacking = getReadableStreamResourceBacking(respBody);
+ if (resourceBacking) {
+ if (respBody.locked) {
+ throw new TypeError("ReadableStream is locked.");
+ }
+ const reader = respBody.getReader(); // Aquire JS lock.
+ try {
+ PromisePrototypeThen(
+ core.opAsync(
+ "op_flash_write_resource",
+ http1Response(
+ method,
+ innerResp.status ?? 200,
+ innerResp.headerList,
+ 0, // Content-Length will be set by the op.
+ null,
+ true,
),
- () => {
- // Release JS lock.
- readableStreamClose(respBody);
- },
- );
- } catch (error) {
- await reader.cancel(error);
- throw error;
- }
- } else {
- const reader = respBody.getReader();
-
- // Best case: sends headers + first chunk in a single go.
- const { value, done } = await reader.read();
- writeFixedResponse(
- serverId,
- i,
- http1Response(
- method,
- innerResp.status ?? 200,
- innerResp.headerList,
- respBody.byteLength,
- null,
+ serverId,
+ i,
+ resourceBacking.rid,
+ resourceBacking.autoClose,
),
- respBody.byteLength,
- false,
- respondFast,
+ () => {
+ // Release JS lock.
+ readableStreamClose(respBody);
+ },
);
-
- await tryRespondChunked(
- i,
- value,
- done,
- );
-
- if (!done) {
- while (true) {
- const chunk = await reader.read();
- await respondChunked(
- i,
- chunk.value,
- chunk.done,
- );
- if (chunk.done) break;
- }
- }
+ } catch (error) {
+ await reader.cancel(error);
+ throw error;
}
- }
+ } else {
+ const reader = respBody.getReader();
- if (ws) {
- const wsRid = await core.opAsync(
- "op_flash_upgrade_websocket",
+ // Best case: sends headers + first chunk in a single go.
+ const { value, done } = await reader.read();
+ writeFixedResponse(
serverId,
i,
+ http1Response(
+ method,
+ innerResp.status ?? 200,
+ innerResp.headerList,
+ respBody.byteLength,
+ null,
+ ),
+ respBody.byteLength,
+ false,
+ respondFast,
+ );
+
+ await tryRespondChunked(
+ i,
+ value,
+ done,
);
- ws[_rid] = wsRid;
- ws[_protocol] = resp.headers.get("sec-websocket-protocol");
-
- ws[_readyState] = WebSocket.OPEN;
- const event = new Event("open");
- ws.dispatchEvent(event);
-
- ws[_eventLoop]();
- if (ws[_idleTimeoutDuration]) {
- ws.addEventListener(
- "close",
- () => clearTimeout(ws[_idleTimeoutTimeout]),
- );
- }
- ws[_serverHandleIdleTimeout]();
- }
- })();
- }
- function createServe(opFn) {
- return async function serve(arg1, arg2) {
- let options = undefined;
- let handler = undefined;
- if (typeof arg1 === "function") {
- handler = arg1;
- options = arg2;
- } else if (typeof arg2 === "function") {
- handler = arg2;
- options = arg1;
- } else {
- options = arg1;
- }
- if (handler === undefined) {
- if (options === undefined) {
- throw new TypeError(
- "No handler was provided, so an options bag is mandatory.",
- );
+ if (!done) {
+ while (true) {
+ const chunk = await reader.read();
+ await respondChunked(
+ i,
+ chunk.value,
+ chunk.done,
+ );
+ if (chunk.done) break;
+ }
}
- handler = options.handler;
}
- if (typeof handler !== "function") {
- throw new TypeError("A handler function must be provided.");
+ }
+
+ if (ws) {
+ const wsRid = await core.opAsync(
+ "op_flash_upgrade_websocket",
+ serverId,
+ i,
+ );
+ ws[_rid] = wsRid;
+ ws[_protocol] = resp.headers.get("sec-websocket-protocol");
+
+ ws[_readyState] = WebSocket.OPEN;
+ const event = new Event("open");
+ ws.dispatchEvent(event);
+
+ ws[_eventLoop]();
+ if (ws[_idleTimeoutDuration]) {
+ ws.addEventListener(
+ "close",
+ () => clearTimeout(ws[_idleTimeoutTimeout]),
+ );
}
+ ws[_serverHandleIdleTimeout]();
+ }
+ })();
+}
+
+function createServe(opFn) {
+ return async function serve(arg1, arg2) {
+ let options = undefined;
+ let handler = undefined;
+ if (typeof arg1 === "function") {
+ handler = arg1;
+ options = arg2;
+ } else if (typeof arg2 === "function") {
+ handler = arg2;
+ options = arg1;
+ } else {
+ options = arg1;
+ }
+ if (handler === undefined) {
if (options === undefined) {
- options = {};
+ throw new TypeError(
+ "No handler was provided, so an options bag is mandatory.",
+ );
}
+ handler = options.handler;
+ }
+ if (typeof handler !== "function") {
+ throw new TypeError("A handler function must be provided.");
+ }
+ if (options === undefined) {
+ options = {};
+ }
- const signal = options.signal;
+ const signal = options.signal;
- const onError = options.onError ?? function (error) {
- console.error(error);
- return new Response("Internal Server Error", { status: 500 });
- };
+ const onError = options.onError ?? function (error) {
+ console.error(error);
+ return new Response("Internal Server Error", { status: 500 });
+ };
- const onListen = options.onListen ?? function ({ port }) {
- console.log(
- `Listening on http://${
- hostnameForDisplay(listenOpts.hostname)
- }:${port}/`,
+ const onListen = options.onListen ?? function ({ port }) {
+ console.log(
+ `Listening on http://${
+ hostnameForDisplay(listenOpts.hostname)
+ }:${port}/`,
+ );
+ };
+
+ const listenOpts = {
+ hostname: options.hostname ?? "127.0.0.1",
+ port: options.port ?? 9000,
+ reuseport: options.reusePort ?? false,
+ };
+ if (options.cert || options.key) {
+ if (!options.cert || !options.key) {
+ throw new TypeError(
+ "Both cert and key must be provided to enable HTTPS.",
);
- };
-
- const listenOpts = {
- hostname: options.hostname ?? "127.0.0.1",
- port: options.port ?? 9000,
- reuseport: options.reusePort ?? false,
- };
- if (options.cert || options.key) {
- if (!options.cert || !options.key) {
- throw new TypeError(
- "Both cert and key must be provided to enable HTTPS.",
- );
- }
- listenOpts.cert = options.cert;
- listenOpts.key = options.key;
}
+ listenOpts.cert = options.cert;
+ listenOpts.key = options.key;
+ }
- const serverId = opFn(listenOpts);
- const serverPromise = core.opAsync("op_flash_drive_server", serverId);
-
- PromisePrototypeCatch(
- PromisePrototypeThen(
- core.opAsync("op_flash_wait_for_listening", serverId),
- (port) => {
- onListen({ hostname: listenOpts.hostname, port });
- },
- ),
- () => {},
- );
- const finishedPromise = PromisePrototypeCatch(serverPromise, () => {});
-
- const server = {
- id: serverId,
- transport: listenOpts.cert && listenOpts.key ? "https" : "http",
- hostname: listenOpts.hostname,
- port: listenOpts.port,
- closed: false,
- finished: finishedPromise,
- async close() {
+ const serverId = opFn(listenOpts);
+ const serverPromise = core.opAsync("op_flash_drive_server", serverId);
+
+ PromisePrototypeCatch(
+ PromisePrototypeThen(
+ core.opAsync("op_flash_wait_for_listening", serverId),
+ (port) => {
+ onListen({ hostname: listenOpts.hostname, port });
+ },
+ ),
+ () => {},
+ );
+ const finishedPromise = PromisePrototypeCatch(serverPromise, () => {});
+
+ const server = {
+ id: serverId,
+ transport: listenOpts.cert && listenOpts.key ? "https" : "http",
+ hostname: listenOpts.hostname,
+ port: listenOpts.port,
+ closed: false,
+ finished: finishedPromise,
+ async close() {
+ if (server.closed) {
+ return;
+ }
+ server.closed = true;
+ await core.opAsync("op_flash_close_server", serverId);
+ await server.finished;
+ },
+ async serve() {
+ let offset = 0;
+ while (true) {
if (server.closed) {
- return;
+ break;
}
- server.closed = true;
- await core.opAsync("op_flash_close_server", serverId);
- await server.finished;
- },
- async serve() {
- let offset = 0;
- while (true) {
+
+ let tokens = nextRequestSync();
+ if (tokens === 0) {
+ tokens = await core.opAsync("op_flash_next_async", serverId);
if (server.closed) {
break;
}
+ }
- let tokens = nextRequestSync();
- if (tokens === 0) {
- tokens = await core.opAsync("op_flash_next_async", serverId);
- if (server.closed) {
- break;
+ for (let i = offset; i < offset + tokens; i++) {
+ let body = null;
+ // There might be a body, but we don't expose it for GET/HEAD requests.
+ // It will be closed automatically once the request has been handled and
+ // the response has been sent.
+ const method = getMethodSync(i);
+ let hasBody = method > 2; // Not GET/HEAD/CONNECT
+ if (hasBody) {
+ body = createRequestBodyStream(serverId, i);
+ if (body === null) {
+ hasBody = false;
}
}
- for (let i = offset; i < offset + tokens; i++) {
- let body = null;
- // There might be a body, but we don't expose it for GET/HEAD requests.
- // It will be closed automatically once the request has been handled and
- // the response has been sent.
- const method = getMethodSync(i);
- let hasBody = method > 2; // Not GET/HEAD/CONNECT
- if (hasBody) {
- body = createRequestBodyStream(serverId, i);
- if (body === null) {
- hasBody = false;
- }
- }
+ const req = fromFlashRequest(
+ serverId,
+ /* streamRid */
+ i,
+ body,
+ /* methodCb */
+ () => methods[method],
+ /* urlCb */
+ () => {
+ const path = ops.op_flash_path(serverId, i);
+ return `${server.transport}://${server.hostname}:${server.port}${path}`;
+ },
+ /* headersCb */
+ () => ops.op_flash_headers(serverId, i),
+ );
- const req = fromFlashRequest(
- serverId,
- /* streamRid */
- i,
- body,
- /* methodCb */
- () => methods[method],
- /* urlCb */
- () => {
- const path = core.ops.op_flash_path(serverId, i);
- return `${server.transport}://${server.hostname}:${server.port}${path}`;
- },
- /* headersCb */
- () => core.ops.op_flash_headers(serverId, i),
- );
-
- let resp;
- try {
- resp = handler(req);
- if (ObjectPrototypeIsPrototypeOf(PromisePrototype, resp)) {
- PromisePrototypeCatch(
- PromisePrototypeThen(
- resp,
- (resp) =>
- handleResponse(
- req,
- resp,
- body,
- hasBody,
- method,
- serverId,
- i,
- respondFast,
- respondChunked,
- tryRespondChunked,
- ),
- ),
- onError,
- );
- } else if (typeof resp?.then === "function") {
- resp.then((resp) =>
- handleResponse(
- req,
- resp,
- body,
- hasBody,
- method,
- serverId,
- i,
- respondFast,
- respondChunked,
- tryRespondChunked,
- )
- ).catch(onError);
- } else {
+ let resp;
+ try {
+ resp = handler(req);
+ if (ObjectPrototypeIsPrototypeOf(PromisePrototype, resp)) {
+ PromisePrototypeCatch(
+ PromisePrototypeThen(
+ resp,
+ (resp) =>
+ handleResponse(
+ req,
+ resp,
+ body,
+ hasBody,
+ method,
+ serverId,
+ i,
+ respondFast,
+ respondChunked,
+ tryRespondChunked,
+ ),
+ ),
+ onError,
+ );
+ } else if (typeof resp?.then === "function") {
+ resp.then((resp) =>
handleResponse(
req,
resp,
@@ -617,147 +602,157 @@
respondFast,
respondChunked,
tryRespondChunked,
- ).catch(onError);
- }
- } catch (e) {
- resp = await onError(e);
+ )
+ ).catch(onError);
+ } else {
+ handleResponse(
+ req,
+ resp,
+ body,
+ hasBody,
+ method,
+ serverId,
+ i,
+ respondFast,
+ respondChunked,
+ tryRespondChunked,
+ ).catch(onError);
}
+ } catch (e) {
+ resp = await onError(e);
}
-
- offset += tokens;
}
- await server.finished;
- },
- };
-
- signal?.addEventListener("abort", () => {
- clearInterval(dateInterval);
- PromisePrototypeThen(server.close(), () => {}, () => {});
- }, {
- once: true,
- });
- function tryRespondChunked(token, chunk, shutdown) {
- const nwritten = core.ops.op_try_flash_respond_chunked(
- serverId,
- token,
- chunk ?? new Uint8Array(),
- shutdown,
- );
- if (nwritten > 0) {
- return core.opAsync(
- "op_flash_respond_chunked",
- serverId,
- token,
- chunk,
- shutdown,
- nwritten,
- );
+ offset += tokens;
}
- }
+ await server.finished;
+ },
+ };
- function respondChunked(token, chunk, shutdown) {
+ signal?.addEventListener("abort", () => {
+ clearInterval(dateInterval);
+ PromisePrototypeThen(server.close(), () => {}, () => {});
+ }, {
+ once: true,
+ });
+
+ function tryRespondChunked(token, chunk, shutdown) {
+ const nwritten = ops.op_try_flash_respond_chunked(
+ serverId,
+ token,
+ chunk ?? new Uint8Array(),
+ shutdown,
+ );
+ if (nwritten > 0) {
return core.opAsync(
"op_flash_respond_chunked",
serverId,
token,
chunk,
shutdown,
+ nwritten,
);
}
+ }
- const fastOp = prepareFastCalls();
- let nextRequestSync = () => fastOp.nextRequest();
- let getMethodSync = (token) => fastOp.getMethod(token);
- let respondFast = (token, response, shutdown) =>
- fastOp.respond(token, response, shutdown);
- if (serverId > 0) {
- nextRequestSync = () => core.ops.op_flash_next_server(serverId);
- getMethodSync = (token) => core.ops.op_flash_method(serverId, token);
- respondFast = (token, response, shutdown) =>
- core.ops.op_flash_respond(serverId, token, response, null, shutdown);
- }
+ function respondChunked(token, chunk, shutdown) {
+ return core.opAsync(
+ "op_flash_respond_chunked",
+ serverId,
+ token,
+ chunk,
+ shutdown,
+ );
+ }
- if (!dateInterval) {
- date = new Date().toUTCString();
- dateInterval = setInterval(() => {
- date = new Date().toUTCString();
- }, 1000);
- }
+ const fastOp = prepareFastCalls();
+ let nextRequestSync = () => fastOp.nextRequest();
+ let getMethodSync = (token) => fastOp.getMethod(token);
+ let respondFast = (token, response, shutdown) =>
+ fastOp.respond(token, response, shutdown);
+ if (serverId > 0) {
+ nextRequestSync = () => ops.op_flash_next_server(serverId);
+ getMethodSync = (token) => ops.op_flash_method(serverId, token);
+ respondFast = (token, response, shutdown) =>
+ ops.op_flash_respond(serverId, token, response, null, shutdown);
+ }
- await SafePromiseAll([
- PromisePrototypeCatch(server.serve(), console.error),
- serverPromise,
- ]);
- };
- }
+ if (!dateInterval) {
+ date = new Date().toUTCString();
+ dateInterval = setInterval(() => {
+ date = new Date().toUTCString();
+ }, 1000);
+ }
- function createRequestBodyStream(serverId, token) {
- // The first packet is left over bytes after parsing the request
- const firstRead = core.ops.op_flash_first_packet(
- serverId,
- token,
- );
- if (!firstRead) return null;
- let firstEnqueued = firstRead.byteLength == 0;
+ await SafePromiseAll([
+ PromisePrototypeCatch(server.serve(), console.error),
+ serverPromise,
+ ]);
+ };
+}
- return new ReadableStream({
- type: "bytes",
- async pull(controller) {
- try {
- if (firstEnqueued === false) {
- controller.enqueue(firstRead);
- firstEnqueued = true;
- return;
- }
- // This is the largest possible size for a single packet on a TLS
- // stream.
- const chunk = new Uint8Array(16 * 1024 + 256);
- const read = await core.opAsync(
- "op_flash_read_body",
- serverId,
- token,
- chunk,
- );
- if (read > 0) {
- // We read some data. Enqueue it onto the stream.
- controller.enqueue(TypedArrayPrototypeSubarray(chunk, 0, read));
- } else {
- // We have reached the end of the body, so we close the stream.
- controller.close();
- }
- } catch (err) {
- // There was an error while reading a chunk of the body, so we
- // error.
- controller.error(err);
+function createRequestBodyStream(serverId, token) {
+ // The first packet is left over bytes after parsing the request
+ const firstRead = ops.op_flash_first_packet(
+ serverId,
+ token,
+ );
+ if (!firstRead) return null;
+ let firstEnqueued = firstRead.byteLength == 0;
+
+ return new ReadableStream({
+ type: "bytes",
+ async pull(controller) {
+ try {
+ if (firstEnqueued === false) {
+ controller.enqueue(firstRead);
+ firstEnqueued = true;
+ return;
+ }
+ // This is the largest possible size for a single packet on a TLS
+ // stream.
+ const chunk = new Uint8Array(16 * 1024 + 256);
+ const read = await core.opAsync(
+ "op_flash_read_body",
+ serverId,
+ token,
+ chunk,
+ );
+ if (read > 0) {
+ // We read some data. Enqueue it onto the stream.
+ controller.enqueue(TypedArrayPrototypeSubarray(chunk, 0, read));
+ } else {
+ // We have reached the end of the body, so we close the stream.
controller.close();
}
- },
- });
+ } catch (err) {
+ // There was an error while reading a chunk of the body, so we
+ // error.
+ controller.error(err);
+ controller.close();
+ }
+ },
+ });
+}
+
+function upgradeHttpRaw(req) {
+ if (!req[_flash]) {
+ throw new TypeError(
+ "Non-flash requests can not be upgraded with `upgradeHttpRaw`. Use `upgradeHttp` instead.",
+ );
}
- function upgradeHttpRaw(req) {
- if (!req[_flash]) {
- throw new TypeError(
- "Non-flash requests can not be upgraded with `upgradeHttpRaw`. Use `upgradeHttp` instead.",
- );
- }
+ // NOTE(bartlomieju):
+ // Access these fields so they are cached on `req` object, otherwise
+ // they wouldn't be available after the connection gets upgraded.
+ req.url;
+ req.method;
+ req.headers;
- // NOTE(bartlomieju):
- // Access these fields so they are cached on `req` object, otherwise
- // they wouldn't be available after the connection gets upgraded.
- req.url;
- req.method;
- req.headers;
-
- const { serverId, streamRid } = req[_flash];
- const connRid = core.ops.op_flash_upgrade_http(streamRid, serverId);
- // TODO(@littledivy): return already read first packet too.
- return [new TcpConn(connRid), new Uint8Array()];
- }
+ const { serverId, streamRid } = req[_flash];
+ const connRid = ops.op_flash_upgrade_http(streamRid, serverId);
+ // TODO(@littledivy): return already read first packet too.
+ return [new TcpConn(connRid), new Uint8Array()];
+}
- window.__bootstrap.flash = {
- createServe,
- upgradeHttpRaw,
- };
-})(this);
+export { createServe, upgradeHttpRaw };
diff --git a/ext/flash/lib.rs b/ext/flash/lib.rs
index d31e78caa..ab048c9cd 100644
--- a/ext/flash/lib.rs
+++ b/ext/flash/lib.rs
@@ -1514,7 +1514,7 @@ pub fn init<P: FlashPermissions + 'static>(unstable: bool) -> Extension {
"deno_websocket",
"deno_http",
])
- .js(deno_core::include_js_files!(
+ .esm(deno_core::include_js_files!(
prefix "internal:ext/flash",
"01_http.js",
))
diff --git a/ext/http/01_http.js b/ext/http/01_http.js
index cb98d246d..7ce5f9172 100644
--- a/ext/http/01_http.js
+++ b/ext/http/01_http.js
@@ -1,296 +1,318 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const webidl = window.__bootstrap.webidl;
- const { InnerBody } = window.__bootstrap.fetchBody;
- const { Event } = window.__bootstrap.event;
- const { setEventTargetData } = window.__bootstrap.eventTarget;
- const { BlobPrototype } = window.__bootstrap.file;
- const {
- ResponsePrototype,
- fromInnerRequest,
- toInnerResponse,
- newInnerRequest,
- newInnerResponse,
- fromInnerResponse,
- _flash,
- } = window.__bootstrap.fetch;
- const core = window.Deno.core;
- const { BadResourcePrototype, InterruptedPrototype, ops } = core;
- const { ReadableStreamPrototype } = window.__bootstrap.streams;
- const abortSignal = window.__bootstrap.abortSignal;
- const {
- WebSocket,
- _rid,
- _readyState,
- _eventLoop,
- _protocol,
- _server,
- _idleTimeoutDuration,
- _idleTimeoutTimeout,
- _serverHandleIdleTimeout,
- } = window.__bootstrap.webSocket;
- const { TcpConn, UnixConn } = window.__bootstrap.net;
- const { TlsConn } = window.__bootstrap.tls;
- const {
- Deferred,
- getReadableStreamResourceBacking,
- readableStreamForRid,
- readableStreamClose,
- } = window.__bootstrap.streams;
- const {
- ArrayPrototypeIncludes,
- ArrayPrototypePush,
- ArrayPrototypeSome,
- Error,
- ObjectPrototypeIsPrototypeOf,
- SafeSetIterator,
- Set,
- SetPrototypeAdd,
- SetPrototypeDelete,
- StringPrototypeIncludes,
- StringPrototypeToLowerCase,
- StringPrototypeSplit,
- Symbol,
- SymbolAsyncIterator,
- TypeError,
- Uint8Array,
- Uint8ArrayPrototype,
- } = window.__bootstrap.primordials;
-
- const connErrorSymbol = Symbol("connError");
- const _deferred = Symbol("upgradeHttpDeferred");
-
- class HttpConn {
- #rid = 0;
- #closed = false;
- #remoteAddr;
- #localAddr;
-
- // This set holds resource ids of resources
- // that were created during lifecycle of this request.
- // When the connection is closed these resources should be closed
- // as well.
- managedResources = new Set();
-
- constructor(rid, remoteAddr, localAddr) {
- this.#rid = rid;
- this.#remoteAddr = remoteAddr;
- this.#localAddr = localAddr;
- }
-
- /** @returns {number} */
- get rid() {
- return this.#rid;
- }
+const core = globalThis.Deno.core;
+const primordials = globalThis.__bootstrap.primordials;
+const { BadResourcePrototype, InterruptedPrototype, ops } = core;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { InnerBody } from "internal:ext/fetch/22_body.js";
+import { Event, setEventTargetData } from "internal:ext/web/02_event.js";
+import { BlobPrototype } from "internal:ext/web/09_file.js";
+import {
+ fromInnerResponse,
+ newInnerResponse,
+ ResponsePrototype,
+ toInnerResponse,
+} from "internal:ext/fetch/23_response.js";
+import {
+ _flash,
+ fromInnerRequest,
+ newInnerRequest,
+} from "internal:ext/fetch/23_request.js";
+import * as abortSignal from "internal:ext/web/03_abort_signal.js";
+import {
+ _eventLoop,
+ _idleTimeoutDuration,
+ _idleTimeoutTimeout,
+ _protocol,
+ _readyState,
+ _rid,
+ _server,
+ _serverHandleIdleTimeout,
+ WebSocket,
+} from "internal:ext/websocket/01_websocket.js";
+import { TcpConn, UnixConn } from "internal:ext/net/01_net.js";
+import { TlsConn } from "internal:ext/net/02_tls.js";
+import {
+ Deferred,
+ getReadableStreamResourceBacking,
+ readableStreamClose,
+ readableStreamForRid,
+ ReadableStreamPrototype,
+} from "internal:ext/web/06_streams.js";
+const {
+ ArrayPrototypeIncludes,
+ ArrayPrototypePush,
+ ArrayPrototypeSome,
+ Error,
+ ObjectPrototypeIsPrototypeOf,
+ SafeSetIterator,
+ Set,
+ SetPrototypeAdd,
+ SetPrototypeDelete,
+ StringPrototypeIncludes,
+ StringPrototypeToLowerCase,
+ StringPrototypeSplit,
+ Symbol,
+ SymbolAsyncIterator,
+ TypeError,
+ Uint8Array,
+ Uint8ArrayPrototype,
+} = primordials;
+
+const connErrorSymbol = Symbol("connError");
+const _deferred = Symbol("upgradeHttpDeferred");
+
+class HttpConn {
+ #rid = 0;
+ #closed = false;
+ #remoteAddr;
+ #localAddr;
+
+ // This set holds resource ids of resources
+ // that were created during lifecycle of this request.
+ // When the connection is closed these resources should be closed
+ // as well.
+ managedResources = new Set();
+
+ constructor(rid, remoteAddr, localAddr) {
+ this.#rid = rid;
+ this.#remoteAddr = remoteAddr;
+ this.#localAddr = localAddr;
+ }
- /** @returns {Promise<RequestEvent | null>} */
- async nextRequest() {
- let nextRequest;
- try {
- nextRequest = await core.opAsync("op_http_accept", this.#rid);
- } catch (error) {
- this.close();
- // A connection error seen here would cause disrupted responses to throw
- // a generic `BadResource` error. Instead store this error and replace
- // those with it.
- this[connErrorSymbol] = error;
- if (
- ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error) ||
- ObjectPrototypeIsPrototypeOf(InterruptedPrototype, error) ||
- StringPrototypeIncludes(error.message, "connection closed")
- ) {
- return null;
- }
- throw error;
- }
- if (nextRequest == null) {
- // Work-around for servers (deno_std/http in particular) that call
- // `nextRequest()` before upgrading a previous request which has a
- // `connection: upgrade` header.
- await null;
+ /** @returns {number} */
+ get rid() {
+ return this.#rid;
+ }
- this.close();
+ /** @returns {Promise<RequestEvent | null>} */
+ async nextRequest() {
+ let nextRequest;
+ try {
+ nextRequest = await core.opAsync("op_http_accept", this.#rid);
+ } catch (error) {
+ this.close();
+ // A connection error seen here would cause disrupted responses to throw
+ // a generic `BadResource` error. Instead store this error and replace
+ // those with it.
+ this[connErrorSymbol] = error;
+ if (
+ ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error) ||
+ ObjectPrototypeIsPrototypeOf(InterruptedPrototype, error) ||
+ StringPrototypeIncludes(error.message, "connection closed")
+ ) {
return null;
}
+ throw error;
+ }
+ if (nextRequest == null) {
+ // Work-around for servers (deno_std/http in particular) that call
+ // `nextRequest()` before upgrading a previous request which has a
+ // `connection: upgrade` header.
+ await null;
+
+ this.close();
+ return null;
+ }
- const { 0: streamRid, 1: method, 2: url } = nextRequest;
- SetPrototypeAdd(this.managedResources, streamRid);
-
- /** @type {ReadableStream<Uint8Array> | undefined} */
- let body = null;
- // There might be a body, but we don't expose it for GET/HEAD requests.
- // It will be closed automatically once the request has been handled and
- // the response has been sent.
- if (method !== "GET" && method !== "HEAD") {
- body = readableStreamForRid(streamRid, false);
- }
-
- const innerRequest = newInnerRequest(
- () => method,
- url,
- () => ops.op_http_headers(streamRid),
- body !== null ? new InnerBody(body) : null,
- false,
- );
- const signal = abortSignal.newSignal();
- const request = fromInnerRequest(
- innerRequest,
- signal,
- "immutable",
- false,
- );
-
- const respondWith = createRespondWith(
- this,
- streamRid,
- request,
- this.#remoteAddr,
- this.#localAddr,
- );
+ const { 0: streamRid, 1: method, 2: url } = nextRequest;
+ SetPrototypeAdd(this.managedResources, streamRid);
- return { request, respondWith };
+ /** @type {ReadableStream<Uint8Array> | undefined} */
+ let body = null;
+ // There might be a body, but we don't expose it for GET/HEAD requests.
+ // It will be closed automatically once the request has been handled and
+ // the response has been sent.
+ if (method !== "GET" && method !== "HEAD") {
+ body = readableStreamForRid(streamRid, false);
}
- /** @returns {void} */
- close() {
- if (!this.#closed) {
- this.#closed = true;
- core.close(this.#rid);
- for (const rid of new SafeSetIterator(this.managedResources)) {
- SetPrototypeDelete(this.managedResources, rid);
- core.close(rid);
- }
- }
- }
+ const innerRequest = newInnerRequest(
+ () => method,
+ url,
+ () => ops.op_http_headers(streamRid),
+ body !== null ? new InnerBody(body) : null,
+ false,
+ );
+ const signal = abortSignal.newSignal();
+ const request = fromInnerRequest(
+ innerRequest,
+ signal,
+ "immutable",
+ false,
+ );
+
+ const respondWith = createRespondWith(
+ this,
+ streamRid,
+ request,
+ this.#remoteAddr,
+ this.#localAddr,
+ );
+
+ return { request, respondWith };
+ }
- [SymbolAsyncIterator]() {
- // deno-lint-ignore no-this-alias
- const httpConn = this;
- return {
- async next() {
- const reqEvt = await httpConn.nextRequest();
- // Change with caution, current form avoids a v8 deopt
- return { value: reqEvt ?? undefined, done: reqEvt === null };
- },
- };
+ /** @returns {void} */
+ close() {
+ if (!this.#closed) {
+ this.#closed = true;
+ core.close(this.#rid);
+ for (const rid of new SafeSetIterator(this.managedResources)) {
+ SetPrototypeDelete(this.managedResources, rid);
+ core.close(rid);
+ }
}
}
- function createRespondWith(
- httpConn,
- streamRid,
- request,
- remoteAddr,
- localAddr,
- ) {
- return async function respondWith(resp) {
- try {
- resp = await resp;
- if (!(ObjectPrototypeIsPrototypeOf(ResponsePrototype, resp))) {
- throw new TypeError(
- "First argument to respondWith must be a Response or a promise resolving to a Response.",
- );
- }
+ [SymbolAsyncIterator]() {
+ // deno-lint-ignore no-this-alias
+ const httpConn = this;
+ return {
+ async next() {
+ const reqEvt = await httpConn.nextRequest();
+ // Change with caution, current form avoids a v8 deopt
+ return { value: reqEvt ?? undefined, done: reqEvt === null };
+ },
+ };
+ }
+}
+
+function createRespondWith(
+ httpConn,
+ streamRid,
+ request,
+ remoteAddr,
+ localAddr,
+) {
+ return async function respondWith(resp) {
+ try {
+ resp = await resp;
+ if (!(ObjectPrototypeIsPrototypeOf(ResponsePrototype, resp))) {
+ throw new TypeError(
+ "First argument to respondWith must be a Response or a promise resolving to a Response.",
+ );
+ }
- const innerResp = toInnerResponse(resp);
+ const innerResp = toInnerResponse(resp);
- // If response body length is known, it will be sent synchronously in a
- // single op, in other case a "response body" resource will be created and
- // we'll be streaming it.
- /** @type {ReadableStream<Uint8Array> | Uint8Array | null} */
- let respBody = null;
- if (innerResp.body !== null) {
- if (innerResp.body.unusable()) {
- throw new TypeError("Body is unusable.");
- }
+ // If response body length is known, it will be sent synchronously in a
+ // single op, in other case a "response body" resource will be created and
+ // we'll be streaming it.
+ /** @type {ReadableStream<Uint8Array> | Uint8Array | null} */
+ let respBody = null;
+ if (innerResp.body !== null) {
+ if (innerResp.body.unusable()) {
+ throw new TypeError("Body is unusable.");
+ }
+ if (
+ ObjectPrototypeIsPrototypeOf(
+ ReadableStreamPrototype,
+ innerResp.body.streamOrStatic,
+ )
+ ) {
if (
+ innerResp.body.length === null ||
ObjectPrototypeIsPrototypeOf(
- ReadableStreamPrototype,
- innerResp.body.streamOrStatic,
+ BlobPrototype,
+ innerResp.body.source,
)
) {
- if (
- innerResp.body.length === null ||
- ObjectPrototypeIsPrototypeOf(
- BlobPrototype,
- innerResp.body.source,
- )
- ) {
- respBody = innerResp.body.stream;
+ respBody = innerResp.body.stream;
+ } else {
+ const reader = innerResp.body.stream.getReader();
+ const r1 = await reader.read();
+ if (r1.done) {
+ respBody = new Uint8Array(0);
} else {
- const reader = innerResp.body.stream.getReader();
- const r1 = await reader.read();
- if (r1.done) {
- respBody = new Uint8Array(0);
- } else {
- respBody = r1.value;
- const r2 = await reader.read();
- if (!r2.done) throw new TypeError("Unreachable");
- }
+ respBody = r1.value;
+ const r2 = await reader.read();
+ if (!r2.done) throw new TypeError("Unreachable");
}
- } else {
- innerResp.body.streamOrStatic.consumed = true;
- respBody = innerResp.body.streamOrStatic.body;
}
} else {
- respBody = new Uint8Array(0);
+ innerResp.body.streamOrStatic.consumed = true;
+ respBody = innerResp.body.streamOrStatic.body;
}
- const isStreamingResponseBody = !(
- typeof respBody === "string" ||
- ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, respBody)
+ } else {
+ respBody = new Uint8Array(0);
+ }
+ const isStreamingResponseBody = !(
+ typeof respBody === "string" ||
+ ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, respBody)
+ );
+ try {
+ await core.opAsync(
+ "op_http_write_headers",
+ streamRid,
+ innerResp.status ?? 200,
+ innerResp.headerList,
+ isStreamingResponseBody ? null : respBody,
);
- try {
- await core.opAsync(
- "op_http_write_headers",
- streamRid,
- innerResp.status ?? 200,
- innerResp.headerList,
- isStreamingResponseBody ? null : respBody,
- );
- } catch (error) {
- const connError = httpConn[connErrorSymbol];
- if (
- ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error) &&
- connError != null
- ) {
- // deno-lint-ignore no-ex-assign
- error = new connError.constructor(connError.message);
- }
- if (
- respBody !== null &&
- ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, respBody)
- ) {
- await respBody.cancel(error);
- }
- throw error;
+ } catch (error) {
+ const connError = httpConn[connErrorSymbol];
+ if (
+ ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error) &&
+ connError != null
+ ) {
+ // deno-lint-ignore no-ex-assign
+ error = new connError.constructor(connError.message);
+ }
+ if (
+ respBody !== null &&
+ ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, respBody)
+ ) {
+ await respBody.cancel(error);
}
+ throw error;
+ }
- if (isStreamingResponseBody) {
- let success = false;
- if (
- respBody === null ||
- !ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, respBody)
- ) {
- throw new TypeError("Unreachable");
+ if (isStreamingResponseBody) {
+ let success = false;
+ if (
+ respBody === null ||
+ !ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, respBody)
+ ) {
+ throw new TypeError("Unreachable");
+ }
+ const resourceBacking = getReadableStreamResourceBacking(respBody);
+ let reader;
+ if (resourceBacking) {
+ if (respBody.locked) {
+ throw new TypeError("ReadableStream is locked.");
+ }
+ reader = respBody.getReader(); // Aquire JS lock.
+ try {
+ await core.opAsync(
+ "op_http_write_resource",
+ streamRid,
+ resourceBacking.rid,
+ );
+ if (resourceBacking.autoClose) core.tryClose(resourceBacking.rid);
+ readableStreamClose(respBody); // Release JS lock.
+ success = true;
+ } catch (error) {
+ const connError = httpConn[connErrorSymbol];
+ if (
+ ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error) &&
+ connError != null
+ ) {
+ // deno-lint-ignore no-ex-assign
+ error = new connError.constructor(connError.message);
+ }
+ await reader.cancel(error);
+ throw error;
}
- const resourceBacking = getReadableStreamResourceBacking(respBody);
- let reader;
- if (resourceBacking) {
- if (respBody.locked) {
- throw new TypeError("ReadableStream is locked.");
+ } else {
+ reader = respBody.getReader();
+ while (true) {
+ const { value, done } = await reader.read();
+ if (done) break;
+ if (!ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, value)) {
+ await reader.cancel(new TypeError("Value not a Uint8Array"));
+ break;
}
- reader = respBody.getReader(); // Aquire JS lock.
try {
- await core.opAsync(
- "op_http_write_resource",
- streamRid,
- resourceBacking.rid,
- );
- if (resourceBacking.autoClose) core.tryClose(resourceBacking.rid);
- readableStreamClose(respBody); // Release JS lock.
- success = true;
+ await core.opAsync("op_http_write", streamRid, value);
} catch (error) {
const connError = httpConn[connErrorSymbol];
if (
@@ -303,176 +325,147 @@
await reader.cancel(error);
throw error;
}
- } else {
- reader = respBody.getReader();
- while (true) {
- const { value, done } = await reader.read();
- if (done) break;
- if (!ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, value)) {
- await reader.cancel(new TypeError("Value not a Uint8Array"));
- break;
- }
- try {
- await core.opAsync("op_http_write", streamRid, value);
- } catch (error) {
- const connError = httpConn[connErrorSymbol];
- if (
- ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error) &&
- connError != null
- ) {
- // deno-lint-ignore no-ex-assign
- error = new connError.constructor(connError.message);
- }
- await reader.cancel(error);
- throw error;
- }
- }
- success = true;
- }
-
- if (success) {
- try {
- await core.opAsync("op_http_shutdown", streamRid);
- } catch (error) {
- await reader.cancel(error);
- throw error;
- }
}
+ success = true;
}
- const deferred = request[_deferred];
- if (deferred) {
- const res = await core.opAsync("op_http_upgrade", streamRid);
- let conn;
- if (res.connType === "tcp") {
- conn = new TcpConn(res.connRid, remoteAddr, localAddr);
- } else if (res.connType === "tls") {
- conn = new TlsConn(res.connRid, remoteAddr, localAddr);
- } else if (res.connType === "unix") {
- conn = new UnixConn(res.connRid, remoteAddr, localAddr);
- } else {
- throw new Error("unreachable");
+ if (success) {
+ try {
+ await core.opAsync("op_http_shutdown", streamRid);
+ } catch (error) {
+ await reader.cancel(error);
+ throw error;
}
+ }
+ }
- deferred.resolve([conn, res.readBuf]);
+ const deferred = request[_deferred];
+ if (deferred) {
+ const res = await core.opAsync("op_http_upgrade", streamRid);
+ let conn;
+ if (res.connType === "tcp") {
+ conn = new TcpConn(res.connRid, remoteAddr, localAddr);
+ } else if (res.connType === "tls") {
+ conn = new TlsConn(res.connRid, remoteAddr, localAddr);
+ } else if (res.connType === "unix") {
+ conn = new UnixConn(res.connRid, remoteAddr, localAddr);
+ } else {
+ throw new Error("unreachable");
}
- const ws = resp[_ws];
- if (ws) {
- const wsRid = await core.opAsync(
- "op_http_upgrade_websocket",
- streamRid,
- );
- ws[_rid] = wsRid;
- ws[_protocol] = resp.headers.get("sec-websocket-protocol");
- httpConn.close();
+ deferred.resolve([conn, res.readBuf]);
+ }
+ const ws = resp[_ws];
+ if (ws) {
+ const wsRid = await core.opAsync(
+ "op_http_upgrade_websocket",
+ streamRid,
+ );
+ ws[_rid] = wsRid;
+ ws[_protocol] = resp.headers.get("sec-websocket-protocol");
- ws[_readyState] = WebSocket.OPEN;
- const event = new Event("open");
- ws.dispatchEvent(event);
+ httpConn.close();
- ws[_eventLoop]();
- if (ws[_idleTimeoutDuration]) {
- ws.addEventListener(
- "close",
- () => clearTimeout(ws[_idleTimeoutTimeout]),
- );
- }
- ws[_serverHandleIdleTimeout]();
- }
- } finally {
- if (SetPrototypeDelete(httpConn.managedResources, streamRid)) {
- core.close(streamRid);
+ ws[_readyState] = WebSocket.OPEN;
+ const event = new Event("open");
+ ws.dispatchEvent(event);
+
+ ws[_eventLoop]();
+ if (ws[_idleTimeoutDuration]) {
+ ws.addEventListener(
+ "close",
+ () => clearTimeout(ws[_idleTimeoutTimeout]),
+ );
}
+ ws[_serverHandleIdleTimeout]();
}
- };
+ } finally {
+ if (SetPrototypeDelete(httpConn.managedResources, streamRid)) {
+ core.close(streamRid);
+ }
+ }
+ };
+}
+
+const _ws = Symbol("[[associated_ws]]");
+
+function upgradeWebSocket(request, options = {}) {
+ const upgrade = request.headers.get("upgrade");
+ const upgradeHasWebSocketOption = upgrade !== null &&
+ ArrayPrototypeSome(
+ StringPrototypeSplit(upgrade, /\s*,\s*/),
+ (option) => StringPrototypeToLowerCase(option) === "websocket",
+ );
+ if (!upgradeHasWebSocketOption) {
+ throw new TypeError(
+ "Invalid Header: 'upgrade' header must contain 'websocket'",
+ );
}
- const _ws = Symbol("[[associated_ws]]");
-
- function upgradeWebSocket(request, options = {}) {
- const upgrade = request.headers.get("upgrade");
- const upgradeHasWebSocketOption = upgrade !== null &&
- ArrayPrototypeSome(
- StringPrototypeSplit(upgrade, /\s*,\s*/),
- (option) => StringPrototypeToLowerCase(option) === "websocket",
- );
- if (!upgradeHasWebSocketOption) {
- throw new TypeError(
- "Invalid Header: 'upgrade' header must contain 'websocket'",
- );
- }
+ const connection = request.headers.get("connection");
+ const connectionHasUpgradeOption = connection !== null &&
+ ArrayPrototypeSome(
+ StringPrototypeSplit(connection, /\s*,\s*/),
+ (option) => StringPrototypeToLowerCase(option) === "upgrade",
+ );
+ if (!connectionHasUpgradeOption) {
+ throw new TypeError(
+ "Invalid Header: 'connection' header must contain 'Upgrade'",
+ );
+ }
- const connection = request.headers.get("connection");
- const connectionHasUpgradeOption = connection !== null &&
- ArrayPrototypeSome(
- StringPrototypeSplit(connection, /\s*,\s*/),
- (option) => StringPrototypeToLowerCase(option) === "upgrade",
- );
- if (!connectionHasUpgradeOption) {
- throw new TypeError(
- "Invalid Header: 'connection' header must contain 'Upgrade'",
- );
- }
+ const websocketKey = request.headers.get("sec-websocket-key");
+ if (websocketKey === null) {
+ throw new TypeError(
+ "Invalid Header: 'sec-websocket-key' header must be set",
+ );
+ }
- const websocketKey = request.headers.get("sec-websocket-key");
- if (websocketKey === null) {
+ const accept = ops.op_http_websocket_accept_header(websocketKey);
+
+ const r = newInnerResponse(101);
+ r.headerList = [
+ ["upgrade", "websocket"],
+ ["connection", "Upgrade"],
+ ["sec-websocket-accept", accept],
+ ];
+
+ const protocolsStr = request.headers.get("sec-websocket-protocol") || "";
+ const protocols = StringPrototypeSplit(protocolsStr, ", ");
+ if (protocols && options.protocol) {
+ if (ArrayPrototypeIncludes(protocols, options.protocol)) {
+ ArrayPrototypePush(r.headerList, [
+ "sec-websocket-protocol",
+ options.protocol,
+ ]);
+ } else {
throw new TypeError(
- "Invalid Header: 'sec-websocket-key' header must be set",
+ `Protocol '${options.protocol}' not in the request's protocol list (non negotiable)`,
);
}
+ }
- const accept = ops.op_http_websocket_accept_header(websocketKey);
-
- const r = newInnerResponse(101);
- r.headerList = [
- ["upgrade", "websocket"],
- ["connection", "Upgrade"],
- ["sec-websocket-accept", accept],
- ];
-
- const protocolsStr = request.headers.get("sec-websocket-protocol") || "";
- const protocols = StringPrototypeSplit(protocolsStr, ", ");
- if (protocols && options.protocol) {
- if (ArrayPrototypeIncludes(protocols, options.protocol)) {
- ArrayPrototypePush(r.headerList, [
- "sec-websocket-protocol",
- options.protocol,
- ]);
- } else {
- throw new TypeError(
- `Protocol '${options.protocol}' not in the request's protocol list (non negotiable)`,
- );
- }
- }
+ const response = fromInnerResponse(r, "immutable");
- const response = fromInnerResponse(r, "immutable");
+ const socket = webidl.createBranded(WebSocket);
+ setEventTargetData(socket);
+ socket[_server] = true;
+ response[_ws] = socket;
+ socket[_idleTimeoutDuration] = options.idleTimeout ?? 120;
+ socket[_idleTimeoutTimeout] = null;
- const socket = webidl.createBranded(WebSocket);
- setEventTargetData(socket);
- socket[_server] = true;
- response[_ws] = socket;
- socket[_idleTimeoutDuration] = options.idleTimeout ?? 120;
- socket[_idleTimeoutTimeout] = null;
+ return { response, socket };
+}
- return { response, socket };
+function upgradeHttp(req) {
+ if (req[_flash]) {
+ throw new TypeError(
+ "Flash requests can not be upgraded with `upgradeHttp`. Use `upgradeHttpRaw` instead.",
+ );
}
- function upgradeHttp(req) {
- if (req[_flash]) {
- throw new TypeError(
- "Flash requests can not be upgraded with `upgradeHttp`. Use `upgradeHttpRaw` instead.",
- );
- }
+ req[_deferred] = new Deferred();
+ return req[_deferred].promise;
+}
- req[_deferred] = new Deferred();
- return req[_deferred].promise;
- }
-
- window.__bootstrap.http = {
- HttpConn,
- upgradeWebSocket,
- upgradeHttp,
- _ws,
- };
-})(this);
+export { _ws, HttpConn, upgradeHttp, upgradeWebSocket };
diff --git a/ext/http/lib.rs b/ext/http/lib.rs
index 0e3ebf766..a0593de8c 100644
--- a/ext/http/lib.rs
+++ b/ext/http/lib.rs
@@ -80,7 +80,7 @@ mod reader_stream;
pub fn init() -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_web", "deno_net", "deno_fetch", "deno_websocket"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/http",
"01_http.js",
))
diff --git a/ext/net/01_net.js b/ext/net/01_net.js
index a6043786f..46561cae5 100644
--- a/ext/net/01_net.js
+++ b/ext/net/01_net.js
@@ -1,423 +1,421 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const { BadResourcePrototype, InterruptedPrototype, ops } = core;
- const {
- readableStreamForRidUnrefable,
- readableStreamForRidUnrefableRef,
- readableStreamForRidUnrefableUnref,
- writableStreamForRid,
- } = window.__bootstrap.streams;
- const {
- Error,
- ObjectPrototypeIsPrototypeOf,
- PromiseResolve,
- SymbolAsyncIterator,
- SymbolFor,
- TypedArrayPrototypeSubarray,
- TypeError,
- Uint8Array,
- } = window.__bootstrap.primordials;
-
- const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId");
-
- async function write(rid, data) {
- return await core.write(rid, data);
- }
-
- function shutdown(rid) {
- return core.shutdown(rid);
- }
-
- function resolveDns(query, recordType, options) {
- return core.opAsync("op_dns_resolve", { query, recordType, options });
- }
-
- class Conn {
- #rid = 0;
- #remoteAddr = null;
- #localAddr = null;
- #unref = false;
- #pendingReadPromiseIds = [];
-
- #readable;
- #writable;
-
- constructor(rid, remoteAddr, localAddr) {
- this.#rid = rid;
- this.#remoteAddr = remoteAddr;
- this.#localAddr = localAddr;
- }
- get rid() {
- return this.#rid;
- }
+const core = globalThis.Deno.core;
+const { BadResourcePrototype, InterruptedPrototype, ops } = core;
+import {
+ readableStreamForRidUnrefable,
+ readableStreamForRidUnrefableRef,
+ readableStreamForRidUnrefableUnref,
+ writableStreamForRid,
+} from "internal:ext/web/06_streams.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ Error,
+ ObjectPrototypeIsPrototypeOf,
+ PromiseResolve,
+ SymbolAsyncIterator,
+ SymbolFor,
+ TypedArrayPrototypeSubarray,
+ TypeError,
+ Uint8Array,
+} = primordials;
+
+const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId");
+
+async function write(rid, data) {
+ return await core.write(rid, data);
+}
+
+function shutdown(rid) {
+ return core.shutdown(rid);
+}
+
+function resolveDns(query, recordType, options) {
+ return core.opAsync("op_dns_resolve", { query, recordType, options });
+}
+
+class Conn {
+ #rid = 0;
+ #remoteAddr = null;
+ #localAddr = null;
+ #unref = false;
+ #pendingReadPromiseIds = [];
+
+ #readable;
+ #writable;
+
+ constructor(rid, remoteAddr, localAddr) {
+ this.#rid = rid;
+ this.#remoteAddr = remoteAddr;
+ this.#localAddr = localAddr;
+ }
- get remoteAddr() {
- return this.#remoteAddr;
- }
+ get rid() {
+ return this.#rid;
+ }
- get localAddr() {
- return this.#localAddr;
- }
+ get remoteAddr() {
+ return this.#remoteAddr;
+ }
- write(p) {
- return write(this.rid, p);
- }
+ get localAddr() {
+ return this.#localAddr;
+ }
- async read(buffer) {
- if (buffer.length === 0) {
- return 0;
- }
- const promise = core.read(this.rid, buffer);
- const promiseId = promise[promiseIdSymbol];
- if (this.#unref) core.unrefOp(promiseId);
- this.#pendingReadPromiseIds.push(promiseId);
- let nread;
- try {
- nread = await promise;
- } catch (e) {
- throw e;
- } finally {
- this.#pendingReadPromiseIds = this.#pendingReadPromiseIds.filter((id) =>
- id !== promiseId
- );
- }
- return nread === 0 ? null : nread;
- }
+ write(p) {
+ return write(this.rid, p);
+ }
- close() {
- core.close(this.rid);
- }
+ async read(buffer) {
+ if (buffer.length === 0) {
+ return 0;
+ }
+ const promise = core.read(this.rid, buffer);
+ const promiseId = promise[promiseIdSymbol];
+ if (this.#unref) core.unrefOp(promiseId);
+ this.#pendingReadPromiseIds.push(promiseId);
+ let nread;
+ try {
+ nread = await promise;
+ } catch (e) {
+ throw e;
+ } finally {
+ this.#pendingReadPromiseIds = this.#pendingReadPromiseIds.filter((id) =>
+ id !== promiseId
+ );
+ }
+ return nread === 0 ? null : nread;
+ }
- closeWrite() {
- return shutdown(this.rid);
- }
+ close() {
+ core.close(this.rid);
+ }
- get readable() {
- if (this.#readable === undefined) {
- this.#readable = readableStreamForRidUnrefable(this.rid);
- if (this.#unref) {
- readableStreamForRidUnrefableUnref(this.#readable);
- }
- }
- return this.#readable;
- }
+ closeWrite() {
+ return shutdown(this.rid);
+ }
- get writable() {
- if (this.#writable === undefined) {
- this.#writable = writableStreamForRid(this.rid);
+ get readable() {
+ if (this.#readable === undefined) {
+ this.#readable = readableStreamForRidUnrefable(this.rid);
+ if (this.#unref) {
+ readableStreamForRidUnrefableUnref(this.#readable);
}
- return this.#writable;
}
+ return this.#readable;
+ }
- ref() {
- this.#unref = false;
- if (this.#readable) {
- readableStreamForRidUnrefableRef(this.#readable);
- }
- this.#pendingReadPromiseIds.forEach((id) => core.refOp(id));
+ get writable() {
+ if (this.#writable === undefined) {
+ this.#writable = writableStreamForRid(this.rid);
}
+ return this.#writable;
+ }
- unref() {
- this.#unref = true;
- if (this.#readable) {
- readableStreamForRidUnrefableUnref(this.#readable);
- }
- this.#pendingReadPromiseIds.forEach((id) => core.unrefOp(id));
+ ref() {
+ this.#unref = false;
+ if (this.#readable) {
+ readableStreamForRidUnrefableRef(this.#readable);
}
+ this.#pendingReadPromiseIds.forEach((id) => core.refOp(id));
}
- class TcpConn extends Conn {
- setNoDelay(noDelay = true) {
- return ops.op_set_nodelay(this.rid, noDelay);
+ unref() {
+ this.#unref = true;
+ if (this.#readable) {
+ readableStreamForRidUnrefableUnref(this.#readable);
}
+ this.#pendingReadPromiseIds.forEach((id) => core.unrefOp(id));
+ }
+}
- setKeepAlive(keepAlive = true) {
- return ops.op_set_keepalive(this.rid, keepAlive);
- }
+class TcpConn extends Conn {
+ setNoDelay(noDelay = true) {
+ return ops.op_set_nodelay(this.rid, noDelay);
}
- class UnixConn extends Conn {}
+ setKeepAlive(keepAlive = true) {
+ return ops.op_set_keepalive(this.rid, keepAlive);
+ }
+}
- class Listener {
- #rid = 0;
- #addr = null;
- #unref = false;
- #promiseId = null;
+class UnixConn extends Conn {}
- constructor(rid, addr) {
- this.#rid = rid;
- this.#addr = addr;
- }
+class Listener {
+ #rid = 0;
+ #addr = null;
+ #unref = false;
+ #promiseId = null;
- get rid() {
- return this.#rid;
- }
+ constructor(rid, addr) {
+ this.#rid = rid;
+ this.#addr = addr;
+ }
- get addr() {
- return this.#addr;
- }
+ get rid() {
+ return this.#rid;
+ }
- async accept() {
- let promise;
- switch (this.addr.transport) {
- case "tcp":
- promise = core.opAsync("op_net_accept_tcp", this.rid);
- break;
- case "unix":
- promise = core.opAsync("op_net_accept_unix", this.rid);
- break;
- default:
- throw new Error(`Unsupported transport: ${this.addr.transport}`);
- }
- this.#promiseId = promise[promiseIdSymbol];
- if (this.#unref) core.unrefOp(this.#promiseId);
- const { 0: rid, 1: localAddr, 2: remoteAddr } = await promise;
- this.#promiseId = null;
- if (this.addr.transport == "tcp") {
- localAddr.transport = "tcp";
- remoteAddr.transport = "tcp";
- return new TcpConn(rid, remoteAddr, localAddr);
- } else if (this.addr.transport == "unix") {
- return new UnixConn(
- rid,
- { transport: "unix", path: remoteAddr },
- { transport: "unix", path: localAddr },
- );
- } else {
- throw new Error("unreachable");
- }
+ get addr() {
+ return this.#addr;
+ }
+
+ async accept() {
+ let promise;
+ switch (this.addr.transport) {
+ case "tcp":
+ promise = core.opAsync("op_net_accept_tcp", this.rid);
+ break;
+ case "unix":
+ promise = core.opAsync("op_net_accept_unix", this.rid);
+ break;
+ default:
+ throw new Error(`Unsupported transport: ${this.addr.transport}`);
+ }
+ this.#promiseId = promise[promiseIdSymbol];
+ if (this.#unref) core.unrefOp(this.#promiseId);
+ const { 0: rid, 1: localAddr, 2: remoteAddr } = await promise;
+ this.#promiseId = null;
+ if (this.addr.transport == "tcp") {
+ localAddr.transport = "tcp";
+ remoteAddr.transport = "tcp";
+ return new TcpConn(rid, remoteAddr, localAddr);
+ } else if (this.addr.transport == "unix") {
+ return new UnixConn(
+ rid,
+ { transport: "unix", path: remoteAddr },
+ { transport: "unix", path: localAddr },
+ );
+ } else {
+ throw new Error("unreachable");
}
+ }
- async next() {
- let conn;
- try {
- conn = await this.accept();
- } catch (error) {
- if (
- ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error) ||
- ObjectPrototypeIsPrototypeOf(InterruptedPrototype, error)
- ) {
- return { value: undefined, done: true };
- }
- throw error;
+ async next() {
+ let conn;
+ try {
+ conn = await this.accept();
+ } catch (error) {
+ if (
+ ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error) ||
+ ObjectPrototypeIsPrototypeOf(InterruptedPrototype, error)
+ ) {
+ return { value: undefined, done: true };
}
- return { value: conn, done: false };
+ throw error;
}
+ return { value: conn, done: false };
+ }
- return(value) {
- this.close();
- return PromiseResolve({ value, done: true });
- }
+ return(value) {
+ this.close();
+ return PromiseResolve({ value, done: true });
+ }
- close() {
- core.close(this.rid);
- }
+ close() {
+ core.close(this.rid);
+ }
- [SymbolAsyncIterator]() {
- return this;
- }
+ [SymbolAsyncIterator]() {
+ return this;
+ }
- ref() {
- this.#unref = false;
- if (typeof this.#promiseId === "number") {
- core.refOp(this.#promiseId);
- }
+ ref() {
+ this.#unref = false;
+ if (typeof this.#promiseId === "number") {
+ core.refOp(this.#promiseId);
}
+ }
- unref() {
- this.#unref = true;
- if (typeof this.#promiseId === "number") {
- core.unrefOp(this.#promiseId);
- }
+ unref() {
+ this.#unref = true;
+ if (typeof this.#promiseId === "number") {
+ core.unrefOp(this.#promiseId);
}
}
+}
- class Datagram {
- #rid = 0;
- #addr = null;
+class Datagram {
+ #rid = 0;
+ #addr = null;
- constructor(rid, addr, bufSize = 1024) {
- this.#rid = rid;
- this.#addr = addr;
- this.bufSize = bufSize;
- }
-
- get rid() {
- return this.#rid;
- }
+ constructor(rid, addr, bufSize = 1024) {
+ this.#rid = rid;
+ this.#addr = addr;
+ this.bufSize = bufSize;
+ }
- get addr() {
- return this.#addr;
- }
+ get rid() {
+ return this.#rid;
+ }
- async receive(p) {
- const buf = p || new Uint8Array(this.bufSize);
- let nread;
- let remoteAddr;
- switch (this.addr.transport) {
- case "udp": {
- ({ 0: nread, 1: remoteAddr } = await core.opAsync(
- "op_net_recv_udp",
- this.rid,
- buf,
- ));
- remoteAddr.transport = "udp";
- break;
- }
- case "unixpacket": {
- let path;
- ({ 0: nread, 1: path } = await core.opAsync(
- "op_net_recv_unixpacket",
- this.rid,
- buf,
- ));
- remoteAddr = { transport: "unixpacket", path };
- break;
- }
- default:
- throw new Error(`Unsupported transport: ${this.addr.transport}`);
- }
- const sub = TypedArrayPrototypeSubarray(buf, 0, nread);
- return [sub, remoteAddr];
- }
+ get addr() {
+ return this.#addr;
+ }
- async send(p, opts) {
- switch (this.addr.transport) {
- case "udp":
- return await core.opAsync(
- "op_net_send_udp",
- this.rid,
- { hostname: opts.hostname ?? "127.0.0.1", port: opts.port },
- p,
- );
- case "unixpacket":
- return await core.opAsync(
- "op_net_send_unixpacket",
- this.rid,
- opts.path,
- p,
- );
- default:
- throw new Error(`Unsupported transport: ${this.addr.transport}`);
+ async receive(p) {
+ const buf = p || new Uint8Array(this.bufSize);
+ let nread;
+ let remoteAddr;
+ switch (this.addr.transport) {
+ case "udp": {
+ ({ 0: nread, 1: remoteAddr } = await core.opAsync(
+ "op_net_recv_udp",
+ this.rid,
+ buf,
+ ));
+ remoteAddr.transport = "udp";
+ break;
}
- }
-
- close() {
- core.close(this.rid);
- }
-
- async *[SymbolAsyncIterator]() {
- while (true) {
- try {
- yield await this.receive();
- } catch (err) {
- if (
- ObjectPrototypeIsPrototypeOf(BadResourcePrototype, err) ||
- ObjectPrototypeIsPrototypeOf(InterruptedPrototype, err)
- ) {
- break;
- }
- throw err;
- }
+ case "unixpacket": {
+ let path;
+ ({ 0: nread, 1: path } = await core.opAsync(
+ "op_net_recv_unixpacket",
+ this.rid,
+ buf,
+ ));
+ remoteAddr = { transport: "unixpacket", path };
+ break;
}
+ default:
+ throw new Error(`Unsupported transport: ${this.addr.transport}`);
}
+ const sub = TypedArrayPrototypeSubarray(buf, 0, nread);
+ return [sub, remoteAddr];
}
- function listen(args) {
- switch (args.transport ?? "tcp") {
- case "tcp": {
- const { 0: rid, 1: addr } = ops.op_net_listen_tcp({
- hostname: args.hostname ?? "0.0.0.0",
- port: args.port,
- }, args.reusePort);
- addr.transport = "tcp";
- return new Listener(rid, addr);
- }
- case "unix": {
- const { 0: rid, 1: path } = ops.op_net_listen_unix(args.path);
- const addr = {
- transport: "unix",
- path,
- };
- return new Listener(rid, addr);
- }
+ async send(p, opts) {
+ switch (this.addr.transport) {
+ case "udp":
+ return await core.opAsync(
+ "op_net_send_udp",
+ this.rid,
+ { hostname: opts.hostname ?? "127.0.0.1", port: opts.port },
+ p,
+ );
+ case "unixpacket":
+ return await core.opAsync(
+ "op_net_send_unixpacket",
+ this.rid,
+ opts.path,
+ p,
+ );
default:
- throw new TypeError(`Unsupported transport: '${transport}'`);
+ throw new Error(`Unsupported transport: ${this.addr.transport}`);
}
}
- function createListenDatagram(udpOpFn, unixOpFn) {
- return function listenDatagram(args) {
- switch (args.transport) {
- case "udp": {
- const { 0: rid, 1: addr } = udpOpFn(
- {
- hostname: args.hostname ?? "127.0.0.1",
- port: args.port,
- },
- args.reuseAddress ?? false,
- );
- addr.transport = "udp";
- return new Datagram(rid, addr);
- }
- case "unixpacket": {
- const { 0: rid, 1: path } = unixOpFn(args.path);
- const addr = {
- transport: "unixpacket",
- path,
- };
- return new Datagram(rid, addr);
+ close() {
+ core.close(this.rid);
+ }
+
+ async *[SymbolAsyncIterator]() {
+ while (true) {
+ try {
+ yield await this.receive();
+ } catch (err) {
+ if (
+ ObjectPrototypeIsPrototypeOf(BadResourcePrototype, err) ||
+ ObjectPrototypeIsPrototypeOf(InterruptedPrototype, err)
+ ) {
+ break;
}
- default:
- throw new TypeError(`Unsupported transport: '${transport}'`);
+ throw err;
}
- };
+ }
+ }
+}
+
+function listen(args) {
+ switch (args.transport ?? "tcp") {
+ case "tcp": {
+ const { 0: rid, 1: addr } = ops.op_net_listen_tcp({
+ hostname: args.hostname ?? "0.0.0.0",
+ port: args.port,
+ }, args.reusePort);
+ addr.transport = "tcp";
+ return new Listener(rid, addr);
+ }
+ case "unix": {
+ const { 0: rid, 1: path } = ops.op_net_listen_unix(args.path);
+ const addr = {
+ transport: "unix",
+ path,
+ };
+ return new Listener(rid, addr);
+ }
+ default:
+ throw new TypeError(`Unsupported transport: '${transport}'`);
}
+}
- async function connect(args) {
- switch (args.transport ?? "tcp") {
- case "tcp": {
- const { 0: rid, 1: localAddr, 2: remoteAddr } = await core.opAsync(
- "op_net_connect_tcp",
+function createListenDatagram(udpOpFn, unixOpFn) {
+ return function listenDatagram(args) {
+ switch (args.transport) {
+ case "udp": {
+ const { 0: rid, 1: addr } = udpOpFn(
{
hostname: args.hostname ?? "127.0.0.1",
port: args.port,
},
+ args.reuseAddress ?? false,
);
- localAddr.transport = "tcp";
- remoteAddr.transport = "tcp";
- return new TcpConn(rid, remoteAddr, localAddr);
+ addr.transport = "udp";
+ return new Datagram(rid, addr);
}
- case "unix": {
- const { 0: rid, 1: localAddr, 2: remoteAddr } = await core.opAsync(
- "op_net_connect_unix",
- args.path,
- );
- return new UnixConn(
- rid,
- { transport: "unix", path: remoteAddr },
- { transport: "unix", path: localAddr },
- );
+ case "unixpacket": {
+ const { 0: rid, 1: path } = unixOpFn(args.path);
+ const addr = {
+ transport: "unixpacket",
+ path,
+ };
+ return new Datagram(rid, addr);
}
default:
throw new TypeError(`Unsupported transport: '${transport}'`);
}
- }
-
- window.__bootstrap.net = {
- connect,
- Conn,
- TcpConn,
- UnixConn,
- listen,
- createListenDatagram,
- Listener,
- shutdown,
- Datagram,
- resolveDns,
};
-})(this);
+}
+
+async function connect(args) {
+ switch (args.transport ?? "tcp") {
+ case "tcp": {
+ const { 0: rid, 1: localAddr, 2: remoteAddr } = await core.opAsync(
+ "op_net_connect_tcp",
+ {
+ hostname: args.hostname ?? "127.0.0.1",
+ port: args.port,
+ },
+ );
+ localAddr.transport = "tcp";
+ remoteAddr.transport = "tcp";
+ return new TcpConn(rid, remoteAddr, localAddr);
+ }
+ case "unix": {
+ const { 0: rid, 1: localAddr, 2: remoteAddr } = await core.opAsync(
+ "op_net_connect_unix",
+ args.path,
+ );
+ return new UnixConn(
+ rid,
+ { transport: "unix", path: remoteAddr },
+ { transport: "unix", path: localAddr },
+ );
+ }
+ default:
+ throw new TypeError(`Unsupported transport: '${transport}'`);
+ }
+}
+
+export {
+ Conn,
+ connect,
+ createListenDatagram,
+ Datagram,
+ listen,
+ Listener,
+ resolveDns,
+ shutdown,
+ TcpConn,
+ UnixConn,
+};
diff --git a/ext/net/02_tls.js b/ext/net/02_tls.js
index 632e1fbd4..4701d3da7 100644
--- a/ext/net/02_tls.js
+++ b/ext/net/02_tls.js
@@ -1,106 +1,98 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const { Listener, Conn } = window.__bootstrap.net;
- const { TypeError } = window.__bootstrap.primordials;
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import { Conn, Listener } from "internal:ext/net/01_net.js";
+const primordials = globalThis.__bootstrap.primordials;
+const { TypeError } = primordials;
- function opStartTls(args) {
- return core.opAsync("op_tls_start", args);
- }
+function opStartTls(args) {
+ return core.opAsync("op_tls_start", args);
+}
+
+function opTlsHandshake(rid) {
+ return core.opAsync("op_tls_handshake", rid);
+}
- function opTlsHandshake(rid) {
- return core.opAsync("op_tls_handshake", rid);
+class TlsConn extends Conn {
+ handshake() {
+ return opTlsHandshake(this.rid);
}
+}
- class TlsConn extends Conn {
- handshake() {
- return opTlsHandshake(this.rid);
- }
+async function connectTls({
+ port,
+ hostname = "127.0.0.1",
+ transport = "tcp",
+ certFile = undefined,
+ caCerts = [],
+ certChain = undefined,
+ privateKey = undefined,
+ alpnProtocols = undefined,
+}) {
+ if (transport !== "tcp") {
+ throw new TypeError(`Unsupported transport: '${transport}'`);
}
+ const { 0: rid, 1: localAddr, 2: remoteAddr } = await core.opAsync(
+ "op_net_connect_tls",
+ { hostname, port },
+ { certFile, caCerts, certChain, privateKey, alpnProtocols },
+ );
+ localAddr.transport = "tcp";
+ remoteAddr.transport = "tcp";
+ return new TlsConn(rid, remoteAddr, localAddr);
+}
- async function connectTls({
- port,
- hostname = "127.0.0.1",
- transport = "tcp",
- certFile = undefined,
- caCerts = [],
- certChain = undefined,
- privateKey = undefined,
- alpnProtocols = undefined,
- }) {
- if (transport !== "tcp") {
- throw new TypeError(`Unsupported transport: '${transport}'`);
- }
+class TlsListener extends Listener {
+ async accept() {
const { 0: rid, 1: localAddr, 2: remoteAddr } = await core.opAsync(
- "op_net_connect_tls",
- { hostname, port },
- { certFile, caCerts, certChain, privateKey, alpnProtocols },
+ "op_net_accept_tls",
+ this.rid,
);
localAddr.transport = "tcp";
remoteAddr.transport = "tcp";
return new TlsConn(rid, remoteAddr, localAddr);
}
+}
- class TlsListener extends Listener {
- async accept() {
- const { 0: rid, 1: localAddr, 2: remoteAddr } = await core.opAsync(
- "op_net_accept_tls",
- this.rid,
- );
- localAddr.transport = "tcp";
- remoteAddr.transport = "tcp";
- return new TlsConn(rid, remoteAddr, localAddr);
- }
+function listenTls({
+ port,
+ cert,
+ certFile,
+ key,
+ keyFile,
+ hostname = "0.0.0.0",
+ transport = "tcp",
+ alpnProtocols = undefined,
+ reusePort = false,
+}) {
+ if (transport !== "tcp") {
+ throw new TypeError(`Unsupported transport: '${transport}'`);
}
+ const { 0: rid, 1: localAddr } = ops.op_net_listen_tls(
+ { hostname, port },
+ { cert, certFile, key, keyFile, alpnProtocols, reusePort },
+ );
+ return new TlsListener(rid, localAddr);
+}
- function listenTls({
- port,
- cert,
- certFile,
- key,
- keyFile,
- hostname = "0.0.0.0",
- transport = "tcp",
+async function startTls(
+ conn,
+ {
+ hostname = "127.0.0.1",
+ certFile = undefined,
+ caCerts = [],
alpnProtocols = undefined,
- reusePort = false,
- }) {
- if (transport !== "tcp") {
- throw new TypeError(`Unsupported transport: '${transport}'`);
- }
- const { 0: rid, 1: localAddr } = ops.op_net_listen_tls(
- { hostname, port },
- { cert, certFile, key, keyFile, alpnProtocols, reusePort },
- );
- return new TlsListener(rid, localAddr);
- }
-
- async function startTls(
- conn,
- {
- hostname = "127.0.0.1",
- certFile = undefined,
- caCerts = [],
- alpnProtocols = undefined,
- } = {},
- ) {
- const { 0: rid, 1: localAddr, 2: remoteAddr } = await opStartTls({
- rid: conn.rid,
- hostname,
- certFile,
- caCerts,
- alpnProtocols,
- });
- return new TlsConn(rid, remoteAddr, localAddr);
- }
+ } = {},
+) {
+ const { 0: rid, 1: localAddr, 2: remoteAddr } = await opStartTls({
+ rid: conn.rid,
+ hostname,
+ certFile,
+ caCerts,
+ alpnProtocols,
+ });
+ return new TlsConn(rid, remoteAddr, localAddr);
+}
- window.__bootstrap.tls = {
- startTls,
- listenTls,
- connectTls,
- TlsConn,
- TlsListener,
- };
-})(this);
+export { connectTls, listenTls, startTls, TlsConn, TlsListener };
diff --git a/ext/net/lib.rs b/ext/net/lib.rs
index 932f8c8c5..ed620fcdd 100644
--- a/ext/net/lib.rs
+++ b/ext/net/lib.rs
@@ -86,7 +86,7 @@ pub fn init<P: NetPermissions + 'static>(
ops.extend(ops_tls::init::<P>());
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_web"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/net",
"01_net.js",
"02_tls.js",
diff --git a/ext/node/01_node.js b/ext/node/01_node.js
index 4ed5b3eda..de27c5180 100644
--- a/ext/node/01_node.js
+++ b/ext/node/01_node.js
@@ -2,127 +2,122 @@
// deno-lint-ignore-file
-"use strict";
+const internals = globalThis.__bootstrap.internals;
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypePush,
+ ArrayPrototypeFilter,
+ ObjectEntries,
+ ObjectCreate,
+ ObjectDefineProperty,
+ Proxy,
+ ReflectDefineProperty,
+ ReflectGetOwnPropertyDescriptor,
+ ReflectOwnKeys,
+ Set,
+ SetPrototypeHas,
+} = primordials;
-((window) => {
- const {
- ArrayPrototypePush,
- ArrayPrototypeFilter,
- ObjectEntries,
- ObjectCreate,
- ObjectDefineProperty,
- Proxy,
- ReflectDefineProperty,
- ReflectGetOwnPropertyDescriptor,
- ReflectOwnKeys,
- Set,
- SetPrototypeHas,
- } = window.__bootstrap.primordials;
-
- function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
+function assert(cond) {
+ if (!cond) {
+ throw Error("assert");
}
+}
- let initialized = false;
- const nodeGlobals = {};
- const nodeGlobalThis = new Proxy(globalThis, {
- get(_target, prop, _receiver) {
- if (prop in nodeGlobals) {
- return nodeGlobals[prop];
- } else {
- return globalThis[prop];
- }
- },
- set(_target, prop, value) {
- if (prop in nodeGlobals) {
- nodeGlobals[prop] = value;
- } else {
- globalThis[prop] = value;
- }
- return true;
- },
- deleteProperty(_target, prop) {
- let success = false;
- if (prop in nodeGlobals) {
- delete nodeGlobals[prop];
- success = true;
- }
- if (prop in globalThis) {
- delete globalThis[prop];
- success = true;
- }
- return success;
- },
- ownKeys(_target) {
- const globalThisKeys = ReflectOwnKeys(globalThis);
- const nodeGlobalsKeys = ReflectOwnKeys(nodeGlobals);
- const nodeGlobalsKeySet = new Set(nodeGlobalsKeys);
- return [
- ...ArrayPrototypeFilter(
- globalThisKeys,
- (k) => !SetPrototypeHas(nodeGlobalsKeySet, k),
- ),
- ...nodeGlobalsKeys,
- ];
- },
- defineProperty(_target, prop, desc) {
- if (prop in nodeGlobals) {
- return ReflectDefineProperty(nodeGlobals, prop, desc);
- } else {
- return ReflectDefineProperty(globalThis, prop, desc);
- }
- },
- getOwnPropertyDescriptor(_target, prop) {
- if (prop in nodeGlobals) {
- return ReflectGetOwnPropertyDescriptor(nodeGlobals, prop);
- } else {
- return ReflectGetOwnPropertyDescriptor(globalThis, prop);
- }
- },
- has(_target, prop) {
- return prop in nodeGlobals || prop in globalThis;
- },
- });
-
- const nativeModuleExports = ObjectCreate(null);
- const builtinModules = [];
-
- function initialize(nodeModules, nodeGlobalThisName) {
- assert(!initialized);
- initialized = true;
- for (const [name, exports] of ObjectEntries(nodeModules)) {
- nativeModuleExports[name] = exports;
- ArrayPrototypePush(builtinModules, name);
+let initialized = false;
+const nodeGlobals = {};
+const nodeGlobalThis = new Proxy(globalThis, {
+ get(_target, prop, _receiver) {
+ if (prop in nodeGlobals) {
+ return nodeGlobals[prop];
+ } else {
+ return globalThis[prop];
+ }
+ },
+ set(_target, prop, value) {
+ if (prop in nodeGlobals) {
+ nodeGlobals[prop] = value;
+ } else {
+ globalThis[prop] = value;
+ }
+ return true;
+ },
+ deleteProperty(_target, prop) {
+ let success = false;
+ if (prop in nodeGlobals) {
+ delete nodeGlobals[prop];
+ success = true;
}
- nodeGlobals.Buffer = nativeModuleExports["buffer"].Buffer;
- nodeGlobals.clearImmediate = nativeModuleExports["timers"].clearImmediate;
- nodeGlobals.clearInterval = nativeModuleExports["timers"].clearInterval;
- nodeGlobals.clearTimeout = nativeModuleExports["timers"].clearTimeout;
- nodeGlobals.console = nativeModuleExports["console"];
- nodeGlobals.global = nodeGlobalThis;
- nodeGlobals.process = nativeModuleExports["process"];
- nodeGlobals.setImmediate = nativeModuleExports["timers"].setImmediate;
- nodeGlobals.setInterval = nativeModuleExports["timers"].setInterval;
- nodeGlobals.setTimeout = nativeModuleExports["timers"].setTimeout;
+ if (prop in globalThis) {
+ delete globalThis[prop];
+ success = true;
+ }
+ return success;
+ },
+ ownKeys(_target) {
+ const globalThisKeys = ReflectOwnKeys(globalThis);
+ const nodeGlobalsKeys = ReflectOwnKeys(nodeGlobals);
+ const nodeGlobalsKeySet = new Set(nodeGlobalsKeys);
+ return [
+ ...ArrayPrototypeFilter(
+ globalThisKeys,
+ (k) => !SetPrototypeHas(nodeGlobalsKeySet, k),
+ ),
+ ...nodeGlobalsKeys,
+ ];
+ },
+ defineProperty(_target, prop, desc) {
+ if (prop in nodeGlobals) {
+ return ReflectDefineProperty(nodeGlobals, prop, desc);
+ } else {
+ return ReflectDefineProperty(globalThis, prop, desc);
+ }
+ },
+ getOwnPropertyDescriptor(_target, prop) {
+ if (prop in nodeGlobals) {
+ return ReflectGetOwnPropertyDescriptor(nodeGlobals, prop);
+ } else {
+ return ReflectGetOwnPropertyDescriptor(globalThis, prop);
+ }
+ },
+ has(_target, prop) {
+ return prop in nodeGlobals || prop in globalThis;
+ },
+});
- // add a hidden global for the esm code to use in order to reliably
- // get node's globalThis
- ObjectDefineProperty(globalThis, nodeGlobalThisName, {
- enumerable: false,
- writable: false,
- value: nodeGlobalThis,
- });
+const nativeModuleExports = ObjectCreate(null);
+const builtinModules = [];
+
+function initialize(nodeModules, nodeGlobalThisName) {
+ assert(!initialized);
+ initialized = true;
+ for (const [name, exports] of ObjectEntries(nodeModules)) {
+ nativeModuleExports[name] = exports;
+ ArrayPrototypePush(builtinModules, name);
}
+ nodeGlobals.Buffer = nativeModuleExports["buffer"].Buffer;
+ nodeGlobals.clearImmediate = nativeModuleExports["timers"].clearImmediate;
+ nodeGlobals.clearInterval = nativeModuleExports["timers"].clearInterval;
+ nodeGlobals.clearTimeout = nativeModuleExports["timers"].clearTimeout;
+ nodeGlobals.console = nativeModuleExports["console"];
+ nodeGlobals.global = nodeGlobalThis;
+ nodeGlobals.process = nativeModuleExports["process"];
+ nodeGlobals.setImmediate = nativeModuleExports["timers"].setImmediate;
+ nodeGlobals.setInterval = nativeModuleExports["timers"].setInterval;
+ nodeGlobals.setTimeout = nativeModuleExports["timers"].setTimeout;
+
+ // add a hidden global for the esm code to use in order to reliably
+ // get node's globalThis
+ ObjectDefineProperty(globalThis, nodeGlobalThisName, {
+ enumerable: false,
+ writable: false,
+ value: nodeGlobalThis,
+ });
+}
- window.__bootstrap.internals = {
- ...window.__bootstrap.internals ?? {},
- node: {
- globalThis: nodeGlobalThis,
- initialize,
- nativeModuleExports,
- builtinModules,
- },
- };
-})(globalThis);
+internals.node = {
+ globalThis: nodeGlobalThis,
+ initialize,
+ nativeModuleExports,
+ builtinModules,
+};
diff --git a/ext/node/02_require.js b/ext/node/02_require.js
index bda74c01f..2b4a9c16c 100644
--- a/ext/node/02_require.js
+++ b/ext/node/02_require.js
@@ -2,943 +2,938 @@
// deno-lint-ignore-file
-"use strict";
-
-((window) => {
- const {
- ArrayIsArray,
- ArrayPrototypeIncludes,
- ArrayPrototypeIndexOf,
- ArrayPrototypeJoin,
- ArrayPrototypePush,
- ArrayPrototypeSlice,
- ArrayPrototypeSplice,
- ObjectGetOwnPropertyDescriptor,
- ObjectGetPrototypeOf,
- ObjectPrototypeHasOwnProperty,
- ObjectSetPrototypeOf,
- ObjectKeys,
- ObjectPrototype,
- ObjectCreate,
- Proxy,
- SafeMap,
- SafeWeakMap,
- SafeArrayIterator,
- JSONParse,
- String,
- StringPrototypeEndsWith,
- StringPrototypeIndexOf,
- StringPrototypeIncludes,
- StringPrototypeMatch,
- StringPrototypeSlice,
- StringPrototypeSplit,
- StringPrototypeStartsWith,
- StringPrototypeCharCodeAt,
- RegExpPrototypeTest,
- Error,
- TypeError,
- } = window.__bootstrap.primordials;
- const core = window.Deno.core;
- const ops = core.ops;
- const { node } = window.__bootstrap.internals;
-
- // Map used to store CJS parsing data.
- const cjsParseCache = new SafeWeakMap();
-
- function pathDirname(filepath) {
- if (filepath == null || filepath === "") {
- throw new Error("Empty filepath.");
- }
- return ops.op_require_path_dirname(filepath);
+const core = globalThis.Deno.core;
+const ops = core.ops;
+const internals = globalThis.__bootstrap.internals;
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayIsArray,
+ ArrayPrototypeIncludes,
+ ArrayPrototypeIndexOf,
+ ArrayPrototypeJoin,
+ ArrayPrototypePush,
+ ArrayPrototypeSlice,
+ ArrayPrototypeSplice,
+ ObjectGetOwnPropertyDescriptor,
+ ObjectGetPrototypeOf,
+ ObjectPrototypeHasOwnProperty,
+ ObjectSetPrototypeOf,
+ ObjectKeys,
+ ObjectPrototype,
+ ObjectCreate,
+ Proxy,
+ SafeMap,
+ SafeWeakMap,
+ SafeArrayIterator,
+ JSONParse,
+ String,
+ StringPrototypeEndsWith,
+ StringPrototypeIndexOf,
+ StringPrototypeIncludes,
+ StringPrototypeMatch,
+ StringPrototypeSlice,
+ StringPrototypeSplit,
+ StringPrototypeStartsWith,
+ StringPrototypeCharCodeAt,
+ RegExpPrototypeTest,
+ Error,
+ TypeError,
+} = primordials;
+const node = internals.node;
+
+// Map used to store CJS parsing data.
+const cjsParseCache = new SafeWeakMap();
+
+function pathDirname(filepath) {
+ if (filepath == null || filepath === "") {
+ throw new Error("Empty filepath.");
}
+ return ops.op_require_path_dirname(filepath);
+}
- function pathResolve(...args) {
- return ops.op_require_path_resolve(args);
- }
+function pathResolve(...args) {
+ return ops.op_require_path_resolve(args);
+}
- function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
+function assert(cond) {
+ if (!cond) {
+ throw Error("assert");
}
-
- const nativeModulePolyfill = new SafeMap();
-
- const relativeResolveCache = ObjectCreate(null);
- let requireDepth = 0;
- let statCache = null;
- let isPreloading = false;
- let mainModule = null;
- let hasBrokenOnInspectBrk = false;
- let hasInspectBrk = false;
- // Are we running with --node-modules-dir flag?
- let usesLocalNodeModulesDir = false;
-
- function stat(filename) {
- // TODO: required only on windows
- // filename = path.toNamespacedPath(filename);
- if (statCache !== null) {
- const result = statCache.get(filename);
- if (result !== undefined) {
- return result;
- }
- }
- const result = ops.op_require_stat(filename);
- if (statCache !== null && result >= 0) {
- statCache.set(filename, result);
+}
+
+const nativeModulePolyfill = new SafeMap();
+
+const relativeResolveCache = ObjectCreate(null);
+let requireDepth = 0;
+let statCache = null;
+let isPreloading = false;
+let mainModule = null;
+let hasBrokenOnInspectBrk = false;
+let hasInspectBrk = false;
+// Are we running with --node-modules-dir flag?
+let usesLocalNodeModulesDir = false;
+
+function stat(filename) {
+ // TODO: required only on windows
+ // filename = path.toNamespacedPath(filename);
+ if (statCache !== null) {
+ const result = statCache.get(filename);
+ if (result !== undefined) {
+ return result;
}
-
- return result;
+ }
+ const result = ops.op_require_stat(filename);
+ if (statCache !== null && result >= 0) {
+ statCache.set(filename, result);
}
- function updateChildren(parent, child, scan) {
- if (!parent) {
- return;
- }
+ return result;
+}
- const children = parent.children;
- if (children && !(scan && ArrayPrototypeIncludes(children, child))) {
- ArrayPrototypePush(children, child);
- }
+function updateChildren(parent, child, scan) {
+ if (!parent) {
+ return;
}
- function tryFile(requestPath, _isMain) {
- const rc = stat(requestPath);
- if (rc !== 0) return;
- return toRealPath(requestPath);
+ const children = parent.children;
+ if (children && !(scan && ArrayPrototypeIncludes(children, child))) {
+ ArrayPrototypePush(children, child);
+ }
+}
+
+function tryFile(requestPath, _isMain) {
+ const rc = stat(requestPath);
+ if (rc !== 0) return;
+ return toRealPath(requestPath);
+}
+
+function tryPackage(requestPath, exts, isMain, originalPath) {
+ const packageJsonPath = pathResolve(
+ requestPath,
+ "package.json",
+ );
+ const pkg = ops.op_require_read_package_scope(packageJsonPath)?.main;
+ if (!pkg) {
+ return tryExtensions(
+ pathResolve(requestPath, "index"),
+ exts,
+ isMain,
+ );
}
- function tryPackage(requestPath, exts, isMain, originalPath) {
- const packageJsonPath = pathResolve(
- requestPath,
- "package.json",
+ const filename = pathResolve(requestPath, pkg);
+ let actual = tryFile(filename, isMain) ||
+ tryExtensions(filename, exts, isMain) ||
+ tryExtensions(
+ pathResolve(filename, "index"),
+ exts,
+ isMain,
+ );
+ if (actual === false) {
+ actual = tryExtensions(
+ pathResolve(requestPath, "index"),
+ exts,
+ isMain,
);
- const pkg = core.ops.op_require_read_package_scope(packageJsonPath)?.main;
- if (!pkg) {
- return tryExtensions(
- pathResolve(requestPath, "index"),
- exts,
- isMain,
+ if (!actual) {
+ // eslint-disable-next-line no-restricted-syntax
+ const err = new Error(
+ `Cannot find module '${filename}'. ` +
+ 'Please verify that the package.json has a valid "main" entry',
);
- }
-
- const filename = pathResolve(requestPath, pkg);
- let actual = tryFile(filename, isMain) ||
- tryExtensions(filename, exts, isMain) ||
- tryExtensions(
- pathResolve(filename, "index"),
- exts,
- isMain,
+ err.code = "MODULE_NOT_FOUND";
+ err.path = pathResolve(
+ requestPath,
+ "package.json",
);
- if (actual === false) {
- actual = tryExtensions(
- pathResolve(requestPath, "index"),
- exts,
- isMain,
+ err.requestPath = originalPath;
+ throw err;
+ } else {
+ node.globalThis.process.emitWarning(
+ `Invalid 'main' field in '${packageJsonPath}' of '${pkg}'. ` +
+ "Please either fix that or report it to the module author",
+ "DeprecationWarning",
+ "DEP0128",
);
- if (!actual) {
- // eslint-disable-next-line no-restricted-syntax
- const err = new Error(
- `Cannot find module '${filename}'. ` +
- 'Please verify that the package.json has a valid "main" entry',
- );
- err.code = "MODULE_NOT_FOUND";
- err.path = pathResolve(
- requestPath,
- "package.json",
- );
- err.requestPath = originalPath;
- throw err;
- } else {
- node.globalThis.process.emitWarning(
- `Invalid 'main' field in '${packageJsonPath}' of '${pkg}'. ` +
- "Please either fix that or report it to the module author",
- "DeprecationWarning",
- "DEP0128",
- );
- }
}
- return actual;
}
-
- const realpathCache = new SafeMap();
- function toRealPath(requestPath) {
- const maybeCached = realpathCache.get(requestPath);
- if (maybeCached) {
- return maybeCached;
- }
- const rp = ops.op_require_real_path(requestPath);
- realpathCache.set(requestPath, rp);
- return rp;
+ return actual;
+}
+
+const realpathCache = new SafeMap();
+function toRealPath(requestPath) {
+ const maybeCached = realpathCache.get(requestPath);
+ if (maybeCached) {
+ return maybeCached;
}
+ const rp = ops.op_require_real_path(requestPath);
+ realpathCache.set(requestPath, rp);
+ return rp;
+}
- function tryExtensions(p, exts, isMain) {
- for (let i = 0; i < exts.length; i++) {
- const filename = tryFile(p + exts[i], isMain);
+function tryExtensions(p, exts, isMain) {
+ for (let i = 0; i < exts.length; i++) {
+ const filename = tryFile(p + exts[i], isMain);
- if (filename) {
- return filename;
- }
+ if (filename) {
+ return filename;
}
- return false;
}
-
- // Find the longest (possibly multi-dot) extension registered in
- // Module._extensions
- function findLongestRegisteredExtension(filename) {
- const name = ops.op_require_path_basename(filename);
- let currentExtension;
- let index;
- let startIndex = 0;
- while ((index = StringPrototypeIndexOf(name, ".", startIndex)) !== -1) {
- startIndex = index + 1;
- if (index === 0) continue; // Skip dotfiles like .gitignore
- currentExtension = StringPrototypeSlice(name, index);
- if (Module._extensions[currentExtension]) {
- return currentExtension;
- }
+ return false;
+}
+
+// Find the longest (possibly multi-dot) extension registered in
+// Module._extensions
+function findLongestRegisteredExtension(filename) {
+ const name = ops.op_require_path_basename(filename);
+ let currentExtension;
+ let index;
+ let startIndex = 0;
+ while ((index = StringPrototypeIndexOf(name, ".", startIndex)) !== -1) {
+ startIndex = index + 1;
+ if (index === 0) continue; // Skip dotfiles like .gitignore
+ currentExtension = StringPrototypeSlice(name, index);
+ if (Module._extensions[currentExtension]) {
+ return currentExtension;
}
- return ".js";
}
+ return ".js";
+}
+
+function getExportsForCircularRequire(module) {
+ if (
+ module.exports &&
+ ObjectGetPrototypeOf(module.exports) === ObjectPrototype &&
+ // Exclude transpiled ES6 modules / TypeScript code because those may
+ // employ unusual patterns for accessing 'module.exports'. That should
+ // be okay because ES6 modules have a different approach to circular
+ // dependencies anyway.
+ !module.exports.__esModule
+ ) {
+ // This is later unset once the module is done loading.
+ ObjectSetPrototypeOf(
+ module.exports,
+ CircularRequirePrototypeWarningProxy,
+ );
+ }
+
+ return module.exports;
+}
+
+function emitCircularRequireWarning(prop) {
+ node.globalThis.process.emitWarning(
+ `Accessing non-existent property '${String(prop)}' of module exports ` +
+ "inside circular dependency",
+ );
+}
+
+// A Proxy that can be used as the prototype of a module.exports object and
+// warns when non-existent properties are accessed.
+const CircularRequirePrototypeWarningProxy = new Proxy({}, {
+ get(target, prop) {
+ // Allow __esModule access in any case because it is used in the output
+ // of transpiled code to determine whether something comes from an
+ // ES module, and is not used as a regular key of `module.exports`.
+ if (prop in target || prop === "__esModule") return target[prop];
+ emitCircularRequireWarning(prop);
+ return undefined;
+ },
- function getExportsForCircularRequire(module) {
+ getOwnPropertyDescriptor(target, prop) {
if (
- module.exports &&
- ObjectGetPrototypeOf(module.exports) === ObjectPrototype &&
- // Exclude transpiled ES6 modules / TypeScript code because those may
- // employ unusual patterns for accessing 'module.exports'. That should
- // be okay because ES6 modules have a different approach to circular
- // dependencies anyway.
- !module.exports.__esModule
+ ObjectPrototypeHasOwnProperty(target, prop) || prop === "__esModule"
) {
- // This is later unset once the module is done loading.
- ObjectSetPrototypeOf(
- module.exports,
- CircularRequirePrototypeWarningProxy,
- );
+ return ObjectGetOwnPropertyDescriptor(target, prop);
}
-
- return module.exports;
- }
-
- function emitCircularRequireWarning(prop) {
- node.globalThis.process.emitWarning(
- `Accessing non-existent property '${String(prop)}' of module exports ` +
- "inside circular dependency",
+ emitCircularRequireWarning(prop);
+ return undefined;
+ },
+});
+
+const moduleParentCache = new SafeWeakMap();
+function Module(id = "", parent) {
+ this.id = id;
+ this.path = pathDirname(id);
+ this.exports = {};
+ moduleParentCache.set(this, parent);
+ updateChildren(parent, this, false);
+ this.filename = null;
+ this.loaded = false;
+ this.children = [];
+}
+
+Module.builtinModules = node.builtinModules;
+
+Module._extensions = ObjectCreate(null);
+Module._cache = ObjectCreate(null);
+Module._pathCache = ObjectCreate(null);
+let modulePaths = [];
+Module.globalPaths = modulePaths;
+
+const CHAR_FORWARD_SLASH = 47;
+const TRAILING_SLASH_REGEX = /(?:^|\/)\.?\.$/;
+const encodedSepRegEx = /%2F|%2C/i;
+
+function finalizeEsmResolution(
+ resolved,
+ parentPath,
+ pkgPath,
+) {
+ if (RegExpPrototypeTest(encodedSepRegEx, resolved)) {
+ throw new ERR_INVALID_MODULE_SPECIFIER(
+ resolved,
+ 'must not include encoded "/" or "\\" characters',
+ parentPath,
);
}
-
- // A Proxy that can be used as the prototype of a module.exports object and
- // warns when non-existent properties are accessed.
- const CircularRequirePrototypeWarningProxy = new Proxy({}, {
- get(target, prop) {
- // Allow __esModule access in any case because it is used in the output
- // of transpiled code to determine whether something comes from an
- // ES module, and is not used as a regular key of `module.exports`.
- if (prop in target || prop === "__esModule") return target[prop];
- emitCircularRequireWarning(prop);
- return undefined;
- },
-
- getOwnPropertyDescriptor(target, prop) {
- if (
- ObjectPrototypeHasOwnProperty(target, prop) || prop === "__esModule"
- ) {
- return ObjectGetOwnPropertyDescriptor(target, prop);
- }
- emitCircularRequireWarning(prop);
- return undefined;
- },
- });
-
- const moduleParentCache = new SafeWeakMap();
- function Module(id = "", parent) {
- this.id = id;
- this.path = pathDirname(id);
- this.exports = {};
- moduleParentCache.set(this, parent);
- updateChildren(parent, this, false);
- this.filename = null;
- this.loaded = false;
- this.children = [];
- }
-
- Module.builtinModules = node.builtinModules;
-
- Module._extensions = ObjectCreate(null);
- Module._cache = ObjectCreate(null);
- Module._pathCache = ObjectCreate(null);
- let modulePaths = [];
- Module.globalPaths = modulePaths;
-
- const CHAR_FORWARD_SLASH = 47;
- const TRAILING_SLASH_REGEX = /(?:^|\/)\.?\.$/;
- const encodedSepRegEx = /%2F|%2C/i;
-
- function finalizeEsmResolution(
- resolved,
- parentPath,
- pkgPath,
- ) {
- if (RegExpPrototypeTest(encodedSepRegEx, resolved)) {
- throw new ERR_INVALID_MODULE_SPECIFIER(
- resolved,
- 'must not include encoded "/" or "\\" characters',
- parentPath,
- );
- }
- // const filename = fileURLToPath(resolved);
- const filename = resolved;
- const actual = tryFile(filename, false);
- if (actual) {
- return actual;
- }
- throw new ERR_MODULE_NOT_FOUND(
- filename,
- path.resolve(pkgPath, "package.json"),
- );
+ // const filename = fileURLToPath(resolved);
+ const filename = resolved;
+ const actual = tryFile(filename, false);
+ if (actual) {
+ return actual;
+ }
+ throw new ERR_MODULE_NOT_FOUND(
+ filename,
+ path.resolve(pkgPath, "package.json"),
+ );
+}
+
+// This only applies to requests of a specific form:
+// 1. name/.*
+// 2. @scope/name/.*
+const EXPORTS_PATTERN = /^((?:@[^/\\%]+\/)?[^./\\%][^/\\%]*)(\/.*)?$/;
+function resolveExports(
+ modulesPath,
+ request,
+ parentPath,
+ usesLocalNodeModulesDir,
+) {
+ // The implementation's behavior is meant to mirror resolution in ESM.
+ const [, name, expansion = ""] =
+ StringPrototypeMatch(request, EXPORTS_PATTERN) || [];
+ if (!name) {
+ return;
}
- // This only applies to requests of a specific form:
- // 1. name/.*
- // 2. @scope/name/.*
- const EXPORTS_PATTERN = /^((?:@[^/\\%]+\/)?[^./\\%][^/\\%]*)(\/.*)?$/;
- function resolveExports(
+ return ops.op_require_resolve_exports(
+ usesLocalNodeModulesDir,
modulesPath,
request,
+ name,
+ expansion,
parentPath,
- usesLocalNodeModulesDir,
- ) {
- // The implementation's behavior is meant to mirror resolution in ESM.
- const [, name, expansion = ""] =
- StringPrototypeMatch(request, EXPORTS_PATTERN) || [];
- if (!name) {
- return;
- }
-
- return core.ops.op_require_resolve_exports(
- usesLocalNodeModulesDir,
- modulesPath,
- request,
- name,
- expansion,
- parentPath,
- ) ?? false;
+ ) ?? false;
+}
+
+Module._findPath = function (request, paths, isMain, parentPath) {
+ const absoluteRequest = ops.op_require_path_is_absolute(request);
+ if (absoluteRequest) {
+ paths = [""];
+ } else if (!paths || paths.length === 0) {
+ return false;
}
- Module._findPath = function (request, paths, isMain, parentPath) {
- const absoluteRequest = ops.op_require_path_is_absolute(request);
- if (absoluteRequest) {
- paths = [""];
- } else if (!paths || paths.length === 0) {
- return false;
- }
-
- const cacheKey = request + "\x00" + ArrayPrototypeJoin(paths, "\x00");
- const entry = Module._pathCache[cacheKey];
- if (entry) {
- return entry;
- }
+ const cacheKey = request + "\x00" + ArrayPrototypeJoin(paths, "\x00");
+ const entry = Module._pathCache[cacheKey];
+ if (entry) {
+ return entry;
+ }
- let exts;
- let trailingSlash = request.length > 0 &&
- StringPrototypeCharCodeAt(request, request.length - 1) ===
- CHAR_FORWARD_SLASH;
- if (!trailingSlash) {
- trailingSlash = RegExpPrototypeTest(TRAILING_SLASH_REGEX, request);
- }
+ let exts;
+ let trailingSlash = request.length > 0 &&
+ StringPrototypeCharCodeAt(request, request.length - 1) ===
+ CHAR_FORWARD_SLASH;
+ if (!trailingSlash) {
+ trailingSlash = RegExpPrototypeTest(TRAILING_SLASH_REGEX, request);
+ }
- // For each path
- for (let i = 0; i < paths.length; i++) {
- // Don't search further if path doesn't exist
- const curPath = paths[i];
- if (curPath && stat(curPath) < 1) continue;
-
- if (!absoluteRequest) {
- const exportsResolved = resolveExports(
- curPath,
- request,
- parentPath,
- usesLocalNodeModulesDir,
- );
- if (exportsResolved) {
- return exportsResolved;
- }
- }
+ // For each path
+ for (let i = 0; i < paths.length; i++) {
+ // Don't search further if path doesn't exist
+ const curPath = paths[i];
+ if (curPath && stat(curPath) < 1) continue;
- const isDenoDirPackage = core.ops.op_require_is_deno_dir_package(
+ if (!absoluteRequest) {
+ const exportsResolved = resolveExports(
curPath,
- );
- const isRelative = ops.op_require_is_request_relative(
request,
+ parentPath,
+ usesLocalNodeModulesDir,
);
- const basePath =
- (isDenoDirPackage && !isRelative && !usesLocalNodeModulesDir)
- ? pathResolve(curPath, packageSpecifierSubPath(request))
- : pathResolve(curPath, request);
- let filename;
-
- const rc = stat(basePath);
- if (!trailingSlash) {
- if (rc === 0) { // File.
- filename = toRealPath(basePath);
- }
+ if (exportsResolved) {
+ return exportsResolved;
+ }
+ }
- if (!filename) {
- // Try it with each of the extensions
- if (exts === undefined) {
- exts = ObjectKeys(Module._extensions);
- }
- filename = tryExtensions(basePath, exts, isMain);
- }
+ const isDenoDirPackage = ops.op_require_is_deno_dir_package(
+ curPath,
+ );
+ const isRelative = ops.op_require_is_request_relative(
+ request,
+ );
+ const basePath =
+ (isDenoDirPackage && !isRelative && !usesLocalNodeModulesDir)
+ ? pathResolve(curPath, packageSpecifierSubPath(request))
+ : pathResolve(curPath, request);
+ let filename;
+
+ const rc = stat(basePath);
+ if (!trailingSlash) {
+ if (rc === 0) { // File.
+ filename = toRealPath(basePath);
}
- if (!filename && rc === 1) { // Directory.
- // try it with each of the extensions at "index"
+ if (!filename) {
+ // Try it with each of the extensions
if (exts === undefined) {
exts = ObjectKeys(Module._extensions);
}
- filename = tryPackage(basePath, exts, isMain, request);
+ filename = tryExtensions(basePath, exts, isMain);
}
+ }
- if (filename) {
- Module._pathCache[cacheKey] = filename;
- return filename;
+ if (!filename && rc === 1) { // Directory.
+ // try it with each of the extensions at "index"
+ if (exts === undefined) {
+ exts = ObjectKeys(Module._extensions);
}
+ filename = tryPackage(basePath, exts, isMain, request);
}
- return false;
- };
+ if (filename) {
+ Module._pathCache[cacheKey] = filename;
+ return filename;
+ }
+ }
- Module._nodeModulePaths = function (fromPath) {
- return ops.op_require_node_module_paths(fromPath);
- };
+ return false;
+};
- Module._resolveLookupPaths = function (request, parent) {
- const paths = [];
+Module._nodeModulePaths = function (fromPath) {
+ return ops.op_require_node_module_paths(fromPath);
+};
- if (core.ops.op_require_is_request_relative(request) && parent?.filename) {
- ArrayPrototypePush(
- paths,
- core.ops.op_require_path_dirname(parent.filename),
- );
- return paths;
- }
+Module._resolveLookupPaths = function (request, parent) {
+ const paths = [];
- if (parent?.filename && parent.filename.length > 0) {
- const denoDirPath = core.ops.op_require_resolve_deno_dir(
- request,
- parent.filename,
- );
- if (denoDirPath) {
- ArrayPrototypePush(paths, denoDirPath);
- }
- }
- const lookupPathsResult = ops.op_require_resolve_lookup_paths(
- request,
- parent?.paths,
- parent?.filename ?? "",
+ if (ops.op_require_is_request_relative(request) && parent?.filename) {
+ ArrayPrototypePush(
+ paths,
+ ops.op_require_path_dirname(parent.filename),
);
- if (lookupPathsResult) {
- ArrayPrototypePush(paths, ...new SafeArrayIterator(lookupPathsResult));
- }
return paths;
- };
+ }
- Module._load = function (request, parent, isMain) {
- let relResolveCacheIdentifier;
- if (parent) {
- // Fast path for (lazy loaded) modules in the same directory. The indirect
- // caching is required to allow cache invalidation without changing the old
- // cache key names.
- relResolveCacheIdentifier = `${parent.path}\x00${request}`;
- const filename = relativeResolveCache[relResolveCacheIdentifier];
- if (filename !== undefined) {
- const cachedModule = Module._cache[filename];
- if (cachedModule !== undefined) {
- updateChildren(parent, cachedModule, true);
- if (!cachedModule.loaded) {
- return getExportsForCircularRequire(cachedModule);
- }
- return cachedModule.exports;
+ if (parent?.filename && parent.filename.length > 0) {
+ const denoDirPath = ops.op_require_resolve_deno_dir(
+ request,
+ parent.filename,
+ );
+ if (denoDirPath) {
+ ArrayPrototypePush(paths, denoDirPath);
+ }
+ }
+ const lookupPathsResult = ops.op_require_resolve_lookup_paths(
+ request,
+ parent?.paths,
+ parent?.filename ?? "",
+ );
+ if (lookupPathsResult) {
+ ArrayPrototypePush(paths, ...new SafeArrayIterator(lookupPathsResult));
+ }
+ return paths;
+};
+
+Module._load = function (request, parent, isMain) {
+ let relResolveCacheIdentifier;
+ if (parent) {
+ // Fast path for (lazy loaded) modules in the same directory. The indirect
+ // caching is required to allow cache invalidation without changing the old
+ // cache key names.
+ relResolveCacheIdentifier = `${parent.path}\x00${request}`;
+ const filename = relativeResolveCache[relResolveCacheIdentifier];
+ if (filename !== undefined) {
+ const cachedModule = Module._cache[filename];
+ if (cachedModule !== undefined) {
+ updateChildren(parent, cachedModule, true);
+ if (!cachedModule.loaded) {
+ return getExportsForCircularRequire(cachedModule);
}
- delete relativeResolveCache[relResolveCacheIdentifier];
+ return cachedModule.exports;
}
+ delete relativeResolveCache[relResolveCacheIdentifier];
}
+ }
- const filename = Module._resolveFilename(request, parent, isMain);
- if (StringPrototypeStartsWith(filename, "node:")) {
- // Slice 'node:' prefix
- const id = StringPrototypeSlice(filename, 5);
-
- const module = loadNativeModule(id, id);
- if (!module) {
- // TODO:
- // throw new ERR_UNKNOWN_BUILTIN_MODULE(filename);
- throw new Error("Unknown built-in module");
- }
+ const filename = Module._resolveFilename(request, parent, isMain);
+ if (StringPrototypeStartsWith(filename, "node:")) {
+ // Slice 'node:' prefix
+ const id = StringPrototypeSlice(filename, 5);
- return module.exports;
+ const module = loadNativeModule(id, id);
+ if (!module) {
+ // TODO:
+ // throw new ERR_UNKNOWN_BUILTIN_MODULE(filename);
+ throw new Error("Unknown built-in module");
}
- const cachedModule = Module._cache[filename];
- if (cachedModule !== undefined) {
- updateChildren(parent, cachedModule, true);
- if (!cachedModule.loaded) {
- return getExportsForCircularRequire(cachedModule);
- }
- return cachedModule.exports;
- }
+ return module.exports;
+ }
- const mod = loadNativeModule(filename, request);
- if (
- mod
- ) {
- return mod.exports;
+ const cachedModule = Module._cache[filename];
+ if (cachedModule !== undefined) {
+ updateChildren(parent, cachedModule, true);
+ if (!cachedModule.loaded) {
+ return getExportsForCircularRequire(cachedModule);
}
- // Don't call updateChildren(), Module constructor already does.
- const module = cachedModule || new Module(filename, parent);
+ return cachedModule.exports;
+ }
- if (isMain) {
- node.globalThis.process.mainModule = module;
- mainModule = module;
- module.id = ".";
- }
+ const mod = loadNativeModule(filename, request);
+ if (
+ mod
+ ) {
+ return mod.exports;
+ }
+ // Don't call updateChildren(), Module constructor already does.
+ const module = cachedModule || new Module(filename, parent);
- Module._cache[filename] = module;
- if (parent !== undefined) {
- relativeResolveCache[relResolveCacheIdentifier] = filename;
- }
+ if (isMain) {
+ node.globalThis.process.mainModule = module;
+ mainModule = module;
+ module.id = ".";
+ }
- let threw = true;
- try {
- module.load(filename);
- threw = false;
- } finally {
- if (threw) {
- delete Module._cache[filename];
- if (parent !== undefined) {
- delete relativeResolveCache[relResolveCacheIdentifier];
- const children = parent?.children;
- if (ArrayIsArray(children)) {
- const index = ArrayPrototypeIndexOf(children, module);
- if (index !== -1) {
- ArrayPrototypeSplice(children, index, 1);
- }
+ Module._cache[filename] = module;
+ if (parent !== undefined) {
+ relativeResolveCache[relResolveCacheIdentifier] = filename;
+ }
+
+ let threw = true;
+ try {
+ module.load(filename);
+ threw = false;
+ } finally {
+ if (threw) {
+ delete Module._cache[filename];
+ if (parent !== undefined) {
+ delete relativeResolveCache[relResolveCacheIdentifier];
+ const children = parent?.children;
+ if (ArrayIsArray(children)) {
+ const index = ArrayPrototypeIndexOf(children, module);
+ if (index !== -1) {
+ ArrayPrototypeSplice(children, index, 1);
}
}
- } else if (
- module.exports &&
- ObjectGetPrototypeOf(module.exports) ===
- CircularRequirePrototypeWarningProxy
- ) {
- ObjectSetPrototypeOf(module.exports, ObjectPrototype);
}
+ } else if (
+ module.exports &&
+ ObjectGetPrototypeOf(module.exports) ===
+ CircularRequirePrototypeWarningProxy
+ ) {
+ ObjectSetPrototypeOf(module.exports, ObjectPrototype);
}
+ }
- return module.exports;
- };
-
- Module._resolveFilename = function (
- request,
- parent,
- isMain,
- options,
+ return module.exports;
+};
+
+Module._resolveFilename = function (
+ request,
+ parent,
+ isMain,
+ options,
+) {
+ if (
+ StringPrototypeStartsWith(request, "node:") ||
+ nativeModuleCanBeRequiredByUsers(request)
) {
- if (
- StringPrototypeStartsWith(request, "node:") ||
- nativeModuleCanBeRequiredByUsers(request)
- ) {
- return request;
- }
+ return request;
+ }
- let paths;
+ let paths;
- if (typeof options === "object" && options !== null) {
- if (ArrayIsArray(options.paths)) {
- const isRelative = ops.op_require_is_request_relative(
- request,
- );
+ if (typeof options === "object" && options !== null) {
+ if (ArrayIsArray(options.paths)) {
+ const isRelative = ops.op_require_is_request_relative(
+ request,
+ );
- if (isRelative) {
- paths = options.paths;
- } else {
- const fakeParent = new Module("", null);
+ if (isRelative) {
+ paths = options.paths;
+ } else {
+ const fakeParent = new Module("", null);
- paths = [];
+ paths = [];
- for (let i = 0; i < options.paths.length; i++) {
- const path = options.paths[i];
- fakeParent.paths = Module._nodeModulePaths(path);
- const lookupPaths = Module._resolveLookupPaths(request, fakeParent);
+ for (let i = 0; i < options.paths.length; i++) {
+ const path = options.paths[i];
+ fakeParent.paths = Module._nodeModulePaths(path);
+ const lookupPaths = Module._resolveLookupPaths(request, fakeParent);
- for (let j = 0; j < lookupPaths.length; j++) {
- if (!ArrayPrototypeIncludes(paths, lookupPaths[j])) {
- ArrayPrototypePush(paths, lookupPaths[j]);
- }
+ for (let j = 0; j < lookupPaths.length; j++) {
+ if (!ArrayPrototypeIncludes(paths, lookupPaths[j])) {
+ ArrayPrototypePush(paths, lookupPaths[j]);
}
}
}
- } else if (options.paths === undefined) {
- paths = Module._resolveLookupPaths(request, parent);
- } else {
- // TODO:
- // throw new ERR_INVALID_ARG_VALUE("options.paths", options.paths);
- throw new Error("Invalid arg value options.paths", options.path);
}
- } else {
+ } else if (options.paths === undefined) {
paths = Module._resolveLookupPaths(request, parent);
+ } else {
+ // TODO:
+ // throw new ERR_INVALID_ARG_VALUE("options.paths", options.paths);
+ throw new Error("Invalid arg value options.paths", options.path);
}
+ } else {
+ paths = Module._resolveLookupPaths(request, parent);
+ }
- if (parent?.filename) {
- if (request[0] === "#") {
- const maybeResolved = core.ops.op_require_package_imports_resolve(
- parent.filename,
- request,
- );
- if (maybeResolved) {
- return maybeResolved;
- }
+ if (parent?.filename) {
+ if (request[0] === "#") {
+ const maybeResolved = ops.op_require_package_imports_resolve(
+ parent.filename,
+ request,
+ );
+ if (maybeResolved) {
+ return maybeResolved;
}
}
+ }
- // Try module self resolution first
- const parentPath = ops.op_require_try_self_parent_path(
- !!parent,
- parent?.filename,
- parent?.id,
- );
- const selfResolved = ops.op_require_try_self(parentPath, request);
- if (selfResolved) {
- const cacheKey = request + "\x00" +
- (paths.length === 1 ? paths[0] : ArrayPrototypeJoin(paths, "\x00"));
- Module._pathCache[cacheKey] = selfResolved;
- return selfResolved;
- }
-
- // Look up the filename first, since that's the cache key.
- const filename = Module._findPath(
- request,
- paths,
- isMain,
- parentPath,
- );
- if (filename) return filename;
- const requireStack = [];
- for (let cursor = parent; cursor; cursor = moduleParentCache.get(cursor)) {
- ArrayPrototypePush(requireStack, cursor.filename || cursor.id);
- }
- let message = `Cannot find module '${request}'`;
- if (requireStack.length > 0) {
- message = message + "\nRequire stack:\n- " +
- ArrayPrototypeJoin(requireStack, "\n- ");
- }
- // eslint-disable-next-line no-restricted-syntax
- const err = new Error(message);
- err.code = "MODULE_NOT_FOUND";
- err.requireStack = requireStack;
- throw err;
- };
-
- Module.prototype.load = function (filename) {
- assert(!this.loaded);
- this.filename = filename;
- this.paths = Module._nodeModulePaths(
- pathDirname(filename),
- );
- const extension = findLongestRegisteredExtension(filename);
- // allow .mjs to be overriden
- if (
- StringPrototypeEndsWith(filename, ".mjs") && !Module._extensions[".mjs"]
- ) {
- // TODO: use proper error class
- throw new Error("require ESM", filename);
- }
-
- Module._extensions[extension](this, filename);
- this.loaded = true;
-
- // TODO: do caching
- };
-
- // Loads a module at the given file path. Returns that module's
- // `exports` property.
- Module.prototype.require = function (id) {
- if (typeof id !== "string") {
- // TODO(bartlomieju): it should use different error type
- // ("ERR_INVALID_ARG_VALUE")
- throw new TypeError("Invalid argument type");
- }
-
- if (id === "") {
- // TODO(bartlomieju): it should use different error type
- // ("ERR_INVALID_ARG_VALUE")
- throw new TypeError("id must be non empty");
- }
- requireDepth++;
- try {
- return Module._load(id, this, /* isMain */ false);
- } finally {
- requireDepth--;
- }
- };
-
- Module.wrapper = [
- // We provide the non-standard APIs in the CommonJS wrapper
- // to avoid exposing them in global namespace.
- "(function (exports, require, module, __filename, __dirname, globalThis) { const { Buffer, clearImmediate, clearInterval, clearTimeout, console, global, process, setImmediate, setInterval, setTimeout} = globalThis; var window = undefined; (function () {",
- "\n}).call(this); })",
- ];
- Module.wrap = function (script) {
- script = script.replace(/^#!.*?\n/, "");
- return `${Module.wrapper[0]}${script}${Module.wrapper[1]}`;
- };
-
- function enrichCJSError(error) {
- if (error instanceof SyntaxError) {
- if (
- StringPrototypeIncludes(
- error.message,
- "Cannot use import statement outside a module",
- ) ||
- StringPrototypeIncludes(error.message, "Unexpected token 'export'")
- ) {
- console.error(
- 'To load an ES module, set "type": "module" in the package.json or use ' +
- "the .mjs extension.",
- );
- }
- }
+ // Try module self resolution first
+ const parentPath = ops.op_require_try_self_parent_path(
+ !!parent,
+ parent?.filename,
+ parent?.id,
+ );
+ const selfResolved = ops.op_require_try_self(parentPath, request);
+ if (selfResolved) {
+ const cacheKey = request + "\x00" +
+ (paths.length === 1 ? paths[0] : ArrayPrototypeJoin(paths, "\x00"));
+ Module._pathCache[cacheKey] = selfResolved;
+ return selfResolved;
}
- function wrapSafe(
- filename,
- content,
- cjsModuleInstance,
+ // Look up the filename first, since that's the cache key.
+ const filename = Module._findPath(
+ request,
+ paths,
+ isMain,
+ parentPath,
+ );
+ if (filename) return filename;
+ const requireStack = [];
+ for (let cursor = parent; cursor; cursor = moduleParentCache.get(cursor)) {
+ ArrayPrototypePush(requireStack, cursor.filename || cursor.id);
+ }
+ let message = `Cannot find module '${request}'`;
+ if (requireStack.length > 0) {
+ message = message + "\nRequire stack:\n- " +
+ ArrayPrototypeJoin(requireStack, "\n- ");
+ }
+ // eslint-disable-next-line no-restricted-syntax
+ const err = new Error(message);
+ err.code = "MODULE_NOT_FOUND";
+ err.requireStack = requireStack;
+ throw err;
+};
+
+Module.prototype.load = function (filename) {
+ assert(!this.loaded);
+ this.filename = filename;
+ this.paths = Module._nodeModulePaths(
+ pathDirname(filename),
+ );
+ const extension = findLongestRegisteredExtension(filename);
+ // allow .mjs to be overriden
+ if (
+ StringPrototypeEndsWith(filename, ".mjs") && !Module._extensions[".mjs"]
) {
- const wrapper = Module.wrap(content);
- const [f, err] = core.evalContext(wrapper, filename);
- if (err) {
- if (node.globalThis.process.mainModule === cjsModuleInstance) {
- enrichCJSError(err.thrown);
- }
- throw err.thrown;
- }
- return f;
+ // TODO: use proper error class
+ throw new Error("require ESM", filename);
}
- Module.prototype._compile = function (content, filename) {
- const compiledWrapper = wrapSafe(filename, content, this);
+ Module._extensions[extension](this, filename);
+ this.loaded = true;
- const dirname = pathDirname(filename);
- const require = makeRequireFunction(this);
- const exports = this.exports;
- const thisValue = exports;
- const module = this;
- if (requireDepth === 0) {
- statCache = new SafeMap();
- }
+ // TODO: do caching
+};
- if (hasInspectBrk && !hasBrokenOnInspectBrk) {
- hasBrokenOnInspectBrk = true;
- core.ops.op_require_break_on_next_statement();
- }
+// Loads a module at the given file path. Returns that module's
+// `exports` property.
+Module.prototype.require = function (id) {
+ if (typeof id !== "string") {
+ // TODO(bartlomieju): it should use different error type
+ // ("ERR_INVALID_ARG_VALUE")
+ throw new TypeError("Invalid argument type");
+ }
- const result = compiledWrapper.call(
- thisValue,
- exports,
- require,
- this,
- filename,
- dirname,
- node.globalThis,
- );
- if (requireDepth === 0) {
- statCache = null;
+ if (id === "") {
+ // TODO(bartlomieju): it should use different error type
+ // ("ERR_INVALID_ARG_VALUE")
+ throw new TypeError("id must be non empty");
+ }
+ requireDepth++;
+ try {
+ return Module._load(id, this, /* isMain */ false);
+ } finally {
+ requireDepth--;
+ }
+};
+
+Module.wrapper = [
+ // We provide the non-standard APIs in the CommonJS wrapper
+ // to avoid exposing them in global namespace.
+ "(function (exports, require, module, __filename, __dirname, globalThis) { const { Buffer, clearImmediate, clearInterval, clearTimeout, console, global, process, setImmediate, setInterval, setTimeout} = globalThis; var window = undefined; (function () {",
+ "\n}).call(this); })",
+];
+Module.wrap = function (script) {
+ script = script.replace(/^#!.*?\n/, "");
+ return `${Module.wrapper[0]}${script}${Module.wrapper[1]}`;
+};
+
+function enrichCJSError(error) {
+ if (error instanceof SyntaxError) {
+ if (
+ StringPrototypeIncludes(
+ error.message,
+ "Cannot use import statement outside a module",
+ ) ||
+ StringPrototypeIncludes(error.message, "Unexpected token 'export'")
+ ) {
+ console.error(
+ 'To load an ES module, set "type": "module" in the package.json or use ' +
+ "the .mjs extension.",
+ );
}
- return result;
- };
+ }
+}
+
+function wrapSafe(
+ filename,
+ content,
+ cjsModuleInstance,
+) {
+ const wrapper = Module.wrap(content);
+ const [f, err] = core.evalContext(wrapper, filename);
+ if (err) {
+ if (node.globalThis.process.mainModule === cjsModuleInstance) {
+ enrichCJSError(err.thrown);
+ }
+ throw err.thrown;
+ }
+ return f;
+}
+
+Module.prototype._compile = function (content, filename) {
+ const compiledWrapper = wrapSafe(filename, content, this);
+
+ const dirname = pathDirname(filename);
+ const require = makeRequireFunction(this);
+ const exports = this.exports;
+ const thisValue = exports;
+ const module = this;
+ if (requireDepth === 0) {
+ statCache = new SafeMap();
+ }
- Module._extensions[".js"] = function (module, filename) {
- const content = ops.op_require_read_file(filename);
+ if (hasInspectBrk && !hasBrokenOnInspectBrk) {
+ hasBrokenOnInspectBrk = true;
+ ops.op_require_break_on_next_statement();
+ }
- if (StringPrototypeEndsWith(filename, ".js")) {
- const pkg = core.ops.op_require_read_closest_package_json(filename);
- if (pkg && pkg.exists && pkg.typ == "module") {
- let message = `Trying to import ESM module: ${filename}`;
+ const result = compiledWrapper.call(
+ thisValue,
+ exports,
+ require,
+ this,
+ filename,
+ dirname,
+ node.globalThis,
+ );
+ if (requireDepth === 0) {
+ statCache = null;
+ }
+ return result;
+};
- if (module.parent) {
- message += ` from ${module.parent.filename}`;
- }
+Module._extensions[".js"] = function (module, filename) {
+ const content = ops.op_require_read_file(filename);
- message += ` using require()`;
+ if (StringPrototypeEndsWith(filename, ".js")) {
+ const pkg = ops.op_require_read_closest_package_json(filename);
+ if (pkg && pkg.exists && pkg.typ == "module") {
+ let message = `Trying to import ESM module: ${filename}`;
- throw new Error(message);
+ if (module.parent) {
+ message += ` from ${module.parent.filename}`;
}
- }
- module._compile(content, filename);
- };
+ message += ` using require()`;
- function stripBOM(content) {
- if (StringPrototypeCharCodeAt(content, 0) === 0xfeff) {
- content = StringPrototypeSlice(content, 1);
+ throw new Error(message);
}
- return content;
}
- // Native extension for .json
- Module._extensions[".json"] = function (module, filename) {
- const content = ops.op_require_read_file(filename);
-
- try {
- module.exports = JSONParse(stripBOM(content));
- } catch (err) {
- err.message = filename + ": " + err.message;
- throw err;
- }
- };
+ module._compile(content, filename);
+};
- // Native extension for .node
- Module._extensions[".node"] = function (module, filename) {
- if (filename.endsWith("fsevents.node")) {
- throw new Error("Using fsevents module is currently not supported");
- }
- module.exports = ops.op_napi_open(filename, node.globalThis);
- };
-
- function createRequireFromPath(filename) {
- const proxyPath = ops.op_require_proxy_path(filename);
- const mod = new Module(proxyPath);
- mod.filename = proxyPath;
- mod.paths = Module._nodeModulePaths(mod.path);
- return makeRequireFunction(mod);
+function stripBOM(content) {
+ if (StringPrototypeCharCodeAt(content, 0) === 0xfeff) {
+ content = StringPrototypeSlice(content, 1);
}
+ return content;
+}
- function makeRequireFunction(mod) {
- const require = function require(path) {
- return mod.require(path);
- };
-
- function resolve(request, options) {
- return Module._resolveFilename(request, mod, false, options);
- }
-
- require.resolve = resolve;
+// Native extension for .json
+Module._extensions[".json"] = function (module, filename) {
+ const content = ops.op_require_read_file(filename);
- function paths(request) {
- return Module._resolveLookupPaths(request, mod);
- }
+ try {
+ module.exports = JSONParse(stripBOM(content));
+ } catch (err) {
+ err.message = filename + ": " + err.message;
+ throw err;
+ }
+};
- resolve.paths = paths;
- require.main = mainModule;
- // Enable support to add extra extension types.
- require.extensions = Module._extensions;
- require.cache = Module._cache;
+// Native extension for .node
+Module._extensions[".node"] = function (module, filename) {
+ if (filename.endsWith("fsevents.node")) {
+ throw new Error("Using fsevents module is currently not supported");
+ }
+ module.exports = ops.op_napi_open(filename, node.globalThis);
+};
+
+function createRequireFromPath(filename) {
+ const proxyPath = ops.op_require_proxy_path(filename);
+ const mod = new Module(proxyPath);
+ mod.filename = proxyPath;
+ mod.paths = Module._nodeModulePaths(mod.path);
+ return makeRequireFunction(mod);
+}
+
+function makeRequireFunction(mod) {
+ const require = function require(path) {
+ return mod.require(path);
+ };
- return require;
+ function resolve(request, options) {
+ return Module._resolveFilename(request, mod, false, options);
}
- // Matches to:
- // - /foo/...
- // - \foo\...
- // - C:/foo/...
- // - C:\foo\...
- const RE_START_OF_ABS_PATH = /^([/\\]|[a-zA-Z]:[/\\])/;
+ require.resolve = resolve;
- function isAbsolute(filenameOrUrl) {
- return RE_START_OF_ABS_PATH.test(filenameOrUrl);
+ function paths(request) {
+ return Module._resolveLookupPaths(request, mod);
}
- function createRequire(filenameOrUrl) {
- let fileUrlStr;
- if (filenameOrUrl instanceof URL) {
- if (filenameOrUrl.protocol !== "file:") {
- throw new Error(
- `The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ${filenameOrUrl}`,
- );
- }
- fileUrlStr = filenameOrUrl.toString();
- } else if (typeof filenameOrUrl === "string") {
- if (!filenameOrUrl.startsWith("file:") && !isAbsolute(filenameOrUrl)) {
- throw new Error(
- `The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ${filenameOrUrl}`,
- );
- }
- fileUrlStr = filenameOrUrl;
- } else {
+ resolve.paths = paths;
+ require.main = mainModule;
+ // Enable support to add extra extension types.
+ require.extensions = Module._extensions;
+ require.cache = Module._cache;
+
+ return require;
+}
+
+// Matches to:
+// - /foo/...
+// - \foo\...
+// - C:/foo/...
+// - C:\foo\...
+const RE_START_OF_ABS_PATH = /^([/\\]|[a-zA-Z]:[/\\])/;
+
+function isAbsolute(filenameOrUrl) {
+ return RE_START_OF_ABS_PATH.test(filenameOrUrl);
+}
+
+function createRequire(filenameOrUrl) {
+ let fileUrlStr;
+ if (filenameOrUrl instanceof URL) {
+ if (filenameOrUrl.protocol !== "file:") {
+ throw new Error(
+ `The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ${filenameOrUrl}`,
+ );
+ }
+ fileUrlStr = filenameOrUrl.toString();
+ } else if (typeof filenameOrUrl === "string") {
+ if (!filenameOrUrl.startsWith("file:") && !isAbsolute(filenameOrUrl)) {
throw new Error(
`The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ${filenameOrUrl}`,
);
}
- const filename = core.ops.op_require_as_file_path(fileUrlStr);
- return createRequireFromPath(filename);
+ fileUrlStr = filenameOrUrl;
+ } else {
+ throw new Error(
+ `The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ${filenameOrUrl}`,
+ );
}
+ const filename = ops.op_require_as_file_path(fileUrlStr);
+ return createRequireFromPath(filename);
+}
- Module.createRequire = createRequire;
+Module.createRequire = createRequire;
- Module._initPaths = function () {
- const paths = ops.op_require_init_paths();
- modulePaths = paths;
- Module.globalPaths = ArrayPrototypeSlice(modulePaths);
- };
+Module._initPaths = function () {
+ const paths = ops.op_require_init_paths();
+ modulePaths = paths;
+ Module.globalPaths = ArrayPrototypeSlice(modulePaths);
+};
- Module.syncBuiltinESMExports = function syncBuiltinESMExports() {
- throw new Error("not implemented");
- };
+Module.syncBuiltinESMExports = function syncBuiltinESMExports() {
+ throw new Error("not implemented");
+};
- Module.Module = Module;
+Module.Module = Module;
- node.nativeModuleExports.module = Module;
+node.nativeModuleExports.module = Module;
- function loadNativeModule(_id, request) {
- if (nativeModulePolyfill.has(request)) {
- return nativeModulePolyfill.get(request);
- }
- const modExports = node.nativeModuleExports[request];
- if (modExports) {
- const nodeMod = new Module(request);
- nodeMod.exports = modExports;
- nodeMod.loaded = true;
- nativeModulePolyfill.set(request, nodeMod);
- return nodeMod;
- }
- return undefined;
+function loadNativeModule(_id, request) {
+ if (nativeModulePolyfill.has(request)) {
+ return nativeModulePolyfill.get(request);
}
-
- function nativeModuleCanBeRequiredByUsers(request) {
- return !!node.nativeModuleExports[request];
+ const modExports = node.nativeModuleExports[request];
+ if (modExports) {
+ const nodeMod = new Module(request);
+ nodeMod.exports = modExports;
+ nodeMod.loaded = true;
+ nativeModulePolyfill.set(request, nodeMod);
+ return nodeMod;
}
-
- function readPackageScope() {
- throw new Error("not implemented");
+ return undefined;
+}
+
+function nativeModuleCanBeRequiredByUsers(request) {
+ return !!node.nativeModuleExports[request];
+}
+
+function readPackageScope() {
+ throw new Error("not implemented");
+}
+
+/** @param specifier {string} */
+function packageSpecifierSubPath(specifier) {
+ let parts = StringPrototypeSplit(specifier, "/");
+ if (StringPrototypeStartsWith(parts[0], "@")) {
+ parts = ArrayPrototypeSlice(parts, 2);
+ } else {
+ parts = ArrayPrototypeSlice(parts, 1);
}
-
- /** @param specifier {string} */
- function packageSpecifierSubPath(specifier) {
- let parts = StringPrototypeSplit(specifier, "/");
- if (StringPrototypeStartsWith(parts[0], "@")) {
- parts = ArrayPrototypeSlice(parts, 2);
- } else {
- parts = ArrayPrototypeSlice(parts, 1);
- }
- return ArrayPrototypeJoin(parts, "/");
- }
-
- window.__bootstrap.internals = {
- ...window.__bootstrap.internals ?? {},
- require: {
- setUsesLocalNodeModulesDir() {
- usesLocalNodeModulesDir = true;
- },
- setInspectBrk() {
- hasInspectBrk = true;
- },
- Module,
- wrapSafe,
- toRealPath,
- cjsParseCache,
- readPackageScope,
- },
- };
-})(globalThis);
+ return ArrayPrototypeJoin(parts, "/");
+}
+
+internals.require = {
+ setUsesLocalNodeModulesDir() {
+ usesLocalNodeModulesDir = true;
+ },
+ setInspectBrk() {
+ hasInspectBrk = true;
+ },
+ Module,
+ wrapSafe,
+ toRealPath,
+ cjsParseCache,
+ readPackageScope,
+};
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index ad8619889..8db2bb3a7 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -85,7 +85,7 @@ pub fn init<P: NodePermissions + 'static>(
maybe_npm_resolver: Option<Rc<dyn RequireNpmResolver>>,
) -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/node",
"01_node.js",
"02_require.js",
diff --git a/ext/url/00_url.js b/ext/url/00_url.js
index 1191565ee..faaba2911 100644
--- a/ext/url/00_url.js
+++ b/ext/url/00_url.js
@@ -5,806 +5,803 @@
/// <reference path="../../core/lib.deno_core.d.ts" />
/// <reference path="../webidl/internal.d.ts" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const {
- ArrayIsArray,
- ArrayPrototypeMap,
- ArrayPrototypePush,
- ArrayPrototypeSome,
- ArrayPrototypeSort,
- ArrayPrototypeSplice,
- ObjectKeys,
- Uint32Array,
- SafeArrayIterator,
- StringPrototypeSlice,
- Symbol,
- SymbolFor,
- SymbolIterator,
- TypeError,
- } = window.__bootstrap.primordials;
-
- const _list = Symbol("list");
- const _urlObject = Symbol("url object");
-
- // WARNING: must match rust code's UrlSetter::*
- const SET_HASH = 0;
- const SET_HOST = 1;
- const SET_HOSTNAME = 2;
- const SET_PASSWORD = 3;
- const SET_PATHNAME = 4;
- const SET_PORT = 5;
- const SET_PROTOCOL = 6;
- const SET_SEARCH = 7;
- const SET_USERNAME = 8;
-
- // Helper functions
- function opUrlReparse(href, setter, value) {
- const status = ops.op_url_reparse(
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayIsArray,
+ ArrayPrototypeMap,
+ ArrayPrototypePush,
+ ArrayPrototypeSome,
+ ArrayPrototypeSort,
+ ArrayPrototypeSplice,
+ ObjectKeys,
+ Uint32Array,
+ SafeArrayIterator,
+ StringPrototypeSlice,
+ Symbol,
+ SymbolFor,
+ SymbolIterator,
+ TypeError,
+} = primordials;
+
+const _list = Symbol("list");
+const _urlObject = Symbol("url object");
+
+// WARNING: must match rust code's UrlSetter::*
+const SET_HASH = 0;
+const SET_HOST = 1;
+const SET_HOSTNAME = 2;
+const SET_PASSWORD = 3;
+const SET_PATHNAME = 4;
+const SET_PORT = 5;
+const SET_PROTOCOL = 6;
+const SET_SEARCH = 7;
+const SET_USERNAME = 8;
+
+// Helper functions
+function opUrlReparse(href, setter, value) {
+ const status = ops.op_url_reparse(
+ href,
+ setter,
+ value,
+ componentsBuf.buffer,
+ );
+ return getSerialization(status, href);
+}
+
+function opUrlParse(href, maybeBase) {
+ let status;
+ if (maybeBase === undefined) {
+ status = ops.op_url_parse(href, componentsBuf.buffer);
+ } else {
+ status = ops.op_url_parse_with_base(
href,
- setter,
- value,
+ maybeBase,
componentsBuf.buffer,
);
- return getSerialization(status, href);
}
+ return getSerialization(status, href, maybeBase);
+}
+
+function getSerialization(status, href, maybeBase) {
+ if (status === 0) {
+ return href;
+ } else if (status === 1) {
+ return ops.op_url_get_serialization();
+ } else {
+ throw new TypeError(
+ `Invalid URL: '${href}'` +
+ (maybeBase ? ` with base '${maybeBase}'` : ""),
+ );
+ }
+}
- function opUrlParse(href, maybeBase) {
- let status;
- if (maybeBase === undefined) {
- status = ops.op_url_parse(href, componentsBuf.buffer);
+class URLSearchParams {
+ [_list];
+ [_urlObject] = null;
+
+ /**
+ * @param {string | [string][] | Record<string, string>} init
+ */
+ 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 (!init) {
+ // if there is no query string, return early
+ this[_list] = [];
+ return;
+ }
+
+ if (typeof init === "string") {
+ // Overload: USVString
+ // If init is a string and starts with U+003F (?),
+ // remove the first code point from init.
+ if (init[0] == "?") {
+ init = StringPrototypeSlice(init, 1);
+ }
+ this[_list] = ops.op_url_parse_search_params(init);
+ } else if (ArrayIsArray(init)) {
+ // Overload: sequence<sequence<USVString>>
+ this[_list] = ArrayPrototypeMap(init, (pair, i) => {
+ if (pair.length !== 2) {
+ throw new TypeError(
+ `${prefix}: Item ${
+ i + 0
+ } in the parameter list does have length 2 exactly.`,
+ );
+ }
+ return [pair[0], pair[1]];
+ });
} else {
- status = core.ops.op_url_parse_with_base(
- href,
- maybeBase,
- componentsBuf.buffer,
+ // Overload: record<USVString, USVString>
+ this[_list] = ArrayPrototypeMap(
+ ObjectKeys(init),
+ (key) => [key, init[key]],
);
}
- return getSerialization(status, href, maybeBase);
}
- function getSerialization(status, href, maybeBase) {
- if (status === 0) {
- return href;
- } else if (status === 1) {
- return core.ops.op_url_get_serialization();
- } else {
- throw new TypeError(
- `Invalid URL: '${href}'` +
- (maybeBase ? ` with base '${maybeBase}'` : ""),
- );
+ #updateUrlSearch() {
+ const url = this[_urlObject];
+ if (url === null) {
+ return;
}
+ url[_updateUrlSearch](this.toString());
}
- class URLSearchParams {
- [_list];
- [_urlObject] = null;
-
- /**
- * @param {string | [string][] | Record<string, string>} init
- */
- 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 (!init) {
- // if there is no query string, return early
- this[_list] = [];
- return;
- }
+ /**
+ * @param {string} name
+ * @param {string} value
+ */
+ append(name, value) {
+ webidl.assertBranded(this, URLSearchParamsPrototype);
+ 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",
+ });
+ ArrayPrototypePush(this[_list], [name, value]);
+ this.#updateUrlSearch();
+ }
- if (typeof init === "string") {
- // Overload: USVString
- // If init is a string and starts with U+003F (?),
- // remove the first code point from init.
- if (init[0] == "?") {
- init = StringPrototypeSlice(init, 1);
- }
- this[_list] = ops.op_url_parse_search_params(init);
- } else if (ArrayIsArray(init)) {
- // Overload: sequence<sequence<USVString>>
- this[_list] = ArrayPrototypeMap(init, (pair, i) => {
- if (pair.length !== 2) {
- throw new TypeError(
- `${prefix}: Item ${
- i + 0
- } in the parameter list does have length 2 exactly.`,
- );
- }
- return [pair[0], pair[1]];
- });
+ /**
+ * @param {string} name
+ */
+ delete(name) {
+ webidl.assertBranded(this, URLSearchParamsPrototype);
+ 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 < list.length) {
+ if (list[i][0] === name) {
+ ArrayPrototypeSplice(list, i, 1);
} else {
- // Overload: record<USVString, USVString>
- this[_list] = ArrayPrototypeMap(
- ObjectKeys(init),
- (key) => [key, init[key]],
- );
+ i++;
}
}
+ this.#updateUrlSearch();
+ }
- #updateUrlSearch() {
- const url = this[_urlObject];
- if (url === null) {
- return;
+ /**
+ * @param {string} name
+ * @returns {string[]}
+ */
+ getAll(name) {
+ webidl.assertBranded(this, URLSearchParamsPrototype);
+ 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 = [];
+ const entries = this[_list];
+ for (let i = 0; i < entries.length; ++i) {
+ const entry = entries[i];
+ if (entry[0] === name) {
+ ArrayPrototypePush(values, entry[1]);
}
- url[_updateUrlSearch](this.toString());
}
+ return values;
+ }
- /**
- * @param {string} name
- * @param {string} value
- */
- append(name, value) {
- webidl.assertBranded(this, URLSearchParamsPrototype);
- 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",
- });
- ArrayPrototypePush(this[_list], [name, value]);
- this.#updateUrlSearch();
+ /**
+ * @param {string} name
+ * @return {string | null}
+ */
+ get(name) {
+ webidl.assertBranded(this, URLSearchParamsPrototype);
+ const prefix = "Failed to execute 'get' on 'URLSearchParams'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ name = webidl.converters.USVString(name, {
+ prefix,
+ context: "Argument 1",
+ });
+ const entries = this[_list];
+ for (let i = 0; i < entries.length; ++i) {
+ const entry = entries[i];
+ if (entry[0] === name) {
+ return entry[1];
+ }
}
+ return null;
+ }
- /**
- * @param {string} name
- */
- delete(name) {
- webidl.assertBranded(this, URLSearchParamsPrototype);
- 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 < list.length) {
- if (list[i][0] === name) {
- ArrayPrototypeSplice(list, i, 1);
- } else {
+ /**
+ * @param {string} name
+ * @return {boolean}
+ */
+ has(name) {
+ webidl.assertBranded(this, URLSearchParamsPrototype);
+ const prefix = "Failed to execute 'has' on 'URLSearchParams'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ name = webidl.converters.USVString(name, {
+ prefix,
+ context: "Argument 1",
+ });
+ return ArrayPrototypeSome(this[_list], (entry) => entry[0] === name);
+ }
+
+ /**
+ * @param {string} name
+ * @param {string} value
+ */
+ set(name, value) {
+ webidl.assertBranded(this, URLSearchParamsPrototype);
+ 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.
+ let found = false;
+ let i = 0;
+ while (i < list.length) {
+ if (list[i][0] === name) {
+ if (!found) {
+ list[i][1] = value;
+ found = true;
i++;
+ } else {
+ ArrayPrototypeSplice(list, i, 1);
}
+ } else {
+ i++;
}
- this.#updateUrlSearch();
}
- /**
- * @param {string} name
- * @returns {string[]}
- */
- getAll(name) {
- webidl.assertBranded(this, URLSearchParamsPrototype);
- 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 = [];
- const entries = this[_list];
- for (let i = 0; i < entries.length; ++i) {
- const entry = entries[i];
- if (entry[0] === name) {
- ArrayPrototypePush(values, entry[1]);
- }
- }
- return values;
+ // Otherwise, append a new name-value pair whose name is name
+ // and value is value, to list.
+ if (!found) {
+ ArrayPrototypePush(list, [name, value]);
}
- /**
- * @param {string} name
- * @return {string | null}
- */
- get(name) {
- webidl.assertBranded(this, URLSearchParamsPrototype);
- const prefix = "Failed to execute 'get' on 'URLSearchParams'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- name = webidl.converters.USVString(name, {
- prefix,
- context: "Argument 1",
- });
- const entries = this[_list];
- for (let i = 0; i < entries.length; ++i) {
- const entry = entries[i];
- if (entry[0] === name) {
- return entry[1];
- }
- }
- return null;
- }
+ this.#updateUrlSearch();
+ }
- /**
- * @param {string} name
- * @return {boolean}
- */
- has(name) {
- webidl.assertBranded(this, URLSearchParamsPrototype);
- const prefix = "Failed to execute 'has' on 'URLSearchParams'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- name = webidl.converters.USVString(name, {
- prefix,
- context: "Argument 1",
- });
- return ArrayPrototypeSome(this[_list], (entry) => entry[0] === name);
- }
+ sort() {
+ webidl.assertBranded(this, URLSearchParamsPrototype);
+ ArrayPrototypeSort(
+ this[_list],
+ (a, b) => (a[0] === b[0] ? 0 : a[0] > b[0] ? 1 : -1),
+ );
+ this.#updateUrlSearch();
+ }
- /**
- * @param {string} name
- * @param {string} value
- */
- set(name, value) {
- webidl.assertBranded(this, URLSearchParamsPrototype);
- 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, {
+ /**
+ * @return {string}
+ */
+ toString() {
+ webidl.assertBranded(this, URLSearchParamsPrototype);
+ return ops.op_url_stringify_search_params(this[_list]);
+ }
+}
+
+webidl.mixinPairIterable("URLSearchParams", URLSearchParams, _list, 0, 1);
+
+webidl.configurePrototype(URLSearchParams);
+const URLSearchParamsPrototype = URLSearchParams.prototype;
+
+webidl.converters["URLSearchParams"] = webidl.createInterfaceConverter(
+ "URLSearchParams",
+ URLSearchParamsPrototype,
+);
+
+const _updateUrlSearch = Symbol("updateUrlSearch");
+
+function trim(s) {
+ if (s.length === 1) return "";
+ return s;
+}
+
+// Represents a "no port" value. A port in URL cannot be greater than 2^16 − 1
+const NO_PORT = 65536;
+
+const componentsBuf = new Uint32Array(8);
+class URL {
+ #queryObject = null;
+ #serialization;
+ #schemeEnd;
+ #usernameEnd;
+ #hostStart;
+ #hostEnd;
+ #port;
+ #pathStart;
+ #queryStart;
+ #fragmentStart;
+
+ [_updateUrlSearch](value) {
+ this.#serialization = opUrlReparse(
+ this.#serialization,
+ SET_SEARCH,
+ value,
+ );
+ this.#updateComponents();
+ }
+
+ /**
+ * @param {string} url
+ * @param {string} base
+ */
+ constructor(url, base = undefined) {
+ const prefix = "Failed to construct 'URL'";
+ url = webidl.converters.DOMString(url, { prefix, context: "Argument 1" });
+ if (base !== undefined) {
+ base = webidl.converters.DOMString(base, {
prefix,
context: "Argument 2",
});
+ }
+ this[webidl.brand] = webidl.brand;
+ this.#serialization = opUrlParse(url, base);
+ this.#updateComponents();
+ }
- 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.
- let found = false;
- let i = 0;
- while (i < list.length) {
- if (list[i][0] === name) {
- if (!found) {
- list[i][1] = value;
- found = true;
- i++;
- } else {
- ArrayPrototypeSplice(list, i, 1);
- }
- } else {
- i++;
- }
- }
-
- // Otherwise, append a new name-value pair whose name is name
- // and value is value, to list.
- if (!found) {
- ArrayPrototypePush(list, [name, value]);
- }
+ #updateComponents() {
+ ({
+ 0: this.#schemeEnd,
+ 1: this.#usernameEnd,
+ 2: this.#hostStart,
+ 3: this.#hostEnd,
+ 4: this.#port,
+ 5: this.#pathStart,
+ 6: this.#queryStart,
+ 7: this.#fragmentStart,
+ } = componentsBuf);
+ }
- this.#updateUrlSearch();
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
+ const object = {
+ href: this.href,
+ origin: this.origin,
+ protocol: this.protocol,
+ username: this.username,
+ password: this.password,
+ host: this.host,
+ hostname: this.hostname,
+ port: this.port,
+ pathname: this.pathname,
+ hash: this.hash,
+ search: this.search,
+ };
+ return `${this.constructor.name} ${inspect(object, inspectOptions)}`;
+ }
- sort() {
- webidl.assertBranded(this, URLSearchParamsPrototype);
- ArrayPrototypeSort(
- this[_list],
- (a, b) => (a[0] === b[0] ? 0 : a[0] > b[0] ? 1 : -1),
+ #updateSearchParams() {
+ if (this.#queryObject !== null) {
+ const params = this.#queryObject[_list];
+ const newParams = ops.op_url_parse_search_params(
+ StringPrototypeSlice(this.search, 1),
+ );
+ ArrayPrototypeSplice(
+ params,
+ 0,
+ params.length,
+ ...new SafeArrayIterator(newParams),
);
- this.#updateUrlSearch();
- }
-
- /**
- * @return {string}
- */
- toString() {
- webidl.assertBranded(this, URLSearchParamsPrototype);
- return ops.op_url_stringify_search_params(this[_list]);
}
}
- webidl.mixinPairIterable("URLSearchParams", URLSearchParams, _list, 0, 1);
-
- webidl.configurePrototype(URLSearchParams);
- const URLSearchParamsPrototype = URLSearchParams.prototype;
-
- webidl.converters["URLSearchParams"] = webidl.createInterfaceConverter(
- "URLSearchParams",
- URLSearchParamsPrototype,
- );
-
- const _updateUrlSearch = Symbol("updateUrlSearch");
-
- function trim(s) {
- if (s.length === 1) return "";
- return s;
+ #hasAuthority() {
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/lib.rs#L824
+ return this.#serialization.slice(this.#schemeEnd).startsWith("://");
}
- // Represents a "no port" value. A port in URL cannot be greater than 2^16 − 1
- const NO_PORT = 65536;
-
- const componentsBuf = new Uint32Array(8);
- class URL {
- #queryObject = null;
- #serialization;
- #schemeEnd;
- #usernameEnd;
- #hostStart;
- #hostEnd;
- #port;
- #pathStart;
- #queryStart;
- #fragmentStart;
+ /** @return {string} */
+ get hash() {
+ webidl.assertBranded(this, URLPrototype);
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/quirks.rs#L263
+ return this.#fragmentStart
+ ? trim(this.#serialization.slice(this.#fragmentStart))
+ : "";
+ }
- [_updateUrlSearch](value) {
+ /** @param {string} value */
+ set hash(value) {
+ webidl.assertBranded(this, URLPrototype);
+ const prefix = "Failed to set 'hash' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
this.#serialization = opUrlReparse(
this.#serialization,
- SET_SEARCH,
+ SET_HASH,
value,
);
this.#updateComponents();
+ } catch {
+ /* pass */
}
+ }
- /**
- * @param {string} url
- * @param {string} base
- */
- constructor(url, base = undefined) {
- const prefix = "Failed to construct 'URL'";
- url = webidl.converters.DOMString(url, { prefix, context: "Argument 1" });
- if (base !== undefined) {
- base = webidl.converters.DOMString(base, {
- prefix,
- context: "Argument 2",
- });
- }
- this[webidl.brand] = webidl.brand;
- this.#serialization = opUrlParse(url, base);
+ /** @return {string} */
+ get host() {
+ webidl.assertBranded(this, URLPrototype);
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/quirks.rs#L101
+ return this.#serialization.slice(this.#hostStart, this.#pathStart);
+ }
+
+ /** @param {string} value */
+ set host(value) {
+ webidl.assertBranded(this, URLPrototype);
+ const prefix = "Failed to set 'host' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
+ this.#serialization = opUrlReparse(
+ this.#serialization,
+ SET_HOST,
+ value,
+ );
this.#updateComponents();
+ } catch {
+ /* pass */
}
+ }
- #updateComponents() {
- ({
- 0: this.#schemeEnd,
- 1: this.#usernameEnd,
- 2: this.#hostStart,
- 3: this.#hostEnd,
- 4: this.#port,
- 5: this.#pathStart,
- 6: this.#queryStart,
- 7: this.#fragmentStart,
- } = componentsBuf);
- }
+ /** @return {string} */
+ get hostname() {
+ webidl.assertBranded(this, URLPrototype);
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/lib.rs#L988
+ return this.#serialization.slice(this.#hostStart, this.#hostEnd);
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
- const object = {
- href: this.href,
- origin: this.origin,
- protocol: this.protocol,
- username: this.username,
- password: this.password,
- host: this.host,
- hostname: this.hostname,
- port: this.port,
- pathname: this.pathname,
- hash: this.hash,
- search: this.search,
- };
- return `${this.constructor.name} ${inspect(object, inspectOptions)}`;
+ /** @param {string} value */
+ set hostname(value) {
+ webidl.assertBranded(this, URLPrototype);
+ const prefix = "Failed to set 'hostname' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
+ this.#serialization = opUrlReparse(
+ this.#serialization,
+ SET_HOSTNAME,
+ value,
+ );
+ this.#updateComponents();
+ } catch {
+ /* pass */
}
+ }
- #updateSearchParams() {
- if (this.#queryObject !== null) {
- const params = this.#queryObject[_list];
- const newParams = ops.op_url_parse_search_params(
- StringPrototypeSlice(this.search, 1),
- );
- ArrayPrototypeSplice(
- params,
- 0,
- params.length,
- ...new SafeArrayIterator(newParams),
- );
- }
- }
+ /** @return {string} */
+ get href() {
+ webidl.assertBranded(this, URLPrototype);
+ return this.#serialization;
+ }
- #hasAuthority() {
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/lib.rs#L824
- return this.#serialization.slice(this.#schemeEnd).startsWith("://");
- }
+ /** @param {string} value */
+ set href(value) {
+ webidl.assertBranded(this, URLPrototype);
+ const prefix = "Failed to set 'href' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ this.#serialization = opUrlParse(value);
+ this.#updateComponents();
+ this.#updateSearchParams();
+ }
- /** @return {string} */
- get hash() {
- webidl.assertBranded(this, URLPrototype);
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/quirks.rs#L263
- return this.#fragmentStart
- ? trim(this.#serialization.slice(this.#fragmentStart))
- : "";
+ /** @return {string} */
+ get origin() {
+ webidl.assertBranded(this, URLPrototype);
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/origin.rs#L14
+ const scheme = this.#serialization.slice(0, this.#schemeEnd);
+ if (
+ scheme === "http" || scheme === "https" || scheme === "ftp" ||
+ scheme === "ws" || scheme === "wss"
+ ) {
+ return `${scheme}://${this.host}`;
}
- /** @param {string} value */
- set hash(value) {
- webidl.assertBranded(this, URLPrototype);
- const prefix = "Failed to set 'hash' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 1",
- });
+ if (scheme === "blob") {
+ // TODO(@littledivy): Fast path.
try {
- this.#serialization = opUrlReparse(
- this.#serialization,
- SET_HASH,
- value,
- );
- this.#updateComponents();
+ return new URL(this.pathname).origin;
} catch {
- /* pass */
+ return "null";
}
}
- /** @return {string} */
- get host() {
- webidl.assertBranded(this, URLPrototype);
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/quirks.rs#L101
- return this.#serialization.slice(this.#hostStart, this.#pathStart);
- }
-
- /** @param {string} value */
- set host(value) {
- webidl.assertBranded(this, URLPrototype);
- const prefix = "Failed to set 'host' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 1",
- });
- try {
- this.#serialization = opUrlReparse(
- this.#serialization,
- SET_HOST,
- value,
- );
- this.#updateComponents();
- } catch {
- /* pass */
- }
- }
-
- /** @return {string} */
- get hostname() {
- webidl.assertBranded(this, URLPrototype);
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/lib.rs#L988
- return this.#serialization.slice(this.#hostStart, this.#hostEnd);
- }
-
- /** @param {string} value */
- set hostname(value) {
- webidl.assertBranded(this, URLPrototype);
- const prefix = "Failed to set 'hostname' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 1",
- });
- try {
- this.#serialization = opUrlReparse(
- this.#serialization,
- SET_HOSTNAME,
- value,
- );
- this.#updateComponents();
- } catch {
- /* pass */
- }
- }
+ return "null";
+ }
- /** @return {string} */
- get href() {
- webidl.assertBranded(this, URLPrototype);
- return this.#serialization;
+ /** @return {string} */
+ get password() {
+ webidl.assertBranded(this, URLPrototype);
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/lib.rs#L914
+ if (
+ this.#hasAuthority() &&
+ this.#usernameEnd !== this.#serialization.length &&
+ this.#serialization[this.#usernameEnd] === ":"
+ ) {
+ return this.#serialization.slice(
+ this.#usernameEnd + 1,
+ this.#hostStart - 1,
+ );
}
+ return "";
+ }
- /** @param {string} value */
- set href(value) {
- webidl.assertBranded(this, URLPrototype);
- const prefix = "Failed to set 'href' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 1",
- });
- this.#serialization = opUrlParse(value);
+ /** @param {string} value */
+ set password(value) {
+ webidl.assertBranded(this, URLPrototype);
+ const prefix = "Failed to set 'password' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
+ this.#serialization = opUrlReparse(
+ this.#serialization,
+ SET_PASSWORD,
+ value,
+ );
this.#updateComponents();
- this.#updateSearchParams();
- }
-
- /** @return {string} */
- get origin() {
- webidl.assertBranded(this, URLPrototype);
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/origin.rs#L14
- const scheme = this.#serialization.slice(0, this.#schemeEnd);
- if (
- scheme === "http" || scheme === "https" || scheme === "ftp" ||
- scheme === "ws" || scheme === "wss"
- ) {
- return `${scheme}://${this.host}`;
- }
-
- if (scheme === "blob") {
- // TODO(@littledivy): Fast path.
- try {
- return new URL(this.pathname).origin;
- } catch {
- return "null";
- }
- }
-
- return "null";
- }
-
- /** @return {string} */
- get password() {
- webidl.assertBranded(this, URLPrototype);
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/lib.rs#L914
- if (
- this.#hasAuthority() &&
- this.#usernameEnd !== this.#serialization.length &&
- this.#serialization[this.#usernameEnd] === ":"
- ) {
- return this.#serialization.slice(
- this.#usernameEnd + 1,
- this.#hostStart - 1,
- );
- }
- return "";
- }
-
- /** @param {string} value */
- set password(value) {
- webidl.assertBranded(this, URLPrototype);
- const prefix = "Failed to set 'password' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 1",
- });
- try {
- this.#serialization = opUrlReparse(
- this.#serialization,
- SET_PASSWORD,
- value,
- );
- this.#updateComponents();
- } catch {
- /* pass */
- }
- }
-
- /** @return {string} */
- get pathname() {
- webidl.assertBranded(this, URLPrototype);
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/lib.rs#L1203
- if (!this.#queryStart && !this.#fragmentStart) {
- return this.#serialization.slice(this.#pathStart);
- }
-
- const nextComponentStart = this.#queryStart || this.#fragmentStart;
- return this.#serialization.slice(this.#pathStart, nextComponentStart);
+ } catch {
+ /* pass */
}
+ }
- /** @param {string} value */
- set pathname(value) {
- webidl.assertBranded(this, URLPrototype);
- const prefix = "Failed to set 'pathname' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 1",
- });
- try {
- this.#serialization = opUrlReparse(
- this.#serialization,
- SET_PATHNAME,
- value,
- );
- this.#updateComponents();
- } catch {
- /* pass */
- }
+ /** @return {string} */
+ get pathname() {
+ webidl.assertBranded(this, URLPrototype);
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/lib.rs#L1203
+ if (!this.#queryStart && !this.#fragmentStart) {
+ return this.#serialization.slice(this.#pathStart);
}
- /** @return {string} */
- get port() {
- webidl.assertBranded(this, URLPrototype);
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/quirks.rs#L196
- if (this.#port === NO_PORT) {
- return this.#serialization.slice(this.#hostEnd, this.#pathStart);
- } else {
- return this.#serialization.slice(
- this.#hostEnd + 1, /* : */
- this.#pathStart,
- );
- }
- }
+ const nextComponentStart = this.#queryStart || this.#fragmentStart;
+ return this.#serialization.slice(this.#pathStart, nextComponentStart);
+ }
- /** @param {string} value */
- set port(value) {
- webidl.assertBranded(this, URLPrototype);
- const prefix = "Failed to set 'port' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 1",
- });
- try {
- this.#serialization = opUrlReparse(
- this.#serialization,
- SET_PORT,
- value,
- );
- this.#updateComponents();
- } catch {
- /* pass */
- }
+ /** @param {string} value */
+ set pathname(value) {
+ webidl.assertBranded(this, URLPrototype);
+ const prefix = "Failed to set 'pathname' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
+ this.#serialization = opUrlReparse(
+ this.#serialization,
+ SET_PATHNAME,
+ value,
+ );
+ this.#updateComponents();
+ } catch {
+ /* pass */
}
+ }
- /** @return {string} */
- get protocol() {
- webidl.assertBranded(this, URLPrototype);
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/quirks.rs#L56
- return this.#serialization.slice(0, this.#schemeEnd + 1 /* : */);
+ /** @return {string} */
+ get port() {
+ webidl.assertBranded(this, URLPrototype);
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/quirks.rs#L196
+ if (this.#port === NO_PORT) {
+ return this.#serialization.slice(this.#hostEnd, this.#pathStart);
+ } else {
+ return this.#serialization.slice(
+ this.#hostEnd + 1, /* : */
+ this.#pathStart,
+ );
}
+ }
- /** @param {string} value */
- set protocol(value) {
- webidl.assertBranded(this, URLPrototype);
- const prefix = "Failed to set 'protocol' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 1",
- });
- try {
- this.#serialization = opUrlReparse(
- this.#serialization,
- SET_PROTOCOL,
- value,
- );
- this.#updateComponents();
- } catch {
- /* pass */
- }
+ /** @param {string} value */
+ set port(value) {
+ webidl.assertBranded(this, URLPrototype);
+ const prefix = "Failed to set 'port' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
+ this.#serialization = opUrlReparse(
+ this.#serialization,
+ SET_PORT,
+ value,
+ );
+ this.#updateComponents();
+ } catch {
+ /* pass */
}
+ }
- /** @return {string} */
- get search() {
- webidl.assertBranded(this, URLPrototype);
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/quirks.rs#L249
- const afterPath = this.#queryStart || this.#fragmentStart ||
- this.#serialization.length;
- const afterQuery = this.#fragmentStart || this.#serialization.length;
- return trim(this.#serialization.slice(afterPath, afterQuery));
- }
+ /** @return {string} */
+ get protocol() {
+ webidl.assertBranded(this, URLPrototype);
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/quirks.rs#L56
+ return this.#serialization.slice(0, this.#schemeEnd + 1 /* : */);
+ }
- /** @param {string} value */
- set search(value) {
- webidl.assertBranded(this, URLPrototype);
- const prefix = "Failed to set 'search' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 1",
- });
- try {
- this.#serialization = opUrlReparse(
- this.#serialization,
- SET_SEARCH,
- value,
- );
- this.#updateComponents();
- this.#updateSearchParams();
- } catch {
- /* pass */
- }
+ /** @param {string} value */
+ set protocol(value) {
+ webidl.assertBranded(this, URLPrototype);
+ const prefix = "Failed to set 'protocol' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
+ this.#serialization = opUrlReparse(
+ this.#serialization,
+ SET_PROTOCOL,
+ value,
+ );
+ this.#updateComponents();
+ } catch {
+ /* pass */
}
+ }
- /** @return {string} */
- get username() {
- webidl.assertBranded(this, URLPrototype);
- // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/lib.rs#L881
- const schemeSeperatorLen = 3; /* :// */
- if (
- this.#hasAuthority() &&
- this.#usernameEnd > this.#schemeEnd + schemeSeperatorLen
- ) {
- return this.#serialization.slice(
- this.#schemeEnd + schemeSeperatorLen,
- this.#usernameEnd,
- );
- } else {
- return "";
- }
- }
+ /** @return {string} */
+ get search() {
+ webidl.assertBranded(this, URLPrototype);
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/quirks.rs#L249
+ const afterPath = this.#queryStart || this.#fragmentStart ||
+ this.#serialization.length;
+ const afterQuery = this.#fragmentStart || this.#serialization.length;
+ return trim(this.#serialization.slice(afterPath, afterQuery));
+ }
- /** @param {string} value */
- set username(value) {
- webidl.assertBranded(this, URLPrototype);
- const prefix = "Failed to set 'username' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 1",
- });
- try {
- this.#serialization = opUrlReparse(
- this.#serialization,
- SET_USERNAME,
- value,
- );
- this.#updateComponents();
- } catch {
- /* pass */
- }
+ /** @param {string} value */
+ set search(value) {
+ webidl.assertBranded(this, URLPrototype);
+ const prefix = "Failed to set 'search' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
+ this.#serialization = opUrlReparse(
+ this.#serialization,
+ SET_SEARCH,
+ value,
+ );
+ this.#updateComponents();
+ this.#updateSearchParams();
+ } catch {
+ /* pass */
}
+ }
- /** @return {string} */
- get searchParams() {
- if (this.#queryObject == null) {
- this.#queryObject = new URLSearchParams(this.search);
- this.#queryObject[_urlObject] = this;
- }
- return this.#queryObject;
+ /** @return {string} */
+ get username() {
+ webidl.assertBranded(this, URLPrototype);
+ // https://github.com/servo/rust-url/blob/1d307ae51a28fecc630ecec03380788bfb03a643/url/src/lib.rs#L881
+ const schemeSeperatorLen = 3; /* :// */
+ if (
+ this.#hasAuthority() &&
+ this.#usernameEnd > this.#schemeEnd + schemeSeperatorLen
+ ) {
+ return this.#serialization.slice(
+ this.#schemeEnd + schemeSeperatorLen,
+ this.#usernameEnd,
+ );
+ } else {
+ return "";
}
+ }
- /** @return {string} */
- toString() {
- webidl.assertBranded(this, URLPrototype);
- return this.#serialization;
+ /** @param {string} value */
+ set username(value) {
+ webidl.assertBranded(this, URLPrototype);
+ const prefix = "Failed to set 'username' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
+ this.#serialization = opUrlReparse(
+ this.#serialization,
+ SET_USERNAME,
+ value,
+ );
+ this.#updateComponents();
+ } catch {
+ /* pass */
}
+ }
- /** @return {string} */
- toJSON() {
- webidl.assertBranded(this, URLPrototype);
- return this.#serialization;
+ /** @return {string} */
+ get searchParams() {
+ if (this.#queryObject == null) {
+ this.#queryObject = new URLSearchParams(this.search);
+ this.#queryObject[_urlObject] = this;
}
+ return this.#queryObject;
}
- webidl.configurePrototype(URL);
- const URLPrototype = URL.prototype;
+ /** @return {string} */
+ toString() {
+ webidl.assertBranded(this, URLPrototype);
+ return this.#serialization;
+ }
- /**
- * This function implements application/x-www-form-urlencoded parsing.
- * https://url.spec.whatwg.org/#concept-urlencoded-parser
- * @param {Uint8Array} bytes
- * @returns {[string, string][]}
- */
- function parseUrlEncoded(bytes) {
- return ops.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[SymbolIterator] !== undefined) {
- return webidl.converters["sequence<sequence<USVString>>"](V, opts);
- }
- return webidl.converters["record<USVString, USVString>"](V, opts);
+ /** @return {string} */
+ toJSON() {
+ webidl.assertBranded(this, URLPrototype);
+ return this.#serialization;
+ }
+}
+
+webidl.configurePrototype(URL);
+const URLPrototype = URL.prototype;
+
+/**
+ * This function implements application/x-www-form-urlencoded parsing.
+ * https://url.spec.whatwg.org/#concept-urlencoded-parser
+ * @param {Uint8Array} bytes
+ * @returns {[string, string][]}
+ */
+function parseUrlEncoded(bytes) {
+ return ops.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[SymbolIterator] !== undefined) {
+ return webidl.converters["sequence<sequence<USVString>>"](V, opts);
}
- return webidl.converters.USVString(V, opts);
- };
-
- window.__bootstrap.url = {
- URL,
- URLPrototype,
- URLSearchParams,
- URLSearchParamsPrototype,
- parseUrlEncoded,
+ return webidl.converters["record<USVString, USVString>"](V, opts);
+ }
+ return webidl.converters.USVString(V, opts);
};
-})(this);
+
+export {
+ parseUrlEncoded,
+ URL,
+ URLPrototype,
+ URLSearchParams,
+ URLSearchParamsPrototype,
+};
diff --git a/ext/url/01_urlpattern.js b/ext/url/01_urlpattern.js
index 14f052551..1c5882553 100644
--- a/ext/url/01_urlpattern.js
+++ b/ext/url/01_urlpattern.js
@@ -7,268 +7,263 @@
/// <reference path="./internal.d.ts" />
/// <reference path="./lib.deno_url.d.ts" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const {
- ArrayPrototypeMap,
- ObjectKeys,
- ObjectFromEntries,
- RegExp,
- RegExpPrototypeExec,
- RegExpPrototypeTest,
- Symbol,
- SymbolFor,
- TypeError,
- } = window.__bootstrap.primordials;
-
- const _components = Symbol("components");
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeMap,
+ ObjectKeys,
+ ObjectFromEntries,
+ RegExp,
+ RegExpPrototypeExec,
+ RegExpPrototypeTest,
+ Symbol,
+ SymbolFor,
+ TypeError,
+} = primordials;
+
+const _components = Symbol("components");
+
+/**
+ * @typedef Components
+ * @property {Component} protocol
+ * @property {Component} username
+ * @property {Component} password
+ * @property {Component} hostname
+ * @property {Component} port
+ * @property {Component} pathname
+ * @property {Component} search
+ * @property {Component} hash
+ */
+
+/**
+ * @typedef Component
+ * @property {string} patternString
+ * @property {RegExp} regexp
+ * @property {string[]} groupNameList
+ */
+
+class URLPattern {
+ /** @type {Components} */
+ [_components];
/**
- * @typedef Components
- * @property {Component} protocol
- * @property {Component} username
- * @property {Component} password
- * @property {Component} hostname
- * @property {Component} port
- * @property {Component} pathname
- * @property {Component} search
- * @property {Component} hash
+ * @param {URLPatternInput} input
+ * @param {string} [baseURL]
*/
-
- /**
- * @typedef Component
- * @property {string} patternString
- * @property {RegExp} regexp
- * @property {string[]} groupNameList
- */
-
- class URLPattern {
- /** @type {Components} */
- [_components];
-
- /**
- * @param {URLPatternInput} input
- * @param {string} [baseURL]
- */
- constructor(input, baseURL = undefined) {
- this[webidl.brand] = webidl.brand;
- const prefix = "Failed to construct 'URLPattern'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- input = webidl.converters.URLPatternInput(input, {
+ constructor(input, baseURL = undefined) {
+ this[webidl.brand] = webidl.brand;
+ const prefix = "Failed to construct 'URLPattern'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ input = webidl.converters.URLPatternInput(input, {
+ prefix,
+ context: "Argument 1",
+ });
+ if (baseURL !== undefined) {
+ baseURL = webidl.converters.USVString(baseURL, {
prefix,
- context: "Argument 1",
+ context: "Argument 2",
});
- if (baseURL !== undefined) {
- baseURL = webidl.converters.USVString(baseURL, {
- prefix,
- context: "Argument 2",
- });
- }
+ }
- const components = ops.op_urlpattern_parse(input, baseURL);
-
- const keys = ObjectKeys(components);
- for (let i = 0; i < keys.length; ++i) {
- const key = keys[i];
- try {
- components[key].regexp = new RegExp(
- components[key].regexpString,
- "u",
- );
- } catch (e) {
- throw new TypeError(`${prefix}: ${key} is invalid; ${e.message}`);
- }
- }
+ const components = ops.op_urlpattern_parse(input, baseURL);
- this[_components] = components;
+ const keys = ObjectKeys(components);
+ for (let i = 0; i < keys.length; ++i) {
+ const key = keys[i];
+ try {
+ components[key].regexp = new RegExp(
+ components[key].regexpString,
+ "u",
+ );
+ } catch (e) {
+ throw new TypeError(`${prefix}: ${key} is invalid; ${e.message}`);
+ }
}
- get protocol() {
- webidl.assertBranded(this, URLPatternPrototype);
- return this[_components].protocol.patternString;
- }
+ this[_components] = components;
+ }
- get username() {
- webidl.assertBranded(this, URLPatternPrototype);
- return this[_components].username.patternString;
- }
+ get protocol() {
+ webidl.assertBranded(this, URLPatternPrototype);
+ return this[_components].protocol.patternString;
+ }
- get password() {
- webidl.assertBranded(this, URLPatternPrototype);
- return this[_components].password.patternString;
- }
+ get username() {
+ webidl.assertBranded(this, URLPatternPrototype);
+ return this[_components].username.patternString;
+ }
- get hostname() {
- webidl.assertBranded(this, URLPatternPrototype);
- return this[_components].hostname.patternString;
- }
+ get password() {
+ webidl.assertBranded(this, URLPatternPrototype);
+ return this[_components].password.patternString;
+ }
- get port() {
- webidl.assertBranded(this, URLPatternPrototype);
- return this[_components].port.patternString;
- }
+ get hostname() {
+ webidl.assertBranded(this, URLPatternPrototype);
+ return this[_components].hostname.patternString;
+ }
- get pathname() {
- webidl.assertBranded(this, URLPatternPrototype);
- return this[_components].pathname.patternString;
- }
+ get port() {
+ webidl.assertBranded(this, URLPatternPrototype);
+ return this[_components].port.patternString;
+ }
- get search() {
- webidl.assertBranded(this, URLPatternPrototype);
- return this[_components].search.patternString;
- }
+ get pathname() {
+ webidl.assertBranded(this, URLPatternPrototype);
+ return this[_components].pathname.patternString;
+ }
- get hash() {
- webidl.assertBranded(this, URLPatternPrototype);
- return this[_components].hash.patternString;
- }
+ get search() {
+ webidl.assertBranded(this, URLPatternPrototype);
+ return this[_components].search.patternString;
+ }
+
+ get hash() {
+ webidl.assertBranded(this, URLPatternPrototype);
+ return this[_components].hash.patternString;
+ }
- /**
- * @param {URLPatternInput} input
- * @param {string} [baseURL]
- * @returns {boolean}
- */
- test(input, baseURL = undefined) {
- webidl.assertBranded(this, URLPatternPrototype);
- const prefix = "Failed to execute 'test' on 'URLPattern'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- input = webidl.converters.URLPatternInput(input, {
+ /**
+ * @param {URLPatternInput} input
+ * @param {string} [baseURL]
+ * @returns {boolean}
+ */
+ test(input, baseURL = undefined) {
+ webidl.assertBranded(this, URLPatternPrototype);
+ const prefix = "Failed to execute 'test' on 'URLPattern'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ input = webidl.converters.URLPatternInput(input, {
+ prefix,
+ context: "Argument 1",
+ });
+ if (baseURL !== undefined) {
+ baseURL = webidl.converters.USVString(baseURL, {
prefix,
- context: "Argument 1",
+ context: "Argument 2",
});
- if (baseURL !== undefined) {
- baseURL = webidl.converters.USVString(baseURL, {
- prefix,
- context: "Argument 2",
- });
- }
+ }
- const res = ops.op_urlpattern_process_match_input(
- input,
- baseURL,
- );
- if (res === null) {
- return false;
- }
+ const res = ops.op_urlpattern_process_match_input(
+ input,
+ baseURL,
+ );
+ if (res === null) {
+ return false;
+ }
- const values = res[0];
+ const values = res[0];
- const keys = ObjectKeys(values);
- for (let i = 0; i < keys.length; ++i) {
- const key = keys[i];
- if (!RegExpPrototypeTest(this[_components][key].regexp, values[key])) {
- return false;
- }
+ const keys = ObjectKeys(values);
+ for (let i = 0; i < keys.length; ++i) {
+ const key = keys[i];
+ if (!RegExpPrototypeTest(this[_components][key].regexp, values[key])) {
+ return false;
}
-
- return true;
}
- /**
- * @param {URLPatternInput} input
- * @param {string} [baseURL]
- * @returns {URLPatternResult | null}
- */
- exec(input, baseURL = undefined) {
- webidl.assertBranded(this, URLPatternPrototype);
- const prefix = "Failed to execute 'exec' on 'URLPattern'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- input = webidl.converters.URLPatternInput(input, {
+ return true;
+ }
+
+ /**
+ * @param {URLPatternInput} input
+ * @param {string} [baseURL]
+ * @returns {URLPatternResult | null}
+ */
+ exec(input, baseURL = undefined) {
+ webidl.assertBranded(this, URLPatternPrototype);
+ const prefix = "Failed to execute 'exec' on 'URLPattern'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ input = webidl.converters.URLPatternInput(input, {
+ prefix,
+ context: "Argument 1",
+ });
+ if (baseURL !== undefined) {
+ baseURL = webidl.converters.USVString(baseURL, {
prefix,
- context: "Argument 1",
+ context: "Argument 2",
});
- if (baseURL !== undefined) {
- baseURL = webidl.converters.USVString(baseURL, {
- prefix,
- context: "Argument 2",
- });
- }
+ }
- const res = ops.op_urlpattern_process_match_input(
- input,
- baseURL,
- );
- if (res === null) {
- return null;
- }
+ const res = ops.op_urlpattern_process_match_input(
+ input,
+ baseURL,
+ );
+ if (res === null) {
+ return null;
+ }
- const { 0: values, 1: inputs } = res;
- if (inputs[1] === null) {
- inputs.pop();
- }
+ const { 0: values, 1: inputs } = res;
+ if (inputs[1] === null) {
+ inputs.pop();
+ }
- /** @type {URLPatternResult} */
- const result = { inputs };
-
- const keys = ObjectKeys(values);
- for (let i = 0; i < keys.length; ++i) {
- const key = keys[i];
- /** @type {Component} */
- const component = this[_components][key];
- const input = values[key];
- const match = RegExpPrototypeExec(component.regexp, input);
- if (match === null) {
- return null;
- }
- const groupEntries = ArrayPrototypeMap(
- component.groupNameList,
- (name, i) => [name, match[i + 1] ?? ""],
- );
- const groups = ObjectFromEntries(groupEntries);
- result[key] = {
- input,
- groups,
- };
+ /** @type {URLPatternResult} */
+ const result = { inputs };
+
+ const keys = ObjectKeys(values);
+ for (let i = 0; i < keys.length; ++i) {
+ const key = keys[i];
+ /** @type {Component} */
+ const component = this[_components][key];
+ const input = values[key];
+ const match = RegExpPrototypeExec(component.regexp, input);
+ if (match === null) {
+ return null;
}
-
- return result;
+ const groupEntries = ArrayPrototypeMap(
+ component.groupNameList,
+ (name, i) => [name, match[i + 1] ?? ""],
+ );
+ const groups = ObjectFromEntries(groupEntries);
+ result[key] = {
+ input,
+ groups,
+ };
}
- [SymbolFor("Deno.customInspect")](inspect) {
- return `URLPattern ${
- inspect({
- protocol: this.protocol,
- username: this.username,
- password: this.password,
- hostname: this.hostname,
- port: this.port,
- pathname: this.pathname,
- search: this.search,
- hash: this.hash,
- })
- }`;
- }
+ return result;
}
- webidl.configurePrototype(URLPattern);
- const URLPatternPrototype = URLPattern.prototype;
-
- webidl.converters.URLPatternInit = webidl
- .createDictionaryConverter("URLPatternInit", [
- { key: "protocol", converter: webidl.converters.USVString },
- { key: "username", converter: webidl.converters.USVString },
- { key: "password", converter: webidl.converters.USVString },
- { key: "hostname", converter: webidl.converters.USVString },
- { key: "port", converter: webidl.converters.USVString },
- { key: "pathname", converter: webidl.converters.USVString },
- { key: "search", converter: webidl.converters.USVString },
- { key: "hash", converter: webidl.converters.USVString },
- { key: "baseURL", converter: webidl.converters.USVString },
- ]);
-
- webidl.converters["URLPatternInput"] = (V, opts) => {
- // Union for (URLPatternInit or USVString)
- if (typeof V == "object") {
- return webidl.converters.URLPatternInit(V, opts);
- }
- return webidl.converters.USVString(V, opts);
- };
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return `URLPattern ${
+ inspect({
+ protocol: this.protocol,
+ username: this.username,
+ password: this.password,
+ hostname: this.hostname,
+ port: this.port,
+ pathname: this.pathname,
+ search: this.search,
+ hash: this.hash,
+ })
+ }`;
+ }
+}
+
+webidl.configurePrototype(URLPattern);
+const URLPatternPrototype = URLPattern.prototype;
+
+webidl.converters.URLPatternInit = webidl
+ .createDictionaryConverter("URLPatternInit", [
+ { key: "protocol", converter: webidl.converters.USVString },
+ { key: "username", converter: webidl.converters.USVString },
+ { key: "password", converter: webidl.converters.USVString },
+ { key: "hostname", converter: webidl.converters.USVString },
+ { key: "port", converter: webidl.converters.USVString },
+ { key: "pathname", converter: webidl.converters.USVString },
+ { key: "search", converter: webidl.converters.USVString },
+ { key: "hash", converter: webidl.converters.USVString },
+ { key: "baseURL", converter: webidl.converters.USVString },
+ ]);
+
+webidl.converters["URLPatternInput"] = (V, opts) => {
+ // Union for (URLPatternInit or USVString)
+ if (typeof V == "object") {
+ return webidl.converters.URLPatternInit(V, opts);
+ }
+ return webidl.converters.USVString(V, opts);
+};
- window.__bootstrap.urlPattern = {
- URLPattern,
- };
-})(globalThis);
+export { URLPattern };
diff --git a/ext/url/benches/url_ops.rs b/ext/url/benches/url_ops.rs
index 5a5997fc8..4b41eb3a0 100644
--- a/ext/url/benches/url_ops.rs
+++ b/ext/url/benches/url_ops.rs
@@ -12,9 +12,11 @@ fn setup() -> Vec<Extension> {
deno_webidl::init(),
deno_url::init(),
Extension::builder("bench_setup")
- .js(vec![(
- "setup",
- "const { URL } = globalThis.__bootstrap.url;",
+ .esm(vec![(
+ "internal:setup",
+ r#"import { URL } from "internal:ext/url/00_url.js";
+ globalThis.URL = URL;
+ "#,
)])
.build(),
]
diff --git a/ext/url/internal.d.ts b/ext/url/internal.d.ts
index 7065c432f..b8a2a000a 100644
--- a/ext/url/internal.d.ts
+++ b/ext/url/internal.d.ts
@@ -1,20 +1,14 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-// deno-lint-ignore-file no-var
-
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
-declare namespace globalThis {
- declare namespace __bootstrap {
- declare var url: {
- URL: typeof URL;
- URLSearchParams: typeof URLSearchParams;
- parseUrlEncoded(bytes: Uint8Array): [string, string][];
- };
+declare module "internal:ext/url/00_url.js" {
+ const URL: typeof URL;
+ const URLSearchParams: typeof URLSearchParams;
+ function parseUrlEncoded(bytes: Uint8Array): [string, string][];
+}
- declare var urlPattern: {
- URLPattern: typeof URLPattern;
- };
- }
+declare module "internal:ext/url/01_urlpattern.js" {
+ const URLPattern: typeof URLPattern;
}
diff --git a/ext/url/lib.rs b/ext/url/lib.rs
index 064590f29..95ca326c4 100644
--- a/ext/url/lib.rs
+++ b/ext/url/lib.rs
@@ -20,7 +20,7 @@ use crate::urlpattern::op_urlpattern_process_match_input;
pub fn init() -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_webidl"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/url",
"00_url.js",
"01_urlpattern.js",
diff --git a/ext/web/00_infra.js b/ext/web/00_infra.js
index 3f3f98165..c44b124c9 100644
--- a/ext/web/00_infra.js
+++ b/ext/web/00_infra.js
@@ -6,334 +6,331 @@
/// <reference path="../web/internal.d.ts" />
/// <reference path="../web/lib.deno_web.d.ts" />
-"use strict";
+const core = globalThis.Deno.core;
+const ops = core.ops;
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeJoin,
+ ArrayPrototypeMap,
+ Error,
+ JSONStringify,
+ NumberPrototypeToString,
+ RegExp,
+ SafeArrayIterator,
+ String,
+ StringPrototypeCharAt,
+ StringPrototypeCharCodeAt,
+ StringPrototypeMatch,
+ StringPrototypePadStart,
+ StringPrototypeReplace,
+ StringPrototypeSlice,
+ StringPrototypeSubstring,
+ StringPrototypeToLowerCase,
+ StringPrototypeToUpperCase,
+ TypeError,
+} = primordials;
-((window) => {
- const core = Deno.core;
- const ops = core.ops;
- const {
- ArrayPrototypeJoin,
- ArrayPrototypeMap,
- Error,
- JSONStringify,
- NumberPrototypeToString,
- RegExp,
- SafeArrayIterator,
- String,
- StringPrototypeCharAt,
- StringPrototypeCharCodeAt,
- StringPrototypeMatch,
- StringPrototypePadStart,
- StringPrototypeReplace,
- StringPrototypeSlice,
- StringPrototypeSubstring,
- StringPrototypeToLowerCase,
- StringPrototypeToUpperCase,
- TypeError,
- } = window.__bootstrap.primordials;
+const ASCII_DIGIT = ["\u0030-\u0039"];
+const ASCII_UPPER_ALPHA = ["\u0041-\u005A"];
+const ASCII_LOWER_ALPHA = ["\u0061-\u007A"];
+const ASCII_ALPHA = [
+ ...new SafeArrayIterator(ASCII_UPPER_ALPHA),
+ ...new SafeArrayIterator(ASCII_LOWER_ALPHA),
+];
+const ASCII_ALPHANUMERIC = [
+ ...new SafeArrayIterator(ASCII_DIGIT),
+ ...new SafeArrayIterator(ASCII_ALPHA),
+];
- const ASCII_DIGIT = ["\u0030-\u0039"];
- const ASCII_UPPER_ALPHA = ["\u0041-\u005A"];
- const ASCII_LOWER_ALPHA = ["\u0061-\u007A"];
- const ASCII_ALPHA = [
- ...new SafeArrayIterator(ASCII_UPPER_ALPHA),
- ...new SafeArrayIterator(ASCII_LOWER_ALPHA),
- ];
- const ASCII_ALPHANUMERIC = [
- ...new SafeArrayIterator(ASCII_DIGIT),
- ...new SafeArrayIterator(ASCII_ALPHA),
- ];
+const HTTP_TAB_OR_SPACE = ["\u0009", "\u0020"];
+const HTTP_WHITESPACE = [
+ "\u000A",
+ "\u000D",
+ ...new SafeArrayIterator(HTTP_TAB_OR_SPACE),
+];
- const HTTP_TAB_OR_SPACE = ["\u0009", "\u0020"];
- const HTTP_WHITESPACE = [
- "\u000A",
- "\u000D",
- ...new SafeArrayIterator(HTTP_TAB_OR_SPACE),
- ];
+const HTTP_TOKEN_CODE_POINT = [
+ "\u0021",
+ "\u0023",
+ "\u0024",
+ "\u0025",
+ "\u0026",
+ "\u0027",
+ "\u002A",
+ "\u002B",
+ "\u002D",
+ "\u002E",
+ "\u005E",
+ "\u005F",
+ "\u0060",
+ "\u007C",
+ "\u007E",
+ ...new SafeArrayIterator(ASCII_ALPHANUMERIC),
+];
+const HTTP_TOKEN_CODE_POINT_RE = new RegExp(
+ `^[${regexMatcher(HTTP_TOKEN_CODE_POINT)}]+$`,
+);
+const HTTP_QUOTED_STRING_TOKEN_POINT = [
+ "\u0009",
+ "\u0020-\u007E",
+ "\u0080-\u00FF",
+];
+const HTTP_QUOTED_STRING_TOKEN_POINT_RE = new RegExp(
+ `^[${regexMatcher(HTTP_QUOTED_STRING_TOKEN_POINT)}]+$`,
+);
+const HTTP_TAB_OR_SPACE_MATCHER = regexMatcher(HTTP_TAB_OR_SPACE);
+const HTTP_TAB_OR_SPACE_PREFIX_RE = new RegExp(
+ `^[${HTTP_TAB_OR_SPACE_MATCHER}]+`,
+ "g",
+);
+const HTTP_TAB_OR_SPACE_SUFFIX_RE = new RegExp(
+ `[${HTTP_TAB_OR_SPACE_MATCHER}]+$`,
+ "g",
+);
+const HTTP_WHITESPACE_MATCHER = regexMatcher(HTTP_WHITESPACE);
+const HTTP_BETWEEN_WHITESPACE = new RegExp(
+ `^[${HTTP_WHITESPACE_MATCHER}]*(.*?)[${HTTP_WHITESPACE_MATCHER}]*$`,
+);
+const HTTP_WHITESPACE_PREFIX_RE = new RegExp(
+ `^[${HTTP_WHITESPACE_MATCHER}]+`,
+ "g",
+);
+const HTTP_WHITESPACE_SUFFIX_RE = new RegExp(
+ `[${HTTP_WHITESPACE_MATCHER}]+$`,
+ "g",
+);
- const HTTP_TOKEN_CODE_POINT = [
- "\u0021",
- "\u0023",
- "\u0024",
- "\u0025",
- "\u0026",
- "\u0027",
- "\u002A",
- "\u002B",
- "\u002D",
- "\u002E",
- "\u005E",
- "\u005F",
- "\u0060",
- "\u007C",
- "\u007E",
- ...new SafeArrayIterator(ASCII_ALPHANUMERIC),
- ];
- const HTTP_TOKEN_CODE_POINT_RE = new RegExp(
- `^[${regexMatcher(HTTP_TOKEN_CODE_POINT)}]+$`,
- );
- const HTTP_QUOTED_STRING_TOKEN_POINT = [
- "\u0009",
- "\u0020-\u007E",
- "\u0080-\u00FF",
- ];
- const HTTP_QUOTED_STRING_TOKEN_POINT_RE = new RegExp(
- `^[${regexMatcher(HTTP_QUOTED_STRING_TOKEN_POINT)}]+$`,
- );
- const HTTP_TAB_OR_SPACE_MATCHER = regexMatcher(HTTP_TAB_OR_SPACE);
- const HTTP_TAB_OR_SPACE_PREFIX_RE = new RegExp(
- `^[${HTTP_TAB_OR_SPACE_MATCHER}]+`,
- "g",
- );
- const HTTP_TAB_OR_SPACE_SUFFIX_RE = new RegExp(
- `[${HTTP_TAB_OR_SPACE_MATCHER}]+$`,
- "g",
- );
- const HTTP_WHITESPACE_MATCHER = regexMatcher(HTTP_WHITESPACE);
- const HTTP_BETWEEN_WHITESPACE = new RegExp(
- `^[${HTTP_WHITESPACE_MATCHER}]*(.*?)[${HTTP_WHITESPACE_MATCHER}]*$`,
- );
- const HTTP_WHITESPACE_PREFIX_RE = new RegExp(
- `^[${HTTP_WHITESPACE_MATCHER}]+`,
- "g",
- );
- const HTTP_WHITESPACE_SUFFIX_RE = new RegExp(
- `[${HTTP_WHITESPACE_MATCHER}]+$`,
- "g",
+/**
+ * Turn a string of chars into a regex safe matcher.
+ * @param {string[]} chars
+ * @returns {string}
+ */
+function regexMatcher(chars) {
+ const matchers = ArrayPrototypeMap(chars, (char) => {
+ if (char.length === 1) {
+ const a = StringPrototypePadStart(
+ NumberPrototypeToString(StringPrototypeCharCodeAt(char, 0), 16),
+ 4,
+ "0",
+ );
+ return `\\u${a}`;
+ } else if (char.length === 3 && char[1] === "-") {
+ const a = StringPrototypePadStart(
+ NumberPrototypeToString(StringPrototypeCharCodeAt(char, 0), 16),
+ 4,
+ "0",
+ );
+ const b = StringPrototypePadStart(
+ NumberPrototypeToString(StringPrototypeCharCodeAt(char, 2), 16),
+ 4,
+ "0",
+ );
+ return `\\u${a}-\\u${b}`;
+ } else {
+ throw TypeError("unreachable");
+ }
+ });
+ return ArrayPrototypeJoin(matchers, "");
+}
+
+/**
+ * https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
+ * @param {string} input
+ * @param {number} position
+ * @param {(char: string) => boolean} condition
+ * @returns {{result: string, position: number}}
+ */
+function collectSequenceOfCodepoints(input, position, condition) {
+ const start = position;
+ for (
+ let c = StringPrototypeCharAt(input, position);
+ position < input.length && condition(c);
+ c = StringPrototypeCharAt(input, ++position)
);
+ return { result: StringPrototypeSlice(input, start, position), position };
+}
- /**
- * Turn a string of chars into a regex safe matcher.
- * @param {string[]} chars
- * @returns {string}
- */
- function regexMatcher(chars) {
- const matchers = ArrayPrototypeMap(chars, (char) => {
- if (char.length === 1) {
- const a = StringPrototypePadStart(
- NumberPrototypeToString(StringPrototypeCharCodeAt(char, 0), 16),
- 4,
- "0",
- );
- return `\\u${a}`;
- } else if (char.length === 3 && char[1] === "-") {
- const a = StringPrototypePadStart(
- NumberPrototypeToString(StringPrototypeCharCodeAt(char, 0), 16),
- 4,
- "0",
- );
- const b = StringPrototypePadStart(
- NumberPrototypeToString(StringPrototypeCharCodeAt(char, 2), 16),
- 4,
- "0",
- );
- return `\\u${a}-\\u${b}`;
- } else {
- throw TypeError("unreachable");
- }
- });
- return ArrayPrototypeJoin(matchers, "");
- }
+/**
+ * @param {string} s
+ * @returns {string}
+ */
+function byteUpperCase(s) {
+ return StringPrototypeReplace(
+ String(s),
+ /[a-z]/g,
+ function byteUpperCaseReplace(c) {
+ return StringPrototypeToUpperCase(c);
+ },
+ );
+}
- /**
- * https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
- * @param {string} input
- * @param {number} position
- * @param {(char: string) => boolean} condition
- * @returns {{result: string, position: number}}
- */
- function collectSequenceOfCodepoints(input, position, condition) {
- const start = position;
- for (
- let c = StringPrototypeCharAt(input, position);
- position < input.length && condition(c);
- c = StringPrototypeCharAt(input, ++position)
- );
- return { result: StringPrototypeSlice(input, start, position), position };
- }
+/**
+ * @param {string} s
+ * @returns {string}
+ */
+function byteLowerCase(s) {
+ // NOTE: correct since all callers convert to ByteString first
+ // TODO(@AaronO): maybe prefer a ByteString_Lower webidl converter
+ return StringPrototypeToLowerCase(s);
+}
- /**
- * @param {string} s
- * @returns {string}
- */
- function byteUpperCase(s) {
- return StringPrototypeReplace(
- String(s),
- /[a-z]/g,
- function byteUpperCaseReplace(c) {
- return StringPrototypeToUpperCase(c);
- },
+/**
+ * https://fetch.spec.whatwg.org/#collect-an-http-quoted-string
+ * @param {string} input
+ * @param {number} position
+ * @param {boolean} extractValue
+ * @returns {{result: string, position: number}}
+ */
+function collectHttpQuotedString(input, position, extractValue) {
+ // 1.
+ const positionStart = position;
+ // 2.
+ let value = "";
+ // 3.
+ if (input[position] !== "\u0022") throw new TypeError('must be "');
+ // 4.
+ position++;
+ // 5.
+ while (true) {
+ // 5.1.
+ const res = collectSequenceOfCodepoints(
+ input,
+ position,
+ (c) => c !== "\u0022" && c !== "\u005C",
);
- }
-
- /**
- * @param {string} s
- * @returns {string}
- */
- function byteLowerCase(s) {
- // NOTE: correct since all callers convert to ByteString first
- // TODO(@AaronO): maybe prefer a ByteString_Lower webidl converter
- return StringPrototypeToLowerCase(s);
- }
-
- /**
- * https://fetch.spec.whatwg.org/#collect-an-http-quoted-string
- * @param {string} input
- * @param {number} position
- * @param {boolean} extractValue
- * @returns {{result: string, position: number}}
- */
- function collectHttpQuotedString(input, position, extractValue) {
- // 1.
- const positionStart = position;
- // 2.
- let value = "";
- // 3.
- if (input[position] !== "\u0022") throw new TypeError('must be "');
- // 4.
+ value += res.result;
+ position = res.position;
+ // 5.2.
+ if (position >= input.length) break;
+ // 5.3.
+ const quoteOrBackslash = input[position];
+ // 5.4.
position++;
- // 5.
- while (true) {
- // 5.1.
- const res = collectSequenceOfCodepoints(
- input,
- position,
- (c) => c !== "\u0022" && c !== "\u005C",
- );
- value += res.result;
- position = res.position;
- // 5.2.
- if (position >= input.length) break;
- // 5.3.
- const quoteOrBackslash = input[position];
- // 5.4.
- position++;
- // 5.5.
- if (quoteOrBackslash === "\u005C") {
- // 5.5.1.
- if (position >= input.length) {
- value += "\u005C";
- break;
- }
- // 5.5.2.
- value += input[position];
- // 5.5.3.
- position++;
- } else { // 5.6.
- // 5.6.1
- if (quoteOrBackslash !== "\u0022") throw new TypeError('must be "');
- // 5.6.2
+ // 5.5.
+ if (quoteOrBackslash === "\u005C") {
+ // 5.5.1.
+ if (position >= input.length) {
+ value += "\u005C";
break;
}
+ // 5.5.2.
+ value += input[position];
+ // 5.5.3.
+ position++;
+ } else { // 5.6.
+ // 5.6.1
+ if (quoteOrBackslash !== "\u0022") throw new TypeError('must be "');
+ // 5.6.2
+ break;
}
- // 6.
- if (extractValue) return { result: value, position };
- // 7.
- return {
- result: StringPrototypeSubstring(input, positionStart, position + 1),
- position,
- };
}
+ // 6.
+ if (extractValue) return { result: value, position };
+ // 7.
+ return {
+ result: StringPrototypeSubstring(input, positionStart, position + 1),
+ position,
+ };
+}
- /**
- * @param {Uint8Array} data
- * @returns {string}
- */
- function forgivingBase64Encode(data) {
- return ops.op_base64_encode(data);
- }
+/**
+ * @param {Uint8Array} data
+ * @returns {string}
+ */
+function forgivingBase64Encode(data) {
+ return ops.op_base64_encode(data);
+}
- /**
- * @param {string} data
- * @returns {Uint8Array}
- */
- function forgivingBase64Decode(data) {
- return ops.op_base64_decode(data);
- }
+/**
+ * @param {string} data
+ * @returns {Uint8Array}
+ */
+function forgivingBase64Decode(data) {
+ return ops.op_base64_decode(data);
+}
- /**
- * @param {string} char
- * @returns {boolean}
- */
- function isHttpWhitespace(char) {
- switch (char) {
- case "\u0009":
- case "\u000A":
- case "\u000D":
- case "\u0020":
- return true;
- default:
- return false;
- }
+/**
+ * @param {string} char
+ * @returns {boolean}
+ */
+function isHttpWhitespace(char) {
+ switch (char) {
+ case "\u0009":
+ case "\u000A":
+ case "\u000D":
+ case "\u0020":
+ return true;
+ default:
+ return false;
}
+}
- /**
- * @param {string} s
- * @returns {string}
- */
- function httpTrim(s) {
- if (!isHttpWhitespace(s[0]) && !isHttpWhitespace(s[s.length - 1])) {
- return s;
- }
- return StringPrototypeMatch(s, HTTP_BETWEEN_WHITESPACE)?.[1] ?? "";
+/**
+ * @param {string} s
+ * @returns {string}
+ */
+function httpTrim(s) {
+ if (!isHttpWhitespace(s[0]) && !isHttpWhitespace(s[s.length - 1])) {
+ return s;
}
+ return StringPrototypeMatch(s, HTTP_BETWEEN_WHITESPACE)?.[1] ?? "";
+}
- class AssertionError extends Error {
- constructor(msg) {
- super(msg);
- this.name = "AssertionError";
- }
+class AssertionError extends Error {
+ constructor(msg) {
+ super(msg);
+ this.name = "AssertionError";
}
+}
- /**
- * @param {unknown} cond
- * @param {string=} msg
- * @returns {asserts cond}
- */
- function assert(cond, msg = "Assertion failed.") {
- if (!cond) {
- throw new AssertionError(msg);
- }
+/**
+ * @param {unknown} cond
+ * @param {string=} msg
+ * @returns {asserts cond}
+ */
+function assert(cond, msg = "Assertion failed.") {
+ if (!cond) {
+ throw new AssertionError(msg);
}
+}
- /**
- * @param {unknown} value
- * @returns {string}
- */
- function serializeJSValueToJSONString(value) {
- const result = JSONStringify(value);
- if (result === undefined) {
- throw new TypeError("Value is not JSON serializable.");
- }
- return result;
+/**
+ * @param {unknown} value
+ * @returns {string}
+ */
+function serializeJSValueToJSONString(value) {
+ const result = JSONStringify(value);
+ if (result === undefined) {
+ throw new TypeError("Value is not JSON serializable.");
}
+ return result;
+}
- window.__bootstrap.infra = {
- collectSequenceOfCodepoints,
- ASCII_DIGIT,
- ASCII_UPPER_ALPHA,
- ASCII_LOWER_ALPHA,
- ASCII_ALPHA,
- ASCII_ALPHANUMERIC,
- HTTP_TAB_OR_SPACE,
- HTTP_WHITESPACE,
- HTTP_TOKEN_CODE_POINT,
- HTTP_TOKEN_CODE_POINT_RE,
- HTTP_QUOTED_STRING_TOKEN_POINT,
- HTTP_QUOTED_STRING_TOKEN_POINT_RE,
- HTTP_TAB_OR_SPACE_PREFIX_RE,
- HTTP_TAB_OR_SPACE_SUFFIX_RE,
- HTTP_WHITESPACE_PREFIX_RE,
- HTTP_WHITESPACE_SUFFIX_RE,
- httpTrim,
- regexMatcher,
- byteUpperCase,
- byteLowerCase,
- collectHttpQuotedString,
- forgivingBase64Encode,
- forgivingBase64Decode,
- AssertionError,
- assert,
- serializeJSValueToJSONString,
- };
-})(globalThis);
+export {
+ ASCII_ALPHA,
+ ASCII_ALPHANUMERIC,
+ ASCII_DIGIT,
+ ASCII_LOWER_ALPHA,
+ ASCII_UPPER_ALPHA,
+ assert,
+ AssertionError,
+ byteLowerCase,
+ byteUpperCase,
+ collectHttpQuotedString,
+ collectSequenceOfCodepoints,
+ forgivingBase64Decode,
+ forgivingBase64Encode,
+ HTTP_QUOTED_STRING_TOKEN_POINT,
+ HTTP_QUOTED_STRING_TOKEN_POINT_RE,
+ HTTP_TAB_OR_SPACE,
+ HTTP_TAB_OR_SPACE_PREFIX_RE,
+ HTTP_TAB_OR_SPACE_SUFFIX_RE,
+ HTTP_TOKEN_CODE_POINT,
+ HTTP_TOKEN_CODE_POINT_RE,
+ HTTP_WHITESPACE,
+ HTTP_WHITESPACE_PREFIX_RE,
+ HTTP_WHITESPACE_SUFFIX_RE,
+ httpTrim,
+ regexMatcher,
+ serializeJSValueToJSONString,
+};
diff --git a/ext/web/01_dom_exception.js b/ext/web/01_dom_exception.js
index a4556c03c..cbec9ca22 100644
--- a/ext/web/01_dom_exception.js
+++ b/ext/web/01_dom_exception.js
@@ -7,197 +7,194 @@
/// <reference path="../web/internal.d.ts" />
/// <reference path="../web/lib.deno_web.d.ts" />
-"use strict";
-
-((window) => {
- const {
- ArrayPrototypeSlice,
- Error,
- ErrorPrototype,
- ObjectDefineProperty,
- ObjectCreate,
- ObjectEntries,
- ObjectPrototypeIsPrototypeOf,
- ObjectSetPrototypeOf,
- Symbol,
- SymbolFor,
- } = window.__bootstrap.primordials;
- const webidl = window.__bootstrap.webidl;
- const consoleInternal = window.__bootstrap.console;
-
- const _name = Symbol("name");
- const _message = Symbol("message");
- const _code = Symbol("code");
-
- // Defined in WebIDL 4.3.
- // https://webidl.spec.whatwg.org/#idl-DOMException
- const INDEX_SIZE_ERR = 1;
- const DOMSTRING_SIZE_ERR = 2;
- const HIERARCHY_REQUEST_ERR = 3;
- const WRONG_DOCUMENT_ERR = 4;
- const INVALID_CHARACTER_ERR = 5;
- const NO_DATA_ALLOWED_ERR = 6;
- const NO_MODIFICATION_ALLOWED_ERR = 7;
- const NOT_FOUND_ERR = 8;
- const NOT_SUPPORTED_ERR = 9;
- const INUSE_ATTRIBUTE_ERR = 10;
- const INVALID_STATE_ERR = 11;
- const SYNTAX_ERR = 12;
- const INVALID_MODIFICATION_ERR = 13;
- const NAMESPACE_ERR = 14;
- const INVALID_ACCESS_ERR = 15;
- const VALIDATION_ERR = 16;
- const TYPE_MISMATCH_ERR = 17;
- const SECURITY_ERR = 18;
- const NETWORK_ERR = 19;
- const ABORT_ERR = 20;
- const URL_MISMATCH_ERR = 21;
- const QUOTA_EXCEEDED_ERR = 22;
- const TIMEOUT_ERR = 23;
- const INVALID_NODE_TYPE_ERR = 24;
- const DATA_CLONE_ERR = 25;
-
- // Defined in WebIDL 2.8.1.
- // https://webidl.spec.whatwg.org/#dfn-error-names-table
- /** @type {Record<string, number>} */
- // the prototype should be null, to prevent user code from looking
- // up Object.prototype properties, such as "toString"
- const nameToCodeMapping = ObjectCreate(null, {
- IndexSizeError: { value: INDEX_SIZE_ERR },
- HierarchyRequestError: { value: HIERARCHY_REQUEST_ERR },
- WrongDocumentError: { value: WRONG_DOCUMENT_ERR },
- InvalidCharacterError: { value: INVALID_CHARACTER_ERR },
- NoModificationAllowedError: { value: NO_MODIFICATION_ALLOWED_ERR },
- NotFoundError: { value: NOT_FOUND_ERR },
- NotSupportedError: { value: NOT_SUPPORTED_ERR },
- InUseAttributeError: { value: INUSE_ATTRIBUTE_ERR },
- InvalidStateError: { value: INVALID_STATE_ERR },
- SyntaxError: { value: SYNTAX_ERR },
- InvalidModificationError: { value: INVALID_MODIFICATION_ERR },
- NamespaceError: { value: NAMESPACE_ERR },
- InvalidAccessError: { value: INVALID_ACCESS_ERR },
- TypeMismatchError: { value: TYPE_MISMATCH_ERR },
- SecurityError: { value: SECURITY_ERR },
- NetworkError: { value: NETWORK_ERR },
- AbortError: { value: ABORT_ERR },
- URLMismatchError: { value: URL_MISMATCH_ERR },
- QuotaExceededError: { value: QUOTA_EXCEEDED_ERR },
- TimeoutError: { value: TIMEOUT_ERR },
- InvalidNodeTypeError: { value: INVALID_NODE_TYPE_ERR },
- DataCloneError: { value: DATA_CLONE_ERR },
- });
-
- // Defined in WebIDL 4.3.
- // https://webidl.spec.whatwg.org/#idl-DOMException
- class DOMException {
- [_message];
- [_name];
- [_code];
-
- // https://webidl.spec.whatwg.org/#dom-domexception-domexception
- constructor(message = "", name = "Error") {
- message = webidl.converters.DOMString(message, {
- prefix: "Failed to construct 'DOMException'",
- context: "Argument 1",
- });
- name = webidl.converters.DOMString(name, {
- prefix: "Failed to construct 'DOMException'",
- context: "Argument 2",
- });
- const code = nameToCodeMapping[name] ?? 0;
-
- this[_message] = message;
- this[_name] = name;
- this[_code] = code;
- this[webidl.brand] = webidl.brand;
-
- const error = new Error(message);
- error.name = "DOMException";
- ObjectDefineProperty(this, "stack", {
- value: error.stack,
- writable: true,
- configurable: true,
- });
-
- // `DOMException` isn't a native error, so `Error.prepareStackTrace()` is
- // not called when accessing `.stack`, meaning our structured stack trace
- // hack doesn't apply. This patches it in.
- ObjectDefineProperty(this, "__callSiteEvals", {
- value: ArrayPrototypeSlice(error.__callSiteEvals, 1),
- configurable: true,
- });
- }
-
- get message() {
- webidl.assertBranded(this, DOMExceptionPrototype);
- return this[_message];
- }
-
- get name() {
- webidl.assertBranded(this, DOMExceptionPrototype);
- return this[_name];
- }
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeSlice,
+ Error,
+ ErrorPrototype,
+ ObjectDefineProperty,
+ ObjectCreate,
+ ObjectEntries,
+ ObjectPrototypeIsPrototypeOf,
+ ObjectSetPrototypeOf,
+ Symbol,
+ SymbolFor,
+} = primordials;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { createFilteredInspectProxy } from "internal:ext/console/02_console.js";
+
+const _name = Symbol("name");
+const _message = Symbol("message");
+const _code = Symbol("code");
+
+// Defined in WebIDL 4.3.
+// https://webidl.spec.whatwg.org/#idl-DOMException
+const INDEX_SIZE_ERR = 1;
+const DOMSTRING_SIZE_ERR = 2;
+const HIERARCHY_REQUEST_ERR = 3;
+const WRONG_DOCUMENT_ERR = 4;
+const INVALID_CHARACTER_ERR = 5;
+const NO_DATA_ALLOWED_ERR = 6;
+const NO_MODIFICATION_ALLOWED_ERR = 7;
+const NOT_FOUND_ERR = 8;
+const NOT_SUPPORTED_ERR = 9;
+const INUSE_ATTRIBUTE_ERR = 10;
+const INVALID_STATE_ERR = 11;
+const SYNTAX_ERR = 12;
+const INVALID_MODIFICATION_ERR = 13;
+const NAMESPACE_ERR = 14;
+const INVALID_ACCESS_ERR = 15;
+const VALIDATION_ERR = 16;
+const TYPE_MISMATCH_ERR = 17;
+const SECURITY_ERR = 18;
+const NETWORK_ERR = 19;
+const ABORT_ERR = 20;
+const URL_MISMATCH_ERR = 21;
+const QUOTA_EXCEEDED_ERR = 22;
+const TIMEOUT_ERR = 23;
+const INVALID_NODE_TYPE_ERR = 24;
+const DATA_CLONE_ERR = 25;
+
+// Defined in WebIDL 2.8.1.
+// https://webidl.spec.whatwg.org/#dfn-error-names-table
+/** @type {Record<string, number>} */
+// the prototype should be null, to prevent user code from looking
+// up Object.prototype properties, such as "toString"
+const nameToCodeMapping = ObjectCreate(null, {
+ IndexSizeError: { value: INDEX_SIZE_ERR },
+ HierarchyRequestError: { value: HIERARCHY_REQUEST_ERR },
+ WrongDocumentError: { value: WRONG_DOCUMENT_ERR },
+ InvalidCharacterError: { value: INVALID_CHARACTER_ERR },
+ NoModificationAllowedError: { value: NO_MODIFICATION_ALLOWED_ERR },
+ NotFoundError: { value: NOT_FOUND_ERR },
+ NotSupportedError: { value: NOT_SUPPORTED_ERR },
+ InUseAttributeError: { value: INUSE_ATTRIBUTE_ERR },
+ InvalidStateError: { value: INVALID_STATE_ERR },
+ SyntaxError: { value: SYNTAX_ERR },
+ InvalidModificationError: { value: INVALID_MODIFICATION_ERR },
+ NamespaceError: { value: NAMESPACE_ERR },
+ InvalidAccessError: { value: INVALID_ACCESS_ERR },
+ TypeMismatchError: { value: TYPE_MISMATCH_ERR },
+ SecurityError: { value: SECURITY_ERR },
+ NetworkError: { value: NETWORK_ERR },
+ AbortError: { value: ABORT_ERR },
+ URLMismatchError: { value: URL_MISMATCH_ERR },
+ QuotaExceededError: { value: QUOTA_EXCEEDED_ERR },
+ TimeoutError: { value: TIMEOUT_ERR },
+ InvalidNodeTypeError: { value: INVALID_NODE_TYPE_ERR },
+ DataCloneError: { value: DATA_CLONE_ERR },
+});
+
+// Defined in WebIDL 4.3.
+// https://webidl.spec.whatwg.org/#idl-DOMException
+class DOMException {
+ [_message];
+ [_name];
+ [_code];
+
+ // https://webidl.spec.whatwg.org/#dom-domexception-domexception
+ constructor(message = "", name = "Error") {
+ message = webidl.converters.DOMString(message, {
+ prefix: "Failed to construct 'DOMException'",
+ context: "Argument 1",
+ });
+ name = webidl.converters.DOMString(name, {
+ prefix: "Failed to construct 'DOMException'",
+ context: "Argument 2",
+ });
+ const code = nameToCodeMapping[name] ?? 0;
+
+ this[_message] = message;
+ this[_name] = name;
+ this[_code] = code;
+ this[webidl.brand] = webidl.brand;
+
+ const error = new Error(message);
+ error.name = "DOMException";
+ ObjectDefineProperty(this, "stack", {
+ value: error.stack,
+ writable: true,
+ configurable: true,
+ });
+
+ // `DOMException` isn't a native error, so `Error.prepareStackTrace()` is
+ // not called when accessing `.stack`, meaning our structured stack trace
+ // hack doesn't apply. This patches it in.
+ ObjectDefineProperty(this, "__callSiteEvals", {
+ value: ArrayPrototypeSlice(error.__callSiteEvals, 1),
+ configurable: true,
+ });
+ }
- get code() {
- webidl.assertBranded(this, DOMExceptionPrototype);
- return this[_code];
- }
+ get message() {
+ webidl.assertBranded(this, DOMExceptionPrototype);
+ return this[_message];
+ }
- [SymbolFor("Deno.customInspect")](inspect) {
- if (ObjectPrototypeIsPrototypeOf(DOMExceptionPrototype, this)) {
- return `DOMException: ${this[_message]}`;
- } else {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: false,
- keys: [
- "message",
- "name",
- "code",
- ],
- }));
- }
- }
+ get name() {
+ webidl.assertBranded(this, DOMExceptionPrototype);
+ return this[_name];
}
- ObjectSetPrototypeOf(DOMException.prototype, ErrorPrototype);
-
- webidl.configurePrototype(DOMException);
- const DOMExceptionPrototype = DOMException.prototype;
-
- const entries = ObjectEntries({
- INDEX_SIZE_ERR,
- DOMSTRING_SIZE_ERR,
- HIERARCHY_REQUEST_ERR,
- WRONG_DOCUMENT_ERR,
- INVALID_CHARACTER_ERR,
- NO_DATA_ALLOWED_ERR,
- NO_MODIFICATION_ALLOWED_ERR,
- NOT_FOUND_ERR,
- NOT_SUPPORTED_ERR,
- INUSE_ATTRIBUTE_ERR,
- INVALID_STATE_ERR,
- SYNTAX_ERR,
- INVALID_MODIFICATION_ERR,
- NAMESPACE_ERR,
- INVALID_ACCESS_ERR,
- VALIDATION_ERR,
- TYPE_MISMATCH_ERR,
- SECURITY_ERR,
- NETWORK_ERR,
- ABORT_ERR,
- URL_MISMATCH_ERR,
- QUOTA_EXCEEDED_ERR,
- TIMEOUT_ERR,
- INVALID_NODE_TYPE_ERR,
- DATA_CLONE_ERR,
- });
- for (let i = 0; i < entries.length; ++i) {
- const { 0: key, 1: value } = entries[i];
- const desc = { value, enumerable: true };
- ObjectDefineProperty(DOMException, key, desc);
- ObjectDefineProperty(DOMException.prototype, key, desc);
+ get code() {
+ webidl.assertBranded(this, DOMExceptionPrototype);
+ return this[_code];
}
- window.__bootstrap.domException = { DOMException };
-})(this);
+ [SymbolFor("Deno.customInspect")](inspect) {
+ if (ObjectPrototypeIsPrototypeOf(DOMExceptionPrototype, this)) {
+ return `DOMException: ${this[_message]}`;
+ } else {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: false,
+ keys: [
+ "message",
+ "name",
+ "code",
+ ],
+ }));
+ }
+ }
+}
+
+ObjectSetPrototypeOf(DOMException.prototype, ErrorPrototype);
+
+webidl.configurePrototype(DOMException);
+const DOMExceptionPrototype = DOMException.prototype;
+
+const entries = ObjectEntries({
+ INDEX_SIZE_ERR,
+ DOMSTRING_SIZE_ERR,
+ HIERARCHY_REQUEST_ERR,
+ WRONG_DOCUMENT_ERR,
+ INVALID_CHARACTER_ERR,
+ NO_DATA_ALLOWED_ERR,
+ NO_MODIFICATION_ALLOWED_ERR,
+ NOT_FOUND_ERR,
+ NOT_SUPPORTED_ERR,
+ INUSE_ATTRIBUTE_ERR,
+ INVALID_STATE_ERR,
+ SYNTAX_ERR,
+ INVALID_MODIFICATION_ERR,
+ NAMESPACE_ERR,
+ INVALID_ACCESS_ERR,
+ VALIDATION_ERR,
+ TYPE_MISMATCH_ERR,
+ SECURITY_ERR,
+ NETWORK_ERR,
+ ABORT_ERR,
+ URL_MISMATCH_ERR,
+ QUOTA_EXCEEDED_ERR,
+ TIMEOUT_ERR,
+ INVALID_NODE_TYPE_ERR,
+ DATA_CLONE_ERR,
+});
+for (let i = 0; i < entries.length; ++i) {
+ const { 0: key, 1: value } = entries[i];
+ const desc = { value, enumerable: true };
+ ObjectDefineProperty(DOMException, key, desc);
+ ObjectDefineProperty(DOMException.prototype, key, desc);
+}
+
+export default DOMException;
diff --git a/ext/web/01_mimesniff.js b/ext/web/01_mimesniff.js
index 2d67d5f95..17d954eb4 100644
--- a/ext/web/01_mimesniff.js
+++ b/ext/web/01_mimesniff.js
@@ -6,255 +6,247 @@
/// <reference path="../web/internal.d.ts" />
/// <reference path="../web/lib.deno_web.d.ts" />
-"use strict";
-
-((window) => {
- const {
- ArrayPrototypeIncludes,
- Map,
- MapPrototypeGet,
- MapPrototypeHas,
- MapPrototypeSet,
- RegExpPrototypeTest,
- SafeMapIterator,
- StringPrototypeReplaceAll,
- StringPrototypeToLowerCase,
- } = window.__bootstrap.primordials;
- const {
- collectSequenceOfCodepoints,
- HTTP_WHITESPACE,
- HTTP_WHITESPACE_PREFIX_RE,
- HTTP_WHITESPACE_SUFFIX_RE,
- HTTP_QUOTED_STRING_TOKEN_POINT_RE,
- HTTP_TOKEN_CODE_POINT_RE,
- collectHttpQuotedString,
- } = window.__bootstrap.infra;
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeIncludes,
+ Map,
+ MapPrototypeGet,
+ MapPrototypeHas,
+ MapPrototypeSet,
+ RegExpPrototypeTest,
+ SafeMapIterator,
+ StringPrototypeReplaceAll,
+ StringPrototypeToLowerCase,
+} = primordials;
+import {
+ collectHttpQuotedString,
+ collectSequenceOfCodepoints,
+ HTTP_QUOTED_STRING_TOKEN_POINT_RE,
+ HTTP_TOKEN_CODE_POINT_RE,
+ HTTP_WHITESPACE,
+ HTTP_WHITESPACE_PREFIX_RE,
+ HTTP_WHITESPACE_SUFFIX_RE,
+} from "internal:ext/web/00_infra.js";
+
+/**
+ * @typedef MimeType
+ * @property {string} type
+ * @property {string} subtype
+ * @property {Map<string,string>} parameters
+ */
+
+/**
+ * @param {string} input
+ * @returns {MimeType | null}
+ */
+function parseMimeType(input) {
+ // 1.
+ input = StringPrototypeReplaceAll(input, HTTP_WHITESPACE_PREFIX_RE, "");
+ input = StringPrototypeReplaceAll(input, HTTP_WHITESPACE_SUFFIX_RE, "");
+
+ // 2.
+ let position = 0;
+ const endOfInput = input.length;
+
+ // 3.
+ const res1 = collectSequenceOfCodepoints(
+ input,
+ position,
+ (c) => c != "\u002F",
+ );
+ const type = res1.result;
+ position = res1.position;
+
+ // 4.
+ if (type === "" || !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, type)) {
+ return null;
+ }
- /**
- * @typedef MimeType
- * @property {string} type
- * @property {string} subtype
- * @property {Map<string,string>} parameters
- */
+ // 5.
+ if (position >= endOfInput) return null;
+
+ // 6.
+ position++;
+
+ // 7.
+ const res2 = collectSequenceOfCodepoints(
+ input,
+ position,
+ (c) => c != "\u003B",
+ );
+ let subtype = res2.result;
+ position = res2.position;
+
+ // 8.
+ subtype = StringPrototypeReplaceAll(subtype, HTTP_WHITESPACE_SUFFIX_RE, "");
+
+ // 9.
+ if (
+ subtype === "" || !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, subtype)
+ ) {
+ return null;
+ }
- /**
- * @param {string} input
- * @returns {MimeType | null}
- */
- function parseMimeType(input) {
- // 1.
- input = StringPrototypeReplaceAll(input, HTTP_WHITESPACE_PREFIX_RE, "");
- input = StringPrototypeReplaceAll(input, HTTP_WHITESPACE_SUFFIX_RE, "");
+ // 10.
+ const mimeType = {
+ type: StringPrototypeToLowerCase(type),
+ subtype: StringPrototypeToLowerCase(subtype),
+ /** @type {Map<string, string>} */
+ parameters: new Map(),
+ };
- // 2.
- let position = 0;
- const endOfInput = input.length;
+ // 11.
+ while (position < endOfInput) {
+ // 11.1.
+ position++;
- // 3.
+ // 11.2.
const res1 = collectSequenceOfCodepoints(
input,
position,
- (c) => c != "\u002F",
+ (c) => ArrayPrototypeIncludes(HTTP_WHITESPACE, c),
);
- const type = res1.result;
position = res1.position;
- // 4.
- if (type === "" || !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, type)) {
- return null;
- }
-
- // 5.
- if (position >= endOfInput) return null;
-
- // 6.
- position++;
-
- // 7.
+ // 11.3.
const res2 = collectSequenceOfCodepoints(
input,
position,
- (c) => c != "\u003B",
+ (c) => c !== "\u003B" && c !== "\u003D",
);
- let subtype = res2.result;
+ let parameterName = res2.result;
position = res2.position;
- // 8.
- subtype = StringPrototypeReplaceAll(subtype, HTTP_WHITESPACE_SUFFIX_RE, "");
+ // 11.4.
+ parameterName = StringPrototypeToLowerCase(parameterName);
- // 9.
- if (
- subtype === "" || !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, subtype)
- ) {
- return null;
+ // 11.5.
+ if (position < endOfInput) {
+ if (input[position] == "\u003B") continue;
+ position++;
}
- // 10.
- const mimeType = {
- type: StringPrototypeToLowerCase(type),
- subtype: StringPrototypeToLowerCase(subtype),
- /** @type {Map<string, string>} */
- parameters: new Map(),
- };
+ // 11.6.
+ if (position >= endOfInput) break;
- // 11.
- while (position < endOfInput) {
- // 11.1.
- position++;
+ // 11.7.
+ let parameterValue = null;
- // 11.2.
- const res1 = collectSequenceOfCodepoints(
- input,
- position,
- (c) => ArrayPrototypeIncludes(HTTP_WHITESPACE, c),
- );
- position = res1.position;
+ // 11.8.
+ if (input[position] === "\u0022") {
+ // 11.8.1.
+ const res = collectHttpQuotedString(input, position, true);
+ parameterValue = res.result;
+ position = res.position;
- // 11.3.
- const res2 = collectSequenceOfCodepoints(
+ // 11.8.2.
+ position++;
+ } else { // 11.9.
+ // 11.9.1.
+ const res = collectSequenceOfCodepoints(
input,
position,
- (c) => c !== "\u003B" && c !== "\u003D",
+ (c) => c !== "\u003B",
+ );
+ parameterValue = res.result;
+ position = res.position;
+
+ // 11.9.2.
+ parameterValue = StringPrototypeReplaceAll(
+ parameterValue,
+ HTTP_WHITESPACE_SUFFIX_RE,
+ "",
);
- let parameterName = res2.result;
- position = res2.position;
-
- // 11.4.
- parameterName = StringPrototypeToLowerCase(parameterName);
-
- // 11.5.
- if (position < endOfInput) {
- if (input[position] == "\u003B") continue;
- position++;
- }
-
- // 11.6.
- if (position >= endOfInput) break;
-
- // 11.7.
- let parameterValue = null;
-
- // 11.8.
- if (input[position] === "\u0022") {
- // 11.8.1.
- const res = collectHttpQuotedString(input, position, true);
- parameterValue = res.result;
- position = res.position;
-
- // 11.8.2.
- position++;
- } else { // 11.9.
- // 11.9.1.
- const res = collectSequenceOfCodepoints(
- input,
- position,
- (c) => c !== "\u003B",
- );
- parameterValue = res.result;
- position = res.position;
-
- // 11.9.2.
- parameterValue = StringPrototypeReplaceAll(
- parameterValue,
- HTTP_WHITESPACE_SUFFIX_RE,
- "",
- );
-
- // 11.9.3.
- if (parameterValue === "") continue;
- }
- // 11.10.
- if (
- parameterName !== "" &&
- RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, parameterName) &&
- RegExpPrototypeTest(
- HTTP_QUOTED_STRING_TOKEN_POINT_RE,
- parameterValue,
- ) &&
- !MapPrototypeHas(mimeType.parameters, parameterName)
- ) {
- MapPrototypeSet(mimeType.parameters, parameterName, parameterValue);
- }
+ // 11.9.3.
+ if (parameterValue === "") continue;
}
- // 12.
- return mimeType;
- }
-
- /**
- * @param {MimeType} mimeType
- * @returns {string}
- */
- function essence(mimeType) {
- return `${mimeType.type}/${mimeType.subtype}`;
+ // 11.10.
+ if (
+ parameterName !== "" &&
+ RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, parameterName) &&
+ RegExpPrototypeTest(
+ HTTP_QUOTED_STRING_TOKEN_POINT_RE,
+ parameterValue,
+ ) &&
+ !MapPrototypeHas(mimeType.parameters, parameterName)
+ ) {
+ MapPrototypeSet(mimeType.parameters, parameterName, parameterValue);
+ }
}
- /**
- * @param {MimeType} mimeType
- * @returns {string}
- */
- function serializeMimeType(mimeType) {
- let serialization = essence(mimeType);
- for (const param of new SafeMapIterator(mimeType.parameters)) {
- serialization += `;${param[0]}=`;
- let value = param[1];
- if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, value)) {
- value = StringPrototypeReplaceAll(value, "\\", "\\\\");
- value = StringPrototypeReplaceAll(value, '"', '\\"');
- value = `"${value}"`;
- }
- serialization += value;
+ // 12.
+ return mimeType;
+}
+
+/**
+ * @param {MimeType} mimeType
+ * @returns {string}
+ */
+function essence(mimeType) {
+ return `${mimeType.type}/${mimeType.subtype}`;
+}
+
+/**
+ * @param {MimeType} mimeType
+ * @returns {string}
+ */
+function serializeMimeType(mimeType) {
+ let serialization = essence(mimeType);
+ for (const param of new SafeMapIterator(mimeType.parameters)) {
+ serialization += `;${param[0]}=`;
+ let value = param[1];
+ if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, value)) {
+ value = StringPrototypeReplaceAll(value, "\\", "\\\\");
+ value = StringPrototypeReplaceAll(value, '"', '\\"');
+ value = `"${value}"`;
}
- return serialization;
+ serialization += value;
}
-
- /**
- * Part of the Fetch spec's "extract a MIME type" algorithm
- * (https://fetch.spec.whatwg.org/#concept-header-extract-mime-type).
- * @param {string[] | null} headerValues The result of getting, decoding and
- * splitting the "Content-Type" header.
- * @returns {MimeType | null}
- */
- function extractMimeType(headerValues) {
- if (headerValues === null) return null;
-
- let charset = null;
- let essence_ = null;
- let mimeType = null;
- for (let i = 0; i < headerValues.length; ++i) {
- const value = headerValues[i];
- const temporaryMimeType = parseMimeType(value);
+ return serialization;
+}
+
+/**
+ * Part of the Fetch spec's "extract a MIME type" algorithm
+ * (https://fetch.spec.whatwg.org/#concept-header-extract-mime-type).
+ * @param {string[] | null} headerValues The result of getting, decoding and
+ * splitting the "Content-Type" header.
+ * @returns {MimeType | null}
+ */
+function extractMimeType(headerValues) {
+ if (headerValues === null) return null;
+
+ let charset = null;
+ let essence_ = null;
+ let mimeType = null;
+ for (let i = 0; i < headerValues.length; ++i) {
+ const value = headerValues[i];
+ const temporaryMimeType = parseMimeType(value);
+ if (
+ temporaryMimeType === null ||
+ essence(temporaryMimeType) == "*/*"
+ ) {
+ continue;
+ }
+ mimeType = temporaryMimeType;
+ if (essence(mimeType) !== essence_) {
+ charset = null;
+ const newCharset = MapPrototypeGet(mimeType.parameters, "charset");
+ if (newCharset !== undefined) {
+ charset = newCharset;
+ }
+ essence_ = essence(mimeType);
+ } else {
if (
- temporaryMimeType === null ||
- essence(temporaryMimeType) == "*/*"
+ !MapPrototypeHas(mimeType.parameters, "charset") &&
+ charset !== null
) {
- continue;
- }
- mimeType = temporaryMimeType;
- if (essence(mimeType) !== essence_) {
- charset = null;
- const newCharset = MapPrototypeGet(mimeType.parameters, "charset");
- if (newCharset !== undefined) {
- charset = newCharset;
- }
- essence_ = essence(mimeType);
- } else {
- if (
- !MapPrototypeHas(mimeType.parameters, "charset") &&
- charset !== null
- ) {
- MapPrototypeSet(mimeType.parameters, "charset", charset);
- }
+ MapPrototypeSet(mimeType.parameters, "charset", charset);
}
}
- return mimeType;
}
+ return mimeType;
+}
- window.__bootstrap.mimesniff = {
- parseMimeType,
- essence,
- serializeMimeType,
- extractMimeType,
- };
-})(this);
+export { essence, extractMimeType, parseMimeType, serializeMimeType };
diff --git a/ext/web/02_event.js b/ext/web/02_event.js
index c99eb8f6e..de5210d33 100644
--- a/ext/web/02_event.js
+++ b/ext/web/02_event.js
@@ -4,1520 +4,1525 @@
// Many parts of the DOM are not implemented in Deno, but the logic for those
// parts still exists. This means you will observe a lot of strange structures
// and impossible logic branches based on what Deno currently supports.
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const { DOMException } = window.__bootstrap.domException;
- const consoleInternal = window.__bootstrap.console;
- const {
- ArrayPrototypeFilter,
- ArrayPrototypeIncludes,
- ArrayPrototypeIndexOf,
- ArrayPrototypeMap,
- ArrayPrototypePush,
- ArrayPrototypeSlice,
- ArrayPrototypeSplice,
- ArrayPrototypeUnshift,
- Boolean,
- DateNow,
- Error,
- FunctionPrototypeCall,
- Map,
- MapPrototypeGet,
- MapPrototypeSet,
- ObjectCreate,
- ObjectDefineProperty,
- ObjectGetOwnPropertyDescriptor,
- ObjectPrototypeIsPrototypeOf,
- ReflectDefineProperty,
- ReflectHas,
- SafeArrayIterator,
- StringPrototypeStartsWith,
- Symbol,
- SymbolFor,
- SymbolToStringTag,
- TypeError,
- } = window.__bootstrap.primordials;
-
- // accessors for non runtime visible data
-
- function getDispatched(event) {
- return Boolean(event[_dispatched]);
- }
-
- function getPath(event) {
- return event[_path] ?? [];
- }
-
- function getStopImmediatePropagation(event) {
- return Boolean(event[_stopImmediatePropagationFlag]);
- }
-
- function setCurrentTarget(
- event,
- value,
- ) {
- event[_attributes].currentTarget = value;
- }
-
- function setIsTrusted(event, value) {
- event[_isTrusted] = value;
- }
- function setDispatched(event, value) {
- event[_dispatched] = value;
- }
-
- function setEventPhase(event, value) {
- event[_attributes].eventPhase = value;
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+import { createFilteredInspectProxy } from "internal:ext/console/02_console.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeFilter,
+ ArrayPrototypeIncludes,
+ ArrayPrototypeIndexOf,
+ ArrayPrototypeMap,
+ ArrayPrototypePush,
+ ArrayPrototypeSlice,
+ ArrayPrototypeSplice,
+ ArrayPrototypeUnshift,
+ Boolean,
+ DateNow,
+ Error,
+ FunctionPrototypeCall,
+ Map,
+ MapPrototypeGet,
+ MapPrototypeSet,
+ ObjectCreate,
+ ObjectDefineProperty,
+ ObjectGetOwnPropertyDescriptor,
+ ObjectPrototypeIsPrototypeOf,
+ ReflectDefineProperty,
+ ReflectHas,
+ SafeArrayIterator,
+ StringPrototypeStartsWith,
+ Symbol,
+ SymbolFor,
+ SymbolToStringTag,
+ TypeError,
+} = primordials;
+
+// This should be set via setGlobalThis this is required so that if even
+// user deletes globalThis it is still usable
+let globalThis_;
+
+function saveGlobalThisReference(val) {
+ globalThis_ = val;
+}
+
+// accessors for non runtime visible data
+
+function getDispatched(event) {
+ return Boolean(event[_dispatched]);
+}
+
+function getPath(event) {
+ return event[_path] ?? [];
+}
+
+function getStopImmediatePropagation(event) {
+ return Boolean(event[_stopImmediatePropagationFlag]);
+}
+
+function setCurrentTarget(
+ event,
+ value,
+) {
+ event[_attributes].currentTarget = value;
+}
+
+function setIsTrusted(event, value) {
+ event[_isTrusted] = value;
+}
+
+function setDispatched(event, value) {
+ event[_dispatched] = value;
+}
+
+function setEventPhase(event, value) {
+ event[_attributes].eventPhase = value;
+}
+
+function setInPassiveListener(event, value) {
+ event[_inPassiveListener] = value;
+}
+
+function setPath(event, value) {
+ event[_path] = value;
+}
+
+function setRelatedTarget(
+ event,
+ value,
+) {
+ event[_attributes].relatedTarget = value;
+}
+
+function setTarget(event, value) {
+ event[_attributes].target = value;
+}
+
+function setStopImmediatePropagation(
+ event,
+ value,
+) {
+ event[_stopImmediatePropagationFlag] = value;
+}
+
+// Type guards that widen the event type
+
+function hasRelatedTarget(
+ event,
+) {
+ return ReflectHas(event, "relatedTarget");
+}
+
+const isTrusted = ObjectGetOwnPropertyDescriptor({
+ get isTrusted() {
+ return this[_isTrusted];
+ },
+}, "isTrusted").get;
+
+const eventInitConverter = webidl.createDictionaryConverter("EventInit", [{
+ key: "bubbles",
+ defaultValue: false,
+ converter: webidl.converters.boolean,
+}, {
+ key: "cancelable",
+ defaultValue: false,
+ converter: webidl.converters.boolean,
+}, {
+ key: "composed",
+ defaultValue: false,
+ converter: webidl.converters.boolean,
+}]);
+
+const _attributes = Symbol("[[attributes]]");
+const _canceledFlag = Symbol("[[canceledFlag]]");
+const _stopPropagationFlag = Symbol("[[stopPropagationFlag]]");
+const _stopImmediatePropagationFlag = Symbol(
+ "[[stopImmediatePropagationFlag]]",
+);
+const _inPassiveListener = Symbol("[[inPassiveListener]]");
+const _dispatched = Symbol("[[dispatched]]");
+const _isTrusted = Symbol("[[isTrusted]]");
+const _path = Symbol("[[path]]");
+// internal.
+const _skipInternalInit = Symbol("[[skipSlowInit]]");
+
+class Event {
+ constructor(type, eventInitDict = {}) {
+ // TODO(lucacasonato): remove when this interface is spec aligned
+ this[SymbolToStringTag] = "Event";
+ this[_canceledFlag] = false;
+ this[_stopPropagationFlag] = false;
+ this[_stopImmediatePropagationFlag] = false;
+ this[_inPassiveListener] = false;
+ this[_dispatched] = false;
+ this[_isTrusted] = false;
+ this[_path] = [];
+
+ if (!eventInitDict[_skipInternalInit]) {
+ webidl.requiredArguments(arguments.length, 1, {
+ prefix: "Failed to construct 'Event'",
+ });
+ type = webidl.converters.DOMString(type, {
+ prefix: "Failed to construct 'Event'",
+ context: "Argument 1",
+ });
+ const eventInit = eventInitConverter(eventInitDict, {
+ prefix: "Failed to construct 'Event'",
+ context: "Argument 2",
+ });
+ this[_attributes] = {
+ type,
+ ...eventInit,
+ currentTarget: null,
+ eventPhase: Event.NONE,
+ target: null,
+ timeStamp: DateNow(),
+ };
+ // [LegacyUnforgeable]
+ ReflectDefineProperty(this, "isTrusted", {
+ enumerable: true,
+ get: isTrusted,
+ });
+ } else {
+ this[_attributes] = {
+ type,
+ data: eventInitDict.data ?? null,
+ bubbles: eventInitDict.bubbles ?? false,
+ cancelable: eventInitDict.cancelable ?? false,
+ composed: eventInitDict.composed ?? false,
+ currentTarget: null,
+ eventPhase: Event.NONE,
+ target: null,
+ timeStamp: DateNow(),
+ };
+ // TODO(@littledivy): Not spec compliant but performance is hurt badly
+ // for users of `_skipInternalInit`.
+ this.isTrusted = false;
+ }
}
- function setInPassiveListener(event, value) {
- event[_inPassiveListener] = value;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(Event.prototype, this),
+ keys: EVENT_PROPS,
+ }));
}
- function setPath(event, value) {
- event[_path] = value;
+ get type() {
+ return this[_attributes].type;
}
- function setRelatedTarget(
- event,
- value,
- ) {
- event[_attributes].relatedTarget = value;
+ get target() {
+ return this[_attributes].target;
}
- function setTarget(event, value) {
- event[_attributes].target = value;
+ get srcElement() {
+ return null;
}
- function setStopImmediatePropagation(
- event,
- value,
- ) {
- event[_stopImmediatePropagationFlag] = value;
+ set srcElement(_) {
+ // this member is deprecated
}
- // Type guards that widen the event type
-
- function hasRelatedTarget(
- event,
- ) {
- return ReflectHas(event, "relatedTarget");
+ get currentTarget() {
+ return this[_attributes].currentTarget;
}
- const isTrusted = ObjectGetOwnPropertyDescriptor({
- get isTrusted() {
- return this[_isTrusted];
- },
- }, "isTrusted").get;
-
- const eventInitConverter = webidl.createDictionaryConverter("EventInit", [{
- key: "bubbles",
- defaultValue: false,
- converter: webidl.converters.boolean,
- }, {
- key: "cancelable",
- defaultValue: false,
- converter: webidl.converters.boolean,
- }, {
- key: "composed",
- defaultValue: false,
- converter: webidl.converters.boolean,
- }]);
-
- const _attributes = Symbol("[[attributes]]");
- const _canceledFlag = Symbol("[[canceledFlag]]");
- const _stopPropagationFlag = Symbol("[[stopPropagationFlag]]");
- const _stopImmediatePropagationFlag = Symbol(
- "[[stopImmediatePropagationFlag]]",
- );
- const _inPassiveListener = Symbol("[[inPassiveListener]]");
- const _dispatched = Symbol("[[dispatched]]");
- const _isTrusted = Symbol("[[isTrusted]]");
- const _path = Symbol("[[path]]");
- // internal.
- const _skipInternalInit = Symbol("[[skipSlowInit]]");
-
- class Event {
- constructor(type, eventInitDict = {}) {
- // TODO(lucacasonato): remove when this interface is spec aligned
- this[SymbolToStringTag] = "Event";
- this[_canceledFlag] = false;
- this[_stopPropagationFlag] = false;
- this[_stopImmediatePropagationFlag] = false;
- this[_inPassiveListener] = false;
- this[_dispatched] = false;
- this[_isTrusted] = false;
- this[_path] = [];
-
- if (!eventInitDict[_skipInternalInit]) {
- webidl.requiredArguments(arguments.length, 1, {
- prefix: "Failed to construct 'Event'",
- });
- type = webidl.converters.DOMString(type, {
- prefix: "Failed to construct 'Event'",
- context: "Argument 1",
- });
- const eventInit = eventInitConverter(eventInitDict, {
- prefix: "Failed to construct 'Event'",
- context: "Argument 2",
- });
- this[_attributes] = {
- type,
- ...eventInit,
- currentTarget: null,
- eventPhase: Event.NONE,
- target: null,
- timeStamp: DateNow(),
- };
- // [LegacyUnforgeable]
- ReflectDefineProperty(this, "isTrusted", {
- enumerable: true,
- get: isTrusted,
- });
- } else {
- this[_attributes] = {
- type,
- data: eventInitDict.data ?? null,
- bubbles: eventInitDict.bubbles ?? false,
- cancelable: eventInitDict.cancelable ?? false,
- composed: eventInitDict.composed ?? false,
- currentTarget: null,
- eventPhase: Event.NONE,
- target: null,
- timeStamp: DateNow(),
- };
- // TODO(@littledivy): Not spec compliant but performance is hurt badly
- // for users of `_skipInternalInit`.
- this.isTrusted = false;
- }
+ composedPath() {
+ const path = this[_path];
+ if (path.length === 0) {
+ return [];
}
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(Event.prototype, this),
- keys: EVENT_PROPS,
- }));
+ if (!this.currentTarget) {
+ throw new Error("assertion error");
}
+ const composedPath = [
+ {
+ item: this.currentTarget,
+ itemInShadowTree: false,
+ relatedTarget: null,
+ rootOfClosedTree: false,
+ slotInClosedTree: false,
+ target: null,
+ touchTargetList: [],
+ },
+ ];
- get type() {
- return this[_attributes].type;
- }
+ let currentTargetIndex = 0;
+ let currentTargetHiddenSubtreeLevel = 0;
- get target() {
- return this[_attributes].target;
- }
+ for (let index = path.length - 1; index >= 0; index--) {
+ const { item, rootOfClosedTree, slotInClosedTree } = path[index];
- get srcElement() {
- return null;
- }
+ if (rootOfClosedTree) {
+ currentTargetHiddenSubtreeLevel++;
+ }
- set srcElement(_) {
- // this member is deprecated
- }
+ if (item === this.currentTarget) {
+ currentTargetIndex = index;
+ break;
+ }
- get currentTarget() {
- return this[_attributes].currentTarget;
+ if (slotInClosedTree) {
+ currentTargetHiddenSubtreeLevel--;
+ }
}
- composedPath() {
- const path = this[_path];
- if (path.length === 0) {
- return [];
- }
+ let currentHiddenLevel = currentTargetHiddenSubtreeLevel;
+ let maxHiddenLevel = currentTargetHiddenSubtreeLevel;
+
+ for (let i = currentTargetIndex - 1; i >= 0; i--) {
+ const { item, rootOfClosedTree, slotInClosedTree } = path[i];
- if (!this.currentTarget) {
- throw new Error("assertion error");
+ if (rootOfClosedTree) {
+ currentHiddenLevel++;
}
- const composedPath = [
- {
- item: this.currentTarget,
+
+ if (currentHiddenLevel <= maxHiddenLevel) {
+ ArrayPrototypeUnshift(composedPath, {
+ item,
itemInShadowTree: false,
relatedTarget: null,
rootOfClosedTree: false,
slotInClosedTree: false,
target: null,
touchTargetList: [],
- },
- ];
-
- let currentTargetIndex = 0;
- let currentTargetHiddenSubtreeLevel = 0;
-
- for (let index = path.length - 1; index >= 0; index--) {
- const { item, rootOfClosedTree, slotInClosedTree } = path[index];
-
- if (rootOfClosedTree) {
- currentTargetHiddenSubtreeLevel++;
- }
-
- if (item === this.currentTarget) {
- currentTargetIndex = index;
- break;
- }
-
- if (slotInClosedTree) {
- currentTargetHiddenSubtreeLevel--;
- }
+ });
}
- let currentHiddenLevel = currentTargetHiddenSubtreeLevel;
- let maxHiddenLevel = currentTargetHiddenSubtreeLevel;
-
- for (let i = currentTargetIndex - 1; i >= 0; i--) {
- const { item, rootOfClosedTree, slotInClosedTree } = path[i];
-
- if (rootOfClosedTree) {
- currentHiddenLevel++;
- }
-
- if (currentHiddenLevel <= maxHiddenLevel) {
- ArrayPrototypeUnshift(composedPath, {
- item,
- itemInShadowTree: false,
- relatedTarget: null,
- rootOfClosedTree: false,
- slotInClosedTree: false,
- target: null,
- touchTargetList: [],
- });
- }
-
- if (slotInClosedTree) {
- currentHiddenLevel--;
+ if (slotInClosedTree) {
+ currentHiddenLevel--;
- if (currentHiddenLevel < maxHiddenLevel) {
- maxHiddenLevel = currentHiddenLevel;
- }
+ if (currentHiddenLevel < maxHiddenLevel) {
+ maxHiddenLevel = currentHiddenLevel;
}
}
+ }
- currentHiddenLevel = currentTargetHiddenSubtreeLevel;
- maxHiddenLevel = currentTargetHiddenSubtreeLevel;
+ currentHiddenLevel = currentTargetHiddenSubtreeLevel;
+ maxHiddenLevel = currentTargetHiddenSubtreeLevel;
- for (let index = currentTargetIndex + 1; index < path.length; index++) {
- const { item, rootOfClosedTree, slotInClosedTree } = path[index];
+ for (let index = currentTargetIndex + 1; index < path.length; index++) {
+ const { item, rootOfClosedTree, slotInClosedTree } = path[index];
- if (slotInClosedTree) {
- currentHiddenLevel++;
- }
+ if (slotInClosedTree) {
+ currentHiddenLevel++;
+ }
- if (currentHiddenLevel <= maxHiddenLevel) {
- ArrayPrototypePush(composedPath, {
- item,
- itemInShadowTree: false,
- relatedTarget: null,
- rootOfClosedTree: false,
- slotInClosedTree: false,
- target: null,
- touchTargetList: [],
- });
- }
+ if (currentHiddenLevel <= maxHiddenLevel) {
+ ArrayPrototypePush(composedPath, {
+ item,
+ itemInShadowTree: false,
+ relatedTarget: null,
+ rootOfClosedTree: false,
+ slotInClosedTree: false,
+ target: null,
+ touchTargetList: [],
+ });
+ }
- if (rootOfClosedTree) {
- currentHiddenLevel--;
+ if (rootOfClosedTree) {
+ currentHiddenLevel--;
- if (currentHiddenLevel < maxHiddenLevel) {
- maxHiddenLevel = currentHiddenLevel;
- }
+ if (currentHiddenLevel < maxHiddenLevel) {
+ maxHiddenLevel = currentHiddenLevel;
}
}
- return ArrayPrototypeMap(composedPath, (p) => p.item);
- }
-
- get NONE() {
- return Event.NONE;
- }
-
- get CAPTURING_PHASE() {
- return Event.CAPTURING_PHASE;
- }
-
- get AT_TARGET() {
- return Event.AT_TARGET;
- }
-
- get BUBBLING_PHASE() {
- return Event.BUBBLING_PHASE;
- }
-
- static get NONE() {
- return 0;
}
+ return ArrayPrototypeMap(composedPath, (p) => p.item);
+ }
- static get CAPTURING_PHASE() {
- return 1;
- }
+ get NONE() {
+ return Event.NONE;
+ }
- static get AT_TARGET() {
- return 2;
- }
+ get CAPTURING_PHASE() {
+ return Event.CAPTURING_PHASE;
+ }
- static get BUBBLING_PHASE() {
- return 3;
- }
+ get AT_TARGET() {
+ return Event.AT_TARGET;
+ }
- get eventPhase() {
- return this[_attributes].eventPhase;
- }
+ get BUBBLING_PHASE() {
+ return Event.BUBBLING_PHASE;
+ }
- stopPropagation() {
- this[_stopPropagationFlag] = true;
- }
+ static get NONE() {
+ return 0;
+ }
- get cancelBubble() {
- return this[_stopPropagationFlag];
- }
+ static get CAPTURING_PHASE() {
+ return 1;
+ }
- set cancelBubble(value) {
- this[_stopPropagationFlag] = webidl.converters.boolean(value);
- }
+ static get AT_TARGET() {
+ return 2;
+ }
- stopImmediatePropagation() {
- this[_stopPropagationFlag] = true;
- this[_stopImmediatePropagationFlag] = true;
- }
+ static get BUBBLING_PHASE() {
+ return 3;
+ }
- get bubbles() {
- return this[_attributes].bubbles;
- }
+ get eventPhase() {
+ return this[_attributes].eventPhase;
+ }
- get cancelable() {
- return this[_attributes].cancelable;
- }
+ stopPropagation() {
+ this[_stopPropagationFlag] = true;
+ }
- get returnValue() {
- return !this[_canceledFlag];
- }
+ get cancelBubble() {
+ return this[_stopPropagationFlag];
+ }
- set returnValue(value) {
- if (!webidl.converters.boolean(value)) {
- this[_canceledFlag] = true;
- }
- }
+ set cancelBubble(value) {
+ this[_stopPropagationFlag] = webidl.converters.boolean(value);
+ }
- preventDefault() {
- if (this[_attributes].cancelable && !this[_inPassiveListener]) {
- this[_canceledFlag] = true;
- }
- }
+ stopImmediatePropagation() {
+ this[_stopPropagationFlag] = true;
+ this[_stopImmediatePropagationFlag] = true;
+ }
- get defaultPrevented() {
- return this[_canceledFlag];
- }
+ get bubbles() {
+ return this[_attributes].bubbles;
+ }
- get composed() {
- return this[_attributes].composed;
- }
+ get cancelable() {
+ return this[_attributes].cancelable;
+ }
- get initialized() {
- return true;
- }
+ get returnValue() {
+ return !this[_canceledFlag];
+ }
- get timeStamp() {
- return this[_attributes].timeStamp;
+ set returnValue(value) {
+ if (!webidl.converters.boolean(value)) {
+ this[_canceledFlag] = true;
}
}
- function defineEnumerableProps(
- Ctor,
- props,
- ) {
- for (let i = 0; i < props.length; ++i) {
- const prop = props[i];
- ReflectDefineProperty(Ctor.prototype, prop, { enumerable: true });
+ preventDefault() {
+ if (this[_attributes].cancelable && !this[_inPassiveListener]) {
+ this[_canceledFlag] = true;
}
}
- const EVENT_PROPS = [
- "bubbles",
- "cancelable",
- "composed",
- "currentTarget",
- "defaultPrevented",
- "eventPhase",
- "srcElement",
- "target",
- "returnValue",
- "timeStamp",
- "type",
- ];
-
- defineEnumerableProps(Event, EVENT_PROPS);
-
- // This is currently the only node type we are using, so instead of implementing
- // the whole of the Node interface at the moment, this just gives us the one
- // value to power the standards based logic
- const DOCUMENT_FRAGMENT_NODE = 11;
-
- // DOM Logic Helper functions and type guards
-
- /** Get the parent node, for event targets that have a parent.
- *
- * Ref: https://dom.spec.whatwg.org/#get-the-parent */
- function getParent(eventTarget) {
- return isNode(eventTarget) ? eventTarget.parentNode : null;
+ get defaultPrevented() {
+ return this[_canceledFlag];
}
- function getRoot(eventTarget) {
- return isNode(eventTarget)
- ? eventTarget.getRootNode({ composed: true })
- : null;
+ get composed() {
+ return this[_attributes].composed;
}
- function isNode(
- eventTarget,
- ) {
- return Boolean(eventTarget && ReflectHas(eventTarget, "nodeType"));
+ get initialized() {
+ return true;
}
- // https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor
- function isShadowInclusiveAncestor(
- ancestor,
- node,
- ) {
- while (isNode(node)) {
- if (node === ancestor) {
- return true;
- }
-
- if (isShadowRoot(node)) {
- node = node && getHost(node);
- } else {
- node = getParent(node);
- }
- }
-
- return false;
+ get timeStamp() {
+ return this[_attributes].timeStamp;
}
-
- function isShadowRoot(nodeImpl) {
- return Boolean(
- nodeImpl &&
- isNode(nodeImpl) &&
- nodeImpl.nodeType === DOCUMENT_FRAGMENT_NODE &&
- getHost(nodeImpl) != null,
- );
+}
+
+function defineEnumerableProps(
+ Ctor,
+ props,
+) {
+ for (let i = 0; i < props.length; ++i) {
+ const prop = props[i];
+ ReflectDefineProperty(Ctor.prototype, prop, { enumerable: true });
}
+}
+
+const EVENT_PROPS = [
+ "bubbles",
+ "cancelable",
+ "composed",
+ "currentTarget",
+ "defaultPrevented",
+ "eventPhase",
+ "srcElement",
+ "target",
+ "returnValue",
+ "timeStamp",
+ "type",
+];
+
+defineEnumerableProps(Event, EVENT_PROPS);
+
+// This is currently the only node type we are using, so instead of implementing
+// the whole of the Node interface at the moment, this just gives us the one
+// value to power the standards based logic
+const DOCUMENT_FRAGMENT_NODE = 11;
+
+// DOM Logic Helper functions and type guards
+
+/** Get the parent node, for event targets that have a parent.
+ *
+ * Ref: https://dom.spec.whatwg.org/#get-the-parent */
+function getParent(eventTarget) {
+ return isNode(eventTarget) ? eventTarget.parentNode : null;
+}
+
+function getRoot(eventTarget) {
+ return isNode(eventTarget)
+ ? eventTarget.getRootNode({ composed: true })
+ : null;
+}
+
+function isNode(
+ eventTarget,
+) {
+ return Boolean(eventTarget && ReflectHas(eventTarget, "nodeType"));
+}
+
+// https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor
+function isShadowInclusiveAncestor(
+ ancestor,
+ node,
+) {
+ while (isNode(node)) {
+ if (node === ancestor) {
+ return true;
+ }
- function isSlotable(
- nodeImpl,
- ) {
- return Boolean(isNode(nodeImpl) && ReflectHas(nodeImpl, "assignedSlot"));
+ if (isShadowRoot(node)) {
+ node = node && getHost(node);
+ } else {
+ node = getParent(node);
+ }
}
- // DOM Logic functions
+ return false;
+}
- /** Append a path item to an event's path.
- *
- * Ref: https://dom.spec.whatwg.org/#concept-event-path-append
- */
- function appendToEventPath(
- eventImpl,
- target,
- targetOverride,
+function isShadowRoot(nodeImpl) {
+ return Boolean(
+ nodeImpl &&
+ isNode(nodeImpl) &&
+ nodeImpl.nodeType === DOCUMENT_FRAGMENT_NODE &&
+ getHost(nodeImpl) != null,
+ );
+}
+
+function isSlotable(
+ nodeImpl,
+) {
+ return Boolean(isNode(nodeImpl) && ReflectHas(nodeImpl, "assignedSlot"));
+}
+
+// DOM Logic functions
+
+/** Append a path item to an event's path.
+ *
+ * Ref: https://dom.spec.whatwg.org/#concept-event-path-append
+ */
+function appendToEventPath(
+ eventImpl,
+ target,
+ targetOverride,
+ relatedTarget,
+ touchTargets,
+ slotInClosedTree,
+) {
+ const itemInShadowTree = isNode(target) && isShadowRoot(getRoot(target));
+ const rootOfClosedTree = isShadowRoot(target) &&
+ getMode(target) === "closed";
+
+ ArrayPrototypePush(getPath(eventImpl), {
+ item: target,
+ itemInShadowTree,
+ target: targetOverride,
relatedTarget,
- touchTargets,
+ touchTargetList: touchTargets,
+ rootOfClosedTree,
slotInClosedTree,
- ) {
- const itemInShadowTree = isNode(target) && isShadowRoot(getRoot(target));
- const rootOfClosedTree = isShadowRoot(target) &&
- getMode(target) === "closed";
-
- ArrayPrototypePush(getPath(eventImpl), {
- item: target,
- itemInShadowTree,
- target: targetOverride,
+ });
+}
+
+function dispatch(
+ targetImpl,
+ eventImpl,
+ targetOverride,
+) {
+ let clearTargets = false;
+ let activationTarget = null;
+
+ setDispatched(eventImpl, true);
+
+ targetOverride = targetOverride ?? targetImpl;
+ const eventRelatedTarget = hasRelatedTarget(eventImpl)
+ ? eventImpl.relatedTarget
+ : null;
+ let relatedTarget = retarget(eventRelatedTarget, targetImpl);
+
+ if (targetImpl !== relatedTarget || targetImpl === eventRelatedTarget) {
+ const touchTargets = [];
+
+ appendToEventPath(
+ eventImpl,
+ targetImpl,
+ targetOverride,
relatedTarget,
- touchTargetList: touchTargets,
- rootOfClosedTree,
- slotInClosedTree,
- });
- }
+ touchTargets,
+ false,
+ );
- function dispatch(
- targetImpl,
- eventImpl,
- targetOverride,
- ) {
- let clearTargets = false;
- let activationTarget = null;
+ const isActivationEvent = eventImpl.type === "click";
- setDispatched(eventImpl, true);
+ if (isActivationEvent && getHasActivationBehavior(targetImpl)) {
+ activationTarget = targetImpl;
+ }
- targetOverride = targetOverride ?? targetImpl;
- const eventRelatedTarget = hasRelatedTarget(eventImpl)
- ? eventImpl.relatedTarget
+ let slotInClosedTree = false;
+ let slotable = isSlotable(targetImpl) && getAssignedSlot(targetImpl)
+ ? targetImpl
: null;
- let relatedTarget = retarget(eventRelatedTarget, targetImpl);
-
- if (targetImpl !== relatedTarget || targetImpl === eventRelatedTarget) {
- const touchTargets = [];
-
- appendToEventPath(
- eventImpl,
- targetImpl,
- targetOverride,
- relatedTarget,
- touchTargets,
- false,
- );
-
- const isActivationEvent = eventImpl.type === "click";
+ let parent = getParent(targetImpl);
- if (isActivationEvent && getHasActivationBehavior(targetImpl)) {
- activationTarget = targetImpl;
- }
-
- let slotInClosedTree = false;
- let slotable = isSlotable(targetImpl) && getAssignedSlot(targetImpl)
- ? targetImpl
- : null;
- let parent = getParent(targetImpl);
-
- // Populate event path
- // https://dom.spec.whatwg.org/#event-path
- while (parent !== null) {
- if (slotable !== null) {
- slotable = null;
-
- const parentRoot = getRoot(parent);
- if (
- isShadowRoot(parentRoot) &&
- parentRoot &&
- getMode(parentRoot) === "closed"
- ) {
- slotInClosedTree = true;
- }
- }
-
- relatedTarget = retarget(eventRelatedTarget, parent);
+ // Populate event path
+ // https://dom.spec.whatwg.org/#event-path
+ while (parent !== null) {
+ if (slotable !== null) {
+ slotable = null;
+ const parentRoot = getRoot(parent);
if (
- isNode(parent) &&
- isShadowInclusiveAncestor(getRoot(targetImpl), parent)
+ isShadowRoot(parentRoot) &&
+ parentRoot &&
+ getMode(parentRoot) === "closed"
) {
- appendToEventPath(
- eventImpl,
- parent,
- null,
- relatedTarget,
- touchTargets,
- slotInClosedTree,
- );
- } else if (parent === relatedTarget) {
- parent = null;
- } else {
- targetImpl = parent;
-
- if (
- isActivationEvent &&
- activationTarget === null &&
- getHasActivationBehavior(targetImpl)
- ) {
- activationTarget = targetImpl;
- }
-
- appendToEventPath(
- eventImpl,
- parent,
- targetImpl,
- relatedTarget,
- touchTargets,
- slotInClosedTree,
- );
- }
-
- if (parent !== null) {
- parent = getParent(parent);
- }
-
- slotInClosedTree = false;
- }
-
- let clearTargetsTupleIndex = -1;
- const path = getPath(eventImpl);
- for (
- let i = path.length - 1;
- i >= 0 && clearTargetsTupleIndex === -1;
- i--
- ) {
- if (path[i].target !== null) {
- clearTargetsTupleIndex = i;
- }
- }
- const clearTargetsTuple = path[clearTargetsTupleIndex];
-
- clearTargets = (isNode(clearTargetsTuple.target) &&
- isShadowRoot(getRoot(clearTargetsTuple.target))) ||
- (isNode(clearTargetsTuple.relatedTarget) &&
- isShadowRoot(getRoot(clearTargetsTuple.relatedTarget)));
-
- setEventPhase(eventImpl, Event.CAPTURING_PHASE);
-
- for (let i = path.length - 1; i >= 0; --i) {
- const tuple = path[i];
-
- if (tuple.target === null) {
- invokeEventListeners(tuple, eventImpl);
+ slotInClosedTree = true;
}
}
- for (let i = 0; i < path.length; i++) {
- const tuple = path[i];
+ relatedTarget = retarget(eventRelatedTarget, parent);
- if (tuple.target !== null) {
- setEventPhase(eventImpl, Event.AT_TARGET);
- } else {
- setEventPhase(eventImpl, Event.BUBBLING_PHASE);
- }
+ if (
+ isNode(parent) &&
+ isShadowInclusiveAncestor(getRoot(targetImpl), parent)
+ ) {
+ appendToEventPath(
+ eventImpl,
+ parent,
+ null,
+ relatedTarget,
+ touchTargets,
+ slotInClosedTree,
+ );
+ } else if (parent === relatedTarget) {
+ parent = null;
+ } else {
+ targetImpl = parent;
if (
- (eventImpl.eventPhase === Event.BUBBLING_PHASE &&
- eventImpl.bubbles) ||
- eventImpl.eventPhase === Event.AT_TARGET
+ isActivationEvent &&
+ activationTarget === null &&
+ getHasActivationBehavior(targetImpl)
) {
- invokeEventListeners(tuple, eventImpl);
+ activationTarget = targetImpl;
}
+
+ appendToEventPath(
+ eventImpl,
+ parent,
+ targetImpl,
+ relatedTarget,
+ touchTargets,
+ slotInClosedTree,
+ );
}
- }
- setEventPhase(eventImpl, Event.NONE);
- setCurrentTarget(eventImpl, null);
- setPath(eventImpl, []);
- setDispatched(eventImpl, false);
- eventImpl.cancelBubble = false;
- setStopImmediatePropagation(eventImpl, false);
+ if (parent !== null) {
+ parent = getParent(parent);
+ }
- if (clearTargets) {
- setTarget(eventImpl, null);
- setRelatedTarget(eventImpl, null);
+ slotInClosedTree = false;
}
- // TODO(bartlomieju): invoke activation targets if HTML nodes will be implemented
- // if (activationTarget !== null) {
- // if (!eventImpl.defaultPrevented) {
- // activationTarget._activationBehavior();
- // }
- // }
+ let clearTargetsTupleIndex = -1;
+ const path = getPath(eventImpl);
+ for (
+ let i = path.length - 1;
+ i >= 0 && clearTargetsTupleIndex === -1;
+ i--
+ ) {
+ if (path[i].target !== null) {
+ clearTargetsTupleIndex = i;
+ }
+ }
+ const clearTargetsTuple = path[clearTargetsTupleIndex];
- return !eventImpl.defaultPrevented;
- }
+ clearTargets = (isNode(clearTargetsTuple.target) &&
+ isShadowRoot(getRoot(clearTargetsTuple.target))) ||
+ (isNode(clearTargetsTuple.relatedTarget) &&
+ isShadowRoot(getRoot(clearTargetsTuple.relatedTarget)));
- /** Inner invoking of the event listeners where the resolved listeners are
- * called.
- *
- * Ref: https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke */
- function innerInvokeEventListeners(
- eventImpl,
- targetListeners,
- ) {
- let found = false;
+ setEventPhase(eventImpl, Event.CAPTURING_PHASE);
- const { type } = eventImpl;
+ for (let i = path.length - 1; i >= 0; --i) {
+ const tuple = path[i];
- if (!targetListeners || !targetListeners[type]) {
- return found;
+ if (tuple.target === null) {
+ invokeEventListeners(tuple, eventImpl);
+ }
}
- // Copy event listeners before iterating since the list can be modified during the iteration.
- const handlers = ArrayPrototypeSlice(targetListeners[type]);
+ for (let i = 0; i < path.length; i++) {
+ const tuple = path[i];
- for (let i = 0; i < handlers.length; i++) {
- const listener = handlers[i];
-
- let capture, once, passive;
- if (typeof listener.options === "boolean") {
- capture = listener.options;
- once = false;
- passive = false;
+ if (tuple.target !== null) {
+ setEventPhase(eventImpl, Event.AT_TARGET);
} else {
- capture = listener.options.capture;
- once = listener.options.once;
- passive = listener.options.passive;
- }
-
- // Check if the event listener has been removed since the listeners has been cloned.
- if (!ArrayPrototypeIncludes(targetListeners[type], listener)) {
- continue;
+ setEventPhase(eventImpl, Event.BUBBLING_PHASE);
}
- found = true;
-
if (
- (eventImpl.eventPhase === Event.CAPTURING_PHASE && !capture) ||
- (eventImpl.eventPhase === Event.BUBBLING_PHASE && capture)
+ (eventImpl.eventPhase === Event.BUBBLING_PHASE &&
+ eventImpl.bubbles) ||
+ eventImpl.eventPhase === Event.AT_TARGET
) {
- continue;
- }
-
- if (once) {
- ArrayPrototypeSplice(
- targetListeners[type],
- ArrayPrototypeIndexOf(targetListeners[type], listener),
- 1,
- );
- }
-
- if (passive) {
- setInPassiveListener(eventImpl, true);
- }
-
- if (typeof listener.callback === "object") {
- if (typeof listener.callback.handleEvent === "function") {
- listener.callback.handleEvent(eventImpl);
- }
- } else {
- FunctionPrototypeCall(
- listener.callback,
- eventImpl.currentTarget,
- eventImpl,
- );
+ invokeEventListeners(tuple, eventImpl);
}
+ }
+ }
- setInPassiveListener(eventImpl, false);
+ setEventPhase(eventImpl, Event.NONE);
+ setCurrentTarget(eventImpl, null);
+ setPath(eventImpl, []);
+ setDispatched(eventImpl, false);
+ eventImpl.cancelBubble = false;
+ setStopImmediatePropagation(eventImpl, false);
- if (getStopImmediatePropagation(eventImpl)) {
- return found;
- }
- }
+ if (clearTargets) {
+ setTarget(eventImpl, null);
+ setRelatedTarget(eventImpl, null);
+ }
+ // TODO(bartlomieju): invoke activation targets if HTML nodes will be implemented
+ // if (activationTarget !== null) {
+ // if (!eventImpl.defaultPrevented) {
+ // activationTarget._activationBehavior();
+ // }
+ // }
+
+ return !eventImpl.defaultPrevented;
+}
+
+/** Inner invoking of the event listeners where the resolved listeners are
+ * called.
+ *
+ * Ref: https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke */
+function innerInvokeEventListeners(
+ eventImpl,
+ targetListeners,
+) {
+ let found = false;
+
+ const { type } = eventImpl;
+
+ if (!targetListeners || !targetListeners[type]) {
return found;
}
- /** Invokes the listeners on a given event path with the supplied event.
- *
- * Ref: https://dom.spec.whatwg.org/#concept-event-listener-invoke */
- function invokeEventListeners(tuple, eventImpl) {
- const path = getPath(eventImpl);
- const tupleIndex = ArrayPrototypeIndexOf(path, tuple);
- for (let i = tupleIndex; i >= 0; i--) {
- const t = path[i];
- if (t.target) {
- setTarget(eventImpl, t.target);
- break;
- }
- }
+ // Copy event listeners before iterating since the list can be modified during the iteration.
+ const handlers = ArrayPrototypeSlice(targetListeners[type]);
- setRelatedTarget(eventImpl, tuple.relatedTarget);
+ for (let i = 0; i < handlers.length; i++) {
+ const listener = handlers[i];
- if (eventImpl.cancelBubble) {
- return;
+ let capture, once, passive;
+ if (typeof listener.options === "boolean") {
+ capture = listener.options;
+ once = false;
+ passive = false;
+ } else {
+ capture = listener.options.capture;
+ once = listener.options.once;
+ passive = listener.options.passive;
}
- setCurrentTarget(eventImpl, tuple.item);
-
- try {
- innerInvokeEventListeners(eventImpl, getListeners(tuple.item));
- } catch (error) {
- reportException(error);
+ // Check if the event listener has been removed since the listeners has been cloned.
+ if (!ArrayPrototypeIncludes(targetListeners[type], listener)) {
+ continue;
}
- }
- function normalizeEventHandlerOptions(
- options,
- ) {
- if (typeof options === "boolean" || typeof options === "undefined") {
- return {
- capture: Boolean(options),
- };
- } else {
- return options;
- }
- }
+ found = true;
- /** Retarget the target following the spec logic.
- *
- * Ref: https://dom.spec.whatwg.org/#retarget */
- function retarget(a, b) {
- while (true) {
- if (!isNode(a)) {
- return a;
- }
+ if (
+ (eventImpl.eventPhase === Event.CAPTURING_PHASE && !capture) ||
+ (eventImpl.eventPhase === Event.BUBBLING_PHASE && capture)
+ ) {
+ continue;
+ }
- const aRoot = a.getRootNode();
+ if (once) {
+ ArrayPrototypeSplice(
+ targetListeners[type],
+ ArrayPrototypeIndexOf(targetListeners[type], listener),
+ 1,
+ );
+ }
- if (aRoot) {
- if (
- !isShadowRoot(aRoot) ||
- (isNode(b) && isShadowInclusiveAncestor(aRoot, b))
- ) {
- return a;
- }
+ if (passive) {
+ setInPassiveListener(eventImpl, true);
+ }
- a = getHost(aRoot);
+ if (typeof listener.callback === "object") {
+ if (typeof listener.callback.handleEvent === "function") {
+ listener.callback.handleEvent(eventImpl);
}
+ } else {
+ FunctionPrototypeCall(
+ listener.callback,
+ eventImpl.currentTarget,
+ eventImpl,
+ );
}
- }
- // Accessors for non-public data
+ setInPassiveListener(eventImpl, false);
- const eventTargetData = Symbol();
-
- function setEventTargetData(target) {
- target[eventTargetData] = getDefaultTargetData();
- }
-
- function getAssignedSlot(target) {
- return Boolean(target?.[eventTargetData]?.assignedSlot);
+ if (getStopImmediatePropagation(eventImpl)) {
+ return found;
+ }
}
- function getHasActivationBehavior(target) {
- return Boolean(target?.[eventTargetData]?.hasActivationBehavior);
+ return found;
+}
+
+/** Invokes the listeners on a given event path with the supplied event.
+ *
+ * Ref: https://dom.spec.whatwg.org/#concept-event-listener-invoke */
+function invokeEventListeners(tuple, eventImpl) {
+ const path = getPath(eventImpl);
+ const tupleIndex = ArrayPrototypeIndexOf(path, tuple);
+ for (let i = tupleIndex; i >= 0; i--) {
+ const t = path[i];
+ if (t.target) {
+ setTarget(eventImpl, t.target);
+ break;
+ }
}
- function getHost(target) {
- return target?.[eventTargetData]?.host ?? null;
- }
+ setRelatedTarget(eventImpl, tuple.relatedTarget);
- function getListeners(target) {
- return target?.[eventTargetData]?.listeners ?? {};
+ if (eventImpl.cancelBubble) {
+ return;
}
- function getMode(target) {
- return target?.[eventTargetData]?.mode ?? null;
- }
+ setCurrentTarget(eventImpl, tuple.item);
- function listenerCount(target, type) {
- return getListeners(target)?.[type]?.length ?? 0;
+ try {
+ innerInvokeEventListeners(eventImpl, getListeners(tuple.item));
+ } catch (error) {
+ reportException(error);
}
+}
- function getDefaultTargetData() {
+function normalizeEventHandlerOptions(
+ options,
+) {
+ if (typeof options === "boolean" || typeof options === "undefined") {
return {
- assignedSlot: false,
- hasActivationBehavior: false,
- host: null,
- listeners: ObjectCreate(null),
- mode: "",
+ capture: Boolean(options),
};
+ } else {
+ return options;
}
+}
- // This is lazy loaded because there is a circular dependency with AbortSignal.
- let addEventListenerOptionsConverter;
-
- function lazyAddEventListenerOptionsConverter() {
- addEventListenerOptionsConverter ??= webidl.createDictionaryConverter(
- "AddEventListenerOptions",
- [
- {
- key: "capture",
- defaultValue: false,
- converter: webidl.converters.boolean,
- },
- {
- key: "passive",
- defaultValue: false,
- converter: webidl.converters.boolean,
- },
- {
- key: "once",
- defaultValue: false,
- converter: webidl.converters.boolean,
- },
- {
- key: "signal",
- converter: webidl.converters.AbortSignal,
- },
- ],
- );
- }
-
- webidl.converters.AddEventListenerOptions = (V, opts) => {
- if (webidl.type(V) !== "Object" || V === null) {
- V = { capture: Boolean(V) };
- }
-
- lazyAddEventListenerOptionsConverter();
- return addEventListenerOptionsConverter(V, opts);
- };
-
- class EventTarget {
- constructor() {
- this[eventTargetData] = getDefaultTargetData();
- this[webidl.brand] = webidl.brand;
+/** Retarget the target following the spec logic.
+ *
+ * Ref: https://dom.spec.whatwg.org/#retarget */
+function retarget(a, b) {
+ while (true) {
+ if (!isNode(a)) {
+ return a;
}
- addEventListener(
- type,
- callback,
- options,
- ) {
- const self = this ?? globalThis;
- webidl.assertBranded(self, EventTargetPrototype);
- const prefix = "Failed to execute 'addEventListener' on 'EventTarget'";
+ const aRoot = a.getRootNode();
- webidl.requiredArguments(arguments.length, 2, {
- prefix,
- });
+ if (aRoot) {
+ if (
+ !isShadowRoot(aRoot) ||
+ (isNode(b) && isShadowInclusiveAncestor(aRoot, b))
+ ) {
+ return a;
+ }
- options = webidl.converters.AddEventListenerOptions(options, {
- prefix,
- context: "Argument 3",
- });
+ a = getHost(aRoot);
+ }
+ }
+}
- if (callback === null) {
- return;
- }
+// Accessors for non-public data
- const { listeners } = self[eventTargetData];
+const eventTargetData = Symbol();
- if (!(ReflectHas(listeners, type))) {
- listeners[type] = [];
- }
+function setEventTargetData(target) {
+ target[eventTargetData] = getDefaultTargetData();
+}
- const listenerList = listeners[type];
- for (let i = 0; i < listenerList.length; ++i) {
- const listener = listenerList[i];
- if (
- ((typeof listener.options === "boolean" &&
- listener.options === options.capture) ||
- (typeof listener.options === "object" &&
- listener.options.capture === options.capture)) &&
- listener.callback === callback
- ) {
- return;
- }
- }
- if (options?.signal) {
- const signal = options?.signal;
- if (signal.aborted) {
- // If signal is not null and its aborted flag is set, then return.
- return;
- } else {
- // If listener’s signal is not null, then add the following abort
- // abort steps to it: Remove an event listener.
- signal.addEventListener("abort", () => {
- self.removeEventListener(type, callback, options);
- });
- }
- }
+function getAssignedSlot(target) {
+ return Boolean(target?.[eventTargetData]?.assignedSlot);
+}
- ArrayPrototypePush(listeners[type], { callback, options });
- }
+function getHasActivationBehavior(target) {
+ return Boolean(target?.[eventTargetData]?.hasActivationBehavior);
+}
- removeEventListener(
- type,
- callback,
- options,
- ) {
- const self = this ?? globalThis;
- webidl.assertBranded(self, EventTargetPrototype);
- webidl.requiredArguments(arguments.length, 2, {
- prefix: "Failed to execute 'removeEventListener' on 'EventTarget'",
- });
+function getHost(target) {
+ return target?.[eventTargetData]?.host ?? null;
+}
- const { listeners } = self[eventTargetData];
- if (callback !== null && ReflectHas(listeners, type)) {
- listeners[type] = ArrayPrototypeFilter(
- listeners[type],
- (listener) => listener.callback !== callback,
- );
- } else if (callback === null || !listeners[type]) {
- return;
- }
+function getListeners(target) {
+ return target?.[eventTargetData]?.listeners ?? {};
+}
- options = normalizeEventHandlerOptions(options);
+function getMode(target) {
+ return target?.[eventTargetData]?.mode ?? null;
+}
- for (let i = 0; i < listeners[type].length; ++i) {
- const listener = listeners[type][i];
- if (
- ((typeof listener.options === "boolean" &&
- listener.options === options.capture) ||
- (typeof listener.options === "object" &&
- listener.options.capture === options.capture)) &&
- listener.callback === callback
- ) {
- ArrayPrototypeSplice(listeners[type], i, 1);
- break;
- }
- }
- }
+function listenerCount(target, type) {
+ return getListeners(target)?.[type]?.length ?? 0;
+}
- dispatchEvent(event) {
- // If `this` is not present, then fallback to global scope. We don't use
- // `globalThis` directly here, because it could be deleted by user.
- // Instead use saved reference to global scope when the script was
- // executed.
- const self = this ?? window;
- webidl.assertBranded(self, EventTargetPrototype);
- webidl.requiredArguments(arguments.length, 1, {
- prefix: "Failed to execute 'dispatchEvent' on 'EventTarget'",
- });
+function getDefaultTargetData() {
+ return {
+ assignedSlot: false,
+ hasActivationBehavior: false,
+ host: null,
+ listeners: ObjectCreate(null),
+ mode: "",
+ };
+}
- const { listeners } = self[eventTargetData];
- if (!ReflectHas(listeners, event.type)) {
- setTarget(event, this);
- return true;
- }
+// This is lazy loaded because there is a circular dependency with AbortSignal.
+let addEventListenerOptionsConverter;
- if (getDispatched(event)) {
- throw new DOMException("Invalid event state.", "InvalidStateError");
- }
+function lazyAddEventListenerOptionsConverter() {
+ addEventListenerOptionsConverter ??= webidl.createDictionaryConverter(
+ "AddEventListenerOptions",
+ [
+ {
+ key: "capture",
+ defaultValue: false,
+ converter: webidl.converters.boolean,
+ },
+ {
+ key: "passive",
+ defaultValue: false,
+ converter: webidl.converters.boolean,
+ },
+ {
+ key: "once",
+ defaultValue: false,
+ converter: webidl.converters.boolean,
+ },
+ {
+ key: "signal",
+ converter: webidl.converters.AbortSignal,
+ },
+ ],
+ );
+}
- if (event.eventPhase !== Event.NONE) {
- throw new DOMException("Invalid event state.", "InvalidStateError");
- }
+webidl.converters.AddEventListenerOptions = (V, opts) => {
+ if (webidl.type(V) !== "Object" || V === null) {
+ V = { capture: Boolean(V) };
+ }
- return dispatch(self, event);
- }
+ lazyAddEventListenerOptionsConverter();
+ return addEventListenerOptionsConverter(V, opts);
+};
- getParent(_event) {
- return null;
- }
+class EventTarget {
+ constructor() {
+ this[eventTargetData] = getDefaultTargetData();
+ this[webidl.brand] = webidl.brand;
}
- webidl.configurePrototype(EventTarget);
- const EventTargetPrototype = EventTarget.prototype;
+ addEventListener(
+ type,
+ callback,
+ options,
+ ) {
+ const self = this ?? globalThis_;
+ webidl.assertBranded(self, EventTargetPrototype);
+ const prefix = "Failed to execute 'addEventListener' on 'EventTarget'";
- defineEnumerableProps(EventTarget, [
- "addEventListener",
- "removeEventListener",
- "dispatchEvent",
- ]);
+ webidl.requiredArguments(arguments.length, 2, {
+ prefix,
+ });
- class ErrorEvent extends Event {
- #message = "";
- #filename = "";
- #lineno = "";
- #colno = "";
- #error = "";
+ options = webidl.converters.AddEventListenerOptions(options, {
+ prefix,
+ context: "Argument 3",
+ });
- get message() {
- return this.#message;
- }
- get filename() {
- return this.#filename;
+ if (callback === null) {
+ return;
}
- get lineno() {
- return this.#lineno;
+
+ const { listeners } = self[eventTargetData];
+
+ if (!(ReflectHas(listeners, type))) {
+ listeners[type] = [];
}
- get colno() {
- return this.#colno;
+
+ const listenerList = listeners[type];
+ for (let i = 0; i < listenerList.length; ++i) {
+ const listener = listenerList[i];
+ if (
+ ((typeof listener.options === "boolean" &&
+ listener.options === options.capture) ||
+ (typeof listener.options === "object" &&
+ listener.options.capture === options.capture)) &&
+ listener.callback === callback
+ ) {
+ return;
+ }
}
- get error() {
- return this.#error;
+ if (options?.signal) {
+ const signal = options?.signal;
+ if (signal.aborted) {
+ // If signal is not null and its aborted flag is set, then return.
+ return;
+ } else {
+ // If listener’s signal is not null, then add the following abort
+ // abort steps to it: Remove an event listener.
+ signal.addEventListener("abort", () => {
+ self.removeEventListener(type, callback, options);
+ });
+ }
}
- constructor(
- type,
- {
- bubbles,
- cancelable,
- composed,
- message = "",
- filename = "",
- lineno = 0,
- colno = 0,
- error,
- } = {},
- ) {
- super(type, {
- bubbles: bubbles,
- cancelable: cancelable,
- composed: composed,
- });
+ ArrayPrototypePush(listeners[type], { callback, options });
+ }
- this.#message = message;
- this.#filename = filename;
- this.#lineno = lineno;
- this.#colno = colno;
- this.#error = error;
- }
+ removeEventListener(
+ type,
+ callback,
+ options,
+ ) {
+ const self = this ?? globalThis_;
+ webidl.assertBranded(self, EventTargetPrototype);
+ webidl.requiredArguments(arguments.length, 2, {
+ prefix: "Failed to execute 'removeEventListener' on 'EventTarget'",
+ });
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(ErrorEvent.prototype, this),
- keys: [
- ...new SafeArrayIterator(EVENT_PROPS),
- "message",
- "filename",
- "lineno",
- "colno",
- "error",
- ],
- }));
+ const { listeners } = self[eventTargetData];
+ if (callback !== null && ReflectHas(listeners, type)) {
+ listeners[type] = ArrayPrototypeFilter(
+ listeners[type],
+ (listener) => listener.callback !== callback,
+ );
+ } else if (callback === null || !listeners[type]) {
+ return;
}
- // TODO(lucacasonato): remove when this interface is spec aligned
- [SymbolToStringTag] = "ErrorEvent";
- }
+ options = normalizeEventHandlerOptions(options);
- defineEnumerableProps(ErrorEvent, [
- "message",
- "filename",
- "lineno",
- "colno",
- "error",
- ]);
+ for (let i = 0; i < listeners[type].length; ++i) {
+ const listener = listeners[type][i];
+ if (
+ ((typeof listener.options === "boolean" &&
+ listener.options === options.capture) ||
+ (typeof listener.options === "object" &&
+ listener.options.capture === options.capture)) &&
+ listener.callback === callback
+ ) {
+ ArrayPrototypeSplice(listeners[type], i, 1);
+ break;
+ }
+ }
+ }
- class CloseEvent extends Event {
- #wasClean = "";
- #code = "";
- #reason = "";
+ dispatchEvent(event) {
+ // If `this` is not present, then fallback to global scope. We don't use
+ // `globalThis` directly here, because it could be deleted by user.
+ // Instead use saved reference to global scope when the script was
+ // executed.
+ const self = this ?? globalThis_;
+ webidl.assertBranded(self, EventTargetPrototype);
+ webidl.requiredArguments(arguments.length, 1, {
+ prefix: "Failed to execute 'dispatchEvent' on 'EventTarget'",
+ });
- get wasClean() {
- return this.#wasClean;
+ const { listeners } = self[eventTargetData];
+ if (!ReflectHas(listeners, event.type)) {
+ setTarget(event, this);
+ return true;
}
- get code() {
- return this.#code;
+
+ if (getDispatched(event)) {
+ throw new DOMException("Invalid event state.", "InvalidStateError");
}
- get reason() {
- return this.#reason;
+
+ if (event.eventPhase !== Event.NONE) {
+ throw new DOMException("Invalid event state.", "InvalidStateError");
}
- constructor(type, {
+ return dispatch(self, event);
+ }
+
+ getParent(_event) {
+ return null;
+ }
+}
+
+webidl.configurePrototype(EventTarget);
+const EventTargetPrototype = EventTarget.prototype;
+
+defineEnumerableProps(EventTarget, [
+ "addEventListener",
+ "removeEventListener",
+ "dispatchEvent",
+]);
+
+class ErrorEvent extends Event {
+ #message = "";
+ #filename = "";
+ #lineno = "";
+ #colno = "";
+ #error = "";
+
+ get message() {
+ return this.#message;
+ }
+ get filename() {
+ return this.#filename;
+ }
+ get lineno() {
+ return this.#lineno;
+ }
+ get colno() {
+ return this.#colno;
+ }
+ get error() {
+ return this.#error;
+ }
+
+ constructor(
+ type,
+ {
bubbles,
cancelable,
composed,
- wasClean = false,
- code = 0,
- reason = "",
- } = {}) {
- super(type, {
- bubbles: bubbles,
- cancelable: cancelable,
- composed: composed,
- });
+ message = "",
+ filename = "",
+ lineno = 0,
+ colno = 0,
+ error,
+ } = {},
+ ) {
+ super(type, {
+ bubbles: bubbles,
+ cancelable: cancelable,
+ composed: composed,
+ });
- this.#wasClean = wasClean;
- this.#code = code;
- this.#reason = reason;
- }
+ this.#message = message;
+ this.#filename = filename;
+ this.#lineno = lineno;
+ this.#colno = colno;
+ this.#error = error;
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(CloseEvent.prototype, this),
- keys: [
- ...new SafeArrayIterator(EVENT_PROPS),
- "wasClean",
- "code",
- "reason",
- ],
- }));
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(ErrorEvent.prototype, this),
+ keys: [
+ ...new SafeArrayIterator(EVENT_PROPS),
+ "message",
+ "filename",
+ "lineno",
+ "colno",
+ "error",
+ ],
+ }));
}
- class MessageEvent extends Event {
- get source() {
- return null;
- }
+ // TODO(lucacasonato): remove when this interface is spec aligned
+ [SymbolToStringTag] = "ErrorEvent";
+}
+
+defineEnumerableProps(ErrorEvent, [
+ "message",
+ "filename",
+ "lineno",
+ "colno",
+ "error",
+]);
+
+class CloseEvent extends Event {
+ #wasClean = "";
+ #code = "";
+ #reason = "";
+
+ get wasClean() {
+ return this.#wasClean;
+ }
+ get code() {
+ return this.#code;
+ }
+ get reason() {
+ return this.#reason;
+ }
- constructor(type, eventInitDict) {
- super(type, {
- bubbles: eventInitDict?.bubbles ?? false,
- cancelable: eventInitDict?.cancelable ?? false,
- composed: eventInitDict?.composed ?? false,
- [_skipInternalInit]: eventInitDict?.[_skipInternalInit],
- });
+ constructor(type, {
+ bubbles,
+ cancelable,
+ composed,
+ wasClean = false,
+ code = 0,
+ reason = "",
+ } = {}) {
+ super(type, {
+ bubbles: bubbles,
+ cancelable: cancelable,
+ composed: composed,
+ });
- this.data = eventInitDict?.data ?? null;
- this.ports = eventInitDict?.ports ?? [];
- this.origin = eventInitDict?.origin ?? "";
- this.lastEventId = eventInitDict?.lastEventId ?? "";
- }
+ this.#wasClean = wasClean;
+ this.#code = code;
+ this.#reason = reason;
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(MessageEvent.prototype, this),
- keys: [
- ...new SafeArrayIterator(EVENT_PROPS),
- "data",
- "origin",
- "lastEventId",
- ],
- }));
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(CloseEvent.prototype, this),
+ keys: [
+ ...new SafeArrayIterator(EVENT_PROPS),
+ "wasClean",
+ "code",
+ "reason",
+ ],
+ }));
+ }
+}
- // TODO(lucacasonato): remove when this interface is spec aligned
- [SymbolToStringTag] = "CloseEvent";
+class MessageEvent extends Event {
+ get source() {
+ return null;
}
- class CustomEvent extends Event {
- #detail = null;
+ constructor(type, eventInitDict) {
+ super(type, {
+ bubbles: eventInitDict?.bubbles ?? false,
+ cancelable: eventInitDict?.cancelable ?? false,
+ composed: eventInitDict?.composed ?? false,
+ [_skipInternalInit]: eventInitDict?.[_skipInternalInit],
+ });
- constructor(type, eventInitDict = {}) {
- super(type, eventInitDict);
- webidl.requiredArguments(arguments.length, 1, {
- prefix: "Failed to construct 'CustomEvent'",
- });
- const { detail } = eventInitDict;
- this.#detail = detail;
- }
+ this.data = eventInitDict?.data ?? null;
+ this.ports = eventInitDict?.ports ?? [];
+ this.origin = eventInitDict?.origin ?? "";
+ this.lastEventId = eventInitDict?.lastEventId ?? "";
+ }
- get detail() {
- return this.#detail;
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(MessageEvent.prototype, this),
+ keys: [
+ ...new SafeArrayIterator(EVENT_PROPS),
+ "data",
+ "origin",
+ "lastEventId",
+ ],
+ }));
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(CustomEvent.prototype, this),
- keys: [
- ...new SafeArrayIterator(EVENT_PROPS),
- "detail",
- ],
- }));
- }
+ // TODO(lucacasonato): remove when this interface is spec aligned
+ [SymbolToStringTag] = "CloseEvent";
+}
- // TODO(lucacasonato): remove when this interface is spec aligned
- [SymbolToStringTag] = "CustomEvent";
+class CustomEvent extends Event {
+ #detail = null;
+
+ constructor(type, eventInitDict = {}) {
+ super(type, eventInitDict);
+ webidl.requiredArguments(arguments.length, 1, {
+ prefix: "Failed to construct 'CustomEvent'",
+ });
+ const { detail } = eventInitDict;
+ this.#detail = detail;
}
- ReflectDefineProperty(CustomEvent.prototype, "detail", {
- enumerable: true,
- });
+ get detail() {
+ return this.#detail;
+ }
- // ProgressEvent could also be used in other DOM progress event emits.
- // Current use is for FileReader.
- class ProgressEvent extends Event {
- constructor(type, eventInitDict = {}) {
- super(type, eventInitDict);
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(CustomEvent.prototype, this),
+ keys: [
+ ...new SafeArrayIterator(EVENT_PROPS),
+ "detail",
+ ],
+ }));
+ }
- this.lengthComputable = eventInitDict?.lengthComputable ?? false;
- this.loaded = eventInitDict?.loaded ?? 0;
- this.total = eventInitDict?.total ?? 0;
- }
+ // TODO(lucacasonato): remove when this interface is spec aligned
+ [SymbolToStringTag] = "CustomEvent";
+}
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(ProgressEvent.prototype, this),
- keys: [
- ...new SafeArrayIterator(EVENT_PROPS),
- "lengthComputable",
- "loaded",
- "total",
- ],
- }));
- }
+ReflectDefineProperty(CustomEvent.prototype, "detail", {
+ enumerable: true,
+});
- // TODO(lucacasonato): remove when this interface is spec aligned
- [SymbolToStringTag] = "ProgressEvent";
+// ProgressEvent could also be used in other DOM progress event emits.
+// Current use is for FileReader.
+class ProgressEvent extends Event {
+ constructor(type, eventInitDict = {}) {
+ super(type, eventInitDict);
+
+ this.lengthComputable = eventInitDict?.lengthComputable ?? false;
+ this.loaded = eventInitDict?.loaded ?? 0;
+ this.total = eventInitDict?.total ?? 0;
}
- class PromiseRejectionEvent extends Event {
- #promise = null;
- #reason = null;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(ProgressEvent.prototype, this),
+ keys: [
+ ...new SafeArrayIterator(EVENT_PROPS),
+ "lengthComputable",
+ "loaded",
+ "total",
+ ],
+ }));
+ }
- get promise() {
- return this.#promise;
- }
- get reason() {
- return this.#reason;
- }
+ // TODO(lucacasonato): remove when this interface is spec aligned
+ [SymbolToStringTag] = "ProgressEvent";
+}
- constructor(
- type,
- {
- bubbles,
- cancelable,
- composed,
- promise,
- reason,
- } = {},
- ) {
- super(type, {
- bubbles: bubbles,
- cancelable: cancelable,
- composed: composed,
- });
+class PromiseRejectionEvent extends Event {
+ #promise = null;
+ #reason = null;
- this.#promise = promise;
- this.#reason = reason;
- }
+ get promise() {
+ return this.#promise;
+ }
+ get reason() {
+ return this.#reason;
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(
- PromiseRejectionEvent.prototype,
- this,
- ),
- keys: [
- ...new SafeArrayIterator(EVENT_PROPS),
- "promise",
- "reason",
- ],
- }));
- }
+ constructor(
+ type,
+ {
+ bubbles,
+ cancelable,
+ composed,
+ promise,
+ reason,
+ } = {},
+ ) {
+ super(type, {
+ bubbles: bubbles,
+ cancelable: cancelable,
+ composed: composed,
+ });
- // TODO(lucacasonato): remove when this interface is spec aligned
- [SymbolToStringTag] = "PromiseRejectionEvent";
+ this.#promise = promise;
+ this.#reason = reason;
}
- defineEnumerableProps(PromiseRejectionEvent, [
- "promise",
- "reason",
- ]);
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ PromiseRejectionEvent.prototype,
+ this,
+ ),
+ keys: [
+ ...new SafeArrayIterator(EVENT_PROPS),
+ "promise",
+ "reason",
+ ],
+ }));
+ }
- const _eventHandlers = Symbol("eventHandlers");
+ // TODO(lucacasonato): remove when this interface is spec aligned
+ [SymbolToStringTag] = "PromiseRejectionEvent";
+}
- function makeWrappedHandler(handler, isSpecialErrorEventHandler) {
- function wrappedHandler(evt) {
- if (typeof wrappedHandler.handler !== "function") {
- return;
- }
+defineEnumerableProps(PromiseRejectionEvent, [
+ "promise",
+ "reason",
+]);
- if (
- isSpecialErrorEventHandler &&
- ObjectPrototypeIsPrototypeOf(ErrorEvent.prototype, evt) &&
- evt.type === "error"
- ) {
- const ret = FunctionPrototypeCall(
- wrappedHandler.handler,
- this,
- evt.message,
- evt.filename,
- evt.lineno,
- evt.colno,
- evt.error,
- );
- if (ret === true) {
- evt.preventDefault();
- }
- return;
- }
+const _eventHandlers = Symbol("eventHandlers");
- return FunctionPrototypeCall(wrappedHandler.handler, this, evt);
+function makeWrappedHandler(handler, isSpecialErrorEventHandler) {
+ function wrappedHandler(evt) {
+ if (typeof wrappedHandler.handler !== "function") {
+ return;
}
- wrappedHandler.handler = handler;
- return wrappedHandler;
- }
-
- // `init` is an optional function that will be called the first time that the
- // event handler property is set. It will be called with the object on which
- // the property is set as its argument.
- // `isSpecialErrorEventHandler` can be set to true to opt into the special
- // behavior of event handlers for the "error" event in a global scope.
- function defineEventHandler(
- emitter,
- name,
- init = undefined,
- isSpecialErrorEventHandler = false,
- ) {
- // HTML specification section 8.1.7.1
- ObjectDefineProperty(emitter, `on${name}`, {
- get() {
- if (!this[_eventHandlers]) {
- return null;
- }
- return MapPrototypeGet(this[_eventHandlers], name)?.handler ?? null;
- },
- set(value) {
- // All three Web IDL event handler types are nullable callback functions
- // with the [LegacyTreatNonObjectAsNull] extended attribute, meaning
- // anything other than an object is treated as null.
- if (typeof value !== "object" && typeof value !== "function") {
- value = null;
- }
+ if (
+ isSpecialErrorEventHandler &&
+ ObjectPrototypeIsPrototypeOf(ErrorEvent.prototype, evt) &&
+ evt.type === "error"
+ ) {
+ const ret = FunctionPrototypeCall(
+ wrappedHandler.handler,
+ this,
+ evt.message,
+ evt.filename,
+ evt.lineno,
+ evt.colno,
+ evt.error,
+ );
+ if (ret === true) {
+ evt.preventDefault();
+ }
+ return;
+ }
- if (!this[_eventHandlers]) {
- this[_eventHandlers] = new Map();
- }
- let handlerWrapper = MapPrototypeGet(this[_eventHandlers], name);
- if (handlerWrapper) {
- handlerWrapper.handler = value;
- } else if (value !== null) {
- handlerWrapper = makeWrappedHandler(
- value,
- isSpecialErrorEventHandler,
- );
- this.addEventListener(name, handlerWrapper);
- init?.(this);
- }
- MapPrototypeSet(this[_eventHandlers], name, handlerWrapper);
- },
- configurable: true,
- enumerable: true,
- });
+ return FunctionPrototypeCall(wrappedHandler.handler, this, evt);
}
+ wrappedHandler.handler = handler;
+ return wrappedHandler;
+}
+
+// `init` is an optional function that will be called the first time that the
+// event handler property is set. It will be called with the object on which
+// the property is set as its argument.
+// `isSpecialErrorEventHandler` can be set to true to opt into the special
+// behavior of event handlers for the "error" event in a global scope.
+function defineEventHandler(
+ emitter,
+ name,
+ init = undefined,
+ isSpecialErrorEventHandler = false,
+) {
+ // HTML specification section 8.1.7.1
+ ObjectDefineProperty(emitter, `on${name}`, {
+ get() {
+ if (!this[_eventHandlers]) {
+ return null;
+ }
- let reportExceptionStackedCalls = 0;
-
- // https://html.spec.whatwg.org/#report-the-exception
- function reportException(error) {
- reportExceptionStackedCalls++;
- const jsError = core.destructureError(error);
- const message = jsError.exceptionMessage;
- let filename = "";
- let lineno = 0;
- let colno = 0;
- if (jsError.frames.length > 0) {
- filename = jsError.frames[0].fileName;
- lineno = jsError.frames[0].lineNumber;
- colno = jsError.frames[0].columnNumber;
- } else {
- const jsError = core.destructureError(new Error());
- const frames = jsError.frames;
- for (let i = 0; i < frames.length; ++i) {
- const frame = frames[i];
- if (
- typeof frame.fileName == "string" &&
- !StringPrototypeStartsWith(frame.fileName, "internal:")
- ) {
- filename = frame.fileName;
- lineno = frame.lineNumber;
- colno = frame.columnNumber;
- break;
- }
+ return MapPrototypeGet(this[_eventHandlers], name)?.handler ?? null;
+ },
+ set(value) {
+ // All three Web IDL event handler types are nullable callback functions
+ // with the [LegacyTreatNonObjectAsNull] extended attribute, meaning
+ // anything other than an object is treated as null.
+ if (typeof value !== "object" && typeof value !== "function") {
+ value = null;
}
- }
- const event = new ErrorEvent("error", {
- cancelable: true,
- message,
- filename,
- lineno,
- colno,
- error,
- });
- // Avoid recursing `reportException()` via error handlers more than once.
- if (reportExceptionStackedCalls > 1 || window.dispatchEvent(event)) {
- ops.op_dispatch_exception(error);
- }
- reportExceptionStackedCalls--;
- }
- function checkThis(thisArg) {
- if (thisArg !== null && thisArg !== undefined && thisArg !== globalThis) {
- throw new TypeError("Illegal invocation");
+ if (!this[_eventHandlers]) {
+ this[_eventHandlers] = new Map();
+ }
+ let handlerWrapper = MapPrototypeGet(this[_eventHandlers], name);
+ if (handlerWrapper) {
+ handlerWrapper.handler = value;
+ } else if (value !== null) {
+ handlerWrapper = makeWrappedHandler(
+ value,
+ isSpecialErrorEventHandler,
+ );
+ this.addEventListener(name, handlerWrapper);
+ init?.(this);
+ }
+ MapPrototypeSet(this[_eventHandlers], name, handlerWrapper);
+ },
+ configurable: true,
+ enumerable: true,
+ });
+}
+
+let reportExceptionStackedCalls = 0;
+
+// https://html.spec.whatwg.org/#report-the-exception
+function reportException(error) {
+ reportExceptionStackedCalls++;
+ const jsError = core.destructureError(error);
+ const message = jsError.exceptionMessage;
+ let filename = "";
+ let lineno = 0;
+ let colno = 0;
+ if (jsError.frames.length > 0) {
+ filename = jsError.frames[0].fileName;
+ lineno = jsError.frames[0].lineNumber;
+ colno = jsError.frames[0].columnNumber;
+ } else {
+ const jsError = core.destructureError(new Error());
+ const frames = jsError.frames;
+ for (let i = 0; i < frames.length; ++i) {
+ const frame = frames[i];
+ if (
+ typeof frame.fileName == "string" &&
+ !StringPrototypeStartsWith(frame.fileName, "internal:")
+ ) {
+ filename = frame.fileName;
+ lineno = frame.lineNumber;
+ colno = frame.columnNumber;
+ break;
+ }
}
}
-
- // https://html.spec.whatwg.org/#dom-reporterror
- function reportError(error) {
- checkThis(this);
- const prefix = "Failed to call 'reportError'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- reportException(error);
+ const event = new ErrorEvent("error", {
+ cancelable: true,
+ message,
+ filename,
+ lineno,
+ colno,
+ error,
+ });
+ // Avoid recursing `reportException()` via error handlers more than once.
+ if (reportExceptionStackedCalls > 1 || globalThis_.dispatchEvent(event)) {
+ ops.op_dispatch_exception(error);
}
+ reportExceptionStackedCalls--;
+}
- window.__bootstrap.eventTarget = {
- EventTarget,
- setEventTargetData,
- listenerCount,
- };
- window.__bootstrap.event = {
- reportException,
- setIsTrusted,
- setTarget,
- defineEventHandler,
- _skipInternalInit,
- Event,
- ErrorEvent,
- CloseEvent,
- MessageEvent,
- CustomEvent,
- ProgressEvent,
- PromiseRejectionEvent,
- reportError,
- };
-})(this);
+function checkThis(thisArg) {
+ if (thisArg !== null && thisArg !== undefined && thisArg !== globalThis_) {
+ throw new TypeError("Illegal invocation");
+ }
+}
+
+// https://html.spec.whatwg.org/#dom-reporterror
+function reportError(error) {
+ checkThis(this);
+ const prefix = "Failed to call 'reportError'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ reportException(error);
+}
+
+export {
+ _skipInternalInit,
+ CloseEvent,
+ CustomEvent,
+ defineEventHandler,
+ ErrorEvent,
+ Event,
+ EventTarget,
+ listenerCount,
+ MessageEvent,
+ ProgressEvent,
+ PromiseRejectionEvent,
+ reportError,
+ reportException,
+ saveGlobalThisReference,
+ setEventTargetData,
+ setIsTrusted,
+ setTarget,
+};
diff --git a/ext/web/02_structured_clone.js b/ext/web/02_structured_clone.js
index 793cb1c75..373ae0ab2 100644
--- a/ext/web/02_structured_clone.js
+++ b/ext/web/02_structured_clone.js
@@ -6,138 +6,135 @@
/// <reference path="../web/internal.d.ts" />
/// <reference path="../web/lib.deno_web.d.ts" />
-"use strict";
+const core = globalThis.Deno.core;
+import DOMException from "internal:ext/web/01_dom_exception.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayBuffer,
+ ArrayBufferPrototype,
+ ArrayBufferPrototypeGetByteLength,
+ ArrayBufferPrototypeSlice,
+ ArrayBufferIsView,
+ DataView,
+ DataViewPrototypeGetBuffer,
+ DataViewPrototypeGetByteLength,
+ DataViewPrototypeGetByteOffset,
+ ObjectPrototypeIsPrototypeOf,
+ TypedArrayPrototypeGetBuffer,
+ TypedArrayPrototypeGetByteOffset,
+ TypedArrayPrototypeGetLength,
+ TypedArrayPrototypeGetSymbolToStringTag,
+ TypeErrorPrototype,
+ WeakMap,
+ WeakMapPrototypeSet,
+ Int8Array,
+ Int16Array,
+ Int32Array,
+ BigInt64Array,
+ Uint8Array,
+ Uint8ClampedArray,
+ Uint16Array,
+ Uint32Array,
+ BigUint64Array,
+ Float32Array,
+ Float64Array,
+} = primordials;
-((window) => {
- const core = window.Deno.core;
- const { DOMException } = window.__bootstrap.domException;
- const {
- ArrayBuffer,
- ArrayBufferPrototype,
- ArrayBufferPrototypeGetByteLength,
- ArrayBufferPrototypeSlice,
- ArrayBufferIsView,
- DataView,
- DataViewPrototypeGetBuffer,
- DataViewPrototypeGetByteLength,
- DataViewPrototypeGetByteOffset,
- ObjectPrototypeIsPrototypeOf,
- TypedArrayPrototypeGetBuffer,
- TypedArrayPrototypeGetByteOffset,
- TypedArrayPrototypeGetLength,
- TypedArrayPrototypeGetSymbolToStringTag,
- TypeErrorPrototype,
- WeakMap,
- WeakMapPrototypeSet,
- Int8Array,
- Int16Array,
- Int32Array,
- BigInt64Array,
- Uint8Array,
- Uint8ClampedArray,
- Uint16Array,
- Uint32Array,
- BigUint64Array,
- Float32Array,
- Float64Array,
- } = window.__bootstrap.primordials;
+const objectCloneMemo = new WeakMap();
- const objectCloneMemo = new WeakMap();
-
- function cloneArrayBuffer(
+function cloneArrayBuffer(
+ srcBuffer,
+ srcByteOffset,
+ srcLength,
+ _cloneConstructor,
+) {
+ // this function fudges the return type but SharedArrayBuffer is disabled for a while anyway
+ return ArrayBufferPrototypeSlice(
srcBuffer,
srcByteOffset,
- srcLength,
- _cloneConstructor,
- ) {
- // this function fudges the return type but SharedArrayBuffer is disabled for a while anyway
- return ArrayBufferPrototypeSlice(
- srcBuffer,
- srcByteOffset,
- srcByteOffset + srcLength,
+ srcByteOffset + srcLength,
+ );
+}
+
+// TODO(petamoriken): Resizable ArrayBuffer support in the future
+/** Clone a value in a similar way to structured cloning. It is similar to a
+ * StructureDeserialize(StructuredSerialize(...)). */
+function structuredClone(value) {
+ // Performance optimization for buffers, otherwise
+ // `serialize/deserialize` will allocate new buffer.
+ if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, value)) {
+ const cloned = cloneArrayBuffer(
+ value,
+ 0,
+ ArrayBufferPrototypeGetByteLength(value),
+ ArrayBuffer,
);
+ WeakMapPrototypeSet(objectCloneMemo, value, cloned);
+ return cloned;
}
- // TODO(petamoriken): Resizable ArrayBuffer support in the future
- /** Clone a value in a similar way to structured cloning. It is similar to a
- * StructureDeserialize(StructuredSerialize(...)). */
- function structuredClone(value) {
- // Performance optimization for buffers, otherwise
- // `serialize/deserialize` will allocate new buffer.
- if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, value)) {
- const cloned = cloneArrayBuffer(
- value,
- 0,
- ArrayBufferPrototypeGetByteLength(value),
- ArrayBuffer,
+ if (ArrayBufferIsView(value)) {
+ const tag = TypedArrayPrototypeGetSymbolToStringTag(value);
+ // DataView
+ if (tag === undefined) {
+ return new DataView(
+ structuredClone(DataViewPrototypeGetBuffer(value)),
+ DataViewPrototypeGetByteOffset(value),
+ DataViewPrototypeGetByteLength(value),
);
- WeakMapPrototypeSet(objectCloneMemo, value, cloned);
- return cloned;
}
-
- if (ArrayBufferIsView(value)) {
- const tag = TypedArrayPrototypeGetSymbolToStringTag(value);
- // DataView
- if (tag === undefined) {
- return new DataView(
- structuredClone(DataViewPrototypeGetBuffer(value)),
- DataViewPrototypeGetByteOffset(value),
- DataViewPrototypeGetByteLength(value),
- );
- }
- // TypedArray
- let Constructor;
- switch (tag) {
- case "Int8Array":
- Constructor = Int8Array;
- break;
- case "Int16Array":
- Constructor = Int16Array;
- break;
- case "Int32Array":
- Constructor = Int32Array;
- break;
- case "BigInt64Array":
- Constructor = BigInt64Array;
- break;
- case "Uint8Array":
- Constructor = Uint8Array;
- break;
- case "Uint8ClampedArray":
- Constructor = Uint8ClampedArray;
- break;
- case "Uint16Array":
- Constructor = Uint16Array;
- break;
- case "Uint32Array":
- Constructor = Uint32Array;
- break;
- case "BigUint64Array":
- Constructor = BigUint64Array;
- break;
- case "Float32Array":
- Constructor = Float32Array;
- break;
- case "Float64Array":
- Constructor = Float64Array;
- break;
- }
- return new Constructor(
- structuredClone(TypedArrayPrototypeGetBuffer(value)),
- TypedArrayPrototypeGetByteOffset(value),
- TypedArrayPrototypeGetLength(value),
- );
+ // TypedArray
+ let Constructor;
+ switch (tag) {
+ case "Int8Array":
+ Constructor = Int8Array;
+ break;
+ case "Int16Array":
+ Constructor = Int16Array;
+ break;
+ case "Int32Array":
+ Constructor = Int32Array;
+ break;
+ case "BigInt64Array":
+ Constructor = BigInt64Array;
+ break;
+ case "Uint8Array":
+ Constructor = Uint8Array;
+ break;
+ case "Uint8ClampedArray":
+ Constructor = Uint8ClampedArray;
+ break;
+ case "Uint16Array":
+ Constructor = Uint16Array;
+ break;
+ case "Uint32Array":
+ Constructor = Uint32Array;
+ break;
+ case "BigUint64Array":
+ Constructor = BigUint64Array;
+ break;
+ case "Float32Array":
+ Constructor = Float32Array;
+ break;
+ case "Float64Array":
+ Constructor = Float64Array;
+ break;
}
+ return new Constructor(
+ structuredClone(TypedArrayPrototypeGetBuffer(value)),
+ TypedArrayPrototypeGetByteOffset(value),
+ TypedArrayPrototypeGetLength(value),
+ );
+ }
- try {
- return core.deserialize(core.serialize(value));
- } catch (e) {
- if (ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e)) {
- throw new DOMException(e.message, "DataCloneError");
- }
- throw e;
+ try {
+ return core.deserialize(core.serialize(value));
+ } catch (e) {
+ if (ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e)) {
+ throw new DOMException(e.message, "DataCloneError");
}
+ throw e;
}
+}
- window.__bootstrap.structuredClone = structuredClone;
-})(globalThis);
+export { structuredClone };
diff --git a/ext/web/02_timers.js b/ext/web/02_timers.js
index a582cf428..302b6f62c 100644
--- a/ext/web/02_timers.js
+++ b/ext/web/02_timers.js
@@ -1,375 +1,372 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const {
- ArrayPrototypePush,
- ArrayPrototypeShift,
- FunctionPrototypeCall,
- Map,
- MapPrototypeDelete,
- MapPrototypeGet,
- MapPrototypeHas,
- MapPrototypeSet,
- Uint8Array,
- Uint32Array,
- // deno-lint-ignore camelcase
- NumberPOSITIVE_INFINITY,
- PromisePrototypeThen,
- SafeArrayIterator,
- SymbolFor,
- TypeError,
- indirectEval,
- } = window.__bootstrap.primordials;
- const { webidl } = window.__bootstrap;
- const { reportException } = window.__bootstrap.event;
- const { assert } = window.__bootstrap.infra;
-
- const hrU8 = new Uint8Array(8);
- const hr = new Uint32Array(hrU8.buffer);
- function opNow() {
- ops.op_now(hrU8);
- return (hr[0] * 1000 + hr[1] / 1e6);
- }
- // ---------------------------------------------------------------------------
-
- /**
- * The task queue corresponding to the timer task source.
- *
- * @type { {action: () => void, nestingLevel: number}[] }
- */
- const timerTasks = [];
-
- /**
- * The current task's timer nesting level, or zero if we're not currently
- * running a timer task (since the minimum nesting level is 1).
- *
- * @type {number}
- */
- let timerNestingLevel = 0;
-
- function handleTimerMacrotask() {
- if (timerTasks.length === 0) {
- return true;
- }
-
- const task = ArrayPrototypeShift(timerTasks);
-
- timerNestingLevel = task.nestingLevel;
-
- try {
- task.action();
- } finally {
- timerNestingLevel = 0;
- }
- return timerTasks.length === 0;
+const core = globalThis.Deno.core;
+const ops = core.ops;
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypePush,
+ ArrayPrototypeShift,
+ FunctionPrototypeCall,
+ Map,
+ MapPrototypeDelete,
+ MapPrototypeGet,
+ MapPrototypeHas,
+ MapPrototypeSet,
+ Uint8Array,
+ Uint32Array,
+ // deno-lint-ignore camelcase
+ NumberPOSITIVE_INFINITY,
+ PromisePrototypeThen,
+ SafeArrayIterator,
+ SymbolFor,
+ TypeError,
+ indirectEval,
+} = primordials;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { reportException } from "internal:ext/web/02_event.js";
+import { assert } from "internal:ext/web/00_infra.js";
+
+const hrU8 = new Uint8Array(8);
+const hr = new Uint32Array(hrU8.buffer);
+function opNow() {
+ ops.op_now(hrU8);
+ return (hr[0] * 1000 + hr[1] / 1e6);
+}
+
+// ---------------------------------------------------------------------------
+
+/**
+ * The task queue corresponding to the timer task source.
+ *
+ * @type { {action: () => void, nestingLevel: number}[] }
+ */
+const timerTasks = [];
+
+/**
+ * The current task's timer nesting level, or zero if we're not currently
+ * running a timer task (since the minimum nesting level is 1).
+ *
+ * @type {number}
+ */
+let timerNestingLevel = 0;
+
+function handleTimerMacrotask() {
+ if (timerTasks.length === 0) {
+ return true;
}
- // ---------------------------------------------------------------------------
-
- /**
- * The keys in this map correspond to the key ID's in the spec's map of active
- * timers. The values are the timeout's cancel rid.
- *
- * @type {Map<number, { cancelRid: number, isRef: boolean, promiseId: number }>}
- */
- const activeTimers = new Map();
-
- let nextId = 1;
-
- /**
- * @param {Function | string} callback
- * @param {number} timeout
- * @param {Array<any>} args
- * @param {boolean} repeat
- * @param {number | undefined} prevId
- * @returns {number} The timer ID
- */
- function initializeTimer(
- callback,
- timeout,
- args,
- repeat,
- prevId,
- ) {
- // 2. If previousId was given, let id be previousId; otherwise, let
- // previousId be an implementation-defined integer than is greater than zero
- // and does not already exist in global's map of active timers.
- let id;
- let timerInfo;
- if (prevId !== undefined) {
- // `prevId` is only passed for follow-up calls on intervals
- assert(repeat);
- id = prevId;
- timerInfo = MapPrototypeGet(activeTimers, id);
- } else {
- // TODO(@andreubotella): Deal with overflow.
- // https://github.com/whatwg/html/issues/7358
- id = nextId++;
- const cancelRid = ops.op_timer_handle();
- timerInfo = { cancelRid, isRef: true, promiseId: -1 };
-
- // Step 4 in "run steps after a timeout".
- MapPrototypeSet(activeTimers, id, timerInfo);
- }
-
- // 3. If the surrounding agent's event loop's currently running task is a
- // task that was created by this algorithm, then let nesting level be the
- // task's timer nesting level. Otherwise, let nesting level be zero.
- // 4. If timeout is less than 0, then set timeout to 0.
- // 5. If nesting level is greater than 5, and timeout is less than 4, then
- // set timeout to 4.
- //
- // The nesting level of 5 and minimum of 4 ms are spec-mandated magic
- // constants.
- if (timeout < 0) timeout = 0;
- if (timerNestingLevel > 5 && timeout < 4) timeout = 4;
-
- // 9. Let task be a task that runs the following steps:
- const task = {
- action: () => {
- // 1. If id does not exist in global's map of active timers, then abort
- // these steps.
- //
- // This is relevant if the timer has been canceled after the sleep op
- // resolves but before this task runs.
- if (!MapPrototypeHas(activeTimers, id)) {
- return;
- }
+ const task = ArrayPrototypeShift(timerTasks);
- // 2.
- // 3.
- if (typeof callback === "function") {
- try {
- FunctionPrototypeCall(
- callback,
- globalThis,
- ...new SafeArrayIterator(args),
- );
- } catch (error) {
- reportException(error);
- }
- } else {
- indirectEval(callback);
- }
+ timerNestingLevel = task.nestingLevel;
- if (repeat) {
- if (MapPrototypeHas(activeTimers, id)) {
- // 4. If id does not exist in global's map of active timers, then
- // abort these steps.
- // NOTE: If might have been removed via the author code in handler
- // calling clearTimeout() or clearInterval().
- // 5. If repeat is true, then perform the timer initialization steps
- // again, given global, handler, timeout, arguments, true, and id.
- initializeTimer(callback, timeout, args, true, id);
- }
- } else {
- // 6. Otherwise, remove global's map of active timers[id].
- core.tryClose(timerInfo.cancelRid);
- MapPrototypeDelete(activeTimers, id);
- }
- },
-
- // 10. Increment nesting level by one.
- // 11. Set task's timer nesting level to nesting level.
- nestingLevel: timerNestingLevel + 1,
- };
-
- // 12. Let completionStep be an algorithm step which queues a global task on
- // the timer task source given global to run task.
- // 13. Run steps after a timeout given global, "setTimeout/setInterval",
- // timeout, completionStep, and id.
- runAfterTimeout(
- () => ArrayPrototypePush(timerTasks, task),
- timeout,
- timerInfo,
- );
-
- return id;
+ try {
+ task.action();
+ } finally {
+ timerNestingLevel = 0;
+ }
+ return timerTasks.length === 0;
+}
+
+// ---------------------------------------------------------------------------
+
+/**
+ * The keys in this map correspond to the key ID's in the spec's map of active
+ * timers. The values are the timeout's cancel rid.
+ *
+ * @type {Map<number, { cancelRid: number, isRef: boolean, promiseId: number }>}
+ */
+const activeTimers = new Map();
+
+let nextId = 1;
+
+/**
+ * @param {Function | string} callback
+ * @param {number} timeout
+ * @param {Array<any>} args
+ * @param {boolean} repeat
+ * @param {number | undefined} prevId
+ * @returns {number} The timer ID
+ */
+function initializeTimer(
+ callback,
+ timeout,
+ args,
+ repeat,
+ prevId,
+) {
+ // 2. If previousId was given, let id be previousId; otherwise, let
+ // previousId be an implementation-defined integer than is greater than zero
+ // and does not already exist in global's map of active timers.
+ let id;
+ let timerInfo;
+ if (prevId !== undefined) {
+ // `prevId` is only passed for follow-up calls on intervals
+ assert(repeat);
+ id = prevId;
+ timerInfo = MapPrototypeGet(activeTimers, id);
+ } else {
+ // TODO(@andreubotella): Deal with overflow.
+ // https://github.com/whatwg/html/issues/7358
+ id = nextId++;
+ const cancelRid = ops.op_timer_handle();
+ timerInfo = { cancelRid, isRef: true, promiseId: -1 };
+
+ // Step 4 in "run steps after a timeout".
+ MapPrototypeSet(activeTimers, id, timerInfo);
}
- // ---------------------------------------------------------------------------
-
- /**
- * @typedef ScheduledTimer
- * @property {number} millis
- * @property {() => void} cb
- * @property {boolean} resolved
- * @property {ScheduledTimer | null} prev
- * @property {ScheduledTimer | null} next
- */
-
- /**
- * A doubly linked list of timers.
- * @type { { head: ScheduledTimer | null, tail: ScheduledTimer | null } }
- */
- const scheduledTimers = { head: null, tail: null };
-
- /**
- * @param {() => void} cb Will be run after the timeout, if it hasn't been
- * cancelled.
- * @param {number} millis
- * @param {{ cancelRid: number, isRef: boolean, promiseId: number }} timerInfo
- */
- function runAfterTimeout(cb, millis, timerInfo) {
- const cancelRid = timerInfo.cancelRid;
- const sleepPromise = core.opAsync("op_sleep", millis, cancelRid);
- timerInfo.promiseId =
- sleepPromise[SymbolFor("Deno.core.internalPromiseId")];
- if (!timerInfo.isRef) {
- core.unrefOp(timerInfo.promiseId);
- }
-
- /** @type {ScheduledTimer} */
- const timerObject = {
- millis,
- cb,
- resolved: false,
- prev: scheduledTimers.tail,
- next: null,
- };
-
- // Add timerObject to the end of the list.
- if (scheduledTimers.tail === null) {
- assert(scheduledTimers.head === null);
- scheduledTimers.head = scheduledTimers.tail = timerObject;
- } else {
- scheduledTimers.tail.next = timerObject;
- scheduledTimers.tail = timerObject;
- }
-
- // 1.
- PromisePrototypeThen(
- sleepPromise,
- (cancelled) => {
- if (!cancelled) {
- // The timer was cancelled.
- removeFromScheduledTimers(timerObject);
- return;
+ // 3. If the surrounding agent's event loop's currently running task is a
+ // task that was created by this algorithm, then let nesting level be the
+ // task's timer nesting level. Otherwise, let nesting level be zero.
+ // 4. If timeout is less than 0, then set timeout to 0.
+ // 5. If nesting level is greater than 5, and timeout is less than 4, then
+ // set timeout to 4.
+ //
+ // The nesting level of 5 and minimum of 4 ms are spec-mandated magic
+ // constants.
+ if (timeout < 0) timeout = 0;
+ if (timerNestingLevel > 5 && timeout < 4) timeout = 4;
+
+ // 9. Let task be a task that runs the following steps:
+ const task = {
+ action: () => {
+ // 1. If id does not exist in global's map of active timers, then abort
+ // these steps.
+ //
+ // This is relevant if the timer has been canceled after the sleep op
+ // resolves but before this task runs.
+ if (!MapPrototypeHas(activeTimers, id)) {
+ return;
+ }
+
+ // 2.
+ // 3.
+ if (typeof callback === "function") {
+ try {
+ FunctionPrototypeCall(
+ callback,
+ globalThis,
+ ...new SafeArrayIterator(args),
+ );
+ } catch (error) {
+ reportException(error);
}
- // 2. Wait until any invocations of this algorithm that had the same
- // global and orderingIdentifier, that started before this one, and
- // whose milliseconds is equal to or less than this one's, have
- // completed.
- // 4. Perform completionSteps.
-
- // IMPORTANT: Since the sleep ops aren't guaranteed to resolve in the
- // right order, whenever one resolves, we run through the scheduled
- // timers list (which is in the order in which they were scheduled), and
- // we call the callback for every timer which both:
- // a) has resolved, and
- // b) its timeout is lower than the lowest unresolved timeout found so
- // far in the list.
-
- timerObject.resolved = true;
-
- let lowestUnresolvedTimeout = NumberPOSITIVE_INFINITY;
-
- let currentEntry = scheduledTimers.head;
- while (currentEntry !== null) {
- if (currentEntry.millis < lowestUnresolvedTimeout) {
- if (currentEntry.resolved) {
- currentEntry.cb();
- removeFromScheduledTimers(currentEntry);
- } else {
- lowestUnresolvedTimeout = currentEntry.millis;
- }
- }
-
- currentEntry = currentEntry.next;
+ } else {
+ indirectEval(callback);
+ }
+
+ if (repeat) {
+ if (MapPrototypeHas(activeTimers, id)) {
+ // 4. If id does not exist in global's map of active timers, then
+ // abort these steps.
+ // NOTE: If might have been removed via the author code in handler
+ // calling clearTimeout() or clearInterval().
+ // 5. If repeat is true, then perform the timer initialization steps
+ // again, given global, handler, timeout, arguments, true, and id.
+ initializeTimer(callback, timeout, args, true, id);
}
- },
- );
- }
+ } else {
+ // 6. Otherwise, remove global's map of active timers[id].
+ core.tryClose(timerInfo.cancelRid);
+ MapPrototypeDelete(activeTimers, id);
+ }
+ },
+
+ // 10. Increment nesting level by one.
+ // 11. Set task's timer nesting level to nesting level.
+ nestingLevel: timerNestingLevel + 1,
+ };
- /** @param {ScheduledTimer} timerObj */
- function removeFromScheduledTimers(timerObj) {
- if (timerObj.prev !== null) {
- timerObj.prev.next = timerObj.next;
- } else {
- assert(scheduledTimers.head === timerObj);
- scheduledTimers.head = timerObj.next;
- }
- if (timerObj.next !== null) {
- timerObj.next.prev = timerObj.prev;
- } else {
- assert(scheduledTimers.tail === timerObj);
- scheduledTimers.tail = timerObj.prev;
- }
+ // 12. Let completionStep be an algorithm step which queues a global task on
+ // the timer task source given global to run task.
+ // 13. Run steps after a timeout given global, "setTimeout/setInterval",
+ // timeout, completionStep, and id.
+ runAfterTimeout(
+ () => ArrayPrototypePush(timerTasks, task),
+ timeout,
+ timerInfo,
+ );
+
+ return id;
+}
+
+// ---------------------------------------------------------------------------
+
+/**
+ * @typedef ScheduledTimer
+ * @property {number} millis
+ * @property {() => void} cb
+ * @property {boolean} resolved
+ * @property {ScheduledTimer | null} prev
+ * @property {ScheduledTimer | null} next
+ */
+
+/**
+ * A doubly linked list of timers.
+ * @type { { head: ScheduledTimer | null, tail: ScheduledTimer | null } }
+ */
+const scheduledTimers = { head: null, tail: null };
+
+/**
+ * @param {() => void} cb Will be run after the timeout, if it hasn't been
+ * cancelled.
+ * @param {number} millis
+ * @param {{ cancelRid: number, isRef: boolean, promiseId: number }} timerInfo
+ */
+function runAfterTimeout(cb, millis, timerInfo) {
+ const cancelRid = timerInfo.cancelRid;
+ const sleepPromise = core.opAsync("op_sleep", millis, cancelRid);
+ timerInfo.promiseId = sleepPromise[SymbolFor("Deno.core.internalPromiseId")];
+ if (!timerInfo.isRef) {
+ core.unrefOp(timerInfo.promiseId);
}
- // ---------------------------------------------------------------------------
+ /** @type {ScheduledTimer} */
+ const timerObject = {
+ millis,
+ cb,
+ resolved: false,
+ prev: scheduledTimers.tail,
+ next: null,
+ };
- function checkThis(thisArg) {
- if (thisArg !== null && thisArg !== undefined && thisArg !== globalThis) {
- throw new TypeError("Illegal invocation");
- }
+ // Add timerObject to the end of the list.
+ if (scheduledTimers.tail === null) {
+ assert(scheduledTimers.head === null);
+ scheduledTimers.head = scheduledTimers.tail = timerObject;
+ } else {
+ scheduledTimers.tail.next = timerObject;
+ scheduledTimers.tail = timerObject;
}
- function setTimeout(callback, timeout = 0, ...args) {
- checkThis(this);
- if (typeof callback !== "function") {
- callback = webidl.converters.DOMString(callback);
- }
- timeout = webidl.converters.long(timeout);
+ // 1.
+ PromisePrototypeThen(
+ sleepPromise,
+ (cancelled) => {
+ if (!cancelled) {
+ // The timer was cancelled.
+ removeFromScheduledTimers(timerObject);
+ return;
+ }
+ // 2. Wait until any invocations of this algorithm that had the same
+ // global and orderingIdentifier, that started before this one, and
+ // whose milliseconds is equal to or less than this one's, have
+ // completed.
+ // 4. Perform completionSteps.
+
+ // IMPORTANT: Since the sleep ops aren't guaranteed to resolve in the
+ // right order, whenever one resolves, we run through the scheduled
+ // timers list (which is in the order in which they were scheduled), and
+ // we call the callback for every timer which both:
+ // a) has resolved, and
+ // b) its timeout is lower than the lowest unresolved timeout found so
+ // far in the list.
+
+ timerObject.resolved = true;
+
+ let lowestUnresolvedTimeout = NumberPOSITIVE_INFINITY;
+
+ let currentEntry = scheduledTimers.head;
+ while (currentEntry !== null) {
+ if (currentEntry.millis < lowestUnresolvedTimeout) {
+ if (currentEntry.resolved) {
+ currentEntry.cb();
+ removeFromScheduledTimers(currentEntry);
+ } else {
+ lowestUnresolvedTimeout = currentEntry.millis;
+ }
+ }
- return initializeTimer(callback, timeout, args, false);
+ currentEntry = currentEntry.next;
+ }
+ },
+ );
+}
+
+/** @param {ScheduledTimer} timerObj */
+function removeFromScheduledTimers(timerObj) {
+ if (timerObj.prev !== null) {
+ timerObj.prev.next = timerObj.next;
+ } else {
+ assert(scheduledTimers.head === timerObj);
+ scheduledTimers.head = timerObj.next;
+ }
+ if (timerObj.next !== null) {
+ timerObj.next.prev = timerObj.prev;
+ } else {
+ assert(scheduledTimers.tail === timerObj);
+ scheduledTimers.tail = timerObj.prev;
}
+}
- function setInterval(callback, timeout = 0, ...args) {
- checkThis(this);
- if (typeof callback !== "function") {
- callback = webidl.converters.DOMString(callback);
- }
- timeout = webidl.converters.long(timeout);
+// ---------------------------------------------------------------------------
- return initializeTimer(callback, timeout, args, true);
+function checkThis(thisArg) {
+ if (thisArg !== null && thisArg !== undefined && thisArg !== globalThis) {
+ throw new TypeError("Illegal invocation");
}
+}
- function clearTimeout(id = 0) {
- checkThis(this);
- id = webidl.converters.long(id);
- const timerInfo = MapPrototypeGet(activeTimers, id);
- if (timerInfo !== undefined) {
- core.tryClose(timerInfo.cancelRid);
- MapPrototypeDelete(activeTimers, id);
- }
+function setTimeout(callback, timeout = 0, ...args) {
+ checkThis(this);
+ if (typeof callback !== "function") {
+ callback = webidl.converters.DOMString(callback);
}
+ timeout = webidl.converters.long(timeout);
- function clearInterval(id = 0) {
- checkThis(this);
- clearTimeout(id);
- }
+ return initializeTimer(callback, timeout, args, false);
+}
- function refTimer(id) {
- const timerInfo = MapPrototypeGet(activeTimers, id);
- if (timerInfo === undefined || timerInfo.isRef) {
- return;
- }
- timerInfo.isRef = true;
- core.refOp(timerInfo.promiseId);
+function setInterval(callback, timeout = 0, ...args) {
+ checkThis(this);
+ if (typeof callback !== "function") {
+ callback = webidl.converters.DOMString(callback);
}
-
- function unrefTimer(id) {
- const timerInfo = MapPrototypeGet(activeTimers, id);
- if (timerInfo === undefined || !timerInfo.isRef) {
- return;
- }
- timerInfo.isRef = false;
- core.unrefOp(timerInfo.promiseId);
+ timeout = webidl.converters.long(timeout);
+
+ return initializeTimer(callback, timeout, args, true);
+}
+
+function clearTimeout(id = 0) {
+ checkThis(this);
+ id = webidl.converters.long(id);
+ const timerInfo = MapPrototypeGet(activeTimers, id);
+ if (timerInfo !== undefined) {
+ core.tryClose(timerInfo.cancelRid);
+ MapPrototypeDelete(activeTimers, id);
}
+}
- window.__bootstrap.timers = {
- setTimeout,
- setInterval,
- clearTimeout,
- clearInterval,
- handleTimerMacrotask,
- opNow,
- refTimer,
- unrefTimer,
- };
-})(this);
+function clearInterval(id = 0) {
+ checkThis(this);
+ clearTimeout(id);
+}
+
+function refTimer(id) {
+ const timerInfo = MapPrototypeGet(activeTimers, id);
+ if (timerInfo === undefined || timerInfo.isRef) {
+ return;
+ }
+ timerInfo.isRef = true;
+ core.refOp(timerInfo.promiseId);
+}
+
+function unrefTimer(id) {
+ const timerInfo = MapPrototypeGet(activeTimers, id);
+ if (timerInfo === undefined || !timerInfo.isRef) {
+ return;
+ }
+ timerInfo.isRef = false;
+ core.unrefOp(timerInfo.promiseId);
+}
+
+export {
+ clearInterval,
+ clearTimeout,
+ handleTimerMacrotask,
+ opNow,
+ refTimer,
+ setInterval,
+ setTimeout,
+ unrefTimer,
+};
diff --git a/ext/web/03_abort_signal.js b/ext/web/03_abort_signal.js
index cce1bac7e..96757f41f 100644
--- a/ext/web/03_abort_signal.js
+++ b/ext/web/03_abort_signal.js
@@ -1,200 +1,205 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
// @ts-check
/// <reference path="../../core/internal.d.ts" />
-((window) => {
- const webidl = window.__bootstrap.webidl;
- const { Event, setIsTrusted, defineEventHandler } = window.__bootstrap.event;
- const { EventTarget, listenerCount } = window.__bootstrap.eventTarget;
- const {
- SafeArrayIterator,
- SafeSetIterator,
- Set,
- SetPrototypeAdd,
- SetPrototypeDelete,
- Symbol,
- TypeError,
- } = window.__bootstrap.primordials;
- const { setTimeout, refTimer, unrefTimer } = window.__bootstrap.timers;
-
- const add = Symbol("[[add]]");
- const signalAbort = Symbol("[[signalAbort]]");
- const remove = Symbol("[[remove]]");
- const abortReason = Symbol("[[abortReason]]");
- const abortAlgos = Symbol("[[abortAlgos]]");
- const signal = Symbol("[[signal]]");
- const timerId = Symbol("[[timerId]]");
-
- const illegalConstructorKey = Symbol("illegalConstructorKey");
-
- class AbortSignal extends EventTarget {
- static abort(reason = undefined) {
- if (reason !== undefined) {
- reason = webidl.converters.any(reason);
- }
- const signal = new AbortSignal(illegalConstructorKey);
- signal[signalAbort](reason);
- return signal;
- }
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import {
+ defineEventHandler,
+ Event,
+ EventTarget,
+ listenerCount,
+ setIsTrusted,
+} from "internal:ext/web/02_event.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ SafeArrayIterator,
+ SafeSetIterator,
+ Set,
+ SetPrototypeAdd,
+ SetPrototypeDelete,
+ Symbol,
+ TypeError,
+} = primordials;
+import {
+ refTimer,
+ setTimeout,
+ unrefTimer,
+} from "internal:ext/web/02_timers.js";
+
+const add = Symbol("[[add]]");
+const signalAbort = Symbol("[[signalAbort]]");
+const remove = Symbol("[[remove]]");
+const abortReason = Symbol("[[abortReason]]");
+const abortAlgos = Symbol("[[abortAlgos]]");
+const signal = Symbol("[[signal]]");
+const timerId = Symbol("[[timerId]]");
+
+const illegalConstructorKey = Symbol("illegalConstructorKey");
+
+class AbortSignal extends EventTarget {
+ static abort(reason = undefined) {
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
+ }
+ const signal = new AbortSignal(illegalConstructorKey);
+ signal[signalAbort](reason);
+ return signal;
+ }
- static timeout(millis) {
- const prefix = "Failed to call 'AbortSignal.timeout'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- millis = webidl.converters["unsigned long long"](millis, {
- enforceRange: true,
- });
-
- const signal = new AbortSignal(illegalConstructorKey);
- signal[timerId] = setTimeout(
- () => {
- signal[timerId] = null;
- signal[signalAbort](
- new DOMException("Signal timed out.", "TimeoutError"),
- );
- },
- millis,
- );
- unrefTimer(signal[timerId]);
- return signal;
- }
+ static timeout(millis) {
+ const prefix = "Failed to call 'AbortSignal.timeout'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ millis = webidl.converters["unsigned long long"](millis, {
+ enforceRange: true,
+ });
+
+ const signal = new AbortSignal(illegalConstructorKey);
+ signal[timerId] = setTimeout(
+ () => {
+ signal[timerId] = null;
+ signal[signalAbort](
+ new DOMException("Signal timed out.", "TimeoutError"),
+ );
+ },
+ millis,
+ );
+ unrefTimer(signal[timerId]);
+ return signal;
+ }
- [add](algorithm) {
- if (this.aborted) {
- return;
- }
- if (this[abortAlgos] === null) {
- this[abortAlgos] = new Set();
- }
- SetPrototypeAdd(this[abortAlgos], algorithm);
+ [add](algorithm) {
+ if (this.aborted) {
+ return;
}
-
- [signalAbort](
- reason = new DOMException("The signal has been aborted", "AbortError"),
- ) {
- if (this.aborted) {
- return;
- }
- this[abortReason] = reason;
- if (this[abortAlgos] !== null) {
- for (const algorithm of new SafeSetIterator(this[abortAlgos])) {
- algorithm();
- }
- this[abortAlgos] = null;
- }
- const event = new Event("abort");
- setIsTrusted(event, true);
- this.dispatchEvent(event);
+ if (this[abortAlgos] === null) {
+ this[abortAlgos] = new Set();
}
+ SetPrototypeAdd(this[abortAlgos], algorithm);
+ }
- [remove](algorithm) {
- this[abortAlgos] && SetPrototypeDelete(this[abortAlgos], algorithm);
+ [signalAbort](
+ reason = new DOMException("The signal has been aborted", "AbortError"),
+ ) {
+ if (this.aborted) {
+ return;
}
-
- constructor(key = null) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
+ this[abortReason] = reason;
+ if (this[abortAlgos] !== null) {
+ for (const algorithm of new SafeSetIterator(this[abortAlgos])) {
+ algorithm();
}
- super();
- this[abortReason] = undefined;
this[abortAlgos] = null;
- this[timerId] = null;
- this[webidl.brand] = webidl.brand;
}
+ const event = new Event("abort");
+ setIsTrusted(event, true);
+ this.dispatchEvent(event);
+ }
- get aborted() {
- webidl.assertBranded(this, AbortSignalPrototype);
- return this[abortReason] !== undefined;
- }
+ [remove](algorithm) {
+ this[abortAlgos] && SetPrototypeDelete(this[abortAlgos], algorithm);
+ }
- get reason() {
- webidl.assertBranded(this, AbortSignalPrototype);
- return this[abortReason];
+ constructor(key = null) {
+ if (key != illegalConstructorKey) {
+ throw new TypeError("Illegal constructor.");
}
+ super();
+ this[abortReason] = undefined;
+ this[abortAlgos] = null;
+ this[timerId] = null;
+ this[webidl.brand] = webidl.brand;
+ }
- throwIfAborted() {
- webidl.assertBranded(this, AbortSignalPrototype);
- if (this[abortReason] !== undefined) {
- throw this[abortReason];
- }
+ get aborted() {
+ webidl.assertBranded(this, AbortSignalPrototype);
+ return this[abortReason] !== undefined;
+ }
+
+ get reason() {
+ webidl.assertBranded(this, AbortSignalPrototype);
+ return this[abortReason];
+ }
+
+ throwIfAborted() {
+ webidl.assertBranded(this, AbortSignalPrototype);
+ if (this[abortReason] !== undefined) {
+ throw this[abortReason];
}
+ }
- // `addEventListener` and `removeEventListener` have to be overriden in
- // order to have the timer block the event loop while there are listeners.
- // `[add]` and `[remove]` don't ref and unref the timer because they can
- // only be used by Deno internals, which use it to essentially cancel async
- // ops which would block the event loop.
- addEventListener(...args) {
- super.addEventListener(...new SafeArrayIterator(args));
- if (this[timerId] !== null && listenerCount(this, "abort") > 0) {
- refTimer(this[timerId]);
- }
+ // `addEventListener` and `removeEventListener` have to be overriden in
+ // order to have the timer block the event loop while there are listeners.
+ // `[add]` and `[remove]` don't ref and unref the timer because they can
+ // only be used by Deno internals, which use it to essentially cancel async
+ // ops which would block the event loop.
+ addEventListener(...args) {
+ super.addEventListener(...new SafeArrayIterator(args));
+ if (this[timerId] !== null && listenerCount(this, "abort") > 0) {
+ refTimer(this[timerId]);
}
+ }
- removeEventListener(...args) {
- super.removeEventListener(...new SafeArrayIterator(args));
- if (this[timerId] !== null && listenerCount(this, "abort") === 0) {
- unrefTimer(this[timerId]);
- }
+ removeEventListener(...args) {
+ super.removeEventListener(...new SafeArrayIterator(args));
+ if (this[timerId] !== null && listenerCount(this, "abort") === 0) {
+ unrefTimer(this[timerId]);
}
}
- defineEventHandler(AbortSignal.prototype, "abort");
+}
+defineEventHandler(AbortSignal.prototype, "abort");
- webidl.configurePrototype(AbortSignal);
- const AbortSignalPrototype = AbortSignal.prototype;
+webidl.configurePrototype(AbortSignal);
+const AbortSignalPrototype = AbortSignal.prototype;
- class AbortController {
- [signal] = new AbortSignal(illegalConstructorKey);
+class AbortController {
+ [signal] = new AbortSignal(illegalConstructorKey);
- constructor() {
- this[webidl.brand] = webidl.brand;
- }
+ constructor() {
+ this[webidl.brand] = webidl.brand;
+ }
- get signal() {
- webidl.assertBranded(this, AbortControllerPrototype);
- return this[signal];
- }
+ get signal() {
+ webidl.assertBranded(this, AbortControllerPrototype);
+ return this[signal];
+ }
- abort(reason) {
- webidl.assertBranded(this, AbortControllerPrototype);
- this[signal][signalAbort](reason);
- }
+ abort(reason) {
+ webidl.assertBranded(this, AbortControllerPrototype);
+ this[signal][signalAbort](reason);
}
+}
- webidl.configurePrototype(AbortController);
- const AbortControllerPrototype = AbortController.prototype;
+webidl.configurePrototype(AbortController);
+const AbortControllerPrototype = AbortController.prototype;
- webidl.converters["AbortSignal"] = webidl.createInterfaceConverter(
- "AbortSignal",
- AbortSignal.prototype,
- );
+webidl.converters["AbortSignal"] = webidl.createInterfaceConverter(
+ "AbortSignal",
+ AbortSignal.prototype,
+);
- function newSignal() {
- return new AbortSignal(illegalConstructorKey);
- }
+function newSignal() {
+ return new AbortSignal(illegalConstructorKey);
+}
- function follow(followingSignal, parentSignal) {
- if (followingSignal.aborted) {
- return;
- }
- if (parentSignal.aborted) {
- followingSignal[signalAbort](parentSignal.reason);
- } else {
- parentSignal[add](() =>
- followingSignal[signalAbort](parentSignal.reason)
- );
- }
+function follow(followingSignal, parentSignal) {
+ if (followingSignal.aborted) {
+ return;
}
-
- window.__bootstrap.abortSignal = {
- AbortSignal,
- AbortController,
- AbortSignalPrototype,
- add,
- signalAbort,
- remove,
- follow,
- newSignal,
- };
-})(this);
+ if (parentSignal.aborted) {
+ followingSignal[signalAbort](parentSignal.reason);
+ } else {
+ parentSignal[add](() => followingSignal[signalAbort](parentSignal.reason));
+ }
+}
+
+export {
+ AbortController,
+ AbortSignal,
+ AbortSignalPrototype,
+ add,
+ follow,
+ newSignal,
+ remove,
+ signalAbort,
+};
diff --git a/ext/web/04_global_interfaces.js b/ext/web/04_global_interfaces.js
index 840f93ba9..6a42968db 100644
--- a/ext/web/04_global_interfaces.js
+++ b/ext/web/04_global_interfaces.js
@@ -1,79 +1,83 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
// @ts-check
/// <reference path="../../core/internal.d.ts" />
-((window) => {
- const { EventTarget } = window.__bootstrap.eventTarget;
- const {
- Symbol,
- SymbolToStringTag,
- TypeError,
- } = window.__bootstrap.primordials;
+import { EventTarget } from "internal:ext/web/02_event.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ Symbol,
+ SymbolToStringTag,
+ TypeError,
+} = primordials;
- const illegalConstructorKey = Symbol("illegalConstructorKey");
+const illegalConstructorKey = Symbol("illegalConstructorKey");
- class Window extends EventTarget {
- constructor(key = null) {
- if (key !== illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- super();
+class Window extends EventTarget {
+ constructor(key = null) {
+ if (key !== illegalConstructorKey) {
+ throw new TypeError("Illegal constructor.");
}
+ super();
+ }
- get [SymbolToStringTag]() {
- return "Window";
- }
+ get [SymbolToStringTag]() {
+ return "Window";
}
+}
- class WorkerGlobalScope extends EventTarget {
- constructor(key = null) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- super();
+class WorkerGlobalScope extends EventTarget {
+ constructor(key = null) {
+ if (key != illegalConstructorKey) {
+ throw new TypeError("Illegal constructor.");
}
+ super();
+ }
- get [SymbolToStringTag]() {
- return "WorkerGlobalScope";
- }
+ get [SymbolToStringTag]() {
+ return "WorkerGlobalScope";
}
+}
- class DedicatedWorkerGlobalScope extends WorkerGlobalScope {
- constructor(key = null) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- super();
+class DedicatedWorkerGlobalScope extends WorkerGlobalScope {
+ constructor(key = null) {
+ if (key != illegalConstructorKey) {
+ throw new TypeError("Illegal constructor.");
}
+ super();
+ }
- get [SymbolToStringTag]() {
- return "DedicatedWorkerGlobalScope";
- }
+ get [SymbolToStringTag]() {
+ return "DedicatedWorkerGlobalScope";
}
+}
+
+const dedicatedWorkerGlobalScopeConstructorDescriptor = {
+ configurable: true,
+ enumerable: false,
+ value: DedicatedWorkerGlobalScope,
+ writable: true,
+};
+
+const windowConstructorDescriptor = {
+ configurable: true,
+ enumerable: false,
+ value: Window,
+ writable: true,
+};
+
+const workerGlobalScopeConstructorDescriptor = {
+ configurable: true,
+ enumerable: false,
+ value: WorkerGlobalScope,
+ writable: true,
+};
- window.__bootstrap.globalInterfaces = {
- DedicatedWorkerGlobalScope,
- Window,
- WorkerGlobalScope,
- dedicatedWorkerGlobalScopeConstructorDescriptor: {
- configurable: true,
- enumerable: false,
- value: DedicatedWorkerGlobalScope,
- writable: true,
- },
- windowConstructorDescriptor: {
- configurable: true,
- enumerable: false,
- value: Window,
- writable: true,
- },
- workerGlobalScopeConstructorDescriptor: {
- configurable: true,
- enumerable: false,
- value: WorkerGlobalScope,
- writable: true,
- },
- };
-})(this);
+export {
+ DedicatedWorkerGlobalScope,
+ dedicatedWorkerGlobalScopeConstructorDescriptor,
+ Window,
+ windowConstructorDescriptor,
+ WorkerGlobalScope,
+ workerGlobalScopeConstructorDescriptor,
+};
diff --git a/ext/web/05_base64.js b/ext/web/05_base64.js
index dac366ca0..9f11ec97c 100644
--- a/ext/web/05_base64.js
+++ b/ext/web/05_base64.js
@@ -6,68 +6,62 @@
/// <reference path="../web/internal.d.ts" />
/// <reference lib="esnext" />
-"use strict";
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ObjectPrototypeIsPrototypeOf,
+ TypeErrorPrototype,
+} = primordials;
-((window) => {
- const core = Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const { DOMException } = window.__bootstrap.domException;
- const {
- ObjectPrototypeIsPrototypeOf,
- TypeErrorPrototype,
- } = window.__bootstrap.primordials;
-
- /**
- * @param {string} data
- * @returns {string}
- */
- function atob(data) {
- const prefix = "Failed to execute 'atob'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- data = webidl.converters.DOMString(data, {
- prefix,
- context: "Argument 1",
- });
- try {
- return ops.op_base64_atob(data);
- } catch (e) {
- if (ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e)) {
- throw new DOMException(
- "Failed to decode base64: invalid character",
- "InvalidCharacterError",
- );
- }
- throw e;
+/**
+ * @param {string} data
+ * @returns {string}
+ */
+function atob(data) {
+ const prefix = "Failed to execute 'atob'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ data = webidl.converters.DOMString(data, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
+ return ops.op_base64_atob(data);
+ } catch (e) {
+ if (ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e)) {
+ throw new DOMException(
+ "Failed to decode base64: invalid character",
+ "InvalidCharacterError",
+ );
}
+ throw e;
}
+}
- /**
- * @param {string} data
- * @returns {string}
- */
- function btoa(data) {
- const prefix = "Failed to execute 'btoa'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- data = webidl.converters.DOMString(data, {
- prefix,
- context: "Argument 1",
- });
- try {
- return ops.op_base64_btoa(data);
- } catch (e) {
- if (ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e)) {
- throw new DOMException(
- "The string to be encoded contains characters outside of the Latin1 range.",
- "InvalidCharacterError",
- );
- }
- throw e;
+/**
+ * @param {string} data
+ * @returns {string}
+ */
+function btoa(data) {
+ const prefix = "Failed to execute 'btoa'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ data = webidl.converters.DOMString(data, {
+ prefix,
+ context: "Argument 1",
+ });
+ try {
+ return ops.op_base64_btoa(data);
+ } catch (e) {
+ if (ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e)) {
+ throw new DOMException(
+ "The string to be encoded contains characters outside of the Latin1 range.",
+ "InvalidCharacterError",
+ );
}
+ throw e;
}
+}
- window.__bootstrap.base64 = {
- atob,
- btoa,
- };
-})(globalThis);
+export { atob, btoa };
diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js
index 1bad4f314..a88b60893 100644
--- a/ext/web/06_streams.js
+++ b/ext/web/06_streams.js
@@ -5,3092 +5,3199 @@
/// <reference path="./06_streams_types.d.ts" />
/// <reference path="./lib.deno_web.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const webidl = window.__bootstrap.webidl;
- const { add, remove, signalAbort, newSignal, AbortSignalPrototype } =
- window.__bootstrap.abortSignal;
- const {
- ArrayBuffer,
- ArrayBufferPrototype,
- ArrayBufferIsView,
- ArrayPrototypeMap,
- ArrayPrototypePush,
- ArrayPrototypeShift,
- AsyncGeneratorPrototype,
- BigInt64ArrayPrototype,
- BigUint64ArrayPrototype,
- DataView,
- FinalizationRegistry,
- Int8ArrayPrototype,
- Int16ArrayPrototype,
- Int32ArrayPrototype,
- NumberIsInteger,
- NumberIsNaN,
- MathMin,
- ObjectCreate,
- ObjectDefineProperties,
- ObjectDefineProperty,
- ObjectGetPrototypeOf,
- ObjectPrototype,
- ObjectPrototypeIsPrototypeOf,
- ObjectSetPrototypeOf,
- Promise,
- PromisePrototypeCatch,
- PromisePrototypeThen,
- PromiseReject,
- PromiseResolve,
- queueMicrotask,
- RangeError,
- ReflectHas,
- SafePromiseAll,
- // TODO(lucacasonato): add SharedArrayBuffer to primordials
- // SharedArrayBufferPrototype
- Symbol,
- SymbolAsyncIterator,
- SymbolFor,
- TypeError,
- TypedArrayPrototypeSet,
- Uint8Array,
- Uint8ArrayPrototype,
- Uint16ArrayPrototype,
- Uint32ArrayPrototype,
- Uint8ClampedArrayPrototype,
- WeakMap,
- WeakMapPrototypeGet,
- WeakMapPrototypeHas,
- WeakMapPrototypeSet,
- } = globalThis.__bootstrap.primordials;
- const consoleInternal = window.__bootstrap.console;
- const ops = core.ops;
- const { AssertionError, assert } = window.__bootstrap.infra;
-
- /** @template T */
- class Deferred {
- /** @type {Promise<T>} */
- #promise;
- /** @type {(reject?: any) => void} */
- #reject;
- /** @type {(value: T | PromiseLike<T>) => void} */
- #resolve;
- /** @type {"pending" | "fulfilled"} */
- #state = "pending";
-
- constructor() {
- this.#promise = new Promise((resolve, reject) => {
- this.#resolve = resolve;
- this.#reject = reject;
- });
- }
-
- /** @returns {Promise<T>} */
- get promise() {
- return this.#promise;
- }
-
- /** @returns {"pending" | "fulfilled"} */
- get state() {
- return this.#state;
- }
-
- /** @param {any=} reason */
- reject(reason) {
- // already settled promises are a no-op
- if (this.#state !== "pending") {
- return;
- }
- this.#state = "fulfilled";
- this.#reject(reason);
- }
-
- /** @param {T | PromiseLike<T>} value */
- resolve(value) {
- // already settled promises are a no-op
- if (this.#state !== "pending") {
- return;
- }
- this.#state = "fulfilled";
- this.#resolve(value);
- }
- }
-
- /**
- * @template T
- * @param {T | PromiseLike<T>} value
- * @returns {Promise<T>}
- */
- function resolvePromiseWith(value) {
- return new Promise((resolve) => resolve(value));
- }
-
- /** @param {any} e */
- function rethrowAssertionErrorRejection(e) {
- if (e && ObjectPrototypeIsPrototypeOf(AssertionError.prototype, e)) {
- queueMicrotask(() => {
- console.error(`Internal Error: ${e.stack}`);
- });
- }
- }
-
- /** @param {Promise<any>} promise */
- function setPromiseIsHandledToTrue(promise) {
- PromisePrototypeThen(promise, undefined, rethrowAssertionErrorRejection);
- }
-
- /**
- * @template T
- * @template TResult1
- * @template TResult2
- * @param {Promise<T>} promise
- * @param {(value: T) => TResult1 | PromiseLike<TResult1>} fulfillmentHandler
- * @param {(reason: any) => TResult2 | PromiseLike<TResult2>=} rejectionHandler
- * @returns {Promise<TResult1 | TResult2>}
- */
- function transformPromiseWith(promise, fulfillmentHandler, rejectionHandler) {
- return PromisePrototypeThen(promise, fulfillmentHandler, rejectionHandler);
- }
-
- /**
- * @template T
- * @template TResult
- * @param {Promise<T>} promise
- * @param {(value: T) => TResult | PromiseLike<TResult>} onFulfilled
- * @returns {void}
- */
- function uponFulfillment(promise, onFulfilled) {
- uponPromise(promise, onFulfilled);
- }
- /**
- * @template T
- * @template TResult
- * @param {Promise<T>} promise
- * @param {(value: T) => TResult | PromiseLike<TResult>} onRejected
- * @returns {void}
- */
- function uponRejection(promise, onRejected) {
- uponPromise(promise, undefined, onRejected);
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import {
+ AbortSignalPrototype,
+ add,
+ newSignal,
+ remove,
+ signalAbort,
+} from "internal:ext/web/03_abort_signal.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayBuffer,
+ ArrayBufferPrototype,
+ ArrayBufferIsView,
+ ArrayPrototypeMap,
+ ArrayPrototypePush,
+ ArrayPrototypeShift,
+ AsyncGeneratorPrototype,
+ BigInt64ArrayPrototype,
+ BigUint64ArrayPrototype,
+ DataView,
+ FinalizationRegistry,
+ Int8ArrayPrototype,
+ Int16ArrayPrototype,
+ Int32ArrayPrototype,
+ NumberIsInteger,
+ NumberIsNaN,
+ MathMin,
+ ObjectCreate,
+ ObjectDefineProperties,
+ ObjectDefineProperty,
+ ObjectGetPrototypeOf,
+ ObjectPrototype,
+ ObjectPrototypeIsPrototypeOf,
+ ObjectSetPrototypeOf,
+ Promise,
+ PromisePrototypeCatch,
+ PromisePrototypeThen,
+ PromiseReject,
+ PromiseResolve,
+ queueMicrotask,
+ RangeError,
+ ReflectHas,
+ SafePromiseAll,
+ // TODO(lucacasonato): add SharedArrayBuffer to primordials
+ // SharedArrayBufferPrototype
+ Symbol,
+ SymbolAsyncIterator,
+ SymbolFor,
+ TypeError,
+ TypedArrayPrototypeSet,
+ Uint8Array,
+ Uint8ArrayPrototype,
+ Uint16ArrayPrototype,
+ Uint32ArrayPrototype,
+ Uint8ClampedArrayPrototype,
+ WeakMap,
+ WeakMapPrototypeGet,
+ WeakMapPrototypeHas,
+ WeakMapPrototypeSet,
+} = primordials;
+import { createFilteredInspectProxy } from "internal:ext/console/02_console.js";
+import { assert, AssertionError } from "internal:ext/web/00_infra.js";
+
+/** @template T */
+class Deferred {
+ /** @type {Promise<T>} */
+ #promise;
+ /** @type {(reject?: any) => void} */
+ #reject;
+ /** @type {(value: T | PromiseLike<T>) => void} */
+ #resolve;
+ /** @type {"pending" | "fulfilled"} */
+ #state = "pending";
+
+ constructor() {
+ this.#promise = new Promise((resolve, reject) => {
+ this.#resolve = resolve;
+ this.#reject = reject;
+ });
}
- /**
- * @template T
- * @template TResult1
- * @template TResult2
- * @param {Promise<T>} promise
- * @param {(value: T) => TResult1 | PromiseLike<TResult1>} onFulfilled
- * @param {(reason: any) => TResult2 | PromiseLike<TResult2>=} onRejected
- * @returns {void}
- */
- function uponPromise(promise, onFulfilled, onRejected) {
- PromisePrototypeThen(
- PromisePrototypeThen(promise, onFulfilled, onRejected),
- undefined,
- rethrowAssertionErrorRejection,
- );
+ /** @returns {Promise<T>} */
+ get promise() {
+ return this.#promise;
}
- /**
- * @param {ArrayBufferLike} O
- * @returns {boolean}
- */
- function isDetachedBuffer(O) {
- return O.byteLength === 0 && ops.op_arraybuffer_was_detached(O);
+ /** @returns {"pending" | "fulfilled"} */
+ get state() {
+ return this.#state;
}
- /**
- * @param {ArrayBufferLike} O
- * @returns {boolean}
- */
- function canTransferArrayBuffer(O) {
- assert(typeof O === "object");
- assert(
- ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, O) ||
- // deno-lint-ignore prefer-primordials
- ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, O),
- );
- if (isDetachedBuffer(O)) {
- return false;
+ /** @param {any=} reason */
+ reject(reason) {
+ // already settled promises are a no-op
+ if (this.#state !== "pending") {
+ return;
}
- // TODO(@crowlKats): 4. If SameValue(O.[[ArrayBufferDetachKey]], undefined) is false, return false.
- return true;
- }
-
- /**
- * @param {ArrayBufferLike} O
- * @returns {ArrayBufferLike}
- */
- function transferArrayBuffer(O) {
- return ops.op_transfer_arraybuffer(O);
- }
-
- /**
- * @param {ArrayBufferView} O
- * @returns {Uint8Array}
- */
- function cloneAsUint8Array(O) {
- assert(typeof O === "object");
- assert(ArrayBufferIsView(O));
- assert(!isDetachedBuffer(O.buffer));
- const buffer = O.buffer.slice(O.byteOffset, O.byteOffset + O.byteLength);
- return new Uint8Array(buffer);
- }
-
- const _abortAlgorithm = Symbol("[[abortAlgorithm]]");
- const _abortSteps = Symbol("[[AbortSteps]]");
- const _autoAllocateChunkSize = Symbol("[[autoAllocateChunkSize]]");
- const _backpressure = Symbol("[[backpressure]]");
- const _backpressureChangePromise = Symbol("[[backpressureChangePromise]]");
- const _byobRequest = Symbol("[[byobRequest]]");
- const _cancelAlgorithm = Symbol("[[cancelAlgorithm]]");
- const _cancelSteps = Symbol("[[CancelSteps]]");
- const _close = Symbol("close sentinel");
- const _closeAlgorithm = Symbol("[[closeAlgorithm]]");
- const _closedPromise = Symbol("[[closedPromise]]");
- const _closeRequest = Symbol("[[closeRequest]]");
- const _closeRequested = Symbol("[[closeRequested]]");
- const _controller = Symbol("[[controller]]");
- const _detached = Symbol("[[Detached]]");
- const _disturbed = Symbol("[[disturbed]]");
- const _errorSteps = Symbol("[[ErrorSteps]]");
- const _flushAlgorithm = Symbol("[[flushAlgorithm]]");
- const _globalObject = Symbol("[[globalObject]]");
- const _highWaterMark = Symbol("[[highWaterMark]]");
- const _inFlightCloseRequest = Symbol("[[inFlightCloseRequest]]");
- const _inFlightWriteRequest = Symbol("[[inFlightWriteRequest]]");
- const _pendingAbortRequest = Symbol("[pendingAbortRequest]");
- const _pendingPullIntos = Symbol("[[pendingPullIntos]]");
- const _preventCancel = Symbol("[[preventCancel]]");
- const _pullAgain = Symbol("[[pullAgain]]");
- const _pullAlgorithm = Symbol("[[pullAlgorithm]]");
- const _pulling = Symbol("[[pulling]]");
- const _pullSteps = Symbol("[[PullSteps]]");
- const _releaseSteps = Symbol("[[ReleaseSteps]]");
- const _queue = Symbol("[[queue]]");
- const _queueTotalSize = Symbol("[[queueTotalSize]]");
- const _readable = Symbol("[[readable]]");
- const _reader = Symbol("[[reader]]");
- const _readRequests = Symbol("[[readRequests]]");
- const _readIntoRequests = Symbol("[[readIntoRequests]]");
- const _readyPromise = Symbol("[[readyPromise]]");
- const _signal = Symbol("[[signal]]");
- const _started = Symbol("[[started]]");
- const _state = Symbol("[[state]]");
- const _storedError = Symbol("[[storedError]]");
- const _strategyHWM = Symbol("[[strategyHWM]]");
- const _strategySizeAlgorithm = Symbol("[[strategySizeAlgorithm]]");
- const _stream = Symbol("[[stream]]");
- const _transformAlgorithm = Symbol("[[transformAlgorithm]]");
- const _view = Symbol("[[view]]");
- const _writable = Symbol("[[writable]]");
- const _writeAlgorithm = Symbol("[[writeAlgorithm]]");
- const _writer = Symbol("[[writer]]");
- const _writeRequests = Symbol("[[writeRequests]]");
-
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @returns {ReadableStreamDefaultReader<R>}
- */
- function acquireReadableStreamDefaultReader(stream) {
- return new ReadableStreamDefaultReader(stream);
+ this.#state = "fulfilled";
+ this.#reject(reason);
}
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @returns {ReadableStreamBYOBReader<R>}
- */
- function acquireReadableStreamBYOBReader(stream) {
- const reader = webidl.createBranded(ReadableStreamBYOBReader);
- setUpReadableStreamBYOBReader(reader, stream);
- return reader;
+ /** @param {T | PromiseLike<T>} value */
+ resolve(value) {
+ // already settled promises are a no-op
+ if (this.#state !== "pending") {
+ return;
+ }
+ this.#state = "fulfilled";
+ this.#resolve(value);
+ }
+}
+
+/**
+ * @template T
+ * @param {T | PromiseLike<T>} value
+ * @returns {Promise<T>}
+ */
+function resolvePromiseWith(value) {
+ return new Promise((resolve) => resolve(value));
+}
+
+/** @param {any} e */
+function rethrowAssertionErrorRejection(e) {
+ if (e && ObjectPrototypeIsPrototypeOf(AssertionError.prototype, e)) {
+ queueMicrotask(() => {
+ console.error(`Internal Error: ${e.stack}`);
+ });
}
-
- /**
- * @template W
- * @param {WritableStream<W>} stream
- * @returns {WritableStreamDefaultWriter<W>}
- */
- function acquireWritableStreamDefaultWriter(stream) {
- return new WritableStreamDefaultWriter(stream);
+}
+
+/** @param {Promise<any>} promise */
+function setPromiseIsHandledToTrue(promise) {
+ PromisePrototypeThen(promise, undefined, rethrowAssertionErrorRejection);
+}
+
+/**
+ * @template T
+ * @template TResult1
+ * @template TResult2
+ * @param {Promise<T>} promise
+ * @param {(value: T) => TResult1 | PromiseLike<TResult1>} fulfillmentHandler
+ * @param {(reason: any) => TResult2 | PromiseLike<TResult2>=} rejectionHandler
+ * @returns {Promise<TResult1 | TResult2>}
+ */
+function transformPromiseWith(promise, fulfillmentHandler, rejectionHandler) {
+ return PromisePrototypeThen(promise, fulfillmentHandler, rejectionHandler);
+}
+
+/**
+ * @template T
+ * @template TResult
+ * @param {Promise<T>} promise
+ * @param {(value: T) => TResult | PromiseLike<TResult>} onFulfilled
+ * @returns {void}
+ */
+function uponFulfillment(promise, onFulfilled) {
+ uponPromise(promise, onFulfilled);
+}
+
+/**
+ * @template T
+ * @template TResult
+ * @param {Promise<T>} promise
+ * @param {(value: T) => TResult | PromiseLike<TResult>} onRejected
+ * @returns {void}
+ */
+function uponRejection(promise, onRejected) {
+ uponPromise(promise, undefined, onRejected);
+}
+
+/**
+ * @template T
+ * @template TResult1
+ * @template TResult2
+ * @param {Promise<T>} promise
+ * @param {(value: T) => TResult1 | PromiseLike<TResult1>} onFulfilled
+ * @param {(reason: any) => TResult2 | PromiseLike<TResult2>=} onRejected
+ * @returns {void}
+ */
+function uponPromise(promise, onFulfilled, onRejected) {
+ PromisePrototypeThen(
+ PromisePrototypeThen(promise, onFulfilled, onRejected),
+ undefined,
+ rethrowAssertionErrorRejection,
+ );
+}
+
+/**
+ * @param {ArrayBufferLike} O
+ * @returns {boolean}
+ */
+function isDetachedBuffer(O) {
+ return O.byteLength === 0 && ops.op_arraybuffer_was_detached(O);
+}
+
+/**
+ * @param {ArrayBufferLike} O
+ * @returns {boolean}
+ */
+function canTransferArrayBuffer(O) {
+ assert(typeof O === "object");
+ assert(
+ ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, O) ||
+ // deno-lint-ignore prefer-primordials
+ ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, O),
+ );
+ if (isDetachedBuffer(O)) {
+ return false;
}
-
- /**
- * @template R
- * @param {() => void} startAlgorithm
- * @param {() => Promise<void>} pullAlgorithm
- * @param {(reason: any) => Promise<void>} cancelAlgorithm
- * @param {number=} highWaterMark
- * @param {((chunk: R) => number)=} sizeAlgorithm
- * @returns {ReadableStream<R>}
- */
- function createReadableStream(
+ // TODO(@crowlKats): 4. If SameValue(O.[[ArrayBufferDetachKey]], undefined) is false, return false.
+ return true;
+}
+
+/**
+ * @param {ArrayBufferLike} O
+ * @returns {ArrayBufferLike}
+ */
+function transferArrayBuffer(O) {
+ return ops.op_transfer_arraybuffer(O);
+}
+
+/**
+ * @param {ArrayBufferView} O
+ * @returns {Uint8Array}
+ */
+function cloneAsUint8Array(O) {
+ assert(typeof O === "object");
+ assert(ArrayBufferIsView(O));
+ assert(!isDetachedBuffer(O.buffer));
+ const buffer = O.buffer.slice(O.byteOffset, O.byteOffset + O.byteLength);
+ return new Uint8Array(buffer);
+}
+
+const _abortAlgorithm = Symbol("[[abortAlgorithm]]");
+const _abortSteps = Symbol("[[AbortSteps]]");
+const _autoAllocateChunkSize = Symbol("[[autoAllocateChunkSize]]");
+const _backpressure = Symbol("[[backpressure]]");
+const _backpressureChangePromise = Symbol("[[backpressureChangePromise]]");
+const _byobRequest = Symbol("[[byobRequest]]");
+const _cancelAlgorithm = Symbol("[[cancelAlgorithm]]");
+const _cancelSteps = Symbol("[[CancelSteps]]");
+const _close = Symbol("close sentinel");
+const _closeAlgorithm = Symbol("[[closeAlgorithm]]");
+const _closedPromise = Symbol("[[closedPromise]]");
+const _closeRequest = Symbol("[[closeRequest]]");
+const _closeRequested = Symbol("[[closeRequested]]");
+const _controller = Symbol("[[controller]]");
+const _detached = Symbol("[[Detached]]");
+const _disturbed = Symbol("[[disturbed]]");
+const _errorSteps = Symbol("[[ErrorSteps]]");
+const _flushAlgorithm = Symbol("[[flushAlgorithm]]");
+const _globalObject = Symbol("[[globalObject]]");
+const _highWaterMark = Symbol("[[highWaterMark]]");
+const _inFlightCloseRequest = Symbol("[[inFlightCloseRequest]]");
+const _inFlightWriteRequest = Symbol("[[inFlightWriteRequest]]");
+const _pendingAbortRequest = Symbol("[pendingAbortRequest]");
+const _pendingPullIntos = Symbol("[[pendingPullIntos]]");
+const _preventCancel = Symbol("[[preventCancel]]");
+const _pullAgain = Symbol("[[pullAgain]]");
+const _pullAlgorithm = Symbol("[[pullAlgorithm]]");
+const _pulling = Symbol("[[pulling]]");
+const _pullSteps = Symbol("[[PullSteps]]");
+const _releaseSteps = Symbol("[[ReleaseSteps]]");
+const _queue = Symbol("[[queue]]");
+const _queueTotalSize = Symbol("[[queueTotalSize]]");
+const _readable = Symbol("[[readable]]");
+const _reader = Symbol("[[reader]]");
+const _readRequests = Symbol("[[readRequests]]");
+const _readIntoRequests = Symbol("[[readIntoRequests]]");
+const _readyPromise = Symbol("[[readyPromise]]");
+const _signal = Symbol("[[signal]]");
+const _started = Symbol("[[started]]");
+const _state = Symbol("[[state]]");
+const _storedError = Symbol("[[storedError]]");
+const _strategyHWM = Symbol("[[strategyHWM]]");
+const _strategySizeAlgorithm = Symbol("[[strategySizeAlgorithm]]");
+const _stream = Symbol("[[stream]]");
+const _transformAlgorithm = Symbol("[[transformAlgorithm]]");
+const _view = Symbol("[[view]]");
+const _writable = Symbol("[[writable]]");
+const _writeAlgorithm = Symbol("[[writeAlgorithm]]");
+const _writer = Symbol("[[writer]]");
+const _writeRequests = Symbol("[[writeRequests]]");
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @returns {ReadableStreamDefaultReader<R>}
+ */
+function acquireReadableStreamDefaultReader(stream) {
+ return new ReadableStreamDefaultReader(stream);
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @returns {ReadableStreamBYOBReader<R>}
+ */
+function acquireReadableStreamBYOBReader(stream) {
+ const reader = webidl.createBranded(ReadableStreamBYOBReader);
+ setUpReadableStreamBYOBReader(reader, stream);
+ return reader;
+}
+
+/**
+ * @template W
+ * @param {WritableStream<W>} stream
+ * @returns {WritableStreamDefaultWriter<W>}
+ */
+function acquireWritableStreamDefaultWriter(stream) {
+ return new WritableStreamDefaultWriter(stream);
+}
+
+/**
+ * @template R
+ * @param {() => void} startAlgorithm
+ * @param {() => Promise<void>} pullAlgorithm
+ * @param {(reason: any) => Promise<void>} cancelAlgorithm
+ * @param {number=} highWaterMark
+ * @param {((chunk: R) => number)=} sizeAlgorithm
+ * @returns {ReadableStream<R>}
+ */
+function createReadableStream(
+ startAlgorithm,
+ pullAlgorithm,
+ cancelAlgorithm,
+ highWaterMark = 1,
+ sizeAlgorithm = () => 1,
+) {
+ assert(isNonNegativeNumber(highWaterMark));
+ /** @type {ReadableStream} */
+ const stream = webidl.createBranded(ReadableStream);
+ initializeReadableStream(stream);
+ const controller = webidl.createBranded(ReadableStreamDefaultController);
+ setUpReadableStreamDefaultController(
+ stream,
+ controller,
startAlgorithm,
pullAlgorithm,
cancelAlgorithm,
- highWaterMark = 1,
- sizeAlgorithm = () => 1,
- ) {
- assert(isNonNegativeNumber(highWaterMark));
- /** @type {ReadableStream} */
- const stream = webidl.createBranded(ReadableStream);
- initializeReadableStream(stream);
- const controller = webidl.createBranded(ReadableStreamDefaultController);
- setUpReadableStreamDefaultController(
- stream,
- controller,
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- highWaterMark,
- sizeAlgorithm,
- );
- return stream;
- }
-
- /**
- * @template W
- * @param {(controller: WritableStreamDefaultController<W>) => Promise<void>} startAlgorithm
- * @param {(chunk: W) => Promise<void>} writeAlgorithm
- * @param {() => Promise<void>} closeAlgorithm
- * @param {(reason: any) => Promise<void>} abortAlgorithm
- * @param {number} highWaterMark
- * @param {(chunk: W) => number} sizeAlgorithm
- * @returns {WritableStream<W>}
- */
- function createWritableStream(
+ highWaterMark,
+ sizeAlgorithm,
+ );
+ return stream;
+}
+
+/**
+ * @template W
+ * @param {(controller: WritableStreamDefaultController<W>) => Promise<void>} startAlgorithm
+ * @param {(chunk: W) => Promise<void>} writeAlgorithm
+ * @param {() => Promise<void>} closeAlgorithm
+ * @param {(reason: any) => Promise<void>} abortAlgorithm
+ * @param {number} highWaterMark
+ * @param {(chunk: W) => number} sizeAlgorithm
+ * @returns {WritableStream<W>}
+ */
+function createWritableStream(
+ startAlgorithm,
+ writeAlgorithm,
+ closeAlgorithm,
+ abortAlgorithm,
+ highWaterMark,
+ sizeAlgorithm,
+) {
+ assert(isNonNegativeNumber(highWaterMark));
+ const stream = webidl.createBranded(WritableStream);
+ initializeWritableStream(stream);
+ const controller = webidl.createBranded(WritableStreamDefaultController);
+ setUpWritableStreamDefaultController(
+ stream,
+ controller,
startAlgorithm,
writeAlgorithm,
closeAlgorithm,
abortAlgorithm,
highWaterMark,
sizeAlgorithm,
- ) {
- assert(isNonNegativeNumber(highWaterMark));
- const stream = webidl.createBranded(WritableStream);
- initializeWritableStream(stream);
- const controller = webidl.createBranded(WritableStreamDefaultController);
- setUpWritableStreamDefaultController(
- stream,
- controller,
- startAlgorithm,
- writeAlgorithm,
- closeAlgorithm,
- abortAlgorithm,
- highWaterMark,
- sizeAlgorithm,
- );
- return stream;
+ );
+ return stream;
+}
+
+/**
+ * @template T
+ * @param {{ [_queue]: Array<ValueWithSize<T>>, [_queueTotalSize]: number }} container
+ * @returns {T}
+ */
+function dequeueValue(container) {
+ assert(
+ ReflectHas(container, _queue) &&
+ ReflectHas(container, _queueTotalSize),
+ );
+ assert(container[_queue].length);
+ const valueWithSize = ArrayPrototypeShift(container[_queue]);
+ container[_queueTotalSize] -= valueWithSize.size;
+ if (container[_queueTotalSize] < 0) {
+ container[_queueTotalSize] = 0;
}
-
- /**
- * @template T
- * @param {{ [_queue]: Array<ValueWithSize<T>>, [_queueTotalSize]: number }} container
- * @returns {T}
- */
- function dequeueValue(container) {
- assert(
- ReflectHas(container, _queue) &&
- ReflectHas(container, _queueTotalSize),
+ return valueWithSize.value;
+}
+
+/**
+ * @template T
+ * @param {{ [_queue]: Array<ValueWithSize<T | _close>>, [_queueTotalSize]: number }} container
+ * @param {T} value
+ * @param {number} size
+ * @returns {void}
+ */
+function enqueueValueWithSize(container, value, size) {
+ assert(
+ ReflectHas(container, _queue) &&
+ ReflectHas(container, _queueTotalSize),
+ );
+ if (isNonNegativeNumber(size) === false) {
+ throw RangeError("chunk size isn't a positive number");
+ }
+ if (size === Infinity) {
+ throw RangeError("chunk size is invalid");
+ }
+ ArrayPrototypePush(container[_queue], { value, size });
+ container[_queueTotalSize] += size;
+}
+
+/**
+ * @param {QueuingStrategy} strategy
+ * @param {number} defaultHWM
+ */
+function extractHighWaterMark(strategy, defaultHWM) {
+ if (strategy.highWaterMark === undefined) {
+ return defaultHWM;
+ }
+ const highWaterMark = strategy.highWaterMark;
+ if (NumberIsNaN(highWaterMark) || highWaterMark < 0) {
+ throw RangeError(
+ `Expected highWaterMark to be a positive number or Infinity, got "${highWaterMark}".`,
);
- assert(container[_queue].length);
- const valueWithSize = ArrayPrototypeShift(container[_queue]);
- container[_queueTotalSize] -= valueWithSize.size;
- if (container[_queueTotalSize] < 0) {
- container[_queueTotalSize] = 0;
- }
- return valueWithSize.value;
}
-
- /**
- * @template T
- * @param {{ [_queue]: Array<ValueWithSize<T | _close>>, [_queueTotalSize]: number }} container
- * @param {T} value
- * @param {number} size
- * @returns {void}
- */
- function enqueueValueWithSize(container, value, size) {
- assert(
- ReflectHas(container, _queue) &&
- ReflectHas(container, _queueTotalSize),
+ return highWaterMark;
+}
+
+/**
+ * @template T
+ * @param {QueuingStrategy<T>} strategy
+ * @return {(chunk: T) => number}
+ */
+function extractSizeAlgorithm(strategy) {
+ if (strategy.size === undefined) {
+ return () => 1;
+ }
+ return (chunk) =>
+ webidl.invokeCallbackFunction(
+ strategy.size,
+ [chunk],
+ undefined,
+ webidl.converters["unrestricted double"],
+ { prefix: "Failed to call `sizeAlgorithm`" },
);
- if (isNonNegativeNumber(size) === false) {
- throw RangeError("chunk size isn't a positive number");
- }
- if (size === Infinity) {
- throw RangeError("chunk size is invalid");
- }
- ArrayPrototypePush(container[_queue], { value, size });
- container[_queueTotalSize] += size;
- }
-
- /**
- * @param {QueuingStrategy} strategy
- * @param {number} defaultHWM
- */
- function extractHighWaterMark(strategy, defaultHWM) {
- if (strategy.highWaterMark === undefined) {
- return defaultHWM;
- }
- const highWaterMark = strategy.highWaterMark;
- if (NumberIsNaN(highWaterMark) || highWaterMark < 0) {
- throw RangeError(
- `Expected highWaterMark to be a positive number or Infinity, got "${highWaterMark}".`,
- );
- }
- return highWaterMark;
- }
-
- /**
- * @template T
- * @param {QueuingStrategy<T>} strategy
- * @return {(chunk: T) => number}
- */
- function extractSizeAlgorithm(strategy) {
- if (strategy.size === undefined) {
- return () => 1;
- }
- return (chunk) =>
- webidl.invokeCallbackFunction(
- strategy.size,
- [chunk],
- undefined,
- webidl.converters["unrestricted double"],
- { prefix: "Failed to call `sizeAlgorithm`" },
- );
- }
-
- /**
- * @param {() => void} startAlgorithm
- * @param {() => Promise<void>} pullAlgorithm
- * @param {(reason: any) => Promise<void>} cancelAlgorithm
- * @returns {ReadableStream}
- */
- function createReadableByteStream(
+}
+
+/**
+ * @param {() => void} startAlgorithm
+ * @param {() => Promise<void>} pullAlgorithm
+ * @param {(reason: any) => Promise<void>} cancelAlgorithm
+ * @returns {ReadableStream}
+ */
+function createReadableByteStream(
+ startAlgorithm,
+ pullAlgorithm,
+ cancelAlgorithm,
+) {
+ const stream = webidl.createBranded(ReadableStream);
+ initializeReadableStream(stream);
+ const controller = webidl.createBranded(ReadableByteStreamController);
+ setUpReadableByteStreamController(
+ stream,
+ controller,
startAlgorithm,
pullAlgorithm,
cancelAlgorithm,
- ) {
- const stream = webidl.createBranded(ReadableStream);
- initializeReadableStream(stream);
- const controller = webidl.createBranded(ReadableByteStreamController);
- setUpReadableByteStreamController(
- stream,
- controller,
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- 0,
- undefined,
- );
- return stream;
- }
-
- /**
- * @param {ReadableStream} stream
- * @returns {void}
- */
- function initializeReadableStream(stream) {
- stream[_state] = "readable";
- stream[_reader] = stream[_storedError] = undefined;
- stream[_disturbed] = false;
- }
-
- /**
- * @template I
- * @template O
- * @param {TransformStream<I, O>} stream
- * @param {Deferred<void>} startPromise
- * @param {number} writableHighWaterMark
- * @param {(chunk: I) => number} writableSizeAlgorithm
- * @param {number} readableHighWaterMark
- * @param {(chunk: O) => number} readableSizeAlgorithm
- */
- function initializeTransformStream(
- stream,
- startPromise,
+ 0,
+ undefined,
+ );
+ return stream;
+}
+
+/**
+ * @param {ReadableStream} stream
+ * @returns {void}
+ */
+function initializeReadableStream(stream) {
+ stream[_state] = "readable";
+ stream[_reader] = stream[_storedError] = undefined;
+ stream[_disturbed] = false;
+}
+
+/**
+ * @template I
+ * @template O
+ * @param {TransformStream<I, O>} stream
+ * @param {Deferred<void>} startPromise
+ * @param {number} writableHighWaterMark
+ * @param {(chunk: I) => number} writableSizeAlgorithm
+ * @param {number} readableHighWaterMark
+ * @param {(chunk: O) => number} readableSizeAlgorithm
+ */
+function initializeTransformStream(
+ stream,
+ startPromise,
+ writableHighWaterMark,
+ writableSizeAlgorithm,
+ readableHighWaterMark,
+ readableSizeAlgorithm,
+) {
+ function startAlgorithm() {
+ return startPromise.promise;
+ }
+
+ function writeAlgorithm(chunk) {
+ return transformStreamDefaultSinkWriteAlgorithm(stream, chunk);
+ }
+
+ function abortAlgorithm(reason) {
+ return transformStreamDefaultSinkAbortAlgorithm(stream, reason);
+ }
+
+ function closeAlgorithm() {
+ return transformStreamDefaultSinkCloseAlgorithm(stream);
+ }
+
+ stream[_writable] = createWritableStream(
+ startAlgorithm,
+ writeAlgorithm,
+ closeAlgorithm,
+ abortAlgorithm,
writableHighWaterMark,
writableSizeAlgorithm,
- readableHighWaterMark,
- readableSizeAlgorithm,
- ) {
- function startAlgorithm() {
- return startPromise.promise;
- }
-
- function writeAlgorithm(chunk) {
- return transformStreamDefaultSinkWriteAlgorithm(stream, chunk);
- }
-
- function abortAlgorithm(reason) {
- return transformStreamDefaultSinkAbortAlgorithm(stream, reason);
- }
-
- function closeAlgorithm() {
- return transformStreamDefaultSinkCloseAlgorithm(stream);
- }
-
- stream[_writable] = createWritableStream(
- startAlgorithm,
- writeAlgorithm,
- closeAlgorithm,
- abortAlgorithm,
- writableHighWaterMark,
- writableSizeAlgorithm,
- );
-
- function pullAlgorithm() {
- return transformStreamDefaultSourcePullAlgorithm(stream);
- }
-
- function cancelAlgorithm(reason) {
- transformStreamErrorWritableAndUnblockWrite(stream, reason);
- return resolvePromiseWith(undefined);
- }
-
- stream[_readable] = createReadableStream(
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- readableHighWaterMark,
- readableSizeAlgorithm,
- );
-
- stream[_backpressure] = stream[_backpressureChangePromise] = undefined;
- transformStreamSetBackpressure(stream, true);
- stream[_controller] = undefined;
- }
+ );
- /** @param {WritableStream} stream */
- function initializeWritableStream(stream) {
- stream[_state] = "writable";
- stream[_storedError] =
- stream[_writer] =
- stream[_controller] =
- stream[_inFlightWriteRequest] =
- stream[_closeRequest] =
- stream[_inFlightCloseRequest] =
- stream[_pendingAbortRequest] =
- undefined;
- stream[_writeRequests] = [];
- stream[_backpressure] = false;
+ function pullAlgorithm() {
+ return transformStreamDefaultSourcePullAlgorithm(stream);
}
- /**
- * @param {unknown} v
- * @returns {v is number}
- */
- function isNonNegativeNumber(v) {
- if (typeof v !== "number") {
- return false;
- }
- if (NumberIsNaN(v)) {
- return false;
- }
- if (v < 0) {
- return false;
- }
- return true;
+ function cancelAlgorithm(reason) {
+ transformStreamErrorWritableAndUnblockWrite(stream, reason);
+ return resolvePromiseWith(undefined);
}
- /**
- * @param {unknown} value
- * @returns {value is ReadableStream}
- */
- function isReadableStream(value) {
- return !(typeof value !== "object" || value === null ||
- !ReflectHas(value, _controller));
- }
+ stream[_readable] = createReadableStream(
+ startAlgorithm,
+ pullAlgorithm,
+ cancelAlgorithm,
+ readableHighWaterMark,
+ readableSizeAlgorithm,
+ );
- /**
- * @param {ReadableStream} stream
- * @returns {boolean}
- */
- function isReadableStreamLocked(stream) {
- if (stream[_reader] === undefined) {
- return false;
- }
- return true;
+ stream[_backpressure] = stream[_backpressureChangePromise] = undefined;
+ transformStreamSetBackpressure(stream, true);
+ stream[_controller] = undefined;
+}
+
+/** @param {WritableStream} stream */
+function initializeWritableStream(stream) {
+ stream[_state] = "writable";
+ stream[_storedError] =
+ stream[_writer] =
+ stream[_controller] =
+ stream[_inFlightWriteRequest] =
+ stream[_closeRequest] =
+ stream[_inFlightCloseRequest] =
+ stream[_pendingAbortRequest] =
+ undefined;
+ stream[_writeRequests] = [];
+ stream[_backpressure] = false;
+}
+
+/**
+ * @param {unknown} v
+ * @returns {v is number}
+ */
+function isNonNegativeNumber(v) {
+ if (typeof v !== "number") {
+ return false;
}
-
- /**
- * @param {unknown} value
- * @returns {value is ReadableStreamDefaultReader}
- */
- function isReadableStreamDefaultReader(value) {
- return !(typeof value !== "object" || value === null ||
- !ReflectHas(value, _readRequests));
+ if (NumberIsNaN(v)) {
+ return false;
}
-
- /**
- * @param {unknown} value
- * @returns {value is ReadableStreamBYOBReader}
- */
- function isReadableStreamBYOBReader(value) {
- return !(typeof value !== "object" || value === null ||
- !ReflectHas(value, _readIntoRequests));
+ if (v < 0) {
+ return false;
}
-
- /**
- * @param {ReadableStream} stream
- * @returns {boolean}
- */
- function isReadableStreamDisturbed(stream) {
- assert(isReadableStream(stream));
- return stream[_disturbed];
+ return true;
+}
+
+/**
+ * @param {unknown} value
+ * @returns {value is ReadableStream}
+ */
+function isReadableStream(value) {
+ return !(typeof value !== "object" || value === null ||
+ !ReflectHas(value, _controller));
+}
+
+/**
+ * @param {ReadableStream} stream
+ * @returns {boolean}
+ */
+function isReadableStreamLocked(stream) {
+ if (stream[_reader] === undefined) {
+ return false;
}
-
- const DEFAULT_CHUNK_SIZE = 64 * 1024; // 64 KiB
-
- // A finalization registry to clean up underlying resources that are GC'ed.
- const RESOURCE_REGISTRY = new FinalizationRegistry((rid) => {
+ return true;
+}
+
+/**
+ * @param {unknown} value
+ * @returns {value is ReadableStreamDefaultReader}
+ */
+function isReadableStreamDefaultReader(value) {
+ return !(typeof value !== "object" || value === null ||
+ !ReflectHas(value, _readRequests));
+}
+
+/**
+ * @param {unknown} value
+ * @returns {value is ReadableStreamBYOBReader}
+ */
+function isReadableStreamBYOBReader(value) {
+ return !(typeof value !== "object" || value === null ||
+ !ReflectHas(value, _readIntoRequests));
+}
+
+/**
+ * @param {ReadableStream} stream
+ * @returns {boolean}
+ */
+function isReadableStreamDisturbed(stream) {
+ assert(isReadableStream(stream));
+ return stream[_disturbed];
+}
+
+const DEFAULT_CHUNK_SIZE = 64 * 1024; // 64 KiB
+
+// A finalization registry to clean up underlying resources that are GC'ed.
+const RESOURCE_REGISTRY = new FinalizationRegistry((rid) => {
+ core.tryClose(rid);
+});
+
+const _readAll = Symbol("[[readAll]]");
+const _original = Symbol("[[original]]");
+/**
+ * Create a new ReadableStream object that is backed by a Resource that
+ * implements `Resource::read_return`. This object contains enough metadata to
+ * allow callers to bypass the JavaScript ReadableStream implementation and
+ * read directly from the underlying resource if they so choose (FastStream).
+ *
+ * @param {number} rid The resource ID to read from.
+ * @param {boolean=} autoClose If the resource should be auto-closed when the stream closes. Defaults to true.
+ * @returns {ReadableStream<Uint8Array>}
+ */
+function readableStreamForRid(rid, autoClose = true) {
+ const stream = webidl.createBranded(ReadableStream);
+ stream[_resourceBacking] = { rid, autoClose };
+
+ const tryClose = () => {
+ if (!autoClose) return;
+ RESOURCE_REGISTRY.unregister(stream);
core.tryClose(rid);
- });
-
- const _readAll = Symbol("[[readAll]]");
- const _original = Symbol("[[original]]");
- /**
- * Create a new ReadableStream object that is backed by a Resource that
- * implements `Resource::read_return`. This object contains enough metadata to
- * allow callers to bypass the JavaScript ReadableStream implementation and
- * read directly from the underlying resource if they so choose (FastStream).
- *
- * @param {number} rid The resource ID to read from.
- * @param {boolean=} autoClose If the resource should be auto-closed when the stream closes. Defaults to true.
- * @returns {ReadableStream<Uint8Array>}
- */
- function readableStreamForRid(rid, autoClose = true) {
- const stream = webidl.createBranded(ReadableStream);
- stream[_resourceBacking] = { rid, autoClose };
-
- const tryClose = () => {
- if (!autoClose) return;
- RESOURCE_REGISTRY.unregister(stream);
- core.tryClose(rid);
- };
+ };
- if (autoClose) {
- RESOURCE_REGISTRY.register(stream, rid, stream);
- }
+ if (autoClose) {
+ RESOURCE_REGISTRY.register(stream, rid, stream);
+ }
- const underlyingSource = {
- type: "bytes",
- async pull(controller) {
- const v = controller.byobRequest.view;
- try {
- if (controller[_readAll] === true) {
- // fast path for tee'd streams consuming body
- const chunk = await core.readAll(rid);
- if (chunk.byteLength > 0) {
- controller.enqueue(chunk);
- }
- controller.close();
- tryClose();
- return;
+ const underlyingSource = {
+ type: "bytes",
+ async pull(controller) {
+ const v = controller.byobRequest.view;
+ try {
+ if (controller[_readAll] === true) {
+ // fast path for tee'd streams consuming body
+ const chunk = await core.readAll(rid);
+ if (chunk.byteLength > 0) {
+ controller.enqueue(chunk);
}
+ controller.close();
+ tryClose();
+ return;
+ }
- const bytesRead = await core.read(rid, v);
- if (bytesRead === 0) {
- tryClose();
- controller.close();
- controller.byobRequest.respond(0);
- } else {
- controller.byobRequest.respond(bytesRead);
- }
- } catch (e) {
- controller.error(e);
+ const bytesRead = await core.read(rid, v);
+ if (bytesRead === 0) {
tryClose();
+ controller.close();
+ controller.byobRequest.respond(0);
+ } else {
+ controller.byobRequest.respond(bytesRead);
}
- },
- cancel() {
+ } catch (e) {
+ controller.error(e);
tryClose();
- },
- autoAllocateChunkSize: DEFAULT_CHUNK_SIZE,
- };
- initializeReadableStream(stream);
- setUpReadableByteStreamControllerFromUnderlyingSource(
- stream,
- underlyingSource,
- underlyingSource,
- 0,
- );
- return stream;
- }
-
- const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId");
- const _isUnref = Symbol("isUnref");
- /**
- * Create a new ReadableStream object that is backed by a Resource that
- * implements `Resource::read_return`. This readable stream supports being
- * refed and unrefed by calling `readableStreamForRidUnrefableRef` and
- * `readableStreamForRidUnrefableUnref` on it. Unrefable streams are not
- * FastStream compatible.
- *
- * @param {number} rid The resource ID to read from.
- * @returns {ReadableStream<Uint8Array>}
- */
- function readableStreamForRidUnrefable(rid) {
- const stream = webidl.createBranded(ReadableStream);
- stream[promiseIdSymbol] = undefined;
- stream[_isUnref] = false;
- stream[_resourceBackingUnrefable] = { rid, autoClose: true };
- const underlyingSource = {
- type: "bytes",
- async pull(controller) {
- const v = controller.byobRequest.view;
- try {
- const promise = core.read(rid, v);
- const promiseId = stream[promiseIdSymbol] = promise[promiseIdSymbol];
- if (stream[_isUnref]) core.unrefOp(promiseId);
- const bytesRead = await promise;
- stream[promiseIdSymbol] = undefined;
- if (bytesRead === 0) {
- core.tryClose(rid);
- controller.close();
- controller.byobRequest.respond(0);
- } else {
- controller.byobRequest.respond(bytesRead);
- }
- } catch (e) {
- controller.error(e);
+ }
+ },
+ cancel() {
+ tryClose();
+ },
+ autoAllocateChunkSize: DEFAULT_CHUNK_SIZE,
+ };
+ initializeReadableStream(stream);
+ setUpReadableByteStreamControllerFromUnderlyingSource(
+ stream,
+ underlyingSource,
+ underlyingSource,
+ 0,
+ );
+ return stream;
+}
+
+const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId");
+const _isUnref = Symbol("isUnref");
+/**
+ * Create a new ReadableStream object that is backed by a Resource that
+ * implements `Resource::read_return`. This readable stream supports being
+ * refed and unrefed by calling `readableStreamForRidUnrefableRef` and
+ * `readableStreamForRidUnrefableUnref` on it. Unrefable streams are not
+ * FastStream compatible.
+ *
+ * @param {number} rid The resource ID to read from.
+ * @returns {ReadableStream<Uint8Array>}
+ */
+function readableStreamForRidUnrefable(rid) {
+ const stream = webidl.createBranded(ReadableStream);
+ stream[promiseIdSymbol] = undefined;
+ stream[_isUnref] = false;
+ stream[_resourceBackingUnrefable] = { rid, autoClose: true };
+ const underlyingSource = {
+ type: "bytes",
+ async pull(controller) {
+ const v = controller.byobRequest.view;
+ try {
+ const promise = core.read(rid, v);
+ const promiseId = stream[promiseIdSymbol] = promise[promiseIdSymbol];
+ if (stream[_isUnref]) core.unrefOp(promiseId);
+ const bytesRead = await promise;
+ stream[promiseIdSymbol] = undefined;
+ if (bytesRead === 0) {
core.tryClose(rid);
+ controller.close();
+ controller.byobRequest.respond(0);
+ } else {
+ controller.byobRequest.respond(bytesRead);
}
- },
- cancel() {
+ } catch (e) {
+ controller.error(e);
core.tryClose(rid);
- },
- autoAllocateChunkSize: DEFAULT_CHUNK_SIZE,
- };
- initializeReadableStream(stream);
- setUpReadableByteStreamControllerFromUnderlyingSource(
- stream,
- underlyingSource,
- underlyingSource,
- 0,
- );
- return stream;
- }
+ }
+ },
+ cancel() {
+ core.tryClose(rid);
+ },
+ autoAllocateChunkSize: DEFAULT_CHUNK_SIZE,
+ };
+ initializeReadableStream(stream);
+ setUpReadableByteStreamControllerFromUnderlyingSource(
+ stream,
+ underlyingSource,
+ underlyingSource,
+ 0,
+ );
+ return stream;
+}
- function readableStreamIsUnrefable(stream) {
- return ReflectHas(stream, _isUnref);
- }
+function readableStreamIsUnrefable(stream) {
+ return ReflectHas(stream, _isUnref);
+}
- function readableStreamForRidUnrefableRef(stream) {
- if (!readableStreamIsUnrefable(stream)) {
- throw new TypeError("Not an unrefable stream");
- }
- stream[_isUnref] = false;
- if (stream[promiseIdSymbol] !== undefined) {
- core.refOp(stream[promiseIdSymbol]);
- }
+function readableStreamForRidUnrefableRef(stream) {
+ if (!readableStreamIsUnrefable(stream)) {
+ throw new TypeError("Not an unrefable stream");
}
-
- function readableStreamForRidUnrefableUnref(stream) {
- if (!readableStreamIsUnrefable(stream)) {
- throw new TypeError("Not an unrefable stream");
- }
- stream[_isUnref] = true;
- if (stream[promiseIdSymbol] !== undefined) {
- core.unrefOp(stream[promiseIdSymbol]);
- }
+ stream[_isUnref] = false;
+ if (stream[promiseIdSymbol] !== undefined) {
+ core.refOp(stream[promiseIdSymbol]);
}
+}
- function getReadableStreamResourceBacking(stream) {
- return stream[_resourceBacking];
+function readableStreamForRidUnrefableUnref(stream) {
+ if (!readableStreamIsUnrefable(stream)) {
+ throw new TypeError("Not an unrefable stream");
}
-
- function getReadableStreamResourceBackingUnrefable(stream) {
- return stream[_resourceBackingUnrefable];
+ stream[_isUnref] = true;
+ if (stream[promiseIdSymbol] !== undefined) {
+ core.unrefOp(stream[promiseIdSymbol]);
}
+}
- async function readableStreamCollectIntoUint8Array(stream) {
- const resourceBacking = getReadableStreamResourceBacking(stream) ||
- getReadableStreamResourceBackingUnrefable(stream);
- const reader = acquireReadableStreamDefaultReader(stream);
-
- if (resourceBacking) {
- // fast path, read whole body in a single op call
- try {
- readableStreamDisturb(stream);
- const promise = core.opAsync("op_read_all", resourceBacking.rid);
- if (readableStreamIsUnrefable(stream)) {
- const promiseId = stream[promiseIdSymbol] = promise[promiseIdSymbol];
- if (stream[_isUnref]) core.unrefOp(promiseId);
- }
- const buf = await promise;
- readableStreamThrowIfErrored(stream);
- readableStreamClose(stream);
- return buf;
- } catch (err) {
- readableStreamThrowIfErrored(stream);
- readableStreamError(stream, err);
- throw err;
- } finally {
- if (resourceBacking.autoClose) {
- core.tryClose(resourceBacking.rid);
- }
- }
- }
-
- // slow path
- /** @type {Uint8Array[]} */
- const chunks = [];
- let totalLength = 0;
+function getReadableStreamResourceBacking(stream) {
+ return stream[_resourceBacking];
+}
- // tee'd stream
- if (stream[_original]) {
- // One of the branches is consuming the stream
- // signal controller.pull that we can consume it in a single op
- stream[_original][_controller][_readAll] = true;
- }
-
- while (true) {
- const { value: chunk, done } = await reader.read();
+function getReadableStreamResourceBackingUnrefable(stream) {
+ return stream[_resourceBackingUnrefable];
+}
- if (done) break;
+async function readableStreamCollectIntoUint8Array(stream) {
+ const resourceBacking = getReadableStreamResourceBacking(stream) ||
+ getReadableStreamResourceBackingUnrefable(stream);
+ const reader = acquireReadableStreamDefaultReader(stream);
- if (!ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, chunk)) {
- throw new TypeError(
- "Can't convert value to Uint8Array while consuming the stream",
- );
+ if (resourceBacking) {
+ // fast path, read whole body in a single op call
+ try {
+ readableStreamDisturb(stream);
+ const promise = core.opAsync("op_read_all", resourceBacking.rid);
+ if (readableStreamIsUnrefable(stream)) {
+ const promiseId = stream[promiseIdSymbol] = promise[promiseIdSymbol];
+ if (stream[_isUnref]) core.unrefOp(promiseId);
+ }
+ const buf = await promise;
+ readableStreamThrowIfErrored(stream);
+ readableStreamClose(stream);
+ return buf;
+ } catch (err) {
+ readableStreamThrowIfErrored(stream);
+ readableStreamError(stream, err);
+ throw err;
+ } finally {
+ if (resourceBacking.autoClose) {
+ core.tryClose(resourceBacking.rid);
}
-
- ArrayPrototypePush(chunks, chunk);
- totalLength += chunk.byteLength;
}
-
- const finalBuffer = new Uint8Array(totalLength);
- let offset = 0;
- for (let i = 0; i < chunks.length; ++i) {
- const chunk = chunks[i];
- TypedArrayPrototypeSet(finalBuffer, chunk, offset);
- offset += chunk.byteLength;
- }
- return finalBuffer;
}
- /**
- * Create a new Writable object that is backed by a Resource that implements
- * `Resource::write` / `Resource::write_all`. This object contains enough
- * metadata to allow callers to bypass the JavaScript WritableStream
- * implementation and write directly to the underlying resource if they so
- * choose (FastStream).
- *
- * @param {number} rid The resource ID to write to.
- * @param {boolean=} autoClose If the resource should be auto-closed when the stream closes. Defaults to true.
- * @returns {ReadableStream<Uint8Array>}
- */
- function writableStreamForRid(rid, autoClose = true) {
- const stream = webidl.createBranded(WritableStream);
- stream[_resourceBacking] = { rid, autoClose };
+ // slow path
+ /** @type {Uint8Array[]} */
+ const chunks = [];
+ let totalLength = 0;
- const tryClose = () => {
- if (!autoClose) return;
- RESOURCE_REGISTRY.unregister(stream);
- core.tryClose(rid);
- };
-
- if (autoClose) {
- RESOURCE_REGISTRY.register(stream, rid, stream);
- }
-
- const underlyingSink = {
- async write(chunk, controller) {
- try {
- await core.writeAll(rid, chunk);
- } catch (e) {
- controller.error(e);
- tryClose();
- }
- },
- close() {
- tryClose();
- },
- abort() {
- tryClose();
- },
- };
- initializeWritableStream(stream);
- setUpWritableStreamDefaultControllerFromUnderlyingSink(
- stream,
- underlyingSink,
- underlyingSink,
- 1,
- () => 1,
- );
- return stream;
+ // tee'd stream
+ if (stream[_original]) {
+ // One of the branches is consuming the stream
+ // signal controller.pull that we can consume it in a single op
+ stream[_original][_controller][_readAll] = true;
}
- function getWritableStreamResourceBacking(stream) {
- return stream[_resourceBacking];
- }
+ while (true) {
+ const { value: chunk, done } = await reader.read();
- /*
- * @param {ReadableStream} stream
- */
- function readableStreamThrowIfErrored(stream) {
- if (stream[_state] === "errored") {
- throw stream[_storedError];
- }
- }
+ if (done) break;
- /**
- * @param {unknown} value
- * @returns {value is WritableStream}
- */
- function isWritableStream(value) {
- return !(typeof value !== "object" || value === null ||
- !ReflectHas(value, _controller));
- }
-
- /**
- * @param {WritableStream} stream
- * @returns {boolean}
- */
- function isWritableStreamLocked(stream) {
- if (stream[_writer] === undefined) {
- return false;
- }
- return true;
- }
- /**
- * @template T
- * @param {{ [_queue]: Array<ValueWithSize<T | _close>>, [_queueTotalSize]: number }} container
- * @returns {T | _close}
- */
- function peekQueueValue(container) {
- assert(
- ReflectHas(container, _queue) &&
- ReflectHas(container, _queueTotalSize),
- );
- assert(container[_queue].length);
- const valueWithSize = container[_queue][0];
- return valueWithSize.value;
- }
-
- /**
- * @param {ReadableByteStreamController} controller
- * @returns {void}
- */
- function readableByteStreamControllerCallPullIfNeeded(controller) {
- const shouldPull = readableByteStreamControllerShouldCallPull(controller);
- if (!shouldPull) {
- return;
- }
- if (controller[_pulling]) {
- controller[_pullAgain] = true;
- return;
+ if (!ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, chunk)) {
+ throw new TypeError(
+ "Can't convert value to Uint8Array while consuming the stream",
+ );
}
- assert(controller[_pullAgain] === false);
- controller[_pulling] = true;
- /** @type {Promise<void>} */
- const pullPromise = controller[_pullAlgorithm](controller);
- setPromiseIsHandledToTrue(
- PromisePrototypeThen(
- pullPromise,
- () => {
- controller[_pulling] = false;
- if (controller[_pullAgain]) {
- controller[_pullAgain] = false;
- readableByteStreamControllerCallPullIfNeeded(controller);
- }
- },
- (e) => {
- readableByteStreamControllerError(controller, e);
- },
- ),
- );
- }
- /**
- * @param {ReadableByteStreamController} controller
- * @returns {void}
- */
- function readableByteStreamControllerClearAlgorithms(controller) {
- controller[_pullAlgorithm] = undefined;
- controller[_cancelAlgorithm] = undefined;
- }
+ ArrayPrototypePush(chunks, chunk);
+ totalLength += chunk.byteLength;
+ }
+
+ const finalBuffer = new Uint8Array(totalLength);
+ let offset = 0;
+ for (let i = 0; i < chunks.length; ++i) {
+ const chunk = chunks[i];
+ TypedArrayPrototypeSet(finalBuffer, chunk, offset);
+ offset += chunk.byteLength;
+ }
+ return finalBuffer;
+}
+
+/**
+ * Create a new Writable object that is backed by a Resource that implements
+ * `Resource::write` / `Resource::write_all`. This object contains enough
+ * metadata to allow callers to bypass the JavaScript WritableStream
+ * implementation and write directly to the underlying resource if they so
+ * choose (FastStream).
+ *
+ * @param {number} rid The resource ID to write to.
+ * @param {boolean=} autoClose If the resource should be auto-closed when the stream closes. Defaults to true.
+ * @returns {ReadableStream<Uint8Array>}
+ */
+function writableStreamForRid(rid, autoClose = true) {
+ const stream = webidl.createBranded(WritableStream);
+ stream[_resourceBacking] = { rid, autoClose };
+
+ const tryClose = () => {
+ if (!autoClose) return;
+ RESOURCE_REGISTRY.unregister(stream);
+ core.tryClose(rid);
+ };
- /**
- * @param {ReadableByteStreamController} controller
- * @param {any} e
- */
- function readableByteStreamControllerError(controller, e) {
- /** @type {ReadableStream<ArrayBuffer>} */
- const stream = controller[_stream];
- if (stream[_state] !== "readable") {
- return;
- }
- readableByteStreamControllerClearPendingPullIntos(controller);
- resetQueue(controller);
- readableByteStreamControllerClearAlgorithms(controller);
- readableStreamError(stream, e);
+ if (autoClose) {
+ RESOURCE_REGISTRY.register(stream, rid, stream);
}
- /**
- * @param {ReadableByteStreamController} controller
- * @returns {void}
- */
- function readableByteStreamControllerClearPendingPullIntos(controller) {
- readableByteStreamControllerInvalidateBYOBRequest(controller);
- controller[_pendingPullIntos] = [];
+ const underlyingSink = {
+ async write(chunk, controller) {
+ try {
+ await core.writeAll(rid, chunk);
+ } catch (e) {
+ controller.error(e);
+ tryClose();
+ }
+ },
+ close() {
+ tryClose();
+ },
+ abort() {
+ tryClose();
+ },
+ };
+ initializeWritableStream(stream);
+ setUpWritableStreamDefaultControllerFromUnderlyingSink(
+ stream,
+ underlyingSink,
+ underlyingSink,
+ 1,
+ () => 1,
+ );
+ return stream;
+}
+
+function getWritableStreamResourceBacking(stream) {
+ return stream[_resourceBacking];
+}
+
+/*
+ * @param {ReadableStream} stream
+ */
+function readableStreamThrowIfErrored(stream) {
+ if (stream[_state] === "errored") {
+ throw stream[_storedError];
+ }
+}
+
+/**
+ * @param {unknown} value
+ * @returns {value is WritableStream}
+ */
+function isWritableStream(value) {
+ return !(typeof value !== "object" || value === null ||
+ !ReflectHas(value, _controller));
+}
+
+/**
+ * @param {WritableStream} stream
+ * @returns {boolean}
+ */
+function isWritableStreamLocked(stream) {
+ if (stream[_writer] === undefined) {
+ return false;
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @returns {void}
- */
- function readableByteStreamControllerClose(controller) {
- /** @type {ReadableStream<ArrayBuffer>} */
- const stream = controller[_stream];
- if (controller[_closeRequested] || stream[_state] !== "readable") {
- return;
- }
- if (controller[_queueTotalSize] > 0) {
- controller[_closeRequested] = true;
- return;
- }
- if (controller[_pendingPullIntos].length !== 0) {
- const firstPendingPullInto = controller[_pendingPullIntos][0];
- if (firstPendingPullInto.bytesFilled > 0) {
- const e = new TypeError(
- "Insufficient bytes to fill elements in the given buffer",
- );
+ return true;
+}
+/**
+ * @template T
+ * @param {{ [_queue]: Array<ValueWithSize<T | _close>>, [_queueTotalSize]: number }} container
+ * @returns {T | _close}
+ */
+function peekQueueValue(container) {
+ assert(
+ ReflectHas(container, _queue) &&
+ ReflectHas(container, _queueTotalSize),
+ );
+ assert(container[_queue].length);
+ const valueWithSize = container[_queue][0];
+ return valueWithSize.value;
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @returns {void}
+ */
+function readableByteStreamControllerCallPullIfNeeded(controller) {
+ const shouldPull = readableByteStreamControllerShouldCallPull(controller);
+ if (!shouldPull) {
+ return;
+ }
+ if (controller[_pulling]) {
+ controller[_pullAgain] = true;
+ return;
+ }
+ assert(controller[_pullAgain] === false);
+ controller[_pulling] = true;
+ /** @type {Promise<void>} */
+ const pullPromise = controller[_pullAlgorithm](controller);
+ setPromiseIsHandledToTrue(
+ PromisePrototypeThen(
+ pullPromise,
+ () => {
+ controller[_pulling] = false;
+ if (controller[_pullAgain]) {
+ controller[_pullAgain] = false;
+ readableByteStreamControllerCallPullIfNeeded(controller);
+ }
+ },
+ (e) => {
readableByteStreamControllerError(controller, e);
- throw e;
- }
- }
- readableByteStreamControllerClearAlgorithms(controller);
- readableStreamClose(stream);
+ },
+ ),
+ );
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @returns {void}
+ */
+function readableByteStreamControllerClearAlgorithms(controller) {
+ controller[_pullAlgorithm] = undefined;
+ controller[_cancelAlgorithm] = undefined;
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {any} e
+ */
+function readableByteStreamControllerError(controller, e) {
+ /** @type {ReadableStream<ArrayBuffer>} */
+ const stream = controller[_stream];
+ if (stream[_state] !== "readable") {
+ return;
+ }
+ readableByteStreamControllerClearPendingPullIntos(controller);
+ resetQueue(controller);
+ readableByteStreamControllerClearAlgorithms(controller);
+ readableStreamError(stream, e);
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @returns {void}
+ */
+function readableByteStreamControllerClearPendingPullIntos(controller) {
+ readableByteStreamControllerInvalidateBYOBRequest(controller);
+ controller[_pendingPullIntos] = [];
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @returns {void}
+ */
+function readableByteStreamControllerClose(controller) {
+ /** @type {ReadableStream<ArrayBuffer>} */
+ const stream = controller[_stream];
+ if (controller[_closeRequested] || stream[_state] !== "readable") {
+ return;
+ }
+ if (controller[_queueTotalSize] > 0) {
+ controller[_closeRequested] = true;
+ return;
+ }
+ if (controller[_pendingPullIntos].length !== 0) {
+ const firstPendingPullInto = controller[_pendingPullIntos][0];
+ if (firstPendingPullInto.bytesFilled > 0) {
+ const e = new TypeError(
+ "Insufficient bytes to fill elements in the given buffer",
+ );
+ readableByteStreamControllerError(controller, e);
+ throw e;
+ }
+ }
+ readableByteStreamControllerClearAlgorithms(controller);
+ readableStreamClose(stream);
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {ArrayBufferView} chunk
+ */
+function readableByteStreamControllerEnqueue(controller, chunk) {
+ /** @type {ReadableStream<ArrayBuffer>} */
+ const stream = controller[_stream];
+ if (
+ controller[_closeRequested] ||
+ controller[_stream][_state] !== "readable"
+ ) {
+ return;
}
- /**
- * @param {ReadableByteStreamController} controller
- * @param {ArrayBufferView} chunk
- */
- function readableByteStreamControllerEnqueue(controller, chunk) {
- /** @type {ReadableStream<ArrayBuffer>} */
- const stream = controller[_stream];
- if (
- controller[_closeRequested] ||
- controller[_stream][_state] !== "readable"
- ) {
- return;
- }
-
- const { buffer, byteOffset, byteLength } = chunk;
- if (isDetachedBuffer(buffer)) {
+ const { buffer, byteOffset, byteLength } = chunk;
+ if (isDetachedBuffer(buffer)) {
+ throw new TypeError(
+ "chunk's buffer is detached and so cannot be enqueued",
+ );
+ }
+ const transferredBuffer = transferArrayBuffer(buffer);
+ if (controller[_pendingPullIntos].length !== 0) {
+ const firstPendingPullInto = controller[_pendingPullIntos][0];
+ if (isDetachedBuffer(firstPendingPullInto.buffer)) {
throw new TypeError(
- "chunk's buffer is detached and so cannot be enqueued",
+ "The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk",
);
}
- const transferredBuffer = transferArrayBuffer(buffer);
- if (controller[_pendingPullIntos].length !== 0) {
- const firstPendingPullInto = controller[_pendingPullIntos][0];
- if (isDetachedBuffer(firstPendingPullInto.buffer)) {
- throw new TypeError(
- "The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk",
- );
- }
- readableByteStreamControllerInvalidateBYOBRequest(controller);
- firstPendingPullInto.buffer = transferArrayBuffer(
- firstPendingPullInto.buffer,
+ readableByteStreamControllerInvalidateBYOBRequest(controller);
+ firstPendingPullInto.buffer = transferArrayBuffer(
+ firstPendingPullInto.buffer,
+ );
+ if (firstPendingPullInto.readerType === "none") {
+ readableByteStreamControllerEnqueueDetachedPullIntoToQueue(
+ controller,
+ firstPendingPullInto,
);
- if (firstPendingPullInto.readerType === "none") {
- readableByteStreamControllerEnqueueDetachedPullIntoToQueue(
- controller,
- firstPendingPullInto,
- );
- }
}
- if (readableStreamHasDefaultReader(stream)) {
- readableByteStreamControllerProcessReadRequestsUsingQueue(controller);
- if (readableStreamGetNumReadRequests(stream) === 0) {
- assert(controller[_pendingPullIntos].length === 0);
- readableByteStreamControllerEnqueueChunkToQueue(
- controller,
- transferredBuffer,
- byteOffset,
- byteLength,
- );
- } else {
- assert(controller[_queue].length === 0);
- if (controller[_pendingPullIntos].length !== 0) {
- assert(controller[_pendingPullIntos][0].readerType === "default");
- readableByteStreamControllerShiftPendingPullInto(controller);
- }
- const transferredView = new Uint8Array(
- transferredBuffer,
- byteOffset,
- byteLength,
- );
- readableStreamFulfillReadRequest(stream, transferredView, false);
- }
- } else if (readableStreamHasBYOBReader(stream)) {
+ }
+ if (readableStreamHasDefaultReader(stream)) {
+ readableByteStreamControllerProcessReadRequestsUsingQueue(controller);
+ if (readableStreamGetNumReadRequests(stream) === 0) {
+ assert(controller[_pendingPullIntos].length === 0);
readableByteStreamControllerEnqueueChunkToQueue(
controller,
transferredBuffer,
byteOffset,
byteLength,
);
- readableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
- controller,
- );
} else {
- assert(isReadableStreamLocked(stream) === false);
- readableByteStreamControllerEnqueueChunkToQueue(
- controller,
+ assert(controller[_queue].length === 0);
+ if (controller[_pendingPullIntos].length !== 0) {
+ assert(controller[_pendingPullIntos][0].readerType === "default");
+ readableByteStreamControllerShiftPendingPullInto(controller);
+ }
+ const transferredView = new Uint8Array(
transferredBuffer,
byteOffset,
byteLength,
);
+ readableStreamFulfillReadRequest(stream, transferredView, false);
}
- readableByteStreamControllerCallPullIfNeeded(controller);
+ } else if (readableStreamHasBYOBReader(stream)) {
+ readableByteStreamControllerEnqueueChunkToQueue(
+ controller,
+ transferredBuffer,
+ byteOffset,
+ byteLength,
+ );
+ readableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
+ controller,
+ );
+ } else {
+ assert(isReadableStreamLocked(stream) === false);
+ readableByteStreamControllerEnqueueChunkToQueue(
+ controller,
+ transferredBuffer,
+ byteOffset,
+ byteLength,
+ );
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {ArrayBufferLike} buffer
- * @param {number} byteOffset
- * @param {number} byteLength
- * @returns {void}
- */
- function readableByteStreamControllerEnqueueChunkToQueue(
+ readableByteStreamControllerCallPullIfNeeded(controller);
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {ArrayBufferLike} buffer
+ * @param {number} byteOffset
+ * @param {number} byteLength
+ * @returns {void}
+ */
+function readableByteStreamControllerEnqueueChunkToQueue(
+ controller,
+ buffer,
+ byteOffset,
+ byteLength,
+) {
+ ArrayPrototypePush(controller[_queue], { buffer, byteOffset, byteLength });
+ controller[_queueTotalSize] += byteLength;
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {ArrayBufferLike} buffer
+ * @param {number} byteOffset
+ * @param {number} byteLength
+ * @returns {void}
+ */
+function readableByteStreamControllerEnqueueClonedChunkToQueue(
+ controller,
+ buffer,
+ byteOffset,
+ byteLength,
+) {
+ let cloneResult;
+ try {
+ cloneResult = buffer.slice(byteOffset, byteOffset + byteLength);
+ } catch (e) {
+ readableByteStreamControllerError(controller, e);
+ }
+ readableByteStreamControllerEnqueueChunkToQueue(
controller,
- buffer,
- byteOffset,
+ cloneResult,
+ 0,
byteLength,
- ) {
- ArrayPrototypePush(controller[_queue], { buffer, byteOffset, byteLength });
- controller[_queueTotalSize] += byteLength;
+ );
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {PullIntoDescriptor} pullIntoDescriptor
+ * @returns {void}
+ */
+function readableByteStreamControllerEnqueueDetachedPullIntoToQueue(
+ controller,
+ pullIntoDescriptor,
+) {
+ assert(pullIntoDescriptor.readerType === "none");
+ if (pullIntoDescriptor.bytesFilled > 0) {
+ readableByteStreamControllerEnqueueClonedChunkToQueue(
+ controller,
+ pullIntoDescriptor.buffer,
+ pullIntoDescriptor.byteOffset,
+ pullIntoDescriptor.bytesFilled,
+ );
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {ArrayBufferLike} buffer
- * @param {number} byteOffset
- * @param {number} byteLength
- * @returns {void}
- */
- function readableByteStreamControllerEnqueueClonedChunkToQueue(
- controller,
- buffer,
- byteOffset,
- byteLength,
+ readableByteStreamControllerShiftPendingPullInto(controller);
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @returns {ReadableStreamBYOBRequest | null}
+ */
+function readableByteStreamControllerGetBYOBRequest(controller) {
+ if (
+ controller[_byobRequest] === null &&
+ controller[_pendingPullIntos].length !== 0
) {
- let cloneResult;
- try {
- cloneResult = buffer.slice(byteOffset, byteOffset + byteLength);
- } catch (e) {
- readableByteStreamControllerError(controller, e);
- }
- readableByteStreamControllerEnqueueChunkToQueue(
- controller,
- cloneResult,
- 0,
- byteLength,
+ const firstDescriptor = controller[_pendingPullIntos][0];
+ const view = new Uint8Array(
+ firstDescriptor.buffer,
+ firstDescriptor.byteOffset + firstDescriptor.bytesFilled,
+ firstDescriptor.byteLength - firstDescriptor.bytesFilled,
);
+ const byobRequest = webidl.createBranded(ReadableStreamBYOBRequest);
+ byobRequest[_controller] = controller;
+ byobRequest[_view] = view;
+ controller[_byobRequest] = byobRequest;
+ }
+ return controller[_byobRequest];
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @returns {number | null}
+ */
+function readableByteStreamControllerGetDesiredSize(controller) {
+ const state = controller[_stream][_state];
+ if (state === "errored") {
+ return null;
+ }
+ if (state === "closed") {
+ return 0;
+ }
+ return controller[_strategyHWM] - controller[_queueTotalSize];
+}
+
+/**
+ * @param {{ [_queue]: any[], [_queueTotalSize]: number }} container
+ * @returns {void}
+ */
+function resetQueue(container) {
+ container[_queue] = [];
+ container[_queueTotalSize] = 0;
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @returns {void}
+ */
+function readableByteStreamControllerHandleQueueDrain(controller) {
+ assert(controller[_stream][_state] === "readable");
+ if (
+ controller[_queueTotalSize] === 0 && controller[_closeRequested]
+ ) {
+ readableByteStreamControllerClearAlgorithms(controller);
+ readableStreamClose(controller[_stream]);
+ } else {
+ readableByteStreamControllerCallPullIfNeeded(controller);
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {PullIntoDescriptor} pullIntoDescriptor
- * @returns {void}
- */
- function readableByteStreamControllerEnqueueDetachedPullIntoToQueue(
- controller,
- pullIntoDescriptor,
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @returns {boolean}
+ */
+function readableByteStreamControllerShouldCallPull(controller) {
+ /** @type {ReadableStream<ArrayBuffer>} */
+ const stream = controller[_stream];
+ if (
+ stream[_state] !== "readable" ||
+ controller[_closeRequested] ||
+ !controller[_started]
) {
- assert(pullIntoDescriptor.readerType === "none");
- if (pullIntoDescriptor.bytesFilled > 0) {
- readableByteStreamControllerEnqueueClonedChunkToQueue(
- controller,
- pullIntoDescriptor.buffer,
- pullIntoDescriptor.byteOffset,
- pullIntoDescriptor.bytesFilled,
- );
- }
- readableByteStreamControllerShiftPendingPullInto(controller);
+ return false;
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @returns {ReadableStreamBYOBRequest | null}
- */
- function readableByteStreamControllerGetBYOBRequest(controller) {
- if (
- controller[_byobRequest] === null &&
- controller[_pendingPullIntos].length !== 0
- ) {
- const firstDescriptor = controller[_pendingPullIntos][0];
- const view = new Uint8Array(
- firstDescriptor.buffer,
- firstDescriptor.byteOffset + firstDescriptor.bytesFilled,
- firstDescriptor.byteLength - firstDescriptor.bytesFilled,
- );
- const byobRequest = webidl.createBranded(ReadableStreamBYOBRequest);
- byobRequest[_controller] = controller;
- byobRequest[_view] = view;
- controller[_byobRequest] = byobRequest;
- }
- return controller[_byobRequest];
+ if (
+ readableStreamHasDefaultReader(stream) &&
+ readableStreamGetNumReadRequests(stream) > 0
+ ) {
+ return true;
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @returns {number | null}
- */
- function readableByteStreamControllerGetDesiredSize(controller) {
- const state = controller[_stream][_state];
- if (state === "errored") {
- return null;
- }
- if (state === "closed") {
- return 0;
- }
- return controller[_strategyHWM] - controller[_queueTotalSize];
+ if (
+ readableStreamHasBYOBReader(stream) &&
+ readableStreamGetNumReadIntoRequests(stream) > 0
+ ) {
+ return true;
}
-
- /**
- * @param {{ [_queue]: any[], [_queueTotalSize]: number }} container
- * @returns {void}
- */
- function resetQueue(container) {
- container[_queue] = [];
- container[_queueTotalSize] = 0;
+ const desiredSize = readableByteStreamControllerGetDesiredSize(controller);
+ assert(desiredSize !== null);
+ return desiredSize > 0;
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @param {ReadRequest<R>} readRequest
+ * @returns {void}
+ */
+function readableStreamAddReadRequest(stream, readRequest) {
+ assert(isReadableStreamDefaultReader(stream[_reader]));
+ assert(stream[_state] === "readable");
+ ArrayPrototypePush(stream[_reader][_readRequests], readRequest);
+}
+
+/**
+ * @param {ReadableStream} stream
+ * @param {ReadIntoRequest} readRequest
+ * @returns {void}
+ */
+function readableStreamAddReadIntoRequest(stream, readRequest) {
+ assert(isReadableStreamBYOBReader(stream[_reader]));
+ assert(stream[_state] === "readable" || stream[_state] === "closed");
+ ArrayPrototypePush(stream[_reader][_readIntoRequests], readRequest);
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @param {any=} reason
+ * @returns {Promise<void>}
+ */
+function readableStreamCancel(stream, reason) {
+ stream[_disturbed] = true;
+ if (stream[_state] === "closed") {
+ return resolvePromiseWith(undefined);
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @returns {void}
- */
- function readableByteStreamControllerHandleQueueDrain(controller) {
- assert(controller[_stream][_state] === "readable");
- if (
- controller[_queueTotalSize] === 0 && controller[_closeRequested]
- ) {
- readableByteStreamControllerClearAlgorithms(controller);
- readableStreamClose(controller[_stream]);
- } else {
- readableByteStreamControllerCallPullIfNeeded(controller);
+ if (stream[_state] === "errored") {
+ return PromiseReject(stream[_storedError]);
+ }
+ readableStreamClose(stream);
+ const reader = stream[_reader];
+ if (reader !== undefined && isReadableStreamBYOBReader(reader)) {
+ const readIntoRequests = reader[_readIntoRequests];
+ reader[_readIntoRequests] = [];
+ for (let i = 0; i < readIntoRequests.length; ++i) {
+ const readIntoRequest = readIntoRequests[i];
+ readIntoRequest.closeSteps(undefined);
+ }
+ }
+ /** @type {Promise<void>} */
+ const sourceCancelPromise = stream[_controller][_cancelSteps](reason);
+ return PromisePrototypeThen(sourceCancelPromise, () => undefined);
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @returns {void}
+ */
+function readableStreamClose(stream) {
+ assert(stream[_state] === "readable");
+ stream[_state] = "closed";
+ /** @type {ReadableStreamDefaultReader<R> | undefined} */
+ const reader = stream[_reader];
+ if (!reader) {
+ return;
+ }
+ if (isReadableStreamDefaultReader(reader)) {
+ /** @type {Array<ReadRequest<R>>} */
+ const readRequests = reader[_readRequests];
+ reader[_readRequests] = [];
+ for (let i = 0; i < readRequests.length; ++i) {
+ const readRequest = readRequests[i];
+ readRequest.closeSteps();
}
}
+ // This promise can be double resolved.
+ // See: https://github.com/whatwg/streams/issues/1100
+ reader[_closedPromise].resolve(undefined);
+}
- /**
- * @param {ReadableByteStreamController} controller
- * @returns {boolean}
- */
- function readableByteStreamControllerShouldCallPull(controller) {
- /** @type {ReadableStream<ArrayBuffer>} */
- const stream = controller[_stream];
- if (
- stream[_state] !== "readable" ||
- controller[_closeRequested] ||
- !controller[_started]
- ) {
- return false;
- }
- if (
- readableStreamHasDefaultReader(stream) &&
- readableStreamGetNumReadRequests(stream) > 0
- ) {
- return true;
- }
- if (
- readableStreamHasBYOBReader(stream) &&
- readableStreamGetNumReadIntoRequests(stream) > 0
- ) {
- return true;
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @returns {void}
+ */
+function readableStreamDisturb(stream) {
+ stream[_disturbed] = true;
+}
+
+/** @param {ReadableStreamDefaultController<any>} controller */
+function readableStreamDefaultControllerCallPullIfNeeded(controller) {
+ const shouldPull = readableStreamDefaultcontrollerShouldCallPull(
+ controller,
+ );
+ if (shouldPull === false) {
+ return;
+ }
+ if (controller[_pulling] === true) {
+ controller[_pullAgain] = true;
+ return;
+ }
+ assert(controller[_pullAgain] === false);
+ controller[_pulling] = true;
+ const pullPromise = controller[_pullAlgorithm](controller);
+ uponFulfillment(pullPromise, () => {
+ controller[_pulling] = false;
+ if (controller[_pullAgain] === true) {
+ controller[_pullAgain] = false;
+ readableStreamDefaultControllerCallPullIfNeeded(controller);
}
- const desiredSize = readableByteStreamControllerGetDesiredSize(controller);
- assert(desiredSize !== null);
- return desiredSize > 0;
+ });
+ uponRejection(pullPromise, (e) => {
+ readableStreamDefaultControllerError(controller, e);
+ });
+}
+
+/**
+ * @param {ReadableStreamDefaultController<any>} controller
+ * @returns {boolean}
+ */
+function readableStreamDefaultControllerCanCloseOrEnqueue(controller) {
+ const state = controller[_stream][_state];
+ if (controller[_closeRequested] === false && state === "readable") {
+ return true;
+ } else {
+ return false;
}
+}
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @param {ReadRequest<R>} readRequest
- * @returns {void}
- */
- function readableStreamAddReadRequest(stream, readRequest) {
- assert(isReadableStreamDefaultReader(stream[_reader]));
- assert(stream[_state] === "readable");
- ArrayPrototypePush(stream[_reader][_readRequests], readRequest);
- }
+/** @param {ReadableStreamDefaultController<any>} controller */
+function readableStreamDefaultControllerClearAlgorithms(controller) {
+ controller[_pullAlgorithm] = undefined;
+ controller[_cancelAlgorithm] = undefined;
+ controller[_strategySizeAlgorithm] = undefined;
+}
- /**
- * @param {ReadableStream} stream
- * @param {ReadIntoRequest} readRequest
- * @returns {void}
- */
- function readableStreamAddReadIntoRequest(stream, readRequest) {
- assert(isReadableStreamBYOBReader(stream[_reader]));
- assert(stream[_state] === "readable" || stream[_state] === "closed");
- ArrayPrototypePush(stream[_reader][_readIntoRequests], readRequest);
+/** @param {ReadableStreamDefaultController<any>} controller */
+function readableStreamDefaultControllerClose(controller) {
+ if (
+ readableStreamDefaultControllerCanCloseOrEnqueue(controller) === false
+ ) {
+ return;
}
-
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @param {any=} reason
- * @returns {Promise<void>}
- */
- function readableStreamCancel(stream, reason) {
- stream[_disturbed] = true;
- if (stream[_state] === "closed") {
- return resolvePromiseWith(undefined);
- }
- if (stream[_state] === "errored") {
- return PromiseReject(stream[_storedError]);
- }
+ const stream = controller[_stream];
+ controller[_closeRequested] = true;
+ if (controller[_queue].length === 0) {
+ readableStreamDefaultControllerClearAlgorithms(controller);
readableStreamClose(stream);
- const reader = stream[_reader];
- if (reader !== undefined && isReadableStreamBYOBReader(reader)) {
- const readIntoRequests = reader[_readIntoRequests];
- reader[_readIntoRequests] = [];
- for (let i = 0; i < readIntoRequests.length; ++i) {
- const readIntoRequest = readIntoRequests[i];
- readIntoRequest.closeSteps(undefined);
- }
- }
- /** @type {Promise<void>} */
- const sourceCancelPromise = stream[_controller][_cancelSteps](reason);
- return PromisePrototypeThen(sourceCancelPromise, () => undefined);
}
-
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @returns {void}
- */
- function readableStreamClose(stream) {
- assert(stream[_state] === "readable");
- stream[_state] = "closed";
- /** @type {ReadableStreamDefaultReader<R> | undefined} */
- const reader = stream[_reader];
- if (!reader) {
- return;
- }
- if (isReadableStreamDefaultReader(reader)) {
- /** @type {Array<ReadRequest<R>>} */
- const readRequests = reader[_readRequests];
- reader[_readRequests] = [];
- for (let i = 0; i < readRequests.length; ++i) {
- const readRequest = readRequests[i];
- readRequest.closeSteps();
- }
- }
- // This promise can be double resolved.
- // See: https://github.com/whatwg/streams/issues/1100
- reader[_closedPromise].resolve(undefined);
- }
-
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @returns {void}
- */
- function readableStreamDisturb(stream) {
- stream[_disturbed] = true;
+}
+
+/**
+ * @template R
+ * @param {ReadableStreamDefaultController<R>} controller
+ * @param {R} chunk
+ * @returns {void}
+ */
+function readableStreamDefaultControllerEnqueue(controller, chunk) {
+ if (
+ readableStreamDefaultControllerCanCloseOrEnqueue(controller) === false
+ ) {
+ return;
}
-
- /** @param {ReadableStreamDefaultController<any>} controller */
- function readableStreamDefaultControllerCallPullIfNeeded(controller) {
- const shouldPull = readableStreamDefaultcontrollerShouldCallPull(
- controller,
- );
- if (shouldPull === false) {
- return;
- }
- if (controller[_pulling] === true) {
- controller[_pullAgain] = true;
- return;
+ const stream = controller[_stream];
+ if (
+ isReadableStreamLocked(stream) === true &&
+ readableStreamGetNumReadRequests(stream) > 0
+ ) {
+ readableStreamFulfillReadRequest(stream, chunk, false);
+ } else {
+ let chunkSize;
+ try {
+ chunkSize = controller[_strategySizeAlgorithm](chunk);
+ } catch (e) {
+ readableStreamDefaultControllerError(controller, e);
+ throw e;
}
- assert(controller[_pullAgain] === false);
- controller[_pulling] = true;
- const pullPromise = controller[_pullAlgorithm](controller);
- uponFulfillment(pullPromise, () => {
- controller[_pulling] = false;
- if (controller[_pullAgain] === true) {
- controller[_pullAgain] = false;
- readableStreamDefaultControllerCallPullIfNeeded(controller);
- }
- });
- uponRejection(pullPromise, (e) => {
+
+ try {
+ enqueueValueWithSize(controller, chunk, chunkSize);
+ } catch (e) {
readableStreamDefaultControllerError(controller, e);
- });
+ throw e;
+ }
+ }
+ readableStreamDefaultControllerCallPullIfNeeded(controller);
+}
+
+/**
+ * @param {ReadableStreamDefaultController<any>} controller
+ * @param {any} e
+ */
+function readableStreamDefaultControllerError(controller, e) {
+ const stream = controller[_stream];
+ if (stream[_state] !== "readable") {
+ return;
+ }
+ resetQueue(controller);
+ readableStreamDefaultControllerClearAlgorithms(controller);
+ readableStreamError(stream, e);
+}
+
+/**
+ * @param {ReadableStreamDefaultController<any>} controller
+ * @returns {number | null}
+ */
+function readableStreamDefaultControllerGetDesiredSize(controller) {
+ const state = controller[_stream][_state];
+ if (state === "errored") {
+ return null;
+ }
+ if (state === "closed") {
+ return 0;
+ }
+ return controller[_strategyHWM] - controller[_queueTotalSize];
+}
+
+/** @param {ReadableStreamDefaultController} controller */
+function readableStreamDefaultcontrollerHasBackpressure(controller) {
+ if (readableStreamDefaultcontrollerShouldCallPull(controller) === true) {
+ return false;
+ } else {
+ return true;
}
+}
- /**
- * @param {ReadableStreamDefaultController<any>} controller
- * @returns {boolean}
- */
- function readableStreamDefaultControllerCanCloseOrEnqueue(controller) {
- const state = controller[_stream][_state];
- if (controller[_closeRequested] === false && state === "readable") {
- return true;
- } else {
- return false;
- }
+/**
+ * @param {ReadableStreamDefaultController<any>} controller
+ * @returns {boolean}
+ */
+function readableStreamDefaultcontrollerShouldCallPull(controller) {
+ const stream = controller[_stream];
+ if (
+ readableStreamDefaultControllerCanCloseOrEnqueue(controller) === false
+ ) {
+ return false;
}
-
- /** @param {ReadableStreamDefaultController<any>} controller */
- function readableStreamDefaultControllerClearAlgorithms(controller) {
- controller[_pullAlgorithm] = undefined;
- controller[_cancelAlgorithm] = undefined;
- controller[_strategySizeAlgorithm] = undefined;
+ if (controller[_started] === false) {
+ return false;
}
-
- /** @param {ReadableStreamDefaultController<any>} controller */
- function readableStreamDefaultControllerClose(controller) {
- if (
- readableStreamDefaultControllerCanCloseOrEnqueue(controller) === false
- ) {
- return;
- }
- const stream = controller[_stream];
- controller[_closeRequested] = true;
- if (controller[_queue].length === 0) {
- readableStreamDefaultControllerClearAlgorithms(controller);
- readableStreamClose(stream);
- }
+ if (
+ isReadableStreamLocked(stream) &&
+ readableStreamGetNumReadRequests(stream) > 0
+ ) {
+ return true;
}
-
- /**
- * @template R
- * @param {ReadableStreamDefaultController<R>} controller
- * @param {R} chunk
- * @returns {void}
- */
- function readableStreamDefaultControllerEnqueue(controller, chunk) {
- if (
- readableStreamDefaultControllerCanCloseOrEnqueue(controller) === false
- ) {
+ const desiredSize = readableStreamDefaultControllerGetDesiredSize(
+ controller,
+ );
+ assert(desiredSize !== null);
+ if (desiredSize > 0) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * @param {ReadableStreamBYOBReader} reader
+ * @param {ArrayBufferView} view
+ * @param {ReadIntoRequest} readIntoRequest
+ * @returns {void}
+ */
+function readableStreamBYOBReaderRead(reader, view, readIntoRequest) {
+ const stream = reader[_stream];
+ assert(stream);
+ stream[_disturbed] = true;
+ if (stream[_state] === "errored") {
+ readIntoRequest.errorSteps(stream[_storedError]);
+ } else {
+ readableByteStreamControllerPullInto(
+ stream[_controller],
+ view,
+ readIntoRequest,
+ );
+ }
+}
+
+/**
+ * @param {ReadableStreamBYOBReader} reader
+ */
+function readableStreamBYOBReaderRelease(reader) {
+ readableStreamReaderGenericRelease(reader);
+ const e = new TypeError("The reader was released.");
+ readableStreamBYOBReaderErrorReadIntoRequests(reader, e);
+}
+
+/**
+ * @param {ReadableStreamBYOBReader} reader
+ * @param {any} e
+ */
+function readableStreamDefaultReaderErrorReadRequests(reader, e) {
+ const readRequests = reader[_readRequests];
+ reader[_readRequests] = [];
+ for (let i = 0; i < readRequests.length; ++i) {
+ const readRequest = readRequests[i];
+ readRequest.errorSteps(e);
+ }
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ */
+function readableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
+ controller,
+) {
+ assert(!controller[_closeRequested]);
+ while (controller[_pendingPullIntos].length !== 0) {
+ if (controller[_queueTotalSize] === 0) {
return;
}
- const stream = controller[_stream];
+ const pullIntoDescriptor = controller[_pendingPullIntos][0];
if (
- isReadableStreamLocked(stream) === true &&
- readableStreamGetNumReadRequests(stream) > 0
+ readableByteStreamControllerFillPullIntoDescriptorFromQueue(
+ controller,
+ pullIntoDescriptor,
+ )
) {
- readableStreamFulfillReadRequest(stream, chunk, false);
- } else {
- let chunkSize;
- try {
- chunkSize = controller[_strategySizeAlgorithm](chunk);
- } catch (e) {
- readableStreamDefaultControllerError(controller, e);
- throw e;
- }
-
- try {
- enqueueValueWithSize(controller, chunk, chunkSize);
- } catch (e) {
- readableStreamDefaultControllerError(controller, e);
- throw e;
- }
+ readableByteStreamControllerShiftPendingPullInto(controller);
+ readableByteStreamControllerCommitPullIntoDescriptor(
+ controller[_stream],
+ pullIntoDescriptor,
+ );
}
- readableStreamDefaultControllerCallPullIfNeeded(controller);
}
-
- /**
- * @param {ReadableStreamDefaultController<any>} controller
- * @param {any} e
- */
- function readableStreamDefaultControllerError(controller, e) {
- const stream = controller[_stream];
- if (stream[_state] !== "readable") {
+}
+/**
+ * @param {ReadableByteStreamController} controller
+ */
+function readableByteStreamControllerProcessReadRequestsUsingQueue(
+ controller,
+) {
+ const reader = controller[_stream][_reader];
+ assert(isReadableStreamDefaultReader(reader));
+ while (reader[_readRequests].length !== 0) {
+ if (controller[_queueTotalSize] === 0) {
return;
}
- resetQueue(controller);
- readableStreamDefaultControllerClearAlgorithms(controller);
- readableStreamError(stream, e);
- }
-
- /**
- * @param {ReadableStreamDefaultController<any>} controller
- * @returns {number | null}
- */
- function readableStreamDefaultControllerGetDesiredSize(controller) {
- const state = controller[_stream][_state];
- if (state === "errored") {
- return null;
- }
- if (state === "closed") {
- return 0;
- }
- return controller[_strategyHWM] - controller[_queueTotalSize];
- }
-
- /** @param {ReadableStreamDefaultController} controller */
- function readableStreamDefaultcontrollerHasBackpressure(controller) {
- if (readableStreamDefaultcontrollerShouldCallPull(controller) === true) {
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * @param {ReadableStreamDefaultController<any>} controller
- * @returns {boolean}
- */
- function readableStreamDefaultcontrollerShouldCallPull(controller) {
- const stream = controller[_stream];
- if (
- readableStreamDefaultControllerCanCloseOrEnqueue(controller) === false
- ) {
- return false;
- }
- if (controller[_started] === false) {
- return false;
- }
- if (
- isReadableStreamLocked(stream) &&
- readableStreamGetNumReadRequests(stream) > 0
- ) {
- return true;
- }
- const desiredSize = readableStreamDefaultControllerGetDesiredSize(
+ const readRequest = ArrayPrototypeShift(reader[_readRequests]);
+ readableByteStreamControllerFillReadRequestFromQueue(
controller,
+ readRequest,
);
- assert(desiredSize !== null);
- if (desiredSize > 0) {
- return true;
- }
- return false;
}
-
- /**
- * @param {ReadableStreamBYOBReader} reader
- * @param {ArrayBufferView} view
- * @param {ReadIntoRequest} readIntoRequest
- * @returns {void}
- */
- function readableStreamBYOBReaderRead(reader, view, readIntoRequest) {
- const stream = reader[_stream];
- assert(stream);
- stream[_disturbed] = true;
- if (stream[_state] === "errored") {
- readIntoRequest.errorSteps(stream[_storedError]);
- } else {
- readableByteStreamControllerPullInto(
- stream[_controller],
- view,
- readIntoRequest,
- );
- }
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {ArrayBufferView} view
+ * @param {ReadIntoRequest} readIntoRequest
+ * @returns {void}
+ */
+function readableByteStreamControllerPullInto(
+ controller,
+ view,
+ readIntoRequest,
+) {
+ const stream = controller[_stream];
+ let elementSize = 1;
+ let ctor = DataView;
+
+ if (
+ ObjectPrototypeIsPrototypeOf(Int8ArrayPrototype, view) ||
+ ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, view) ||
+ ObjectPrototypeIsPrototypeOf(Uint8ClampedArrayPrototype, view) ||
+ ObjectPrototypeIsPrototypeOf(Int16ArrayPrototype, view) ||
+ ObjectPrototypeIsPrototypeOf(Uint16ArrayPrototype, view) ||
+ ObjectPrototypeIsPrototypeOf(Int32ArrayPrototype, view) ||
+ ObjectPrototypeIsPrototypeOf(Uint32ArrayPrototype, view) ||
+ ObjectPrototypeIsPrototypeOf(BigInt64ArrayPrototype, view) ||
+ ObjectPrototypeIsPrototypeOf(BigUint64ArrayPrototype, view)
+ ) {
+ elementSize = view.constructor.BYTES_PER_ELEMENT;
+ ctor = view.constructor;
}
+ const byteOffset = view.byteOffset;
+ const byteLength = view.byteLength;
- /**
- * @param {ReadableStreamBYOBReader} reader
- */
- function readableStreamBYOBReaderRelease(reader) {
- readableStreamReaderGenericRelease(reader);
- const e = new TypeError("The reader was released.");
- readableStreamBYOBReaderErrorReadIntoRequests(reader, e);
- }
+ /** @type {ArrayBufferLike} */
+ let buffer;
- /**
- * @param {ReadableStreamBYOBReader} reader
- * @param {any} e
- */
- function readableStreamDefaultReaderErrorReadRequests(reader, e) {
- const readRequests = reader[_readRequests];
- reader[_readRequests] = [];
- for (let i = 0; i < readRequests.length; ++i) {
- const readRequest = readRequests[i];
- readRequest.errorSteps(e);
- }
+ try {
+ buffer = transferArrayBuffer(view.buffer);
+ } catch (e) {
+ readIntoRequest.errorSteps(e);
+ return;
}
- /**
- * @param {ReadableByteStreamController} controller
- */
- function readableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
- controller,
- ) {
- assert(!controller[_closeRequested]);
- while (controller[_pendingPullIntos].length !== 0) {
- if (controller[_queueTotalSize] === 0) {
- return;
- }
- const pullIntoDescriptor = controller[_pendingPullIntos][0];
- if (
- readableByteStreamControllerFillPullIntoDescriptorFromQueue(
- controller,
- pullIntoDescriptor,
- )
- ) {
- readableByteStreamControllerShiftPendingPullInto(controller);
- readableByteStreamControllerCommitPullIntoDescriptor(
- controller[_stream],
- pullIntoDescriptor,
- );
- }
- }
+ /** @type {PullIntoDescriptor} */
+ const pullIntoDescriptor = {
+ buffer,
+ bufferByteLength: buffer.byteLength,
+ byteOffset,
+ byteLength,
+ bytesFilled: 0,
+ elementSize,
+ viewConstructor: ctor,
+ readerType: "byob",
+ };
+
+ if (controller[_pendingPullIntos].length !== 0) {
+ ArrayPrototypePush(controller[_pendingPullIntos], pullIntoDescriptor);
+ readableStreamAddReadIntoRequest(stream, readIntoRequest);
+ return;
}
- /**
- * @param {ReadableByteStreamController} controller
- */
- function readableByteStreamControllerProcessReadRequestsUsingQueue(
- controller,
- ) {
- const reader = controller[_stream][_reader];
- assert(isReadableStreamDefaultReader(reader));
- while (reader[_readRequests].length !== 0) {
- if (controller[_queueTotalSize] === 0) {
- return;
- }
- const readRequest = ArrayPrototypeShift(reader[_readRequests]);
- readableByteStreamControllerFillReadRequestFromQueue(
- controller,
- readRequest,
- );
- }
+ if (stream[_state] === "closed") {
+ const emptyView = new ctor(
+ pullIntoDescriptor.buffer,
+ pullIntoDescriptor.byteOffset,
+ 0,
+ );
+ readIntoRequest.closeSteps(emptyView);
+ return;
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {ArrayBufferView} view
- * @param {ReadIntoRequest} readIntoRequest
- * @returns {void}
- */
- function readableByteStreamControllerPullInto(
- controller,
- view,
- readIntoRequest,
- ) {
- const stream = controller[_stream];
- let elementSize = 1;
- let ctor = DataView;
-
+ if (controller[_queueTotalSize] > 0) {
if (
- ObjectPrototypeIsPrototypeOf(Int8ArrayPrototype, view) ||
- ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, view) ||
- ObjectPrototypeIsPrototypeOf(Uint8ClampedArrayPrototype, view) ||
- ObjectPrototypeIsPrototypeOf(Int16ArrayPrototype, view) ||
- ObjectPrototypeIsPrototypeOf(Uint16ArrayPrototype, view) ||
- ObjectPrototypeIsPrototypeOf(Int32ArrayPrototype, view) ||
- ObjectPrototypeIsPrototypeOf(Uint32ArrayPrototype, view) ||
- ObjectPrototypeIsPrototypeOf(BigInt64ArrayPrototype, view) ||
- ObjectPrototypeIsPrototypeOf(BigUint64ArrayPrototype, view)
+ readableByteStreamControllerFillPullIntoDescriptorFromQueue(
+ controller,
+ pullIntoDescriptor,
+ )
) {
- elementSize = view.constructor.BYTES_PER_ELEMENT;
- ctor = view.constructor;
- }
- const byteOffset = view.byteOffset;
- const byteLength = view.byteLength;
-
- /** @type {ArrayBufferLike} */
- let buffer;
-
- try {
- buffer = transferArrayBuffer(view.buffer);
- } catch (e) {
- readIntoRequest.errorSteps(e);
- return;
- }
-
- /** @type {PullIntoDescriptor} */
- const pullIntoDescriptor = {
- buffer,
- bufferByteLength: buffer.byteLength,
- byteOffset,
- byteLength,
- bytesFilled: 0,
- elementSize,
- viewConstructor: ctor,
- readerType: "byob",
- };
-
- if (controller[_pendingPullIntos].length !== 0) {
- ArrayPrototypePush(controller[_pendingPullIntos], pullIntoDescriptor);
- readableStreamAddReadIntoRequest(stream, readIntoRequest);
+ const filledView = readableByteStreamControllerConvertPullIntoDescriptor(
+ pullIntoDescriptor,
+ );
+ readableByteStreamControllerHandleQueueDrain(controller);
+ readIntoRequest.chunkSteps(filledView);
return;
}
- if (stream[_state] === "closed") {
- const emptyView = new ctor(
- pullIntoDescriptor.buffer,
- pullIntoDescriptor.byteOffset,
- 0,
+ if (controller[_closeRequested]) {
+ const e = new TypeError(
+ "Insufficient bytes to fill elements in the given buffer",
);
- readIntoRequest.closeSteps(emptyView);
+ readableByteStreamControllerError(controller, e);
+ readIntoRequest.errorSteps(e);
return;
}
- if (controller[_queueTotalSize] > 0) {
- if (
- readableByteStreamControllerFillPullIntoDescriptorFromQueue(
- controller,
- pullIntoDescriptor,
- )
- ) {
- const filledView =
- readableByteStreamControllerConvertPullIntoDescriptor(
- pullIntoDescriptor,
- );
- readableByteStreamControllerHandleQueueDrain(controller);
- readIntoRequest.chunkSteps(filledView);
- return;
- }
- if (controller[_closeRequested]) {
- const e = new TypeError(
- "Insufficient bytes to fill elements in the given buffer",
- );
- readableByteStreamControllerError(controller, e);
- readIntoRequest.errorSteps(e);
- return;
- }
- }
- controller[_pendingPullIntos].push(pullIntoDescriptor);
- readableStreamAddReadIntoRequest(stream, readIntoRequest);
- readableByteStreamControllerCallPullIfNeeded(controller);
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {number} bytesWritten
- * @returns {void}
- */
- function readableByteStreamControllerRespond(controller, bytesWritten) {
- assert(controller[_pendingPullIntos].length !== 0);
- const firstDescriptor = controller[_pendingPullIntos][0];
- const state = controller[_stream][_state];
- if (state === "closed") {
- if (bytesWritten !== 0) {
- throw new TypeError(
- "bytesWritten must be 0 when calling respond() on a closed stream",
- );
- }
- } else {
- assert(state === "readable");
- if (bytesWritten === 0) {
- throw new TypeError(
- "bytesWritten must be greater than 0 when calling respond() on a readable stream",
- );
- }
- if (
- (firstDescriptor.bytesFilled + bytesWritten) >
- firstDescriptor.byteLength
- ) {
- throw new RangeError("bytesWritten out of range");
- }
+ controller[_pendingPullIntos].push(pullIntoDescriptor);
+ readableStreamAddReadIntoRequest(stream, readIntoRequest);
+ readableByteStreamControllerCallPullIfNeeded(controller);
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {number} bytesWritten
+ * @returns {void}
+ */
+function readableByteStreamControllerRespond(controller, bytesWritten) {
+ assert(controller[_pendingPullIntos].length !== 0);
+ const firstDescriptor = controller[_pendingPullIntos][0];
+ const state = controller[_stream][_state];
+ if (state === "closed") {
+ if (bytesWritten !== 0) {
+ throw new TypeError(
+ "bytesWritten must be 0 when calling respond() on a closed stream",
+ );
}
- firstDescriptor.buffer = transferArrayBuffer(firstDescriptor.buffer);
- readableByteStreamControllerRespondInternal(controller, bytesWritten);
- }
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {number} bytesWritten
- * @param {PullIntoDescriptor} pullIntoDescriptor
- * @returns {void}
- */
- function readableByteStreamControllerRespondInReadableState(
+ } else {
+ assert(state === "readable");
+ if (bytesWritten === 0) {
+ throw new TypeError(
+ "bytesWritten must be greater than 0 when calling respond() on a readable stream",
+ );
+ }
+ if (
+ (firstDescriptor.bytesFilled + bytesWritten) >
+ firstDescriptor.byteLength
+ ) {
+ throw new RangeError("bytesWritten out of range");
+ }
+ }
+ firstDescriptor.buffer = transferArrayBuffer(firstDescriptor.buffer);
+ readableByteStreamControllerRespondInternal(controller, bytesWritten);
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {number} bytesWritten
+ * @param {PullIntoDescriptor} pullIntoDescriptor
+ * @returns {void}
+ */
+function readableByteStreamControllerRespondInReadableState(
+ controller,
+ bytesWritten,
+ pullIntoDescriptor,
+) {
+ assert(
+ (pullIntoDescriptor.bytesFilled + bytesWritten) <=
+ pullIntoDescriptor.byteLength,
+ );
+ readableByteStreamControllerFillHeadPullIntoDescriptor(
controller,
bytesWritten,
pullIntoDescriptor,
- ) {
- assert(
- (pullIntoDescriptor.bytesFilled + bytesWritten) <=
- pullIntoDescriptor.byteLength,
- );
- readableByteStreamControllerFillHeadPullIntoDescriptor(
+ );
+ if (pullIntoDescriptor.readerType === "none") {
+ readableByteStreamControllerEnqueueDetachedPullIntoToQueue(
controller,
- bytesWritten,
- pullIntoDescriptor,
- );
- if (pullIntoDescriptor.readerType === "none") {
- readableByteStreamControllerEnqueueDetachedPullIntoToQueue(
- controller,
- pullIntoDescriptor,
- );
- readableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
- controller,
- );
- return;
- }
- if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) {
- return;
- }
- readableByteStreamControllerShiftPendingPullInto(controller);
- const remainderSize = pullIntoDescriptor.bytesFilled %
- pullIntoDescriptor.elementSize;
- if (remainderSize > 0) {
- const end = pullIntoDescriptor.byteOffset +
- pullIntoDescriptor.bytesFilled;
- readableByteStreamControllerEnqueueClonedChunkToQueue(
- controller,
- pullIntoDescriptor.buffer,
- end - remainderSize,
- remainderSize,
- );
- }
- pullIntoDescriptor.bytesFilled -= remainderSize;
- readableByteStreamControllerCommitPullIntoDescriptor(
- controller[_stream],
pullIntoDescriptor,
);
readableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
controller,
);
+ return;
+ }
+ if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) {
+ return;
+ }
+ readableByteStreamControllerShiftPendingPullInto(controller);
+ const remainderSize = pullIntoDescriptor.bytesFilled %
+ pullIntoDescriptor.elementSize;
+ if (remainderSize > 0) {
+ const end = pullIntoDescriptor.byteOffset +
+ pullIntoDescriptor.bytesFilled;
+ readableByteStreamControllerEnqueueClonedChunkToQueue(
+ controller,
+ pullIntoDescriptor.buffer,
+ end - remainderSize,
+ remainderSize,
+ );
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {number} bytesWritten
- * @returns {void}
- */
- function readableByteStreamControllerRespondInternal(
+ pullIntoDescriptor.bytesFilled -= remainderSize;
+ readableByteStreamControllerCommitPullIntoDescriptor(
+ controller[_stream],
+ pullIntoDescriptor,
+ );
+ readableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
controller,
- bytesWritten,
- ) {
- const firstDescriptor = controller[_pendingPullIntos][0];
- assert(canTransferArrayBuffer(firstDescriptor.buffer));
- readableByteStreamControllerInvalidateBYOBRequest(controller);
- const state = controller[_stream][_state];
- if (state === "closed") {
- assert(bytesWritten === 0);
- readableByteStreamControllerRespondInClosedState(
- controller,
- firstDescriptor,
- );
- } else {
- assert(state === "readable");
- assert(bytesWritten > 0);
- readableByteStreamControllerRespondInReadableState(
- controller,
- bytesWritten,
- firstDescriptor,
- );
- }
- readableByteStreamControllerCallPullIfNeeded(controller);
+ );
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {number} bytesWritten
+ * @returns {void}
+ */
+function readableByteStreamControllerRespondInternal(
+ controller,
+ bytesWritten,
+) {
+ const firstDescriptor = controller[_pendingPullIntos][0];
+ assert(canTransferArrayBuffer(firstDescriptor.buffer));
+ readableByteStreamControllerInvalidateBYOBRequest(controller);
+ const state = controller[_stream][_state];
+ if (state === "closed") {
+ assert(bytesWritten === 0);
+ readableByteStreamControllerRespondInClosedState(
+ controller,
+ firstDescriptor,
+ );
+ } else {
+ assert(state === "readable");
+ assert(bytesWritten > 0);
+ readableByteStreamControllerRespondInReadableState(
+ controller,
+ bytesWritten,
+ firstDescriptor,
+ );
}
-
- /**
- * @param {ReadableByteStreamController} controller
- */
- function readableByteStreamControllerInvalidateBYOBRequest(controller) {
- if (controller[_byobRequest] === null) {
- return;
- }
- controller[_byobRequest][_controller] = undefined;
- controller[_byobRequest][_view] = null;
- controller[_byobRequest] = null;
+ readableByteStreamControllerCallPullIfNeeded(controller);
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ */
+function readableByteStreamControllerInvalidateBYOBRequest(controller) {
+ if (controller[_byobRequest] === null) {
+ return;
+ }
+ controller[_byobRequest][_controller] = undefined;
+ controller[_byobRequest][_view] = null;
+ controller[_byobRequest] = null;
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {PullIntoDescriptor} firstDescriptor
+ */
+function readableByteStreamControllerRespondInClosedState(
+ controller,
+ firstDescriptor,
+) {
+ assert(firstDescriptor.bytesFilled === 0);
+ if (firstDescriptor.readerType === "none") {
+ readableByteStreamControllerShiftPendingPullInto(controller);
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {PullIntoDescriptor} firstDescriptor
- */
- function readableByteStreamControllerRespondInClosedState(
- controller,
- firstDescriptor,
- ) {
- assert(firstDescriptor.bytesFilled === 0);
- if (firstDescriptor.readerType === "none") {
- readableByteStreamControllerShiftPendingPullInto(controller);
- }
- const stream = controller[_stream];
- if (readableStreamHasBYOBReader(stream)) {
- while (readableStreamGetNumReadIntoRequests(stream) > 0) {
- const pullIntoDescriptor =
- readableByteStreamControllerShiftPendingPullInto(controller);
- readableByteStreamControllerCommitPullIntoDescriptor(
- stream,
- pullIntoDescriptor,
- );
- }
+ const stream = controller[_stream];
+ if (readableStreamHasBYOBReader(stream)) {
+ while (readableStreamGetNumReadIntoRequests(stream) > 0) {
+ const pullIntoDescriptor =
+ readableByteStreamControllerShiftPendingPullInto(controller);
+ readableByteStreamControllerCommitPullIntoDescriptor(
+ stream,
+ pullIntoDescriptor,
+ );
}
}
-
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @param {PullIntoDescriptor} pullIntoDescriptor
- */
- function readableByteStreamControllerCommitPullIntoDescriptor(
- stream,
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @param {PullIntoDescriptor} pullIntoDescriptor
+ */
+function readableByteStreamControllerCommitPullIntoDescriptor(
+ stream,
+ pullIntoDescriptor,
+) {
+ assert(stream[_state] !== "errored");
+ assert(pullIntoDescriptor.readerType !== "none");
+ let done = false;
+ if (stream[_state] === "closed") {
+ assert(pullIntoDescriptor.bytesFilled === 0);
+ done = true;
+ }
+ const filledView = readableByteStreamControllerConvertPullIntoDescriptor(
pullIntoDescriptor,
- ) {
- assert(stream[_state] !== "errored");
- assert(pullIntoDescriptor.readerType !== "none");
- let done = false;
- if (stream[_state] === "closed") {
- assert(pullIntoDescriptor.bytesFilled === 0);
- done = true;
- }
- const filledView = readableByteStreamControllerConvertPullIntoDescriptor(
- pullIntoDescriptor,
- );
- if (pullIntoDescriptor.readerType === "default") {
- readableStreamFulfillReadRequest(stream, filledView, done);
- } else {
- assert(pullIntoDescriptor.readerType === "byob");
- readableStreamFulfillReadIntoRequest(stream, filledView, done);
- }
- }
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {ArrayBufferView} view
- */
- function readableByteStreamControllerRespondWithNewView(controller, view) {
- assert(controller[_pendingPullIntos].length !== 0);
- assert(!isDetachedBuffer(view.buffer));
- const firstDescriptor = controller[_pendingPullIntos][0];
- const state = controller[_stream][_state];
- if (state === "closed") {
- if (view.byteLength !== 0) {
- throw new TypeError(
- "The view's length must be 0 when calling respondWithNewView() on a closed stream",
- );
- }
- } else {
- assert(state === "readable");
- if (view.byteLength === 0) {
- throw new TypeError(
- "The view's length must be greater than 0 when calling respondWithNewView() on a readable stream",
- );
- }
- }
- if (
- (firstDescriptor.byteOffset + firstDescriptor.bytesFilled) !==
- view.byteOffset
- ) {
- throw new RangeError(
- "The region specified by view does not match byobRequest",
- );
- }
- if (firstDescriptor.bufferByteLength !== view.buffer.byteLength) {
- throw new RangeError(
- "The buffer of view has different capacity than byobRequest",
+ );
+ if (pullIntoDescriptor.readerType === "default") {
+ readableStreamFulfillReadRequest(stream, filledView, done);
+ } else {
+ assert(pullIntoDescriptor.readerType === "byob");
+ readableStreamFulfillReadIntoRequest(stream, filledView, done);
+ }
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {ArrayBufferView} view
+ */
+function readableByteStreamControllerRespondWithNewView(controller, view) {
+ assert(controller[_pendingPullIntos].length !== 0);
+ assert(!isDetachedBuffer(view.buffer));
+ const firstDescriptor = controller[_pendingPullIntos][0];
+ const state = controller[_stream][_state];
+ if (state === "closed") {
+ if (view.byteLength !== 0) {
+ throw new TypeError(
+ "The view's length must be 0 when calling respondWithNewView() on a closed stream",
);
}
- if (
- (firstDescriptor.bytesFilled + view.byteLength) >
- firstDescriptor.byteLength
- ) {
- throw new RangeError(
- "The region specified by view is larger than byobRequest",
+ } else {
+ assert(state === "readable");
+ if (view.byteLength === 0) {
+ throw new TypeError(
+ "The view's length must be greater than 0 when calling respondWithNewView() on a readable stream",
);
}
- const viewByteLength = view.byteLength;
- firstDescriptor.buffer = transferArrayBuffer(view.buffer);
- readableByteStreamControllerRespondInternal(controller, viewByteLength);
- }
-
- /**
- * @param {ReadableByteStreamController} controller
- * @returns {PullIntoDescriptor}
- */
- function readableByteStreamControllerShiftPendingPullInto(controller) {
- assert(controller[_byobRequest] === null);
- return ArrayPrototypeShift(controller[_pendingPullIntos]);
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {PullIntoDescriptor} pullIntoDescriptor
- * @returns {boolean}
- */
- function readableByteStreamControllerFillPullIntoDescriptorFromQueue(
- controller,
- pullIntoDescriptor,
+ if (
+ (firstDescriptor.byteOffset + firstDescriptor.bytesFilled) !==
+ view.byteOffset
) {
- const elementSize = pullIntoDescriptor.elementSize;
- const currentAlignedBytes = pullIntoDescriptor.bytesFilled -
- (pullIntoDescriptor.bytesFilled % elementSize);
- const maxBytesToCopy = MathMin(
- controller[_queueTotalSize],
- pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled,
+ throw new RangeError(
+ "The region specified by view does not match byobRequest",
);
- const maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy;
- const maxAlignedBytes = maxBytesFilled - (maxBytesFilled % elementSize);
- let totalBytesToCopyRemaining = maxBytesToCopy;
- let ready = false;
- if (maxAlignedBytes > currentAlignedBytes) {
- totalBytesToCopyRemaining = maxAlignedBytes -
- pullIntoDescriptor.bytesFilled;
- ready = true;
- }
- const queue = controller[_queue];
- while (totalBytesToCopyRemaining > 0) {
- const headOfQueue = queue[0];
- const bytesToCopy = MathMin(
- totalBytesToCopyRemaining,
- headOfQueue.byteLength,
- );
- const destStart = pullIntoDescriptor.byteOffset +
- pullIntoDescriptor.bytesFilled;
-
- const destBuffer = new Uint8Array(
- pullIntoDescriptor.buffer,
- destStart,
- bytesToCopy,
- );
- const srcBuffer = new Uint8Array(
- headOfQueue.buffer,
- headOfQueue.byteOffset,
- bytesToCopy,
- );
- destBuffer.set(srcBuffer);
-
- if (headOfQueue.byteLength === bytesToCopy) {
- ArrayPrototypeShift(queue);
- } else {
- headOfQueue.byteOffset += bytesToCopy;
- headOfQueue.byteLength -= bytesToCopy;
- }
- controller[_queueTotalSize] -= bytesToCopy;
- readableByteStreamControllerFillHeadPullIntoDescriptor(
- controller,
- bytesToCopy,
- pullIntoDescriptor,
- );
- totalBytesToCopyRemaining -= bytesToCopy;
- }
- if (!ready) {
- assert(controller[_queueTotalSize] === 0);
- assert(pullIntoDescriptor.bytesFilled > 0);
- assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize);
- }
- return ready;
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {ReadRequest} readRequest
- * @returns {void}
- */
- function readableByteStreamControllerFillReadRequestFromQueue(
- controller,
- readRequest,
- ) {
- assert(controller[_queueTotalSize] > 0);
- const entry = ArrayPrototypeShift(controller[_queue]);
- controller[_queueTotalSize] -= entry.byteLength;
- readableByteStreamControllerHandleQueueDrain(controller);
- const view = new Uint8Array(
- entry.buffer,
- entry.byteOffset,
- entry.byteLength,
+ if (firstDescriptor.bufferByteLength !== view.buffer.byteLength) {
+ throw new RangeError(
+ "The buffer of view has different capacity than byobRequest",
);
- readRequest.chunkSteps(view);
}
-
- /**
- * @param {ReadableByteStreamController} controller
- * @param {number} size
- * @param {PullIntoDescriptor} pullIntoDescriptor
- * @returns {void}
- */
- function readableByteStreamControllerFillHeadPullIntoDescriptor(
- controller,
- size,
- pullIntoDescriptor,
+ if (
+ (firstDescriptor.bytesFilled + view.byteLength) >
+ firstDescriptor.byteLength
) {
- assert(
- controller[_pendingPullIntos].length === 0 ||
- controller[_pendingPullIntos][0] === pullIntoDescriptor,
+ throw new RangeError(
+ "The region specified by view is larger than byobRequest",
);
- assert(controller[_byobRequest] === null);
- pullIntoDescriptor.bytesFilled += size;
}
+ const viewByteLength = view.byteLength;
+ firstDescriptor.buffer = transferArrayBuffer(view.buffer);
+ readableByteStreamControllerRespondInternal(controller, viewByteLength);
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @returns {PullIntoDescriptor}
+ */
+function readableByteStreamControllerShiftPendingPullInto(controller) {
+ assert(controller[_byobRequest] === null);
+ return ArrayPrototypeShift(controller[_pendingPullIntos]);
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {PullIntoDescriptor} pullIntoDescriptor
+ * @returns {boolean}
+ */
+function readableByteStreamControllerFillPullIntoDescriptorFromQueue(
+ controller,
+ pullIntoDescriptor,
+) {
+ const elementSize = pullIntoDescriptor.elementSize;
+ const currentAlignedBytes = pullIntoDescriptor.bytesFilled -
+ (pullIntoDescriptor.bytesFilled % elementSize);
+ const maxBytesToCopy = MathMin(
+ controller[_queueTotalSize],
+ pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled,
+ );
+ const maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy;
+ const maxAlignedBytes = maxBytesFilled - (maxBytesFilled % elementSize);
+ let totalBytesToCopyRemaining = maxBytesToCopy;
+ let ready = false;
+ if (maxAlignedBytes > currentAlignedBytes) {
+ totalBytesToCopyRemaining = maxAlignedBytes -
+ pullIntoDescriptor.bytesFilled;
+ ready = true;
+ }
+ const queue = controller[_queue];
+ while (totalBytesToCopyRemaining > 0) {
+ const headOfQueue = queue[0];
+ const bytesToCopy = MathMin(
+ totalBytesToCopyRemaining,
+ headOfQueue.byteLength,
+ );
+ const destStart = pullIntoDescriptor.byteOffset +
+ pullIntoDescriptor.bytesFilled;
- /**
- * @param {PullIntoDescriptor} pullIntoDescriptor
- * @returns {ArrayBufferView}
- */
- function readableByteStreamControllerConvertPullIntoDescriptor(
- pullIntoDescriptor,
- ) {
- const bytesFilled = pullIntoDescriptor.bytesFilled;
- const elementSize = pullIntoDescriptor.elementSize;
- assert(bytesFilled <= pullIntoDescriptor.byteLength);
- assert((bytesFilled % elementSize) === 0);
- const buffer = transferArrayBuffer(pullIntoDescriptor.buffer);
- return new pullIntoDescriptor.viewConstructor(
- buffer,
- pullIntoDescriptor.byteOffset,
- bytesFilled / elementSize,
+ const destBuffer = new Uint8Array(
+ pullIntoDescriptor.buffer,
+ destStart,
+ bytesToCopy,
);
- }
+ const srcBuffer = new Uint8Array(
+ headOfQueue.buffer,
+ headOfQueue.byteOffset,
+ bytesToCopy,
+ );
+ destBuffer.set(srcBuffer);
- /**
- * @template R
- * @param {ReadableStreamDefaultReader<R>} reader
- * @param {ReadRequest<R>} readRequest
- * @returns {void}
- */
- function readableStreamDefaultReaderRead(reader, readRequest) {
- const stream = reader[_stream];
- assert(stream);
- stream[_disturbed] = true;
- if (stream[_state] === "closed") {
- readRequest.closeSteps();
- } else if (stream[_state] === "errored") {
- readRequest.errorSteps(stream[_storedError]);
+ if (headOfQueue.byteLength === bytesToCopy) {
+ ArrayPrototypeShift(queue);
} else {
- assert(stream[_state] === "readable");
- stream[_controller][_pullSteps](readRequest);
+ headOfQueue.byteOffset += bytesToCopy;
+ headOfQueue.byteLength -= bytesToCopy;
}
- }
-
- /**
- * @template R
- * @param {ReadableStreamDefaultReader<R>} reader
- */
- function readableStreamDefaultReaderRelease(reader) {
- readableStreamReaderGenericRelease(reader);
- const e = new TypeError("The reader was released.");
- readableStreamDefaultReaderErrorReadRequests(reader, e);
- }
-
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @param {any} e
- */
- function readableStreamError(stream, e) {
+ controller[_queueTotalSize] -= bytesToCopy;
+ readableByteStreamControllerFillHeadPullIntoDescriptor(
+ controller,
+ bytesToCopy,
+ pullIntoDescriptor,
+ );
+ totalBytesToCopyRemaining -= bytesToCopy;
+ }
+ if (!ready) {
+ assert(controller[_queueTotalSize] === 0);
+ assert(pullIntoDescriptor.bytesFilled > 0);
+ assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize);
+ }
+ return ready;
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {ReadRequest} readRequest
+ * @returns {void}
+ */
+function readableByteStreamControllerFillReadRequestFromQueue(
+ controller,
+ readRequest,
+) {
+ assert(controller[_queueTotalSize] > 0);
+ const entry = ArrayPrototypeShift(controller[_queue]);
+ controller[_queueTotalSize] -= entry.byteLength;
+ readableByteStreamControllerHandleQueueDrain(controller);
+ const view = new Uint8Array(
+ entry.buffer,
+ entry.byteOffset,
+ entry.byteLength,
+ );
+ readRequest.chunkSteps(view);
+}
+
+/**
+ * @param {ReadableByteStreamController} controller
+ * @param {number} size
+ * @param {PullIntoDescriptor} pullIntoDescriptor
+ * @returns {void}
+ */
+function readableByteStreamControllerFillHeadPullIntoDescriptor(
+ controller,
+ size,
+ pullIntoDescriptor,
+) {
+ assert(
+ controller[_pendingPullIntos].length === 0 ||
+ controller[_pendingPullIntos][0] === pullIntoDescriptor,
+ );
+ assert(controller[_byobRequest] === null);
+ pullIntoDescriptor.bytesFilled += size;
+}
+
+/**
+ * @param {PullIntoDescriptor} pullIntoDescriptor
+ * @returns {ArrayBufferView}
+ */
+function readableByteStreamControllerConvertPullIntoDescriptor(
+ pullIntoDescriptor,
+) {
+ const bytesFilled = pullIntoDescriptor.bytesFilled;
+ const elementSize = pullIntoDescriptor.elementSize;
+ assert(bytesFilled <= pullIntoDescriptor.byteLength);
+ assert((bytesFilled % elementSize) === 0);
+ const buffer = transferArrayBuffer(pullIntoDescriptor.buffer);
+ return new pullIntoDescriptor.viewConstructor(
+ buffer,
+ pullIntoDescriptor.byteOffset,
+ bytesFilled / elementSize,
+ );
+}
+
+/**
+ * @template R
+ * @param {ReadableStreamDefaultReader<R>} reader
+ * @param {ReadRequest<R>} readRequest
+ * @returns {void}
+ */
+function readableStreamDefaultReaderRead(reader, readRequest) {
+ const stream = reader[_stream];
+ assert(stream);
+ stream[_disturbed] = true;
+ if (stream[_state] === "closed") {
+ readRequest.closeSteps();
+ } else if (stream[_state] === "errored") {
+ readRequest.errorSteps(stream[_storedError]);
+ } else {
assert(stream[_state] === "readable");
- stream[_state] = "errored";
- stream[_storedError] = e;
- /** @type {ReadableStreamDefaultReader<R> | undefined} */
- const reader = stream[_reader];
- if (reader === undefined) {
- return;
- }
- /** @type {Deferred<void>} */
- const closedPromise = reader[_closedPromise];
- closedPromise.reject(e);
- setPromiseIsHandledToTrue(closedPromise.promise);
- if (isReadableStreamDefaultReader(reader)) {
- readableStreamDefaultReaderErrorReadRequests(reader, e);
- } else {
- assert(isReadableStreamBYOBReader(reader));
- readableStreamBYOBReaderErrorReadIntoRequests(reader, e);
- }
- }
-
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @param {R} chunk
- * @param {boolean} done
- */
- function readableStreamFulfillReadIntoRequest(stream, chunk, done) {
- assert(readableStreamHasBYOBReader(stream));
- /** @type {ReadableStreamDefaultReader<R>} */
- const reader = stream[_reader];
- assert(reader[_readIntoRequests].length !== 0);
- /** @type {ReadIntoRequest} */
- const readIntoRequest = ArrayPrototypeShift(reader[_readIntoRequests]);
- if (done) {
- readIntoRequest.closeSteps(chunk);
- } else {
- readIntoRequest.chunkSteps(chunk);
- }
- }
-
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @param {R} chunk
- * @param {boolean} done
- */
- function readableStreamFulfillReadRequest(stream, chunk, done) {
- assert(readableStreamHasDefaultReader(stream) === true);
- /** @type {ReadableStreamDefaultReader<R>} */
- const reader = stream[_reader];
- assert(reader[_readRequests].length);
- /** @type {ReadRequest<R>} */
- const readRequest = ArrayPrototypeShift(reader[_readRequests]);
- if (done) {
- readRequest.closeSteps();
- } else {
- readRequest.chunkSteps(chunk);
- }
+ stream[_controller][_pullSteps](readRequest);
+ }
+}
+
+/**
+ * @template R
+ * @param {ReadableStreamDefaultReader<R>} reader
+ */
+function readableStreamDefaultReaderRelease(reader) {
+ readableStreamReaderGenericRelease(reader);
+ const e = new TypeError("The reader was released.");
+ readableStreamDefaultReaderErrorReadRequests(reader, e);
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @param {any} e
+ */
+function readableStreamError(stream, e) {
+ assert(stream[_state] === "readable");
+ stream[_state] = "errored";
+ stream[_storedError] = e;
+ /** @type {ReadableStreamDefaultReader<R> | undefined} */
+ const reader = stream[_reader];
+ if (reader === undefined) {
+ return;
+ }
+ /** @type {Deferred<void>} */
+ const closedPromise = reader[_closedPromise];
+ closedPromise.reject(e);
+ setPromiseIsHandledToTrue(closedPromise.promise);
+ if (isReadableStreamDefaultReader(reader)) {
+ readableStreamDefaultReaderErrorReadRequests(reader, e);
+ } else {
+ assert(isReadableStreamBYOBReader(reader));
+ readableStreamBYOBReaderErrorReadIntoRequests(reader, e);
}
-
- /**
- * @param {ReadableStream} stream
- * @return {number}
- */
- function readableStreamGetNumReadIntoRequests(stream) {
- assert(readableStreamHasBYOBReader(stream) === true);
- return stream[_reader][_readIntoRequests].length;
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @param {R} chunk
+ * @param {boolean} done
+ */
+function readableStreamFulfillReadIntoRequest(stream, chunk, done) {
+ assert(readableStreamHasBYOBReader(stream));
+ /** @type {ReadableStreamDefaultReader<R>} */
+ const reader = stream[_reader];
+ assert(reader[_readIntoRequests].length !== 0);
+ /** @type {ReadIntoRequest} */
+ const readIntoRequest = ArrayPrototypeShift(reader[_readIntoRequests]);
+ if (done) {
+ readIntoRequest.closeSteps(chunk);
+ } else {
+ readIntoRequest.chunkSteps(chunk);
+ }
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @param {R} chunk
+ * @param {boolean} done
+ */
+function readableStreamFulfillReadRequest(stream, chunk, done) {
+ assert(readableStreamHasDefaultReader(stream) === true);
+ /** @type {ReadableStreamDefaultReader<R>} */
+ const reader = stream[_reader];
+ assert(reader[_readRequests].length);
+ /** @type {ReadRequest<R>} */
+ const readRequest = ArrayPrototypeShift(reader[_readRequests]);
+ if (done) {
+ readRequest.closeSteps();
+ } else {
+ readRequest.chunkSteps(chunk);
+ }
+}
+
+/**
+ * @param {ReadableStream} stream
+ * @return {number}
+ */
+function readableStreamGetNumReadIntoRequests(stream) {
+ assert(readableStreamHasBYOBReader(stream) === true);
+ return stream[_reader][_readIntoRequests].length;
+}
+
+/**
+ * @param {ReadableStream} stream
+ * @return {number}
+ */
+function readableStreamGetNumReadRequests(stream) {
+ assert(readableStreamHasDefaultReader(stream) === true);
+ return stream[_reader][_readRequests].length;
+}
+
+/**
+ * @param {ReadableStream} stream
+ * @returns {boolean}
+ */
+function readableStreamHasBYOBReader(stream) {
+ const reader = stream[_reader];
+ if (reader === undefined) {
+ return false;
}
-
- /**
- * @param {ReadableStream} stream
- * @return {number}
- */
- function readableStreamGetNumReadRequests(stream) {
- assert(readableStreamHasDefaultReader(stream) === true);
- return stream[_reader][_readRequests].length;
+ if (isReadableStreamBYOBReader(reader)) {
+ return true;
}
+ return false;
+}
- /**
- * @param {ReadableStream} stream
- * @returns {boolean}
- */
- function readableStreamHasBYOBReader(stream) {
- const reader = stream[_reader];
- if (reader === undefined) {
- return false;
- }
- if (isReadableStreamBYOBReader(reader)) {
- return true;
- }
+/**
+ * @param {ReadableStream} stream
+ * @returns {boolean}
+ */
+function readableStreamHasDefaultReader(stream) {
+ const reader = stream[_reader];
+ if (reader === undefined) {
return false;
}
-
- /**
- * @param {ReadableStream} stream
- * @returns {boolean}
- */
- function readableStreamHasDefaultReader(stream) {
- const reader = stream[_reader];
- if (reader === undefined) {
- return false;
- }
- if (isReadableStreamDefaultReader(reader)) {
- return true;
- }
- return false;
+ if (isReadableStreamDefaultReader(reader)) {
+ return true;
}
-
- /**
- * @template T
- * @param {ReadableStream<T>} source
- * @param {WritableStream<T>} dest
- * @param {boolean} preventClose
- * @param {boolean} preventAbort
- * @param {boolean} preventCancel
- * @param {AbortSignal=} signal
- * @returns {Promise<void>}
- */
- function readableStreamPipeTo(
- source,
- dest,
- preventClose,
- preventAbort,
- preventCancel,
- signal,
- ) {
- assert(isReadableStream(source));
- assert(isWritableStream(dest));
- assert(
- typeof preventClose === "boolean" && typeof preventAbort === "boolean" &&
- typeof preventCancel === "boolean",
- );
- assert(
- signal === undefined ||
- ObjectPrototypeIsPrototypeOf(AbortSignalPrototype, signal),
- );
- assert(!isReadableStreamLocked(source));
- assert(!isWritableStreamLocked(dest));
- // We use acquireReadableStreamDefaultReader even in case of ReadableByteStreamController
- // as the spec allows us, and the only reason to use BYOBReader is to do some smart things
- // with it, but the spec does not specify what things, so to simplify we stick to DefaultReader.
- const reader = acquireReadableStreamDefaultReader(source);
- const writer = acquireWritableStreamDefaultWriter(dest);
- source[_disturbed] = true;
- let shuttingDown = false;
- let currentWrite = resolvePromiseWith(undefined);
- /** @type {Deferred<void>} */
- const promise = new Deferred();
- /** @type {() => void} */
- let abortAlgorithm;
- if (signal) {
- abortAlgorithm = () => {
- const error = signal.reason;
- /** @type {Array<() => Promise<void>>} */
- const actions = [];
- if (preventAbort === false) {
- ArrayPrototypePush(actions, () => {
- if (dest[_state] === "writable") {
- return writableStreamAbort(dest, error);
- } else {
- return resolvePromiseWith(undefined);
- }
- });
- }
- if (preventCancel === false) {
- ArrayPrototypePush(actions, () => {
- if (source[_state] === "readable") {
- return readableStreamCancel(source, error);
- } else {
- return resolvePromiseWith(undefined);
- }
- });
- }
- shutdownWithAction(
- () =>
- SafePromiseAll(ArrayPrototypeMap(actions, (action) => action())),
- true,
- error,
- );
- };
-
- if (signal.aborted) {
- abortAlgorithm();
- return promise.promise;
+ return false;
+}
+
+/**
+ * @template T
+ * @param {ReadableStream<T>} source
+ * @param {WritableStream<T>} dest
+ * @param {boolean} preventClose
+ * @param {boolean} preventAbort
+ * @param {boolean} preventCancel
+ * @param {AbortSignal=} signal
+ * @returns {Promise<void>}
+ */
+function readableStreamPipeTo(
+ source,
+ dest,
+ preventClose,
+ preventAbort,
+ preventCancel,
+ signal,
+) {
+ assert(isReadableStream(source));
+ assert(isWritableStream(dest));
+ assert(
+ typeof preventClose === "boolean" && typeof preventAbort === "boolean" &&
+ typeof preventCancel === "boolean",
+ );
+ assert(
+ signal === undefined ||
+ ObjectPrototypeIsPrototypeOf(AbortSignalPrototype, signal),
+ );
+ assert(!isReadableStreamLocked(source));
+ assert(!isWritableStreamLocked(dest));
+ // We use acquireReadableStreamDefaultReader even in case of ReadableByteStreamController
+ // as the spec allows us, and the only reason to use BYOBReader is to do some smart things
+ // with it, but the spec does not specify what things, so to simplify we stick to DefaultReader.
+ const reader = acquireReadableStreamDefaultReader(source);
+ const writer = acquireWritableStreamDefaultWriter(dest);
+ source[_disturbed] = true;
+ let shuttingDown = false;
+ let currentWrite = resolvePromiseWith(undefined);
+ /** @type {Deferred<void>} */
+ const promise = new Deferred();
+ /** @type {() => void} */
+ let abortAlgorithm;
+ if (signal) {
+ abortAlgorithm = () => {
+ const error = signal.reason;
+ /** @type {Array<() => Promise<void>>} */
+ const actions = [];
+ if (preventAbort === false) {
+ ArrayPrototypePush(actions, () => {
+ if (dest[_state] === "writable") {
+ return writableStreamAbort(dest, error);
+ } else {
+ return resolvePromiseWith(undefined);
+ }
+ });
}
- signal[add](abortAlgorithm);
- }
-
- function pipeLoop() {
- return new Promise((resolveLoop, rejectLoop) => {
- /** @param {boolean} done */
- function next(done) {
- if (done) {
- resolveLoop();
+ if (preventCancel === false) {
+ ArrayPrototypePush(actions, () => {
+ if (source[_state] === "readable") {
+ return readableStreamCancel(source, error);
} else {
- uponPromise(pipeStep(), next, rejectLoop);
+ return resolvePromiseWith(undefined);
}
- }
- next(false);
- });
- }
-
- /** @returns {Promise<boolean>} */
- function pipeStep() {
- if (shuttingDown === true) {
- return resolvePromiseWith(true);
+ });
}
+ shutdownWithAction(
+ () => SafePromiseAll(ArrayPrototypeMap(actions, (action) => action())),
+ true,
+ error,
+ );
+ };
- return transformPromiseWith(writer[_readyPromise].promise, () => {
- return new Promise((resolveRead, rejectRead) => {
- readableStreamDefaultReaderRead(
- reader,
- {
- chunkSteps(chunk) {
- currentWrite = transformPromiseWith(
- writableStreamDefaultWriterWrite(writer, chunk),
- undefined,
- () => {},
- );
- resolveRead(false);
- },
- closeSteps() {
- resolveRead(true);
- },
- errorSteps: rejectRead,
- },
- );
- });
- });
+ if (signal.aborted) {
+ abortAlgorithm();
+ return promise.promise;
}
+ signal[add](abortAlgorithm);
+ }
- isOrBecomesErrored(
- source,
- reader[_closedPromise].promise,
- (storedError) => {
- if (preventAbort === false) {
- shutdownWithAction(
- () => writableStreamAbort(dest, storedError),
- true,
- storedError,
- );
+ function pipeLoop() {
+ return new Promise((resolveLoop, rejectLoop) => {
+ /** @param {boolean} done */
+ function next(done) {
+ if (done) {
+ resolveLoop();
} else {
- shutdown(true, storedError);
+ uponPromise(pipeStep(), next, rejectLoop);
}
- },
- );
-
- isOrBecomesErrored(dest, writer[_closedPromise].promise, (storedError) => {
- if (preventCancel === false) {
- shutdownWithAction(
- () => readableStreamCancel(source, storedError),
- true,
- storedError,
- );
- } else {
- shutdown(true, storedError);
}
+ next(false);
});
+ }
+
+ /** @returns {Promise<boolean>} */
+ function pipeStep() {
+ if (shuttingDown === true) {
+ return resolvePromiseWith(true);
+ }
- isOrBecomesClosed(source, reader[_closedPromise].promise, () => {
- if (preventClose === false) {
- shutdownWithAction(() =>
- writableStreamDefaultWriterCloseWithErrorPropagation(writer)
+ return transformPromiseWith(writer[_readyPromise].promise, () => {
+ return new Promise((resolveRead, rejectRead) => {
+ readableStreamDefaultReaderRead(
+ reader,
+ {
+ chunkSteps(chunk) {
+ currentWrite = transformPromiseWith(
+ writableStreamDefaultWriterWrite(writer, chunk),
+ undefined,
+ () => {},
+ );
+ resolveRead(false);
+ },
+ closeSteps() {
+ resolveRead(true);
+ },
+ errorSteps: rejectRead,
+ },
);
- } else {
- shutdown();
- }
+ });
});
+ }
- if (
- writableStreamCloseQueuedOrInFlight(dest) === true ||
- dest[_state] === "closed"
- ) {
- const destClosed = new TypeError(
- "The destination writable stream closed before all the data could be piped to it.",
- );
- if (preventCancel === false) {
+ isOrBecomesErrored(
+ source,
+ reader[_closedPromise].promise,
+ (storedError) => {
+ if (preventAbort === false) {
shutdownWithAction(
- () => readableStreamCancel(source, destClosed),
+ () => writableStreamAbort(dest, storedError),
true,
- destClosed,
+ storedError,
);
} else {
- shutdown(true, destClosed);
+ shutdown(true, storedError);
}
- }
-
- setPromiseIsHandledToTrue(pipeLoop());
-
- return promise.promise;
+ },
+ );
- /** @returns {Promise<void>} */
- function waitForWritesToFinish() {
- const oldCurrentWrite = currentWrite;
- return transformPromiseWith(
- currentWrite,
- () =>
- oldCurrentWrite !== currentWrite
- ? waitForWritesToFinish()
- : undefined,
+ isOrBecomesErrored(dest, writer[_closedPromise].promise, (storedError) => {
+ if (preventCancel === false) {
+ shutdownWithAction(
+ () => readableStreamCancel(source, storedError),
+ true,
+ storedError,
);
+ } else {
+ shutdown(true, storedError);
}
+ });
- /**
- * @param {ReadableStream | WritableStream} stream
- * @param {Promise<any>} promise
- * @param {(e: any) => void} action
- */
- function isOrBecomesErrored(stream, promise, action) {
- if (stream[_state] === "errored") {
- action(stream[_storedError]);
- } else {
- uponRejection(promise, action);
- }
- }
-
- /**
- * @param {ReadableStream} stream
- * @param {Promise<any>} promise
- * @param {() => void} action
- */
- function isOrBecomesClosed(stream, promise, action) {
- if (stream[_state] === "closed") {
- action();
- } else {
- uponFulfillment(promise, action);
- }
+ isOrBecomesClosed(source, reader[_closedPromise].promise, () => {
+ if (preventClose === false) {
+ shutdownWithAction(() =>
+ writableStreamDefaultWriterCloseWithErrorPropagation(writer)
+ );
+ } else {
+ shutdown();
}
+ });
- /**
- * @param {() => Promise<void[] | void>} action
- * @param {boolean=} originalIsError
- * @param {any=} originalError
- */
- function shutdownWithAction(action, originalIsError, originalError) {
- function doTheRest() {
- uponPromise(
- action(),
- () => finalize(originalIsError, originalError),
- (newError) => finalize(true, newError),
- );
- }
-
- if (shuttingDown === true) {
- return;
- }
- shuttingDown = true;
-
- if (
- dest[_state] === "writable" &&
- writableStreamCloseQueuedOrInFlight(dest) === false
- ) {
- uponFulfillment(waitForWritesToFinish(), doTheRest);
- } else {
- doTheRest();
- }
+ if (
+ writableStreamCloseQueuedOrInFlight(dest) === true ||
+ dest[_state] === "closed"
+ ) {
+ const destClosed = new TypeError(
+ "The destination writable stream closed before all the data could be piped to it.",
+ );
+ if (preventCancel === false) {
+ shutdownWithAction(
+ () => readableStreamCancel(source, destClosed),
+ true,
+ destClosed,
+ );
+ } else {
+ shutdown(true, destClosed);
}
+ }
- /**
- * @param {boolean=} isError
- * @param {any=} error
- */
- function shutdown(isError, error) {
- if (shuttingDown) {
- return;
- }
- shuttingDown = true;
- if (
- dest[_state] === "writable" &&
- writableStreamCloseQueuedOrInFlight(dest) === false
- ) {
- uponFulfillment(
- waitForWritesToFinish(),
- () => finalize(isError, error),
- );
- } else {
- finalize(isError, error);
- }
- }
+ setPromiseIsHandledToTrue(pipeLoop());
- /**
- * @param {boolean=} isError
- * @param {any=} error
- */
- function finalize(isError, error) {
- writableStreamDefaultWriterRelease(writer);
- readableStreamDefaultReaderRelease(reader);
+ return promise.promise;
- if (signal !== undefined) {
- signal[remove](abortAlgorithm);
- }
- if (isError) {
- promise.reject(error);
- } else {
- promise.resolve(undefined);
- }
- }
+ /** @returns {Promise<void>} */
+ function waitForWritesToFinish() {
+ const oldCurrentWrite = currentWrite;
+ return transformPromiseWith(
+ currentWrite,
+ () =>
+ oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : undefined,
+ );
}
/**
- * @param {ReadableStreamGenericReader<any> | ReadableStreamBYOBReader} reader
- * @param {any} reason
- * @returns {Promise<void>}
+ * @param {ReadableStream | WritableStream} stream
+ * @param {Promise<any>} promise
+ * @param {(e: any) => void} action
*/
- function readableStreamReaderGenericCancel(reader, reason) {
- const stream = reader[_stream];
- assert(stream !== undefined);
- return readableStreamCancel(stream, reason);
+ function isOrBecomesErrored(stream, promise, action) {
+ if (stream[_state] === "errored") {
+ action(stream[_storedError]);
+ } else {
+ uponRejection(promise, action);
+ }
}
/**
- * @template R
- * @param {ReadableStreamDefaultReader<R> | ReadableStreamBYOBReader} reader
- * @param {ReadableStream<R>} stream
+ * @param {ReadableStream} stream
+ * @param {Promise<any>} promise
+ * @param {() => void} action
*/
- function readableStreamReaderGenericInitialize(reader, stream) {
- reader[_stream] = stream;
- stream[_reader] = reader;
- if (stream[_state] === "readable") {
- reader[_closedPromise] = new Deferred();
- } else if (stream[_state] === "closed") {
- reader[_closedPromise] = new Deferred();
- reader[_closedPromise].resolve(undefined);
+ function isOrBecomesClosed(stream, promise, action) {
+ if (stream[_state] === "closed") {
+ action();
} else {
- assert(stream[_state] === "errored");
- reader[_closedPromise] = new Deferred();
- reader[_closedPromise].reject(stream[_storedError]);
- setPromiseIsHandledToTrue(reader[_closedPromise].promise);
+ uponFulfillment(promise, action);
}
}
/**
- * @template R
- * @param {ReadableStreamGenericReader<R> | ReadableStreamBYOBReader} reader
+ * @param {() => Promise<void[] | void>} action
+ * @param {boolean=} originalIsError
+ * @param {any=} originalError
*/
- function readableStreamReaderGenericRelease(reader) {
- const stream = reader[_stream];
- assert(stream !== undefined);
- assert(stream[_reader] === reader);
- if (stream[_state] === "readable") {
- reader[_closedPromise].reject(
- new TypeError(
- "Reader was released and can no longer be used to monitor the stream's closedness.",
- ),
- );
- } else {
- reader[_closedPromise] = new Deferred();
- reader[_closedPromise].reject(
- new TypeError(
- "Reader was released and can no longer be used to monitor the stream's closedness.",
- ),
+ function shutdownWithAction(action, originalIsError, originalError) {
+ function doTheRest() {
+ uponPromise(
+ action(),
+ () => finalize(originalIsError, originalError),
+ (newError) => finalize(true, newError),
);
}
- setPromiseIsHandledToTrue(reader[_closedPromise].promise);
- stream[_controller][_releaseSteps]();
- stream[_reader] = undefined;
- reader[_stream] = undefined;
- }
- /**
- * @param {ReadableStreamBYOBReader} reader
- * @param {any} e
- */
- function readableStreamBYOBReaderErrorReadIntoRequests(reader, e) {
- const readIntoRequests = reader[_readIntoRequests];
- reader[_readIntoRequests] = [];
- for (let i = 0; i < readIntoRequests.length; ++i) {
- const readIntoRequest = readIntoRequests[i];
- readIntoRequest.errorSteps(e);
+ if (shuttingDown === true) {
+ return;
+ }
+ shuttingDown = true;
+
+ if (
+ dest[_state] === "writable" &&
+ writableStreamCloseQueuedOrInFlight(dest) === false
+ ) {
+ uponFulfillment(waitForWritesToFinish(), doTheRest);
+ } else {
+ doTheRest();
}
}
/**
- * @template R
- * @param {ReadableStream<R>} stream
- * @param {boolean} cloneForBranch2
- * @returns {[ReadableStream<R>, ReadableStream<R>]}
+ * @param {boolean=} isError
+ * @param {any=} error
*/
- function readableStreamTee(stream, cloneForBranch2) {
- assert(isReadableStream(stream));
- assert(typeof cloneForBranch2 === "boolean");
+ function shutdown(isError, error) {
+ if (shuttingDown) {
+ return;
+ }
+ shuttingDown = true;
if (
- ObjectPrototypeIsPrototypeOf(
- ReadableByteStreamControllerPrototype,
- stream[_controller],
- )
+ dest[_state] === "writable" &&
+ writableStreamCloseQueuedOrInFlight(dest) === false
) {
- return readableByteStreamTee(stream);
+ uponFulfillment(
+ waitForWritesToFinish(),
+ () => finalize(isError, error),
+ );
} else {
- return readableStreamDefaultTee(stream, cloneForBranch2);
+ finalize(isError, error);
}
}
/**
- * @template R
- * @param {ReadableStream<R>} stream
- * @param {boolean} cloneForBranch2
- * @returns {[ReadableStream<R>, ReadableStream<R>]}
+ * @param {boolean=} isError
+ * @param {any=} error
*/
- function readableStreamDefaultTee(stream, cloneForBranch2) {
- assert(isReadableStream(stream));
- assert(typeof cloneForBranch2 === "boolean");
- const reader = acquireReadableStreamDefaultReader(stream);
- let reading = false;
- let readAgain = false;
- let canceled1 = false;
- let canceled2 = false;
- /** @type {any} */
- let reason1;
- /** @type {any} */
- let reason2;
- /** @type {ReadableStream<R>} */
- // deno-lint-ignore prefer-const
- let branch1;
- /** @type {ReadableStream<R>} */
- // deno-lint-ignore prefer-const
- let branch2;
+ function finalize(isError, error) {
+ writableStreamDefaultWriterRelease(writer);
+ readableStreamDefaultReaderRelease(reader);
- /** @type {Deferred<void>} */
- const cancelPromise = new Deferred();
+ if (signal !== undefined) {
+ signal[remove](abortAlgorithm);
+ }
+ if (isError) {
+ promise.reject(error);
+ } else {
+ promise.resolve(undefined);
+ }
+ }
+}
+
+/**
+ * @param {ReadableStreamGenericReader<any> | ReadableStreamBYOBReader} reader
+ * @param {any} reason
+ * @returns {Promise<void>}
+ */
+function readableStreamReaderGenericCancel(reader, reason) {
+ const stream = reader[_stream];
+ assert(stream !== undefined);
+ return readableStreamCancel(stream, reason);
+}
+
+/**
+ * @template R
+ * @param {ReadableStreamDefaultReader<R> | ReadableStreamBYOBReader} reader
+ * @param {ReadableStream<R>} stream
+ */
+function readableStreamReaderGenericInitialize(reader, stream) {
+ reader[_stream] = stream;
+ stream[_reader] = reader;
+ if (stream[_state] === "readable") {
+ reader[_closedPromise] = new Deferred();
+ } else if (stream[_state] === "closed") {
+ reader[_closedPromise] = new Deferred();
+ reader[_closedPromise].resolve(undefined);
+ } else {
+ assert(stream[_state] === "errored");
+ reader[_closedPromise] = new Deferred();
+ reader[_closedPromise].reject(stream[_storedError]);
+ setPromiseIsHandledToTrue(reader[_closedPromise].promise);
+ }
+}
+
+/**
+ * @template R
+ * @param {ReadableStreamGenericReader<R> | ReadableStreamBYOBReader} reader
+ */
+function readableStreamReaderGenericRelease(reader) {
+ const stream = reader[_stream];
+ assert(stream !== undefined);
+ assert(stream[_reader] === reader);
+ if (stream[_state] === "readable") {
+ reader[_closedPromise].reject(
+ new TypeError(
+ "Reader was released and can no longer be used to monitor the stream's closedness.",
+ ),
+ );
+ } else {
+ reader[_closedPromise] = new Deferred();
+ reader[_closedPromise].reject(
+ new TypeError(
+ "Reader was released and can no longer be used to monitor the stream's closedness.",
+ ),
+ );
+ }
+ setPromiseIsHandledToTrue(reader[_closedPromise].promise);
+ stream[_controller][_releaseSteps]();
+ stream[_reader] = undefined;
+ reader[_stream] = undefined;
+}
+
+/**
+ * @param {ReadableStreamBYOBReader} reader
+ * @param {any} e
+ */
+function readableStreamBYOBReaderErrorReadIntoRequests(reader, e) {
+ const readIntoRequests = reader[_readIntoRequests];
+ reader[_readIntoRequests] = [];
+ for (let i = 0; i < readIntoRequests.length; ++i) {
+ const readIntoRequest = readIntoRequests[i];
+ readIntoRequest.errorSteps(e);
+ }
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @param {boolean} cloneForBranch2
+ * @returns {[ReadableStream<R>, ReadableStream<R>]}
+ */
+function readableStreamTee(stream, cloneForBranch2) {
+ assert(isReadableStream(stream));
+ assert(typeof cloneForBranch2 === "boolean");
+ if (
+ ObjectPrototypeIsPrototypeOf(
+ ReadableByteStreamControllerPrototype,
+ stream[_controller],
+ )
+ ) {
+ return readableByteStreamTee(stream);
+ } else {
+ return readableStreamDefaultTee(stream, cloneForBranch2);
+ }
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @param {boolean} cloneForBranch2
+ * @returns {[ReadableStream<R>, ReadableStream<R>]}
+ */
+function readableStreamDefaultTee(stream, cloneForBranch2) {
+ assert(isReadableStream(stream));
+ assert(typeof cloneForBranch2 === "boolean");
+ const reader = acquireReadableStreamDefaultReader(stream);
+ let reading = false;
+ let readAgain = false;
+ let canceled1 = false;
+ let canceled2 = false;
+ /** @type {any} */
+ let reason1;
+ /** @type {any} */
+ let reason2;
+ /** @type {ReadableStream<R>} */
+ // deno-lint-ignore prefer-const
+ let branch1;
+ /** @type {ReadableStream<R>} */
+ // deno-lint-ignore prefer-const
+ let branch2;
+
+ /** @type {Deferred<void>} */
+ const cancelPromise = new Deferred();
+
+ function pullAlgorithm() {
+ if (reading === true) {
+ readAgain = true;
+ return resolvePromiseWith(undefined);
+ }
+ reading = true;
+ /** @type {ReadRequest<R>} */
+ const readRequest = {
+ chunkSteps(value) {
+ queueMicrotask(() => {
+ readAgain = false;
+ const value1 = value;
+ const value2 = value;
- function pullAlgorithm() {
- if (reading === true) {
- readAgain = true;
- return resolvePromiseWith(undefined);
- }
- reading = true;
- /** @type {ReadRequest<R>} */
- const readRequest = {
- chunkSteps(value) {
- queueMicrotask(() => {
- readAgain = false;
- const value1 = value;
- const value2 = value;
-
- // TODO(lucacasonato): respect clonedForBranch2.
-
- if (canceled1 === false) {
- readableStreamDefaultControllerEnqueue(
- /** @type {ReadableStreamDefaultController<any>} */ branch1[
- _controller
- ],
- value1,
- );
- }
- if (canceled2 === false) {
- readableStreamDefaultControllerEnqueue(
- /** @type {ReadableStreamDefaultController<any>} */ branch2[
- _controller
- ],
- value2,
- );
- }
+ // TODO(lucacasonato): respect clonedForBranch2.
- reading = false;
- if (readAgain === true) {
- pullAlgorithm();
- }
- });
- },
- closeSteps() {
- reading = false;
if (canceled1 === false) {
- readableStreamDefaultControllerClose(
+ readableStreamDefaultControllerEnqueue(
/** @type {ReadableStreamDefaultController<any>} */ branch1[
_controller
],
+ value1,
);
}
if (canceled2 === false) {
- readableStreamDefaultControllerClose(
+ readableStreamDefaultControllerEnqueue(
/** @type {ReadableStreamDefaultController<any>} */ branch2[
_controller
],
+ value2,
);
}
- if (canceled1 === false || canceled2 === false) {
- cancelPromise.resolve(undefined);
- }
- },
- errorSteps() {
+
reading = false;
- },
- };
- readableStreamDefaultReaderRead(reader, readRequest);
- return resolvePromiseWith(undefined);
+ if (readAgain === true) {
+ pullAlgorithm();
+ }
+ });
+ },
+ closeSteps() {
+ reading = false;
+ if (canceled1 === false) {
+ readableStreamDefaultControllerClose(
+ /** @type {ReadableStreamDefaultController<any>} */ branch1[
+ _controller
+ ],
+ );
+ }
+ if (canceled2 === false) {
+ readableStreamDefaultControllerClose(
+ /** @type {ReadableStreamDefaultController<any>} */ branch2[
+ _controller
+ ],
+ );
+ }
+ if (canceled1 === false || canceled2 === false) {
+ cancelPromise.resolve(undefined);
+ }
+ },
+ errorSteps() {
+ reading = false;
+ },
+ };
+ readableStreamDefaultReaderRead(reader, readRequest);
+ return resolvePromiseWith(undefined);
+ }
+
+ /**
+ * @param {any} reason
+ * @returns {Promise<void>}
+ */
+ function cancel1Algorithm(reason) {
+ canceled1 = true;
+ reason1 = reason;
+ if (canceled2 === true) {
+ const compositeReason = [reason1, reason2];
+ const cancelResult = readableStreamCancel(stream, compositeReason);
+ cancelPromise.resolve(cancelResult);
}
+ return cancelPromise.promise;
+ }
- /**
- * @param {any} reason
- * @returns {Promise<void>}
- */
- function cancel1Algorithm(reason) {
- canceled1 = true;
- reason1 = reason;
- if (canceled2 === true) {
- const compositeReason = [reason1, reason2];
- const cancelResult = readableStreamCancel(stream, compositeReason);
- cancelPromise.resolve(cancelResult);
- }
- return cancelPromise.promise;
- }
-
- /**
- * @param {any} reason
- * @returns {Promise<void>}
- */
- function cancel2Algorithm(reason) {
- canceled2 = true;
- reason2 = reason;
- if (canceled1 === true) {
- const compositeReason = [reason1, reason2];
- const cancelResult = readableStreamCancel(stream, compositeReason);
- cancelPromise.resolve(cancelResult);
- }
- return cancelPromise.promise;
+ /**
+ * @param {any} reason
+ * @returns {Promise<void>}
+ */
+ function cancel2Algorithm(reason) {
+ canceled2 = true;
+ reason2 = reason;
+ if (canceled1 === true) {
+ const compositeReason = [reason1, reason2];
+ const cancelResult = readableStreamCancel(stream, compositeReason);
+ cancelPromise.resolve(cancelResult);
}
+ return cancelPromise.promise;
+ }
- function startAlgorithm() {}
+ function startAlgorithm() {}
- branch1 = createReadableStream(
- startAlgorithm,
- pullAlgorithm,
- cancel1Algorithm,
+ branch1 = createReadableStream(
+ startAlgorithm,
+ pullAlgorithm,
+ cancel1Algorithm,
+ );
+ branch2 = createReadableStream(
+ startAlgorithm,
+ pullAlgorithm,
+ cancel2Algorithm,
+ );
+
+ uponRejection(reader[_closedPromise].promise, (r) => {
+ readableStreamDefaultControllerError(
+ /** @type {ReadableStreamDefaultController<any>} */ branch1[
+ _controller
+ ],
+ r,
);
- branch2 = createReadableStream(
- startAlgorithm,
- pullAlgorithm,
- cancel2Algorithm,
+ readableStreamDefaultControllerError(
+ /** @type {ReadableStreamDefaultController<any>} */ branch2[
+ _controller
+ ],
+ r,
);
+ if (canceled1 === false || canceled2 === false) {
+ cancelPromise.resolve(undefined);
+ }
+ });
- uponRejection(reader[_closedPromise].promise, (r) => {
- readableStreamDefaultControllerError(
- /** @type {ReadableStreamDefaultController<any>} */ branch1[
- _controller
- ],
- r,
- );
- readableStreamDefaultControllerError(
- /** @type {ReadableStreamDefaultController<any>} */ branch2[
- _controller
- ],
- r,
- );
- if (canceled1 === false || canceled2 === false) {
+ return [branch1, branch2];
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @returns {[ReadableStream<R>, ReadableStream<R>]}
+ */
+function readableByteStreamTee(stream) {
+ assert(isReadableStream(stream));
+ assert(
+ ObjectPrototypeIsPrototypeOf(
+ ReadableByteStreamControllerPrototype,
+ stream[_controller],
+ ),
+ );
+ let reader = acquireReadableStreamDefaultReader(stream);
+ let reading = false;
+ let readAgainForBranch1 = false;
+ let readAgainForBranch2 = false;
+ let canceled1 = false;
+ let canceled2 = false;
+ let reason1 = undefined;
+ let reason2 = undefined;
+ let branch1 = undefined;
+ let branch2 = undefined;
+ /** @type {Deferred<void>} */
+ const cancelPromise = new Deferred();
+
+ /**
+ * @param {ReadableStreamBYOBReader} thisReader
+ */
+ function forwardReaderError(thisReader) {
+ PromisePrototypeCatch(thisReader[_closedPromise].promise, (e) => {
+ if (thisReader !== reader) {
+ return;
+ }
+ readableByteStreamControllerError(branch1[_controller], e);
+ readableByteStreamControllerError(branch2[_controller], e);
+ if (!canceled1 || !canceled2) {
cancelPromise.resolve(undefined);
}
});
-
- return [branch1, branch2];
}
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @returns {[ReadableStream<R>, ReadableStream<R>]}
- */
- function readableByteStreamTee(stream) {
- assert(isReadableStream(stream));
- assert(
- ObjectPrototypeIsPrototypeOf(
- ReadableByteStreamControllerPrototype,
- stream[_controller],
- ),
- );
- let reader = acquireReadableStreamDefaultReader(stream);
- let reading = false;
- let readAgainForBranch1 = false;
- let readAgainForBranch2 = false;
- let canceled1 = false;
- let canceled2 = false;
- let reason1 = undefined;
- let reason2 = undefined;
- let branch1 = undefined;
- let branch2 = undefined;
- /** @type {Deferred<void>} */
- const cancelPromise = new Deferred();
-
- /**
- * @param {ReadableStreamBYOBReader} thisReader
- */
- function forwardReaderError(thisReader) {
- PromisePrototypeCatch(thisReader[_closedPromise].promise, (e) => {
- if (thisReader !== reader) {
- return;
- }
- readableByteStreamControllerError(branch1[_controller], e);
- readableByteStreamControllerError(branch2[_controller], e);
- if (!canceled1 || !canceled2) {
- cancelPromise.resolve(undefined);
- }
- });
- }
-
- function pullWithDefaultReader() {
- if (isReadableStreamBYOBReader(reader)) {
- assert(reader[_readIntoRequests].length === 0);
- readableStreamBYOBReaderRelease(reader);
- reader = acquireReadableStreamDefaultReader(stream);
- forwardReaderError(reader);
- }
-
- /** @type {ReadRequest} */
- const readRequest = {
- chunkSteps(chunk) {
- queueMicrotask(() => {
- readAgainForBranch1 = false;
- readAgainForBranch2 = false;
- const chunk1 = chunk;
- let chunk2 = chunk;
- if (!canceled1 && !canceled2) {
- try {
- chunk2 = cloneAsUint8Array(chunk);
- } catch (e) {
- readableByteStreamControllerError(branch1[_controller], e);
- readableByteStreamControllerError(branch2[_controller], e);
- cancelPromise.resolve(readableStreamCancel(stream, e));
- return;
- }
- }
- if (!canceled1) {
- readableByteStreamControllerEnqueue(branch1[_controller], chunk1);
- }
- if (!canceled2) {
- readableByteStreamControllerEnqueue(branch2[_controller], chunk2);
- }
- reading = false;
- if (readAgainForBranch1) {
- pull1Algorithm();
- } else if (readAgainForBranch2) {
- pull2Algorithm();
+ function pullWithDefaultReader() {
+ if (isReadableStreamBYOBReader(reader)) {
+ assert(reader[_readIntoRequests].length === 0);
+ readableStreamBYOBReaderRelease(reader);
+ reader = acquireReadableStreamDefaultReader(stream);
+ forwardReaderError(reader);
+ }
+
+ /** @type {ReadRequest} */
+ const readRequest = {
+ chunkSteps(chunk) {
+ queueMicrotask(() => {
+ readAgainForBranch1 = false;
+ readAgainForBranch2 = false;
+ const chunk1 = chunk;
+ let chunk2 = chunk;
+ if (!canceled1 && !canceled2) {
+ try {
+ chunk2 = cloneAsUint8Array(chunk);
+ } catch (e) {
+ readableByteStreamControllerError(branch1[_controller], e);
+ readableByteStreamControllerError(branch2[_controller], e);
+ cancelPromise.resolve(readableStreamCancel(stream, e));
+ return;
}
- });
- },
- closeSteps() {
- reading = false;
+ }
if (!canceled1) {
- readableByteStreamControllerClose(branch1[_controller]);
+ readableByteStreamControllerEnqueue(branch1[_controller], chunk1);
}
if (!canceled2) {
- readableByteStreamControllerClose(branch2[_controller]);
- }
- if (branch1[_controller][_pendingPullIntos].length !== 0) {
- readableByteStreamControllerRespond(branch1[_controller], 0);
+ readableByteStreamControllerEnqueue(branch2[_controller], chunk2);
}
- if (branch2[_controller][_pendingPullIntos].length !== 0) {
- readableByteStreamControllerRespond(branch2[_controller], 0);
- }
- if (!canceled1 || !canceled2) {
- cancelPromise.resolve(undefined);
- }
- },
- errorSteps() {
reading = false;
- },
- };
- readableStreamDefaultReaderRead(reader, readRequest);
- }
+ if (readAgainForBranch1) {
+ pull1Algorithm();
+ } else if (readAgainForBranch2) {
+ pull2Algorithm();
+ }
+ });
+ },
+ closeSteps() {
+ reading = false;
+ if (!canceled1) {
+ readableByteStreamControllerClose(branch1[_controller]);
+ }
+ if (!canceled2) {
+ readableByteStreamControllerClose(branch2[_controller]);
+ }
+ if (branch1[_controller][_pendingPullIntos].length !== 0) {
+ readableByteStreamControllerRespond(branch1[_controller], 0);
+ }
+ if (branch2[_controller][_pendingPullIntos].length !== 0) {
+ readableByteStreamControllerRespond(branch2[_controller], 0);
+ }
+ if (!canceled1 || !canceled2) {
+ cancelPromise.resolve(undefined);
+ }
+ },
+ errorSteps() {
+ reading = false;
+ },
+ };
+ readableStreamDefaultReaderRead(reader, readRequest);
+ }
- function pullWithBYOBReader(view, forBranch2) {
- if (isReadableStreamDefaultReader(reader)) {
- assert(reader[_readRequests].length === 0);
- readableStreamDefaultReaderRelease(reader);
- reader = acquireReadableStreamBYOBReader(stream);
- forwardReaderError(reader);
- }
- const byobBranch = forBranch2 ? branch2 : branch1;
- const otherBranch = forBranch2 ? branch1 : branch2;
+ function pullWithBYOBReader(view, forBranch2) {
+ if (isReadableStreamDefaultReader(reader)) {
+ assert(reader[_readRequests].length === 0);
+ readableStreamDefaultReaderRelease(reader);
+ reader = acquireReadableStreamBYOBReader(stream);
+ forwardReaderError(reader);
+ }
+ const byobBranch = forBranch2 ? branch2 : branch1;
+ const otherBranch = forBranch2 ? branch1 : branch2;
- /** @type {ReadIntoRequest} */
- const readIntoRequest = {
- chunkSteps(chunk) {
- queueMicrotask(() => {
- readAgainForBranch1 = false;
- readAgainForBranch2 = false;
- const byobCanceled = forBranch2 ? canceled2 : canceled1;
- const otherCanceled = forBranch2 ? canceled1 : canceled2;
- if (!otherCanceled) {
- let clonedChunk;
- try {
- clonedChunk = cloneAsUint8Array(chunk);
- } catch (e) {
- readableByteStreamControllerError(byobBranch[_controller], e);
- readableByteStreamControllerError(otherBranch[_controller], e);
- cancelPromise.resolve(readableStreamCancel(stream, e));
- return;
- }
- if (!byobCanceled) {
- readableByteStreamControllerRespondWithNewView(
- byobBranch[_controller],
- chunk,
- );
- }
- readableByteStreamControllerEnqueue(
- otherBranch[_controller],
- clonedChunk,
- );
- } else if (!byobCanceled) {
- readableByteStreamControllerRespondWithNewView(
- byobBranch[_controller],
- chunk,
- );
- }
- reading = false;
- if (readAgainForBranch1) {
- pull1Algorithm();
- } else if (readAgainForBranch2) {
- pull2Algorithm();
- }
- });
- },
- closeSteps(chunk) {
- reading = false;
+ /** @type {ReadIntoRequest} */
+ const readIntoRequest = {
+ chunkSteps(chunk) {
+ queueMicrotask(() => {
+ readAgainForBranch1 = false;
+ readAgainForBranch2 = false;
const byobCanceled = forBranch2 ? canceled2 : canceled1;
const otherCanceled = forBranch2 ? canceled1 : canceled2;
- if (!byobCanceled) {
- readableByteStreamControllerClose(byobBranch[_controller]);
- }
if (!otherCanceled) {
- readableByteStreamControllerClose(otherBranch[_controller]);
- }
- if (chunk !== undefined) {
- assert(chunk.byteLength === 0);
+ let clonedChunk;
+ try {
+ clonedChunk = cloneAsUint8Array(chunk);
+ } catch (e) {
+ readableByteStreamControllerError(byobBranch[_controller], e);
+ readableByteStreamControllerError(otherBranch[_controller], e);
+ cancelPromise.resolve(readableStreamCancel(stream, e));
+ return;
+ }
if (!byobCanceled) {
readableByteStreamControllerRespondWithNewView(
byobBranch[_controller],
chunk,
);
}
- if (
- !otherCanceled &&
- otherBranch[_controller][_pendingPullIntos].length !== 0
- ) {
- readableByteStreamControllerRespond(otherBranch[_controller], 0);
- }
- }
- if (!byobCanceled || !otherCanceled) {
- cancelPromise.resolve(undefined);
+ readableByteStreamControllerEnqueue(
+ otherBranch[_controller],
+ clonedChunk,
+ );
+ } else if (!byobCanceled) {
+ readableByteStreamControllerRespondWithNewView(
+ byobBranch[_controller],
+ chunk,
+ );
}
- },
- errorSteps() {
reading = false;
- },
- };
- readableStreamBYOBReaderRead(reader, view, readIntoRequest);
- }
+ if (readAgainForBranch1) {
+ pull1Algorithm();
+ } else if (readAgainForBranch2) {
+ pull2Algorithm();
+ }
+ });
+ },
+ closeSteps(chunk) {
+ reading = false;
+ const byobCanceled = forBranch2 ? canceled2 : canceled1;
+ const otherCanceled = forBranch2 ? canceled1 : canceled2;
+ if (!byobCanceled) {
+ readableByteStreamControllerClose(byobBranch[_controller]);
+ }
+ if (!otherCanceled) {
+ readableByteStreamControllerClose(otherBranch[_controller]);
+ }
+ if (chunk !== undefined) {
+ assert(chunk.byteLength === 0);
+ if (!byobCanceled) {
+ readableByteStreamControllerRespondWithNewView(
+ byobBranch[_controller],
+ chunk,
+ );
+ }
+ if (
+ !otherCanceled &&
+ otherBranch[_controller][_pendingPullIntos].length !== 0
+ ) {
+ readableByteStreamControllerRespond(otherBranch[_controller], 0);
+ }
+ }
+ if (!byobCanceled || !otherCanceled) {
+ cancelPromise.resolve(undefined);
+ }
+ },
+ errorSteps() {
+ reading = false;
+ },
+ };
+ readableStreamBYOBReaderRead(reader, view, readIntoRequest);
+ }
- function pull1Algorithm() {
- if (reading) {
- readAgainForBranch1 = true;
- return PromiseResolve(undefined);
- }
- reading = true;
- const byobRequest = readableByteStreamControllerGetBYOBRequest(
- branch1[_controller],
- );
- if (byobRequest === null) {
- pullWithDefaultReader();
- } else {
- pullWithBYOBReader(byobRequest[_view], false);
- }
+ function pull1Algorithm() {
+ if (reading) {
+ readAgainForBranch1 = true;
return PromiseResolve(undefined);
}
+ reading = true;
+ const byobRequest = readableByteStreamControllerGetBYOBRequest(
+ branch1[_controller],
+ );
+ if (byobRequest === null) {
+ pullWithDefaultReader();
+ } else {
+ pullWithBYOBReader(byobRequest[_view], false);
+ }
+ return PromiseResolve(undefined);
+ }
- function pull2Algorithm() {
- if (reading) {
- readAgainForBranch2 = true;
- return PromiseResolve(undefined);
- }
- reading = true;
- const byobRequest = readableByteStreamControllerGetBYOBRequest(
- branch2[_controller],
- );
- if (byobRequest === null) {
- pullWithDefaultReader();
- } else {
- pullWithBYOBReader(byobRequest[_view], true);
- }
+ function pull2Algorithm() {
+ if (reading) {
+ readAgainForBranch2 = true;
return PromiseResolve(undefined);
}
-
- function cancel1Algorithm(reason) {
- canceled1 = true;
- reason1 = reason;
- if (canceled2) {
- const compositeReason = [reason1, reason2];
- const cancelResult = readableStreamCancel(stream, compositeReason);
- cancelPromise.resolve(cancelResult);
- }
- return cancelPromise.promise;
+ reading = true;
+ const byobRequest = readableByteStreamControllerGetBYOBRequest(
+ branch2[_controller],
+ );
+ if (byobRequest === null) {
+ pullWithDefaultReader();
+ } else {
+ pullWithBYOBReader(byobRequest[_view], true);
}
+ return PromiseResolve(undefined);
+ }
- function cancel2Algorithm(reason) {
- canceled2 = true;
- reason2 = reason;
- if (canceled1) {
- const compositeReason = [reason1, reason2];
- const cancelResult = readableStreamCancel(stream, compositeReason);
- cancelPromise.resolve(cancelResult);
- }
- return cancelPromise.promise;
+ function cancel1Algorithm(reason) {
+ canceled1 = true;
+ reason1 = reason;
+ if (canceled2) {
+ const compositeReason = [reason1, reason2];
+ const cancelResult = readableStreamCancel(stream, compositeReason);
+ cancelPromise.resolve(cancelResult);
}
+ return cancelPromise.promise;
+ }
- function startAlgorithm() {
- return undefined;
+ function cancel2Algorithm(reason) {
+ canceled2 = true;
+ reason2 = reason;
+ if (canceled1) {
+ const compositeReason = [reason1, reason2];
+ const cancelResult = readableStreamCancel(stream, compositeReason);
+ cancelPromise.resolve(cancelResult);
}
+ return cancelPromise.promise;
+ }
- branch1 = createReadableByteStream(
- startAlgorithm,
- pull1Algorithm,
- cancel1Algorithm,
- );
- branch2 = createReadableByteStream(
- startAlgorithm,
- pull2Algorithm,
- cancel2Algorithm,
- );
+ function startAlgorithm() {
+ return undefined;
+ }
- branch1[_original] = stream;
- branch2[_original] = stream;
+ branch1 = createReadableByteStream(
+ startAlgorithm,
+ pull1Algorithm,
+ cancel1Algorithm,
+ );
+ branch2 = createReadableByteStream(
+ startAlgorithm,
+ pull2Algorithm,
+ cancel2Algorithm,
+ );
- forwardReaderError(reader);
- return [branch1, branch2];
+ branch1[_original] = stream;
+ branch2[_original] = stream;
+
+ forwardReaderError(reader);
+ return [branch1, branch2];
+}
+
+/**
+ * @param {ReadableStream<ArrayBuffer>} stream
+ * @param {ReadableByteStreamController} controller
+ * @param {() => void} startAlgorithm
+ * @param {() => Promise<void>} pullAlgorithm
+ * @param {(reason: any) => Promise<void>} cancelAlgorithm
+ * @param {number} highWaterMark
+ * @param {number | undefined} autoAllocateChunkSize
+ */
+function setUpReadableByteStreamController(
+ stream,
+ controller,
+ startAlgorithm,
+ pullAlgorithm,
+ cancelAlgorithm,
+ highWaterMark,
+ autoAllocateChunkSize,
+) {
+ assert(stream[_controller] === undefined);
+ if (autoAllocateChunkSize !== undefined) {
+ assert(NumberIsInteger(autoAllocateChunkSize));
+ assert(autoAllocateChunkSize >= 0);
+ }
+ controller[_stream] = stream;
+ controller[_pullAgain] = controller[_pulling] = false;
+ controller[_byobRequest] = null;
+ resetQueue(controller);
+ controller[_closeRequested] = controller[_started] = false;
+ controller[_strategyHWM] = highWaterMark;
+ controller[_pullAlgorithm] = pullAlgorithm;
+ controller[_cancelAlgorithm] = cancelAlgorithm;
+ controller[_autoAllocateChunkSize] = autoAllocateChunkSize;
+ controller[_pendingPullIntos] = [];
+ stream[_controller] = controller;
+ const startResult = startAlgorithm();
+ const startPromise = resolvePromiseWith(startResult);
+ setPromiseIsHandledToTrue(
+ PromisePrototypeThen(
+ startPromise,
+ () => {
+ controller[_started] = true;
+ assert(controller[_pulling] === false);
+ assert(controller[_pullAgain] === false);
+ readableByteStreamControllerCallPullIfNeeded(controller);
+ },
+ (r) => {
+ readableByteStreamControllerError(controller, r);
+ },
+ ),
+ );
+}
+
+/**
+ * @param {ReadableStream<ArrayBuffer>} stream
+ * @param {UnderlyingSource<ArrayBuffer>} underlyingSource
+ * @param {UnderlyingSource<ArrayBuffer>} underlyingSourceDict
+ * @param {number} highWaterMark
+ */
+function setUpReadableByteStreamControllerFromUnderlyingSource(
+ stream,
+ underlyingSource,
+ underlyingSourceDict,
+ highWaterMark,
+) {
+ const controller = webidl.createBranded(ReadableByteStreamController);
+ /** @type {() => void} */
+ let startAlgorithm = () => undefined;
+ /** @type {() => Promise<void>} */
+ let pullAlgorithm = () => resolvePromiseWith(undefined);
+ /** @type {(reason: any) => Promise<void>} */
+ let cancelAlgorithm = (_reason) => resolvePromiseWith(undefined);
+ if (underlyingSourceDict.start !== undefined) {
+ startAlgorithm = () =>
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.start,
+ [controller],
+ underlyingSource,
+ webidl.converters.any,
+ {
+ prefix:
+ "Failed to call 'startAlgorithm' on 'ReadableByteStreamController'",
+ },
+ );
}
-
- /**
- * @param {ReadableStream<ArrayBuffer>} stream
- * @param {ReadableByteStreamController} controller
- * @param {() => void} startAlgorithm
- * @param {() => Promise<void>} pullAlgorithm
- * @param {(reason: any) => Promise<void>} cancelAlgorithm
- * @param {number} highWaterMark
- * @param {number | undefined} autoAllocateChunkSize
- */
- function setUpReadableByteStreamController(
+ if (underlyingSourceDict.pull !== undefined) {
+ pullAlgorithm = () =>
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.pull,
+ [controller],
+ underlyingSource,
+ webidl.converters["Promise<undefined>"],
+ {
+ prefix:
+ "Failed to call 'pullAlgorithm' on 'ReadableByteStreamController'",
+ returnsPromise: true,
+ },
+ );
+ }
+ if (underlyingSourceDict.cancel !== undefined) {
+ cancelAlgorithm = (reason) =>
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.cancel,
+ [reason],
+ underlyingSource,
+ webidl.converters["Promise<undefined>"],
+ {
+ prefix:
+ "Failed to call 'cancelAlgorithm' on 'ReadableByteStreamController'",
+ returnsPromise: true,
+ },
+ );
+ }
+ const autoAllocateChunkSize = underlyingSourceDict["autoAllocateChunkSize"];
+ if (autoAllocateChunkSize === 0) {
+ throw new TypeError("autoAllocateChunkSize must be greater than 0");
+ }
+ setUpReadableByteStreamController(
stream,
controller,
startAlgorithm,
@@ -3098,127 +3205,117 @@
cancelAlgorithm,
highWaterMark,
autoAllocateChunkSize,
- ) {
- assert(stream[_controller] === undefined);
- if (autoAllocateChunkSize !== undefined) {
- assert(NumberIsInteger(autoAllocateChunkSize));
- assert(autoAllocateChunkSize >= 0);
- }
- controller[_stream] = stream;
- controller[_pullAgain] = controller[_pulling] = false;
- controller[_byobRequest] = null;
- resetQueue(controller);
- controller[_closeRequested] = controller[_started] = false;
- controller[_strategyHWM] = highWaterMark;
- controller[_pullAlgorithm] = pullAlgorithm;
- controller[_cancelAlgorithm] = cancelAlgorithm;
- controller[_autoAllocateChunkSize] = autoAllocateChunkSize;
- controller[_pendingPullIntos] = [];
- stream[_controller] = controller;
- const startResult = startAlgorithm();
- const startPromise = resolvePromiseWith(startResult);
- setPromiseIsHandledToTrue(
- PromisePrototypeThen(
- startPromise,
- () => {
- controller[_started] = true;
- assert(controller[_pulling] === false);
- assert(controller[_pullAgain] === false);
- readableByteStreamControllerCallPullIfNeeded(controller);
+ );
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @param {ReadableStreamDefaultController<R>} controller
+ * @param {(controller: ReadableStreamDefaultController<R>) => void | Promise<void>} startAlgorithm
+ * @param {(controller: ReadableStreamDefaultController<R>) => Promise<void>} pullAlgorithm
+ * @param {(reason: any) => Promise<void>} cancelAlgorithm
+ * @param {number} highWaterMark
+ * @param {(chunk: R) => number} sizeAlgorithm
+ */
+function setUpReadableStreamDefaultController(
+ stream,
+ controller,
+ startAlgorithm,
+ pullAlgorithm,
+ cancelAlgorithm,
+ highWaterMark,
+ sizeAlgorithm,
+) {
+ assert(stream[_controller] === undefined);
+ controller[_stream] = stream;
+ resetQueue(controller);
+ controller[_started] =
+ controller[_closeRequested] =
+ controller[_pullAgain] =
+ controller[_pulling] =
+ false;
+ controller[_strategySizeAlgorithm] = sizeAlgorithm;
+ controller[_strategyHWM] = highWaterMark;
+ controller[_pullAlgorithm] = pullAlgorithm;
+ controller[_cancelAlgorithm] = cancelAlgorithm;
+ stream[_controller] = controller;
+ const startResult = startAlgorithm(controller);
+ const startPromise = resolvePromiseWith(startResult);
+ uponPromise(startPromise, () => {
+ controller[_started] = true;
+ assert(controller[_pulling] === false);
+ assert(controller[_pullAgain] === false);
+ readableStreamDefaultControllerCallPullIfNeeded(controller);
+ }, (r) => {
+ readableStreamDefaultControllerError(controller, r);
+ });
+}
+
+/**
+ * @template R
+ * @param {ReadableStream<R>} stream
+ * @param {UnderlyingSource<R>} underlyingSource
+ * @param {UnderlyingSource<R>} underlyingSourceDict
+ * @param {number} highWaterMark
+ * @param {(chunk: R) => number} sizeAlgorithm
+ */
+function setUpReadableStreamDefaultControllerFromUnderlyingSource(
+ stream,
+ underlyingSource,
+ underlyingSourceDict,
+ highWaterMark,
+ sizeAlgorithm,
+) {
+ const controller = webidl.createBranded(ReadableStreamDefaultController);
+ /** @type {() => Promise<void>} */
+ let startAlgorithm = () => undefined;
+ /** @type {() => Promise<void>} */
+ let pullAlgorithm = () => resolvePromiseWith(undefined);
+ /** @type {(reason?: any) => Promise<void>} */
+ let cancelAlgorithm = () => resolvePromiseWith(undefined);
+ if (underlyingSourceDict.start !== undefined) {
+ startAlgorithm = () =>
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.start,
+ [controller],
+ underlyingSource,
+ webidl.converters.any,
+ {
+ prefix:
+ "Failed to call 'startAlgorithm' on 'ReadableStreamDefaultController'",
},
- (r) => {
- readableByteStreamControllerError(controller, r);
+ );
+ }
+ if (underlyingSourceDict.pull !== undefined) {
+ pullAlgorithm = () =>
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.pull,
+ [controller],
+ underlyingSource,
+ webidl.converters["Promise<undefined>"],
+ {
+ prefix:
+ "Failed to call 'pullAlgorithm' on 'ReadableStreamDefaultController'",
+ returnsPromise: true,
},
- ),
- );
+ );
}
-
- /**
- * @param {ReadableStream<ArrayBuffer>} stream
- * @param {UnderlyingSource<ArrayBuffer>} underlyingSource
- * @param {UnderlyingSource<ArrayBuffer>} underlyingSourceDict
- * @param {number} highWaterMark
- */
- function setUpReadableByteStreamControllerFromUnderlyingSource(
- stream,
- underlyingSource,
- underlyingSourceDict,
- highWaterMark,
- ) {
- const controller = webidl.createBranded(ReadableByteStreamController);
- /** @type {() => void} */
- let startAlgorithm = () => undefined;
- /** @type {() => Promise<void>} */
- let pullAlgorithm = () => resolvePromiseWith(undefined);
- /** @type {(reason: any) => Promise<void>} */
- let cancelAlgorithm = (_reason) => resolvePromiseWith(undefined);
- if (underlyingSourceDict.start !== undefined) {
- startAlgorithm = () =>
- webidl.invokeCallbackFunction(
- underlyingSourceDict.start,
- [controller],
- underlyingSource,
- webidl.converters.any,
- {
- prefix:
- "Failed to call 'startAlgorithm' on 'ReadableByteStreamController'",
- },
- );
- }
- if (underlyingSourceDict.pull !== undefined) {
- pullAlgorithm = () =>
- webidl.invokeCallbackFunction(
- underlyingSourceDict.pull,
- [controller],
- underlyingSource,
- webidl.converters["Promise<undefined>"],
- {
- prefix:
- "Failed to call 'pullAlgorithm' on 'ReadableByteStreamController'",
- returnsPromise: true,
- },
- );
- }
- if (underlyingSourceDict.cancel !== undefined) {
- cancelAlgorithm = (reason) =>
- webidl.invokeCallbackFunction(
- underlyingSourceDict.cancel,
- [reason],
- underlyingSource,
- webidl.converters["Promise<undefined>"],
- {
- prefix:
- "Failed to call 'cancelAlgorithm' on 'ReadableByteStreamController'",
- returnsPromise: true,
- },
- );
- }
- const autoAllocateChunkSize = underlyingSourceDict["autoAllocateChunkSize"];
- if (autoAllocateChunkSize === 0) {
- throw new TypeError("autoAllocateChunkSize must be greater than 0");
- }
- setUpReadableByteStreamController(
- stream,
- controller,
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- highWaterMark,
- autoAllocateChunkSize,
- );
+ if (underlyingSourceDict.cancel !== undefined) {
+ cancelAlgorithm = (reason) =>
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.cancel,
+ [reason],
+ underlyingSource,
+ webidl.converters["Promise<undefined>"],
+ {
+ prefix:
+ "Failed to call 'cancelAlgorithm' on 'ReadableStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
-
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @param {ReadableStreamDefaultController<R>} controller
- * @param {(controller: ReadableStreamDefaultController<R>) => void | Promise<void>} startAlgorithm
- * @param {(controller: ReadableStreamDefaultController<R>) => Promise<void>} pullAlgorithm
- * @param {(reason: any) => Promise<void>} cancelAlgorithm
- * @param {number} highWaterMark
- * @param {(chunk: R) => number} sizeAlgorithm
- */
- function setUpReadableStreamDefaultController(
+ setUpReadableStreamDefaultController(
stream,
controller,
startAlgorithm,
@@ -3226,234 +3323,255 @@
cancelAlgorithm,
highWaterMark,
sizeAlgorithm,
+ );
+}
+
+/**
+ * @template R
+ * @param {ReadableStreamBYOBReader} reader
+ * @param {ReadableStream<R>} stream
+ */
+function setUpReadableStreamBYOBReader(reader, stream) {
+ if (isReadableStreamLocked(stream)) {
+ throw new TypeError("ReadableStream is locked.");
+ }
+ if (
+ !(ObjectPrototypeIsPrototypeOf(
+ ReadableByteStreamControllerPrototype,
+ stream[_controller],
+ ))
) {
- assert(stream[_controller] === undefined);
- controller[_stream] = stream;
- resetQueue(controller);
- controller[_started] =
- controller[_closeRequested] =
- controller[_pullAgain] =
- controller[_pulling] =
- false;
- controller[_strategySizeAlgorithm] = sizeAlgorithm;
- controller[_strategyHWM] = highWaterMark;
- controller[_pullAlgorithm] = pullAlgorithm;
- controller[_cancelAlgorithm] = cancelAlgorithm;
- stream[_controller] = controller;
- const startResult = startAlgorithm(controller);
- const startPromise = resolvePromiseWith(startResult);
- uponPromise(startPromise, () => {
- controller[_started] = true;
- assert(controller[_pulling] === false);
- assert(controller[_pullAgain] === false);
- readableStreamDefaultControllerCallPullIfNeeded(controller);
- }, (r) => {
- readableStreamDefaultControllerError(controller, r);
- });
- }
-
- /**
- * @template R
- * @param {ReadableStream<R>} stream
- * @param {UnderlyingSource<R>} underlyingSource
- * @param {UnderlyingSource<R>} underlyingSourceDict
- * @param {number} highWaterMark
- * @param {(chunk: R) => number} sizeAlgorithm
- */
- function setUpReadableStreamDefaultControllerFromUnderlyingSource(
- stream,
- underlyingSource,
- underlyingSourceDict,
- highWaterMark,
- sizeAlgorithm,
- ) {
- const controller = webidl.createBranded(ReadableStreamDefaultController);
- /** @type {() => Promise<void>} */
- let startAlgorithm = () => undefined;
- /** @type {() => Promise<void>} */
- let pullAlgorithm = () => resolvePromiseWith(undefined);
- /** @type {(reason?: any) => Promise<void>} */
- let cancelAlgorithm = () => resolvePromiseWith(undefined);
- if (underlyingSourceDict.start !== undefined) {
- startAlgorithm = () =>
- webidl.invokeCallbackFunction(
- underlyingSourceDict.start,
- [controller],
- underlyingSource,
- webidl.converters.any,
- {
- prefix:
- "Failed to call 'startAlgorithm' on 'ReadableStreamDefaultController'",
- },
- );
- }
- if (underlyingSourceDict.pull !== undefined) {
- pullAlgorithm = () =>
- webidl.invokeCallbackFunction(
- underlyingSourceDict.pull,
- [controller],
- underlyingSource,
- webidl.converters["Promise<undefined>"],
- {
- prefix:
- "Failed to call 'pullAlgorithm' on 'ReadableStreamDefaultController'",
- returnsPromise: true,
- },
- );
- }
- if (underlyingSourceDict.cancel !== undefined) {
- cancelAlgorithm = (reason) =>
- webidl.invokeCallbackFunction(
- underlyingSourceDict.cancel,
- [reason],
- underlyingSource,
- webidl.converters["Promise<undefined>"],
- {
- prefix:
- "Failed to call 'cancelAlgorithm' on 'ReadableStreamDefaultController'",
- returnsPromise: true,
- },
- );
- }
- setUpReadableStreamDefaultController(
- stream,
- controller,
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- highWaterMark,
- sizeAlgorithm,
- );
- }
-
- /**
- * @template R
- * @param {ReadableStreamBYOBReader} reader
- * @param {ReadableStream<R>} stream
- */
- function setUpReadableStreamBYOBReader(reader, stream) {
- if (isReadableStreamLocked(stream)) {
- throw new TypeError("ReadableStream is locked.");
- }
- if (
- !(ObjectPrototypeIsPrototypeOf(
- ReadableByteStreamControllerPrototype,
- stream[_controller],
- ))
- ) {
- throw new TypeError("Cannot use a BYOB reader with a non-byte stream");
+ throw new TypeError("Cannot use a BYOB reader with a non-byte stream");
+ }
+ readableStreamReaderGenericInitialize(reader, stream);
+ reader[_readIntoRequests] = [];
+}
+
+/**
+ * @template R
+ * @param {ReadableStreamDefaultReader<R>} reader
+ * @param {ReadableStream<R>} stream
+ */
+function setUpReadableStreamDefaultReader(reader, stream) {
+ if (isReadableStreamLocked(stream)) {
+ throw new TypeError("ReadableStream is locked.");
+ }
+ readableStreamReaderGenericInitialize(reader, stream);
+ reader[_readRequests] = [];
+}
+
+/**
+ * @template O
+ * @param {TransformStream<any, O>} stream
+ * @param {TransformStreamDefaultController<O>} controller
+ * @param {(chunk: O, controller: TransformStreamDefaultController<O>) => Promise<void>} transformAlgorithm
+ * @param {(controller: TransformStreamDefaultController<O>) => Promise<void>} flushAlgorithm
+ */
+function setUpTransformStreamDefaultController(
+ stream,
+ controller,
+ transformAlgorithm,
+ flushAlgorithm,
+) {
+ assert(ObjectPrototypeIsPrototypeOf(TransformStreamPrototype, stream));
+ assert(stream[_controller] === undefined);
+ controller[_stream] = stream;
+ stream[_controller] = controller;
+ controller[_transformAlgorithm] = transformAlgorithm;
+ controller[_flushAlgorithm] = flushAlgorithm;
+}
+
+/**
+ * @template I
+ * @template O
+ * @param {TransformStream<I, O>} stream
+ * @param {Transformer<I, O>} transformer
+ * @param {Transformer<I, O>} transformerDict
+ */
+function setUpTransformStreamDefaultControllerFromTransformer(
+ stream,
+ transformer,
+ transformerDict,
+) {
+ /** @type {TransformStreamDefaultController<O>} */
+ const controller = webidl.createBranded(TransformStreamDefaultController);
+ /** @type {(chunk: O, controller: TransformStreamDefaultController<O>) => Promise<void>} */
+ let transformAlgorithm = (chunk) => {
+ try {
+ transformStreamDefaultControllerEnqueue(controller, chunk);
+ } catch (e) {
+ return PromiseReject(e);
}
- readableStreamReaderGenericInitialize(reader, stream);
- reader[_readIntoRequests] = [];
+ return resolvePromiseWith(undefined);
+ };
+ /** @type {(controller: TransformStreamDefaultController<O>) => Promise<void>} */
+ let flushAlgorithm = () => resolvePromiseWith(undefined);
+ if (transformerDict.transform !== undefined) {
+ transformAlgorithm = (chunk, controller) =>
+ webidl.invokeCallbackFunction(
+ transformerDict.transform,
+ [chunk, controller],
+ transformer,
+ webidl.converters["Promise<undefined>"],
+ {
+ prefix:
+ "Failed to call 'transformAlgorithm' on 'TransformStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
-
- /**
- * @template R
- * @param {ReadableStreamDefaultReader<R>} reader
- * @param {ReadableStream<R>} stream
- */
- function setUpReadableStreamDefaultReader(reader, stream) {
- if (isReadableStreamLocked(stream)) {
- throw new TypeError("ReadableStream is locked.");
- }
- readableStreamReaderGenericInitialize(reader, stream);
- reader[_readRequests] = [];
+ if (transformerDict.flush !== undefined) {
+ flushAlgorithm = (controller) =>
+ webidl.invokeCallbackFunction(
+ transformerDict.flush,
+ [controller],
+ transformer,
+ webidl.converters["Promise<undefined>"],
+ {
+ prefix:
+ "Failed to call 'flushAlgorithm' on 'TransformStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
-
- /**
- * @template O
- * @param {TransformStream<any, O>} stream
- * @param {TransformStreamDefaultController<O>} controller
- * @param {(chunk: O, controller: TransformStreamDefaultController<O>) => Promise<void>} transformAlgorithm
- * @param {(controller: TransformStreamDefaultController<O>) => Promise<void>} flushAlgorithm
- */
- function setUpTransformStreamDefaultController(
+ setUpTransformStreamDefaultController(
stream,
controller,
transformAlgorithm,
flushAlgorithm,
- ) {
- assert(ObjectPrototypeIsPrototypeOf(TransformStreamPrototype, stream));
- assert(stream[_controller] === undefined);
- controller[_stream] = stream;
- stream[_controller] = controller;
- controller[_transformAlgorithm] = transformAlgorithm;
- controller[_flushAlgorithm] = flushAlgorithm;
+ );
+}
+
+/**
+ * @template W
+ * @param {WritableStream<W>} stream
+ * @param {WritableStreamDefaultController<W>} controller
+ * @param {(controller: WritableStreamDefaultController<W>) => Promise<void>} startAlgorithm
+ * @param {(chunk: W, controller: WritableStreamDefaultController<W>) => Promise<void>} writeAlgorithm
+ * @param {() => Promise<void>} closeAlgorithm
+ * @param {(reason?: any) => Promise<void>} abortAlgorithm
+ * @param {number} highWaterMark
+ * @param {(chunk: W) => number} sizeAlgorithm
+ */
+function setUpWritableStreamDefaultController(
+ stream,
+ controller,
+ startAlgorithm,
+ writeAlgorithm,
+ closeAlgorithm,
+ abortAlgorithm,
+ highWaterMark,
+ sizeAlgorithm,
+) {
+ assert(isWritableStream(stream));
+ assert(stream[_controller] === undefined);
+ controller[_stream] = stream;
+ stream[_controller] = controller;
+ resetQueue(controller);
+ controller[_signal] = newSignal();
+ controller[_started] = false;
+ controller[_strategySizeAlgorithm] = sizeAlgorithm;
+ controller[_strategyHWM] = highWaterMark;
+ controller[_writeAlgorithm] = writeAlgorithm;
+ controller[_closeAlgorithm] = closeAlgorithm;
+ controller[_abortAlgorithm] = abortAlgorithm;
+ const backpressure = writableStreamDefaultControllerGetBackpressure(
+ controller,
+ );
+ writableStreamUpdateBackpressure(stream, backpressure);
+ const startResult = startAlgorithm(controller);
+ const startPromise = resolvePromiseWith(startResult);
+ uponPromise(startPromise, () => {
+ assert(stream[_state] === "writable" || stream[_state] === "erroring");
+ controller[_started] = true;
+ writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
+ }, (r) => {
+ assert(stream[_state] === "writable" || stream[_state] === "erroring");
+ controller[_started] = true;
+ writableStreamDealWithRejection(stream, r);
+ });
+}
+
+/**
+ * @template W
+ * @param {WritableStream<W>} stream
+ * @param {UnderlyingSink<W>} underlyingSink
+ * @param {UnderlyingSink<W>} underlyingSinkDict
+ * @param {number} highWaterMark
+ * @param {(chunk: W) => number} sizeAlgorithm
+ */
+function setUpWritableStreamDefaultControllerFromUnderlyingSink(
+ stream,
+ underlyingSink,
+ underlyingSinkDict,
+ highWaterMark,
+ sizeAlgorithm,
+) {
+ const controller = webidl.createBranded(WritableStreamDefaultController);
+ /** @type {(controller: WritableStreamDefaultController<W>) => any} */
+ let startAlgorithm = () => undefined;
+ /** @type {(chunk: W, controller: WritableStreamDefaultController<W>) => Promise<void>} */
+ let writeAlgorithm = () => resolvePromiseWith(undefined);
+ let closeAlgorithm = () => resolvePromiseWith(undefined);
+ /** @type {(reason?: any) => Promise<void>} */
+ let abortAlgorithm = () => resolvePromiseWith(undefined);
+
+ if (underlyingSinkDict.start !== undefined) {
+ startAlgorithm = () =>
+ webidl.invokeCallbackFunction(
+ underlyingSinkDict.start,
+ [controller],
+ underlyingSink,
+ webidl.converters.any,
+ {
+ prefix:
+ "Failed to call 'startAlgorithm' on 'WritableStreamDefaultController'",
+ },
+ );
}
-
- /**
- * @template I
- * @template O
- * @param {TransformStream<I, O>} stream
- * @param {Transformer<I, O>} transformer
- * @param {Transformer<I, O>} transformerDict
- */
- function setUpTransformStreamDefaultControllerFromTransformer(
- stream,
- transformer,
- transformerDict,
- ) {
- /** @type {TransformStreamDefaultController<O>} */
- const controller = webidl.createBranded(TransformStreamDefaultController);
- /** @type {(chunk: O, controller: TransformStreamDefaultController<O>) => Promise<void>} */
- let transformAlgorithm = (chunk) => {
- try {
- transformStreamDefaultControllerEnqueue(controller, chunk);
- } catch (e) {
- return PromiseReject(e);
- }
- return resolvePromiseWith(undefined);
- };
- /** @type {(controller: TransformStreamDefaultController<O>) => Promise<void>} */
- let flushAlgorithm = () => resolvePromiseWith(undefined);
- if (transformerDict.transform !== undefined) {
- transformAlgorithm = (chunk, controller) =>
- webidl.invokeCallbackFunction(
- transformerDict.transform,
- [chunk, controller],
- transformer,
- webidl.converters["Promise<undefined>"],
- {
- prefix:
- "Failed to call 'transformAlgorithm' on 'TransformStreamDefaultController'",
- returnsPromise: true,
- },
- );
- }
- if (transformerDict.flush !== undefined) {
- flushAlgorithm = (controller) =>
- webidl.invokeCallbackFunction(
- transformerDict.flush,
- [controller],
- transformer,
- webidl.converters["Promise<undefined>"],
- {
- prefix:
- "Failed to call 'flushAlgorithm' on 'TransformStreamDefaultController'",
- returnsPromise: true,
- },
- );
- }
- setUpTransformStreamDefaultController(
- stream,
- controller,
- transformAlgorithm,
- flushAlgorithm,
- );
+ if (underlyingSinkDict.write !== undefined) {
+ writeAlgorithm = (chunk) =>
+ webidl.invokeCallbackFunction(
+ underlyingSinkDict.write,
+ [chunk, controller],
+ underlyingSink,
+ webidl.converters["Promise<undefined>"],
+ {
+ prefix:
+ "Failed to call 'writeAlgorithm' on 'WritableStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
-
- /**
- * @template W
- * @param {WritableStream<W>} stream
- * @param {WritableStreamDefaultController<W>} controller
- * @param {(controller: WritableStreamDefaultController<W>) => Promise<void>} startAlgorithm
- * @param {(chunk: W, controller: WritableStreamDefaultController<W>) => Promise<void>} writeAlgorithm
- * @param {() => Promise<void>} closeAlgorithm
- * @param {(reason?: any) => Promise<void>} abortAlgorithm
- * @param {number} highWaterMark
- * @param {(chunk: W) => number} sizeAlgorithm
- */
- function setUpWritableStreamDefaultController(
+ if (underlyingSinkDict.close !== undefined) {
+ closeAlgorithm = () =>
+ webidl.invokeCallbackFunction(
+ underlyingSinkDict.close,
+ [],
+ underlyingSink,
+ webidl.converters["Promise<undefined>"],
+ {
+ prefix:
+ "Failed to call 'closeAlgorithm' on 'WritableStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
+ }
+ if (underlyingSinkDict.abort !== undefined) {
+ abortAlgorithm = (reason) =>
+ webidl.invokeCallbackFunction(
+ underlyingSinkDict.abort,
+ [reason],
+ underlyingSink,
+ webidl.converters["Promise<undefined>"],
+ {
+ prefix:
+ "Failed to call 'abortAlgorithm' on 'WritableStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
+ }
+ setUpWritableStreamDefaultController(
stream,
controller,
startAlgorithm,
@@ -3462,2794 +3580,2671 @@
abortAlgorithm,
highWaterMark,
sizeAlgorithm,
- ) {
- assert(isWritableStream(stream));
- assert(stream[_controller] === undefined);
- controller[_stream] = stream;
- stream[_controller] = controller;
- resetQueue(controller);
- controller[_signal] = newSignal();
- controller[_started] = false;
- controller[_strategySizeAlgorithm] = sizeAlgorithm;
- controller[_strategyHWM] = highWaterMark;
- controller[_writeAlgorithm] = writeAlgorithm;
- controller[_closeAlgorithm] = closeAlgorithm;
- controller[_abortAlgorithm] = abortAlgorithm;
- const backpressure = writableStreamDefaultControllerGetBackpressure(
- controller,
- );
- writableStreamUpdateBackpressure(stream, backpressure);
- const startResult = startAlgorithm(controller);
- const startPromise = resolvePromiseWith(startResult);
- uponPromise(startPromise, () => {
- assert(stream[_state] === "writable" || stream[_state] === "erroring");
- controller[_started] = true;
- writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
- }, (r) => {
- assert(stream[_state] === "writable" || stream[_state] === "erroring");
- controller[_started] = true;
- writableStreamDealWithRejection(stream, r);
- });
- }
-
- /**
- * @template W
- * @param {WritableStream<W>} stream
- * @param {UnderlyingSink<W>} underlyingSink
- * @param {UnderlyingSink<W>} underlyingSinkDict
- * @param {number} highWaterMark
- * @param {(chunk: W) => number} sizeAlgorithm
- */
- function setUpWritableStreamDefaultControllerFromUnderlyingSink(
- stream,
- underlyingSink,
- underlyingSinkDict,
- highWaterMark,
- sizeAlgorithm,
- ) {
- const controller = webidl.createBranded(WritableStreamDefaultController);
- /** @type {(controller: WritableStreamDefaultController<W>) => any} */
- let startAlgorithm = () => undefined;
- /** @type {(chunk: W, controller: WritableStreamDefaultController<W>) => Promise<void>} */
- let writeAlgorithm = () => resolvePromiseWith(undefined);
- let closeAlgorithm = () => resolvePromiseWith(undefined);
- /** @type {(reason?: any) => Promise<void>} */
- let abortAlgorithm = () => resolvePromiseWith(undefined);
-
- if (underlyingSinkDict.start !== undefined) {
- startAlgorithm = () =>
- webidl.invokeCallbackFunction(
- underlyingSinkDict.start,
- [controller],
- underlyingSink,
- webidl.converters.any,
- {
- prefix:
- "Failed to call 'startAlgorithm' on 'WritableStreamDefaultController'",
- },
- );
- }
- if (underlyingSinkDict.write !== undefined) {
- writeAlgorithm = (chunk) =>
- webidl.invokeCallbackFunction(
- underlyingSinkDict.write,
- [chunk, controller],
- underlyingSink,
- webidl.converters["Promise<undefined>"],
- {
- prefix:
- "Failed to call 'writeAlgorithm' on 'WritableStreamDefaultController'",
- returnsPromise: true,
- },
- );
- }
- if (underlyingSinkDict.close !== undefined) {
- closeAlgorithm = () =>
- webidl.invokeCallbackFunction(
- underlyingSinkDict.close,
- [],
- underlyingSink,
- webidl.converters["Promise<undefined>"],
- {
- prefix:
- "Failed to call 'closeAlgorithm' on 'WritableStreamDefaultController'",
- returnsPromise: true,
- },
- );
- }
- if (underlyingSinkDict.abort !== undefined) {
- abortAlgorithm = (reason) =>
- webidl.invokeCallbackFunction(
- underlyingSinkDict.abort,
- [reason],
- underlyingSink,
- webidl.converters["Promise<undefined>"],
- {
- prefix:
- "Failed to call 'abortAlgorithm' on 'WritableStreamDefaultController'",
- returnsPromise: true,
- },
- );
- }
- setUpWritableStreamDefaultController(
- stream,
- controller,
- startAlgorithm,
- writeAlgorithm,
- closeAlgorithm,
- abortAlgorithm,
- highWaterMark,
- sizeAlgorithm,
- );
- }
-
- /**
- * @template W
- * @param {WritableStreamDefaultWriter<W>} writer
- * @param {WritableStream<W>} stream
- */
- function setUpWritableStreamDefaultWriter(writer, stream) {
- if (isWritableStreamLocked(stream) === true) {
- throw new TypeError("The stream is already locked.");
- }
- writer[_stream] = stream;
- stream[_writer] = writer;
- const state = stream[_state];
- if (state === "writable") {
- if (
- writableStreamCloseQueuedOrInFlight(stream) === false &&
- stream[_backpressure] === true
- ) {
- writer[_readyPromise] = new Deferred();
- } else {
- writer[_readyPromise] = new Deferred();
- writer[_readyPromise].resolve(undefined);
- }
- writer[_closedPromise] = new Deferred();
- } else if (state === "erroring") {
- writer[_readyPromise] = new Deferred();
- writer[_readyPromise].reject(stream[_storedError]);
- setPromiseIsHandledToTrue(writer[_readyPromise].promise);
- writer[_closedPromise] = new Deferred();
- } else if (state === "closed") {
+ );
+}
+
+/**
+ * @template W
+ * @param {WritableStreamDefaultWriter<W>} writer
+ * @param {WritableStream<W>} stream
+ */
+function setUpWritableStreamDefaultWriter(writer, stream) {
+ if (isWritableStreamLocked(stream) === true) {
+ throw new TypeError("The stream is already locked.");
+ }
+ writer[_stream] = stream;
+ stream[_writer] = writer;
+ const state = stream[_state];
+ if (state === "writable") {
+ if (
+ writableStreamCloseQueuedOrInFlight(stream) === false &&
+ stream[_backpressure] === true
+ ) {
writer[_readyPromise] = new Deferred();
- writer[_readyPromise].resolve(undefined);
- writer[_closedPromise] = new Deferred();
- writer[_closedPromise].resolve(undefined);
} else {
- assert(state === "errored");
- const storedError = stream[_storedError];
writer[_readyPromise] = new Deferred();
- writer[_readyPromise].reject(storedError);
- setPromiseIsHandledToTrue(writer[_readyPromise].promise);
- writer[_closedPromise] = new Deferred();
- writer[_closedPromise].reject(storedError);
- setPromiseIsHandledToTrue(writer[_closedPromise].promise);
+ writer[_readyPromise].resolve(undefined);
}
+ writer[_closedPromise] = new Deferred();
+ } else if (state === "erroring") {
+ writer[_readyPromise] = new Deferred();
+ writer[_readyPromise].reject(stream[_storedError]);
+ setPromiseIsHandledToTrue(writer[_readyPromise].promise);
+ writer[_closedPromise] = new Deferred();
+ } else if (state === "closed") {
+ writer[_readyPromise] = new Deferred();
+ writer[_readyPromise].resolve(undefined);
+ writer[_closedPromise] = new Deferred();
+ writer[_closedPromise].resolve(undefined);
+ } else {
+ assert(state === "errored");
+ const storedError = stream[_storedError];
+ writer[_readyPromise] = new Deferred();
+ writer[_readyPromise].reject(storedError);
+ setPromiseIsHandledToTrue(writer[_readyPromise].promise);
+ writer[_closedPromise] = new Deferred();
+ writer[_closedPromise].reject(storedError);
+ setPromiseIsHandledToTrue(writer[_closedPromise].promise);
}
-
- /** @param {TransformStreamDefaultController} controller */
- function transformStreamDefaultControllerClearAlgorithms(controller) {
- controller[_transformAlgorithm] = undefined;
- controller[_flushAlgorithm] = undefined;
+}
+
+/** @param {TransformStreamDefaultController} controller */
+function transformStreamDefaultControllerClearAlgorithms(controller) {
+ controller[_transformAlgorithm] = undefined;
+ controller[_flushAlgorithm] = undefined;
+}
+
+/**
+ * @template O
+ * @param {TransformStreamDefaultController<O>} controller
+ * @param {O} chunk
+ */
+function transformStreamDefaultControllerEnqueue(controller, chunk) {
+ const stream = controller[_stream];
+ const readableController = stream[_readable][_controller];
+ if (
+ readableStreamDefaultControllerCanCloseOrEnqueue(
+ /** @type {ReadableStreamDefaultController<O>} */ readableController,
+ ) === false
+ ) {
+ throw new TypeError("Readable stream is unavailable.");
}
-
- /**
- * @template O
- * @param {TransformStreamDefaultController<O>} controller
- * @param {O} chunk
- */
- function transformStreamDefaultControllerEnqueue(controller, chunk) {
- const stream = controller[_stream];
- const readableController = stream[_readable][_controller];
- if (
- readableStreamDefaultControllerCanCloseOrEnqueue(
- /** @type {ReadableStreamDefaultController<O>} */ readableController,
- ) === false
- ) {
- throw new TypeError("Readable stream is unavailable.");
- }
- try {
- readableStreamDefaultControllerEnqueue(
- /** @type {ReadableStreamDefaultController<O>} */ readableController,
- chunk,
- );
- } catch (e) {
- transformStreamErrorWritableAndUnblockWrite(stream, e);
- throw stream[_readable][_storedError];
- }
- const backpressure = readableStreamDefaultcontrollerHasBackpressure(
+ try {
+ readableStreamDefaultControllerEnqueue(
/** @type {ReadableStreamDefaultController<O>} */ readableController,
+ chunk,
);
- if (backpressure !== stream[_backpressure]) {
- assert(backpressure === true);
- transformStreamSetBackpressure(stream, true);
- }
- }
-
- /**
- * @param {TransformStreamDefaultController} controller
- * @param {any=} e
- */
- function transformStreamDefaultControllerError(controller, e) {
- transformStreamError(controller[_stream], e);
+ } catch (e) {
+ transformStreamErrorWritableAndUnblockWrite(stream, e);
+ throw stream[_readable][_storedError];
}
-
- /**
- * @template O
- * @param {TransformStreamDefaultController<O>} controller
- * @param {any} chunk
- * @returns {Promise<void>}
- */
- function transformStreamDefaultControllerPerformTransform(controller, chunk) {
- const transformPromise = controller[_transformAlgorithm](chunk, controller);
- return transformPromiseWith(transformPromise, undefined, (r) => {
- transformStreamError(controller[_stream], r);
- throw r;
- });
+ const backpressure = readableStreamDefaultcontrollerHasBackpressure(
+ /** @type {ReadableStreamDefaultController<O>} */ readableController,
+ );
+ if (backpressure !== stream[_backpressure]) {
+ assert(backpressure === true);
+ transformStreamSetBackpressure(stream, true);
}
-
- /** @param {TransformStreamDefaultController} controller */
- function transformStreamDefaultControllerTerminate(controller) {
- const stream = controller[_stream];
- const readableController = stream[_readable][_controller];
+}
+
+/**
+ * @param {TransformStreamDefaultController} controller
+ * @param {any=} e
+ */
+function transformStreamDefaultControllerError(controller, e) {
+ transformStreamError(controller[_stream], e);
+}
+
+/**
+ * @template O
+ * @param {TransformStreamDefaultController<O>} controller
+ * @param {any} chunk
+ * @returns {Promise<void>}
+ */
+function transformStreamDefaultControllerPerformTransform(controller, chunk) {
+ const transformPromise = controller[_transformAlgorithm](chunk, controller);
+ return transformPromiseWith(transformPromise, undefined, (r) => {
+ transformStreamError(controller[_stream], r);
+ throw r;
+ });
+}
+
+/** @param {TransformStreamDefaultController} controller */
+function transformStreamDefaultControllerTerminate(controller) {
+ const stream = controller[_stream];
+ const readableController = stream[_readable][_controller];
+ readableStreamDefaultControllerClose(
+ /** @type {ReadableStreamDefaultController} */ readableController,
+ );
+ const error = new TypeError("The stream has been terminated.");
+ transformStreamErrorWritableAndUnblockWrite(stream, error);
+}
+
+/**
+ * @param {TransformStream} stream
+ * @param {any=} reason
+ * @returns {Promise<void>}
+ */
+function transformStreamDefaultSinkAbortAlgorithm(stream, reason) {
+ transformStreamError(stream, reason);
+ return resolvePromiseWith(undefined);
+}
+
+/**
+ * @template I
+ * @template O
+ * @param {TransformStream<I, O>} stream
+ * @returns {Promise<void>}
+ */
+function transformStreamDefaultSinkCloseAlgorithm(stream) {
+ const readable = stream[_readable];
+ const controller = stream[_controller];
+ const flushPromise = controller[_flushAlgorithm](controller);
+ transformStreamDefaultControllerClearAlgorithms(controller);
+ return transformPromiseWith(flushPromise, () => {
+ if (readable[_state] === "errored") {
+ throw readable[_storedError];
+ }
readableStreamDefaultControllerClose(
- /** @type {ReadableStreamDefaultController} */ readableController,
+ /** @type {ReadableStreamDefaultController} */ readable[_controller],
);
- const error = new TypeError("The stream has been terminated.");
- transformStreamErrorWritableAndUnblockWrite(stream, error);
- }
-
- /**
- * @param {TransformStream} stream
- * @param {any=} reason
- * @returns {Promise<void>}
- */
- function transformStreamDefaultSinkAbortAlgorithm(stream, reason) {
- transformStreamError(stream, reason);
- return resolvePromiseWith(undefined);
- }
-
- /**
- * @template I
- * @template O
- * @param {TransformStream<I, O>} stream
- * @returns {Promise<void>}
- */
- function transformStreamDefaultSinkCloseAlgorithm(stream) {
- const readable = stream[_readable];
- const controller = stream[_controller];
- const flushPromise = controller[_flushAlgorithm](controller);
- transformStreamDefaultControllerClearAlgorithms(controller);
- return transformPromiseWith(flushPromise, () => {
- if (readable[_state] === "errored") {
- throw readable[_storedError];
- }
- readableStreamDefaultControllerClose(
- /** @type {ReadableStreamDefaultController} */ readable[_controller],
+ }, (r) => {
+ transformStreamError(stream, r);
+ throw readable[_storedError];
+ });
+}
+
+/**
+ * @template I
+ * @template O
+ * @param {TransformStream<I, O>} stream
+ * @param {I} chunk
+ * @returns {Promise<void>}
+ */
+function transformStreamDefaultSinkWriteAlgorithm(stream, chunk) {
+ assert(stream[_writable][_state] === "writable");
+ const controller = stream[_controller];
+ if (stream[_backpressure] === true) {
+ const backpressureChangePromise = stream[_backpressureChangePromise];
+ assert(backpressureChangePromise !== undefined);
+ return transformPromiseWith(backpressureChangePromise.promise, () => {
+ const writable = stream[_writable];
+ const state = writable[_state];
+ if (state === "erroring") {
+ throw writable[_storedError];
+ }
+ assert(state === "writable");
+ return transformStreamDefaultControllerPerformTransform(
+ controller,
+ chunk,
);
- }, (r) => {
- transformStreamError(stream, r);
- throw readable[_storedError];
});
}
-
- /**
- * @template I
- * @template O
- * @param {TransformStream<I, O>} stream
- * @param {I} chunk
- * @returns {Promise<void>}
- */
- function transformStreamDefaultSinkWriteAlgorithm(stream, chunk) {
- assert(stream[_writable][_state] === "writable");
- const controller = stream[_controller];
- if (stream[_backpressure] === true) {
- const backpressureChangePromise = stream[_backpressureChangePromise];
- assert(backpressureChangePromise !== undefined);
- return transformPromiseWith(backpressureChangePromise.promise, () => {
- const writable = stream[_writable];
- const state = writable[_state];
- if (state === "erroring") {
- throw writable[_storedError];
- }
- assert(state === "writable");
- return transformStreamDefaultControllerPerformTransform(
- controller,
- chunk,
- );
- });
- }
- return transformStreamDefaultControllerPerformTransform(controller, chunk);
- }
-
- /**
- * @param {TransformStream} stream
- * @returns {Promise<void>}
- */
- function transformStreamDefaultSourcePullAlgorithm(stream) {
- assert(stream[_backpressure] === true);
- assert(stream[_backpressureChangePromise] !== undefined);
+ return transformStreamDefaultControllerPerformTransform(controller, chunk);
+}
+
+/**
+ * @param {TransformStream} stream
+ * @returns {Promise<void>}
+ */
+function transformStreamDefaultSourcePullAlgorithm(stream) {
+ assert(stream[_backpressure] === true);
+ assert(stream[_backpressureChangePromise] !== undefined);
+ transformStreamSetBackpressure(stream, false);
+ return stream[_backpressureChangePromise].promise;
+}
+
+/**
+ * @param {TransformStream} stream
+ * @param {any=} e
+ */
+function transformStreamError(stream, e) {
+ readableStreamDefaultControllerError(
+ /** @type {ReadableStreamDefaultController} */ stream[_readable][
+ _controller
+ ],
+ e,
+ );
+ transformStreamErrorWritableAndUnblockWrite(stream, e);
+}
+
+/**
+ * @param {TransformStream} stream
+ * @param {any=} e
+ */
+function transformStreamErrorWritableAndUnblockWrite(stream, e) {
+ transformStreamDefaultControllerClearAlgorithms(stream[_controller]);
+ writableStreamDefaultControllerErrorIfNeeded(
+ stream[_writable][_controller],
+ e,
+ );
+ if (stream[_backpressure] === true) {
transformStreamSetBackpressure(stream, false);
- return stream[_backpressureChangePromise].promise;
}
-
- /**
- * @param {TransformStream} stream
- * @param {any=} e
- */
- function transformStreamError(stream, e) {
- readableStreamDefaultControllerError(
- /** @type {ReadableStreamDefaultController} */ stream[_readable][
- _controller
- ],
- e,
- );
- transformStreamErrorWritableAndUnblockWrite(stream, e);
- }
-
- /**
- * @param {TransformStream} stream
- * @param {any=} e
- */
- function transformStreamErrorWritableAndUnblockWrite(stream, e) {
- transformStreamDefaultControllerClearAlgorithms(stream[_controller]);
- writableStreamDefaultControllerErrorIfNeeded(
- stream[_writable][_controller],
- e,
- );
- if (stream[_backpressure] === true) {
- transformStreamSetBackpressure(stream, false);
- }
+}
+
+/**
+ * @param {TransformStream} stream
+ * @param {boolean} backpressure
+ */
+function transformStreamSetBackpressure(stream, backpressure) {
+ assert(stream[_backpressure] !== backpressure);
+ if (stream[_backpressureChangePromise] !== undefined) {
+ stream[_backpressureChangePromise].resolve(undefined);
+ }
+ stream[_backpressureChangePromise] = new Deferred();
+ stream[_backpressure] = backpressure;
+}
+
+/**
+ * @param {WritableStream} stream
+ * @param {any=} reason
+ * @returns {Promise<void>}
+ */
+function writableStreamAbort(stream, reason) {
+ const state = stream[_state];
+ if (state === "closed" || state === "errored") {
+ return resolvePromiseWith(undefined);
}
-
- /**
- * @param {TransformStream} stream
- * @param {boolean} backpressure
- */
- function transformStreamSetBackpressure(stream, backpressure) {
- assert(stream[_backpressure] !== backpressure);
- if (stream[_backpressureChangePromise] !== undefined) {
- stream[_backpressureChangePromise].resolve(undefined);
- }
- stream[_backpressureChangePromise] = new Deferred();
- stream[_backpressure] = backpressure;
+ stream[_controller][_signal][signalAbort](reason);
+ if (state === "closed" || state === "errored") {
+ return resolvePromiseWith(undefined);
}
-
- /**
- * @param {WritableStream} stream
- * @param {any=} reason
- * @returns {Promise<void>}
- */
- function writableStreamAbort(stream, reason) {
- const state = stream[_state];
- if (state === "closed" || state === "errored") {
- return resolvePromiseWith(undefined);
- }
- stream[_controller][_signal][signalAbort](reason);
- if (state === "closed" || state === "errored") {
- return resolvePromiseWith(undefined);
- }
- if (stream[_pendingAbortRequest] !== undefined) {
- return stream[_pendingAbortRequest].deferred.promise;
- }
- assert(state === "writable" || state === "erroring");
- let wasAlreadyErroring = false;
- if (state === "erroring") {
- wasAlreadyErroring = true;
- reason = undefined;
- }
- /** Deferred<void> */
- const deferred = new Deferred();
- stream[_pendingAbortRequest] = {
- deferred,
- reason,
- wasAlreadyErroring,
- };
- if (wasAlreadyErroring === false) {
- writableStreamStartErroring(stream, reason);
- }
- return deferred.promise;
+ if (stream[_pendingAbortRequest] !== undefined) {
+ return stream[_pendingAbortRequest].deferred.promise;
+ }
+ assert(state === "writable" || state === "erroring");
+ let wasAlreadyErroring = false;
+ if (state === "erroring") {
+ wasAlreadyErroring = true;
+ reason = undefined;
+ }
+ /** Deferred<void> */
+ const deferred = new Deferred();
+ stream[_pendingAbortRequest] = {
+ deferred,
+ reason,
+ wasAlreadyErroring,
+ };
+ if (wasAlreadyErroring === false) {
+ writableStreamStartErroring(stream, reason);
+ }
+ return deferred.promise;
+}
+
+/**
+ * @param {WritableStream} stream
+ * @returns {Promise<void>}
+ */
+function writableStreamAddWriteRequest(stream) {
+ assert(isWritableStreamLocked(stream) === true);
+ assert(stream[_state] === "writable");
+ /** @type {Deferred<void>} */
+ const deferred = new Deferred();
+ ArrayPrototypePush(stream[_writeRequests], deferred);
+ return deferred.promise;
+}
+
+/**
+ * @param {WritableStream} stream
+ * @returns {Promise<void>}
+ */
+function writableStreamClose(stream) {
+ const state = stream[_state];
+ if (state === "closed" || state === "errored") {
+ return PromiseReject(
+ new TypeError("Writable stream is closed or errored."),
+ );
}
-
- /**
- * @param {WritableStream} stream
- * @returns {Promise<void>}
- */
- function writableStreamAddWriteRequest(stream) {
- assert(isWritableStreamLocked(stream) === true);
- assert(stream[_state] === "writable");
- /** @type {Deferred<void>} */
- const deferred = new Deferred();
- ArrayPrototypePush(stream[_writeRequests], deferred);
- return deferred.promise;
+ assert(state === "writable" || state === "erroring");
+ assert(writableStreamCloseQueuedOrInFlight(stream) === false);
+ /** @type {Deferred<void>} */
+ const deferred = new Deferred();
+ stream[_closeRequest] = deferred;
+ const writer = stream[_writer];
+ if (
+ writer !== undefined && stream[_backpressure] === true &&
+ state === "writable"
+ ) {
+ writer[_readyPromise].resolve(undefined);
+ }
+ writableStreamDefaultControllerClose(stream[_controller]);
+ return deferred.promise;
+}
+
+/**
+ * @param {WritableStream} stream
+ * @returns {boolean}
+ */
+function writableStreamCloseQueuedOrInFlight(stream) {
+ if (
+ stream[_closeRequest] === undefined &&
+ stream[_inFlightCloseRequest] === undefined
+ ) {
+ return false;
}
+ return true;
+}
- /**
- * @param {WritableStream} stream
- * @returns {Promise<void>}
- */
- function writableStreamClose(stream) {
+/**
+ * @param {WritableStream} stream
+ * @param {any=} error
+ */
+function writableStreamDealWithRejection(stream, error) {
+ const state = stream[_state];
+ if (state === "writable") {
+ writableStreamStartErroring(stream, error);
+ return;
+ }
+ assert(state === "erroring");
+ writableStreamFinishErroring(stream);
+}
+
+/**
+ * @template W
+ * @param {WritableStreamDefaultController<W>} controller
+ */
+function writableStreamDefaultControllerAdvanceQueueIfNeeded(controller) {
+ const stream = controller[_stream];
+ if (controller[_started] === false) {
+ return;
+ }
+ if (stream[_inFlightWriteRequest] !== undefined) {
+ return;
+ }
+ const state = stream[_state];
+ assert(state !== "closed" && state !== "errored");
+ if (state === "erroring") {
+ writableStreamFinishErroring(stream);
+ return;
+ }
+ if (controller[_queue].length === 0) {
+ return;
+ }
+ const value = peekQueueValue(controller);
+ if (value === _close) {
+ writableStreamDefaultControllerProcessClose(controller);
+ } else {
+ writableStreamDefaultControllerProcessWrite(controller, value);
+ }
+}
+
+function writableStreamDefaultControllerClearAlgorithms(controller) {
+ controller[_writeAlgorithm] = undefined;
+ controller[_closeAlgorithm] = undefined;
+ controller[_abortAlgorithm] = undefined;
+ controller[_strategySizeAlgorithm] = undefined;
+}
+
+/** @param {WritableStreamDefaultController} controller */
+function writableStreamDefaultControllerClose(controller) {
+ enqueueValueWithSize(controller, _close, 0);
+ writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
+}
+
+/**
+ * @param {WritableStreamDefaultController} controller
+ * @param {any} error
+ */
+function writableStreamDefaultControllerError(controller, error) {
+ const stream = controller[_stream];
+ assert(stream[_state] === "writable");
+ writableStreamDefaultControllerClearAlgorithms(controller);
+ writableStreamStartErroring(stream, error);
+}
+
+/**
+ * @param {WritableStreamDefaultController} controller
+ * @param {any} error
+ */
+function writableStreamDefaultControllerErrorIfNeeded(controller, error) {
+ if (controller[_stream][_state] === "writable") {
+ writableStreamDefaultControllerError(controller, error);
+ }
+}
+
+/**
+ * @param {WritableStreamDefaultController} controller
+ * @returns {boolean}
+ */
+function writableStreamDefaultControllerGetBackpressure(controller) {
+ const desiredSize = writableStreamDefaultControllerGetDesiredSize(
+ controller,
+ );
+ return desiredSize <= 0;
+}
+
+/**
+ * @template W
+ * @param {WritableStreamDefaultController<W>} controller
+ * @param {W} chunk
+ * @returns {number}
+ */
+function writableStreamDefaultControllerGetChunkSize(controller, chunk) {
+ let value;
+ try {
+ value = controller[_strategySizeAlgorithm](chunk);
+ } catch (e) {
+ writableStreamDefaultControllerErrorIfNeeded(controller, e);
+ return 1;
+ }
+ return value;
+}
+
+/**
+ * @param {WritableStreamDefaultController} controller
+ * @returns {number}
+ */
+function writableStreamDefaultControllerGetDesiredSize(controller) {
+ return controller[_strategyHWM] - controller[_queueTotalSize];
+}
+
+/** @param {WritableStreamDefaultController} controller */
+function writableStreamDefaultControllerProcessClose(controller) {
+ const stream = controller[_stream];
+ writableStreamMarkCloseRequestInFlight(stream);
+ dequeueValue(controller);
+ assert(controller[_queue].length === 0);
+ const sinkClosePromise = controller[_closeAlgorithm]();
+ writableStreamDefaultControllerClearAlgorithms(controller);
+ uponPromise(sinkClosePromise, () => {
+ writableStreamFinishInFlightClose(stream);
+ }, (reason) => {
+ writableStreamFinishInFlightCloseWithError(stream, reason);
+ });
+}
+
+/**
+ * @template W
+ * @param {WritableStreamDefaultController<W>} controller
+ * @param {W} chunk
+ */
+function writableStreamDefaultControllerProcessWrite(controller, chunk) {
+ const stream = controller[_stream];
+ writableStreamMarkFirstWriteRequestInFlight(stream);
+ const sinkWritePromise = controller[_writeAlgorithm](chunk, controller);
+ uponPromise(sinkWritePromise, () => {
+ writableStreamFinishInFlightWrite(stream);
const state = stream[_state];
- if (state === "closed" || state === "errored") {
- return PromiseReject(
- new TypeError("Writable stream is closed or errored."),
- );
- }
assert(state === "writable" || state === "erroring");
- assert(writableStreamCloseQueuedOrInFlight(stream) === false);
- /** @type {Deferred<void>} */
- const deferred = new Deferred();
- stream[_closeRequest] = deferred;
- const writer = stream[_writer];
+ dequeueValue(controller);
if (
- writer !== undefined && stream[_backpressure] === true &&
+ writableStreamCloseQueuedOrInFlight(stream) === false &&
state === "writable"
) {
- writer[_readyPromise].resolve(undefined);
+ const backpressure = writableStreamDefaultControllerGetBackpressure(
+ controller,
+ );
+ writableStreamUpdateBackpressure(stream, backpressure);
}
- writableStreamDefaultControllerClose(stream[_controller]);
- return deferred.promise;
- }
-
- /**
- * @param {WritableStream} stream
- * @returns {boolean}
- */
- function writableStreamCloseQueuedOrInFlight(stream) {
- if (
- stream[_closeRequest] === undefined &&
- stream[_inFlightCloseRequest] === undefined
- ) {
- return false;
+ writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
+ }, (reason) => {
+ if (stream[_state] === "writable") {
+ writableStreamDefaultControllerClearAlgorithms(controller);
}
- return true;
+ writableStreamFinishInFlightWriteWithError(stream, reason);
+ });
+}
+
+/**
+ * @template W
+ * @param {WritableStreamDefaultController<W>} controller
+ * @param {W} chunk
+ * @param {number} chunkSize
+ */
+function writableStreamDefaultControllerWrite(controller, chunk, chunkSize) {
+ try {
+ enqueueValueWithSize(controller, chunk, chunkSize);
+ } catch (e) {
+ writableStreamDefaultControllerErrorIfNeeded(controller, e);
+ return;
+ }
+ const stream = controller[_stream];
+ if (
+ writableStreamCloseQueuedOrInFlight(stream) === false &&
+ stream[_state] === "writable"
+ ) {
+ const backpressure = writableStreamDefaultControllerGetBackpressure(
+ controller,
+ );
+ writableStreamUpdateBackpressure(stream, backpressure);
}
-
- /**
- * @param {WritableStream} stream
- * @param {any=} error
- */
- function writableStreamDealWithRejection(stream, error) {
- const state = stream[_state];
- if (state === "writable") {
- writableStreamStartErroring(stream, error);
- return;
+ writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
+}
+
+/**
+ * @param {WritableStreamDefaultWriter} writer
+ * @param {any=} reason
+ * @returns {Promise<void>}
+ */
+function writableStreamDefaultWriterAbort(writer, reason) {
+ const stream = writer[_stream];
+ assert(stream !== undefined);
+ return writableStreamAbort(stream, reason);
+}
+
+/**
+ * @param {WritableStreamDefaultWriter} writer
+ * @returns {Promise<void>}
+ */
+function writableStreamDefaultWriterClose(writer) {
+ const stream = writer[_stream];
+ assert(stream !== undefined);
+ return writableStreamClose(stream);
+}
+
+/**
+ * @param {WritableStreamDefaultWriter} writer
+ * @returns {Promise<void>}
+ */
+function writableStreamDefaultWriterCloseWithErrorPropagation(writer) {
+ const stream = writer[_stream];
+ assert(stream !== undefined);
+ const state = stream[_state];
+ if (
+ writableStreamCloseQueuedOrInFlight(stream) === true || state === "closed"
+ ) {
+ return resolvePromiseWith(undefined);
+ }
+ if (state === "errored") {
+ return PromiseReject(stream[_storedError]);
+ }
+ assert(state === "writable" || state === "erroring");
+ return writableStreamDefaultWriterClose(writer);
+}
+
+/**
+ * @param {WritableStreamDefaultWriter} writer
+ * @param {any=} error
+ */
+function writableStreamDefaultWriterEnsureClosedPromiseRejected(
+ writer,
+ error,
+) {
+ if (writer[_closedPromise].state === "pending") {
+ writer[_closedPromise].reject(error);
+ } else {
+ writer[_closedPromise] = new Deferred();
+ writer[_closedPromise].reject(error);
+ }
+ setPromiseIsHandledToTrue(writer[_closedPromise].promise);
+}
+
+/**
+ * @param {WritableStreamDefaultWriter} writer
+ * @param {any=} error
+ */
+function writableStreamDefaultWriterEnsureReadyPromiseRejected(
+ writer,
+ error,
+) {
+ if (writer[_readyPromise].state === "pending") {
+ writer[_readyPromise].reject(error);
+ } else {
+ writer[_readyPromise] = new Deferred();
+ writer[_readyPromise].reject(error);
+ }
+ setPromiseIsHandledToTrue(writer[_readyPromise].promise);
+}
+
+/**
+ * @param {WritableStreamDefaultWriter} writer
+ * @returns {number | null}
+ */
+function writableStreamDefaultWriterGetDesiredSize(writer) {
+ const stream = writer[_stream];
+ const state = stream[_state];
+ if (state === "errored" || state === "erroring") {
+ return null;
+ }
+ if (state === "closed") {
+ return 0;
+ }
+ return writableStreamDefaultControllerGetDesiredSize(stream[_controller]);
+}
+
+/** @param {WritableStreamDefaultWriter} writer */
+function writableStreamDefaultWriterRelease(writer) {
+ const stream = writer[_stream];
+ assert(stream !== undefined);
+ assert(stream[_writer] === writer);
+ const releasedError = new TypeError(
+ "The writer has already been released.",
+ );
+ writableStreamDefaultWriterEnsureReadyPromiseRejected(
+ writer,
+ releasedError,
+ );
+ writableStreamDefaultWriterEnsureClosedPromiseRejected(
+ writer,
+ releasedError,
+ );
+ stream[_writer] = undefined;
+ writer[_stream] = undefined;
+}
+
+/**
+ * @template W
+ * @param {WritableStreamDefaultWriter<W>} writer
+ * @param {W} chunk
+ * @returns {Promise<void>}
+ */
+function writableStreamDefaultWriterWrite(writer, chunk) {
+ const stream = writer[_stream];
+ assert(stream !== undefined);
+ const controller = stream[_controller];
+ const chunkSize = writableStreamDefaultControllerGetChunkSize(
+ controller,
+ chunk,
+ );
+ if (stream !== writer[_stream]) {
+ return PromiseReject(new TypeError("Writer's stream is unexpected."));
+ }
+ const state = stream[_state];
+ if (state === "errored") {
+ return PromiseReject(stream[_storedError]);
+ }
+ if (
+ writableStreamCloseQueuedOrInFlight(stream) === true || state === "closed"
+ ) {
+ return PromiseReject(
+ new TypeError("The stream is closing or is closed."),
+ );
+ }
+ if (state === "erroring") {
+ return PromiseReject(stream[_storedError]);
+ }
+ assert(state === "writable");
+ const promise = writableStreamAddWriteRequest(stream);
+ writableStreamDefaultControllerWrite(controller, chunk, chunkSize);
+ return promise;
+}
+
+/** @param {WritableStream} stream */
+function writableStreamFinishErroring(stream) {
+ assert(stream[_state] === "erroring");
+ assert(writableStreamHasOperationMarkedInFlight(stream) === false);
+ stream[_state] = "errored";
+ stream[_controller][_errorSteps]();
+ const storedError = stream[_storedError];
+ const writeRequests = stream[_writeRequests];
+ for (let i = 0; i < writeRequests.length; ++i) {
+ const writeRequest = writeRequests[i];
+ writeRequest.reject(storedError);
+ }
+ stream[_writeRequests] = [];
+ if (stream[_pendingAbortRequest] === undefined) {
+ writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
+ return;
+ }
+ const abortRequest = stream[_pendingAbortRequest];
+ stream[_pendingAbortRequest] = undefined;
+ if (abortRequest.wasAlreadyErroring === true) {
+ abortRequest.deferred.reject(storedError);
+ writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
+ return;
+ }
+ const promise = stream[_controller][_abortSteps](abortRequest.reason);
+ uponPromise(promise, () => {
+ abortRequest.deferred.resolve(undefined);
+ writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
+ }, (reason) => {
+ abortRequest.deferred.reject(reason);
+ writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
+ });
+}
+
+/** @param {WritableStream} stream */
+function writableStreamFinishInFlightClose(stream) {
+ assert(stream[_inFlightCloseRequest] !== undefined);
+ stream[_inFlightCloseRequest].resolve(undefined);
+ stream[_inFlightCloseRequest] = undefined;
+ const state = stream[_state];
+ assert(state === "writable" || state === "erroring");
+ if (state === "erroring") {
+ stream[_storedError] = undefined;
+ if (stream[_pendingAbortRequest] !== undefined) {
+ stream[_pendingAbortRequest].deferred.resolve(undefined);
+ stream[_pendingAbortRequest] = undefined;
}
- assert(state === "erroring");
+ }
+ stream[_state] = "closed";
+ const writer = stream[_writer];
+ if (writer !== undefined) {
+ writer[_closedPromise].resolve(undefined);
+ }
+ assert(stream[_pendingAbortRequest] === undefined);
+ assert(stream[_storedError] === undefined);
+}
+
+/**
+ * @param {WritableStream} stream
+ * @param {any=} error
+ */
+function writableStreamFinishInFlightCloseWithError(stream, error) {
+ assert(stream[_inFlightCloseRequest] !== undefined);
+ stream[_inFlightCloseRequest].reject(error);
+ stream[_inFlightCloseRequest] = undefined;
+ assert(stream[_state] === "writable" || stream[_state] === "erroring");
+ if (stream[_pendingAbortRequest] !== undefined) {
+ stream[_pendingAbortRequest].deferred.reject(error);
+ stream[_pendingAbortRequest] = undefined;
+ }
+ writableStreamDealWithRejection(stream, error);
+}
+
+/** @param {WritableStream} stream */
+function writableStreamFinishInFlightWrite(stream) {
+ assert(stream[_inFlightWriteRequest] !== undefined);
+ stream[_inFlightWriteRequest].resolve(undefined);
+ stream[_inFlightWriteRequest] = undefined;
+}
+
+/**
+ * @param {WritableStream} stream
+ * @param {any=} error
+ */
+function writableStreamFinishInFlightWriteWithError(stream, error) {
+ assert(stream[_inFlightWriteRequest] !== undefined);
+ stream[_inFlightWriteRequest].reject(error);
+ stream[_inFlightWriteRequest] = undefined;
+ assert(stream[_state] === "writable" || stream[_state] === "erroring");
+ writableStreamDealWithRejection(stream, error);
+}
+
+/**
+ * @param {WritableStream} stream
+ * @returns {boolean}
+ */
+function writableStreamHasOperationMarkedInFlight(stream) {
+ if (
+ stream[_inFlightWriteRequest] === undefined &&
+ stream[_inFlightCloseRequest] === undefined
+ ) {
+ return false;
+ }
+ return true;
+}
+
+/** @param {WritableStream} stream */
+function writableStreamMarkCloseRequestInFlight(stream) {
+ assert(stream[_inFlightCloseRequest] === undefined);
+ assert(stream[_closeRequest] !== undefined);
+ stream[_inFlightCloseRequest] = stream[_closeRequest];
+ stream[_closeRequest] = undefined;
+}
+
+/**
+ * @template W
+ * @param {WritableStream<W>} stream
+ */
+function writableStreamMarkFirstWriteRequestInFlight(stream) {
+ assert(stream[_inFlightWriteRequest] === undefined);
+ assert(stream[_writeRequests].length);
+ const writeRequest = stream[_writeRequests].shift();
+ stream[_inFlightWriteRequest] = writeRequest;
+}
+
+/** @param {WritableStream} stream */
+function writableStreamRejectCloseAndClosedPromiseIfNeeded(stream) {
+ assert(stream[_state] === "errored");
+ if (stream[_closeRequest] !== undefined) {
+ assert(stream[_inFlightCloseRequest] === undefined);
+ stream[_closeRequest].reject(stream[_storedError]);
+ stream[_closeRequest] = undefined;
+ }
+ const writer = stream[_writer];
+ if (writer !== undefined) {
+ writer[_closedPromise].reject(stream[_storedError]);
+ setPromiseIsHandledToTrue(writer[_closedPromise].promise);
+ }
+}
+
+/**
+ * @param {WritableStream} stream
+ * @param {any=} reason
+ */
+function writableStreamStartErroring(stream, reason) {
+ assert(stream[_storedError] === undefined);
+ assert(stream[_state] === "writable");
+ const controller = stream[_controller];
+ assert(controller !== undefined);
+ stream[_state] = "erroring";
+ stream[_storedError] = reason;
+ const writer = stream[_writer];
+ if (writer !== undefined) {
+ writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason);
+ }
+ if (
+ writableStreamHasOperationMarkedInFlight(stream) === false &&
+ controller[_started] === true
+ ) {
writableStreamFinishErroring(stream);
}
-
- /**
- * @template W
- * @param {WritableStreamDefaultController<W>} controller
- */
- function writableStreamDefaultControllerAdvanceQueueIfNeeded(controller) {
- const stream = controller[_stream];
- if (controller[_started] === false) {
- return;
- }
- if (stream[_inFlightWriteRequest] !== undefined) {
- return;
- }
- const state = stream[_state];
- assert(state !== "closed" && state !== "errored");
- if (state === "erroring") {
- writableStreamFinishErroring(stream);
- return;
- }
- if (controller[_queue].length === 0) {
- return;
- }
- const value = peekQueueValue(controller);
- if (value === _close) {
- writableStreamDefaultControllerProcessClose(controller);
+}
+
+/**
+ * @param {WritableStream} stream
+ * @param {boolean} backpressure
+ */
+function writableStreamUpdateBackpressure(stream, backpressure) {
+ assert(stream[_state] === "writable");
+ assert(writableStreamCloseQueuedOrInFlight(stream) === false);
+ const writer = stream[_writer];
+ if (writer !== undefined && backpressure !== stream[_backpressure]) {
+ if (backpressure === true) {
+ writer[_readyPromise] = new Deferred();
} else {
- writableStreamDefaultControllerProcessWrite(controller, value);
+ assert(backpressure === false);
+ writer[_readyPromise].resolve(undefined);
}
}
+ stream[_backpressure] = backpressure;
+}
+
+/**
+ * @template T
+ * @param {T} value
+ * @param {boolean} done
+ * @returns {IteratorResult<T>}
+ */
+function createIteratorResult(value, done) {
+ const result = ObjectCreate(ObjectPrototype);
+ ObjectDefineProperties(result, {
+ value: { value, writable: true, enumerable: true, configurable: true },
+ done: {
+ value: done,
+ writable: true,
+ enumerable: true,
+ configurable: true,
+ },
+ });
+ return result;
+}
+
+/** @type {AsyncIterator<unknown, unknown>} */
+const asyncIteratorPrototype = ObjectGetPrototypeOf(AsyncGeneratorPrototype);
+
+const _iteratorNext = Symbol("[[iteratorNext]]");
+const _iteratorFinished = Symbol("[[iteratorFinished]]");
+
+/** @type {AsyncIterator<unknown>} */
+const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({
+ /** @returns {Promise<IteratorResult<unknown>>} */
+ next() {
+ /** @type {ReadableStreamDefaultReader} */
+ const reader = this[_reader];
+ function nextSteps() {
+ if (reader[_iteratorFinished]) {
+ return PromiseResolve(createIteratorResult(undefined, true));
+ }
- function writableStreamDefaultControllerClearAlgorithms(controller) {
- controller[_writeAlgorithm] = undefined;
- controller[_closeAlgorithm] = undefined;
- controller[_abortAlgorithm] = undefined;
- controller[_strategySizeAlgorithm] = undefined;
- }
+ if (reader[_stream] === undefined) {
+ return PromiseReject(
+ new TypeError(
+ "Cannot get the next iteration result once the reader has been released.",
+ ),
+ );
+ }
- /** @param {WritableStreamDefaultController} controller */
- function writableStreamDefaultControllerClose(controller) {
- enqueueValueWithSize(controller, _close, 0);
- writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
- }
+ /** @type {Deferred<IteratorResult<any>>} */
+ const promise = new Deferred();
+ /** @type {ReadRequest} */
+ const readRequest = {
+ chunkSteps(chunk) {
+ promise.resolve(createIteratorResult(chunk, false));
+ },
+ closeSteps() {
+ readableStreamDefaultReaderRelease(reader);
+ promise.resolve(createIteratorResult(undefined, true));
+ },
+ errorSteps(e) {
+ readableStreamDefaultReaderRelease(reader);
+ promise.reject(e);
+ },
+ };
+
+ readableStreamDefaultReaderRead(reader, readRequest);
+ return PromisePrototypeThen(promise.promise, (result) => {
+ reader[_iteratorNext] = null;
+ if (result.done === true) {
+ reader[_iteratorFinished] = true;
+ return createIteratorResult(undefined, true);
+ }
+ return result;
+ }, (reason) => {
+ reader[_iteratorNext] = null;
+ reader[_iteratorFinished] = true;
+ throw reason;
+ });
+ }
+
+ reader[_iteratorNext] = reader[_iteratorNext]
+ ? PromisePrototypeThen(reader[_iteratorNext], nextSteps, nextSteps)
+ : nextSteps();
+ return reader[_iteratorNext];
+ },
/**
- * @param {WritableStreamDefaultController} controller
- * @param {any} error
+ * @param {unknown} arg
+ * @returns {Promise<IteratorResult<unknown>>}
*/
- function writableStreamDefaultControllerError(controller, error) {
- const stream = controller[_stream];
- assert(stream[_state] === "writable");
- writableStreamDefaultControllerClearAlgorithms(controller);
- writableStreamStartErroring(stream, error);
+ return(arg) {
+ /** @type {ReadableStreamDefaultReader} */
+ const reader = this[_reader];
+ const returnSteps = () => {
+ if (reader[_iteratorFinished]) {
+ return PromiseResolve(createIteratorResult(arg, true));
+ }
+ reader[_iteratorFinished] = true;
+
+ if (reader[_stream] === undefined) {
+ return PromiseResolve(createIteratorResult(undefined, true));
+ }
+ assert(reader[_readRequests].length === 0);
+ if (this[_preventCancel] === false) {
+ const result = readableStreamReaderGenericCancel(reader, arg);
+ readableStreamDefaultReaderRelease(reader);
+ return result;
+ }
+ readableStreamDefaultReaderRelease(reader);
+ return PromiseResolve(createIteratorResult(undefined, true));
+ };
+
+ const returnPromise = reader[_iteratorNext]
+ ? PromisePrototypeThen(reader[_iteratorNext], returnSteps, returnSteps)
+ : returnSteps();
+ return PromisePrototypeThen(
+ returnPromise,
+ () => createIteratorResult(arg, true),
+ );
+ },
+}, asyncIteratorPrototype);
+
+class ByteLengthQueuingStrategy {
+ /** @param {{ highWaterMark: number }} init */
+ constructor(init) {
+ const prefix = "Failed to construct 'ByteLengthQueuingStrategy'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ init = webidl.converters.QueuingStrategyInit(init, {
+ prefix,
+ context: "Argument 1",
+ });
+ this[webidl.brand] = webidl.brand;
+ this[_globalObject] = globalThis;
+ this[_highWaterMark] = init.highWaterMark;
}
- /**
- * @param {WritableStreamDefaultController} controller
- * @param {any} error
- */
- function writableStreamDefaultControllerErrorIfNeeded(controller, error) {
- if (controller[_stream][_state] === "writable") {
- writableStreamDefaultControllerError(controller, error);
- }
+ /** @returns {number} */
+ get highWaterMark() {
+ webidl.assertBranded(this, ByteLengthQueuingStrategyPrototype);
+ return this[_highWaterMark];
}
- /**
- * @param {WritableStreamDefaultController} controller
- * @returns {boolean}
- */
- function writableStreamDefaultControllerGetBackpressure(controller) {
- const desiredSize = writableStreamDefaultControllerGetDesiredSize(
- controller,
- );
- return desiredSize <= 0;
+ /** @returns {(chunk: ArrayBufferView) => number} */
+ get size() {
+ webidl.assertBranded(this, ByteLengthQueuingStrategyPrototype);
+ initializeByteLengthSizeFunction(this[_globalObject]);
+ return WeakMapPrototypeGet(byteSizeFunctionWeakMap, this[_globalObject]);
}
- /**
- * @template W
- * @param {WritableStreamDefaultController<W>} controller
- * @param {W} chunk
- * @returns {number}
- */
- function writableStreamDefaultControllerGetChunkSize(controller, chunk) {
- let value;
- try {
- value = controller[_strategySizeAlgorithm](chunk);
- } catch (e) {
- writableStreamDefaultControllerErrorIfNeeded(controller, e);
- return 1;
- }
- return value;
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ ByteLengthQueuingStrategyPrototype,
+ this,
+ ),
+ keys: [
+ "highWaterMark",
+ "size",
+ ],
+ }));
}
+}
- /**
- * @param {WritableStreamDefaultController} controller
- * @returns {number}
- */
- function writableStreamDefaultControllerGetDesiredSize(controller) {
- return controller[_strategyHWM] - controller[_queueTotalSize];
+webidl.configurePrototype(ByteLengthQueuingStrategy);
+const ByteLengthQueuingStrategyPrototype = ByteLengthQueuingStrategy.prototype;
+
+/** @type {WeakMap<typeof globalThis, (chunk: ArrayBufferView) => number>} */
+const byteSizeFunctionWeakMap = new WeakMap();
+
+function initializeByteLengthSizeFunction(globalObject) {
+ if (WeakMapPrototypeHas(byteSizeFunctionWeakMap, globalObject)) {
+ return;
}
+ const size = (chunk) => chunk.byteLength;
+ WeakMapPrototypeSet(byteSizeFunctionWeakMap, globalObject, size);
+}
- /** @param {WritableStreamDefaultController} controller */
- function writableStreamDefaultControllerProcessClose(controller) {
- const stream = controller[_stream];
- writableStreamMarkCloseRequestInFlight(stream);
- dequeueValue(controller);
- assert(controller[_queue].length === 0);
- const sinkClosePromise = controller[_closeAlgorithm]();
- writableStreamDefaultControllerClearAlgorithms(controller);
- uponPromise(sinkClosePromise, () => {
- writableStreamFinishInFlightClose(stream);
- }, (reason) => {
- writableStreamFinishInFlightCloseWithError(stream, reason);
+class CountQueuingStrategy {
+ /** @param {{ highWaterMark: number }} init */
+ constructor(init) {
+ const prefix = "Failed to construct 'CountQueuingStrategy'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ init = webidl.converters.QueuingStrategyInit(init, {
+ prefix,
+ context: "Argument 1",
});
+ this[webidl.brand] = webidl.brand;
+ this[_globalObject] = globalThis;
+ this[_highWaterMark] = init.highWaterMark;
}
- /**
- * @template W
- * @param {WritableStreamDefaultController<W>} controller
- * @param {W} chunk
- */
- function writableStreamDefaultControllerProcessWrite(controller, chunk) {
- const stream = controller[_stream];
- writableStreamMarkFirstWriteRequestInFlight(stream);
- const sinkWritePromise = controller[_writeAlgorithm](chunk, controller);
- uponPromise(sinkWritePromise, () => {
- writableStreamFinishInFlightWrite(stream);
- const state = stream[_state];
- assert(state === "writable" || state === "erroring");
- dequeueValue(controller);
- if (
- writableStreamCloseQueuedOrInFlight(stream) === false &&
- state === "writable"
- ) {
- const backpressure = writableStreamDefaultControllerGetBackpressure(
- controller,
- );
- writableStreamUpdateBackpressure(stream, backpressure);
- }
- writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
- }, (reason) => {
- if (stream[_state] === "writable") {
- writableStreamDefaultControllerClearAlgorithms(controller);
- }
- writableStreamFinishInFlightWriteWithError(stream, reason);
- });
+ /** @returns {number} */
+ get highWaterMark() {
+ webidl.assertBranded(this, CountQueuingStrategyPrototype);
+ return this[_highWaterMark];
}
- /**
- * @template W
- * @param {WritableStreamDefaultController<W>} controller
- * @param {W} chunk
- * @param {number} chunkSize
- */
- function writableStreamDefaultControllerWrite(controller, chunk, chunkSize) {
- try {
- enqueueValueWithSize(controller, chunk, chunkSize);
- } catch (e) {
- writableStreamDefaultControllerErrorIfNeeded(controller, e);
- return;
+ /** @returns {(chunk: any) => 1} */
+ get size() {
+ webidl.assertBranded(this, CountQueuingStrategyPrototype);
+ initializeCountSizeFunction(this[_globalObject]);
+ return WeakMapPrototypeGet(countSizeFunctionWeakMap, this[_globalObject]);
+ }
+
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ CountQueuingStrategyPrototype,
+ this,
+ ),
+ keys: [
+ "highWaterMark",
+ "size",
+ ],
+ }));
+ }
+}
+
+webidl.configurePrototype(CountQueuingStrategy);
+const CountQueuingStrategyPrototype = CountQueuingStrategy.prototype;
+
+/** @type {WeakMap<typeof globalThis, () => 1>} */
+const countSizeFunctionWeakMap = new WeakMap();
+
+/** @param {typeof globalThis} globalObject */
+function initializeCountSizeFunction(globalObject) {
+ if (WeakMapPrototypeHas(countSizeFunctionWeakMap, globalObject)) {
+ return;
+ }
+ const size = () => 1;
+ WeakMapPrototypeSet(countSizeFunctionWeakMap, globalObject, size);
+}
+
+const _resourceBacking = Symbol("[[resourceBacking]]");
+// This distinction exists to prevent unrefable streams being used in
+// regular fast streams that are unaware of refability
+const _resourceBackingUnrefable = Symbol("[[resourceBackingUnrefable]]");
+/** @template R */
+class ReadableStream {
+ /** @type {ReadableStreamDefaultController | ReadableByteStreamController} */
+ [_controller];
+ /** @type {boolean} */
+ [_detached];
+ /** @type {boolean} */
+ [_disturbed];
+ /** @type {ReadableStreamDefaultReader | ReadableStreamBYOBReader} */
+ [_reader];
+ /** @type {"readable" | "closed" | "errored"} */
+ [_state];
+ /** @type {any} */
+ [_storedError];
+ /** @type {{ rid: number, autoClose: boolean } | null} */
+ [_resourceBacking] = null;
+
+ /**
+ * @param {UnderlyingSource<R>=} underlyingSource
+ * @param {QueuingStrategy<R>=} strategy
+ */
+ constructor(underlyingSource = undefined, strategy = undefined) {
+ const prefix = "Failed to construct 'ReadableStream'";
+ if (underlyingSource !== undefined) {
+ underlyingSource = webidl.converters.object(underlyingSource, {
+ prefix,
+ context: "Argument 1",
+ });
+ } else {
+ underlyingSource = null;
}
- const stream = controller[_stream];
- if (
- writableStreamCloseQueuedOrInFlight(stream) === false &&
- stream[_state] === "writable"
- ) {
- const backpressure = writableStreamDefaultControllerGetBackpressure(
- controller,
+ if (strategy !== undefined) {
+ strategy = webidl.converters.QueuingStrategy(strategy, {
+ prefix,
+ context: "Argument 2",
+ });
+ } else {
+ strategy = {};
+ }
+ this[webidl.brand] = webidl.brand;
+ let underlyingSourceDict = {};
+ if (underlyingSource !== undefined) {
+ underlyingSourceDict = webidl.converters.UnderlyingSource(
+ underlyingSource,
+ { prefix, context: "underlyingSource" },
+ );
+ }
+ initializeReadableStream(this);
+ if (underlyingSourceDict.type === "bytes") {
+ if (strategy.size !== undefined) {
+ throw new RangeError(
+ `${prefix}: When underlying source is "bytes", strategy.size must be undefined.`,
+ );
+ }
+ const highWaterMark = extractHighWaterMark(strategy, 0);
+ setUpReadableByteStreamControllerFromUnderlyingSource(
+ // @ts-ignore cannot easily assert this is ReadableStream<ArrayBuffer>
+ this,
+ underlyingSource,
+ underlyingSourceDict,
+ highWaterMark,
+ );
+ } else {
+ assert(!(ReflectHas(underlyingSourceDict, "type")));
+ const sizeAlgorithm = extractSizeAlgorithm(strategy);
+ const highWaterMark = extractHighWaterMark(strategy, 1);
+ setUpReadableStreamDefaultControllerFromUnderlyingSource(
+ this,
+ underlyingSource,
+ underlyingSourceDict,
+ highWaterMark,
+ sizeAlgorithm,
);
- writableStreamUpdateBackpressure(stream, backpressure);
}
- writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
- }
-
- /**
- * @param {WritableStreamDefaultWriter} writer
- * @param {any=} reason
- * @returns {Promise<void>}
- */
- function writableStreamDefaultWriterAbort(writer, reason) {
- const stream = writer[_stream];
- assert(stream !== undefined);
- return writableStreamAbort(stream, reason);
}
- /**
- * @param {WritableStreamDefaultWriter} writer
- * @returns {Promise<void>}
- */
- function writableStreamDefaultWriterClose(writer) {
- const stream = writer[_stream];
- assert(stream !== undefined);
- return writableStreamClose(stream);
+ /** @returns {boolean} */
+ get locked() {
+ webidl.assertBranded(this, ReadableStreamPrototype);
+ return isReadableStreamLocked(this);
}
/**
- * @param {WritableStreamDefaultWriter} writer
+ * @param {any=} reason
* @returns {Promise<void>}
*/
- function writableStreamDefaultWriterCloseWithErrorPropagation(writer) {
- const stream = writer[_stream];
- assert(stream !== undefined);
- const state = stream[_state];
- if (
- writableStreamCloseQueuedOrInFlight(stream) === true || state === "closed"
- ) {
- return resolvePromiseWith(undefined);
+ cancel(reason = undefined) {
+ try {
+ webidl.assertBranded(this, ReadableStreamPrototype);
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
+ }
+ } catch (err) {
+ return PromiseReject(err);
}
- if (state === "errored") {
- return PromiseReject(stream[_storedError]);
+ if (isReadableStreamLocked(this)) {
+ return PromiseReject(
+ new TypeError("Cannot cancel a locked ReadableStream."),
+ );
}
- assert(state === "writable" || state === "erroring");
- return writableStreamDefaultWriterClose(writer);
+ return readableStreamCancel(this, reason);
}
/**
- * @param {WritableStreamDefaultWriter} writer
- * @param {any=} error
+ * @param {ReadableStreamGetReaderOptions=} options
+ * @returns {ReadableStreamDefaultReader<R> | ReadableStreamBYOBReader}
*/
- function writableStreamDefaultWriterEnsureClosedPromiseRejected(
- writer,
- error,
- ) {
- if (writer[_closedPromise].state === "pending") {
- writer[_closedPromise].reject(error);
+ getReader(options = undefined) {
+ webidl.assertBranded(this, ReadableStreamPrototype);
+ const prefix = "Failed to execute 'getReader' on 'ReadableStream'";
+ if (options !== undefined) {
+ options = webidl.converters.ReadableStreamGetReaderOptions(options, {
+ prefix,
+ context: "Argument 1",
+ });
} else {
- writer[_closedPromise] = new Deferred();
- writer[_closedPromise].reject(error);
+ options = {};
+ }
+ if (options.mode === undefined) {
+ return acquireReadableStreamDefaultReader(this);
+ } else {
+ assert(options.mode === "byob");
+ return acquireReadableStreamBYOBReader(this);
}
- setPromiseIsHandledToTrue(writer[_closedPromise].promise);
}
/**
- * @param {WritableStreamDefaultWriter} writer
- * @param {any=} error
- */
- function writableStreamDefaultWriterEnsureReadyPromiseRejected(
- writer,
- error,
- ) {
- if (writer[_readyPromise].state === "pending") {
- writer[_readyPromise].reject(error);
- } else {
- writer[_readyPromise] = new Deferred();
- writer[_readyPromise].reject(error);
- }
- setPromiseIsHandledToTrue(writer[_readyPromise].promise);
+ * @template T
+ * @param {{ readable: ReadableStream<T>, writable: WritableStream<R> }} transform
+ * @param {PipeOptions=} options
+ * @returns {ReadableStream<T>}
+ */
+ pipeThrough(transform, options = {}) {
+ webidl.assertBranded(this, ReadableStreamPrototype);
+ const prefix = "Failed to execute 'pipeThrough' on 'ReadableStream'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ transform = webidl.converters.ReadableWritablePair(transform, {
+ prefix,
+ context: "Argument 1",
+ });
+ options = webidl.converters.StreamPipeOptions(options, {
+ prefix,
+ context: "Argument 2",
+ });
+ const { readable, writable } = transform;
+ const { preventClose, preventAbort, preventCancel, signal } = options;
+ if (isReadableStreamLocked(this)) {
+ throw new TypeError("ReadableStream is already locked.");
+ }
+ if (isWritableStreamLocked(writable)) {
+ throw new TypeError("Target WritableStream is already locked.");
+ }
+ const promise = readableStreamPipeTo(
+ this,
+ writable,
+ preventClose,
+ preventAbort,
+ preventCancel,
+ signal,
+ );
+ setPromiseIsHandledToTrue(promise);
+ return readable;
}
/**
- * @param {WritableStreamDefaultWriter} writer
- * @returns {number | null}
+ * @param {WritableStream<R>} destination
+ * @param {PipeOptions=} options
+ * @returns {Promise<void>}
*/
- function writableStreamDefaultWriterGetDesiredSize(writer) {
- const stream = writer[_stream];
- const state = stream[_state];
- if (state === "errored" || state === "erroring") {
- return null;
+ pipeTo(destination, options = {}) {
+ try {
+ webidl.assertBranded(this, ReadableStreamPrototype);
+ const prefix = "Failed to execute 'pipeTo' on 'ReadableStream'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ destination = webidl.converters.WritableStream(destination, {
+ prefix,
+ context: "Argument 1",
+ });
+ options = webidl.converters.StreamPipeOptions(options, {
+ prefix,
+ context: "Argument 2",
+ });
+ } catch (err) {
+ return PromiseReject(err);
}
- if (state === "closed") {
- return 0;
+ const { preventClose, preventAbort, preventCancel, signal } = options;
+ if (isReadableStreamLocked(this)) {
+ return PromiseReject(
+ new TypeError("ReadableStream is already locked."),
+ );
+ }
+ if (isWritableStreamLocked(destination)) {
+ return PromiseReject(
+ new TypeError("destination WritableStream is already locked."),
+ );
}
- return writableStreamDefaultControllerGetDesiredSize(stream[_controller]);
+ return readableStreamPipeTo(
+ this,
+ destination,
+ preventClose,
+ preventAbort,
+ preventCancel,
+ signal,
+ );
}
- /** @param {WritableStreamDefaultWriter} writer */
- function writableStreamDefaultWriterRelease(writer) {
- const stream = writer[_stream];
- assert(stream !== undefined);
- assert(stream[_writer] === writer);
- const releasedError = new TypeError(
- "The writer has already been released.",
- );
- writableStreamDefaultWriterEnsureReadyPromiseRejected(
- writer,
- releasedError,
- );
- writableStreamDefaultWriterEnsureClosedPromiseRejected(
- writer,
- releasedError,
- );
- stream[_writer] = undefined;
- writer[_stream] = undefined;
+ /** @returns {[ReadableStream<R>, ReadableStream<R>]} */
+ tee() {
+ webidl.assertBranded(this, ReadableStreamPrototype);
+ return readableStreamTee(this, false);
}
+ // TODO(lucacasonato): should be moved to webidl crate
/**
- * @template W
- * @param {WritableStreamDefaultWriter<W>} writer
- * @param {W} chunk
- * @returns {Promise<void>}
+ * @param {ReadableStreamIteratorOptions=} options
+ * @returns {AsyncIterableIterator<R>}
*/
- function writableStreamDefaultWriterWrite(writer, chunk) {
- const stream = writer[_stream];
- assert(stream !== undefined);
- const controller = stream[_controller];
- const chunkSize = writableStreamDefaultControllerGetChunkSize(
- controller,
- chunk,
- );
- if (stream !== writer[_stream]) {
- return PromiseReject(new TypeError("Writer's stream is unexpected."));
- }
- const state = stream[_state];
- if (state === "errored") {
- return PromiseReject(stream[_storedError]);
+ values(options = {}) {
+ webidl.assertBranded(this, ReadableStreamPrototype);
+ const prefix = "Failed to execute 'values' on 'ReadableStream'";
+ options = webidl.converters.ReadableStreamIteratorOptions(options, {
+ prefix,
+ context: "Argument 1",
+ });
+ /** @type {AsyncIterableIterator<R>} */
+ const iterator = ObjectCreate(readableStreamAsyncIteratorPrototype);
+ const reader = acquireReadableStreamDefaultReader(this);
+ iterator[_reader] = reader;
+ iterator[_preventCancel] = options.preventCancel;
+ return iterator;
+ }
+
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${inspect({ locked: this.locked })}`;
+ }
+}
+
+// TODO(lucacasonato): should be moved to webidl crate
+ReadableStream.prototype[SymbolAsyncIterator] = ReadableStream.prototype.values;
+ObjectDefineProperty(ReadableStream.prototype, SymbolAsyncIterator, {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+webidl.configurePrototype(ReadableStream);
+const ReadableStreamPrototype = ReadableStream.prototype;
+
+function errorReadableStream(stream, e) {
+ readableStreamDefaultControllerError(stream[_controller], e);
+}
+
+/** @template R */
+class ReadableStreamDefaultReader {
+ /** @type {Deferred<void>} */
+ [_closedPromise];
+ /** @type {ReadableStream<R> | undefined} */
+ [_stream];
+ /** @type {ReadRequest[]} */
+ [_readRequests];
+
+ /** @param {ReadableStream<R>} stream */
+ constructor(stream) {
+ const prefix = "Failed to construct 'ReadableStreamDefaultReader'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ stream = webidl.converters.ReadableStream(stream, {
+ prefix,
+ context: "Argument 1",
+ });
+ this[webidl.brand] = webidl.brand;
+ setUpReadableStreamDefaultReader(this, stream);
+ }
+
+ /** @returns {Promise<ReadableStreamReadResult<R>>} */
+ read() {
+ try {
+ webidl.assertBranded(this, ReadableStreamDefaultReaderPrototype);
+ } catch (err) {
+ return PromiseReject(err);
}
- if (
- writableStreamCloseQueuedOrInFlight(stream) === true || state === "closed"
- ) {
+ if (this[_stream] === undefined) {
return PromiseReject(
- new TypeError("The stream is closing or is closed."),
+ new TypeError("Reader has no associated stream."),
);
}
- if (state === "erroring") {
- return PromiseReject(stream[_storedError]);
- }
- assert(state === "writable");
- const promise = writableStreamAddWriteRequest(stream);
- writableStreamDefaultControllerWrite(controller, chunk, chunkSize);
- return promise;
+ /** @type {Deferred<ReadableStreamReadResult<R>>} */
+ const promise = new Deferred();
+ /** @type {ReadRequest<R>} */
+ const readRequest = {
+ chunkSteps(chunk) {
+ promise.resolve({ value: chunk, done: false });
+ },
+ closeSteps() {
+ promise.resolve({ value: undefined, done: true });
+ },
+ errorSteps(e) {
+ promise.reject(e);
+ },
+ };
+ readableStreamDefaultReaderRead(this, readRequest);
+ return promise.promise;
}
- /** @param {WritableStream} stream */
- function writableStreamFinishErroring(stream) {
- assert(stream[_state] === "erroring");
- assert(writableStreamHasOperationMarkedInFlight(stream) === false);
- stream[_state] = "errored";
- stream[_controller][_errorSteps]();
- const storedError = stream[_storedError];
- const writeRequests = stream[_writeRequests];
- for (let i = 0; i < writeRequests.length; ++i) {
- const writeRequest = writeRequests[i];
- writeRequest.reject(storedError);
- }
- stream[_writeRequests] = [];
- if (stream[_pendingAbortRequest] === undefined) {
- writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
- return;
- }
- const abortRequest = stream[_pendingAbortRequest];
- stream[_pendingAbortRequest] = undefined;
- if (abortRequest.wasAlreadyErroring === true) {
- abortRequest.deferred.reject(storedError);
- writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
+ /** @returns {void} */
+ releaseLock() {
+ webidl.assertBranded(this, ReadableStreamDefaultReaderPrototype);
+ if (this[_stream] === undefined) {
return;
}
- const promise = stream[_controller][_abortSteps](abortRequest.reason);
- uponPromise(promise, () => {
- abortRequest.deferred.resolve(undefined);
- writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
- }, (reason) => {
- abortRequest.deferred.reject(reason);
- writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
- });
+ readableStreamDefaultReaderRelease(this);
}
- /** @param {WritableStream} stream */
- function writableStreamFinishInFlightClose(stream) {
- assert(stream[_inFlightCloseRequest] !== undefined);
- stream[_inFlightCloseRequest].resolve(undefined);
- stream[_inFlightCloseRequest] = undefined;
- const state = stream[_state];
- assert(state === "writable" || state === "erroring");
- if (state === "erroring") {
- stream[_storedError] = undefined;
- if (stream[_pendingAbortRequest] !== undefined) {
- stream[_pendingAbortRequest].deferred.resolve(undefined);
- stream[_pendingAbortRequest] = undefined;
- }
- }
- stream[_state] = "closed";
- const writer = stream[_writer];
- if (writer !== undefined) {
- writer[_closedPromise].resolve(undefined);
+ get closed() {
+ try {
+ webidl.assertBranded(this, ReadableStreamDefaultReaderPrototype);
+ } catch (err) {
+ return PromiseReject(err);
}
- assert(stream[_pendingAbortRequest] === undefined);
- assert(stream[_storedError] === undefined);
+ return this[_closedPromise].promise;
}
/**
- * @param {WritableStream} stream
- * @param {any=} error
+ * @param {any} reason
+ * @returns {Promise<void>}
*/
- function writableStreamFinishInFlightCloseWithError(stream, error) {
- assert(stream[_inFlightCloseRequest] !== undefined);
- stream[_inFlightCloseRequest].reject(error);
- stream[_inFlightCloseRequest] = undefined;
- assert(stream[_state] === "writable" || stream[_state] === "erroring");
- if (stream[_pendingAbortRequest] !== undefined) {
- stream[_pendingAbortRequest].deferred.reject(error);
- stream[_pendingAbortRequest] = undefined;
+ cancel(reason = undefined) {
+ try {
+ webidl.assertBranded(this, ReadableStreamDefaultReaderPrototype);
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
+ }
+ } catch (err) {
+ return PromiseReject(err);
}
- writableStreamDealWithRejection(stream, error);
- }
- /** @param {WritableStream} stream */
- function writableStreamFinishInFlightWrite(stream) {
- assert(stream[_inFlightWriteRequest] !== undefined);
- stream[_inFlightWriteRequest].resolve(undefined);
- stream[_inFlightWriteRequest] = undefined;
+ if (this[_stream] === undefined) {
+ return PromiseReject(
+ new TypeError("Reader has no associated stream."),
+ );
+ }
+ return readableStreamReaderGenericCancel(this, reason);
}
- /**
- * @param {WritableStream} stream
- * @param {any=} error
- */
- function writableStreamFinishInFlightWriteWithError(stream, error) {
- assert(stream[_inFlightWriteRequest] !== undefined);
- stream[_inFlightWriteRequest].reject(error);
- stream[_inFlightWriteRequest] = undefined;
- assert(stream[_state] === "writable" || stream[_state] === "erroring");
- writableStreamDealWithRejection(stream, error);
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${inspect({ closed: this.closed })}`;
}
+}
- /**
- * @param {WritableStream} stream
- * @returns {boolean}
- */
- function writableStreamHasOperationMarkedInFlight(stream) {
- if (
- stream[_inFlightWriteRequest] === undefined &&
- stream[_inFlightCloseRequest] === undefined
- ) {
- return false;
- }
- return true;
- }
+webidl.configurePrototype(ReadableStreamDefaultReader);
+const ReadableStreamDefaultReaderPrototype =
+ ReadableStreamDefaultReader.prototype;
- /** @param {WritableStream} stream */
- function writableStreamMarkCloseRequestInFlight(stream) {
- assert(stream[_inFlightCloseRequest] === undefined);
- assert(stream[_closeRequest] !== undefined);
- stream[_inFlightCloseRequest] = stream[_closeRequest];
- stream[_closeRequest] = undefined;
+/** @template R */
+class ReadableStreamBYOBReader {
+ /** @type {Deferred<void>} */
+ [_closedPromise];
+ /** @type {ReadableStream<R> | undefined} */
+ [_stream];
+ /** @type {ReadIntoRequest[]} */
+ [_readIntoRequests];
+
+ /** @param {ReadableStream<R>} stream */
+ constructor(stream) {
+ const prefix = "Failed to construct 'ReadableStreamBYOBReader'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ stream = webidl.converters.ReadableStream(stream, {
+ prefix,
+ context: "Argument 1",
+ });
+ this[webidl.brand] = webidl.brand;
+ setUpReadableStreamBYOBReader(this, stream);
}
/**
- * @template W
- * @param {WritableStream<W>} stream
+ * @param {ArrayBufferView} view
+ * @returns {Promise<ReadableStreamBYOBReadResult>}
*/
- function writableStreamMarkFirstWriteRequestInFlight(stream) {
- assert(stream[_inFlightWriteRequest] === undefined);
- assert(stream[_writeRequests].length);
- const writeRequest = stream[_writeRequests].shift();
- stream[_inFlightWriteRequest] = writeRequest;
- }
+ read(view) {
+ try {
+ webidl.assertBranded(this, ReadableStreamBYOBReaderPrototype);
+ const prefix = "Failed to execute 'read' on 'ReadableStreamBYOBReader'";
+ view = webidl.converters.ArrayBufferView(view, {
+ prefix,
+ context: "Argument 1",
+ });
+ } catch (err) {
+ return PromiseReject(err);
+ }
- /** @param {WritableStream} stream */
- function writableStreamRejectCloseAndClosedPromiseIfNeeded(stream) {
- assert(stream[_state] === "errored");
- if (stream[_closeRequest] !== undefined) {
- assert(stream[_inFlightCloseRequest] === undefined);
- stream[_closeRequest].reject(stream[_storedError]);
- stream[_closeRequest] = undefined;
+ if (view.byteLength === 0) {
+ return PromiseReject(
+ new TypeError("view must have non-zero byteLength"),
+ );
}
- const writer = stream[_writer];
- if (writer !== undefined) {
- writer[_closedPromise].reject(stream[_storedError]);
- setPromiseIsHandledToTrue(writer[_closedPromise].promise);
+ if (view.buffer.byteLength === 0) {
+ return PromiseReject(
+ new TypeError("view's buffer must have non-zero byteLength"),
+ );
+ }
+ if (isDetachedBuffer(view.buffer)) {
+ return PromiseReject(
+ new TypeError("view's buffer has been detached"),
+ );
}
+ if (this[_stream] === undefined) {
+ return PromiseReject(
+ new TypeError("Reader has no associated stream."),
+ );
+ }
+ /** @type {Deferred<ReadableStreamBYOBReadResult>} */
+ const promise = new Deferred();
+ /** @type {ReadIntoRequest} */
+ const readIntoRequest = {
+ chunkSteps(chunk) {
+ promise.resolve({ value: chunk, done: false });
+ },
+ closeSteps(chunk) {
+ promise.resolve({ value: chunk, done: true });
+ },
+ errorSteps(e) {
+ promise.reject(e);
+ },
+ };
+ readableStreamBYOBReaderRead(this, view, readIntoRequest);
+ return promise.promise;
}
- /**
- * @param {WritableStream} stream
- * @param {any=} reason
- */
- function writableStreamStartErroring(stream, reason) {
- assert(stream[_storedError] === undefined);
- assert(stream[_state] === "writable");
- const controller = stream[_controller];
- assert(controller !== undefined);
- stream[_state] = "erroring";
- stream[_storedError] = reason;
- const writer = stream[_writer];
- if (writer !== undefined) {
- writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason);
- }
- if (
- writableStreamHasOperationMarkedInFlight(stream) === false &&
- controller[_started] === true
- ) {
- writableStreamFinishErroring(stream);
+ /** @returns {void} */
+ releaseLock() {
+ webidl.assertBranded(this, ReadableStreamBYOBReaderPrototype);
+ if (this[_stream] === undefined) {
+ return;
}
+ readableStreamBYOBReaderRelease(this);
}
- /**
- * @param {WritableStream} stream
- * @param {boolean} backpressure
- */
- function writableStreamUpdateBackpressure(stream, backpressure) {
- assert(stream[_state] === "writable");
- assert(writableStreamCloseQueuedOrInFlight(stream) === false);
- const writer = stream[_writer];
- if (writer !== undefined && backpressure !== stream[_backpressure]) {
- if (backpressure === true) {
- writer[_readyPromise] = new Deferred();
- } else {
- assert(backpressure === false);
- writer[_readyPromise].resolve(undefined);
- }
+ get closed() {
+ try {
+ webidl.assertBranded(this, ReadableStreamBYOBReaderPrototype);
+ } catch (err) {
+ return PromiseReject(err);
}
- stream[_backpressure] = backpressure;
+ return this[_closedPromise].promise;
}
/**
- * @template T
- * @param {T} value
- * @param {boolean} done
- * @returns {IteratorResult<T>}
+ * @param {any} reason
+ * @returns {Promise<void>}
*/
- function createIteratorResult(value, done) {
- const result = ObjectCreate(ObjectPrototype);
- ObjectDefineProperties(result, {
- value: { value, writable: true, enumerable: true, configurable: true },
- done: {
- value: done,
- writable: true,
- enumerable: true,
- configurable: true,
- },
- });
- return result;
- }
-
- /** @type {AsyncIterator<unknown, unknown>} */
- const asyncIteratorPrototype = ObjectGetPrototypeOf(AsyncGeneratorPrototype);
-
- const _iteratorNext = Symbol("[[iteratorNext]]");
- const _iteratorFinished = Symbol("[[iteratorFinished]]");
-
- /** @type {AsyncIterator<unknown>} */
- const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({
- /** @returns {Promise<IteratorResult<unknown>>} */
- next() {
- /** @type {ReadableStreamDefaultReader} */
- const reader = this[_reader];
- function nextSteps() {
- if (reader[_iteratorFinished]) {
- return PromiseResolve(createIteratorResult(undefined, true));
- }
-
- if (reader[_stream] === undefined) {
- return PromiseReject(
- new TypeError(
- "Cannot get the next iteration result once the reader has been released.",
- ),
- );
- }
-
- /** @type {Deferred<IteratorResult<any>>} */
- const promise = new Deferred();
- /** @type {ReadRequest} */
- const readRequest = {
- chunkSteps(chunk) {
- promise.resolve(createIteratorResult(chunk, false));
- },
- closeSteps() {
- readableStreamDefaultReaderRelease(reader);
- promise.resolve(createIteratorResult(undefined, true));
- },
- errorSteps(e) {
- readableStreamDefaultReaderRelease(reader);
- promise.reject(e);
- },
- };
-
- readableStreamDefaultReaderRead(reader, readRequest);
- return PromisePrototypeThen(promise.promise, (result) => {
- reader[_iteratorNext] = null;
- if (result.done === true) {
- reader[_iteratorFinished] = true;
- return createIteratorResult(undefined, true);
- }
- return result;
- }, (reason) => {
- reader[_iteratorNext] = null;
- reader[_iteratorFinished] = true;
- throw reason;
- });
+ cancel(reason = undefined) {
+ try {
+ webidl.assertBranded(this, ReadableStreamBYOBReaderPrototype);
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
}
-
- reader[_iteratorNext] = reader[_iteratorNext]
- ? PromisePrototypeThen(reader[_iteratorNext], nextSteps, nextSteps)
- : nextSteps();
-
- return reader[_iteratorNext];
- },
- /**
- * @param {unknown} arg
- * @returns {Promise<IteratorResult<unknown>>}
- */
- return(arg) {
- /** @type {ReadableStreamDefaultReader} */
- const reader = this[_reader];
- const returnSteps = () => {
- if (reader[_iteratorFinished]) {
- return PromiseResolve(createIteratorResult(arg, true));
- }
- reader[_iteratorFinished] = true;
-
- if (reader[_stream] === undefined) {
- return PromiseResolve(createIteratorResult(undefined, true));
- }
- assert(reader[_readRequests].length === 0);
- if (this[_preventCancel] === false) {
- const result = readableStreamReaderGenericCancel(reader, arg);
- readableStreamDefaultReaderRelease(reader);
- return result;
- }
- readableStreamDefaultReaderRelease(reader);
- return PromiseResolve(createIteratorResult(undefined, true));
- };
-
- const returnPromise = reader[_iteratorNext]
- ? PromisePrototypeThen(reader[_iteratorNext], returnSteps, returnSteps)
- : returnSteps();
- return PromisePrototypeThen(
- returnPromise,
- () => createIteratorResult(arg, true),
- );
- },
- }, asyncIteratorPrototype);
-
- class ByteLengthQueuingStrategy {
- /** @param {{ highWaterMark: number }} init */
- constructor(init) {
- const prefix = "Failed to construct 'ByteLengthQueuingStrategy'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- init = webidl.converters.QueuingStrategyInit(init, {
- prefix,
- context: "Argument 1",
- });
- this[webidl.brand] = webidl.brand;
- this[_globalObject] = window;
- this[_highWaterMark] = init.highWaterMark;
+ } catch (err) {
+ return PromiseReject(err);
}
- /** @returns {number} */
- get highWaterMark() {
- webidl.assertBranded(this, ByteLengthQueuingStrategyPrototype);
- return this[_highWaterMark];
- }
-
- /** @returns {(chunk: ArrayBufferView) => number} */
- get size() {
- webidl.assertBranded(this, ByteLengthQueuingStrategyPrototype);
- initializeByteLengthSizeFunction(this[_globalObject]);
- return WeakMapPrototypeGet(byteSizeFunctionWeakMap, this[_globalObject]);
+ if (this[_stream] === undefined) {
+ return PromiseReject(
+ new TypeError("Reader has no associated stream."),
+ );
}
+ return readableStreamReaderGenericCancel(this, reason);
+ }
- [SymbolFor("Deno.customInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(
- ByteLengthQueuingStrategyPrototype,
- this,
- ),
- keys: [
- "highWaterMark",
- "size",
- ],
- }));
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${inspect({ closed: this.closed })}`;
}
+}
- webidl.configurePrototype(ByteLengthQueuingStrategy);
- const ByteLengthQueuingStrategyPrototype =
- ByteLengthQueuingStrategy.prototype;
+webidl.configurePrototype(ReadableStreamBYOBReader);
+const ReadableStreamBYOBReaderPrototype = ReadableStreamBYOBReader.prototype;
- /** @type {WeakMap<typeof globalThis, (chunk: ArrayBufferView) => number>} */
- const byteSizeFunctionWeakMap = new WeakMap();
+class ReadableStreamBYOBRequest {
+ /** @type {ReadableByteStreamController} */
+ [_controller];
+ /** @type {ArrayBufferView | null} */
+ [_view];
- function initializeByteLengthSizeFunction(globalObject) {
- if (WeakMapPrototypeHas(byteSizeFunctionWeakMap, globalObject)) {
- return;
- }
- const size = (chunk) => chunk.byteLength;
- WeakMapPrototypeSet(byteSizeFunctionWeakMap, globalObject, size);
+ /** @returns {ArrayBufferView | null} */
+ get view() {
+ webidl.assertBranded(this, ReadableStreamBYOBRequestPrototype);
+ return this[_view];
}
- class CountQueuingStrategy {
- /** @param {{ highWaterMark: number }} init */
- constructor(init) {
- const prefix = "Failed to construct 'CountQueuingStrategy'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- init = webidl.converters.QueuingStrategyInit(init, {
- prefix,
- context: "Argument 1",
- });
- this[webidl.brand] = webidl.brand;
- this[_globalObject] = window;
- this[_highWaterMark] = init.highWaterMark;
- }
+ constructor() {
+ webidl.illegalConstructor();
+ }
- /** @returns {number} */
- get highWaterMark() {
- webidl.assertBranded(this, CountQueuingStrategyPrototype);
- return this[_highWaterMark];
- }
+ respond(bytesWritten) {
+ webidl.assertBranded(this, ReadableStreamBYOBRequestPrototype);
+ const prefix = "Failed to execute 'respond' on 'ReadableStreamBYOBRequest'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ bytesWritten = webidl.converters["unsigned long long"](bytesWritten, {
+ enforceRange: true,
+ prefix,
+ context: "Argument 1",
+ });
- /** @returns {(chunk: any) => 1} */
- get size() {
- webidl.assertBranded(this, CountQueuingStrategyPrototype);
- initializeCountSizeFunction(this[_globalObject]);
- return WeakMapPrototypeGet(countSizeFunctionWeakMap, this[_globalObject]);
+ if (this[_controller] === undefined) {
+ throw new TypeError("This BYOB request has been invalidated");
}
-
- [SymbolFor("Deno.customInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(
- CountQueuingStrategyPrototype,
- this,
- ),
- keys: [
- "highWaterMark",
- "size",
- ],
- }));
+ if (isDetachedBuffer(this[_view].buffer)) {
+ throw new TypeError(
+ "The BYOB request's buffer has been detached and so cannot be used as a response",
+ );
}
+ assert(this[_view].byteLength > 0);
+ assert(this[_view].buffer.byteLength > 0);
+ readableByteStreamControllerRespond(this[_controller], bytesWritten);
}
- webidl.configurePrototype(CountQueuingStrategy);
- const CountQueuingStrategyPrototype = CountQueuingStrategy.prototype;
-
- /** @type {WeakMap<typeof globalThis, () => 1>} */
- const countSizeFunctionWeakMap = new WeakMap();
-
- /** @param {typeof globalThis} globalObject */
- function initializeCountSizeFunction(globalObject) {
- if (WeakMapPrototypeHas(countSizeFunctionWeakMap, globalObject)) {
- return;
- }
- const size = () => 1;
- WeakMapPrototypeSet(countSizeFunctionWeakMap, globalObject, size);
- }
-
- const _resourceBacking = Symbol("[[resourceBacking]]");
- // This distinction exists to prevent unrefable streams being used in
- // regular fast streams that are unaware of refability
- const _resourceBackingUnrefable = Symbol("[[resourceBackingUnrefable]]");
- /** @template R */
- class ReadableStream {
- /** @type {ReadableStreamDefaultController | ReadableByteStreamController} */
- [_controller];
- /** @type {boolean} */
- [_detached];
- /** @type {boolean} */
- [_disturbed];
- /** @type {ReadableStreamDefaultReader | ReadableStreamBYOBReader} */
- [_reader];
- /** @type {"readable" | "closed" | "errored"} */
- [_state];
- /** @type {any} */
- [_storedError];
- /** @type {{ rid: number, autoClose: boolean } | null} */
- [_resourceBacking] = null;
-
- /**
- * @param {UnderlyingSource<R>=} underlyingSource
- * @param {QueuingStrategy<R>=} strategy
- */
- constructor(underlyingSource = undefined, strategy = undefined) {
- const prefix = "Failed to construct 'ReadableStream'";
- if (underlyingSource !== undefined) {
- underlyingSource = webidl.converters.object(underlyingSource, {
- prefix,
- context: "Argument 1",
- });
- } else {
- underlyingSource = null;
- }
- if (strategy !== undefined) {
- strategy = webidl.converters.QueuingStrategy(strategy, {
- prefix,
- context: "Argument 2",
- });
- } else {
- strategy = {};
- }
- this[webidl.brand] = webidl.brand;
- let underlyingSourceDict = {};
- if (underlyingSource !== undefined) {
- underlyingSourceDict = webidl.converters.UnderlyingSource(
- underlyingSource,
- { prefix, context: "underlyingSource" },
- );
- }
- initializeReadableStream(this);
- if (underlyingSourceDict.type === "bytes") {
- if (strategy.size !== undefined) {
- throw new RangeError(
- `${prefix}: When underlying source is "bytes", strategy.size must be undefined.`,
- );
- }
- const highWaterMark = extractHighWaterMark(strategy, 0);
- setUpReadableByteStreamControllerFromUnderlyingSource(
- // @ts-ignore cannot easily assert this is ReadableStream<ArrayBuffer>
- this,
- underlyingSource,
- underlyingSourceDict,
- highWaterMark,
- );
- } else {
- assert(!(ReflectHas(underlyingSourceDict, "type")));
- const sizeAlgorithm = extractSizeAlgorithm(strategy);
- const highWaterMark = extractHighWaterMark(strategy, 1);
- setUpReadableStreamDefaultControllerFromUnderlyingSource(
- this,
- underlyingSource,
- underlyingSourceDict,
- highWaterMark,
- sizeAlgorithm,
- );
- }
- }
+ respondWithNewView(view) {
+ webidl.assertBranded(this, ReadableStreamBYOBRequestPrototype);
+ const prefix =
+ "Failed to execute 'respondWithNewView' on 'ReadableStreamBYOBRequest'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ view = webidl.converters.ArrayBufferView(view, {
+ prefix,
+ context: "Argument 1",
+ });
- /** @returns {boolean} */
- get locked() {
- webidl.assertBranded(this, ReadableStreamPrototype);
- return isReadableStreamLocked(this);
+ if (this[_controller] === undefined) {
+ throw new TypeError("This BYOB request has been invalidated");
}
-
- /**
- * @param {any=} reason
- * @returns {Promise<void>}
- */
- cancel(reason = undefined) {
- try {
- webidl.assertBranded(this, ReadableStreamPrototype);
- if (reason !== undefined) {
- reason = webidl.converters.any(reason);
- }
- } catch (err) {
- return PromiseReject(err);
- }
- if (isReadableStreamLocked(this)) {
- return PromiseReject(
- new TypeError("Cannot cancel a locked ReadableStream."),
- );
- }
- return readableStreamCancel(this, reason);
+ if (isDetachedBuffer(view.buffer)) {
+ throw new TypeError(
+ "The given view's buffer has been detached and so cannot be used as a response",
+ );
}
-
- /**
- * @param {ReadableStreamGetReaderOptions=} options
- * @returns {ReadableStreamDefaultReader<R> | ReadableStreamBYOBReader}
- */
- getReader(options = undefined) {
- webidl.assertBranded(this, ReadableStreamPrototype);
- const prefix = "Failed to execute 'getReader' on 'ReadableStream'";
- if (options !== undefined) {
- options = webidl.converters.ReadableStreamGetReaderOptions(options, {
- prefix,
- context: "Argument 1",
- });
- } else {
- options = {};
- }
- if (options.mode === undefined) {
- return acquireReadableStreamDefaultReader(this);
- } else {
- assert(options.mode === "byob");
- return acquireReadableStreamBYOBReader(this);
- }
+ readableByteStreamControllerRespondWithNewView(this[_controller], view);
+ }
+}
+
+webidl.configurePrototype(ReadableStreamBYOBRequest);
+const ReadableStreamBYOBRequestPrototype = ReadableStreamBYOBRequest.prototype;
+
+class ReadableByteStreamController {
+ /** @type {number | undefined} */
+ [_autoAllocateChunkSize];
+ /** @type {ReadableStreamBYOBRequest | null} */
+ [_byobRequest];
+ /** @type {(reason: any) => Promise<void>} */
+ [_cancelAlgorithm];
+ /** @type {boolean} */
+ [_closeRequested];
+ /** @type {boolean} */
+ [_pullAgain];
+ /** @type {(controller: this) => Promise<void>} */
+ [_pullAlgorithm];
+ /** @type {boolean} */
+ [_pulling];
+ /** @type {PullIntoDescriptor[]} */
+ [_pendingPullIntos];
+ /** @type {ReadableByteStreamQueueEntry[]} */
+ [_queue];
+ /** @type {number} */
+ [_queueTotalSize];
+ /** @type {boolean} */
+ [_started];
+ /** @type {number} */
+ [_strategyHWM];
+ /** @type {ReadableStream<ArrayBuffer>} */
+ [_stream];
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /** @returns {ReadableStreamBYOBRequest | null} */
+ get byobRequest() {
+ webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
+ return readableByteStreamControllerGetBYOBRequest(this);
+ }
+
+ /** @returns {number | null} */
+ get desiredSize() {
+ webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
+ return readableByteStreamControllerGetDesiredSize(this);
+ }
+
+ /** @returns {void} */
+ close() {
+ webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
+ if (this[_closeRequested] === true) {
+ throw new TypeError("Closed already requested.");
+ }
+ if (this[_stream][_state] !== "readable") {
+ throw new TypeError(
+ "ReadableByteStreamController's stream is not in a readable state.",
+ );
}
+ readableByteStreamControllerClose(this);
+ }
- /**
- * @template T
- * @param {{ readable: ReadableStream<T>, writable: WritableStream<R> }} transform
- * @param {PipeOptions=} options
- * @returns {ReadableStream<T>}
- */
- pipeThrough(transform, options = {}) {
- webidl.assertBranded(this, ReadableStreamPrototype);
- const prefix = "Failed to execute 'pipeThrough' on 'ReadableStream'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- transform = webidl.converters.ReadableWritablePair(transform, {
- prefix,
- context: "Argument 1",
- });
- options = webidl.converters.StreamPipeOptions(options, {
+ /**
+ * @param {ArrayBufferView} chunk
+ * @returns {void}
+ */
+ enqueue(chunk) {
+ webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
+ const prefix =
+ "Failed to execute 'enqueue' on 'ReadableByteStreamController'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ const arg1 = "Argument 1";
+ chunk = webidl.converters.ArrayBufferView(chunk, {
+ prefix,
+ context: arg1,
+ });
+ if (chunk.byteLength === 0) {
+ throw webidl.makeException(TypeError, "length must be non-zero", {
prefix,
- context: "Argument 2",
+ context: arg1,
});
- const { readable, writable } = transform;
- const { preventClose, preventAbort, preventCancel, signal } = options;
- if (isReadableStreamLocked(this)) {
- throw new TypeError("ReadableStream is already locked.");
- }
- if (isWritableStreamLocked(writable)) {
- throw new TypeError("Target WritableStream is already locked.");
- }
- const promise = readableStreamPipeTo(
- this,
- writable,
- preventClose,
- preventAbort,
- preventCancel,
- signal,
- );
- setPromiseIsHandledToTrue(promise);
- return readable;
}
-
- /**
- * @param {WritableStream<R>} destination
- * @param {PipeOptions=} options
- * @returns {Promise<void>}
- */
- pipeTo(destination, options = {}) {
- try {
- webidl.assertBranded(this, ReadableStreamPrototype);
- const prefix = "Failed to execute 'pipeTo' on 'ReadableStream'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- destination = webidl.converters.WritableStream(destination, {
- prefix,
- context: "Argument 1",
- });
- options = webidl.converters.StreamPipeOptions(options, {
- prefix,
- context: "Argument 2",
- });
- } catch (err) {
- return PromiseReject(err);
- }
- const { preventClose, preventAbort, preventCancel, signal } = options;
- if (isReadableStreamLocked(this)) {
- return PromiseReject(
- new TypeError("ReadableStream is already locked."),
- );
- }
- if (isWritableStreamLocked(destination)) {
- return PromiseReject(
- new TypeError("destination WritableStream is already locked."),
- );
- }
- return readableStreamPipeTo(
- this,
- destination,
- preventClose,
- preventAbort,
- preventCancel,
- signal,
+ if (chunk.buffer.byteLength === 0) {
+ throw webidl.makeException(
+ TypeError,
+ "buffer length must be non-zero",
+ { prefix, context: arg1 },
);
}
-
- /** @returns {[ReadableStream<R>, ReadableStream<R>]} */
- tee() {
- webidl.assertBranded(this, ReadableStreamPrototype);
- return readableStreamTee(this, false);
+ if (this[_closeRequested] === true) {
+ throw new TypeError(
+ "Cannot enqueue chunk after a close has been requested.",
+ );
}
-
- // TODO(lucacasonato): should be moved to webidl crate
- /**
- * @param {ReadableStreamIteratorOptions=} options
- * @returns {AsyncIterableIterator<R>}
- */
- values(options = {}) {
- webidl.assertBranded(this, ReadableStreamPrototype);
- const prefix = "Failed to execute 'values' on 'ReadableStream'";
- options = webidl.converters.ReadableStreamIteratorOptions(options, {
- prefix,
- context: "Argument 1",
- });
- /** @type {AsyncIterableIterator<R>} */
- const iterator = ObjectCreate(readableStreamAsyncIteratorPrototype);
- const reader = acquireReadableStreamDefaultReader(this);
- iterator[_reader] = reader;
- iterator[_preventCancel] = options.preventCancel;
- return iterator;
+ if (this[_stream][_state] !== "readable") {
+ throw new TypeError(
+ "Cannot enqueue chunk when underlying stream is not readable.",
+ );
}
+ return readableByteStreamControllerEnqueue(this, chunk);
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${inspect({ locked: this.locked })}`;
+ /**
+ * @param {any=} e
+ * @returns {void}
+ */
+ error(e = undefined) {
+ webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
+ if (e !== undefined) {
+ e = webidl.converters.any(e);
}
+ readableByteStreamControllerError(this, e);
}
- // TODO(lucacasonato): should be moved to webidl crate
- ReadableStream.prototype[SymbolAsyncIterator] =
- ReadableStream.prototype.values;
- ObjectDefineProperty(ReadableStream.prototype, SymbolAsyncIterator, {
- writable: true,
- enumerable: false,
- configurable: true,
- });
-
- webidl.configurePrototype(ReadableStream);
- const ReadableStreamPrototype = ReadableStream.prototype;
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ ReadableByteStreamControllerPrototype,
+ this,
+ ),
+ keys: ["desiredSize"],
+ }));
+ }
- function errorReadableStream(stream, e) {
- readableStreamDefaultControllerError(stream[_controller], e);
+ /**
+ * @param {any} reason
+ * @returns {Promise<void>}
+ */
+ [_cancelSteps](reason) {
+ readableByteStreamControllerClearPendingPullIntos(this);
+ resetQueue(this);
+ const result = this[_cancelAlgorithm](reason);
+ readableByteStreamControllerClearAlgorithms(this);
+ return result;
}
- /** @template R */
- class ReadableStreamDefaultReader {
- /** @type {Deferred<void>} */
- [_closedPromise];
- /** @type {ReadableStream<R> | undefined} */
- [_stream];
- /** @type {ReadRequest[]} */
- [_readRequests];
-
- /** @param {ReadableStream<R>} stream */
- constructor(stream) {
- const prefix = "Failed to construct 'ReadableStreamDefaultReader'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- stream = webidl.converters.ReadableStream(stream, {
- prefix,
- context: "Argument 1",
- });
- this[webidl.brand] = webidl.brand;
- setUpReadableStreamDefaultReader(this, stream);
+ /**
+ * @param {ReadRequest<ArrayBuffer>} readRequest
+ * @returns {void}
+ */
+ [_pullSteps](readRequest) {
+ /** @type {ReadableStream<ArrayBuffer>} */
+ const stream = this[_stream];
+ assert(readableStreamHasDefaultReader(stream));
+ if (this[_queueTotalSize] > 0) {
+ assert(readableStreamGetNumReadRequests(stream) === 0);
+ readableByteStreamControllerFillReadRequestFromQueue(this, readRequest);
+ return;
}
-
- /** @returns {Promise<ReadableStreamReadResult<R>>} */
- read() {
+ const autoAllocateChunkSize = this[_autoAllocateChunkSize];
+ if (autoAllocateChunkSize !== undefined) {
+ let buffer;
try {
- webidl.assertBranded(this, ReadableStreamDefaultReaderPrototype);
- } catch (err) {
- return PromiseReject(err);
- }
- if (this[_stream] === undefined) {
- return PromiseReject(
- new TypeError("Reader has no associated stream."),
- );
- }
- /** @type {Deferred<ReadableStreamReadResult<R>>} */
- const promise = new Deferred();
- /** @type {ReadRequest<R>} */
- const readRequest = {
- chunkSteps(chunk) {
- promise.resolve({ value: chunk, done: false });
- },
- closeSteps() {
- promise.resolve({ value: undefined, done: true });
- },
- errorSteps(e) {
- promise.reject(e);
- },
- };
- readableStreamDefaultReaderRead(this, readRequest);
- return promise.promise;
- }
-
- /** @returns {void} */
- releaseLock() {
- webidl.assertBranded(this, ReadableStreamDefaultReaderPrototype);
- if (this[_stream] === undefined) {
+ buffer = new ArrayBuffer(autoAllocateChunkSize);
+ } catch (e) {
+ readRequest.errorSteps(e);
return;
}
- readableStreamDefaultReaderRelease(this);
- }
-
- get closed() {
- try {
- webidl.assertBranded(this, ReadableStreamDefaultReaderPrototype);
- } catch (err) {
- return PromiseReject(err);
- }
- return this[_closedPromise].promise;
- }
-
- /**
- * @param {any} reason
- * @returns {Promise<void>}
- */
- cancel(reason = undefined) {
- try {
- webidl.assertBranded(this, ReadableStreamDefaultReaderPrototype);
- if (reason !== undefined) {
- reason = webidl.converters.any(reason);
- }
- } catch (err) {
- return PromiseReject(err);
- }
-
- if (this[_stream] === undefined) {
- return PromiseReject(
- new TypeError("Reader has no associated stream."),
- );
- }
- return readableStreamReaderGenericCancel(this, reason);
+ /** @type {PullIntoDescriptor} */
+ const pullIntoDescriptor = {
+ buffer,
+ bufferByteLength: autoAllocateChunkSize,
+ byteOffset: 0,
+ byteLength: autoAllocateChunkSize,
+ bytesFilled: 0,
+ elementSize: 1,
+ viewConstructor: Uint8Array,
+ readerType: "default",
+ };
+ ArrayPrototypePush(this[_pendingPullIntos], pullIntoDescriptor);
}
+ readableStreamAddReadRequest(stream, readRequest);
+ readableByteStreamControllerCallPullIfNeeded(this);
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${inspect({ closed: this.closed })}`;
+ [_releaseSteps]() {
+ if (this[_pendingPullIntos].length !== 0) {
+ /** @type {PullIntoDescriptor} */
+ const firstPendingPullInto = this[_pendingPullIntos][0];
+ firstPendingPullInto.readerType = "none";
+ this[_pendingPullIntos] = [firstPendingPullInto];
}
}
+}
- webidl.configurePrototype(ReadableStreamDefaultReader);
- const ReadableStreamDefaultReaderPrototype =
- ReadableStreamDefaultReader.prototype;
+webidl.configurePrototype(ReadableByteStreamController);
+const ReadableByteStreamControllerPrototype =
+ ReadableByteStreamController.prototype;
- /** @template R */
- class ReadableStreamBYOBReader {
- /** @type {Deferred<void>} */
- [_closedPromise];
- /** @type {ReadableStream<R> | undefined} */
- [_stream];
- /** @type {ReadIntoRequest[]} */
- [_readIntoRequests];
-
- /** @param {ReadableStream<R>} stream */
- constructor(stream) {
- const prefix = "Failed to construct 'ReadableStreamBYOBReader'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- stream = webidl.converters.ReadableStream(stream, {
- prefix,
- context: "Argument 1",
- });
- this[webidl.brand] = webidl.brand;
- setUpReadableStreamBYOBReader(this, stream);
- }
+/** @template R */
+class ReadableStreamDefaultController {
+ /** @type {(reason: any) => Promise<void>} */
+ [_cancelAlgorithm];
+ /** @type {boolean} */
+ [_closeRequested];
+ /** @type {boolean} */
+ [_pullAgain];
+ /** @type {(controller: this) => Promise<void>} */
+ [_pullAlgorithm];
+ /** @type {boolean} */
+ [_pulling];
+ /** @type {Array<ValueWithSize<R>>} */
+ [_queue];
+ /** @type {number} */
+ [_queueTotalSize];
+ /** @type {boolean} */
+ [_started];
+ /** @type {number} */
+ [_strategyHWM];
+ /** @type {(chunk: R) => number} */
+ [_strategySizeAlgorithm];
+ /** @type {ReadableStream<R>} */
+ [_stream];
- /**
- * @param {ArrayBufferView} view
- * @returns {Promise<ReadableStreamBYOBReadResult>}
- */
- read(view) {
- try {
- webidl.assertBranded(this, ReadableStreamBYOBReaderPrototype);
- const prefix = "Failed to execute 'read' on 'ReadableStreamBYOBReader'";
- view = webidl.converters.ArrayBufferView(view, {
- prefix,
- context: "Argument 1",
- });
- } catch (err) {
- return PromiseReject(err);
- }
+ constructor() {
+ webidl.illegalConstructor();
+ }
- if (view.byteLength === 0) {
- return PromiseReject(
- new TypeError("view must have non-zero byteLength"),
- );
- }
- if (view.buffer.byteLength === 0) {
- return PromiseReject(
- new TypeError("view's buffer must have non-zero byteLength"),
- );
- }
- if (isDetachedBuffer(view.buffer)) {
- return PromiseReject(
- new TypeError("view's buffer has been detached"),
- );
- }
- if (this[_stream] === undefined) {
- return PromiseReject(
- new TypeError("Reader has no associated stream."),
- );
- }
- /** @type {Deferred<ReadableStreamBYOBReadResult>} */
- const promise = new Deferred();
- /** @type {ReadIntoRequest} */
- const readIntoRequest = {
- chunkSteps(chunk) {
- promise.resolve({ value: chunk, done: false });
- },
- closeSteps(chunk) {
- promise.resolve({ value: chunk, done: true });
- },
- errorSteps(e) {
- promise.reject(e);
- },
- };
- readableStreamBYOBReaderRead(this, view, readIntoRequest);
- return promise.promise;
- }
+ /** @returns {number | null} */
+ get desiredSize() {
+ webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);
+ return readableStreamDefaultControllerGetDesiredSize(this);
+ }
- /** @returns {void} */
- releaseLock() {
- webidl.assertBranded(this, ReadableStreamBYOBReaderPrototype);
- if (this[_stream] === undefined) {
- return;
- }
- readableStreamBYOBReaderRelease(this);
+ /** @returns {void} */
+ close() {
+ webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);
+ if (readableStreamDefaultControllerCanCloseOrEnqueue(this) === false) {
+ throw new TypeError("The stream controller cannot close or enqueue.");
}
+ readableStreamDefaultControllerClose(this);
+ }
- get closed() {
- try {
- webidl.assertBranded(this, ReadableStreamBYOBReaderPrototype);
- } catch (err) {
- return PromiseReject(err);
- }
- return this[_closedPromise].promise;
+ /**
+ * @param {R} chunk
+ * @returns {void}
+ */
+ enqueue(chunk = undefined) {
+ webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);
+ if (chunk !== undefined) {
+ chunk = webidl.converters.any(chunk);
}
-
- /**
- * @param {any} reason
- * @returns {Promise<void>}
- */
- cancel(reason = undefined) {
- try {
- webidl.assertBranded(this, ReadableStreamBYOBReaderPrototype);
- if (reason !== undefined) {
- reason = webidl.converters.any(reason);
- }
- } catch (err) {
- return PromiseReject(err);
- }
-
- if (this[_stream] === undefined) {
- return PromiseReject(
- new TypeError("Reader has no associated stream."),
- );
- }
- return readableStreamReaderGenericCancel(this, reason);
+ if (readableStreamDefaultControllerCanCloseOrEnqueue(this) === false) {
+ throw new TypeError("The stream controller cannot close or enqueue.");
}
+ readableStreamDefaultControllerEnqueue(this, chunk);
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${inspect({ closed: this.closed })}`;
+ /**
+ * @param {any=} e
+ * @returns {void}
+ */
+ error(e = undefined) {
+ webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);
+ if (e !== undefined) {
+ e = webidl.converters.any(e);
}
+ readableStreamDefaultControllerError(this, e);
}
- webidl.configurePrototype(ReadableStreamBYOBReader);
- const ReadableStreamBYOBReaderPrototype = ReadableStreamBYOBReader.prototype;
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ ReadableStreamDefaultController.prototype,
+ this,
+ ),
+ keys: ["desiredSize"],
+ }));
+ }
- class ReadableStreamBYOBRequest {
- /** @type {ReadableByteStreamController} */
- [_controller];
- /** @type {ArrayBufferView | null} */
- [_view];
+ /**
+ * @param {any} reason
+ * @returns {Promise<void>}
+ */
+ [_cancelSteps](reason) {
+ resetQueue(this);
+ const result = this[_cancelAlgorithm](reason);
+ readableStreamDefaultControllerClearAlgorithms(this);
+ return result;
+ }
- /** @returns {ArrayBufferView | null} */
- get view() {
- webidl.assertBranded(this, ReadableStreamBYOBRequestPrototype);
- return this[_view];
+ /**
+ * @param {ReadRequest<R>} readRequest
+ * @returns {void}
+ */
+ [_pullSteps](readRequest) {
+ const stream = this[_stream];
+ if (this[_queue].length) {
+ const chunk = dequeueValue(this);
+ if (this[_closeRequested] && this[_queue].length === 0) {
+ readableStreamDefaultControllerClearAlgorithms(this);
+ readableStreamClose(stream);
+ } else {
+ readableStreamDefaultControllerCallPullIfNeeded(this);
+ }
+ readRequest.chunkSteps(chunk);
+ } else {
+ readableStreamAddReadRequest(stream, readRequest);
+ readableStreamDefaultControllerCallPullIfNeeded(this);
}
+ }
- constructor() {
- webidl.illegalConstructor();
- }
+ [_releaseSteps]() {
+ return;
+ }
+}
- respond(bytesWritten) {
- webidl.assertBranded(this, ReadableStreamBYOBRequestPrototype);
- const prefix =
- "Failed to execute 'respond' on 'ReadableStreamBYOBRequest'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- bytesWritten = webidl.converters["unsigned long long"](bytesWritten, {
- enforceRange: true,
- prefix,
- context: "Argument 1",
- });
+webidl.configurePrototype(ReadableStreamDefaultController);
+const ReadableStreamDefaultControllerPrototype =
+ ReadableStreamDefaultController.prototype;
- if (this[_controller] === undefined) {
- throw new TypeError("This BYOB request has been invalidated");
- }
- if (isDetachedBuffer(this[_view].buffer)) {
- throw new TypeError(
- "The BYOB request's buffer has been detached and so cannot be used as a response",
- );
- }
- assert(this[_view].byteLength > 0);
- assert(this[_view].buffer.byteLength > 0);
- readableByteStreamControllerRespond(this[_controller], bytesWritten);
- }
+/**
+ * @template I
+ * @template O
+ */
+class TransformStream {
+ /** @type {boolean} */
+ [_backpressure];
+ /** @type {Deferred<void>} */
+ [_backpressureChangePromise];
+ /** @type {TransformStreamDefaultController<O>} */
+ [_controller];
+ /** @type {boolean} */
+ [_detached];
+ /** @type {ReadableStream<O>} */
+ [_readable];
+ /** @type {WritableStream<I>} */
+ [_writable];
- respondWithNewView(view) {
- webidl.assertBranded(this, ReadableStreamBYOBRequestPrototype);
- const prefix =
- "Failed to execute 'respondWithNewView' on 'ReadableStreamBYOBRequest'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- view = webidl.converters.ArrayBufferView(view, {
+ /**
+ * @param {Transformer<I, O>} transformer
+ * @param {QueuingStrategy<I>} writableStrategy
+ * @param {QueuingStrategy<O>} readableStrategy
+ */
+ constructor(
+ transformer = undefined,
+ writableStrategy = {},
+ readableStrategy = {},
+ ) {
+ const prefix = "Failed to construct 'TransformStream'";
+ if (transformer !== undefined) {
+ transformer = webidl.converters.object(transformer, {
prefix,
context: "Argument 1",
});
-
- if (this[_controller] === undefined) {
- throw new TypeError("This BYOB request has been invalidated");
- }
- if (isDetachedBuffer(view.buffer)) {
- throw new TypeError(
- "The given view's buffer has been detached and so cannot be used as a response",
- );
- }
- readableByteStreamControllerRespondWithNewView(this[_controller], view);
- }
- }
-
- webidl.configurePrototype(ReadableStreamBYOBRequest);
- const ReadableStreamBYOBRequestPrototype =
- ReadableStreamBYOBRequest.prototype;
-
- class ReadableByteStreamController {
- /** @type {number | undefined} */
- [_autoAllocateChunkSize];
- /** @type {ReadableStreamBYOBRequest | null} */
- [_byobRequest];
- /** @type {(reason: any) => Promise<void>} */
- [_cancelAlgorithm];
- /** @type {boolean} */
- [_closeRequested];
- /** @type {boolean} */
- [_pullAgain];
- /** @type {(controller: this) => Promise<void>} */
- [_pullAlgorithm];
- /** @type {boolean} */
- [_pulling];
- /** @type {PullIntoDescriptor[]} */
- [_pendingPullIntos];
- /** @type {ReadableByteStreamQueueEntry[]} */
- [_queue];
- /** @type {number} */
- [_queueTotalSize];
- /** @type {boolean} */
- [_started];
- /** @type {number} */
- [_strategyHWM];
- /** @type {ReadableStream<ArrayBuffer>} */
- [_stream];
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- /** @returns {ReadableStreamBYOBRequest | null} */
- get byobRequest() {
- webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
- return readableByteStreamControllerGetBYOBRequest(this);
}
-
- /** @returns {number | null} */
- get desiredSize() {
- webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
- return readableByteStreamControllerGetDesiredSize(this);
- }
-
- /** @returns {void} */
- close() {
- webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
- if (this[_closeRequested] === true) {
- throw new TypeError("Closed already requested.");
- }
- if (this[_stream][_state] !== "readable") {
- throw new TypeError(
- "ReadableByteStreamController's stream is not in a readable state.",
- );
- }
- readableByteStreamControllerClose(this);
+ writableStrategy = webidl.converters.QueuingStrategy(writableStrategy, {
+ prefix,
+ context: "Argument 2",
+ });
+ readableStrategy = webidl.converters.QueuingStrategy(readableStrategy, {
+ prefix,
+ context: "Argument 2",
+ });
+ this[webidl.brand] = webidl.brand;
+ if (transformer === undefined) {
+ transformer = null;
}
-
- /**
- * @param {ArrayBufferView} chunk
- * @returns {void}
- */
- enqueue(chunk) {
- webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
- const prefix =
- "Failed to execute 'enqueue' on 'ReadableByteStreamController'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- const arg1 = "Argument 1";
- chunk = webidl.converters.ArrayBufferView(chunk, {
- prefix,
- context: arg1,
- });
- if (chunk.byteLength === 0) {
- throw webidl.makeException(TypeError, "length must be non-zero", {
- prefix,
- context: arg1,
- });
- }
- if (chunk.buffer.byteLength === 0) {
- throw webidl.makeException(
- TypeError,
- "buffer length must be non-zero",
- { prefix, context: arg1 },
- );
- }
- if (this[_closeRequested] === true) {
- throw new TypeError(
- "Cannot enqueue chunk after a close has been requested.",
- );
- }
- if (this[_stream][_state] !== "readable") {
- throw new TypeError(
- "Cannot enqueue chunk when underlying stream is not readable.",
- );
- }
- return readableByteStreamControllerEnqueue(this, chunk);
+ const transformerDict = webidl.converters.Transformer(transformer, {
+ prefix,
+ context: "transformer",
+ });
+ if (transformerDict.readableType !== undefined) {
+ throw new RangeError(
+ `${prefix}: readableType transformers not supported.`,
+ );
}
-
- /**
- * @param {any=} e
- * @returns {void}
- */
- error(e = undefined) {
- webidl.assertBranded(this, ReadableByteStreamControllerPrototype);
- if (e !== undefined) {
- e = webidl.converters.any(e);
- }
- readableByteStreamControllerError(this, e);
+ if (transformerDict.writableType !== undefined) {
+ throw new RangeError(
+ `${prefix}: writableType transformers not supported.`,
+ );
}
-
- [SymbolFor("Deno.customInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(
- ReadableByteStreamControllerPrototype,
- this,
+ const readableHighWaterMark = extractHighWaterMark(readableStrategy, 0);
+ const readableSizeAlgorithm = extractSizeAlgorithm(readableStrategy);
+ const writableHighWaterMark = extractHighWaterMark(writableStrategy, 1);
+ const writableSizeAlgorithm = extractSizeAlgorithm(writableStrategy);
+ /** @type {Deferred<void>} */
+ const startPromise = new Deferred();
+ initializeTransformStream(
+ this,
+ startPromise,
+ writableHighWaterMark,
+ writableSizeAlgorithm,
+ readableHighWaterMark,
+ readableSizeAlgorithm,
+ );
+ setUpTransformStreamDefaultControllerFromTransformer(
+ this,
+ transformer,
+ transformerDict,
+ );
+ if (transformerDict.start) {
+ startPromise.resolve(
+ webidl.invokeCallbackFunction(
+ transformerDict.start,
+ [this[_controller]],
+ transformer,
+ webidl.converters.any,
+ {
+ prefix:
+ "Failed to call 'start' on 'TransformStreamDefaultController'",
+ },
),
- keys: ["desiredSize"],
- }));
- }
-
- /**
- * @param {any} reason
- * @returns {Promise<void>}
- */
- [_cancelSteps](reason) {
- readableByteStreamControllerClearPendingPullIntos(this);
- resetQueue(this);
- const result = this[_cancelAlgorithm](reason);
- readableByteStreamControllerClearAlgorithms(this);
- return result;
- }
-
- /**
- * @param {ReadRequest<ArrayBuffer>} readRequest
- * @returns {void}
- */
- [_pullSteps](readRequest) {
- /** @type {ReadableStream<ArrayBuffer>} */
- const stream = this[_stream];
- assert(readableStreamHasDefaultReader(stream));
- if (this[_queueTotalSize] > 0) {
- assert(readableStreamGetNumReadRequests(stream) === 0);
- readableByteStreamControllerFillReadRequestFromQueue(this, readRequest);
- return;
- }
- const autoAllocateChunkSize = this[_autoAllocateChunkSize];
- if (autoAllocateChunkSize !== undefined) {
- let buffer;
- try {
- buffer = new ArrayBuffer(autoAllocateChunkSize);
- } catch (e) {
- readRequest.errorSteps(e);
- return;
- }
- /** @type {PullIntoDescriptor} */
- const pullIntoDescriptor = {
- buffer,
- bufferByteLength: autoAllocateChunkSize,
- byteOffset: 0,
- byteLength: autoAllocateChunkSize,
- bytesFilled: 0,
- elementSize: 1,
- viewConstructor: Uint8Array,
- readerType: "default",
- };
- ArrayPrototypePush(this[_pendingPullIntos], pullIntoDescriptor);
- }
- readableStreamAddReadRequest(stream, readRequest);
- readableByteStreamControllerCallPullIfNeeded(this);
+ );
+ } else {
+ startPromise.resolve(undefined);
}
+ }
- [_releaseSteps]() {
- if (this[_pendingPullIntos].length !== 0) {
- /** @type {PullIntoDescriptor} */
- const firstPendingPullInto = this[_pendingPullIntos][0];
- firstPendingPullInto.readerType = "none";
- this[_pendingPullIntos] = [firstPendingPullInto];
- }
- }
+ /** @returns {ReadableStream<O>} */
+ get readable() {
+ webidl.assertBranded(this, TransformStreamPrototype);
+ return this[_readable];
}
- webidl.configurePrototype(ReadableByteStreamController);
- const ReadableByteStreamControllerPrototype =
- ReadableByteStreamController.prototype;
-
- /** @template R */
- class ReadableStreamDefaultController {
- /** @type {(reason: any) => Promise<void>} */
- [_cancelAlgorithm];
- /** @type {boolean} */
- [_closeRequested];
- /** @type {boolean} */
- [_pullAgain];
- /** @type {(controller: this) => Promise<void>} */
- [_pullAlgorithm];
- /** @type {boolean} */
- [_pulling];
- /** @type {Array<ValueWithSize<R>>} */
- [_queue];
- /** @type {number} */
- [_queueTotalSize];
- /** @type {boolean} */
- [_started];
- /** @type {number} */
- [_strategyHWM];
- /** @type {(chunk: R) => number} */
- [_strategySizeAlgorithm];
- /** @type {ReadableStream<R>} */
- [_stream];
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- /** @returns {number | null} */
- get desiredSize() {
- webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);
- return readableStreamDefaultControllerGetDesiredSize(this);
- }
-
- /** @returns {void} */
- close() {
- webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);
- if (readableStreamDefaultControllerCanCloseOrEnqueue(this) === false) {
- throw new TypeError("The stream controller cannot close or enqueue.");
- }
- readableStreamDefaultControllerClose(this);
- }
+ /** @returns {WritableStream<I>} */
+ get writable() {
+ webidl.assertBranded(this, TransformStreamPrototype);
+ return this[_writable];
+ }
- /**
- * @param {R} chunk
- * @returns {void}
- */
- enqueue(chunk = undefined) {
- webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);
- if (chunk !== undefined) {
- chunk = webidl.converters.any(chunk);
- }
- if (readableStreamDefaultControllerCanCloseOrEnqueue(this) === false) {
- throw new TypeError("The stream controller cannot close or enqueue.");
- }
- readableStreamDefaultControllerEnqueue(this, chunk);
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({ readable: this.readable, writable: this.writable })
+ }`;
+ }
+}
- /**
- * @param {any=} e
- * @returns {void}
- */
- error(e = undefined) {
- webidl.assertBranded(this, ReadableStreamDefaultControllerPrototype);
- if (e !== undefined) {
- e = webidl.converters.any(e);
- }
- readableStreamDefaultControllerError(this, e);
- }
+webidl.configurePrototype(TransformStream);
+const TransformStreamPrototype = TransformStream.prototype;
- [SymbolFor("Deno.customInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(
- ReadableStreamDefaultController.prototype,
- this,
- ),
- keys: ["desiredSize"],
- }));
- }
-
- /**
- * @param {any} reason
- * @returns {Promise<void>}
- */
- [_cancelSteps](reason) {
- resetQueue(this);
- const result = this[_cancelAlgorithm](reason);
- readableStreamDefaultControllerClearAlgorithms(this);
- return result;
- }
-
- /**
- * @param {ReadRequest<R>} readRequest
- * @returns {void}
- */
- [_pullSteps](readRequest) {
- const stream = this[_stream];
- if (this[_queue].length) {
- const chunk = dequeueValue(this);
- if (this[_closeRequested] && this[_queue].length === 0) {
- readableStreamDefaultControllerClearAlgorithms(this);
- readableStreamClose(stream);
- } else {
- readableStreamDefaultControllerCallPullIfNeeded(this);
- }
- readRequest.chunkSteps(chunk);
- } else {
- readableStreamAddReadRequest(stream, readRequest);
- readableStreamDefaultControllerCallPullIfNeeded(this);
- }
- }
+/** @template O */
+class TransformStreamDefaultController {
+ /** @type {(controller: this) => Promise<void>} */
+ [_flushAlgorithm];
+ /** @type {TransformStream<O>} */
+ [_stream];
+ /** @type {(chunk: O, controller: this) => Promise<void>} */
+ [_transformAlgorithm];
- [_releaseSteps]() {
- return;
- }
+ constructor() {
+ webidl.illegalConstructor();
}
- webidl.configurePrototype(ReadableStreamDefaultController);
- const ReadableStreamDefaultControllerPrototype =
- ReadableStreamDefaultController.prototype;
+ /** @returns {number | null} */
+ get desiredSize() {
+ webidl.assertBranded(this, TransformStreamDefaultController.prototype);
+ const readableController = this[_stream][_readable][_controller];
+ return readableStreamDefaultControllerGetDesiredSize(
+ /** @type {ReadableStreamDefaultController<O>} */ readableController,
+ );
+ }
/**
- * @template I
- * @template O
+ * @param {O} chunk
+ * @returns {void}
*/
- class TransformStream {
- /** @type {boolean} */
- [_backpressure];
- /** @type {Deferred<void>} */
- [_backpressureChangePromise];
- /** @type {TransformStreamDefaultController<O>} */
- [_controller];
- /** @type {boolean} */
- [_detached];
- /** @type {ReadableStream<O>} */
- [_readable];
- /** @type {WritableStream<I>} */
- [_writable];
-
- /**
- * @param {Transformer<I, O>} transformer
- * @param {QueuingStrategy<I>} writableStrategy
- * @param {QueuingStrategy<O>} readableStrategy
- */
- constructor(
- transformer = undefined,
- writableStrategy = {},
- readableStrategy = {},
- ) {
- const prefix = "Failed to construct 'TransformStream'";
- if (transformer !== undefined) {
- transformer = webidl.converters.object(transformer, {
- prefix,
- context: "Argument 1",
- });
- }
- writableStrategy = webidl.converters.QueuingStrategy(writableStrategy, {
- prefix,
- context: "Argument 2",
- });
- readableStrategy = webidl.converters.QueuingStrategy(readableStrategy, {
- prefix,
- context: "Argument 2",
- });
- this[webidl.brand] = webidl.brand;
- if (transformer === undefined) {
- transformer = null;
- }
- const transformerDict = webidl.converters.Transformer(transformer, {
- prefix,
- context: "transformer",
- });
- if (transformerDict.readableType !== undefined) {
- throw new RangeError(
- `${prefix}: readableType transformers not supported.`,
- );
- }
- if (transformerDict.writableType !== undefined) {
- throw new RangeError(
- `${prefix}: writableType transformers not supported.`,
- );
- }
- const readableHighWaterMark = extractHighWaterMark(readableStrategy, 0);
- const readableSizeAlgorithm = extractSizeAlgorithm(readableStrategy);
- const writableHighWaterMark = extractHighWaterMark(writableStrategy, 1);
- const writableSizeAlgorithm = extractSizeAlgorithm(writableStrategy);
- /** @type {Deferred<void>} */
- const startPromise = new Deferred();
- initializeTransformStream(
- this,
- startPromise,
- writableHighWaterMark,
- writableSizeAlgorithm,
- readableHighWaterMark,
- readableSizeAlgorithm,
- );
- setUpTransformStreamDefaultControllerFromTransformer(
- this,
- transformer,
- transformerDict,
- );
- if (transformerDict.start) {
- startPromise.resolve(
- webidl.invokeCallbackFunction(
- transformerDict.start,
- [this[_controller]],
- transformer,
- webidl.converters.any,
- {
- prefix:
- "Failed to call 'start' on 'TransformStreamDefaultController'",
- },
- ),
- );
- } else {
- startPromise.resolve(undefined);
- }
- }
-
- /** @returns {ReadableStream<O>} */
- get readable() {
- webidl.assertBranded(this, TransformStreamPrototype);
- return this[_readable];
- }
-
- /** @returns {WritableStream<I>} */
- get writable() {
- webidl.assertBranded(this, TransformStreamPrototype);
- return this[_writable];
+ enqueue(chunk = undefined) {
+ webidl.assertBranded(this, TransformStreamDefaultController.prototype);
+ if (chunk !== undefined) {
+ chunk = webidl.converters.any(chunk);
}
+ transformStreamDefaultControllerEnqueue(this, chunk);
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({ readable: this.readable, writable: this.writable })
- }`;
+ /**
+ * @param {any=} reason
+ * @returns {void}
+ */
+ error(reason = undefined) {
+ webidl.assertBranded(this, TransformStreamDefaultController.prototype);
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
}
+ transformStreamDefaultControllerError(this, reason);
}
- webidl.configurePrototype(TransformStream);
- const TransformStreamPrototype = TransformStream.prototype;
-
- /** @template O */
- class TransformStreamDefaultController {
- /** @type {(controller: this) => Promise<void>} */
- [_flushAlgorithm];
- /** @type {TransformStream<O>} */
- [_stream];
- /** @type {(chunk: O, controller: this) => Promise<void>} */
- [_transformAlgorithm];
+ /** @returns {void} */
+ terminate() {
+ webidl.assertBranded(this, TransformStreamDefaultControllerPrototype);
+ transformStreamDefaultControllerTerminate(this);
+ }
- constructor() {
- webidl.illegalConstructor();
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ TransformStreamDefaultController.prototype,
+ this,
+ ),
+ keys: ["desiredSize"],
+ }));
+ }
+}
+
+webidl.configurePrototype(TransformStreamDefaultController);
+const TransformStreamDefaultControllerPrototype =
+ TransformStreamDefaultController.prototype;
+
+/** @template W */
+class WritableStream {
+ /** @type {boolean} */
+ [_backpressure];
+ /** @type {Deferred<void> | undefined} */
+ [_closeRequest];
+ /** @type {WritableStreamDefaultController<W>} */
+ [_controller];
+ /** @type {boolean} */
+ [_detached];
+ /** @type {Deferred<void> | undefined} */
+ [_inFlightWriteRequest];
+ /** @type {Deferred<void> | undefined} */
+ [_inFlightCloseRequest];
+ /** @type {PendingAbortRequest | undefined} */
+ [_pendingAbortRequest];
+ /** @type {"writable" | "closed" | "erroring" | "errored"} */
+ [_state];
+ /** @type {any} */
+ [_storedError];
+ /** @type {WritableStreamDefaultWriter<W>} */
+ [_writer];
+ /** @type {Deferred<void>[]} */
+ [_writeRequests];
+
+ /**
+ * @param {UnderlyingSink<W>=} underlyingSink
+ * @param {QueuingStrategy<W>=} strategy
+ */
+ constructor(underlyingSink = undefined, strategy = {}) {
+ const prefix = "Failed to construct 'WritableStream'";
+ if (underlyingSink !== undefined) {
+ underlyingSink = webidl.converters.object(underlyingSink, {
+ prefix,
+ context: "Argument 1",
+ });
}
-
- /** @returns {number | null} */
- get desiredSize() {
- webidl.assertBranded(this, TransformStreamDefaultController.prototype);
- const readableController = this[_stream][_readable][_controller];
- return readableStreamDefaultControllerGetDesiredSize(
- /** @type {ReadableStreamDefaultController<O>} */ readableController,
+ strategy = webidl.converters.QueuingStrategy(strategy, {
+ prefix,
+ context: "Argument 2",
+ });
+ this[webidl.brand] = webidl.brand;
+ if (underlyingSink === undefined) {
+ underlyingSink = null;
+ }
+ const underlyingSinkDict = webidl.converters.UnderlyingSink(
+ underlyingSink,
+ { prefix, context: "underlyingSink" },
+ );
+ if (underlyingSinkDict.type != null) {
+ throw new RangeError(
+ `${prefix}: WritableStream does not support 'type' in the underlying sink.`,
);
}
+ initializeWritableStream(this);
+ const sizeAlgorithm = extractSizeAlgorithm(strategy);
+ const highWaterMark = extractHighWaterMark(strategy, 1);
+ setUpWritableStreamDefaultControllerFromUnderlyingSink(
+ this,
+ underlyingSink,
+ underlyingSinkDict,
+ highWaterMark,
+ sizeAlgorithm,
+ );
+ }
- /**
- * @param {O} chunk
- * @returns {void}
- */
- enqueue(chunk = undefined) {
- webidl.assertBranded(this, TransformStreamDefaultController.prototype);
- if (chunk !== undefined) {
- chunk = webidl.converters.any(chunk);
- }
- transformStreamDefaultControllerEnqueue(this, chunk);
- }
+ /** @returns {boolean} */
+ get locked() {
+ webidl.assertBranded(this, WritableStreamPrototype);
+ return isWritableStreamLocked(this);
+ }
- /**
- * @param {any=} reason
- * @returns {void}
- */
- error(reason = undefined) {
- webidl.assertBranded(this, TransformStreamDefaultController.prototype);
- if (reason !== undefined) {
- reason = webidl.converters.any(reason);
- }
- transformStreamDefaultControllerError(this, reason);
+ /**
+ * @param {any=} reason
+ * @returns {Promise<void>}
+ */
+ abort(reason = undefined) {
+ try {
+ webidl.assertBranded(this, WritableStreamPrototype);
+ } catch (err) {
+ return PromiseReject(err);
}
-
- /** @returns {void} */
- terminate() {
- webidl.assertBranded(this, TransformStreamDefaultControllerPrototype);
- transformStreamDefaultControllerTerminate(this);
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
}
-
- [SymbolFor("Deno.customInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(
- TransformStreamDefaultController.prototype,
- this,
+ if (isWritableStreamLocked(this)) {
+ return PromiseReject(
+ new TypeError(
+ "The writable stream is locked, therefore cannot be aborted.",
),
- keys: ["desiredSize"],
- }));
- }
- }
-
- webidl.configurePrototype(TransformStreamDefaultController);
- const TransformStreamDefaultControllerPrototype =
- TransformStreamDefaultController.prototype;
-
- /** @template W */
- class WritableStream {
- /** @type {boolean} */
- [_backpressure];
- /** @type {Deferred<void> | undefined} */
- [_closeRequest];
- /** @type {WritableStreamDefaultController<W>} */
- [_controller];
- /** @type {boolean} */
- [_detached];
- /** @type {Deferred<void> | undefined} */
- [_inFlightWriteRequest];
- /** @type {Deferred<void> | undefined} */
- [_inFlightCloseRequest];
- /** @type {PendingAbortRequest | undefined} */
- [_pendingAbortRequest];
- /** @type {"writable" | "closed" | "erroring" | "errored"} */
- [_state];
- /** @type {any} */
- [_storedError];
- /** @type {WritableStreamDefaultWriter<W>} */
- [_writer];
- /** @type {Deferred<void>[]} */
- [_writeRequests];
-
- /**
- * @param {UnderlyingSink<W>=} underlyingSink
- * @param {QueuingStrategy<W>=} strategy
- */
- constructor(underlyingSink = undefined, strategy = {}) {
- const prefix = "Failed to construct 'WritableStream'";
- if (underlyingSink !== undefined) {
- underlyingSink = webidl.converters.object(underlyingSink, {
- prefix,
- context: "Argument 1",
- });
- }
- strategy = webidl.converters.QueuingStrategy(strategy, {
- prefix,
- context: "Argument 2",
- });
- this[webidl.brand] = webidl.brand;
- if (underlyingSink === undefined) {
- underlyingSink = null;
- }
- const underlyingSinkDict = webidl.converters.UnderlyingSink(
- underlyingSink,
- { prefix, context: "underlyingSink" },
- );
- if (underlyingSinkDict.type != null) {
- throw new RangeError(
- `${prefix}: WritableStream does not support 'type' in the underlying sink.`,
- );
- }
- initializeWritableStream(this);
- const sizeAlgorithm = extractSizeAlgorithm(strategy);
- const highWaterMark = extractHighWaterMark(strategy, 1);
- setUpWritableStreamDefaultControllerFromUnderlyingSink(
- this,
- underlyingSink,
- underlyingSinkDict,
- highWaterMark,
- sizeAlgorithm,
);
}
+ return writableStreamAbort(this, reason);
+ }
- /** @returns {boolean} */
- get locked() {
+ /** @returns {Promise<void>} */
+ close() {
+ try {
webidl.assertBranded(this, WritableStreamPrototype);
- return isWritableStreamLocked(this);
+ } catch (err) {
+ return PromiseReject(err);
}
-
- /**
- * @param {any=} reason
- * @returns {Promise<void>}
- */
- abort(reason = undefined) {
- try {
- webidl.assertBranded(this, WritableStreamPrototype);
- } catch (err) {
- return PromiseReject(err);
- }
- if (reason !== undefined) {
- reason = webidl.converters.any(reason);
- }
- if (isWritableStreamLocked(this)) {
- return PromiseReject(
- new TypeError(
- "The writable stream is locked, therefore cannot be aborted.",
- ),
- );
- }
- return writableStreamAbort(this, reason);
+ if (isWritableStreamLocked(this)) {
+ return PromiseReject(
+ new TypeError(
+ "The writable stream is locked, therefore cannot be closed.",
+ ),
+ );
}
-
- /** @returns {Promise<void>} */
- close() {
- try {
- webidl.assertBranded(this, WritableStreamPrototype);
- } catch (err) {
- return PromiseReject(err);
- }
- if (isWritableStreamLocked(this)) {
- return PromiseReject(
- new TypeError(
- "The writable stream is locked, therefore cannot be closed.",
- ),
- );
- }
- if (writableStreamCloseQueuedOrInFlight(this) === true) {
- return PromiseReject(
- new TypeError("The writable stream is already closing."),
- );
- }
- return writableStreamClose(this);
+ if (writableStreamCloseQueuedOrInFlight(this) === true) {
+ return PromiseReject(
+ new TypeError("The writable stream is already closing."),
+ );
}
+ return writableStreamClose(this);
+ }
- /** @returns {WritableStreamDefaultWriter<W>} */
- getWriter() {
- webidl.assertBranded(this, WritableStreamPrototype);
- return acquireWritableStreamDefaultWriter(this);
- }
+ /** @returns {WritableStreamDefaultWriter<W>} */
+ getWriter() {
+ webidl.assertBranded(this, WritableStreamPrototype);
+ return acquireWritableStreamDefaultWriter(this);
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${inspect({ locked: this.locked })}`;
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${inspect({ locked: this.locked })}`;
}
+}
- webidl.configurePrototype(WritableStream);
- const WritableStreamPrototype = WritableStream.prototype;
+webidl.configurePrototype(WritableStream);
+const WritableStreamPrototype = WritableStream.prototype;
- /** @template W */
- class WritableStreamDefaultWriter {
- /** @type {Deferred<void>} */
- [_closedPromise];
+/** @template W */
+class WritableStreamDefaultWriter {
+ /** @type {Deferred<void>} */
+ [_closedPromise];
- /** @type {Deferred<void>} */
- [_readyPromise];
+ /** @type {Deferred<void>} */
+ [_readyPromise];
- /** @type {WritableStream<W>} */
- [_stream];
+ /** @type {WritableStream<W>} */
+ [_stream];
- /**
- * @param {WritableStream<W>} stream
- */
- constructor(stream) {
- const prefix = "Failed to construct 'WritableStreamDefaultWriter'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- stream = webidl.converters.WritableStream(stream, {
- prefix,
- context: "Argument 1",
- });
- this[webidl.brand] = webidl.brand;
- setUpWritableStreamDefaultWriter(this, stream);
+ /**
+ * @param {WritableStream<W>} stream
+ */
+ constructor(stream) {
+ const prefix = "Failed to construct 'WritableStreamDefaultWriter'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ stream = webidl.converters.WritableStream(stream, {
+ prefix,
+ context: "Argument 1",
+ });
+ this[webidl.brand] = webidl.brand;
+ setUpWritableStreamDefaultWriter(this, stream);
+ }
+
+ /** @returns {Promise<void>} */
+ get closed() {
+ try {
+ webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
+ } catch (err) {
+ return PromiseReject(err);
}
+ return this[_closedPromise].promise;
+ }
- /** @returns {Promise<void>} */
- get closed() {
- try {
- webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
- } catch (err) {
- return PromiseReject(err);
- }
- return this[_closedPromise].promise;
+ /** @returns {number} */
+ get desiredSize() {
+ webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
+ if (this[_stream] === undefined) {
+ throw new TypeError(
+ "A writable stream is not associated with the writer.",
+ );
}
+ return writableStreamDefaultWriterGetDesiredSize(this);
+ }
- /** @returns {number} */
- get desiredSize() {
+ /** @returns {Promise<void>} */
+ get ready() {
+ try {
webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
- if (this[_stream] === undefined) {
- throw new TypeError(
- "A writable stream is not associated with the writer.",
- );
- }
- return writableStreamDefaultWriterGetDesiredSize(this);
+ } catch (err) {
+ return PromiseReject(err);
}
+ return this[_readyPromise].promise;
+ }
- /** @returns {Promise<void>} */
- get ready() {
- try {
- webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
- } catch (err) {
- return PromiseReject(err);
- }
- return this[_readyPromise].promise;
+ /**
+ * @param {any} reason
+ * @returns {Promise<void>}
+ */
+ abort(reason = undefined) {
+ try {
+ webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
+ } catch (err) {
+ return PromiseReject(err);
}
-
- /**
- * @param {any} reason
- * @returns {Promise<void>}
- */
- abort(reason = undefined) {
- try {
- webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
- } catch (err) {
- return PromiseReject(err);
- }
- if (reason !== undefined) {
- reason = webidl.converters.any(reason);
- }
- if (this[_stream] === undefined) {
- return PromiseReject(
- new TypeError("A writable stream is not associated with the writer."),
- );
- }
- return writableStreamDefaultWriterAbort(this, reason);
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
}
-
- /** @returns {Promise<void>} */
- close() {
- try {
- webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
- } catch (err) {
- return PromiseReject(err);
- }
- const stream = this[_stream];
- if (stream === undefined) {
- return PromiseReject(
- new TypeError("A writable stream is not associated with the writer."),
- );
- }
- if (writableStreamCloseQueuedOrInFlight(stream) === true) {
- return PromiseReject(
- new TypeError("The associated stream is already closing."),
- );
- }
- return writableStreamDefaultWriterClose(this);
+ if (this[_stream] === undefined) {
+ return PromiseReject(
+ new TypeError("A writable stream is not associated with the writer."),
+ );
}
+ return writableStreamDefaultWriterAbort(this, reason);
+ }
- /** @returns {void} */
- releaseLock() {
+ /** @returns {Promise<void>} */
+ close() {
+ try {
webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
- const stream = this[_stream];
- if (stream === undefined) {
- return;
- }
- assert(stream[_writer] !== undefined);
- writableStreamDefaultWriterRelease(this);
+ } catch (err) {
+ return PromiseReject(err);
}
+ const stream = this[_stream];
+ if (stream === undefined) {
+ return PromiseReject(
+ new TypeError("A writable stream is not associated with the writer."),
+ );
+ }
+ if (writableStreamCloseQueuedOrInFlight(stream) === true) {
+ return PromiseReject(
+ new TypeError("The associated stream is already closing."),
+ );
+ }
+ return writableStreamDefaultWriterClose(this);
+ }
- /**
- * @param {W} chunk
- * @returns {Promise<void>}
- */
- write(chunk = undefined) {
- try {
- webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
- if (chunk !== undefined) {
- chunk = webidl.converters.any(chunk);
- }
- } catch (err) {
- return PromiseReject(err);
- }
- if (this[_stream] === undefined) {
- return PromiseReject(
- new TypeError("A writable stream is not associate with the writer."),
- );
- }
- return writableStreamDefaultWriterWrite(this, chunk);
+ /** @returns {void} */
+ releaseLock() {
+ webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
+ const stream = this[_stream];
+ if (stream === undefined) {
+ return;
}
+ assert(stream[_writer] !== undefined);
+ writableStreamDefaultWriterRelease(this);
+ }
- [SymbolFor("Deno.customInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(
- WritableStreamDefaultWriter.prototype,
- this,
- ),
- keys: [
- "closed",
- "desiredSize",
- "ready",
- ],
- }));
- }
- }
-
- webidl.configurePrototype(WritableStreamDefaultWriter);
- const WritableStreamDefaultWriterPrototype =
- WritableStreamDefaultWriter.prototype;
-
- /** @template W */
- class WritableStreamDefaultController {
- /** @type {(reason?: any) => Promise<void>} */
- [_abortAlgorithm];
- /** @type {() => Promise<void>} */
- [_closeAlgorithm];
- /** @type {ValueWithSize<W | _close>[]} */
- [_queue];
- /** @type {number} */
- [_queueTotalSize];
- /** @type {boolean} */
- [_started];
- /** @type {number} */
- [_strategyHWM];
- /** @type {(chunk: W) => number} */
- [_strategySizeAlgorithm];
- /** @type {WritableStream<W>} */
- [_stream];
- /** @type {(chunk: W, controller: this) => Promise<void>} */
- [_writeAlgorithm];
- /** @type {AbortSignal} */
- [_signal];
-
- get signal() {
- webidl.assertBranded(this, WritableStreamDefaultControllerPrototype);
- return this[_signal];
- }
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- /**
- * @param {any=} e
- * @returns {void}
- */
- error(e = undefined) {
- webidl.assertBranded(this, WritableStreamDefaultControllerPrototype);
- if (e !== undefined) {
- e = webidl.converters.any(e);
- }
- const state = this[_stream][_state];
- if (state !== "writable") {
- return;
+ /**
+ * @param {W} chunk
+ * @returns {Promise<void>}
+ */
+ write(chunk = undefined) {
+ try {
+ webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
+ if (chunk !== undefined) {
+ chunk = webidl.converters.any(chunk);
}
- writableStreamDefaultControllerError(this, e);
+ } catch (err) {
+ return PromiseReject(err);
}
-
- [SymbolFor("Deno.customInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(
- WritableStreamDefaultController.prototype,
- this,
- ),
- keys: [],
- }));
+ if (this[_stream] === undefined) {
+ return PromiseReject(
+ new TypeError("A writable stream is not associate with the writer."),
+ );
}
+ return writableStreamDefaultWriterWrite(this, chunk);
+ }
- /**
- * @param {any=} reason
- * @returns {Promise<void>}
- */
- [_abortSteps](reason) {
- const result = this[_abortAlgorithm](reason);
- writableStreamDefaultControllerClearAlgorithms(this);
- return result;
- }
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ WritableStreamDefaultWriter.prototype,
+ this,
+ ),
+ keys: [
+ "closed",
+ "desiredSize",
+ "ready",
+ ],
+ }));
+ }
+}
+
+webidl.configurePrototype(WritableStreamDefaultWriter);
+const WritableStreamDefaultWriterPrototype =
+ WritableStreamDefaultWriter.prototype;
+
+/** @template W */
+class WritableStreamDefaultController {
+ /** @type {(reason?: any) => Promise<void>} */
+ [_abortAlgorithm];
+ /** @type {() => Promise<void>} */
+ [_closeAlgorithm];
+ /** @type {ValueWithSize<W | _close>[]} */
+ [_queue];
+ /** @type {number} */
+ [_queueTotalSize];
+ /** @type {boolean} */
+ [_started];
+ /** @type {number} */
+ [_strategyHWM];
+ /** @type {(chunk: W) => number} */
+ [_strategySizeAlgorithm];
+ /** @type {WritableStream<W>} */
+ [_stream];
+ /** @type {(chunk: W, controller: this) => Promise<void>} */
+ [_writeAlgorithm];
+ /** @type {AbortSignal} */
+ [_signal];
+
+ get signal() {
+ webidl.assertBranded(this, WritableStreamDefaultControllerPrototype);
+ return this[_signal];
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
- [_errorSteps]() {
- resetQueue(this);
+ /**
+ * @param {any=} e
+ * @returns {void}
+ */
+ error(e = undefined) {
+ webidl.assertBranded(this, WritableStreamDefaultControllerPrototype);
+ if (e !== undefined) {
+ e = webidl.converters.any(e);
+ }
+ const state = this[_stream][_state];
+ if (state !== "writable") {
+ return;
}
+ writableStreamDefaultControllerError(this, e);
}
- webidl.configurePrototype(WritableStreamDefaultController);
- const WritableStreamDefaultControllerPrototype =
- WritableStreamDefaultController.prototype;
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ WritableStreamDefaultController.prototype,
+ this,
+ ),
+ keys: [],
+ }));
+ }
/**
- * @param {ReadableStream} stream
+ * @param {any=} reason
+ * @returns {Promise<void>}
*/
- function createProxy(stream) {
- return stream.pipeThrough(new TransformStream());
+ [_abortSteps](reason) {
+ const result = this[_abortAlgorithm](reason);
+ writableStreamDefaultControllerClearAlgorithms(this);
+ return result;
}
- webidl.converters.ReadableStream = webidl
- .createInterfaceConverter("ReadableStream", ReadableStream.prototype);
- webidl.converters.WritableStream = webidl
- .createInterfaceConverter("WritableStream", WritableStream.prototype);
+ [_errorSteps]() {
+ resetQueue(this);
+ }
+}
- webidl.converters.ReadableStreamType = webidl.createEnumConverter(
- "ReadableStreamType",
- ["bytes"],
- );
+webidl.configurePrototype(WritableStreamDefaultController);
+const WritableStreamDefaultControllerPrototype =
+ WritableStreamDefaultController.prototype;
- webidl.converters.UnderlyingSource = webidl
- .createDictionaryConverter("UnderlyingSource", [
- {
- key: "start",
- converter: webidl.converters.Function,
- },
- {
- key: "pull",
- converter: webidl.converters.Function,
- },
- {
- key: "cancel",
- converter: webidl.converters.Function,
- },
- {
- key: "type",
- converter: webidl.converters.ReadableStreamType,
- },
- {
- key: "autoAllocateChunkSize",
- converter: (V, opts) =>
- webidl.converters["unsigned long long"](V, {
- ...opts,
- enforceRange: true,
- }),
- },
- ]);
- webidl.converters.UnderlyingSink = webidl
- .createDictionaryConverter("UnderlyingSink", [
- {
- key: "start",
- converter: webidl.converters.Function,
- },
- {
- key: "write",
- converter: webidl.converters.Function,
- },
- {
- key: "close",
- converter: webidl.converters.Function,
- },
- {
- key: "abort",
- converter: webidl.converters.Function,
- },
- {
- key: "type",
- converter: webidl.converters.any,
- },
- ]);
- webidl.converters.Transformer = webidl
- .createDictionaryConverter("Transformer", [
- {
- key: "start",
- converter: webidl.converters.Function,
- },
- {
- key: "transform",
- converter: webidl.converters.Function,
- },
- {
- key: "flush",
- converter: webidl.converters.Function,
- },
- {
- key: "readableType",
- converter: webidl.converters.any,
- },
- {
- key: "writableType",
- converter: webidl.converters.any,
- },
- ]);
- webidl.converters.QueuingStrategy = webidl
- .createDictionaryConverter("QueuingStrategy", [
- {
- key: "highWaterMark",
- converter: webidl.converters["unrestricted double"],
- },
- {
- key: "size",
- converter: webidl.converters.Function,
- },
- ]);
- webidl.converters.QueuingStrategyInit = webidl
- .createDictionaryConverter("QueuingStrategyInit", [
- {
- key: "highWaterMark",
- converter: webidl.converters["unrestricted double"],
- required: true,
- },
- ]);
-
- webidl.converters.ReadableStreamIteratorOptions = webidl
- .createDictionaryConverter("ReadableStreamIteratorOptions", [
- {
- key: "preventCancel",
- defaultValue: false,
- converter: webidl.converters.boolean,
- },
- ]);
-
- webidl.converters.ReadableStreamReaderMode = webidl
- .createEnumConverter("ReadableStreamReaderMode", ["byob"]);
- webidl.converters.ReadableStreamGetReaderOptions = webidl
- .createDictionaryConverter("ReadableStreamGetReaderOptions", [{
- key: "mode",
- converter: webidl.converters.ReadableStreamReaderMode,
- }]);
-
- webidl.converters.ReadableWritablePair = webidl
- .createDictionaryConverter("ReadableWritablePair", [
- {
- key: "readable",
- converter: webidl.converters.ReadableStream,
- required: true,
- },
- {
- key: "writable",
- converter: webidl.converters.WritableStream,
- required: true,
- },
- ]);
- webidl.converters.StreamPipeOptions = webidl
- .createDictionaryConverter("StreamPipeOptions", [
- {
- key: "preventClose",
- defaultValue: false,
- converter: webidl.converters.boolean,
- },
- {
- key: "preventAbort",
- defaultValue: false,
- converter: webidl.converters.boolean,
- },
- {
- key: "preventCancel",
- defaultValue: false,
- converter: webidl.converters.boolean,
- },
- { key: "signal", converter: webidl.converters.AbortSignal },
- ]);
-
- window.__bootstrap.streams = {
- // Non-Public
- _state,
- isReadableStreamDisturbed,
- errorReadableStream,
- createProxy,
- writableStreamClose,
- readableStreamClose,
- readableStreamCollectIntoUint8Array,
- readableStreamDisturb,
- readableStreamForRid,
- readableStreamForRidUnrefable,
- readableStreamForRidUnrefableRef,
- readableStreamForRidUnrefableUnref,
- readableStreamThrowIfErrored,
- getReadableStreamResourceBacking,
- writableStreamForRid,
- getWritableStreamResourceBacking,
- Deferred,
- // Exposed in global runtime scope
- ByteLengthQueuingStrategy,
- CountQueuingStrategy,
- ReadableStream,
- ReadableStreamPrototype,
- ReadableStreamDefaultReader,
- TransformStream,
- WritableStream,
- WritableStreamDefaultWriter,
- WritableStreamDefaultController,
- ReadableByteStreamController,
- ReadableStreamBYOBReader,
- ReadableStreamBYOBRequest,
- ReadableStreamDefaultController,
- TransformStreamDefaultController,
- };
-})(this);
+/**
+ * @param {ReadableStream} stream
+ */
+function createProxy(stream) {
+ return stream.pipeThrough(new TransformStream());
+}
+
+webidl.converters.ReadableStream = webidl
+ .createInterfaceConverter("ReadableStream", ReadableStream.prototype);
+webidl.converters.WritableStream = webidl
+ .createInterfaceConverter("WritableStream", WritableStream.prototype);
+
+webidl.converters.ReadableStreamType = webidl.createEnumConverter(
+ "ReadableStreamType",
+ ["bytes"],
+);
+
+webidl.converters.UnderlyingSource = webidl
+ .createDictionaryConverter("UnderlyingSource", [
+ {
+ key: "start",
+ converter: webidl.converters.Function,
+ },
+ {
+ key: "pull",
+ converter: webidl.converters.Function,
+ },
+ {
+ key: "cancel",
+ converter: webidl.converters.Function,
+ },
+ {
+ key: "type",
+ converter: webidl.converters.ReadableStreamType,
+ },
+ {
+ key: "autoAllocateChunkSize",
+ converter: (V, opts) =>
+ webidl.converters["unsigned long long"](V, {
+ ...opts,
+ enforceRange: true,
+ }),
+ },
+ ]);
+webidl.converters.UnderlyingSink = webidl
+ .createDictionaryConverter("UnderlyingSink", [
+ {
+ key: "start",
+ converter: webidl.converters.Function,
+ },
+ {
+ key: "write",
+ converter: webidl.converters.Function,
+ },
+ {
+ key: "close",
+ converter: webidl.converters.Function,
+ },
+ {
+ key: "abort",
+ converter: webidl.converters.Function,
+ },
+ {
+ key: "type",
+ converter: webidl.converters.any,
+ },
+ ]);
+webidl.converters.Transformer = webidl
+ .createDictionaryConverter("Transformer", [
+ {
+ key: "start",
+ converter: webidl.converters.Function,
+ },
+ {
+ key: "transform",
+ converter: webidl.converters.Function,
+ },
+ {
+ key: "flush",
+ converter: webidl.converters.Function,
+ },
+ {
+ key: "readableType",
+ converter: webidl.converters.any,
+ },
+ {
+ key: "writableType",
+ converter: webidl.converters.any,
+ },
+ ]);
+webidl.converters.QueuingStrategy = webidl
+ .createDictionaryConverter("QueuingStrategy", [
+ {
+ key: "highWaterMark",
+ converter: webidl.converters["unrestricted double"],
+ },
+ {
+ key: "size",
+ converter: webidl.converters.Function,
+ },
+ ]);
+webidl.converters.QueuingStrategyInit = webidl
+ .createDictionaryConverter("QueuingStrategyInit", [
+ {
+ key: "highWaterMark",
+ converter: webidl.converters["unrestricted double"],
+ required: true,
+ },
+ ]);
+
+webidl.converters.ReadableStreamIteratorOptions = webidl
+ .createDictionaryConverter("ReadableStreamIteratorOptions", [
+ {
+ key: "preventCancel",
+ defaultValue: false,
+ converter: webidl.converters.boolean,
+ },
+ ]);
+
+webidl.converters.ReadableStreamReaderMode = webidl
+ .createEnumConverter("ReadableStreamReaderMode", ["byob"]);
+webidl.converters.ReadableStreamGetReaderOptions = webidl
+ .createDictionaryConverter("ReadableStreamGetReaderOptions", [{
+ key: "mode",
+ converter: webidl.converters.ReadableStreamReaderMode,
+ }]);
+
+webidl.converters.ReadableWritablePair = webidl
+ .createDictionaryConverter("ReadableWritablePair", [
+ {
+ key: "readable",
+ converter: webidl.converters.ReadableStream,
+ required: true,
+ },
+ {
+ key: "writable",
+ converter: webidl.converters.WritableStream,
+ required: true,
+ },
+ ]);
+webidl.converters.StreamPipeOptions = webidl
+ .createDictionaryConverter("StreamPipeOptions", [
+ {
+ key: "preventClose",
+ defaultValue: false,
+ converter: webidl.converters.boolean,
+ },
+ {
+ key: "preventAbort",
+ defaultValue: false,
+ converter: webidl.converters.boolean,
+ },
+ {
+ key: "preventCancel",
+ defaultValue: false,
+ converter: webidl.converters.boolean,
+ },
+ { key: "signal", converter: webidl.converters.AbortSignal },
+ ]);
+
+export {
+ // Non-Public
+ _state,
+ // Exposed in global runtime scope
+ ByteLengthQueuingStrategy,
+ CountQueuingStrategy,
+ createProxy,
+ Deferred,
+ errorReadableStream,
+ getReadableStreamResourceBacking,
+ getWritableStreamResourceBacking,
+ isReadableStreamDisturbed,
+ ReadableByteStreamController,
+ ReadableStream,
+ ReadableStreamBYOBReader,
+ ReadableStreamBYOBRequest,
+ readableStreamClose,
+ readableStreamCollectIntoUint8Array,
+ ReadableStreamDefaultController,
+ ReadableStreamDefaultReader,
+ readableStreamDisturb,
+ readableStreamForRid,
+ readableStreamForRidUnrefable,
+ readableStreamForRidUnrefableRef,
+ readableStreamForRidUnrefableUnref,
+ ReadableStreamPrototype,
+ readableStreamThrowIfErrored,
+ TransformStream,
+ TransformStreamDefaultController,
+ WritableStream,
+ writableStreamClose,
+ WritableStreamDefaultController,
+ WritableStreamDefaultWriter,
+ writableStreamForRid,
+};
diff --git a/ext/web/08_text_encoding.js b/ext/web/08_text_encoding.js
index 8de7b949f..f3ad966d0 100644
--- a/ext/web/08_text_encoding.js
+++ b/ext/web/08_text_encoding.js
@@ -9,437 +9,434 @@
/// <reference path="../web/lib.deno_web.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-
-((window) => {
- const core = Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const {
- PromiseReject,
- PromiseResolve,
- // TODO(lucacasonato): add SharedArrayBuffer to primordials
- // SharedArrayBufferPrototype
- StringPrototypeCharCodeAt,
- StringPrototypeSlice,
- TypedArrayPrototypeSubarray,
- Uint8Array,
- ObjectPrototypeIsPrototypeOf,
- ArrayBufferIsView,
- Uint32Array,
- } = window.__bootstrap.primordials;
-
- class TextDecoder {
- /** @type {string} */
- #encoding;
- /** @type {boolean} */
- #fatal;
- /** @type {boolean} */
- #ignoreBOM;
- /** @type {boolean} */
- #utf8SinglePass;
-
- /** @type {number | null} */
- #rid = null;
-
- /**
- * @param {string} label
- * @param {TextDecoderOptions} options
- */
- constructor(label = "utf-8", options = {}) {
- const prefix = "Failed to construct 'TextDecoder'";
- label = webidl.converters.DOMString(label, {
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ PromiseReject,
+ PromiseResolve,
+ // TODO(lucacasonato): add SharedArrayBuffer to primordials
+ // SharedArrayBufferPrototype
+ StringPrototypeCharCodeAt,
+ StringPrototypeSlice,
+ TypedArrayPrototypeSubarray,
+ Uint8Array,
+ ObjectPrototypeIsPrototypeOf,
+ ArrayBufferIsView,
+ Uint32Array,
+} = primordials;
+
+class TextDecoder {
+ /** @type {string} */
+ #encoding;
+ /** @type {boolean} */
+ #fatal;
+ /** @type {boolean} */
+ #ignoreBOM;
+ /** @type {boolean} */
+ #utf8SinglePass;
+
+ /** @type {number | null} */
+ #rid = null;
+
+ /**
+ * @param {string} label
+ * @param {TextDecoderOptions} options
+ */
+ constructor(label = "utf-8", options = {}) {
+ const prefix = "Failed to construct 'TextDecoder'";
+ label = webidl.converters.DOMString(label, {
+ prefix,
+ context: "Argument 1",
+ });
+ options = webidl.converters.TextDecoderOptions(options, {
+ prefix,
+ context: "Argument 2",
+ });
+ const encoding = ops.op_encoding_normalize_label(label);
+ this.#encoding = encoding;
+ this.#fatal = options.fatal;
+ this.#ignoreBOM = options.ignoreBOM;
+ this.#utf8SinglePass = encoding === "utf-8" && !options.fatal;
+ this[webidl.brand] = webidl.brand;
+ }
+
+ /** @returns {string} */
+ get encoding() {
+ webidl.assertBranded(this, TextDecoderPrototype);
+ return this.#encoding;
+ }
+
+ /** @returns {boolean} */
+ get fatal() {
+ webidl.assertBranded(this, TextDecoderPrototype);
+ return this.#fatal;
+ }
+
+ /** @returns {boolean} */
+ get ignoreBOM() {
+ webidl.assertBranded(this, TextDecoderPrototype);
+ return this.#ignoreBOM;
+ }
+
+ /**
+ * @param {BufferSource} [input]
+ * @param {TextDecodeOptions} options
+ */
+ decode(input = new Uint8Array(), options = undefined) {
+ webidl.assertBranded(this, TextDecoderPrototype);
+ const prefix = "Failed to execute 'decode' on 'TextDecoder'";
+ if (input !== undefined) {
+ input = webidl.converters.BufferSource(input, {
prefix,
context: "Argument 1",
+ allowShared: true,
});
- options = webidl.converters.TextDecoderOptions(options, {
+ }
+ let stream = false;
+ if (options !== undefined) {
+ options = webidl.converters.TextDecodeOptions(options, {
prefix,
context: "Argument 2",
});
- const encoding = ops.op_encoding_normalize_label(label);
- this.#encoding = encoding;
- this.#fatal = options.fatal;
- this.#ignoreBOM = options.ignoreBOM;
- this.#utf8SinglePass = encoding === "utf-8" && !options.fatal;
- this[webidl.brand] = webidl.brand;
+ stream = options.stream;
}
- /** @returns {string} */
- get encoding() {
- webidl.assertBranded(this, TextDecoderPrototype);
- return this.#encoding;
- }
-
- /** @returns {boolean} */
- get fatal() {
- webidl.assertBranded(this, TextDecoderPrototype);
- return this.#fatal;
- }
-
- /** @returns {boolean} */
- get ignoreBOM() {
- webidl.assertBranded(this, TextDecoderPrototype);
- return this.#ignoreBOM;
- }
-
- /**
- * @param {BufferSource} [input]
- * @param {TextDecodeOptions} options
- */
- decode(input = new Uint8Array(), options = undefined) {
- webidl.assertBranded(this, TextDecoderPrototype);
- const prefix = "Failed to execute 'decode' on 'TextDecoder'";
- if (input !== undefined) {
- input = webidl.converters.BufferSource(input, {
- prefix,
- context: "Argument 1",
- allowShared: true,
- });
- }
- let stream = false;
- if (options !== undefined) {
- options = webidl.converters.TextDecodeOptions(options, {
- prefix,
- context: "Argument 2",
- });
- stream = options.stream;
+ try {
+ // Note from spec: implementations are strongly encouraged to use an implementation strategy that avoids this copy.
+ // When doing so they will have to make sure that changes to input do not affect future calls to decode().
+ if (
+ ObjectPrototypeIsPrototypeOf(
+ // deno-lint-ignore prefer-primordials
+ SharedArrayBuffer.prototype,
+ input || input.buffer,
+ )
+ ) {
+ // We clone the data into a non-shared ArrayBuffer so we can pass it
+ // to Rust.
+ // `input` is now a Uint8Array, and calling the TypedArray constructor
+ // with a TypedArray argument copies the data.
+ if (ArrayBufferIsView(input)) {
+ input = new Uint8Array(
+ input.buffer,
+ input.byteOffset,
+ input.byteLength,
+ );
+ } else {
+ input = new Uint8Array(input);
+ }
}
- try {
- // Note from spec: implementations are strongly encouraged to use an implementation strategy that avoids this copy.
- // When doing so they will have to make sure that changes to input do not affect future calls to decode().
- if (
- ObjectPrototypeIsPrototypeOf(
- // deno-lint-ignore prefer-primordials
- SharedArrayBuffer.prototype,
- input || input.buffer,
- )
- ) {
- // We clone the data into a non-shared ArrayBuffer so we can pass it
- // to Rust.
- // `input` is now a Uint8Array, and calling the TypedArray constructor
- // with a TypedArray argument copies the data.
- if (ArrayBufferIsView(input)) {
- input = new Uint8Array(
- input.buffer,
- input.byteOffset,
- input.byteLength,
- );
- } else {
- input = new Uint8Array(input);
- }
+ // Fast path for single pass encoding.
+ if (!stream && this.#rid === null) {
+ // Fast path for utf8 single pass encoding.
+ if (this.#utf8SinglePass) {
+ return ops.op_encoding_decode_utf8(input, this.#ignoreBOM);
}
- // Fast path for single pass encoding.
- if (!stream && this.#rid === null) {
- // Fast path for utf8 single pass encoding.
- if (this.#utf8SinglePass) {
- return ops.op_encoding_decode_utf8(input, this.#ignoreBOM);
- }
-
- return ops.op_encoding_decode_single(
- input,
- this.#encoding,
- this.#fatal,
- this.#ignoreBOM,
- );
- }
+ return ops.op_encoding_decode_single(
+ input,
+ this.#encoding,
+ this.#fatal,
+ this.#ignoreBOM,
+ );
+ }
- if (this.#rid === null) {
- this.#rid = ops.op_encoding_new_decoder(
- this.#encoding,
- this.#fatal,
- this.#ignoreBOM,
- );
- }
- return ops.op_encoding_decode(input, this.#rid, stream);
- } finally {
- if (!stream && this.#rid !== null) {
- core.close(this.#rid);
- this.#rid = null;
- }
+ if (this.#rid === null) {
+ this.#rid = ops.op_encoding_new_decoder(
+ this.#encoding,
+ this.#fatal,
+ this.#ignoreBOM,
+ );
+ }
+ return ops.op_encoding_decode(input, this.#rid, stream);
+ } finally {
+ if (!stream && this.#rid !== null) {
+ core.close(this.#rid);
+ this.#rid = null;
}
}
}
+}
- webidl.configurePrototype(TextDecoder);
- const TextDecoderPrototype = TextDecoder.prototype;
+webidl.configurePrototype(TextDecoder);
+const TextDecoderPrototype = TextDecoder.prototype;
- class TextEncoder {
- constructor() {
- this[webidl.brand] = webidl.brand;
- }
+class TextEncoder {
+ constructor() {
+ this[webidl.brand] = webidl.brand;
+ }
- /** @returns {string} */
- get encoding() {
- webidl.assertBranded(this, TextEncoderPrototype);
- return "utf-8";
- }
+ /** @returns {string} */
+ get encoding() {
+ webidl.assertBranded(this, TextEncoderPrototype);
+ return "utf-8";
+ }
- /**
- * @param {string} input
- * @returns {Uint8Array}
- */
- encode(input = "") {
- webidl.assertBranded(this, TextEncoderPrototype);
- const prefix = "Failed to execute 'encode' on 'TextEncoder'";
- // The WebIDL type of `input` is `USVString`, but `core.encode` already
- // converts lone surrogates to the replacement character.
- input = webidl.converters.DOMString(input, {
- prefix,
- context: "Argument 1",
- });
- return core.encode(input);
- }
+ /**
+ * @param {string} input
+ * @returns {Uint8Array}
+ */
+ encode(input = "") {
+ webidl.assertBranded(this, TextEncoderPrototype);
+ const prefix = "Failed to execute 'encode' on 'TextEncoder'";
+ // The WebIDL type of `input` is `USVString`, but `core.encode` already
+ // converts lone surrogates to the replacement character.
+ input = webidl.converters.DOMString(input, {
+ prefix,
+ context: "Argument 1",
+ });
+ return core.encode(input);
+ }
- /**
- * @param {string} source
- * @param {Uint8Array} destination
- * @returns {TextEncoderEncodeIntoResult}
- */
- encodeInto(source, destination) {
- webidl.assertBranded(this, TextEncoderPrototype);
- const prefix = "Failed to execute 'encodeInto' on 'TextEncoder'";
- // The WebIDL type of `source` is `USVString`, but the ops bindings
- // already convert lone surrogates to the replacement character.
- source = webidl.converters.DOMString(source, {
- prefix,
- context: "Argument 1",
- });
- destination = webidl.converters.Uint8Array(destination, {
- prefix,
- context: "Argument 2",
- allowShared: true,
- });
- ops.op_encoding_encode_into(source, destination, encodeIntoBuf);
- return {
- read: encodeIntoBuf[0],
- written: encodeIntoBuf[1],
- };
- }
+ /**
+ * @param {string} source
+ * @param {Uint8Array} destination
+ * @returns {TextEncoderEncodeIntoResult}
+ */
+ encodeInto(source, destination) {
+ webidl.assertBranded(this, TextEncoderPrototype);
+ const prefix = "Failed to execute 'encodeInto' on 'TextEncoder'";
+ // The WebIDL type of `source` is `USVString`, but the ops bindings
+ // already convert lone surrogates to the replacement character.
+ source = webidl.converters.DOMString(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ destination = webidl.converters.Uint8Array(destination, {
+ prefix,
+ context: "Argument 2",
+ allowShared: true,
+ });
+ ops.op_encoding_encode_into(source, destination, encodeIntoBuf);
+ return {
+ read: encodeIntoBuf[0],
+ written: encodeIntoBuf[1],
+ };
}
+}
- const encodeIntoBuf = new Uint32Array(2);
+const encodeIntoBuf = new Uint32Array(2);
- webidl.configurePrototype(TextEncoder);
- const TextEncoderPrototype = TextEncoder.prototype;
+webidl.configurePrototype(TextEncoder);
+const TextEncoderPrototype = TextEncoder.prototype;
- class TextDecoderStream {
- /** @type {TextDecoder} */
- #decoder;
- /** @type {TransformStream<BufferSource, string>} */
- #transform;
+class TextDecoderStream {
+ /** @type {TextDecoder} */
+ #decoder;
+ /** @type {TransformStream<BufferSource, string>} */
+ #transform;
- /**
- * @param {string} label
- * @param {TextDecoderOptions} options
- */
- constructor(label = "utf-8", options = {}) {
- const prefix = "Failed to construct 'TextDecoderStream'";
- label = webidl.converters.DOMString(label, {
- prefix,
- context: "Argument 1",
- });
- options = webidl.converters.TextDecoderOptions(options, {
- prefix,
- context: "Argument 2",
- });
- this.#decoder = new TextDecoder(label, options);
- this.#transform = new TransformStream({
- // The transform and flush functions need access to TextDecoderStream's
- // `this`, so they are defined as functions rather than methods.
- transform: (chunk, controller) => {
- try {
- chunk = webidl.converters.BufferSource(chunk, {
- allowShared: true,
- });
- const decoded = this.#decoder.decode(chunk, { stream: true });
- if (decoded) {
- controller.enqueue(decoded);
- }
- return PromiseResolve();
- } catch (err) {
- return PromiseReject(err);
+ /**
+ * @param {string} label
+ * @param {TextDecoderOptions} options
+ */
+ constructor(label = "utf-8", options = {}) {
+ const prefix = "Failed to construct 'TextDecoderStream'";
+ label = webidl.converters.DOMString(label, {
+ prefix,
+ context: "Argument 1",
+ });
+ options = webidl.converters.TextDecoderOptions(options, {
+ prefix,
+ context: "Argument 2",
+ });
+ this.#decoder = new TextDecoder(label, options);
+ this.#transform = new TransformStream({
+ // The transform and flush functions need access to TextDecoderStream's
+ // `this`, so they are defined as functions rather than methods.
+ transform: (chunk, controller) => {
+ try {
+ chunk = webidl.converters.BufferSource(chunk, {
+ allowShared: true,
+ });
+ const decoded = this.#decoder.decode(chunk, { stream: true });
+ if (decoded) {
+ controller.enqueue(decoded);
}
- },
- flush: (controller) => {
- try {
- const final = this.#decoder.decode();
- if (final) {
- controller.enqueue(final);
- }
- return PromiseResolve();
- } catch (err) {
- return PromiseReject(err);
+ return PromiseResolve();
+ } catch (err) {
+ return PromiseReject(err);
+ }
+ },
+ flush: (controller) => {
+ try {
+ const final = this.#decoder.decode();
+ if (final) {
+ controller.enqueue(final);
}
- },
- });
- this[webidl.brand] = webidl.brand;
- }
-
- /** @returns {string} */
- get encoding() {
- webidl.assertBranded(this, TextDecoderStreamPrototype);
- return this.#decoder.encoding;
- }
+ return PromiseResolve();
+ } catch (err) {
+ return PromiseReject(err);
+ }
+ },
+ });
+ this[webidl.brand] = webidl.brand;
+ }
- /** @returns {boolean} */
- get fatal() {
- webidl.assertBranded(this, TextDecoderStreamPrototype);
- return this.#decoder.fatal;
- }
+ /** @returns {string} */
+ get encoding() {
+ webidl.assertBranded(this, TextDecoderStreamPrototype);
+ return this.#decoder.encoding;
+ }
- /** @returns {boolean} */
- get ignoreBOM() {
- webidl.assertBranded(this, TextDecoderStreamPrototype);
- return this.#decoder.ignoreBOM;
- }
+ /** @returns {boolean} */
+ get fatal() {
+ webidl.assertBranded(this, TextDecoderStreamPrototype);
+ return this.#decoder.fatal;
+ }
- /** @returns {ReadableStream<string>} */
- get readable() {
- webidl.assertBranded(this, TextDecoderStreamPrototype);
- return this.#transform.readable;
- }
+ /** @returns {boolean} */
+ get ignoreBOM() {
+ webidl.assertBranded(this, TextDecoderStreamPrototype);
+ return this.#decoder.ignoreBOM;
+ }
- /** @returns {WritableStream<BufferSource>} */
- get writable() {
- webidl.assertBranded(this, TextDecoderStreamPrototype);
- return this.#transform.writable;
- }
+ /** @returns {ReadableStream<string>} */
+ get readable() {
+ webidl.assertBranded(this, TextDecoderStreamPrototype);
+ return this.#transform.readable;
}
- webidl.configurePrototype(TextDecoderStream);
- const TextDecoderStreamPrototype = TextDecoderStream.prototype;
-
- class TextEncoderStream {
- /** @type {string | null} */
- #pendingHighSurrogate = null;
- /** @type {TransformStream<string, Uint8Array>} */
- #transform;
-
- constructor() {
- this.#transform = new TransformStream({
- // The transform and flush functions need access to TextEncoderStream's
- // `this`, so they are defined as functions rather than methods.
- transform: (chunk, controller) => {
- try {
- chunk = webidl.converters.DOMString(chunk);
- if (chunk === "") {
- return PromiseResolve();
- }
- if (this.#pendingHighSurrogate !== null) {
- chunk = this.#pendingHighSurrogate + chunk;
- }
- const lastCodeUnit = StringPrototypeCharCodeAt(
- chunk,
- chunk.length - 1,
- );
- if (0xD800 <= lastCodeUnit && lastCodeUnit <= 0xDBFF) {
- this.#pendingHighSurrogate = StringPrototypeSlice(chunk, -1);
- chunk = StringPrototypeSlice(chunk, 0, -1);
- } else {
- this.#pendingHighSurrogate = null;
- }
- if (chunk) {
- controller.enqueue(core.encode(chunk));
- }
+ /** @returns {WritableStream<BufferSource>} */
+ get writable() {
+ webidl.assertBranded(this, TextDecoderStreamPrototype);
+ return this.#transform.writable;
+ }
+}
+
+webidl.configurePrototype(TextDecoderStream);
+const TextDecoderStreamPrototype = TextDecoderStream.prototype;
+
+class TextEncoderStream {
+ /** @type {string | null} */
+ #pendingHighSurrogate = null;
+ /** @type {TransformStream<string, Uint8Array>} */
+ #transform;
+
+ constructor() {
+ this.#transform = new TransformStream({
+ // The transform and flush functions need access to TextEncoderStream's
+ // `this`, so they are defined as functions rather than methods.
+ transform: (chunk, controller) => {
+ try {
+ chunk = webidl.converters.DOMString(chunk);
+ if (chunk === "") {
return PromiseResolve();
- } catch (err) {
- return PromiseReject(err);
}
- },
- flush: (controller) => {
- try {
- if (this.#pendingHighSurrogate !== null) {
- controller.enqueue(new Uint8Array([0xEF, 0xBF, 0xBD]));
- }
- return PromiseResolve();
- } catch (err) {
- return PromiseReject(err);
+ if (this.#pendingHighSurrogate !== null) {
+ chunk = this.#pendingHighSurrogate + chunk;
}
- },
- });
- this[webidl.brand] = webidl.brand;
- }
-
- /** @returns {string} */
- get encoding() {
- webidl.assertBranded(this, TextEncoderStreamPrototype);
- return "utf-8";
- }
-
- /** @returns {ReadableStream<Uint8Array>} */
- get readable() {
- webidl.assertBranded(this, TextEncoderStreamPrototype);
- return this.#transform.readable;
- }
-
- /** @returns {WritableStream<string>} */
- get writable() {
- webidl.assertBranded(this, TextEncoderStreamPrototype);
- return this.#transform.writable;
- }
- }
-
- webidl.configurePrototype(TextEncoderStream);
- const TextEncoderStreamPrototype = TextEncoderStream.prototype;
-
- webidl.converters.TextDecoderOptions = webidl.createDictionaryConverter(
- "TextDecoderOptions",
- [
- {
- key: "fatal",
- converter: webidl.converters.boolean,
- defaultValue: false,
- },
- {
- key: "ignoreBOM",
- converter: webidl.converters.boolean,
- defaultValue: false,
+ const lastCodeUnit = StringPrototypeCharCodeAt(
+ chunk,
+ chunk.length - 1,
+ );
+ if (0xD800 <= lastCodeUnit && lastCodeUnit <= 0xDBFF) {
+ this.#pendingHighSurrogate = StringPrototypeSlice(chunk, -1);
+ chunk = StringPrototypeSlice(chunk, 0, -1);
+ } else {
+ this.#pendingHighSurrogate = null;
+ }
+ if (chunk) {
+ controller.enqueue(core.encode(chunk));
+ }
+ return PromiseResolve();
+ } catch (err) {
+ return PromiseReject(err);
+ }
},
- ],
- );
- webidl.converters.TextDecodeOptions = webidl.createDictionaryConverter(
- "TextDecodeOptions",
- [
- {
- key: "stream",
- converter: webidl.converters.boolean,
- defaultValue: false,
+ flush: (controller) => {
+ try {
+ if (this.#pendingHighSurrogate !== null) {
+ controller.enqueue(new Uint8Array([0xEF, 0xBF, 0xBD]));
+ }
+ return PromiseResolve();
+ } catch (err) {
+ return PromiseReject(err);
+ }
},
- ],
- );
+ });
+ this[webidl.brand] = webidl.brand;
+ }
- /**
- * @param {Uint8Array} bytes
- */
- function decode(bytes, encoding) {
- const BOMEncoding = BOMSniff(bytes);
- if (BOMEncoding !== null) {
- encoding = BOMEncoding;
- const start = BOMEncoding === "UTF-8" ? 3 : 2;
- bytes = TypedArrayPrototypeSubarray(bytes, start);
- }
- return new TextDecoder(encoding).decode(bytes);
+ /** @returns {string} */
+ get encoding() {
+ webidl.assertBranded(this, TextEncoderStreamPrototype);
+ return "utf-8";
}
- /**
- * @param {Uint8Array} bytes
- */
- function BOMSniff(bytes) {
- if (bytes[0] === 0xEF && bytes[1] === 0xBB && bytes[2] === 0xBF) {
- return "UTF-8";
- }
- if (bytes[0] === 0xFE && bytes[1] === 0xFF) return "UTF-16BE";
- if (bytes[0] === 0xFF && bytes[1] === 0xFE) return "UTF-16LE";
- return null;
+ /** @returns {ReadableStream<Uint8Array>} */
+ get readable() {
+ webidl.assertBranded(this, TextEncoderStreamPrototype);
+ return this.#transform.readable;
}
- window.__bootstrap.encoding = {
- TextEncoder,
- TextDecoder,
- TextEncoderStream,
- TextDecoderStream,
- decode,
- };
-})(this);
+ /** @returns {WritableStream<string>} */
+ get writable() {
+ webidl.assertBranded(this, TextEncoderStreamPrototype);
+ return this.#transform.writable;
+ }
+}
+
+webidl.configurePrototype(TextEncoderStream);
+const TextEncoderStreamPrototype = TextEncoderStream.prototype;
+
+webidl.converters.TextDecoderOptions = webidl.createDictionaryConverter(
+ "TextDecoderOptions",
+ [
+ {
+ key: "fatal",
+ converter: webidl.converters.boolean,
+ defaultValue: false,
+ },
+ {
+ key: "ignoreBOM",
+ converter: webidl.converters.boolean,
+ defaultValue: false,
+ },
+ ],
+);
+webidl.converters.TextDecodeOptions = webidl.createDictionaryConverter(
+ "TextDecodeOptions",
+ [
+ {
+ key: "stream",
+ converter: webidl.converters.boolean,
+ defaultValue: false,
+ },
+ ],
+);
+
+/**
+ * @param {Uint8Array} bytes
+ */
+function decode(bytes, encoding) {
+ const BOMEncoding = BOMSniff(bytes);
+ if (BOMEncoding !== null) {
+ encoding = BOMEncoding;
+ const start = BOMEncoding === "UTF-8" ? 3 : 2;
+ bytes = TypedArrayPrototypeSubarray(bytes, start);
+ }
+ return new TextDecoder(encoding).decode(bytes);
+}
+
+/**
+ * @param {Uint8Array} bytes
+ */
+function BOMSniff(bytes) {
+ if (bytes[0] === 0xEF && bytes[1] === 0xBB && bytes[2] === 0xBF) {
+ return "UTF-8";
+ }
+ if (bytes[0] === 0xFE && bytes[1] === 0xFF) return "UTF-16BE";
+ if (bytes[0] === 0xFF && bytes[1] === 0xFE) return "UTF-16LE";
+ return null;
+}
+
+export {
+ decode,
+ TextDecoder,
+ TextDecoderStream,
+ TextEncoder,
+ TextEncoderStream,
+};
diff --git a/ext/web/09_file.js b/ext/web/09_file.js
index ecdce3e6a..e1be3b4c2 100644
--- a/ext/web/09_file.js
+++ b/ext/web/09_file.js
@@ -9,630 +9,628 @@
/// <reference path="../web/lib.deno_web.d.ts" />
/// <reference path="./internal.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const {
- ArrayBufferPrototype,
- ArrayBufferPrototypeSlice,
- ArrayBufferIsView,
- ArrayPrototypePush,
- AsyncGeneratorPrototypeNext,
- Date,
- DatePrototypeGetTime,
- FinalizationRegistry,
- MathMax,
- MathMin,
- ObjectPrototypeIsPrototypeOf,
- RegExpPrototypeTest,
- // TODO(lucacasonato): add SharedArrayBuffer to primordials
- // SharedArrayBufferPrototype
- StringPrototypeCharAt,
- StringPrototypeToLowerCase,
- StringPrototypeSlice,
- Symbol,
- SymbolFor,
- TypedArrayPrototypeSet,
- TypeError,
- Uint8Array,
- } = window.__bootstrap.primordials;
- const consoleInternal = window.__bootstrap.console;
-
- // TODO(lucacasonato): this needs to not be hardcoded and instead depend on
- // host os.
- const isWindows = false;
- /**
- * @param {string} input
- * @param {number} position
- * @returns {{result: string, position: number}}
- */
- function collectCodepointsNotCRLF(input, position) {
- // See https://w3c.github.io/FileAPI/#convert-line-endings-to-native and
- // https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
- const start = position;
- for (
- let c = StringPrototypeCharAt(input, position);
- position < input.length && !(c === "\r" || c === "\n");
- c = StringPrototypeCharAt(input, ++position)
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayBufferPrototype,
+ ArrayBufferPrototypeSlice,
+ ArrayBufferIsView,
+ ArrayPrototypePush,
+ AsyncGeneratorPrototypeNext,
+ Date,
+ DatePrototypeGetTime,
+ FinalizationRegistry,
+ MathMax,
+ MathMin,
+ ObjectPrototypeIsPrototypeOf,
+ RegExpPrototypeTest,
+ // TODO(lucacasonato): add SharedArrayBuffer to primordials
+ // SharedArrayBufferPrototype
+ StringPrototypeCharAt,
+ StringPrototypeToLowerCase,
+ StringPrototypeSlice,
+ Symbol,
+ SymbolFor,
+ TypedArrayPrototypeSet,
+ TypeError,
+ Uint8Array,
+} = primordials;
+import { createFilteredInspectProxy } from "internal:ext/console/02_console.js";
+
+// TODO(lucacasonato): this needs to not be hardcoded and instead depend on
+// host os.
+const isWindows = false;
+
+/**
+ * @param {string} input
+ * @param {number} position
+ * @returns {{result: string, position: number}}
+ */
+function collectCodepointsNotCRLF(input, position) {
+ // See https://w3c.github.io/FileAPI/#convert-line-endings-to-native and
+ // https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
+ const start = position;
+ for (
+ let c = StringPrototypeCharAt(input, position);
+ position < input.length && !(c === "\r" || c === "\n");
+ c = StringPrototypeCharAt(input, ++position)
+ );
+ return { result: StringPrototypeSlice(input, start, position), position };
+}
+
+/**
+ * @param {string} s
+ * @returns {string}
+ */
+function convertLineEndingsToNative(s) {
+ const nativeLineEnding = isWindows ? "\r\n" : "\n";
+
+ let { result, position } = collectCodepointsNotCRLF(s, 0);
+
+ while (position < s.length) {
+ const codePoint = StringPrototypeCharAt(s, position);
+ if (codePoint === "\r") {
+ result += nativeLineEnding;
+ position++;
+ if (
+ position < s.length && StringPrototypeCharAt(s, position) === "\n"
+ ) {
+ position++;
+ }
+ } else if (codePoint === "\n") {
+ position++;
+ result += nativeLineEnding;
+ }
+ const { result: token, position: newPosition } = collectCodepointsNotCRLF(
+ s,
+ position,
);
- return { result: StringPrototypeSlice(input, start, position), position };
+ position = newPosition;
+ result += token;
}
- /**
- * @param {string} s
- * @returns {string}
- */
- function convertLineEndingsToNative(s) {
- const nativeLineEnding = isWindows ? "\r\n" : "\n";
-
- let { result, position } = collectCodepointsNotCRLF(s, 0);
+ return result;
+}
- while (position < s.length) {
- const codePoint = StringPrototypeCharAt(s, position);
- if (codePoint === "\r") {
- result += nativeLineEnding;
- position++;
- if (
- position < s.length && StringPrototypeCharAt(s, position) === "\n"
- ) {
- position++;
- }
- } else if (codePoint === "\n") {
- position++;
- result += nativeLineEnding;
- }
- const { result: token, position: newPosition } = collectCodepointsNotCRLF(
- s,
- position,
+/** @param {(BlobReference | Blob)[]} parts */
+async function* toIterator(parts) {
+ for (let i = 0; i < parts.length; ++i) {
+ yield* parts[i].stream();
+ }
+}
+
+/** @typedef {BufferSource | Blob | string} BlobPart */
+
+/**
+ * @param {BlobPart[]} parts
+ * @param {string} endings
+ * @returns {{ parts: (BlobReference|Blob)[], size: number }}
+ */
+function processBlobParts(parts, endings) {
+ /** @type {(BlobReference|Blob)[]} */
+ const processedParts = [];
+ let size = 0;
+ for (let i = 0; i < parts.length; ++i) {
+ const element = parts[i];
+ if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, element)) {
+ const chunk = new Uint8Array(ArrayBufferPrototypeSlice(element, 0));
+ ArrayPrototypePush(processedParts, BlobReference.fromUint8Array(chunk));
+ size += element.byteLength;
+ } else if (ArrayBufferIsView(element)) {
+ const chunk = new Uint8Array(
+ element.buffer,
+ element.byteOffset,
+ element.byteLength,
);
- position = newPosition;
- result += token;
+ size += element.byteLength;
+ ArrayPrototypePush(processedParts, BlobReference.fromUint8Array(chunk));
+ } else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, element)) {
+ ArrayPrototypePush(processedParts, element);
+ size += element.size;
+ } else if (typeof element === "string") {
+ const chunk = core.encode(
+ endings == "native" ? convertLineEndingsToNative(element) : element,
+ );
+ size += chunk.byteLength;
+ ArrayPrototypePush(processedParts, BlobReference.fromUint8Array(chunk));
+ } else {
+ throw new TypeError("Unreachable code (invalid element type)");
}
-
- return result;
}
-
- /** @param {(BlobReference | Blob)[]} parts */
- async function* toIterator(parts) {
- for (let i = 0; i < parts.length; ++i) {
- yield* parts[i].stream();
+ return { parts: processedParts, size };
+}
+
+/**
+ * @param {string} str
+ * @returns {string}
+ */
+function normalizeType(str) {
+ let normalizedType = str;
+ if (!RegExpPrototypeTest(/^[\x20-\x7E]*$/, str)) {
+ normalizedType = "";
+ }
+ return StringPrototypeToLowerCase(normalizedType);
+}
+
+/**
+ * Get all Parts as a flat array containing all references
+ * @param {Blob} blob
+ * @param {string[]} bag
+ * @returns {string[]}
+ */
+function getParts(blob, bag = []) {
+ const parts = blob[_parts];
+ for (let i = 0; i < parts.length; ++i) {
+ const part = parts[i];
+ if (ObjectPrototypeIsPrototypeOf(BlobPrototype, part)) {
+ getParts(part, bag);
+ } else {
+ ArrayPrototypePush(bag, part._id);
}
}
+ return bag;
+}
- /** @typedef {BufferSource | Blob | string} BlobPart */
+const _type = Symbol("Type");
+const _size = Symbol("Size");
+const _parts = Symbol("Parts");
+
+class Blob {
+ [_type] = "";
+ [_size] = 0;
+ [_parts];
/**
- * @param {BlobPart[]} parts
- * @param {string} endings
- * @returns {{ parts: (BlobReference|Blob)[], size: number }}
+ * @param {BlobPart[]} blobParts
+ * @param {BlobPropertyBag} options
*/
- function processBlobParts(parts, endings) {
- /** @type {(BlobReference|Blob)[]} */
- const processedParts = [];
- let size = 0;
- for (let i = 0; i < parts.length; ++i) {
- const element = parts[i];
- if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, element)) {
- const chunk = new Uint8Array(ArrayBufferPrototypeSlice(element, 0));
- ArrayPrototypePush(processedParts, BlobReference.fromUint8Array(chunk));
- size += element.byteLength;
- } else if (ArrayBufferIsView(element)) {
- const chunk = new Uint8Array(
- element.buffer,
- element.byteOffset,
- element.byteLength,
- );
- size += element.byteLength;
- ArrayPrototypePush(processedParts, BlobReference.fromUint8Array(chunk));
- } else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, element)) {
- ArrayPrototypePush(processedParts, element);
- size += element.size;
- } else if (typeof element === "string") {
- const chunk = core.encode(
- endings == "native" ? convertLineEndingsToNative(element) : element,
- );
- size += chunk.byteLength;
- ArrayPrototypePush(processedParts, BlobReference.fromUint8Array(chunk));
- } else {
- throw new TypeError("Unreachable code (invalid element type)");
- }
- }
- return { parts: processedParts, size };
+ constructor(blobParts = [], options = {}) {
+ const prefix = "Failed to construct 'Blob'";
+ blobParts = webidl.converters["sequence<BlobPart>"](blobParts, {
+ context: "Argument 1",
+ prefix,
+ });
+ options = webidl.converters["BlobPropertyBag"](options, {
+ context: "Argument 2",
+ prefix,
+ });
+
+ this[webidl.brand] = webidl.brand;
+
+ const { parts, size } = processBlobParts(
+ blobParts,
+ options.endings,
+ );
+
+ this[_parts] = parts;
+ this[_size] = size;
+ this[_type] = normalizeType(options.type);
}
- /**
- * @param {string} str
- * @returns {string}
- */
- function normalizeType(str) {
- let normalizedType = str;
- if (!RegExpPrototypeTest(/^[\x20-\x7E]*$/, str)) {
- normalizedType = "";
- }
- return StringPrototypeToLowerCase(normalizedType);
+ /** @returns {number} */
+ get size() {
+ webidl.assertBranded(this, BlobPrototype);
+ return this[_size];
}
- /**
- * Get all Parts as a flat array containing all references
- * @param {Blob} blob
- * @param {string[]} bag
- * @returns {string[]}
- */
- function getParts(blob, bag = []) {
- const parts = blob[_parts];
- for (let i = 0; i < parts.length; ++i) {
- const part = parts[i];
- if (ObjectPrototypeIsPrototypeOf(BlobPrototype, part)) {
- getParts(part, bag);
- } else {
- ArrayPrototypePush(bag, part._id);
- }
- }
- return bag;
+ /** @returns {string} */
+ get type() {
+ webidl.assertBranded(this, BlobPrototype);
+ return this[_type];
}
- const _type = Symbol("Type");
- const _size = Symbol("Size");
- const _parts = Symbol("Parts");
-
- class Blob {
- [_type] = "";
- [_size] = 0;
- [_parts];
-
- /**
- * @param {BlobPart[]} blobParts
- * @param {BlobPropertyBag} options
- */
- constructor(blobParts = [], options = {}) {
- const prefix = "Failed to construct 'Blob'";
- blobParts = webidl.converters["sequence<BlobPart>"](blobParts, {
+ /**
+ * @param {number} [start]
+ * @param {number} [end]
+ * @param {string} [contentType]
+ * @returns {Blob}
+ */
+ slice(start = undefined, end = undefined, contentType = undefined) {
+ webidl.assertBranded(this, BlobPrototype);
+ const prefix = "Failed to execute 'slice' on 'Blob'";
+ if (start !== undefined) {
+ start = webidl.converters["long long"](start, {
+ clamp: true,
context: "Argument 1",
prefix,
});
- options = webidl.converters["BlobPropertyBag"](options, {
+ }
+ if (end !== undefined) {
+ end = webidl.converters["long long"](end, {
+ clamp: true,
context: "Argument 2",
prefix,
});
-
- this[webidl.brand] = webidl.brand;
-
- const { parts, size } = processBlobParts(
- blobParts,
- options.endings,
- );
-
- this[_parts] = parts;
- this[_size] = size;
- this[_type] = normalizeType(options.type);
}
-
- /** @returns {number} */
- get size() {
- webidl.assertBranded(this, BlobPrototype);
- return this[_size];
- }
-
- /** @returns {string} */
- get type() {
- webidl.assertBranded(this, BlobPrototype);
- return this[_type];
+ if (contentType !== undefined) {
+ contentType = webidl.converters["DOMString"](contentType, {
+ context: "Argument 3",
+ prefix,
+ });
}
- /**
- * @param {number} [start]
- * @param {number} [end]
- * @param {string} [contentType]
- * @returns {Blob}
- */
- slice(start = undefined, end = undefined, contentType = undefined) {
- webidl.assertBranded(this, BlobPrototype);
- const prefix = "Failed to execute 'slice' on 'Blob'";
- if (start !== undefined) {
- start = webidl.converters["long long"](start, {
- clamp: true,
- context: "Argument 1",
- prefix,
- });
- }
- if (end !== undefined) {
- end = webidl.converters["long long"](end, {
- clamp: true,
- context: "Argument 2",
- prefix,
- });
- }
- if (contentType !== undefined) {
- contentType = webidl.converters["DOMString"](contentType, {
- context: "Argument 3",
- prefix,
- });
- }
-
- // deno-lint-ignore no-this-alias
- const O = this;
- /** @type {number} */
- let relativeStart;
- if (start === undefined) {
- relativeStart = 0;
+ // deno-lint-ignore no-this-alias
+ const O = this;
+ /** @type {number} */
+ let relativeStart;
+ if (start === undefined) {
+ relativeStart = 0;
+ } else {
+ if (start < 0) {
+ relativeStart = MathMax(O.size + start, 0);
} else {
- if (start < 0) {
- relativeStart = MathMax(O.size + start, 0);
- } else {
- relativeStart = MathMin(start, O.size);
- }
+ relativeStart = MathMin(start, O.size);
}
- /** @type {number} */
- let relativeEnd;
- if (end === undefined) {
- relativeEnd = O.size;
+ }
+ /** @type {number} */
+ let relativeEnd;
+ if (end === undefined) {
+ relativeEnd = O.size;
+ } else {
+ if (end < 0) {
+ relativeEnd = MathMax(O.size + end, 0);
} else {
- if (end < 0) {
- relativeEnd = MathMax(O.size + end, 0);
- } else {
- relativeEnd = MathMin(end, O.size);
- }
+ relativeEnd = MathMin(end, O.size);
}
+ }
- const span = MathMax(relativeEnd - relativeStart, 0);
- const blobParts = [];
- let added = 0;
-
- const parts = this[_parts];
- for (let i = 0; i < parts.length; ++i) {
- const part = parts[i];
- // don't add the overflow to new blobParts
- if (added >= span) {
- // Could maybe be possible to remove variable `added`
- // and only use relativeEnd?
- break;
- }
- const size = part.size;
- if (relativeStart && size <= relativeStart) {
- // Skip the beginning and change the relative
- // start & end position as we skip the unwanted parts
- relativeStart -= size;
- relativeEnd -= size;
- } else {
- const chunk = part.slice(
- relativeStart,
- MathMin(part.size, relativeEnd),
- );
- added += chunk.size;
- relativeEnd -= part.size;
- ArrayPrototypePush(blobParts, chunk);
- relativeStart = 0; // All next sequential parts should start at 0
- }
- }
+ const span = MathMax(relativeEnd - relativeStart, 0);
+ const blobParts = [];
+ let added = 0;
- /** @type {string} */
- let relativeContentType;
- if (contentType === undefined) {
- relativeContentType = "";
+ const parts = this[_parts];
+ for (let i = 0; i < parts.length; ++i) {
+ const part = parts[i];
+ // don't add the overflow to new blobParts
+ if (added >= span) {
+ // Could maybe be possible to remove variable `added`
+ // and only use relativeEnd?
+ break;
+ }
+ const size = part.size;
+ if (relativeStart && size <= relativeStart) {
+ // Skip the beginning and change the relative
+ // start & end position as we skip the unwanted parts
+ relativeStart -= size;
+ relativeEnd -= size;
} else {
- relativeContentType = normalizeType(contentType);
+ const chunk = part.slice(
+ relativeStart,
+ MathMin(part.size, relativeEnd),
+ );
+ added += chunk.size;
+ relativeEnd -= part.size;
+ ArrayPrototypePush(blobParts, chunk);
+ relativeStart = 0; // All next sequential parts should start at 0
}
-
- const blob = new Blob([], { type: relativeContentType });
- blob[_parts] = blobParts;
- blob[_size] = span;
- return blob;
}
- /**
- * @returns {ReadableStream<Uint8Array>}
- */
- stream() {
- webidl.assertBranded(this, BlobPrototype);
- const partIterator = toIterator(this[_parts]);
- const stream = new ReadableStream({
- type: "bytes",
- /** @param {ReadableByteStreamController} controller */
- async pull(controller) {
- while (true) {
- const { value, done } = await AsyncGeneratorPrototypeNext(
- partIterator,
- );
- if (done) return controller.close();
- if (value.byteLength > 0) {
- return controller.enqueue(value);
- }
- }
- },
- });
- return stream;
+ /** @type {string} */
+ let relativeContentType;
+ if (contentType === undefined) {
+ relativeContentType = "";
+ } else {
+ relativeContentType = normalizeType(contentType);
}
- /**
- * @returns {Promise<string>}
- */
- async text() {
- webidl.assertBranded(this, BlobPrototype);
- const buffer = await this.#u8Array(this.size);
- return core.decode(buffer);
- }
+ const blob = new Blob([], { type: relativeContentType });
+ blob[_parts] = blobParts;
+ blob[_size] = span;
+ return blob;
+ }
- async #u8Array(size) {
- const bytes = new Uint8Array(size);
- const partIterator = toIterator(this[_parts]);
- let offset = 0;
- while (true) {
- const { value, done } = await AsyncGeneratorPrototypeNext(
- partIterator,
- );
- if (done) break;
- const byteLength = value.byteLength;
- if (byteLength > 0) {
- TypedArrayPrototypeSet(bytes, value, offset);
- offset += byteLength;
+ /**
+ * @returns {ReadableStream<Uint8Array>}
+ */
+ stream() {
+ webidl.assertBranded(this, BlobPrototype);
+ const partIterator = toIterator(this[_parts]);
+ const stream = new ReadableStream({
+ type: "bytes",
+ /** @param {ReadableByteStreamController} controller */
+ async pull(controller) {
+ while (true) {
+ const { value, done } = await AsyncGeneratorPrototypeNext(
+ partIterator,
+ );
+ if (done) return controller.close();
+ if (value.byteLength > 0) {
+ return controller.enqueue(value);
+ }
}
- }
- return bytes;
- }
-
- /**
- * @returns {Promise<ArrayBuffer>}
- */
- async arrayBuffer() {
- webidl.assertBranded(this, BlobPrototype);
- const buf = await this.#u8Array(this.size);
- return buf.buffer;
- }
-
- [SymbolFor("Deno.customInspect")](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(BlobPrototype, this),
- keys: [
- "size",
- "type",
- ],
- }));
- }
+ },
+ });
+ return stream;
}
- webidl.configurePrototype(Blob);
- const BlobPrototype = Blob.prototype;
+ /**
+ * @returns {Promise<string>}
+ */
+ async text() {
+ webidl.assertBranded(this, BlobPrototype);
+ const buffer = await this.#u8Array(this.size);
+ return core.decode(buffer);
+ }
- webidl.converters["Blob"] = webidl.createInterfaceConverter(
- "Blob",
- Blob.prototype,
- );
- webidl.converters["BlobPart"] = (V, opts) => {
- // Union for ((ArrayBuffer or ArrayBufferView) or Blob or USVString)
- if (typeof V == "object") {
- if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) {
- return webidl.converters["Blob"](V, opts);
- }
- if (
- ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V) ||
- // deno-lint-ignore prefer-primordials
- ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V)
- ) {
- return webidl.converters["ArrayBuffer"](V, opts);
- }
- if (ArrayBufferIsView(V)) {
- return webidl.converters["ArrayBufferView"](V, opts);
+ async #u8Array(size) {
+ const bytes = new Uint8Array(size);
+ const partIterator = toIterator(this[_parts]);
+ let offset = 0;
+ while (true) {
+ const { value, done } = await AsyncGeneratorPrototypeNext(
+ partIterator,
+ );
+ if (done) break;
+ const byteLength = value.byteLength;
+ if (byteLength > 0) {
+ TypedArrayPrototypeSet(bytes, value, offset);
+ offset += byteLength;
}
}
- // BlobPart is passed to processBlobParts after conversion, which calls core.encode()
- // on the string.
- // core.encode() is equivalent to USVString normalization.
- return webidl.converters["DOMString"](V, opts);
- };
- webidl.converters["sequence<BlobPart>"] = webidl.createSequenceConverter(
- webidl.converters["BlobPart"],
- );
- webidl.converters["EndingType"] = webidl.createEnumConverter("EndingType", [
- "transparent",
- "native",
- ]);
- const blobPropertyBagDictionary = [
- {
- key: "type",
- converter: webidl.converters["DOMString"],
- defaultValue: "",
- },
- {
- key: "endings",
- converter: webidl.converters["EndingType"],
- defaultValue: "transparent",
- },
- ];
- webidl.converters["BlobPropertyBag"] = webidl.createDictionaryConverter(
- "BlobPropertyBag",
- blobPropertyBagDictionary,
- );
-
- const _Name = Symbol("[[Name]]");
- const _LastModified = Symbol("[[LastModified]]");
-
- class File extends Blob {
- /** @type {string} */
- [_Name];
- /** @type {number} */
- [_LastModified];
-
- /**
- * @param {BlobPart[]} fileBits
- * @param {string} fileName
- * @param {FilePropertyBag} options
- */
- constructor(fileBits, fileName, options = {}) {
- const prefix = "Failed to construct 'File'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
-
- fileBits = webidl.converters["sequence<BlobPart>"](fileBits, {
- context: "Argument 1",
- prefix,
- });
- fileName = webidl.converters["USVString"](fileName, {
- context: "Argument 2",
- prefix,
- });
- options = webidl.converters["FilePropertyBag"](options, {
- context: "Argument 3",
- prefix,
- });
+ return bytes;
+ }
- super(fileBits, options);
+ /**
+ * @returns {Promise<ArrayBuffer>}
+ */
+ async arrayBuffer() {
+ webidl.assertBranded(this, BlobPrototype);
+ const buf = await this.#u8Array(this.size);
+ return buf.buffer;
+ }
- /** @type {string} */
- this[_Name] = fileName;
- if (options.lastModified === undefined) {
- /** @type {number} */
- this[_LastModified] = DatePrototypeGetTime(new Date());
- } else {
- /** @type {number} */
- this[_LastModified] = options.lastModified;
- }
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(BlobPrototype, this),
+ keys: [
+ "size",
+ "type",
+ ],
+ }));
+ }
+}
+
+webidl.configurePrototype(Blob);
+const BlobPrototype = Blob.prototype;
+
+webidl.converters["Blob"] = webidl.createInterfaceConverter(
+ "Blob",
+ Blob.prototype,
+);
+webidl.converters["BlobPart"] = (V, opts) => {
+ // Union for ((ArrayBuffer or ArrayBufferView) or Blob or USVString)
+ if (typeof V == "object") {
+ if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) {
+ return webidl.converters["Blob"](V, opts);
}
-
- /** @returns {string} */
- get name() {
- webidl.assertBranded(this, FilePrototype);
- return this[_Name];
+ if (
+ ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V) ||
+ // deno-lint-ignore prefer-primordials
+ ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V)
+ ) {
+ return webidl.converters["ArrayBuffer"](V, opts);
}
-
- /** @returns {number} */
- get lastModified() {
- webidl.assertBranded(this, FilePrototype);
- return this[_LastModified];
+ if (ArrayBufferIsView(V)) {
+ return webidl.converters["ArrayBufferView"](V, opts);
}
}
-
- webidl.configurePrototype(File);
- const FilePrototype = File.prototype;
-
- webidl.converters["FilePropertyBag"] = webidl.createDictionaryConverter(
- "FilePropertyBag",
- blobPropertyBagDictionary,
- [
- {
- key: "lastModified",
- converter: webidl.converters["long long"],
- },
- ],
- );
-
- // A finalization registry to deallocate a blob part when its JS reference is
- // garbage collected.
- const registry = new FinalizationRegistry((uuid) => {
- ops.op_blob_remove_part(uuid);
- });
-
- // TODO(lucacasonato): get a better stream from Rust in BlobReference#stream
+ // BlobPart is passed to processBlobParts after conversion, which calls core.encode()
+ // on the string.
+ // core.encode() is equivalent to USVString normalization.
+ return webidl.converters["DOMString"](V, opts);
+};
+webidl.converters["sequence<BlobPart>"] = webidl.createSequenceConverter(
+ webidl.converters["BlobPart"],
+);
+webidl.converters["EndingType"] = webidl.createEnumConverter("EndingType", [
+ "transparent",
+ "native",
+]);
+const blobPropertyBagDictionary = [
+ {
+ key: "type",
+ converter: webidl.converters["DOMString"],
+ defaultValue: "",
+ },
+ {
+ key: "endings",
+ converter: webidl.converters["EndingType"],
+ defaultValue: "transparent",
+ },
+];
+webidl.converters["BlobPropertyBag"] = webidl.createDictionaryConverter(
+ "BlobPropertyBag",
+ blobPropertyBagDictionary,
+);
+
+const _Name = Symbol("[[Name]]");
+const _LastModified = Symbol("[[LastModified]]");
+
+class File extends Blob {
+ /** @type {string} */
+ [_Name];
+ /** @type {number} */
+ [_LastModified];
/**
- * An opaque reference to a blob part in Rust. This could be backed by a file,
- * in memory storage, or something else.
+ * @param {BlobPart[]} fileBits
+ * @param {string} fileName
+ * @param {FilePropertyBag} options
*/
- class BlobReference {
- /**
- * Don't use directly. Use `BlobReference.fromUint8Array`.
- * @param {string} id
- * @param {number} size
- */
- constructor(id, size) {
- this._id = id;
- this.size = size;
- registry.register(this, id);
- }
+ constructor(fileBits, fileName, options = {}) {
+ const prefix = "Failed to construct 'File'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+
+ fileBits = webidl.converters["sequence<BlobPart>"](fileBits, {
+ context: "Argument 1",
+ prefix,
+ });
+ fileName = webidl.converters["USVString"](fileName, {
+ context: "Argument 2",
+ prefix,
+ });
+ options = webidl.converters["FilePropertyBag"](options, {
+ context: "Argument 3",
+ prefix,
+ });
+
+ super(fileBits, options);
- /**
- * Create a new blob part from a Uint8Array.
- *
- * @param {Uint8Array} data
- * @returns {BlobReference}
- */
- static fromUint8Array(data) {
- const id = ops.op_blob_create_part(data);
- return new BlobReference(id, data.byteLength);
+ /** @type {string} */
+ this[_Name] = fileName;
+ if (options.lastModified === undefined) {
+ /** @type {number} */
+ this[_LastModified] = DatePrototypeGetTime(new Date());
+ } else {
+ /** @type {number} */
+ this[_LastModified] = options.lastModified;
}
+ }
- /**
- * Create a new BlobReference by slicing this BlobReference. This is a copy
- * free operation - the sliced reference will still reference the original
- * underlying bytes.
- *
- * @param {number} start
- * @param {number} end
- * @returns {BlobReference}
- */
- slice(start, end) {
- const size = end - start;
- const id = ops.op_blob_slice_part(this._id, {
- start,
- len: size,
- });
- return new BlobReference(id, size);
- }
+ /** @returns {string} */
+ get name() {
+ webidl.assertBranded(this, FilePrototype);
+ return this[_Name];
+ }
- /**
- * Read the entire contents of the reference blob.
- * @returns {AsyncGenerator<Uint8Array>}
- */
- async *stream() {
- yield core.opAsync("op_blob_read_part", this._id);
-
- // let position = 0;
- // const end = this.size;
- // while (position !== end) {
- // const size = MathMin(end - position, 65536);
- // const chunk = this.slice(position, position + size);
- // position += chunk.size;
- // yield core.opAsync("op_blob_read_part", chunk._id);
- // }
- }
+ /** @returns {number} */
+ get lastModified() {
+ webidl.assertBranded(this, FilePrototype);
+ return this[_LastModified];
}
+}
+webidl.configurePrototype(File);
+const FilePrototype = File.prototype;
+
+webidl.converters["FilePropertyBag"] = webidl.createDictionaryConverter(
+ "FilePropertyBag",
+ blobPropertyBagDictionary,
+ [
+ {
+ key: "lastModified",
+ converter: webidl.converters["long long"],
+ },
+ ],
+);
+
+// A finalization registry to deallocate a blob part when its JS reference is
+// garbage collected.
+const registry = new FinalizationRegistry((uuid) => {
+ ops.op_blob_remove_part(uuid);
+});
+
+// TODO(lucacasonato): get a better stream from Rust in BlobReference#stream
+
+/**
+ * An opaque reference to a blob part in Rust. This could be backed by a file,
+ * in memory storage, or something else.
+ */
+class BlobReference {
/**
- * Construct a new Blob object from an object URL.
- *
- * This new object will not duplicate data in memory with the original Blob
- * object from which this URL was created or with other Blob objects created
- * from the same URL, but they will be different objects.
+ * Don't use directly. Use `BlobReference.fromUint8Array`.
+ * @param {string} id
+ * @param {number} size
+ */
+ constructor(id, size) {
+ this._id = id;
+ this.size = size;
+ registry.register(this, id);
+ }
+
+ /**
+ * Create a new blob part from a Uint8Array.
*
- * The object returned from this function will not be a File object, even if
- * the original object from which the object URL was constructed was one. This
- * means that the `name` and `lastModified` properties are lost.
+ * @param {Uint8Array} data
+ * @returns {BlobReference}
+ */
+ static fromUint8Array(data) {
+ const id = ops.op_blob_create_part(data);
+ return new BlobReference(id, data.byteLength);
+ }
+
+ /**
+ * Create a new BlobReference by slicing this BlobReference. This is a copy
+ * free operation - the sliced reference will still reference the original
+ * underlying bytes.
*
- * @param {string} url
- * @returns {Blob | null}
+ * @param {number} start
+ * @param {number} end
+ * @returns {BlobReference}
*/
- function blobFromObjectUrl(url) {
- const blobData = ops.op_blob_from_object_url(url);
- if (blobData === null) {
- return null;
- }
+ slice(start, end) {
+ const size = end - start;
+ const id = ops.op_blob_slice_part(this._id, {
+ start,
+ len: size,
+ });
+ return new BlobReference(id, size);
+ }
- /** @type {BlobReference[]} */
- const parts = [];
- let totalSize = 0;
+ /**
+ * Read the entire contents of the reference blob.
+ * @returns {AsyncGenerator<Uint8Array>}
+ */
+ async *stream() {
+ yield core.opAsync("op_blob_read_part", this._id);
+
+ // let position = 0;
+ // const end = this.size;
+ // while (position !== end) {
+ // const size = MathMin(end - position, 65536);
+ // const chunk = this.slice(position, position + size);
+ // position += chunk.size;
+ // yield core.opAsync("op_blob_read_part", chunk._id);
+ // }
+ }
+}
+
+/**
+ * Construct a new Blob object from an object URL.
+ *
+ * This new object will not duplicate data in memory with the original Blob
+ * object from which this URL was created or with other Blob objects created
+ * from the same URL, but they will be different objects.
+ *
+ * The object returned from this function will not be a File object, even if
+ * the original object from which the object URL was constructed was one. This
+ * means that the `name` and `lastModified` properties are lost.
+ *
+ * @param {string} url
+ * @returns {Blob | null}
+ */
+function blobFromObjectUrl(url) {
+ const blobData = ops.op_blob_from_object_url(url);
+ if (blobData === null) {
+ return null;
+ }
- for (let i = 0; i < blobData.parts.length; ++i) {
- const { uuid, size } = blobData.parts[i];
- ArrayPrototypePush(parts, new BlobReference(uuid, size));
- totalSize += size;
- }
+ /** @type {BlobReference[]} */
+ const parts = [];
+ let totalSize = 0;
- const blob = webidl.createBranded(Blob);
- blob[_type] = blobData.media_type;
- blob[_size] = totalSize;
- blob[_parts] = parts;
- return blob;
+ for (let i = 0; i < blobData.parts.length; ++i) {
+ const { uuid, size } = blobData.parts[i];
+ ArrayPrototypePush(parts, new BlobReference(uuid, size));
+ totalSize += size;
}
- window.__bootstrap.file = {
- blobFromObjectUrl,
- getParts,
- Blob,
- BlobPrototype,
- File,
- FilePrototype,
- };
-})(this);
+ const blob = webidl.createBranded(Blob);
+ blob[_type] = blobData.media_type;
+ blob[_size] = totalSize;
+ blob[_parts] = parts;
+ return blob;
+}
+
+export {
+ Blob,
+ blobFromObjectUrl,
+ BlobPrototype,
+ File,
+ FilePrototype,
+ getParts,
+};
diff --git a/ext/web/10_filereader.js b/ext/web/10_filereader.js
index fb119f43e..7a46dfa9a 100644
--- a/ext/web/10_filereader.js
+++ b/ext/web/10_filereader.js
@@ -10,487 +10,482 @@
/// <reference path="./internal.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const webidl = window.__bootstrap.webidl;
- const { forgivingBase64Encode } = window.__bootstrap.infra;
- const { ProgressEvent } = window.__bootstrap.event;
- const { EventTarget } = window.__bootstrap.eventTarget;
- const { decode, TextDecoder } = window.__bootstrap.encoding;
- const { parseMimeType } = window.__bootstrap.mimesniff;
- const { DOMException } = window.__bootstrap.domException;
- const {
- ArrayPrototypePush,
- ArrayPrototypeReduce,
- FunctionPrototypeCall,
- Map,
- MapPrototypeGet,
- MapPrototypeSet,
- ObjectDefineProperty,
- ObjectPrototypeIsPrototypeOf,
- queueMicrotask,
- SafeArrayIterator,
- Symbol,
- TypedArrayPrototypeSet,
- TypeError,
- Uint8Array,
- Uint8ArrayPrototype,
- } = window.__bootstrap.primordials;
-
- const state = Symbol("[[state]]");
- const result = Symbol("[[result]]");
- const error = Symbol("[[error]]");
- const aborted = Symbol("[[aborted]]");
- const handlerSymbol = Symbol("eventHandlers");
-
- class FileReader extends EventTarget {
- /** @type {"empty" | "loading" | "done"} */
- [state] = "empty";
- /** @type {null | string | ArrayBuffer} */
- [result] = null;
- /** @type {null | DOMException} */
- [error] = null;
- /** @type {null | {aborted: boolean}} */
- [aborted] = null;
-
- /**
- * @param {Blob} blob
- * @param {{kind: "ArrayBuffer" | "Text" | "DataUrl" | "BinaryString", encoding?: string}} readtype
- */
- #readOperation(blob, readtype) {
- // 1. If fr’s state is "loading", throw an InvalidStateError DOMException.
- if (this[state] === "loading") {
- throw new DOMException(
- "Invalid FileReader state.",
- "InvalidStateError",
- );
- }
- // 2. Set fr’s state to "loading".
- this[state] = "loading";
- // 3. Set fr’s result to null.
- this[result] = null;
- // 4. Set fr’s error to null.
- this[error] = null;
-
- // We set this[aborted] to a new object, and keep track of it in a
- // separate variable, so if a new read operation starts while there are
- // remaining tasks from a previous aborted operation, the new operation
- // will run while the tasks from the previous one are still aborted.
- const abortedState = this[aborted] = { aborted: false };
-
- // 5. Let stream be the result of calling get stream on blob.
- const stream /*: ReadableStream<ArrayBufferView>*/ = blob.stream();
-
- // 6. Let reader be the result of getting a reader from stream.
- const reader = stream.getReader();
-
- // 7. Let bytes be an empty byte sequence.
- /** @type {Uint8Array[]} */
- const chunks = [];
-
- // 8. Let chunkPromise be the result of reading a chunk from stream with reader.
- let chunkPromise = reader.read();
-
- // 9. Let isFirstChunk be true.
- let isFirstChunk = true;
-
- // 10 in parallel while true
- (async () => {
- while (!abortedState.aborted) {
- // 1. Wait for chunkPromise to be fulfilled or rejected.
- try {
- const chunk = await chunkPromise;
- if (abortedState.aborted) return;
-
- // 2. If chunkPromise is fulfilled, and isFirstChunk is true, queue a task to fire a progress event called loadstart at fr.
- if (isFirstChunk) {
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+const primordials = globalThis.__bootstrap.primordials;
+import { forgivingBase64Encode } from "internal:ext/web/00_infra.js";
+import { EventTarget, ProgressEvent } from "internal:ext/web/02_event.js";
+import { decode, TextDecoder } from "internal:ext/web/08_text_encoding.js";
+import { parseMimeType } from "internal:ext/web/01_mimesniff.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+const {
+ ArrayPrototypePush,
+ ArrayPrototypeReduce,
+ FunctionPrototypeCall,
+ Map,
+ MapPrototypeGet,
+ MapPrototypeSet,
+ ObjectDefineProperty,
+ ObjectPrototypeIsPrototypeOf,
+ queueMicrotask,
+ SafeArrayIterator,
+ Symbol,
+ TypedArrayPrototypeSet,
+ TypeError,
+ Uint8Array,
+ Uint8ArrayPrototype,
+} = primordials;
+
+const state = Symbol("[[state]]");
+const result = Symbol("[[result]]");
+const error = Symbol("[[error]]");
+const aborted = Symbol("[[aborted]]");
+const handlerSymbol = Symbol("eventHandlers");
+
+class FileReader extends EventTarget {
+ /** @type {"empty" | "loading" | "done"} */
+ [state] = "empty";
+ /** @type {null | string | ArrayBuffer} */
+ [result] = null;
+ /** @type {null | DOMException} */
+ [error] = null;
+ /** @type {null | {aborted: boolean}} */
+ [aborted] = null;
+
+ /**
+ * @param {Blob} blob
+ * @param {{kind: "ArrayBuffer" | "Text" | "DataUrl" | "BinaryString", encoding?: string}} readtype
+ */
+ #readOperation(blob, readtype) {
+ // 1. If fr’s state is "loading", throw an InvalidStateError DOMException.
+ if (this[state] === "loading") {
+ throw new DOMException(
+ "Invalid FileReader state.",
+ "InvalidStateError",
+ );
+ }
+ // 2. Set fr’s state to "loading".
+ this[state] = "loading";
+ // 3. Set fr’s result to null.
+ this[result] = null;
+ // 4. Set fr’s error to null.
+ this[error] = null;
+
+ // We set this[aborted] to a new object, and keep track of it in a
+ // separate variable, so if a new read operation starts while there are
+ // remaining tasks from a previous aborted operation, the new operation
+ // will run while the tasks from the previous one are still aborted.
+ const abortedState = this[aborted] = { aborted: false };
+
+ // 5. Let stream be the result of calling get stream on blob.
+ const stream /*: ReadableStream<ArrayBufferView>*/ = blob.stream();
+
+ // 6. Let reader be the result of getting a reader from stream.
+ const reader = stream.getReader();
+
+ // 7. Let bytes be an empty byte sequence.
+ /** @type {Uint8Array[]} */
+ const chunks = [];
+
+ // 8. Let chunkPromise be the result of reading a chunk from stream with reader.
+ let chunkPromise = reader.read();
+
+ // 9. Let isFirstChunk be true.
+ let isFirstChunk = true;
+
+ // 10 in parallel while true
+ (async () => {
+ while (!abortedState.aborted) {
+ // 1. Wait for chunkPromise to be fulfilled or rejected.
+ try {
+ const chunk = await chunkPromise;
+ if (abortedState.aborted) return;
+
+ // 2. If chunkPromise is fulfilled, and isFirstChunk is true, queue a task to fire a progress event called loadstart at fr.
+ if (isFirstChunk) {
+ // TODO(lucacasonato): this is wrong, should be HTML "queue a task"
+ queueMicrotask(() => {
+ if (abortedState.aborted) return;
+ // fire a progress event for loadstart
+ const ev = new ProgressEvent("loadstart", {});
+ this.dispatchEvent(ev);
+ });
+ }
+ // 3. Set isFirstChunk to false.
+ isFirstChunk = false;
+
+ // 4. If chunkPromise is fulfilled with an object whose done property is false
+ // and whose value property is a Uint8Array object, run these steps:
+ if (
+ !chunk.done &&
+ ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, chunk.value)
+ ) {
+ ArrayPrototypePush(chunks, chunk.value);
+
+ // TODO(bartlomieju): (only) If roughly 50ms have passed since last progress
+ {
+ const size = ArrayPrototypeReduce(
+ chunks,
+ (p, i) => p + i.byteLength,
+ 0,
+ );
+ const ev = new ProgressEvent("progress", {
+ loaded: size,
+ });
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
queueMicrotask(() => {
if (abortedState.aborted) return;
- // fire a progress event for loadstart
- const ev = new ProgressEvent("loadstart", {});
this.dispatchEvent(ev);
});
}
- // 3. Set isFirstChunk to false.
- isFirstChunk = false;
-
- // 4. If chunkPromise is fulfilled with an object whose done property is false
- // and whose value property is a Uint8Array object, run these steps:
- if (
- !chunk.done &&
- ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, chunk.value)
- ) {
- ArrayPrototypePush(chunks, chunk.value);
-
- // TODO(bartlomieju): (only) If roughly 50ms have passed since last progress
- {
- const size = ArrayPrototypeReduce(
- chunks,
- (p, i) => p + i.byteLength,
- 0,
- );
- const ev = new ProgressEvent("progress", {
- loaded: size,
- });
- // TODO(lucacasonato): this is wrong, should be HTML "queue a task"
- queueMicrotask(() => {
- if (abortedState.aborted) return;
- this.dispatchEvent(ev);
- });
- }
- chunkPromise = reader.read();
- } // 5 Otherwise, if chunkPromise is fulfilled with an object whose done property is true, queue a task to run the following steps and abort this algorithm:
- else if (chunk.done === true) {
- // TODO(lucacasonato): this is wrong, should be HTML "queue a task"
- queueMicrotask(() => {
- if (abortedState.aborted) return;
- // 1. Set fr’s state to "done".
- this[state] = "done";
- // 2. Let result be the result of package data given bytes, type, blob’s type, and encodingName.
- const size = ArrayPrototypeReduce(
- chunks,
- (p, i) => p + i.byteLength,
- 0,
- );
- const bytes = new Uint8Array(size);
- let offs = 0;
- for (let i = 0; i < chunks.length; ++i) {
- const chunk = chunks[i];
- TypedArrayPrototypeSet(bytes, chunk, offs);
- offs += chunk.byteLength;
+ chunkPromise = reader.read();
+ } // 5 Otherwise, if chunkPromise is fulfilled with an object whose done property is true, queue a task to run the following steps and abort this algorithm:
+ else if (chunk.done === true) {
+ // TODO(lucacasonato): this is wrong, should be HTML "queue a task"
+ queueMicrotask(() => {
+ if (abortedState.aborted) return;
+ // 1. Set fr’s state to "done".
+ this[state] = "done";
+ // 2. Let result be the result of package data given bytes, type, blob’s type, and encodingName.
+ const size = ArrayPrototypeReduce(
+ chunks,
+ (p, i) => p + i.byteLength,
+ 0,
+ );
+ const bytes = new Uint8Array(size);
+ let offs = 0;
+ for (let i = 0; i < chunks.length; ++i) {
+ const chunk = chunks[i];
+ TypedArrayPrototypeSet(bytes, chunk, offs);
+ offs += chunk.byteLength;
+ }
+ switch (readtype.kind) {
+ case "ArrayBuffer": {
+ this[result] = bytes.buffer;
+ break;
}
- switch (readtype.kind) {
- case "ArrayBuffer": {
- this[result] = bytes.buffer;
- break;
- }
- case "BinaryString":
- this[result] = core.ops.op_encode_binary_string(bytes);
- break;
- case "Text": {
- let decoder = undefined;
- if (readtype.encoding) {
- try {
- decoder = new TextDecoder(readtype.encoding);
- } catch {
- // don't care about the error
- }
+ case "BinaryString":
+ this[result] = ops.op_encode_binary_string(bytes);
+ break;
+ case "Text": {
+ let decoder = undefined;
+ if (readtype.encoding) {
+ try {
+ decoder = new TextDecoder(readtype.encoding);
+ } catch {
+ // don't care about the error
}
- if (decoder === undefined) {
- const mimeType = parseMimeType(blob.type);
- if (mimeType) {
- const charset = MapPrototypeGet(
- mimeType.parameters,
- "charset",
- );
- if (charset) {
- try {
- decoder = new TextDecoder(charset);
- } catch {
- // don't care about the error
- }
+ }
+ if (decoder === undefined) {
+ const mimeType = parseMimeType(blob.type);
+ if (mimeType) {
+ const charset = MapPrototypeGet(
+ mimeType.parameters,
+ "charset",
+ );
+ if (charset) {
+ try {
+ decoder = new TextDecoder(charset);
+ } catch {
+ // don't care about the error
}
}
}
- if (decoder === undefined) {
- decoder = new TextDecoder();
- }
- this[result] = decode(bytes, decoder.encoding);
- break;
}
- case "DataUrl": {
- const mediaType = blob.type || "application/octet-stream";
- this[result] = `data:${mediaType};base64,${
- forgivingBase64Encode(bytes)
- }`;
- break;
+ if (decoder === undefined) {
+ decoder = new TextDecoder();
}
+ this[result] = decode(bytes, decoder.encoding);
+ break;
}
- // 4.2 Fire a progress event called load at the fr.
- {
- const ev = new ProgressEvent("load", {
- lengthComputable: true,
- loaded: size,
- total: size,
- });
- this.dispatchEvent(ev);
- }
-
- // 5. If fr’s state is not "loading", fire a progress event called loadend at the fr.
- //Note: Event handler for the load or error events could have started another load, if that happens the loadend event for this load is not fired.
- if (this[state] !== "loading") {
- const ev = new ProgressEvent("loadend", {
- lengthComputable: true,
- loaded: size,
- total: size,
- });
- this.dispatchEvent(ev);
+ case "DataUrl": {
+ const mediaType = blob.type || "application/octet-stream";
+ this[result] = `data:${mediaType};base64,${
+ forgivingBase64Encode(bytes)
+ }`;
+ break;
}
- });
- break;
- }
- } catch (err) {
- // TODO(lucacasonato): this is wrong, should be HTML "queue a task"
- queueMicrotask(() => {
- if (abortedState.aborted) return;
-
- // chunkPromise rejected
- this[state] = "done";
- this[error] = err;
-
+ }
+ // 4.2 Fire a progress event called load at the fr.
{
- const ev = new ProgressEvent("error", {});
+ const ev = new ProgressEvent("load", {
+ lengthComputable: true,
+ loaded: size,
+ total: size,
+ });
this.dispatchEvent(ev);
}
- //If fr’s state is not "loading", fire a progress event called loadend at fr.
- //Note: Event handler for the error event could have started another load, if that happens the loadend event for this load is not fired.
+ // 5. If fr’s state is not "loading", fire a progress event called loadend at the fr.
+ //Note: Event handler for the load or error events could have started another load, if that happens the loadend event for this load is not fired.
if (this[state] !== "loading") {
- const ev = new ProgressEvent("loadend", {});
+ const ev = new ProgressEvent("loadend", {
+ lengthComputable: true,
+ loaded: size,
+ total: size,
+ });
this.dispatchEvent(ev);
}
});
break;
}
- }
- })();
- }
+ } catch (err) {
+ // TODO(lucacasonato): this is wrong, should be HTML "queue a task"
+ queueMicrotask(() => {
+ if (abortedState.aborted) return;
- #getEventHandlerFor(name) {
- webidl.assertBranded(this, FileReaderPrototype);
+ // chunkPromise rejected
+ this[state] = "done";
+ this[error] = err;
- const maybeMap = this[handlerSymbol];
- if (!maybeMap) return null;
+ {
+ const ev = new ProgressEvent("error", {});
+ this.dispatchEvent(ev);
+ }
- return MapPrototypeGet(maybeMap, name)?.handler ?? null;
- }
+ //If fr’s state is not "loading", fire a progress event called loadend at fr.
+ //Note: Event handler for the error event could have started another load, if that happens the loadend event for this load is not fired.
+ if (this[state] !== "loading") {
+ const ev = new ProgressEvent("loadend", {});
+ this.dispatchEvent(ev);
+ }
+ });
+ break;
+ }
+ }
+ })();
+ }
- #setEventHandlerFor(name, value) {
- webidl.assertBranded(this, FileReaderPrototype);
+ #getEventHandlerFor(name) {
+ webidl.assertBranded(this, FileReaderPrototype);
- if (!this[handlerSymbol]) {
- this[handlerSymbol] = new Map();
- }
- let handlerWrapper = MapPrototypeGet(this[handlerSymbol], name);
- if (handlerWrapper) {
- handlerWrapper.handler = value;
- } else {
- handlerWrapper = makeWrappedHandler(value);
- this.addEventListener(name, handlerWrapper);
- }
+ const maybeMap = this[handlerSymbol];
+ if (!maybeMap) return null;
- MapPrototypeSet(this[handlerSymbol], name, handlerWrapper);
- }
+ return MapPrototypeGet(maybeMap, name)?.handler ?? null;
+ }
- constructor() {
- super();
- this[webidl.brand] = webidl.brand;
- }
+ #setEventHandlerFor(name, value) {
+ webidl.assertBranded(this, FileReaderPrototype);
- /** @returns {number} */
- get readyState() {
- webidl.assertBranded(this, FileReaderPrototype);
- switch (this[state]) {
- case "empty":
- return FileReader.EMPTY;
- case "loading":
- return FileReader.LOADING;
- case "done":
- return FileReader.DONE;
- default:
- throw new TypeError("Invalid state");
- }
+ if (!this[handlerSymbol]) {
+ this[handlerSymbol] = new Map();
}
-
- get result() {
- webidl.assertBranded(this, FileReaderPrototype);
- return this[result];
+ let handlerWrapper = MapPrototypeGet(this[handlerSymbol], name);
+ if (handlerWrapper) {
+ handlerWrapper.handler = value;
+ } else {
+ handlerWrapper = makeWrappedHandler(value);
+ this.addEventListener(name, handlerWrapper);
}
- get error() {
- webidl.assertBranded(this, FileReaderPrototype);
- return this[error];
+ MapPrototypeSet(this[handlerSymbol], name, handlerWrapper);
+ }
+
+ constructor() {
+ super();
+ this[webidl.brand] = webidl.brand;
+ }
+
+ /** @returns {number} */
+ get readyState() {
+ webidl.assertBranded(this, FileReaderPrototype);
+ switch (this[state]) {
+ case "empty":
+ return FileReader.EMPTY;
+ case "loading":
+ return FileReader.LOADING;
+ case "done":
+ return FileReader.DONE;
+ default:
+ throw new TypeError("Invalid state");
}
+ }
- abort() {
- webidl.assertBranded(this, FileReaderPrototype);
- // If context object's state is "empty" or if context object's state is "done" set context object's result to null and terminate this algorithm.
- if (
- this[state] === "empty" ||
- this[state] === "done"
- ) {
- this[result] = null;
- return;
- }
- // If context object's state is "loading" set context object's state to "done" and set context object's result to null.
- if (this[state] === "loading") {
- this[state] = "done";
- this[result] = null;
- }
- // If there are any tasks from the context object on the file reading task source in an affiliated task queue, then remove those tasks from that task queue.
- // Terminate the algorithm for the read method being processed.
- if (this[aborted] !== null) {
- this[aborted].aborted = true;
- }
+ get result() {
+ webidl.assertBranded(this, FileReaderPrototype);
+ return this[result];
+ }
- // Fire a progress event called abort at the context object.
- const ev = new ProgressEvent("abort", {});
- this.dispatchEvent(ev);
+ get error() {
+ webidl.assertBranded(this, FileReaderPrototype);
+ return this[error];
+ }
- // If context object's state is not "loading", fire a progress event called loadend at the context object.
- if (this[state] !== "loading") {
- const ev = new ProgressEvent("loadend", {});
- this.dispatchEvent(ev);
- }
+ abort() {
+ webidl.assertBranded(this, FileReaderPrototype);
+ // If context object's state is "empty" or if context object's state is "done" set context object's result to null and terminate this algorithm.
+ if (
+ this[state] === "empty" ||
+ this[state] === "done"
+ ) {
+ this[result] = null;
+ return;
}
-
- /** @param {Blob} blob */
- readAsArrayBuffer(blob) {
- webidl.assertBranded(this, FileReaderPrototype);
- const prefix = "Failed to execute 'readAsArrayBuffer' on 'FileReader'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- this.#readOperation(blob, { kind: "ArrayBuffer" });
+ // If context object's state is "loading" set context object's state to "done" and set context object's result to null.
+ if (this[state] === "loading") {
+ this[state] = "done";
+ this[result] = null;
}
-
- /** @param {Blob} blob */
- readAsBinaryString(blob) {
- webidl.assertBranded(this, FileReaderPrototype);
- const prefix = "Failed to execute 'readAsBinaryString' on 'FileReader'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- // alias for readAsArrayBuffer
- this.#readOperation(blob, { kind: "BinaryString" });
+ // If there are any tasks from the context object on the file reading task source in an affiliated task queue, then remove those tasks from that task queue.
+ // Terminate the algorithm for the read method being processed.
+ if (this[aborted] !== null) {
+ this[aborted].aborted = true;
}
- /** @param {Blob} blob */
- readAsDataURL(blob) {
- webidl.assertBranded(this, FileReaderPrototype);
- const prefix = "Failed to execute 'readAsDataURL' on 'FileReader'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- // alias for readAsArrayBuffer
- this.#readOperation(blob, { kind: "DataUrl" });
- }
+ // Fire a progress event called abort at the context object.
+ const ev = new ProgressEvent("abort", {});
+ this.dispatchEvent(ev);
- /**
- * @param {Blob} blob
- * @param {string} [encoding]
- */
- readAsText(blob, encoding = undefined) {
- webidl.assertBranded(this, FileReaderPrototype);
- const prefix = "Failed to execute 'readAsText' on 'FileReader'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- if (encoding !== undefined) {
- encoding = webidl.converters["DOMString"](encoding, {
- prefix,
- context: "Argument 2",
- });
- }
- // alias for readAsArrayBuffer
- this.#readOperation(blob, { kind: "Text", encoding });
+ // If context object's state is not "loading", fire a progress event called loadend at the context object.
+ if (this[state] !== "loading") {
+ const ev = new ProgressEvent("loadend", {});
+ this.dispatchEvent(ev);
}
+ }
- get onerror() {
- return this.#getEventHandlerFor("error");
- }
- set onerror(value) {
- this.#setEventHandlerFor("error", value);
- }
+ /** @param {Blob} blob */
+ readAsArrayBuffer(blob) {
+ webidl.assertBranded(this, FileReaderPrototype);
+ const prefix = "Failed to execute 'readAsArrayBuffer' on 'FileReader'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ this.#readOperation(blob, { kind: "ArrayBuffer" });
+ }
- get onloadstart() {
- return this.#getEventHandlerFor("loadstart");
- }
- set onloadstart(value) {
- this.#setEventHandlerFor("loadstart", value);
- }
+ /** @param {Blob} blob */
+ readAsBinaryString(blob) {
+ webidl.assertBranded(this, FileReaderPrototype);
+ const prefix = "Failed to execute 'readAsBinaryString' on 'FileReader'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ // alias for readAsArrayBuffer
+ this.#readOperation(blob, { kind: "BinaryString" });
+ }
- get onload() {
- return this.#getEventHandlerFor("load");
- }
- set onload(value) {
- this.#setEventHandlerFor("load", value);
- }
+ /** @param {Blob} blob */
+ readAsDataURL(blob) {
+ webidl.assertBranded(this, FileReaderPrototype);
+ const prefix = "Failed to execute 'readAsDataURL' on 'FileReader'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ // alias for readAsArrayBuffer
+ this.#readOperation(blob, { kind: "DataUrl" });
+ }
- get onloadend() {
- return this.#getEventHandlerFor("loadend");
- }
- set onloadend(value) {
- this.#setEventHandlerFor("loadend", value);
+ /**
+ * @param {Blob} blob
+ * @param {string} [encoding]
+ */
+ readAsText(blob, encoding = undefined) {
+ webidl.assertBranded(this, FileReaderPrototype);
+ const prefix = "Failed to execute 'readAsText' on 'FileReader'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ if (encoding !== undefined) {
+ encoding = webidl.converters["DOMString"](encoding, {
+ prefix,
+ context: "Argument 2",
+ });
}
+ // alias for readAsArrayBuffer
+ this.#readOperation(blob, { kind: "Text", encoding });
+ }
- get onprogress() {
- return this.#getEventHandlerFor("progress");
- }
- set onprogress(value) {
- this.#setEventHandlerFor("progress", value);
- }
+ get onerror() {
+ return this.#getEventHandlerFor("error");
+ }
+ set onerror(value) {
+ this.#setEventHandlerFor("error", value);
+ }
- get onabort() {
- return this.#getEventHandlerFor("abort");
- }
- set onabort(value) {
- this.#setEventHandlerFor("abort", value);
- }
+ get onloadstart() {
+ return this.#getEventHandlerFor("loadstart");
+ }
+ set onloadstart(value) {
+ this.#setEventHandlerFor("loadstart", value);
}
- webidl.configurePrototype(FileReader);
- const FileReaderPrototype = FileReader.prototype;
-
- ObjectDefineProperty(FileReader, "EMPTY", {
- writable: false,
- enumerable: true,
- configurable: false,
- value: 0,
- });
- ObjectDefineProperty(FileReader, "LOADING", {
- writable: false,
- enumerable: true,
- configurable: false,
- value: 1,
- });
- ObjectDefineProperty(FileReader, "DONE", {
- writable: false,
- enumerable: true,
- configurable: false,
- value: 2,
- });
- ObjectDefineProperty(FileReader.prototype, "EMPTY", {
- writable: false,
- enumerable: true,
- configurable: false,
- value: 0,
- });
- ObjectDefineProperty(FileReader.prototype, "LOADING", {
- writable: false,
- enumerable: true,
- configurable: false,
- value: 1,
- });
- ObjectDefineProperty(FileReader.prototype, "DONE", {
- writable: false,
- enumerable: true,
- configurable: false,
- value: 2,
- });
-
- function makeWrappedHandler(handler) {
- function wrappedHandler(...args) {
- if (typeof wrappedHandler.handler !== "function") {
- return;
- }
- return FunctionPrototypeCall(
- wrappedHandler.handler,
- this,
- ...new SafeArrayIterator(args),
- );
+ get onload() {
+ return this.#getEventHandlerFor("load");
+ }
+ set onload(value) {
+ this.#setEventHandlerFor("load", value);
+ }
+
+ get onloadend() {
+ return this.#getEventHandlerFor("loadend");
+ }
+ set onloadend(value) {
+ this.#setEventHandlerFor("loadend", value);
+ }
+
+ get onprogress() {
+ return this.#getEventHandlerFor("progress");
+ }
+ set onprogress(value) {
+ this.#setEventHandlerFor("progress", value);
+ }
+
+ get onabort() {
+ return this.#getEventHandlerFor("abort");
+ }
+ set onabort(value) {
+ this.#setEventHandlerFor("abort", value);
+ }
+}
+
+webidl.configurePrototype(FileReader);
+const FileReaderPrototype = FileReader.prototype;
+
+ObjectDefineProperty(FileReader, "EMPTY", {
+ writable: false,
+ enumerable: true,
+ configurable: false,
+ value: 0,
+});
+ObjectDefineProperty(FileReader, "LOADING", {
+ writable: false,
+ enumerable: true,
+ configurable: false,
+ value: 1,
+});
+ObjectDefineProperty(FileReader, "DONE", {
+ writable: false,
+ enumerable: true,
+ configurable: false,
+ value: 2,
+});
+ObjectDefineProperty(FileReader.prototype, "EMPTY", {
+ writable: false,
+ enumerable: true,
+ configurable: false,
+ value: 0,
+});
+ObjectDefineProperty(FileReader.prototype, "LOADING", {
+ writable: false,
+ enumerable: true,
+ configurable: false,
+ value: 1,
+});
+ObjectDefineProperty(FileReader.prototype, "DONE", {
+ writable: false,
+ enumerable: true,
+ configurable: false,
+ value: 2,
+});
+
+function makeWrappedHandler(handler) {
+ function wrappedHandler(...args) {
+ if (typeof wrappedHandler.handler !== "function") {
+ return;
}
- wrappedHandler.handler = handler;
- return wrappedHandler;
+ return FunctionPrototypeCall(
+ wrappedHandler.handler,
+ this,
+ ...new SafeArrayIterator(args),
+ );
}
+ wrappedHandler.handler = handler;
+ return wrappedHandler;
+}
- window.__bootstrap.fileReader = {
- FileReader,
- };
-})(this);
+export { FileReader };
diff --git a/ext/web/11_blob_url.js b/ext/web/11_blob_url.js
index a51a1e718..02551fef6 100644
--- a/ext/web/11_blob_url.js
+++ b/ext/web/11_blob_url.js
@@ -10,50 +10,42 @@
/// <reference path="../url/lib.deno_url.d.ts" />
/// <reference path="./internal.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-((window) => {
- const core = Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const { getParts } = window.__bootstrap.file;
- const { URL } = window.__bootstrap.url;
-
- /**
- * @param {Blob} blob
- * @returns {string}
- */
- function createObjectURL(blob) {
- const prefix = "Failed to execute 'createObjectURL' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- blob = webidl.converters["Blob"](blob, {
- context: "Argument 1",
- prefix,
- });
-
- const url = ops.op_blob_create_object_url(
- blob.type,
- getParts(blob),
- );
-
- return url;
- }
-
- /**
- * @param {string} url
- * @returns {void}
- */
- function revokeObjectURL(url) {
- const prefix = "Failed to execute 'revokeObjectURL' on 'URL'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- url = webidl.converters["DOMString"](url, {
- context: "Argument 1",
- prefix,
- });
-
- ops.op_blob_revoke_object_url(url);
- }
-
- URL.createObjectURL = createObjectURL;
- URL.revokeObjectURL = revokeObjectURL;
-})(globalThis);
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { getParts } from "internal:ext/web/09_file.js";
+import { URL } from "internal:ext/url/00_url.js";
+
+/**
+ * @param {Blob} blob
+ * @returns {string}
+ */
+function createObjectURL(blob) {
+ const prefix = "Failed to execute 'createObjectURL' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ blob = webidl.converters["Blob"](blob, {
+ context: "Argument 1",
+ prefix,
+ });
+
+ return ops.op_blob_create_object_url(blob.type, getParts(blob));
+}
+
+/**
+ * @param {string} url
+ * @returns {void}
+ */
+function revokeObjectURL(url) {
+ const prefix = "Failed to execute 'revokeObjectURL' on 'URL'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ url = webidl.converters["DOMString"](url, {
+ context: "Argument 1",
+ prefix,
+ });
+
+ ops.op_blob_revoke_object_url(url);
+}
+
+URL.createObjectURL = createObjectURL;
+URL.revokeObjectURL = revokeObjectURL;
diff --git a/ext/web/12_location.js b/ext/web/12_location.js
index 964ca591e..da964eae8 100644
--- a/ext/web/12_location.js
+++ b/ext/web/12_location.js
@@ -1,403 +1,410 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
/// <reference path="../../core/internal.d.ts" />
-((window) => {
- const { URL } = window.__bootstrap.url;
- const { DOMException } = window.__bootstrap.domException;
- const {
- Error,
- ObjectDefineProperties,
- Symbol,
- SymbolFor,
- SymbolToStringTag,
- TypeError,
- WeakMap,
- WeakMapPrototypeGet,
- WeakMapPrototypeSet,
- } = window.__bootstrap.primordials;
+import { URL } from "internal:ext/url/00_url.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ Error,
+ ObjectDefineProperties,
+ Symbol,
+ SymbolFor,
+ SymbolToStringTag,
+ TypeError,
+ WeakMap,
+ WeakMapPrototypeGet,
+ WeakMapPrototypeSet,
+} = primordials;
- const locationConstructorKey = Symbol("locationConstuctorKey");
+const locationConstructorKey = Symbol("locationConstuctorKey");
- // The differences between the definitions of `Location` and `WorkerLocation`
- // are because of the `LegacyUnforgeable` attribute only specified upon
- // `Location`'s properties. See:
- // - https://html.spec.whatwg.org/multipage/history.html#the-location-interface
- // - https://heycam.github.io/webidl/#LegacyUnforgeable
- class Location {
- constructor(href = null, key = null) {
- if (key != locationConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- const url = new URL(href);
- url.username = "";
- url.password = "";
- ObjectDefineProperties(this, {
- hash: {
- get() {
- return url.hash;
- },
- set() {
- throw new DOMException(
- `Cannot set "location.hash".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+// The differences between the definitions of `Location` and `WorkerLocation`
+// are because of the `LegacyUnforgeable` attribute only specified upon
+// `Location`'s properties. See:
+// - https://html.spec.whatwg.org/multipage/history.html#the-location-interface
+// - https://heycam.github.io/webidl/#LegacyUnforgeable
+class Location {
+ constructor(href = null, key = null) {
+ if (key != locationConstructorKey) {
+ throw new TypeError("Illegal constructor.");
+ }
+ const url = new URL(href);
+ url.username = "";
+ url.password = "";
+ ObjectDefineProperties(this, {
+ hash: {
+ get() {
+ return url.hash;
},
- host: {
- get() {
- return url.host;
- },
- set() {
- throw new DOMException(
- `Cannot set "location.host".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+ set() {
+ throw new DOMException(
+ `Cannot set "location.hash".`,
+ "NotSupportedError",
+ );
},
- hostname: {
- get() {
- return url.hostname;
- },
- set() {
- throw new DOMException(
- `Cannot set "location.hostname".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+ enumerable: true,
+ },
+ host: {
+ get() {
+ return url.host;
},
- href: {
- get() {
- return url.href;
- },
- set() {
- throw new DOMException(
- `Cannot set "location.href".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+ set() {
+ throw new DOMException(
+ `Cannot set "location.host".`,
+ "NotSupportedError",
+ );
},
- origin: {
- get() {
- return url.origin;
- },
- enumerable: true,
+ enumerable: true,
+ },
+ hostname: {
+ get() {
+ return url.hostname;
},
- pathname: {
- get() {
- return url.pathname;
- },
- set() {
- throw new DOMException(
- `Cannot set "location.pathname".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+ set() {
+ throw new DOMException(
+ `Cannot set "location.hostname".`,
+ "NotSupportedError",
+ );
},
- port: {
- get() {
- return url.port;
- },
- set() {
- throw new DOMException(
- `Cannot set "location.port".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+ enumerable: true,
+ },
+ href: {
+ get() {
+ return url.href;
},
- protocol: {
- get() {
- return url.protocol;
- },
- set() {
- throw new DOMException(
- `Cannot set "location.protocol".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+ set() {
+ throw new DOMException(
+ `Cannot set "location.href".`,
+ "NotSupportedError",
+ );
},
- search: {
- get() {
- return url.search;
- },
- set() {
- throw new DOMException(
- `Cannot set "location.search".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+ enumerable: true,
+ },
+ origin: {
+ get() {
+ return url.origin;
},
- ancestorOrigins: {
- get() {
- // TODO(nayeemrmn): Replace with a `DOMStringList` instance.
- return {
- length: 0,
- item: () => null,
- contains: () => false,
- };
- },
- enumerable: true,
+ enumerable: true,
+ },
+ pathname: {
+ get() {
+ return url.pathname;
},
- assign: {
- value: function assign() {
- throw new DOMException(
- `Cannot call "location.assign()".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+ set() {
+ throw new DOMException(
+ `Cannot set "location.pathname".`,
+ "NotSupportedError",
+ );
},
- reload: {
- value: function reload() {
- throw new DOMException(
- `Cannot call "location.reload()".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+ enumerable: true,
+ },
+ port: {
+ get() {
+ return url.port;
},
- replace: {
- value: function replace() {
- throw new DOMException(
- `Cannot call "location.replace()".`,
- "NotSupportedError",
- );
- },
- enumerable: true,
+ set() {
+ throw new DOMException(
+ `Cannot set "location.port".`,
+ "NotSupportedError",
+ );
},
- toString: {
- value: function toString() {
- return url.href;
- },
- enumerable: true,
+ enumerable: true,
+ },
+ protocol: {
+ get() {
+ return url.protocol;
},
- [SymbolFor("Deno.privateCustomInspect")]: {
- value: function (inspect) {
- const object = {
- hash: this.hash,
- host: this.host,
- hostname: this.hostname,
- href: this.href,
- origin: this.origin,
- pathname: this.pathname,
- port: this.port,
- protocol: this.protocol,
- search: this.search,
- };
- return `${this.constructor.name} ${inspect(object)}`;
- },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.protocol".`,
+ "NotSupportedError",
+ );
},
- });
- }
+ enumerable: true,
+ },
+ search: {
+ get() {
+ return url.search;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.search".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ ancestorOrigins: {
+ get() {
+ // TODO(nayeemrmn): Replace with a `DOMStringList` instance.
+ return {
+ length: 0,
+ item: () => null,
+ contains: () => false,
+ };
+ },
+ enumerable: true,
+ },
+ assign: {
+ value: function assign() {
+ throw new DOMException(
+ `Cannot call "location.assign()".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ reload: {
+ value: function reload() {
+ throw new DOMException(
+ `Cannot call "location.reload()".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ replace: {
+ value: function replace() {
+ throw new DOMException(
+ `Cannot call "location.replace()".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ toString: {
+ value: function toString() {
+ return url.href;
+ },
+ enumerable: true,
+ },
+ [SymbolFor("Deno.privateCustomInspect")]: {
+ value: function (inspect) {
+ const object = {
+ hash: this.hash,
+ host: this.host,
+ hostname: this.hostname,
+ href: this.href,
+ origin: this.origin,
+ pathname: this.pathname,
+ port: this.port,
+ protocol: this.protocol,
+ search: this.search,
+ };
+ return `${this.constructor.name} ${inspect(object)}`;
+ },
+ },
+ });
}
+}
- ObjectDefineProperties(Location.prototype, {
- [SymbolToStringTag]: {
- value: "Location",
- configurable: true,
- },
- });
+ObjectDefineProperties(Location.prototype, {
+ [SymbolToStringTag]: {
+ value: "Location",
+ configurable: true,
+ },
+});
- const workerLocationUrls = new WeakMap();
+const workerLocationUrls = new WeakMap();
- class WorkerLocation {
- constructor(href = null, key = null) {
- if (key != locationConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- const url = new URL(href);
- url.username = "";
- url.password = "";
- WeakMapPrototypeSet(workerLocationUrls, this, url);
+class WorkerLocation {
+ constructor(href = null, key = null) {
+ if (key != locationConstructorKey) {
+ throw new TypeError("Illegal constructor.");
}
+ const url = new URL(href);
+ url.username = "";
+ url.password = "";
+ WeakMapPrototypeSet(workerLocationUrls, this, url);
}
+}
- ObjectDefineProperties(WorkerLocation.prototype, {
- hash: {
- get() {
- const url = WeakMapPrototypeGet(workerLocationUrls, this);
- if (url == null) {
- throw new TypeError("Illegal invocation.");
- }
- return url.hash;
- },
- configurable: true,
- enumerable: true,
- },
- host: {
- get() {
- const url = WeakMapPrototypeGet(workerLocationUrls, this);
- if (url == null) {
- throw new TypeError("Illegal invocation.");
- }
- return url.host;
- },
- configurable: true,
- enumerable: true,
+ObjectDefineProperties(WorkerLocation.prototype, {
+ hash: {
+ get() {
+ const url = WeakMapPrototypeGet(workerLocationUrls, this);
+ if (url == null) {
+ throw new TypeError("Illegal invocation.");
+ }
+ return url.hash;
},
- hostname: {
- get() {
- const url = WeakMapPrototypeGet(workerLocationUrls, this);
- if (url == null) {
- throw new TypeError("Illegal invocation.");
- }
- return url.hostname;
- },
- configurable: true,
- enumerable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ host: {
+ get() {
+ const url = WeakMapPrototypeGet(workerLocationUrls, this);
+ if (url == null) {
+ throw new TypeError("Illegal invocation.");
+ }
+ return url.host;
},
- href: {
- get() {
- const url = WeakMapPrototypeGet(workerLocationUrls, this);
- if (url == null) {
- throw new TypeError("Illegal invocation.");
- }
- return url.href;
- },
- configurable: true,
- enumerable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ hostname: {
+ get() {
+ const url = WeakMapPrototypeGet(workerLocationUrls, this);
+ if (url == null) {
+ throw new TypeError("Illegal invocation.");
+ }
+ return url.hostname;
},
- origin: {
- get() {
- const url = WeakMapPrototypeGet(workerLocationUrls, this);
- if (url == null) {
- throw new TypeError("Illegal invocation.");
- }
- return url.origin;
- },
- configurable: true,
- enumerable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ href: {
+ get() {
+ const url = WeakMapPrototypeGet(workerLocationUrls, this);
+ if (url == null) {
+ throw new TypeError("Illegal invocation.");
+ }
+ return url.href;
},
- pathname: {
- get() {
- const url = WeakMapPrototypeGet(workerLocationUrls, this);
- if (url == null) {
- throw new TypeError("Illegal invocation.");
- }
- return url.pathname;
- },
- configurable: true,
- enumerable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ origin: {
+ get() {
+ const url = WeakMapPrototypeGet(workerLocationUrls, this);
+ if (url == null) {
+ throw new TypeError("Illegal invocation.");
+ }
+ return url.origin;
},
- port: {
- get() {
- const url = WeakMapPrototypeGet(workerLocationUrls, this);
- if (url == null) {
- throw new TypeError("Illegal invocation.");
- }
- return url.port;
- },
- configurable: true,
- enumerable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ pathname: {
+ get() {
+ const url = WeakMapPrototypeGet(workerLocationUrls, this);
+ if (url == null) {
+ throw new TypeError("Illegal invocation.");
+ }
+ return url.pathname;
},
- protocol: {
- get() {
- const url = WeakMapPrototypeGet(workerLocationUrls, this);
- if (url == null) {
- throw new TypeError("Illegal invocation.");
- }
- return url.protocol;
- },
- configurable: true,
- enumerable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ port: {
+ get() {
+ const url = WeakMapPrototypeGet(workerLocationUrls, this);
+ if (url == null) {
+ throw new TypeError("Illegal invocation.");
+ }
+ return url.port;
},
- search: {
- get() {
- const url = WeakMapPrototypeGet(workerLocationUrls, this);
- if (url == null) {
- throw new TypeError("Illegal invocation.");
- }
- return url.search;
- },
- configurable: true,
- enumerable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ protocol: {
+ get() {
+ const url = WeakMapPrototypeGet(workerLocationUrls, this);
+ if (url == null) {
+ throw new TypeError("Illegal invocation.");
+ }
+ return url.protocol;
},
- toString: {
- value: function toString() {
- const url = WeakMapPrototypeGet(workerLocationUrls, this);
- if (url == null) {
- throw new TypeError("Illegal invocation.");
- }
- return url.href;
- },
- configurable: true,
- enumerable: true,
- writable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ search: {
+ get() {
+ const url = WeakMapPrototypeGet(workerLocationUrls, this);
+ if (url == null) {
+ throw new TypeError("Illegal invocation.");
+ }
+ return url.search;
},
- [SymbolToStringTag]: {
- value: "WorkerLocation",
- configurable: true,
+ configurable: true,
+ enumerable: true,
+ },
+ toString: {
+ value: function toString() {
+ const url = WeakMapPrototypeGet(workerLocationUrls, this);
+ if (url == null) {
+ throw new TypeError("Illegal invocation.");
+ }
+ return url.href;
},
- [SymbolFor("Deno.privateCustomInspect")]: {
- value: function (inspect) {
- const object = {
- hash: this.hash,
- host: this.host,
- hostname: this.hostname,
- href: this.href,
- origin: this.origin,
- pathname: this.pathname,
- port: this.port,
- protocol: this.protocol,
- search: this.search,
- };
- return `${this.constructor.name} ${inspect(object)}`;
- },
+ configurable: true,
+ enumerable: true,
+ writable: true,
+ },
+ [SymbolToStringTag]: {
+ value: "WorkerLocation",
+ configurable: true,
+ },
+ [SymbolFor("Deno.privateCustomInspect")]: {
+ value: function (inspect) {
+ const object = {
+ hash: this.hash,
+ host: this.host,
+ hostname: this.hostname,
+ href: this.href,
+ origin: this.origin,
+ pathname: this.pathname,
+ port: this.port,
+ protocol: this.protocol,
+ search: this.search,
+ };
+ return `${this.constructor.name} ${inspect(object)}`;
},
- });
+ },
+});
- let location = undefined;
- let workerLocation = undefined;
+let location = undefined;
+let workerLocation = undefined;
- function setLocationHref(href) {
- location = new Location(href, locationConstructorKey);
- workerLocation = new WorkerLocation(href, locationConstructorKey);
- }
+function setLocationHref(href) {
+ location = new Location(href, locationConstructorKey);
+ workerLocation = new WorkerLocation(href, locationConstructorKey);
+}
- window.__bootstrap.location = {
- locationConstructorDescriptor: {
- value: Location,
- configurable: true,
- writable: true,
- },
- workerLocationConstructorDescriptor: {
- value: WorkerLocation,
- configurable: true,
- writable: true,
- },
- locationDescriptor: {
- get() {
- return location;
- },
- set() {
- throw new DOMException(`Cannot set "location".`, "NotSupportedError");
- },
- enumerable: true,
- },
- workerLocationDescriptor: {
- get() {
- if (workerLocation == null) {
- throw new Error(
- `Assertion: "globalThis.location" must be defined in a worker.`,
- );
- }
- return workerLocation;
- },
- configurable: true,
- enumerable: true,
- },
- setLocationHref,
- getLocationHref() {
- return location?.href;
- },
- };
-})(this);
+function getLocationHref() {
+ return location?.href;
+}
+
+const locationConstructorDescriptor = {
+ value: Location,
+ configurable: true,
+ writable: true,
+};
+
+const workerLocationConstructorDescriptor = {
+ value: WorkerLocation,
+ configurable: true,
+ writable: true,
+};
+
+const locationDescriptor = {
+ get() {
+ return location;
+ },
+ set() {
+ throw new DOMException(`Cannot set "location".`, "NotSupportedError");
+ },
+ enumerable: true,
+};
+const workerLocationDescriptor = {
+ get() {
+ if (workerLocation == null) {
+ throw new Error(
+ `Assertion: "globalThis.location" must be defined in a worker.`,
+ );
+ }
+ return workerLocation;
+ },
+ configurable: true,
+ enumerable: true,
+};
+
+export {
+ getLocationHref,
+ locationConstructorDescriptor,
+ locationDescriptor,
+ setLocationHref,
+ workerLocationConstructorDescriptor,
+ workerLocationDescriptor,
+};
diff --git a/ext/web/13_message_port.js b/ext/web/13_message_port.js
index 7ab2beb82..2a784bf3f 100644
--- a/ext/web/13_message_port.js
+++ b/ext/web/13_message_port.js
@@ -6,338 +6,339 @@
/// <reference path="./internal.d.ts" />
/// <reference path="./lib.deno_web.d.ts" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const { InterruptedPrototype, ops } = core;
- const webidl = window.__bootstrap.webidl;
- const { EventTarget, setEventTargetData } = window.__bootstrap.eventTarget;
- const { MessageEvent, defineEventHandler } = window.__bootstrap.event;
- const { DOMException } = window.__bootstrap.domException;
- const {
- ArrayBufferPrototype,
- ArrayPrototypeFilter,
- ArrayPrototypeIncludes,
- ArrayPrototypePush,
- ObjectPrototypeIsPrototypeOf,
- ObjectSetPrototypeOf,
- Symbol,
- SymbolFor,
- SymbolIterator,
- TypeError,
- } = window.__bootstrap.primordials;
-
- class MessageChannel {
- /** @type {MessagePort} */
- #port1;
- /** @type {MessagePort} */
- #port2;
-
- constructor() {
- this[webidl.brand] = webidl.brand;
- const { 0: port1Id, 1: port2Id } = opCreateEntangledMessagePort();
- const port1 = createMessagePort(port1Id);
- const port2 = createMessagePort(port2Id);
- this.#port1 = port1;
- this.#port2 = port2;
- }
-
- get port1() {
- webidl.assertBranded(this, MessageChannelPrototype);
- return this.#port1;
- }
-
- get port2() {
- webidl.assertBranded(this, MessageChannelPrototype);
- return this.#port2;
- }
+const core = globalThis.Deno.core;
+const { InterruptedPrototype, ops } = core;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import {
+ defineEventHandler,
+ EventTarget,
+ MessageEvent,
+ setEventTargetData,
+} from "internal:ext/web/02_event.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayBufferPrototype,
+ ArrayPrototypeFilter,
+ ArrayPrototypeIncludes,
+ ArrayPrototypePush,
+ ObjectPrototypeIsPrototypeOf,
+ ObjectSetPrototypeOf,
+ Symbol,
+ SymbolFor,
+ SymbolIterator,
+ TypeError,
+} = primordials;
+
+class MessageChannel {
+ /** @type {MessagePort} */
+ #port1;
+ /** @type {MessagePort} */
+ #port2;
+
+ constructor() {
+ this[webidl.brand] = webidl.brand;
+ const { 0: port1Id, 1: port2Id } = opCreateEntangledMessagePort();
+ const port1 = createMessagePort(port1Id);
+ const port2 = createMessagePort(port2Id);
+ this.#port1 = port1;
+ this.#port2 = port2;
+ }
- [SymbolFor("Deno.inspect")](inspect) {
- return `MessageChannel ${
- inspect({ port1: this.port1, port2: this.port2 })
- }`;
- }
+ get port1() {
+ webidl.assertBranded(this, MessageChannelPrototype);
+ return this.#port1;
}
- webidl.configurePrototype(MessageChannel);
- const MessageChannelPrototype = MessageChannel.prototype;
+ get port2() {
+ webidl.assertBranded(this, MessageChannelPrototype);
+ return this.#port2;
+ }
- const _id = Symbol("id");
- const _enabled = Symbol("enabled");
+ [SymbolFor("Deno.inspect")](inspect) {
+ return `MessageChannel ${
+ inspect({ port1: this.port1, port2: this.port2 })
+ }`;
+ }
+}
+
+webidl.configurePrototype(MessageChannel);
+const MessageChannelPrototype = MessageChannel.prototype;
+
+const _id = Symbol("id");
+const _enabled = Symbol("enabled");
+
+/**
+ * @param {number} id
+ * @returns {MessagePort}
+ */
+function createMessagePort(id) {
+ const port = core.createHostObject();
+ ObjectSetPrototypeOf(port, MessagePortPrototype);
+ port[webidl.brand] = webidl.brand;
+ setEventTargetData(port);
+ port[_id] = id;
+ return port;
+}
+
+class MessagePort extends EventTarget {
+ /** @type {number | null} */
+ [_id] = null;
+ /** @type {boolean} */
+ [_enabled] = false;
+
+ constructor() {
+ super();
+ webidl.illegalConstructor();
+ }
/**
- * @param {number} id
- * @returns {MessagePort}
+ * @param {any} message
+ * @param {object[] | StructuredSerializeOptions} transferOrOptions
*/
- function createMessagePort(id) {
- const port = core.createHostObject();
- ObjectSetPrototypeOf(port, MessagePortPrototype);
- port[webidl.brand] = webidl.brand;
- setEventTargetData(port);
- port[_id] = id;
- return port;
- }
-
- class MessagePort extends EventTarget {
- /** @type {number | null} */
- [_id] = null;
- /** @type {boolean} */
- [_enabled] = false;
-
- constructor() {
- super();
- webidl.illegalConstructor();
+ postMessage(message, transferOrOptions = {}) {
+ webidl.assertBranded(this, MessagePortPrototype);
+ const prefix = "Failed to execute 'postMessage' on 'MessagePort'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ message = webidl.converters.any(message);
+ let options;
+ if (
+ webidl.type(transferOrOptions) === "Object" &&
+ transferOrOptions !== undefined &&
+ transferOrOptions[SymbolIterator] !== undefined
+ ) {
+ const transfer = webidl.converters["sequence<object>"](
+ transferOrOptions,
+ { prefix, context: "Argument 2" },
+ );
+ options = { transfer };
+ } else {
+ options = webidl.converters.StructuredSerializeOptions(
+ transferOrOptions,
+ {
+ prefix,
+ context: "Argument 2",
+ },
+ );
}
-
- /**
- * @param {any} message
- * @param {object[] | StructuredSerializeOptions} transferOrOptions
- */
- postMessage(message, transferOrOptions = {}) {
- webidl.assertBranded(this, MessagePortPrototype);
- const prefix = "Failed to execute 'postMessage' on 'MessagePort'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- message = webidl.converters.any(message);
- let options;
- if (
- webidl.type(transferOrOptions) === "Object" &&
- transferOrOptions !== undefined &&
- transferOrOptions[SymbolIterator] !== undefined
- ) {
- const transfer = webidl.converters["sequence<object>"](
- transferOrOptions,
- { prefix, context: "Argument 2" },
- );
- options = { transfer };
- } else {
- options = webidl.converters.StructuredSerializeOptions(
- transferOrOptions,
- {
- prefix,
- context: "Argument 2",
- },
- );
- }
- const { transfer } = options;
- if (ArrayPrototypeIncludes(transfer, this)) {
- throw new DOMException("Can not tranfer self", "DataCloneError");
- }
- const data = serializeJsMessageData(message, transfer);
- if (this[_id] === null) return;
- ops.op_message_port_post_message(this[_id], data);
+ const { transfer } = options;
+ if (ArrayPrototypeIncludes(transfer, this)) {
+ throw new DOMException("Can not tranfer self", "DataCloneError");
}
+ const data = serializeJsMessageData(message, transfer);
+ if (this[_id] === null) return;
+ ops.op_message_port_post_message(this[_id], data);
+ }
- start() {
- webidl.assertBranded(this, MessagePortPrototype);
- if (this[_enabled]) return;
- (async () => {
- this[_enabled] = true;
- while (true) {
- if (this[_id] === null) break;
- let data;
- try {
- data = await core.opAsync(
- "op_message_port_recv_message",
- this[_id],
- );
- } catch (err) {
- if (ObjectPrototypeIsPrototypeOf(InterruptedPrototype, err)) break;
- throw err;
- }
- if (data === null) break;
- let message, transferables;
- try {
- const v = deserializeJsMessageData(data);
- message = v[0];
- transferables = v[1];
- } catch (err) {
- const event = new MessageEvent("messageerror", { data: err });
- this.dispatchEvent(event);
- return;
- }
- const event = new MessageEvent("message", {
- data: message,
- ports: ArrayPrototypeFilter(
- transferables,
- (t) => ObjectPrototypeIsPrototypeOf(MessagePortPrototype, t),
- ),
- });
+ start() {
+ webidl.assertBranded(this, MessagePortPrototype);
+ if (this[_enabled]) return;
+ (async () => {
+ this[_enabled] = true;
+ while (true) {
+ if (this[_id] === null) break;
+ let data;
+ try {
+ data = await core.opAsync(
+ "op_message_port_recv_message",
+ this[_id],
+ );
+ } catch (err) {
+ if (ObjectPrototypeIsPrototypeOf(InterruptedPrototype, err)) break;
+ throw err;
+ }
+ if (data === null) break;
+ let message, transferables;
+ try {
+ const v = deserializeJsMessageData(data);
+ message = v[0];
+ transferables = v[1];
+ } catch (err) {
+ const event = new MessageEvent("messageerror", { data: err });
this.dispatchEvent(event);
+ return;
}
- this[_enabled] = false;
- })();
- }
-
- close() {
- webidl.assertBranded(this, MessagePortPrototype);
- if (this[_id] !== null) {
- core.close(this[_id]);
- this[_id] = null;
+ const event = new MessageEvent("message", {
+ data: message,
+ ports: ArrayPrototypeFilter(
+ transferables,
+ (t) => ObjectPrototypeIsPrototypeOf(MessagePortPrototype, t),
+ ),
+ });
+ this.dispatchEvent(event);
}
- }
+ this[_enabled] = false;
+ })();
}
- defineEventHandler(MessagePort.prototype, "message", function (self) {
- self.start();
- });
- defineEventHandler(MessagePort.prototype, "messageerror");
-
- webidl.configurePrototype(MessagePort);
- const MessagePortPrototype = MessagePort.prototype;
-
- /**
- * @returns {[number, number]}
- */
- function opCreateEntangledMessagePort() {
- return ops.op_message_port_create_entangled();
+ close() {
+ webidl.assertBranded(this, MessagePortPrototype);
+ if (this[_id] !== null) {
+ core.close(this[_id]);
+ this[_id] = null;
+ }
}
-
- /**
- * @param {globalThis.__bootstrap.messagePort.MessageData} messageData
- * @returns {[any, object[]]}
- */
- function deserializeJsMessageData(messageData) {
- /** @type {object[]} */
- const transferables = [];
- const hostObjects = [];
- const arrayBufferIdsInTransferables = [];
- const transferredArrayBuffers = [];
-
- for (let i = 0; i < messageData.transferables.length; ++i) {
- const transferable = messageData.transferables[i];
- switch (transferable.kind) {
- case "messagePort": {
- const port = createMessagePort(transferable.data);
- ArrayPrototypePush(transferables, port);
- ArrayPrototypePush(hostObjects, port);
- break;
- }
- case "arrayBuffer": {
- ArrayPrototypePush(transferredArrayBuffers, transferable.data);
- const index = ArrayPrototypePush(transferables, null);
- ArrayPrototypePush(arrayBufferIdsInTransferables, index);
- break;
- }
- default:
- throw new TypeError("Unreachable");
+}
+
+defineEventHandler(MessagePort.prototype, "message", function (self) {
+ self.start();
+});
+defineEventHandler(MessagePort.prototype, "messageerror");
+
+webidl.configurePrototype(MessagePort);
+const MessagePortPrototype = MessagePort.prototype;
+
+/**
+ * @returns {[number, number]}
+ */
+function opCreateEntangledMessagePort() {
+ return ops.op_message_port_create_entangled();
+}
+
+/**
+ * @param {messagePort.MessageData} messageData
+ * @returns {[any, object[]]}
+ */
+function deserializeJsMessageData(messageData) {
+ /** @type {object[]} */
+ const transferables = [];
+ const hostObjects = [];
+ const arrayBufferIdsInTransferables = [];
+ const transferredArrayBuffers = [];
+
+ for (let i = 0; i < messageData.transferables.length; ++i) {
+ const transferable = messageData.transferables[i];
+ switch (transferable.kind) {
+ case "messagePort": {
+ const port = createMessagePort(transferable.data);
+ ArrayPrototypePush(transferables, port);
+ ArrayPrototypePush(hostObjects, port);
+ break;
+ }
+ case "arrayBuffer": {
+ ArrayPrototypePush(transferredArrayBuffers, transferable.data);
+ const index = ArrayPrototypePush(transferables, null);
+ ArrayPrototypePush(arrayBufferIdsInTransferables, index);
+ break;
}
+ default:
+ throw new TypeError("Unreachable");
}
+ }
- const data = core.deserialize(messageData.data, {
- hostObjects,
- transferredArrayBuffers,
- });
-
- for (let i = 0; i < arrayBufferIdsInTransferables.length; ++i) {
- const id = arrayBufferIdsInTransferables[i];
- transferables[id] = transferredArrayBuffers[i];
- }
+ const data = core.deserialize(messageData.data, {
+ hostObjects,
+ transferredArrayBuffers,
+ });
- return [data, transferables];
+ for (let i = 0; i < arrayBufferIdsInTransferables.length; ++i) {
+ const id = arrayBufferIdsInTransferables[i];
+ transferables[id] = transferredArrayBuffers[i];
}
- /**
- * @param {any} data
- * @param {object[]} transferables
- * @returns {globalThis.__bootstrap.messagePort.MessageData}
- */
- function serializeJsMessageData(data, transferables) {
- const transferredArrayBuffers = [];
- for (let i = 0, j = 0; i < transferables.length; i++) {
- const ab = transferables[i];
- if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, ab)) {
- if (ab.byteLength === 0 && core.ops.op_arraybuffer_was_detached(ab)) {
- throw new DOMException(
- `ArrayBuffer at index ${j} is already detached`,
- "DataCloneError",
- );
- }
- j++;
- transferredArrayBuffers.push(ab);
+ return [data, transferables];
+}
+
+/**
+ * @param {any} data
+ * @param {object[]} transferables
+ * @returns {messagePort.MessageData}
+ */
+function serializeJsMessageData(data, transferables) {
+ const transferredArrayBuffers = [];
+ for (let i = 0, j = 0; i < transferables.length; i++) {
+ const ab = transferables[i];
+ if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, ab)) {
+ if (ab.byteLength === 0 && ops.op_arraybuffer_was_detached(ab)) {
+ throw new DOMException(
+ `ArrayBuffer at index ${j} is already detached`,
+ "DataCloneError",
+ );
}
+ j++;
+ transferredArrayBuffers.push(ab);
}
+ }
- const serializedData = core.serialize(data, {
- hostObjects: ArrayPrototypeFilter(
- transferables,
- (a) => ObjectPrototypeIsPrototypeOf(MessagePortPrototype, a),
- ),
- transferredArrayBuffers,
- }, (err) => {
- throw new DOMException(err, "DataCloneError");
- });
-
- /** @type {globalThis.__bootstrap.messagePort.Transferable[]} */
- const serializedTransferables = [];
+ const serializedData = core.serialize(data, {
+ hostObjects: ArrayPrototypeFilter(
+ transferables,
+ (a) => ObjectPrototypeIsPrototypeOf(MessagePortPrototype, a),
+ ),
+ transferredArrayBuffers,
+ }, (err) => {
+ throw new DOMException(err, "DataCloneError");
+ });
- let arrayBufferI = 0;
- for (let i = 0; i < transferables.length; ++i) {
- const transferable = transferables[i];
- if (ObjectPrototypeIsPrototypeOf(MessagePortPrototype, transferable)) {
- webidl.assertBranded(transferable, MessagePortPrototype);
- const id = transferable[_id];
- if (id === null) {
- throw new DOMException(
- "Can not transfer disentangled message port",
- "DataCloneError",
- );
- }
- transferable[_id] = null;
- ArrayPrototypePush(serializedTransferables, {
- kind: "messagePort",
- data: id,
- });
- } else if (
- ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, transferable)
- ) {
- ArrayPrototypePush(serializedTransferables, {
- kind: "arrayBuffer",
- data: transferredArrayBuffers[arrayBufferI],
- });
- arrayBufferI++;
- } else {
- throw new DOMException("Value not transferable", "DataCloneError");
+ /** @type {messagePort.Transferable[]} */
+ const serializedTransferables = [];
+
+ let arrayBufferI = 0;
+ for (let i = 0; i < transferables.length; ++i) {
+ const transferable = transferables[i];
+ if (ObjectPrototypeIsPrototypeOf(MessagePortPrototype, transferable)) {
+ webidl.assertBranded(transferable, MessagePortPrototype);
+ const id = transferable[_id];
+ if (id === null) {
+ throw new DOMException(
+ "Can not transfer disentangled message port",
+ "DataCloneError",
+ );
}
+ transferable[_id] = null;
+ ArrayPrototypePush(serializedTransferables, {
+ kind: "messagePort",
+ data: id,
+ });
+ } else if (
+ ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, transferable)
+ ) {
+ ArrayPrototypePush(serializedTransferables, {
+ kind: "arrayBuffer",
+ data: transferredArrayBuffers[arrayBufferI],
+ });
+ arrayBufferI++;
+ } else {
+ throw new DOMException("Value not transferable", "DataCloneError");
}
-
- return {
- data: serializedData,
- transferables: serializedTransferables,
- };
}
- webidl.converters.StructuredSerializeOptions = webidl
- .createDictionaryConverter(
- "StructuredSerializeOptions",
- [
- {
- key: "transfer",
- converter: webidl.converters["sequence<object>"],
- get defaultValue() {
- return [];
- },
- },
- ],
- );
-
- function structuredClone(value, options) {
- const prefix = "Failed to execute 'structuredClone'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- options = webidl.converters.StructuredSerializeOptions(options, {
- prefix,
- context: "Argument 2",
- });
- const messageData = serializeJsMessageData(value, options.transfer);
- return deserializeJsMessageData(messageData)[0];
- }
-
- window.__bootstrap.messagePort = {
- MessageChannel,
- MessagePort,
- MessagePortPrototype,
- deserializeJsMessageData,
- serializeJsMessageData,
- structuredClone,
+ return {
+ data: serializedData,
+ transferables: serializedTransferables,
};
-})(globalThis);
+}
+
+webidl.converters.StructuredSerializeOptions = webidl
+ .createDictionaryConverter(
+ "StructuredSerializeOptions",
+ [
+ {
+ key: "transfer",
+ converter: webidl.converters["sequence<object>"],
+ get defaultValue() {
+ return [];
+ },
+ },
+ ],
+ );
+
+function structuredClone(value, options) {
+ const prefix = "Failed to execute 'structuredClone'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ options = webidl.converters.StructuredSerializeOptions(options, {
+ prefix,
+ context: "Argument 2",
+ });
+ const messageData = serializeJsMessageData(value, options.transfer);
+ return deserializeJsMessageData(messageData)[0];
+}
+
+export {
+ deserializeJsMessageData,
+ MessageChannel,
+ MessagePort,
+ MessagePortPrototype,
+ serializeJsMessageData,
+ structuredClone,
+};
diff --git a/ext/web/14_compression.js b/ext/web/14_compression.js
index 338f8c803..680da757e 100644
--- a/ext/web/14_compression.js
+++ b/ext/web/14_compression.js
@@ -5,127 +5,120 @@
/// <reference path="./internal.d.ts" />
/// <reference path="./lib.deno_web.d.ts" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const { TransformStream } = window.__bootstrap.streams;
-
- webidl.converters.CompressionFormat = webidl.createEnumConverter(
- "CompressionFormat",
- [
- "deflate",
- "deflate-raw",
- "gzip",
- ],
- );
-
- class CompressionStream {
- #transform;
-
- constructor(format) {
- const prefix = "Failed to construct 'CompressionStream'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- format = webidl.converters.CompressionFormat(format, {
- prefix,
- context: "Argument 1",
- });
-
- const rid = ops.op_compression_new(format, false);
-
- this.#transform = new TransformStream({
- transform(chunk, controller) {
- chunk = webidl.converters.BufferSource(chunk, {
- prefix,
- context: "chunk",
- });
- const output = ops.op_compression_write(
- rid,
- chunk,
- );
- maybeEnqueue(controller, output);
- },
- flush(controller) {
- const output = ops.op_compression_finish(rid);
- maybeEnqueue(controller, output);
- },
- });
-
- this[webidl.brand] = webidl.brand;
- }
-
- get readable() {
- webidl.assertBranded(this, CompressionStreamPrototype);
- return this.#transform.readable;
- }
-
- get writable() {
- webidl.assertBranded(this, CompressionStreamPrototype);
- return this.#transform.writable;
- }
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { TransformStream } from "internal:ext/web/06_streams.js";
+
+webidl.converters.CompressionFormat = webidl.createEnumConverter(
+ "CompressionFormat",
+ [
+ "deflate",
+ "deflate-raw",
+ "gzip",
+ ],
+);
+
+class CompressionStream {
+ #transform;
+
+ constructor(format) {
+ const prefix = "Failed to construct 'CompressionStream'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ format = webidl.converters.CompressionFormat(format, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ const rid = ops.op_compression_new(format, false);
+
+ this.#transform = new TransformStream({
+ transform(chunk, controller) {
+ chunk = webidl.converters.BufferSource(chunk, {
+ prefix,
+ context: "chunk",
+ });
+ const output = ops.op_compression_write(
+ rid,
+ chunk,
+ );
+ maybeEnqueue(controller, output);
+ },
+ flush(controller) {
+ const output = ops.op_compression_finish(rid);
+ maybeEnqueue(controller, output);
+ },
+ });
+
+ this[webidl.brand] = webidl.brand;
}
- webidl.configurePrototype(CompressionStream);
- const CompressionStreamPrototype = CompressionStream.prototype;
-
- class DecompressionStream {
- #transform;
-
- constructor(format) {
- const prefix = "Failed to construct 'DecompressionStream'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- format = webidl.converters.CompressionFormat(format, {
- prefix,
- context: "Argument 1",
- });
-
- const rid = ops.op_compression_new(format, true);
-
- this.#transform = new TransformStream({
- transform(chunk, controller) {
- chunk = webidl.converters.BufferSource(chunk, {
- prefix,
- context: "chunk",
- });
- const output = ops.op_compression_write(
- rid,
- chunk,
- );
- maybeEnqueue(controller, output);
- },
- flush(controller) {
- const output = ops.op_compression_finish(rid);
- maybeEnqueue(controller, output);
- },
- });
-
- this[webidl.brand] = webidl.brand;
- }
-
- get readable() {
- webidl.assertBranded(this, DecompressionStreamPrototype);
- return this.#transform.readable;
- }
-
- get writable() {
- webidl.assertBranded(this, DecompressionStreamPrototype);
- return this.#transform.writable;
- }
+ get readable() {
+ webidl.assertBranded(this, CompressionStreamPrototype);
+ return this.#transform.readable;
}
- function maybeEnqueue(controller, output) {
- if (output && output.byteLength > 0) {
- controller.enqueue(output);
- }
+ get writable() {
+ webidl.assertBranded(this, CompressionStreamPrototype);
+ return this.#transform.writable;
}
+}
+
+webidl.configurePrototype(CompressionStream);
+const CompressionStreamPrototype = CompressionStream.prototype;
+
+class DecompressionStream {
+ #transform;
+
+ constructor(format) {
+ const prefix = "Failed to construct 'DecompressionStream'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ format = webidl.converters.CompressionFormat(format, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ const rid = ops.op_compression_new(format, true);
+
+ this.#transform = new TransformStream({
+ transform(chunk, controller) {
+ chunk = webidl.converters.BufferSource(chunk, {
+ prefix,
+ context: "chunk",
+ });
+ const output = ops.op_compression_write(
+ rid,
+ chunk,
+ );
+ maybeEnqueue(controller, output);
+ },
+ flush(controller) {
+ const output = ops.op_compression_finish(rid);
+ maybeEnqueue(controller, output);
+ },
+ });
+
+ this[webidl.brand] = webidl.brand;
+ }
+
+ get readable() {
+ webidl.assertBranded(this, DecompressionStreamPrototype);
+ return this.#transform.readable;
+ }
+
+ get writable() {
+ webidl.assertBranded(this, DecompressionStreamPrototype);
+ return this.#transform.writable;
+ }
+}
+
+function maybeEnqueue(controller, output) {
+ if (output && output.byteLength > 0) {
+ controller.enqueue(output);
+ }
+}
- webidl.configurePrototype(DecompressionStream);
- const DecompressionStreamPrototype = DecompressionStream.prototype;
+webidl.configurePrototype(DecompressionStream);
+const DecompressionStreamPrototype = DecompressionStream.prototype;
- window.__bootstrap.compression = {
- CompressionStream,
- DecompressionStream,
- };
-})(globalThis);
+export { CompressionStream, DecompressionStream };
diff --git a/ext/web/15_performance.js b/ext/web/15_performance.js
index 9107ce75b..6a50f45f8 100644
--- a/ext/web/15_performance.js
+++ b/ext/web/15_performance.js
@@ -1,594 +1,594 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const {
- ArrayPrototypeFilter,
- ArrayPrototypeFind,
- ArrayPrototypePush,
- ArrayPrototypeReverse,
- ArrayPrototypeSlice,
- ObjectKeys,
- ObjectPrototypeIsPrototypeOf,
- ReflectHas,
- Symbol,
- SymbolFor,
- TypeError,
- } = window.__bootstrap.primordials;
-
- const { webidl, structuredClone } = window.__bootstrap;
- const consoleInternal = window.__bootstrap.console;
- const { EventTarget } = window.__bootstrap.eventTarget;
- const { opNow } = window.__bootstrap.timers;
- const { DOMException } = window.__bootstrap.domException;
-
- const illegalConstructorKey = Symbol("illegalConstructorKey");
- const customInspect = SymbolFor("Deno.customInspect");
- let performanceEntries = [];
- let timeOrigin;
-
- webidl.converters["PerformanceMarkOptions"] = webidl
- .createDictionaryConverter(
- "PerformanceMarkOptions",
- [
- {
- key: "detail",
- converter: webidl.converters.any,
- },
- {
- key: "startTime",
- converter: webidl.converters.DOMHighResTimeStamp,
- },
- ],
- );
-
- webidl.converters["DOMString or DOMHighResTimeStamp"] = (V, opts) => {
- if (webidl.type(V) === "Number" && V !== null) {
- return webidl.converters.DOMHighResTimeStamp(V, opts);
- }
- return webidl.converters.DOMString(V, opts);
- };
-
- webidl.converters["PerformanceMeasureOptions"] = webidl
- .createDictionaryConverter(
- "PerformanceMeasureOptions",
- [
- {
- key: "detail",
- converter: webidl.converters.any,
- },
- {
- key: "start",
- converter: webidl.converters["DOMString or DOMHighResTimeStamp"],
- },
- {
- key: "duration",
- converter: webidl.converters.DOMHighResTimeStamp,
- },
- {
- key: "end",
- converter: webidl.converters["DOMString or DOMHighResTimeStamp"],
- },
- ],
- );
- webidl.converters["DOMString or PerformanceMeasureOptions"] = (V, opts) => {
- if (webidl.type(V) === "Object" && V !== null) {
- return webidl.converters["PerformanceMeasureOptions"](V, opts);
- }
- return webidl.converters.DOMString(V, opts);
- };
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeFilter,
+ ArrayPrototypeFind,
+ ArrayPrototypePush,
+ ArrayPrototypeReverse,
+ ArrayPrototypeSlice,
+ ObjectKeys,
+ ObjectPrototypeIsPrototypeOf,
+ ReflectHas,
+ Symbol,
+ SymbolFor,
+ TypeError,
+} = primordials;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { structuredClone } from "internal:ext/web/02_structured_clone.js";
+import { createFilteredInspectProxy } from "internal:ext/console/02_console.js";
+import { EventTarget } from "internal:ext/web/02_event.js";
+import { opNow } from "internal:ext/web/02_timers.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+
+const illegalConstructorKey = Symbol("illegalConstructorKey");
+const customInspect = SymbolFor("Deno.customInspect");
+let performanceEntries = [];
+let timeOrigin;
+
+webidl.converters["PerformanceMarkOptions"] = webidl
+ .createDictionaryConverter(
+ "PerformanceMarkOptions",
+ [
+ {
+ key: "detail",
+ converter: webidl.converters.any,
+ },
+ {
+ key: "startTime",
+ converter: webidl.converters.DOMHighResTimeStamp,
+ },
+ ],
+ );
- function setTimeOrigin(origin) {
- timeOrigin = origin;
+webidl.converters["DOMString or DOMHighResTimeStamp"] = (V, opts) => {
+ if (webidl.type(V) === "Number" && V !== null) {
+ return webidl.converters.DOMHighResTimeStamp(V, opts);
}
+ return webidl.converters.DOMString(V, opts);
+};
+
+webidl.converters["PerformanceMeasureOptions"] = webidl
+ .createDictionaryConverter(
+ "PerformanceMeasureOptions",
+ [
+ {
+ key: "detail",
+ converter: webidl.converters.any,
+ },
+ {
+ key: "start",
+ converter: webidl.converters["DOMString or DOMHighResTimeStamp"],
+ },
+ {
+ key: "duration",
+ converter: webidl.converters.DOMHighResTimeStamp,
+ },
+ {
+ key: "end",
+ converter: webidl.converters["DOMString or DOMHighResTimeStamp"],
+ },
+ ],
+ );
- function findMostRecent(
- name,
- type,
- ) {
- return ArrayPrototypeFind(
- ArrayPrototypeReverse(ArrayPrototypeSlice(performanceEntries)),
- (entry) => entry.name === name && entry.entryType === type,
- );
+webidl.converters["DOMString or PerformanceMeasureOptions"] = (V, opts) => {
+ if (webidl.type(V) === "Object" && V !== null) {
+ return webidl.converters["PerformanceMeasureOptions"](V, opts);
}
-
- function convertMarkToTimestamp(mark) {
- if (typeof mark === "string") {
- const entry = findMostRecent(mark, "mark");
- if (!entry) {
- throw new DOMException(
- `Cannot find mark: "${mark}".`,
- "SyntaxError",
- );
- }
- return entry.startTime;
- }
- if (mark < 0) {
- throw new TypeError("Mark cannot be negative.");
+ return webidl.converters.DOMString(V, opts);
+};
+
+function setTimeOrigin(origin) {
+ timeOrigin = origin;
+}
+
+function findMostRecent(
+ name,
+ type,
+) {
+ return ArrayPrototypeFind(
+ ArrayPrototypeReverse(ArrayPrototypeSlice(performanceEntries)),
+ (entry) => entry.name === name && entry.entryType === type,
+ );
+}
+
+function convertMarkToTimestamp(mark) {
+ if (typeof mark === "string") {
+ const entry = findMostRecent(mark, "mark");
+ if (!entry) {
+ throw new DOMException(
+ `Cannot find mark: "${mark}".`,
+ "SyntaxError",
+ );
}
- return mark;
+ return entry.startTime;
}
-
- function filterByNameType(
- name,
- type,
- ) {
- return ArrayPrototypeFilter(
- performanceEntries,
- (entry) =>
- (name ? entry.name === name : true) &&
- (type ? entry.entryType === type : true),
- );
+ if (mark < 0) {
+ throw new TypeError("Mark cannot be negative.");
+ }
+ return mark;
+}
+
+function filterByNameType(
+ name,
+ type,
+) {
+ return ArrayPrototypeFilter(
+ performanceEntries,
+ (entry) =>
+ (name ? entry.name === name : true) &&
+ (type ? entry.entryType === type : true),
+ );
+}
+
+const now = opNow;
+
+const _name = Symbol("[[name]]");
+const _entryType = Symbol("[[entryType]]");
+const _startTime = Symbol("[[startTime]]");
+const _duration = Symbol("[[duration]]");
+class PerformanceEntry {
+ [_name] = "";
+ [_entryType] = "";
+ [_startTime] = 0;
+ [_duration] = 0;
+
+ get name() {
+ webidl.assertBranded(this, PerformanceEntryPrototype);
+ return this[_name];
}
- const now = opNow;
+ get entryType() {
+ webidl.assertBranded(this, PerformanceEntryPrototype);
+ return this[_entryType];
+ }
- const _name = Symbol("[[name]]");
- const _entryType = Symbol("[[entryType]]");
- const _startTime = Symbol("[[startTime]]");
- const _duration = Symbol("[[duration]]");
- class PerformanceEntry {
- [_name] = "";
- [_entryType] = "";
- [_startTime] = 0;
- [_duration] = 0;
+ get startTime() {
+ webidl.assertBranded(this, PerformanceEntryPrototype);
+ return this[_startTime];
+ }
- get name() {
- webidl.assertBranded(this, PerformanceEntryPrototype);
- return this[_name];
- }
+ get duration() {
+ webidl.assertBranded(this, PerformanceEntryPrototype);
+ return this[_duration];
+ }
- get entryType() {
- webidl.assertBranded(this, PerformanceEntryPrototype);
- return this[_entryType];
+ constructor(
+ name = null,
+ entryType = null,
+ startTime = null,
+ duration = null,
+ key = undefined,
+ ) {
+ if (key !== illegalConstructorKey) {
+ webidl.illegalConstructor();
}
+ this[webidl.brand] = webidl.brand;
- get startTime() {
- webidl.assertBranded(this, PerformanceEntryPrototype);
- return this[_startTime];
- }
+ this[_name] = name;
+ this[_entryType] = entryType;
+ this[_startTime] = startTime;
+ this[_duration] = duration;
+ }
- get duration() {
- webidl.assertBranded(this, PerformanceEntryPrototype);
- return this[_duration];
- }
+ toJSON() {
+ webidl.assertBranded(this, PerformanceEntryPrototype);
+ return {
+ name: this[_name],
+ entryType: this[_entryType],
+ startTime: this[_startTime],
+ duration: this[_duration],
+ };
+ }
- constructor(
- name = null,
- entryType = null,
- startTime = null,
- duration = null,
- key = undefined,
- ) {
- if (key !== illegalConstructorKey) {
- webidl.illegalConstructor();
- }
- this[webidl.brand] = webidl.brand;
+ [customInspect](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ PerformanceEntryPrototype,
+ this,
+ ),
+ keys: [
+ "name",
+ "entryType",
+ "startTime",
+ "duration",
+ ],
+ }));
+ }
+}
+webidl.configurePrototype(PerformanceEntry);
+const PerformanceEntryPrototype = PerformanceEntry.prototype;
- this[_name] = name;
- this[_entryType] = entryType;
- this[_startTime] = startTime;
- this[_duration] = duration;
- }
+const _detail = Symbol("[[detail]]");
+class PerformanceMark extends PerformanceEntry {
+ [_detail] = null;
- toJSON() {
- webidl.assertBranded(this, PerformanceEntryPrototype);
- return {
- name: this[_name],
- entryType: this[_entryType],
- startTime: this[_startTime],
- duration: this[_duration],
- };
- }
+ get detail() {
+ webidl.assertBranded(this, PerformanceMarkPrototype);
+ return this[_detail];
+ }
- [customInspect](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(
- PerformanceEntryPrototype,
- this,
- ),
- keys: [
- "name",
- "entryType",
- "startTime",
- "duration",
- ],
- }));
- }
+ get entryType() {
+ webidl.assertBranded(this, PerformanceMarkPrototype);
+ return "mark";
}
- webidl.configurePrototype(PerformanceEntry);
- const PerformanceEntryPrototype = PerformanceEntry.prototype;
- const _detail = Symbol("[[detail]]");
- class PerformanceMark extends PerformanceEntry {
- [_detail] = null;
+ constructor(
+ name,
+ options = {},
+ ) {
+ const prefix = "Failed to construct 'PerformanceMark'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
- get detail() {
- webidl.assertBranded(this, PerformanceMarkPrototype);
- return this[_detail];
- }
+ name = webidl.converters.DOMString(name, {
+ prefix,
+ context: "Argument 1",
+ });
- get entryType() {
- webidl.assertBranded(this, PerformanceMarkPrototype);
- return "mark";
- }
+ options = webidl.converters.PerformanceMarkOptions(options, {
+ prefix,
+ context: "Argument 2",
+ });
- constructor(
- name,
- options = {},
- ) {
- const prefix = "Failed to construct 'PerformanceMark'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
+ const { detail = null, startTime = now() } = options;
- name = webidl.converters.DOMString(name, {
- prefix,
- context: "Argument 1",
- });
+ super(name, "mark", startTime, 0, illegalConstructorKey);
+ this[webidl.brand] = webidl.brand;
+ if (startTime < 0) {
+ throw new TypeError("startTime cannot be negative");
+ }
+ this[_detail] = structuredClone(detail);
+ }
- options = webidl.converters.PerformanceMarkOptions(options, {
- prefix,
- context: "Argument 2",
- });
+ toJSON() {
+ webidl.assertBranded(this, PerformanceMarkPrototype);
+ return {
+ name: this.name,
+ entryType: this.entryType,
+ startTime: this.startTime,
+ duration: this.duration,
+ detail: this.detail,
+ };
+ }
- const { detail = null, startTime = now() } = options;
+ [customInspect](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(PerformanceMarkPrototype, this),
+ keys: [
+ "name",
+ "entryType",
+ "startTime",
+ "duration",
+ "detail",
+ ],
+ }));
+ }
+}
+webidl.configurePrototype(PerformanceMark);
+const PerformanceMarkPrototype = PerformanceMark.prototype;
+class PerformanceMeasure extends PerformanceEntry {
+ [_detail] = null;
+
+ get detail() {
+ webidl.assertBranded(this, PerformanceMeasurePrototype);
+ return this[_detail];
+ }
- super(name, "mark", startTime, 0, illegalConstructorKey);
- this[webidl.brand] = webidl.brand;
- if (startTime < 0) {
- throw new TypeError("startTime cannot be negative");
- }
- this[_detail] = structuredClone(detail);
- }
+ get entryType() {
+ webidl.assertBranded(this, PerformanceMeasurePrototype);
+ return "measure";
+ }
- toJSON() {
- webidl.assertBranded(this, PerformanceMarkPrototype);
- return {
- name: this.name,
- entryType: this.entryType,
- startTime: this.startTime,
- duration: this.duration,
- detail: this.detail,
- };
+ constructor(
+ name = null,
+ startTime = null,
+ duration = null,
+ detail = null,
+ key = undefined,
+ ) {
+ if (key !== illegalConstructorKey) {
+ webidl.illegalConstructor();
}
- [customInspect](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(PerformanceMarkPrototype, this),
- keys: [
- "name",
- "entryType",
- "startTime",
- "duration",
- "detail",
- ],
- }));
- }
+ super(name, "measure", startTime, duration, key);
+ this[webidl.brand] = webidl.brand;
+ this[_detail] = structuredClone(detail);
}
- webidl.configurePrototype(PerformanceMark);
- const PerformanceMarkPrototype = PerformanceMark.prototype;
- class PerformanceMeasure extends PerformanceEntry {
- [_detail] = null;
- get detail() {
- webidl.assertBranded(this, PerformanceMeasurePrototype);
- return this[_detail];
- }
+ toJSON() {
+ webidl.assertBranded(this, PerformanceMeasurePrototype);
+ return {
+ name: this.name,
+ entryType: this.entryType,
+ startTime: this.startTime,
+ duration: this.duration,
+ detail: this.detail,
+ };
+ }
- get entryType() {
- webidl.assertBranded(this, PerformanceMeasurePrototype);
- return "measure";
+ [customInspect](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ PerformanceMeasurePrototype,
+ this,
+ ),
+ keys: [
+ "name",
+ "entryType",
+ "startTime",
+ "duration",
+ "detail",
+ ],
+ }));
+ }
+}
+webidl.configurePrototype(PerformanceMeasure);
+const PerformanceMeasurePrototype = PerformanceMeasure.prototype;
+class Performance extends EventTarget {
+ constructor(key = null) {
+ if (key != illegalConstructorKey) {
+ webidl.illegalConstructor();
}
- constructor(
- name = null,
- startTime = null,
- duration = null,
- detail = null,
- key = undefined,
- ) {
- if (key !== illegalConstructorKey) {
- webidl.illegalConstructor();
- }
+ super();
+ this[webidl.brand] = webidl.brand;
+ }
- super(name, "measure", startTime, duration, key);
- this[webidl.brand] = webidl.brand;
- this[_detail] = structuredClone(detail);
- }
+ get timeOrigin() {
+ webidl.assertBranded(this, PerformancePrototype);
+ return timeOrigin;
+ }
- toJSON() {
- webidl.assertBranded(this, PerformanceMeasurePrototype);
- return {
- name: this.name,
- entryType: this.entryType,
- startTime: this.startTime,
- duration: this.duration,
- detail: this.detail,
- };
- }
+ clearMarks(markName = undefined) {
+ webidl.assertBranded(this, PerformancePrototype);
+ if (markName !== undefined) {
+ markName = webidl.converters.DOMString(markName, {
+ prefix: "Failed to execute 'clearMarks' on 'Performance'",
+ context: "Argument 1",
+ });
- [customInspect](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(
- PerformanceMeasurePrototype,
- this,
- ),
- keys: [
- "name",
- "entryType",
- "startTime",
- "duration",
- "detail",
- ],
- }));
+ performanceEntries = ArrayPrototypeFilter(
+ performanceEntries,
+ (entry) => !(entry.name === markName && entry.entryType === "mark"),
+ );
+ } else {
+ performanceEntries = ArrayPrototypeFilter(
+ performanceEntries,
+ (entry) => entry.entryType !== "mark",
+ );
}
}
- webidl.configurePrototype(PerformanceMeasure);
- const PerformanceMeasurePrototype = PerformanceMeasure.prototype;
- class Performance extends EventTarget {
- constructor(key = null) {
- if (key != illegalConstructorKey) {
- webidl.illegalConstructor();
- }
- super();
- this[webidl.brand] = webidl.brand;
- }
-
- get timeOrigin() {
- webidl.assertBranded(this, PerformancePrototype);
- return timeOrigin;
- }
+ clearMeasures(measureName = undefined) {
+ webidl.assertBranded(this, PerformancePrototype);
+ if (measureName !== undefined) {
+ measureName = webidl.converters.DOMString(measureName, {
+ prefix: "Failed to execute 'clearMeasures' on 'Performance'",
+ context: "Argument 1",
+ });
- clearMarks(markName = undefined) {
- webidl.assertBranded(this, PerformancePrototype);
- if (markName !== undefined) {
- markName = webidl.converters.DOMString(markName, {
- prefix: "Failed to execute 'clearMarks' on 'Performance'",
- context: "Argument 1",
- });
-
- performanceEntries = ArrayPrototypeFilter(
- performanceEntries,
- (entry) => !(entry.name === markName && entry.entryType === "mark"),
- );
- } else {
- performanceEntries = ArrayPrototypeFilter(
- performanceEntries,
- (entry) => entry.entryType !== "mark",
- );
- }
+ performanceEntries = ArrayPrototypeFilter(
+ performanceEntries,
+ (entry) =>
+ !(entry.name === measureName && entry.entryType === "measure"),
+ );
+ } else {
+ performanceEntries = ArrayPrototypeFilter(
+ performanceEntries,
+ (entry) => entry.entryType !== "measure",
+ );
}
+ }
- clearMeasures(measureName = undefined) {
- webidl.assertBranded(this, PerformancePrototype);
- if (measureName !== undefined) {
- measureName = webidl.converters.DOMString(measureName, {
- prefix: "Failed to execute 'clearMeasures' on 'Performance'",
- context: "Argument 1",
- });
-
- performanceEntries = ArrayPrototypeFilter(
- performanceEntries,
- (entry) =>
- !(entry.name === measureName && entry.entryType === "measure"),
- );
- } else {
- performanceEntries = ArrayPrototypeFilter(
- performanceEntries,
- (entry) => entry.entryType !== "measure",
- );
- }
- }
+ getEntries() {
+ webidl.assertBranded(this, PerformancePrototype);
+ return filterByNameType();
+ }
- getEntries() {
- webidl.assertBranded(this, PerformancePrototype);
- return filterByNameType();
- }
+ getEntriesByName(
+ name,
+ type = undefined,
+ ) {
+ webidl.assertBranded(this, PerformancePrototype);
+ const prefix = "Failed to execute 'getEntriesByName' on 'Performance'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
- getEntriesByName(
- name,
- type = undefined,
- ) {
- webidl.assertBranded(this, PerformancePrototype);
- const prefix = "Failed to execute 'getEntriesByName' on 'Performance'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
+ name = webidl.converters.DOMString(name, {
+ prefix,
+ context: "Argument 1",
+ });
- name = webidl.converters.DOMString(name, {
+ if (type !== undefined) {
+ type = webidl.converters.DOMString(type, {
prefix,
- context: "Argument 1",
+ context: "Argument 2",
});
+ }
- if (type !== undefined) {
- type = webidl.converters.DOMString(type, {
- prefix,
- context: "Argument 2",
- });
- }
+ return filterByNameType(name, type);
+ }
- return filterByNameType(name, type);
- }
+ getEntriesByType(type) {
+ webidl.assertBranded(this, PerformancePrototype);
+ const prefix = "Failed to execute 'getEntriesByName' on 'Performance'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
- getEntriesByType(type) {
- webidl.assertBranded(this, PerformancePrototype);
- const prefix = "Failed to execute 'getEntriesByName' on 'Performance'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
+ type = webidl.converters.DOMString(type, {
+ prefix,
+ context: "Argument 1",
+ });
- type = webidl.converters.DOMString(type, {
- prefix,
- context: "Argument 1",
- });
+ return filterByNameType(undefined, type);
+ }
- return filterByNameType(undefined, type);
- }
+ mark(
+ markName,
+ markOptions = {},
+ ) {
+ webidl.assertBranded(this, PerformancePrototype);
+ const prefix = "Failed to execute 'mark' on 'Performance'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ markName = webidl.converters.DOMString(markName, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ markOptions = webidl.converters.PerformanceMarkOptions(markOptions, {
+ prefix,
+ context: "Argument 2",
+ });
+
+ // 3.1.1.1 If the global object is a Window object and markName uses the
+ // same name as a read only attribute in the PerformanceTiming interface,
+ // throw a SyntaxError. - not implemented
+ const entry = new PerformanceMark(markName, markOptions);
+ // 3.1.1.7 Queue entry - not implemented
+ ArrayPrototypePush(performanceEntries, entry);
+ return entry;
+ }
- mark(
- markName,
- markOptions = {},
- ) {
- webidl.assertBranded(this, PerformancePrototype);
- const prefix = "Failed to execute 'mark' on 'Performance'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
+ measure(
+ measureName,
+ startOrMeasureOptions = {},
+ endMark = undefined,
+ ) {
+ webidl.assertBranded(this, PerformancePrototype);
+ const prefix = "Failed to execute 'measure' on 'Performance'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
- markName = webidl.converters.DOMString(markName, {
- prefix,
- context: "Argument 1",
- });
+ measureName = webidl.converters.DOMString(measureName, {
+ prefix,
+ context: "Argument 1",
+ });
- markOptions = webidl.converters.PerformanceMarkOptions(markOptions, {
+ startOrMeasureOptions = webidl.converters
+ ["DOMString or PerformanceMeasureOptions"](startOrMeasureOptions, {
prefix,
context: "Argument 2",
});
- // 3.1.1.1 If the global object is a Window object and markName uses the
- // same name as a read only attribute in the PerformanceTiming interface,
- // throw a SyntaxError. - not implemented
- const entry = new PerformanceMark(markName, markOptions);
- // 3.1.1.7 Queue entry - not implemented
- ArrayPrototypePush(performanceEntries, entry);
- return entry;
- }
-
- measure(
- measureName,
- startOrMeasureOptions = {},
- endMark = undefined,
- ) {
- webidl.assertBranded(this, PerformancePrototype);
- const prefix = "Failed to execute 'measure' on 'Performance'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
-
- measureName = webidl.converters.DOMString(measureName, {
+ if (endMark !== undefined) {
+ endMark = webidl.converters.DOMString(endMark, {
prefix,
- context: "Argument 1",
+ context: "Argument 3",
});
+ }
- startOrMeasureOptions = webidl.converters
- ["DOMString or PerformanceMeasureOptions"](startOrMeasureOptions, {
- prefix,
- context: "Argument 2",
- });
-
- if (endMark !== undefined) {
- endMark = webidl.converters.DOMString(endMark, {
- prefix,
- context: "Argument 3",
- });
+ if (
+ startOrMeasureOptions && typeof startOrMeasureOptions === "object" &&
+ ObjectKeys(startOrMeasureOptions).length > 0
+ ) {
+ if (endMark) {
+ throw new TypeError("Options cannot be passed with endMark.");
}
-
if (
- startOrMeasureOptions && typeof startOrMeasureOptions === "object" &&
- ObjectKeys(startOrMeasureOptions).length > 0
- ) {
- if (endMark) {
- throw new TypeError("Options cannot be passed with endMark.");
- }
- if (
- !ReflectHas(startOrMeasureOptions, "start") &&
- !ReflectHas(startOrMeasureOptions, "end")
- ) {
- throw new TypeError(
- "A start or end mark must be supplied in options.",
- );
- }
- if (
- ReflectHas(startOrMeasureOptions, "start") &&
- ReflectHas(startOrMeasureOptions, "duration") &&
- ReflectHas(startOrMeasureOptions, "end")
- ) {
- throw new TypeError(
- "Cannot specify start, end, and duration together in options.",
- );
- }
- }
- let endTime;
- if (endMark) {
- endTime = convertMarkToTimestamp(endMark);
- } else if (
- typeof startOrMeasureOptions === "object" &&
- ReflectHas(startOrMeasureOptions, "end")
- ) {
- endTime = convertMarkToTimestamp(startOrMeasureOptions.end);
- } else if (
- typeof startOrMeasureOptions === "object" &&
- ReflectHas(startOrMeasureOptions, "start") &&
- ReflectHas(startOrMeasureOptions, "duration")
+ !ReflectHas(startOrMeasureOptions, "start") &&
+ !ReflectHas(startOrMeasureOptions, "end")
) {
- const start = convertMarkToTimestamp(startOrMeasureOptions.start);
- const duration = convertMarkToTimestamp(startOrMeasureOptions.duration);
- endTime = start + duration;
- } else {
- endTime = now();
+ throw new TypeError(
+ "A start or end mark must be supplied in options.",
+ );
}
- let startTime;
if (
- typeof startOrMeasureOptions === "object" &&
- ReflectHas(startOrMeasureOptions, "start")
- ) {
- startTime = convertMarkToTimestamp(startOrMeasureOptions.start);
- } else if (
- typeof startOrMeasureOptions === "object" &&
- ReflectHas(startOrMeasureOptions, "end") &&
- ReflectHas(startOrMeasureOptions, "duration")
+ ReflectHas(startOrMeasureOptions, "start") &&
+ ReflectHas(startOrMeasureOptions, "duration") &&
+ ReflectHas(startOrMeasureOptions, "end")
) {
- const end = convertMarkToTimestamp(startOrMeasureOptions.end);
- const duration = convertMarkToTimestamp(startOrMeasureOptions.duration);
- startTime = end - duration;
- } else if (typeof startOrMeasureOptions === "string") {
- startTime = convertMarkToTimestamp(startOrMeasureOptions);
- } else {
- startTime = 0;
+ throw new TypeError(
+ "Cannot specify start, end, and duration together in options.",
+ );
}
- const entry = new PerformanceMeasure(
- measureName,
- startTime,
- endTime - startTime,
- typeof startOrMeasureOptions === "object"
- ? startOrMeasureOptions.detail ?? null
- : null,
- illegalConstructorKey,
- );
- ArrayPrototypePush(performanceEntries, entry);
- return entry;
- }
-
- now() {
- webidl.assertBranded(this, PerformancePrototype);
- return now();
- }
-
- toJSON() {
- webidl.assertBranded(this, PerformancePrototype);
- return {
- timeOrigin: this.timeOrigin,
- };
}
+ let endTime;
+ if (endMark) {
+ endTime = convertMarkToTimestamp(endMark);
+ } else if (
+ typeof startOrMeasureOptions === "object" &&
+ ReflectHas(startOrMeasureOptions, "end")
+ ) {
+ endTime = convertMarkToTimestamp(startOrMeasureOptions.end);
+ } else if (
+ typeof startOrMeasureOptions === "object" &&
+ ReflectHas(startOrMeasureOptions, "start") &&
+ ReflectHas(startOrMeasureOptions, "duration")
+ ) {
+ const start = convertMarkToTimestamp(startOrMeasureOptions.start);
+ const duration = convertMarkToTimestamp(startOrMeasureOptions.duration);
+ endTime = start + duration;
+ } else {
+ endTime = now();
+ }
+ let startTime;
+ if (
+ typeof startOrMeasureOptions === "object" &&
+ ReflectHas(startOrMeasureOptions, "start")
+ ) {
+ startTime = convertMarkToTimestamp(startOrMeasureOptions.start);
+ } else if (
+ typeof startOrMeasureOptions === "object" &&
+ ReflectHas(startOrMeasureOptions, "end") &&
+ ReflectHas(startOrMeasureOptions, "duration")
+ ) {
+ const end = convertMarkToTimestamp(startOrMeasureOptions.end);
+ const duration = convertMarkToTimestamp(startOrMeasureOptions.duration);
+ startTime = end - duration;
+ } else if (typeof startOrMeasureOptions === "string") {
+ startTime = convertMarkToTimestamp(startOrMeasureOptions);
+ } else {
+ startTime = 0;
+ }
+ const entry = new PerformanceMeasure(
+ measureName,
+ startTime,
+ endTime - startTime,
+ typeof startOrMeasureOptions === "object"
+ ? startOrMeasureOptions.detail ?? null
+ : null,
+ illegalConstructorKey,
+ );
+ ArrayPrototypePush(performanceEntries, entry);
+ return entry;
+ }
- [customInspect](inspect) {
- return inspect(consoleInternal.createFilteredInspectProxy({
- object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(PerformancePrototype, this),
- keys: [],
- }));
- }
+ now() {
+ webidl.assertBranded(this, PerformancePrototype);
+ return now();
}
- webidl.configurePrototype(Performance);
- const PerformancePrototype = Performance.prototype;
- webidl.converters["Performance"] = webidl.createInterfaceConverter(
- "Performance",
- PerformancePrototype,
- );
+ toJSON() {
+ webidl.assertBranded(this, PerformancePrototype);
+ return {
+ timeOrigin: this.timeOrigin,
+ };
+ }
- window.__bootstrap.performance = {
- PerformanceEntry,
- PerformanceMark,
- PerformanceMeasure,
- Performance,
- performance: new Performance(illegalConstructorKey),
- setTimeOrigin,
- };
-})(this);
+ [customInspect](inspect) {
+ return inspect(createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(PerformancePrototype, this),
+ keys: [],
+ }));
+ }
+}
+webidl.configurePrototype(Performance);
+const PerformancePrototype = Performance.prototype;
+
+webidl.converters["Performance"] = webidl.createInterfaceConverter(
+ "Performance",
+ PerformancePrototype,
+);
+
+const performance = new Performance(illegalConstructorKey);
+
+export {
+ Performance,
+ performance,
+ PerformanceEntry,
+ PerformanceMark,
+ PerformanceMeasure,
+ setTimeOrigin,
+};
diff --git a/ext/web/benches/encoding.rs b/ext/web/benches/encoding.rs
index 254ea4455..f8ad57c4f 100644
--- a/ext/web/benches/encoding.rs
+++ b/ext/web/benches/encoding.rs
@@ -29,11 +29,12 @@ fn setup() -> Vec<Extension> {
deno_console::init(),
deno_web::init::<Permissions>(BlobStore::default(), None),
Extension::builder("bench_setup")
- .js(vec![(
- "setup",
+ .esm(vec![(
+ "internal:setup",
r#"
- const { TextDecoder } = globalThis.__bootstrap.encoding;
- const hello12k = Deno.core.encode("hello world\n".repeat(1e3));
+ import { TextDecoder } from "internal:ext/web/08_text_encoding.js";
+ globalThis.TextDecoder = TextDecoder;
+ globalThis.hello12k = Deno.core.encode("hello world\n".repeat(1e3));
"#,
)])
.state(|state| {
diff --git a/ext/web/benches/timers_ops.rs b/ext/web/benches/timers_ops.rs
index b28b1ae1d..a2af22982 100644
--- a/ext/web/benches/timers_ops.rs
+++ b/ext/web/benches/timers_ops.rs
@@ -28,9 +28,10 @@ fn setup() -> Vec<Extension> {
deno_console::init(),
deno_web::init::<Permissions>(BlobStore::default(), None),
Extension::builder("bench_setup")
- .js(vec![
- ("setup", r#"
- const { setTimeout, handleTimerMacrotask } = globalThis.__bootstrap.timers;
+ .esm(vec![
+ ("internal:setup", r#"
+ import { setTimeout, handleTimerMacrotask } from "internal:ext/web/02_timers.js";
+ globalThis.setTimeout = setTimeout;
Deno.core.setMacrotaskCallback(handleTimerMacrotask);
"#),
])
diff --git a/ext/web/internal.d.ts b/ext/web/internal.d.ts
index 9bb89d98e..fe0c8ac07 100644
--- a/ext/web/internal.d.ts
+++ b/ext/web/internal.d.ts
@@ -1,120 +1,111 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-// deno-lint-ignore-file no-var
-
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
-declare namespace globalThis {
- declare namespace __bootstrap {
- declare var infra: {
- collectSequenceOfCodepoints(
- input: string,
- position: number,
- condition: (char: string) => boolean,
- ): {
- result: string;
- position: number;
- };
- ASCII_DIGIT: string[];
- ASCII_UPPER_ALPHA: string[];
- ASCII_LOWER_ALPHA: string[];
- ASCII_ALPHA: string[];
- ASCII_ALPHANUMERIC: string[];
- HTTP_TAB_OR_SPACE: string[];
- HTTP_WHITESPACE: string[];
- HTTP_TOKEN_CODE_POINT: string[];
- HTTP_TOKEN_CODE_POINT_RE: RegExp;
- HTTP_QUOTED_STRING_TOKEN_POINT: string[];
- HTTP_QUOTED_STRING_TOKEN_POINT_RE: RegExp;
- HTTP_TAB_OR_SPACE_PREFIX_RE: RegExp;
- HTTP_TAB_OR_SPACE_SUFFIX_RE: RegExp;
- HTTP_WHITESPACE_PREFIX_RE: RegExp;
- HTTP_WHITESPACE_SUFFIX_RE: RegExp;
- httpTrim(s: string): string;
- regexMatcher(chars: string[]): string;
- byteUpperCase(s: string): string;
- byteLowerCase(s: string): string;
- collectHttpQuotedString(
- input: string,
- position: number,
- extractValue: boolean,
- ): {
- result: string;
- position: number;
- };
- forgivingBase64Encode(data: Uint8Array): string;
- forgivingBase64Decode(data: string): Uint8Array;
- serializeJSValueToJSONString(value: unknown): string;
- };
-
- declare var domException: {
- DOMException: typeof DOMException;
- };
+declare module "internal:ext/web/00_infra.js" {
+ function collectSequenceOfCodepoints(
+ input: string,
+ position: number,
+ condition: (char: string) => boolean,
+ ): {
+ result: string;
+ position: number;
+ };
+ const ASCII_DIGIT: string[];
+ const ASCII_UPPER_ALPHA: string[];
+ const ASCII_LOWER_ALPHA: string[];
+ const ASCII_ALPHA: string[];
+ const ASCII_ALPHANUMERIC: string[];
+ const HTTP_TAB_OR_SPACE: string[];
+ const HTTP_WHITESPACE: string[];
+ const HTTP_TOKEN_CODE_POINT: string[];
+ const HTTP_TOKEN_CODE_POINT_RE: RegExp;
+ const HTTP_QUOTED_STRING_TOKEN_POINT: string[];
+ const HTTP_QUOTED_STRING_TOKEN_POINT_RE: RegExp;
+ const HTTP_TAB_OR_SPACE_PREFIX_RE: RegExp;
+ const HTTP_TAB_OR_SPACE_SUFFIX_RE: RegExp;
+ const HTTP_WHITESPACE_PREFIX_RE: RegExp;
+ const HTTP_WHITESPACE_SUFFIX_RE: RegExp;
+ function httpTrim(s: string): string;
+ function regexMatcher(chars: string[]): string;
+ function byteUpperCase(s: string): string;
+ function byteLowerCase(s: string): string;
+ function collectHttpQuotedString(
+ input: string,
+ position: number,
+ extractValue: boolean,
+ ): {
+ result: string;
+ position: number;
+ };
+ function forgivingBase64Encode(data: Uint8Array): string;
+ function forgivingBase64Decode(data: string): Uint8Array;
+ function serializeJSValueToJSONString(value: unknown): string;
+}
- declare namespace mimesniff {
- declare interface MimeType {
- type: string;
- subtype: string;
- parameters: Map<string, string>;
- }
- declare function parseMimeType(input: string): MimeType | null;
- declare function essence(mimeType: MimeType): string;
- declare function serializeMimeType(mimeType: MimeType): string;
- declare function extractMimeType(
- headerValues: string[] | null,
- ): MimeType | null;
- }
+declare module "internal:ext/web/01_dom_exception.js" {
+ export = DOMException;
+}
- declare var eventTarget: {
- EventTarget: typeof EventTarget;
- };
+declare module "internal:ext/web/01_mimesniff.js" {
+ interface MimeType {
+ type: string;
+ subtype: string;
+ parameters: Map<string, string>;
+ }
+ function parseMimeType(input: string): MimeType | null;
+ function essence(mimeType: MimeType): string;
+ function serializeMimeType(mimeType: MimeType): string;
+ function extractMimeType(
+ headerValues: string[] | null,
+ ): MimeType | null;
+}
- declare var event: {
- Event: typeof event;
- ErrorEvent: typeof ErrorEvent;
- CloseEvent: typeof CloseEvent;
- MessageEvent: typeof MessageEvent;
- CustomEvent: typeof CustomEvent;
- ProgressEvent: typeof ProgressEvent;
- PromiseRejectionEvent: typeof PromiseRejectionEvent;
- reportError: typeof reportError;
- };
+declare module "internal:ext/web/02_event.js" {
+ const EventTarget: typeof EventTarget;
+ const Event: typeof event;
+ const ErrorEvent: typeof ErrorEvent;
+ const CloseEvent: typeof CloseEvent;
+ const MessageEvent: typeof MessageEvent;
+ const CustomEvent: typeof CustomEvent;
+ const ProgressEvent: typeof ProgressEvent;
+ const PromiseRejectionEvent: typeof PromiseRejectionEvent;
+ const reportError: typeof reportError;
+}
- declare var location: {
- getLocationHref(): string | undefined;
- };
+declare module "internal:ext/web/12_location.js" {
+ function getLocationHref(): string | undefined;
+}
- declare var base64: {
- atob(data: string): string;
- btoa(data: string): string;
- };
+declare module "internal:ext/web/05_base64.js" {
+ function atob(data: string): string;
+ function btoa(data: string): string;
+}
- declare var file: {
- blobFromObjectUrl(url: string): Blob | null;
- getParts(blob: Blob): string[];
- Blob: typeof Blob;
- File: typeof File;
- };
+declare module "internal:ext/web/09_file.js" {
+ function blobFromObjectUrl(url: string): Blob | null;
+ function getParts(blob: Blob): string[];
+ const Blob: typeof Blob;
+ const File: typeof File;
+}
- declare var streams: {
- ReadableStream: typeof ReadableStream;
- isReadableStreamDisturbed(stream: ReadableStream): boolean;
- createProxy<T>(stream: ReadableStream<T>): ReadableStream<T>;
- };
+declare module "internal:ext/web/06_streams.js" {
+ const ReadableStream: typeof ReadableStream;
+ function isReadableStreamDisturbed(stream: ReadableStream): boolean;
+ function createProxy<T>(stream: ReadableStream<T>): ReadableStream<T>;
+}
- declare namespace messagePort {
- declare type Transferable = {
- kind: "messagePort";
- data: number;
- } | {
- kind: "arrayBuffer";
- data: number;
- };
- declare interface MessageData {
- data: Uint8Array;
- transferables: Transferable[];
- }
- }
+declare module "internal:ext/web/13_message_port.js" {
+ type Transferable = {
+ kind: "messagePort";
+ data: number;
+ } | {
+ kind: "arrayBuffer";
+ data: number;
+ };
+ interface MessageData {
+ data: Uint8Array;
+ transferables: Transferable[];
}
}
diff --git a/ext/web/lib.rs b/ext/web/lib.rs
index c677bb8e9..4fcc06ef4 100644
--- a/ext/web/lib.rs
+++ b/ext/web/lib.rs
@@ -64,7 +64,7 @@ pub fn init<P: TimersPermission + 'static>(
) -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_webidl", "deno_console", "deno_url"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/web",
"00_infra.js",
"01_dom_exception.js",
diff --git a/ext/webgpu/src/01_webgpu.js b/ext/webgpu/src/01_webgpu.js
index 23e8b24f0..58b713099 100644
--- a/ext/webgpu/src/01_webgpu.js
+++ b/ext/webgpu/src/01_webgpu.js
@@ -6,5260 +6,5241 @@
/// <reference path="../web/lib.deno_web.d.ts" />
/// <reference path="./lib.deno_webgpu.d.ts" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const eventTarget = window.__bootstrap.eventTarget;
- const { DOMException } = window.__bootstrap.domException;
- const {
- ArrayBuffer,
- ArrayBufferIsView,
- ArrayIsArray,
- ArrayPrototypeFilter,
- ArrayPrototypeMap,
- ArrayPrototypePop,
- ArrayPrototypePush,
- Error,
- MathMax,
- ObjectDefineProperty,
- ObjectPrototypeIsPrototypeOf,
- Promise,
- PromisePrototypeCatch,
- PromisePrototypeThen,
- PromiseReject,
- PromiseResolve,
- SafeArrayIterator,
- SafePromiseAll,
- Set,
- SetPrototypeHas,
- Symbol,
- SymbolFor,
- TypeError,
- Uint32Array,
- Uint32ArrayPrototype,
- Uint8Array,
- WeakRef,
- } = window.__bootstrap.primordials;
-
- const _rid = Symbol("[[rid]]");
- const _size = Symbol("[[size]]");
- const _usage = Symbol("[[usage]]");
- const _state = Symbol("[[state]]");
- const _mappingRange = Symbol("[[mapping_range]]");
- const _mappedRanges = Symbol("[[mapped_ranges]]");
- const _mapMode = Symbol("[[map_mode]]");
- const _adapter = Symbol("[[adapter]]");
- const _cleanup = Symbol("[[cleanup]]");
- const _vendor = Symbol("[[vendor]]");
- const _architecture = Symbol("[[architecture]]");
- const _description = Symbol("[[description]]");
- const _limits = Symbol("[[limits]]");
- const _reason = Symbol("[[reason]]");
- const _message = Symbol("[[message]]");
- const _label = Symbol("[[label]]");
- const _device = Symbol("[[device]]");
- const _queue = Symbol("[[queue]]");
- const _views = Symbol("[[views]]");
- const _texture = Symbol("[[texture]]");
- const _encoders = Symbol("[[encoders]]");
- const _encoder = Symbol("[[encoder]]");
- const _descriptor = Symbol("[[descriptor]]");
- const _width = Symbol("[[width]]");
- const _height = Symbol("[[height]]");
- const _depthOrArrayLayers = Symbol("[[depthOrArrayLayers]]");
- const _mipLevelCount = Symbol("[[mipLevelCount]]");
- const _sampleCount = Symbol("[[sampleCount]]");
- const _dimension = Symbol("[[dimension]]");
- const _format = Symbol("[[format]]");
- const _type = Symbol("[[type]]");
- const _count = Symbol("[[count]]");
+const core = globalThis.Deno.core;
+const ops = core.ops;
+const primordials = globalThis.__bootstrap.primordials;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { EventTarget } from "internal:ext/web/02_event.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+const {
+ ArrayBuffer,
+ ArrayBufferIsView,
+ ArrayIsArray,
+ ArrayPrototypeFilter,
+ ArrayPrototypeMap,
+ ArrayPrototypePop,
+ ArrayPrototypePush,
+ Error,
+ MathMax,
+ ObjectDefineProperty,
+ ObjectPrototypeIsPrototypeOf,
+ Promise,
+ PromisePrototypeCatch,
+ PromisePrototypeThen,
+ PromiseReject,
+ PromiseResolve,
+ SafeArrayIterator,
+ SafePromiseAll,
+ Set,
+ SetPrototypeHas,
+ Symbol,
+ SymbolFor,
+ TypeError,
+ Uint32Array,
+ Uint32ArrayPrototype,
+ Uint8Array,
+ WeakRef,
+} = primordials;
+
+const _rid = Symbol("[[rid]]");
+const _size = Symbol("[[size]]");
+const _usage = Symbol("[[usage]]");
+const _state = Symbol("[[state]]");
+const _mappingRange = Symbol("[[mapping_range]]");
+const _mappedRanges = Symbol("[[mapped_ranges]]");
+const _mapMode = Symbol("[[map_mode]]");
+const _adapter = Symbol("[[adapter]]");
+const _cleanup = Symbol("[[cleanup]]");
+const _vendor = Symbol("[[vendor]]");
+const _architecture = Symbol("[[architecture]]");
+const _description = Symbol("[[description]]");
+const _limits = Symbol("[[limits]]");
+const _reason = Symbol("[[reason]]");
+const _message = Symbol("[[message]]");
+const _label = Symbol("[[label]]");
+const _device = Symbol("[[device]]");
+const _queue = Symbol("[[queue]]");
+const _views = Symbol("[[views]]");
+const _texture = Symbol("[[texture]]");
+const _encoders = Symbol("[[encoders]]");
+const _encoder = Symbol("[[encoder]]");
+const _descriptor = Symbol("[[descriptor]]");
+const _width = Symbol("[[width]]");
+const _height = Symbol("[[height]]");
+const _depthOrArrayLayers = Symbol("[[depthOrArrayLayers]]");
+const _mipLevelCount = Symbol("[[mipLevelCount]]");
+const _sampleCount = Symbol("[[sampleCount]]");
+const _dimension = Symbol("[[dimension]]");
+const _format = Symbol("[[format]]");
+const _type = Symbol("[[type]]");
+const _count = Symbol("[[count]]");
+
+/**
+ * @param {any} self
+ * @param {{prefix: string, context: string}} opts
+ * @returns {InnerGPUDevice & {rid: number}}
+ */
+function assertDevice(self, { prefix, context }) {
+ const device = self[_device];
+ const deviceRid = device?.rid;
+ if (deviceRid === undefined) {
+ throw new DOMException(
+ `${prefix}: ${context} references an invalid or destroyed device.`,
+ "OperationError",
+ );
+ }
+ return device;
+}
+
+/**
+ * @param {InnerGPUDevice} self
+ * @param {any} resource
+ * @param {{prefix: string, resourceContext: string, selfContext: string}} opts
+ * @returns {InnerGPUDevice & {rid: number}}
+ */
+function assertDeviceMatch(
+ self,
+ resource,
+ { prefix, resourceContext, selfContext },
+) {
+ const resourceDevice = assertDevice(resource, {
+ prefix,
+ context: resourceContext,
+ });
+ if (resourceDevice.rid !== self.rid) {
+ throw new DOMException(
+ `${prefix}: ${resourceContext} belongs to a diffent device than ${selfContext}.`,
+ "OperationError",
+ );
+ }
+ return { ...resourceDevice, rid: resourceDevice.rid };
+}
+
+/**
+ * @param {any} self
+ * @param {{prefix: string, context: string}} opts
+ * @returns {number}
+ */
+function assertResource(self, { prefix, context }) {
+ const rid = self[_rid];
+ if (rid === undefined) {
+ throw new DOMException(
+ `${prefix}: ${context} an invalid or destroyed resource.`,
+ "OperationError",
+ );
+ }
+ return rid;
+}
+
+/**
+ * @param {number[] | GPUExtent3DDict} data
+ * @returns {GPUExtent3DDict}
+ */
+function normalizeGPUExtent3D(data) {
+ if (ArrayIsArray(data)) {
+ return {
+ width: data[0],
+ height: data[1],
+ depthOrArrayLayers: data[2],
+ };
+ } else {
+ return data;
+ }
+}
+
+/**
+ * @param {number[] | GPUOrigin3DDict} data
+ * @returns {GPUOrigin3DDict}
+ */
+function normalizeGPUOrigin3D(data) {
+ if (ArrayIsArray(data)) {
+ return {
+ x: data[0],
+ y: data[1],
+ z: data[2],
+ };
+ } else {
+ return data;
+ }
+}
+
+/**
+ * @param {number[] | GPUColor} data
+ * @returns {GPUColor}
+ */
+function normalizeGPUColor(data) {
+ if (ArrayIsArray(data)) {
+ return {
+ r: data[0],
+ g: data[1],
+ b: data[2],
+ a: data[3],
+ };
+ } else {
+ return data;
+ }
+}
- /**
- * @param {any} self
- * @param {{prefix: string, context: string}} opts
- * @returns {InnerGPUDevice & {rid: number}}
- */
- function assertDevice(self, { prefix, context }) {
- const device = self[_device];
- const deviceRid = device?.rid;
- if (deviceRid === undefined) {
- throw new DOMException(
- `${prefix}: ${context} references an invalid or destroyed device.`,
- "OperationError",
- );
+const illegalConstructorKey = Symbol("illegalConstructorKey");
+class GPUError extends Error {
+ constructor(key = null) {
+ super();
+ if (key !== illegalConstructorKey) {
+ webidl.illegalConstructor();
}
- return device;
}
- /**
- * @param {InnerGPUDevice} self
- * @param {any} resource
- * @param {{prefix: string, resourceContext: string, selfContext: string}} opts
- * @returns {InnerGPUDevice & {rid: number}}
- */
- function assertDeviceMatch(
- self,
- resource,
- { prefix, resourceContext, selfContext },
- ) {
- const resourceDevice = assertDevice(resource, {
+ [_message];
+ get message() {
+ webidl.assertBranded(this, GPUErrorPrototype);
+ return this[_message];
+ }
+}
+const GPUErrorPrototype = GPUError.prototype;
+
+class GPUValidationError extends GPUError {
+ name = "GPUValidationError";
+ /** @param {string} message */
+ constructor(message) {
+ const prefix = "Failed to construct 'GPUValidationError'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ message = webidl.converters.DOMString(message, {
prefix,
- context: resourceContext,
+ context: "Argument 1",
});
- if (resourceDevice.rid !== self.rid) {
- throw new DOMException(
- `${prefix}: ${resourceContext} belongs to a diffent device than ${selfContext}.`,
- "OperationError",
- );
- }
- return { ...resourceDevice, rid: resourceDevice.rid };
+ super(illegalConstructorKey);
+ this[webidl.brand] = webidl.brand;
+ this[_message] = message;
+ }
+}
+const GPUValidationErrorPrototype = GPUValidationError.prototype;
+
+class GPUOutOfMemoryError extends GPUError {
+ name = "GPUOutOfMemoryError";
+ constructor(message) {
+ const prefix = "Failed to construct 'GPUOutOfMemoryError'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ message = webidl.converters.DOMString(message, {
+ prefix,
+ context: "Argument 1",
+ });
+ super(illegalConstructorKey);
+ this[webidl.brand] = webidl.brand;
+ this[_message] = message;
}
+}
+const GPUOutOfMemoryErrorPrototype = GPUOutOfMemoryError.prototype;
- /**
- * @param {any} self
- * @param {{prefix: string, context: string}} opts
- * @returns {number}
- */
- function assertResource(self, { prefix, context }) {
- const rid = self[_rid];
- if (rid === undefined) {
- throw new DOMException(
- `${prefix}: ${context} an invalid or destroyed resource.`,
- "OperationError",
- );
- }
- return rid;
+class GPU {
+ [webidl.brand] = webidl.brand;
+
+ constructor() {
+ webidl.illegalConstructor();
}
/**
- * @param {number[] | GPUExtent3DDict} data
- * @returns {GPUExtent3DDict}
+ * @param {GPURequestAdapterOptions} options
*/
- function normalizeGPUExtent3D(data) {
- if (ArrayIsArray(data)) {
- return {
- width: data[0],
- height: data[1],
- depthOrArrayLayers: data[2],
- };
+ async requestAdapter(options = {}) {
+ webidl.assertBranded(this, GPUPrototype);
+ options = webidl.converters.GPURequestAdapterOptions(options, {
+ prefix: "Failed to execute 'requestAdapter' on 'GPU'",
+ context: "Argument 1",
+ });
+
+ const { err, ...data } = await core.opAsync(
+ "op_webgpu_request_adapter",
+ options.powerPreference,
+ options.forceFallbackAdapter,
+ );
+
+ if (err) {
+ return null;
} else {
- return data;
+ return createGPUAdapter(data);
}
}
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${inspect({})}`;
+ }
+}
+const GPUPrototype = GPU.prototype;
+
+/**
+ * @typedef InnerGPUAdapter
+ * @property {number} rid
+ * @property {GPUSupportedFeatures} features
+ * @property {GPUSupportedLimits} limits
+ * @property {boolean} isFallbackAdapter
+ */
+
+/**
+ * @param {InnerGPUAdapter} inner
+ * @returns {GPUAdapter}
+ */
+function createGPUAdapter(inner) {
+ /** @type {GPUAdapter} */
+ const adapter = webidl.createBranded(GPUAdapter);
+ adapter[_adapter] = {
+ ...inner,
+ features: createGPUSupportedFeatures(inner.features),
+ limits: createGPUSupportedLimits(inner.limits),
+ };
+ return adapter;
+}
+
+class GPUAdapter {
+ /** @type {InnerGPUAdapter} */
+ [_adapter];
+
+ /** @returns {GPUSupportedFeatures} */
+ get features() {
+ webidl.assertBranded(this, GPUAdapterPrototype);
+ return this[_adapter].features;
+ }
+ /** @returns {GPUSupportedLimits} */
+ get limits() {
+ webidl.assertBranded(this, GPUAdapterPrototype);
+ return this[_adapter].limits;
+ }
+ /** @returns {boolean} */
+ get isFallbackAdapter() {
+ return this[_adapter].isFallbackAdapter;
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
/**
- * @param {number[] | GPUOrigin3DDict} data
- * @returns {GPUOrigin3DDict}
+ * @param {GPUDeviceDescriptor} descriptor
+ * @returns {Promise<GPUDevice>}
*/
- function normalizeGPUOrigin3D(data) {
- if (ArrayIsArray(data)) {
- return {
- x: data[0],
- y: data[1],
- z: data[2],
- };
- } else {
- return data;
+ async requestDevice(descriptor = {}) {
+ webidl.assertBranded(this, GPUAdapterPrototype);
+ const prefix = "Failed to execute 'requestDevice' on 'GPUAdapter'";
+ descriptor = webidl.converters.GPUDeviceDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const requiredFeatures = descriptor.requiredFeatures ?? [];
+ for (let i = 0; i < requiredFeatures.length; ++i) {
+ const feature = requiredFeatures[i];
+ if (
+ !SetPrototypeHas(
+ this[_adapter].features[webidl.setlikeInner],
+ feature,
+ )
+ ) {
+ throw new TypeError(
+ `${prefix}: requiredFeatures must be a subset of the adapter features.`,
+ );
+ }
}
+
+ const { rid, features, limits } = await core.opAsync(
+ "op_webgpu_request_device",
+ this[_adapter].rid,
+ descriptor.label,
+ requiredFeatures,
+ descriptor.requiredLimits,
+ );
+
+ const inner = new InnerGPUDevice({
+ rid,
+ adapter: this,
+ features: createGPUSupportedFeatures(features),
+ limits: createGPUSupportedLimits(limits),
+ });
+ return createGPUDevice(
+ descriptor.label,
+ inner,
+ createGPUQueue(descriptor.label, inner),
+ );
}
/**
- * @param {number[] | GPUColor} data
- * @returns {GPUColor}
+ * @param {string[]} unmaskHints
+ * @returns {Promise<GPUAdapterInfo>}
*/
- function normalizeGPUColor(data) {
- if (ArrayIsArray(data)) {
- return {
- r: data[0],
- g: data[1],
- b: data[2],
- a: data[3],
- };
- } else {
- return data;
- }
- }
+ async requestAdapterInfo(unmaskHints = []) {
+ webidl.assertBranded(this, GPUAdapterPrototype);
+ const prefix = "Failed to execute 'requestAdapterInfo' on 'GPUAdapter'";
+ unmaskHints = webidl.converters["sequence<DOMString>"](unmaskHints, {
+ prefix,
+ context: "Argument 1",
+ });
- const illegalConstructorKey = Symbol("illegalConstructorKey");
- class GPUError extends Error {
- constructor(key = null) {
- super();
- if (key !== illegalConstructorKey) {
- webidl.illegalConstructor();
- }
- }
+ const {
+ vendor,
+ architecture,
+ device,
+ description,
+ } = await core.opAsync(
+ "op_webgpu_request_adapter_info",
+ this[_adapter].rid,
+ );
- [_message];
- get message() {
- webidl.assertBranded(this, GPUErrorPrototype);
- return this[_message];
- }
+ const adapterInfo = webidl.createBranded(GPUAdapterInfo);
+ adapterInfo[_vendor] = unmaskHints.includes("vendor") ? vendor : "";
+ adapterInfo[_architecture] = unmaskHints.includes("architecture")
+ ? architecture
+ : "";
+ adapterInfo[_device] = unmaskHints.includes("device") ? device : "";
+ adapterInfo[_description] = unmaskHints.includes("description")
+ ? description
+ : "";
+ return adapterInfo;
}
- const GPUErrorPrototype = GPUError.prototype;
- class GPUValidationError extends GPUError {
- name = "GPUValidationError";
- /** @param {string} message */
- constructor(message) {
- const prefix = "Failed to construct 'GPUValidationError'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- message = webidl.converters.DOMString(message, {
- prefix,
- context: "Argument 1",
- });
- super(illegalConstructorKey);
- this[webidl.brand] = webidl.brand;
- this[_message] = message;
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ features: this.features,
+ limits: this.limits,
+ })
+ }`;
}
- const GPUValidationErrorPrototype = GPUValidationError.prototype;
-
- class GPUOutOfMemoryError extends GPUError {
- name = "GPUOutOfMemoryError";
- constructor(message) {
- const prefix = "Failed to construct 'GPUOutOfMemoryError'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- message = webidl.converters.DOMString(message, {
- prefix,
- context: "Argument 1",
- });
- super(illegalConstructorKey);
- this[webidl.brand] = webidl.brand;
- this[_message] = message;
- }
+}
+const GPUAdapterPrototype = GPUAdapter.prototype;
+
+class GPUAdapterInfo {
+ /** @type {string} */
+ [_vendor];
+ /** @returns {string} */
+ get vendor() {
+ webidl.assertBranded(this, GPUAdapterInfoPrototype);
+ return this[_vendor];
}
- const GPUOutOfMemoryErrorPrototype = GPUOutOfMemoryError.prototype;
- class GPU {
- [webidl.brand] = webidl.brand;
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- /**
- * @param {GPURequestAdapterOptions} options
- */
- async requestAdapter(options = {}) {
- webidl.assertBranded(this, GPUPrototype);
- options = webidl.converters.GPURequestAdapterOptions(options, {
- prefix: "Failed to execute 'requestAdapter' on 'GPU'",
- context: "Argument 1",
- });
+ /** @type {string} */
+ [_architecture];
+ /** @returns {string} */
+ get architecture() {
+ webidl.assertBranded(this, GPUAdapterInfoPrototype);
+ return this[_architecture];
+ }
- const { err, ...data } = await core.opAsync(
- "op_webgpu_request_adapter",
- options.powerPreference,
- options.forceFallbackAdapter,
- );
+ /** @type {string} */
+ [_device];
+ /** @returns {string} */
+ get device() {
+ webidl.assertBranded(this, GPUAdapterInfoPrototype);
+ return this[_device];
+ }
- if (err) {
- return null;
- } else {
- return createGPUAdapter(data);
- }
- }
+ /** @type {string} */
+ [_description];
+ /** @returns {string} */
+ get description() {
+ webidl.assertBranded(this, GPUAdapterInfoPrototype);
+ return this[_description];
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${inspect({})}`;
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ vendor: this.vendor,
+ architecture: this.architecture,
+ device: this.device,
+ description: this.description,
+ })
+ }`;
+ }
+}
+const GPUAdapterInfoPrototype = GPUAdapterInfo.prototype;
+
+function createGPUSupportedLimits(limits) {
+ /** @type {GPUSupportedLimits} */
+ const adapterFeatures = webidl.createBranded(GPUSupportedLimits);
+ adapterFeatures[_limits] = limits;
+ return adapterFeatures;
+}
+
+/**
+ * @typedef InnerAdapterLimits
+ * @property {number} maxTextureDimension1D
+ * @property {number} maxTextureDimension2D
+ * @property {number} maxTextureDimension3D
+ * @property {number} maxTextureArrayLayers
+ * @property {number} maxBindGroups
+ * @property {number} maxDynamicUniformBuffersPerPipelineLayout
+ * @property {number} maxDynamicStorageBuffersPerPipelineLayout
+ * @property {number} maxSampledTexturesPerShaderStage
+ * @property {number} maxSamplersPerShaderStage
+ * @property {number} maxStorageBuffersPerShaderStage
+ * @property {number} maxStorageTexturesPerShaderStage
+ * @property {number} maxUniformBuffersPerShaderStage
+ * @property {number} maxUniformBufferBindingSize
+ * @property {number} maxStorageBufferBindingSize
+ * @property {number} minUniformBufferOffsetAlignment
+ * @property {number} minStorageBufferOffsetAlignment
+ * @property {number} maxVertexBuffers
+ * @property {number} maxVertexAttributes
+ * @property {number} maxVertexBufferArrayStride
+ * @property {number} maxInterStageShaderComponents
+ * @property {number} maxComputeWorkgroupStorageSize
+ * @property {number} maxComputeInvocationsPerWorkgroup
+ * @property {number} maxComputeWorkgroupSizeX
+ * @property {number} maxComputeWorkgroupSizeY
+ * @property {number} maxComputeWorkgroupSizeZ
+ * @property {number} maxComputeWorkgroupsPerDimension
+ */
+
+class GPUSupportedLimits {
+ /** @type {InnerAdapterLimits} */
+ [_limits];
+ constructor() {
+ webidl.illegalConstructor();
}
- const GPUPrototype = GPU.prototype;
- /**
- * @typedef InnerGPUAdapter
- * @property {number} rid
- * @property {GPUSupportedFeatures} features
- * @property {GPUSupportedLimits} limits
- * @property {boolean} isFallbackAdapter
- */
+ get maxTextureDimension1D() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxTextureDimension1D;
+ }
+ get maxTextureDimension2D() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxTextureDimension2D;
+ }
+ get maxTextureDimension3D() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxTextureDimension3D;
+ }
+ get maxTextureArrayLayers() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxTextureArrayLayers;
+ }
+ get maxBindGroups() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxBindGroups;
+ }
+ get maxBindingsPerBindGroup() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxBindingsPerBindGroup;
+ }
+ get maxBufferSize() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxBufferSize;
+ }
+ get maxDynamicUniformBuffersPerPipelineLayout() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxDynamicUniformBuffersPerPipelineLayout;
+ }
+ get maxDynamicStorageBuffersPerPipelineLayout() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxDynamicStorageBuffersPerPipelineLayout;
+ }
+ get maxSampledTexturesPerShaderStage() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxSampledTexturesPerShaderStage;
+ }
+ get maxSamplersPerShaderStage() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxSamplersPerShaderStage;
+ }
+ get maxStorageBuffersPerShaderStage() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxStorageBuffersPerShaderStage;
+ }
+ get maxStorageTexturesPerShaderStage() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxStorageTexturesPerShaderStage;
+ }
+ get maxUniformBuffersPerShaderStage() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxUniformBuffersPerShaderStage;
+ }
+ get maxUniformBufferBindingSize() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxUniformBufferBindingSize;
+ }
+ get maxStorageBufferBindingSize() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxStorageBufferBindingSize;
+ }
+ get minUniformBufferOffsetAlignment() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].minUniformBufferOffsetAlignment;
+ }
+ get minStorageBufferOffsetAlignment() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].minStorageBufferOffsetAlignment;
+ }
+ get maxVertexBuffers() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxVertexBuffers;
+ }
+ get maxVertexAttributes() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxVertexAttributes;
+ }
+ get maxVertexBufferArrayStride() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxVertexBufferArrayStride;
+ }
+ get maxInterStageShaderComponents() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxInterStageShaderComponents;
+ }
+ get maxComputeWorkgroupStorageSize() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxComputeWorkgroupStorageSize;
+ }
+ get maxComputeInvocationsPerWorkgroup() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxComputeInvocationsPerWorkgroup;
+ }
+ get maxComputeWorkgroupSizeX() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxComputeWorkgroupSizeX;
+ }
+ get maxComputeWorkgroupSizeY() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxComputeWorkgroupSizeY;
+ }
+ get maxComputeWorkgroupSizeZ() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxComputeWorkgroupSizeZ;
+ }
+ get maxComputeWorkgroupsPerDimension() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxComputeWorkgroupsPerDimension;
+ }
- /**
- * @param {InnerGPUAdapter} inner
- * @returns {GPUAdapter}
- */
- function createGPUAdapter(inner) {
- /** @type {GPUAdapter} */
- const adapter = webidl.createBranded(GPUAdapter);
- adapter[_adapter] = {
- ...inner,
- features: createGPUSupportedFeatures(inner.features),
- limits: createGPUSupportedLimits(inner.limits),
- };
- return adapter;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${inspect(this[_limits])}`;
+ }
+}
+const GPUSupportedLimitsPrototype = GPUSupportedLimits.prototype;
+
+function createGPUSupportedFeatures(features) {
+ /** @type {GPUSupportedFeatures} */
+ const supportedFeatures = webidl.createBranded(GPUSupportedFeatures);
+ supportedFeatures[webidl.setlikeInner] = new Set(features);
+ return webidl.setlike(
+ supportedFeatures,
+ GPUSupportedFeaturesPrototype,
+ true,
+ );
+}
+
+class GPUSupportedFeatures {
+ constructor() {
+ webidl.illegalConstructor();
+ }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect([...new SafeArrayIterator(this.values())])
+ }`;
+ }
+}
+
+const GPUSupportedFeaturesPrototype = GPUSupportedFeatures.prototype;
+
+/**
+ * @param {string | undefined} reason
+ * @param {string} message
+ * @returns {GPUDeviceLostInfo}
+ */
+function createGPUDeviceLostInfo(reason, message) {
+ /** @type {GPUDeviceLostInfo} */
+ const deviceLostInfo = webidl.createBranded(GPUDeviceLostInfo);
+ deviceLostInfo[_reason] = reason;
+ deviceLostInfo[_message] = message;
+ return deviceLostInfo;
+}
+
+class GPUDeviceLostInfo {
+ /** @type {string | undefined} */
+ [_reason];
+ /** @type {string} */
+ [_message];
+
+ constructor() {
+ webidl.illegalConstructor();
}
- class GPUAdapter {
- /** @type {InnerGPUAdapter} */
- [_adapter];
+ get reason() {
+ webidl.assertBranded(this, GPUDeviceLostInfoPrototype);
+ return this[_reason];
+ }
+ get message() {
+ webidl.assertBranded(this, GPUDeviceLostInfoPrototype);
+ return this[_message];
+ }
- /** @returns {GPUSupportedFeatures} */
- get features() {
- webidl.assertBranded(this, GPUAdapterPrototype);
- return this[_adapter].features;
- }
- /** @returns {GPUSupportedLimits} */
- get limits() {
- webidl.assertBranded(this, GPUAdapterPrototype);
- return this[_adapter].limits;
- }
- /** @returns {boolean} */
- get isFallbackAdapter() {
- return this[_adapter].isFallbackAdapter;
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({ reason: this[_reason], message: this[_message] })
+ }`;
+ }
+}
- constructor() {
- webidl.illegalConstructor();
- }
+const GPUDeviceLostInfoPrototype = GPUDeviceLostInfo.prototype;
+/**
+ * @param {string} name
+ * @param {any} type
+ */
+function GPUObjectBaseMixin(name, type) {
+ type.prototype[_label] = null;
+ ObjectDefineProperty(type.prototype, "label", {
/**
- * @param {GPUDeviceDescriptor} descriptor
- * @returns {Promise<GPUDevice>}
+ * @return {string | null}
*/
- async requestDevice(descriptor = {}) {
- webidl.assertBranded(this, GPUAdapterPrototype);
- const prefix = "Failed to execute 'requestDevice' on 'GPUAdapter'";
- descriptor = webidl.converters.GPUDeviceDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const requiredFeatures = descriptor.requiredFeatures ?? [];
- for (let i = 0; i < requiredFeatures.length; ++i) {
- const feature = requiredFeatures[i];
- if (
- !SetPrototypeHas(
- this[_adapter].features[webidl.setlikeInner],
- feature,
- )
- ) {
- throw new TypeError(
- `${prefix}: requiredFeatures must be a subset of the adapter features.`,
- );
- }
- }
-
- const { rid, features, limits } = await core.opAsync(
- "op_webgpu_request_device",
- this[_adapter].rid,
- descriptor.label,
- requiredFeatures,
- descriptor.requiredLimits,
- );
-
- const inner = new InnerGPUDevice({
- rid,
- adapter: this,
- features: createGPUSupportedFeatures(features),
- limits: createGPUSupportedLimits(limits),
- });
- return createGPUDevice(
- descriptor.label,
- inner,
- createGPUQueue(descriptor.label, inner),
- );
- }
-
+ get() {
+ webidl.assertBranded(this, type.prototype);
+ return this[_label];
+ },
/**
- * @param {string[]} unmaskHints
- * @returns {Promise<GPUAdapterInfo>}
+ * @param {string | null} label
*/
- async requestAdapterInfo(unmaskHints = []) {
- webidl.assertBranded(this, GPUAdapterPrototype);
- const prefix = "Failed to execute 'requestAdapterInfo' on 'GPUAdapter'";
- unmaskHints = webidl.converters["sequence<DOMString>"](unmaskHints, {
- prefix,
+ set(label) {
+ webidl.assertBranded(this, type.prototype);
+ label = webidl.converters["UVString?"](label, {
+ prefix: `Failed to set 'label' on '${name}'`,
context: "Argument 1",
});
+ this[_label] = label;
+ },
+ });
+}
+
+/**
+ * @typedef ErrorScope
+ * @property {string} filter
+ * @property {Promise<void>[]} operations
+ */
+
+/**
+ * @typedef InnerGPUDeviceOptions
+ * @property {GPUAdapter} adapter
+ * @property {number | undefined} rid
+ * @property {GPUSupportedFeatures} features
+ * @property {GPUSupportedLimits} limits
+ */
+
+class InnerGPUDevice {
+ /** @type {GPUAdapter} */
+ adapter;
+ /** @type {number | undefined} */
+ rid;
+ /** @type {GPUSupportedFeatures} */
+ features;
+ /** @type {GPUSupportedLimits} */
+ limits;
+ /** @type {WeakRef<any>[]} */
+ resources;
+ /** @type {boolean} */
+ isLost;
+ /** @type {Promise<GPUDeviceLostInfo>} */
+ lost;
+ /** @type {(info: GPUDeviceLostInfo) => void} */
+ resolveLost;
+ /** @type {ErrorScope[]} */
+ errorScopeStack;
- const {
- vendor,
- architecture,
- device,
- description,
- } = await core.opAsync(
- "op_webgpu_request_adapter_info",
- this[_adapter].rid,
- );
-
- const adapterInfo = webidl.createBranded(GPUAdapterInfo);
- adapterInfo[_vendor] = unmaskHints.includes("vendor") ? vendor : "";
- adapterInfo[_architecture] = unmaskHints.includes("architecture")
- ? architecture
- : "";
- adapterInfo[_device] = unmaskHints.includes("device") ? device : "";
- adapterInfo[_description] = unmaskHints.includes("description")
- ? description
- : "";
- return adapterInfo;
- }
-
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- features: this.features,
- limits: this.limits,
- })
- }`;
- }
+ /**
+ * @param {InnerGPUDeviceOptions} options
+ */
+ constructor(options) {
+ this.adapter = options.adapter;
+ this.rid = options.rid;
+ this.features = options.features;
+ this.limits = options.limits;
+ this.resources = [];
+ this.isLost = false;
+ this.resolveLost = () => {};
+ this.lost = new Promise((resolve) => {
+ this.resolveLost = resolve;
+ });
+ this.errorScopeStack = [];
}
- const GPUAdapterPrototype = GPUAdapter.prototype;
-
- class GPUAdapterInfo {
- /** @type {string} */
- [_vendor];
- /** @returns {string} */
- get vendor() {
- webidl.assertBranded(this, GPUAdapterInfoPrototype);
- return this[_vendor];
- }
-
- /** @type {string} */
- [_architecture];
- /** @returns {string} */
- get architecture() {
- webidl.assertBranded(this, GPUAdapterInfoPrototype);
- return this[_architecture];
- }
-
- /** @type {string} */
- [_device];
- /** @returns {string} */
- get device() {
- webidl.assertBranded(this, GPUAdapterInfoPrototype);
- return this[_device];
- }
- /** @type {string} */
- [_description];
- /** @returns {string} */
- get description() {
- webidl.assertBranded(this, GPUAdapterInfoPrototype);
- return this[_description];
- }
-
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- vendor: this.vendor,
- architecture: this.architecture,
- device: this.device,
- description: this.description,
- })
- }`;
- }
+ /** @param {any} resource */
+ trackResource(resource) {
+ ArrayPrototypePush(this.resources, new WeakRef(resource));
}
- const GPUAdapterInfoPrototype = GPUAdapterInfo.prototype;
- function createGPUSupportedLimits(limits) {
- /** @type {GPUSupportedLimits} */
- const adapterFeatures = webidl.createBranded(GPUSupportedLimits);
- adapterFeatures[_limits] = limits;
- return adapterFeatures;
+ /** @param {{ type: string, value: string | null } | undefined} err */
+ pushError(err) {
+ this.pushErrorPromise(PromiseResolve(err));
}
- /**
- * @typedef InnerAdapterLimits
- * @property {number} maxTextureDimension1D
- * @property {number} maxTextureDimension2D
- * @property {number} maxTextureDimension3D
- * @property {number} maxTextureArrayLayers
- * @property {number} maxBindGroups
- * @property {number} maxDynamicUniformBuffersPerPipelineLayout
- * @property {number} maxDynamicStorageBuffersPerPipelineLayout
- * @property {number} maxSampledTexturesPerShaderStage
- * @property {number} maxSamplersPerShaderStage
- * @property {number} maxStorageBuffersPerShaderStage
- * @property {number} maxStorageTexturesPerShaderStage
- * @property {number} maxUniformBuffersPerShaderStage
- * @property {number} maxUniformBufferBindingSize
- * @property {number} maxStorageBufferBindingSize
- * @property {number} minUniformBufferOffsetAlignment
- * @property {number} minStorageBufferOffsetAlignment
- * @property {number} maxVertexBuffers
- * @property {number} maxVertexAttributes
- * @property {number} maxVertexBufferArrayStride
- * @property {number} maxInterStageShaderComponents
- * @property {number} maxComputeWorkgroupStorageSize
- * @property {number} maxComputeInvocationsPerWorkgroup
- * @property {number} maxComputeWorkgroupSizeX
- * @property {number} maxComputeWorkgroupSizeY
- * @property {number} maxComputeWorkgroupSizeZ
- * @property {number} maxComputeWorkgroupsPerDimension
- */
+ /** @param {Promise<{ type: string, value: string | null } | undefined>} promise */
+ pushErrorPromise(promise) {
+ const operation = PromisePrototypeThen(promise, (err) => {
+ if (err) {
+ switch (err.type) {
+ case "lost":
+ this.isLost = true;
+ this.resolveLost(
+ createGPUDeviceLostInfo(undefined, "device was lost"),
+ );
+ break;
+ case "validation":
+ return PromiseReject(
+ new GPUValidationError(err.value ?? "validation error"),
+ );
+ case "out-of-memory":
+ return PromiseReject(new GPUOutOfMemoryError());
+ }
+ }
+ });
- class GPUSupportedLimits {
- /** @type {InnerAdapterLimits} */
- [_limits];
- constructor() {
- webidl.illegalConstructor();
+ const validationStack = ArrayPrototypeFilter(
+ this.errorScopeStack,
+ ({ filter }) => filter == "validation",
+ );
+ const validationScope = validationStack[validationStack.length - 1];
+ const validationFilteredPromise = PromisePrototypeCatch(
+ operation,
+ (err) => {
+ if (ObjectPrototypeIsPrototypeOf(GPUValidationErrorPrototype, err)) {
+ return PromiseReject(err);
+ }
+ return PromiseResolve();
+ },
+ );
+ if (validationScope) {
+ ArrayPrototypePush(
+ validationScope.operations,
+ validationFilteredPromise,
+ );
+ } else {
+ PromisePrototypeCatch(validationFilteredPromise, () => {
+ // TODO(lucacasonato): emit an UncapturedErrorEvent
+ });
}
+ // prevent uncaptured promise rejections
+ PromisePrototypeCatch(validationFilteredPromise, (_err) => {});
- get maxTextureDimension1D() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxTextureDimension1D;
- }
- get maxTextureDimension2D() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxTextureDimension2D;
- }
- get maxTextureDimension3D() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxTextureDimension3D;
- }
- get maxTextureArrayLayers() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxTextureArrayLayers;
- }
- get maxBindGroups() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxBindGroups;
- }
- get maxBindingsPerBindGroup() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxBindingsPerBindGroup;
- }
- get maxBufferSize() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxBufferSize;
- }
- get maxDynamicUniformBuffersPerPipelineLayout() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxDynamicUniformBuffersPerPipelineLayout;
- }
- get maxDynamicStorageBuffersPerPipelineLayout() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxDynamicStorageBuffersPerPipelineLayout;
- }
- get maxSampledTexturesPerShaderStage() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxSampledTexturesPerShaderStage;
- }
- get maxSamplersPerShaderStage() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxSamplersPerShaderStage;
- }
- get maxStorageBuffersPerShaderStage() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxStorageBuffersPerShaderStage;
- }
- get maxStorageTexturesPerShaderStage() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxStorageTexturesPerShaderStage;
- }
- get maxUniformBuffersPerShaderStage() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxUniformBuffersPerShaderStage;
- }
- get maxUniformBufferBindingSize() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxUniformBufferBindingSize;
- }
- get maxStorageBufferBindingSize() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxStorageBufferBindingSize;
- }
- get minUniformBufferOffsetAlignment() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].minUniformBufferOffsetAlignment;
- }
- get minStorageBufferOffsetAlignment() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].minStorageBufferOffsetAlignment;
- }
- get maxVertexBuffers() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxVertexBuffers;
- }
- get maxVertexAttributes() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxVertexAttributes;
- }
- get maxVertexBufferArrayStride() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxVertexBufferArrayStride;
- }
- get maxInterStageShaderComponents() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxInterStageShaderComponents;
- }
- get maxComputeWorkgroupStorageSize() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxComputeWorkgroupStorageSize;
- }
- get maxComputeInvocationsPerWorkgroup() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxComputeInvocationsPerWorkgroup;
- }
- get maxComputeWorkgroupSizeX() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxComputeWorkgroupSizeX;
- }
- get maxComputeWorkgroupSizeY() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxComputeWorkgroupSizeY;
- }
- get maxComputeWorkgroupSizeZ() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxComputeWorkgroupSizeZ;
+ const oomStack = ArrayPrototypeFilter(
+ this.errorScopeStack,
+ ({ filter }) => filter == "out-of-memory",
+ );
+ const oomScope = oomStack[oomStack.length - 1];
+ const oomFilteredPromise = PromisePrototypeCatch(operation, (err) => {
+ if (ObjectPrototypeIsPrototypeOf(GPUOutOfMemoryErrorPrototype, err)) {
+ return PromiseReject(err);
+ }
+ return PromiseResolve();
+ });
+ if (oomScope) {
+ ArrayPrototypePush(oomScope.operations, oomFilteredPromise);
+ } else {
+ PromisePrototypeCatch(oomFilteredPromise, () => {
+ // TODO(lucacasonato): emit an UncapturedErrorEvent
+ });
}
- get maxComputeWorkgroupsPerDimension() {
- webidl.assertBranded(this, GPUSupportedLimitsPrototype);
- return this[_limits].maxComputeWorkgroupsPerDimension;
+ // prevent uncaptured promise rejections
+ PromisePrototypeCatch(oomFilteredPromise, (_err) => {});
+ }
+}
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} inner
+ * @param {GPUQueue} queue
+ * @returns {GPUDevice}
+ */
+function createGPUDevice(label, inner, queue) {
+ /** @type {GPUDevice} */
+ const device = webidl.createBranded(GPUDevice);
+ device[_label] = label;
+ device[_device] = inner;
+ device[_queue] = queue;
+ return device;
+}
+
+class GPUDevice extends EventTarget {
+ /** @type {InnerGPUDevice} */
+ [_device];
+
+ /** @type {GPUQueue} */
+ [_queue];
+
+ [_cleanup]() {
+ const device = this[_device];
+ const resources = device.resources;
+ while (resources.length > 0) {
+ const resource = ArrayPrototypePop(resources)?.deref();
+ if (resource) {
+ resource[_cleanup]();
+ }
}
-
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${inspect(this[_limits])}`;
+ const rid = device.rid;
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ device.rid = undefined;
}
}
- const GPUSupportedLimitsPrototype = GPUSupportedLimits.prototype;
- function createGPUSupportedFeatures(features) {
- /** @type {GPUSupportedFeatures} */
- const supportedFeatures = webidl.createBranded(GPUSupportedFeatures);
- supportedFeatures[webidl.setlikeInner] = new Set(features);
- return webidl.setlike(
- supportedFeatures,
- GPUSupportedFeaturesPrototype,
- true,
- );
+ get features() {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ return this[_device].features;
+ }
+ get limits() {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ return this[_device].limits;
+ }
+ get queue() {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ return this[_queue];
}
- class GPUSupportedFeatures {
- constructor() {
- webidl.illegalConstructor();
- }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect([...new SafeArrayIterator(this.values())])
- }`;
- }
+ constructor() {
+ webidl.illegalConstructor();
+ super();
}
- const GPUSupportedFeaturesPrototype = GPUSupportedFeatures.prototype;
+ destroy() {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ this[_cleanup]();
+ }
/**
- * @param {string | undefined} reason
- * @param {string} message
- * @returns {GPUDeviceLostInfo}
+ * @param {GPUBufferDescriptor} descriptor
+ * @returns {GPUBuffer}
*/
- function createGPUDeviceLostInfo(reason, message) {
- /** @type {GPUDeviceLostInfo} */
- const deviceLostInfo = webidl.createBranded(GPUDeviceLostInfo);
- deviceLostInfo[_reason] = reason;
- deviceLostInfo[_message] = message;
- return deviceLostInfo;
- }
-
- class GPUDeviceLostInfo {
- /** @type {string | undefined} */
- [_reason];
- /** @type {string} */
- [_message];
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- get reason() {
- webidl.assertBranded(this, GPUDeviceLostInfoPrototype);
- return this[_reason];
- }
- get message() {
- webidl.assertBranded(this, GPUDeviceLostInfoPrototype);
- return this[_message];
- }
-
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({ reason: this[_reason], message: this[_message] })
- }`;
+ createBuffer(descriptor) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createBuffer' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUBufferDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = ops.op_webgpu_create_buffer(
+ device.rid,
+ descriptor.label,
+ descriptor.size,
+ descriptor.usage,
+ descriptor.mappedAtCreation,
+ );
+ device.pushError(err);
+ /** @type {CreateGPUBufferOptions} */
+ let options;
+ if (descriptor.mappedAtCreation) {
+ options = {
+ mapping: new ArrayBuffer(descriptor.size),
+ mappingRange: [0, descriptor.size],
+ mappedRanges: [],
+ state: "mapped at creation",
+ };
+ } else {
+ options = {
+ mapping: null,
+ mappedRanges: null,
+ mappingRange: null,
+ state: "unmapped",
+ };
}
+ const buffer = createGPUBuffer(
+ descriptor.label,
+ device,
+ rid,
+ descriptor.size,
+ descriptor.usage,
+ options,
+ );
+ device.trackResource(buffer);
+ return buffer;
}
- const GPUDeviceLostInfoPrototype = GPUDeviceLostInfo.prototype;
-
/**
- * @param {string} name
- * @param {any} type
+ * @param {GPUTextureDescriptor} descriptor
+ * @returns {GPUTexture}
*/
- function GPUObjectBaseMixin(name, type) {
- type.prototype[_label] = null;
- ObjectDefineProperty(type.prototype, "label", {
- /**
- * @return {string | null}
- */
- get() {
- webidl.assertBranded(this, type.prototype);
- return this[_label];
- },
- /**
- * @param {string | null} label
- */
- set(label) {
- webidl.assertBranded(this, type.prototype);
- label = webidl.converters["UVString?"](label, {
- prefix: `Failed to set 'label' on '${name}'`,
- context: "Argument 1",
- });
- this[_label] = label;
- },
+ createTexture(descriptor) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createTexture' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUTextureDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = ops.op_webgpu_create_texture({
+ deviceRid: device.rid,
+ ...descriptor,
+ size: normalizeGPUExtent3D(descriptor.size),
});
+ device.pushError(err);
+
+ const texture = createGPUTexture(
+ descriptor,
+ device,
+ rid,
+ );
+ device.trackResource(texture);
+ return texture;
}
/**
- * @typedef ErrorScope
- * @property {string} filter
- * @property {Promise<void>[]} operations
+ * @param {GPUSamplerDescriptor} descriptor
+ * @returns {GPUSampler}
*/
+ createSampler(descriptor = {}) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createSampler' on 'GPUDevice'";
+ descriptor = webidl.converters.GPUSamplerDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = ops.op_webgpu_create_texture({
+ deviceRid: device.rid,
+ ...descriptor,
+ });
+ device.pushError(err);
+
+ const sampler = createGPUSampler(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(sampler);
+ return sampler;
+ }
/**
- * @typedef InnerGPUDeviceOptions
- * @property {GPUAdapter} adapter
- * @property {number | undefined} rid
- * @property {GPUSupportedFeatures} features
- * @property {GPUSupportedLimits} limits
+ * @param {GPUBindGroupLayoutDescriptor} descriptor
+ * @returns {GPUBindGroupLayout}
*/
-
- class InnerGPUDevice {
- /** @type {GPUAdapter} */
- adapter;
- /** @type {number | undefined} */
- rid;
- /** @type {GPUSupportedFeatures} */
- features;
- /** @type {GPUSupportedLimits} */
- limits;
- /** @type {WeakRef<any>[]} */
- resources;
- /** @type {boolean} */
- isLost;
- /** @type {Promise<GPUDeviceLostInfo>} */
- lost;
- /** @type {(info: GPUDeviceLostInfo) => void} */
- resolveLost;
- /** @type {ErrorScope[]} */
- errorScopeStack;
-
- /**
- * @param {InnerGPUDeviceOptions} options
- */
- constructor(options) {
- this.adapter = options.adapter;
- this.rid = options.rid;
- this.features = options.features;
- this.limits = options.limits;
- this.resources = [];
- this.isLost = false;
- this.resolveLost = () => {};
- this.lost = new Promise((resolve) => {
- this.resolveLost = resolve;
- });
- this.errorScopeStack = [];
- }
-
- /** @param {any} resource */
- trackResource(resource) {
- ArrayPrototypePush(this.resources, new WeakRef(resource));
+ createBindGroupLayout(descriptor) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createBindGroupLayout' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUBindGroupLayoutDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ for (let i = 0; i < descriptor.entries.length; ++i) {
+ const entry = descriptor.entries[i];
+
+ let j = 0;
+ if (entry.buffer) j++;
+ if (entry.sampler) j++;
+ if (entry.texture) j++;
+ if (entry.storageTexture) j++;
+
+ if (j !== 1) {
+ throw new Error(); // TODO(@crowlKats): correct error
+ }
}
- /** @param {{ type: string, value: string | null } | undefined} err */
- pushError(err) {
- this.pushErrorPromise(PromiseResolve(err));
- }
+ const { rid, err } = ops.op_webgpu_create_bind_group_layout(
+ device.rid,
+ descriptor.label,
+ descriptor.entries,
+ );
+ device.pushError(err);
- /** @param {Promise<{ type: string, value: string | null } | undefined>} promise */
- pushErrorPromise(promise) {
- const operation = PromisePrototypeThen(promise, (err) => {
- if (err) {
- switch (err.type) {
- case "lost":
- this.isLost = true;
- this.resolveLost(
- createGPUDeviceLostInfo(undefined, "device was lost"),
- );
- break;
- case "validation":
- return PromiseReject(
- new GPUValidationError(err.value ?? "validation error"),
- );
- case "out-of-memory":
- return PromiseReject(new GPUOutOfMemoryError());
- }
- }
- });
+ const bindGroupLayout = createGPUBindGroupLayout(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(bindGroupLayout);
+ return bindGroupLayout;
+ }
- const validationStack = ArrayPrototypeFilter(
- this.errorScopeStack,
- ({ filter }) => filter == "validation",
- );
- const validationScope = validationStack[validationStack.length - 1];
- const validationFilteredPromise = PromisePrototypeCatch(
- operation,
- (err) => {
- if (ObjectPrototypeIsPrototypeOf(GPUValidationErrorPrototype, err)) {
- return PromiseReject(err);
- }
- return PromiseResolve();
- },
- );
- if (validationScope) {
- ArrayPrototypePush(
- validationScope.operations,
- validationFilteredPromise,
- );
- } else {
- PromisePrototypeCatch(validationFilteredPromise, () => {
- // TODO(lucacasonato): emit an UncapturedErrorEvent
+ /**
+ * @param {GPUPipelineLayoutDescriptor} descriptor
+ * @returns {GPUPipelineLayout}
+ */
+ createPipelineLayout(descriptor) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createPipelineLayout' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUPipelineLayoutDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const bindGroupLayouts = ArrayPrototypeMap(
+ descriptor.bindGroupLayouts,
+ (layout, i) => {
+ const context = `bind group layout ${i + 1}`;
+ const rid = assertResource(layout, { prefix, context });
+ assertDeviceMatch(device, layout, {
+ prefix,
+ selfContext: "this",
+ resourceContext: context,
});
- }
- // prevent uncaptured promise rejections
- PromisePrototypeCatch(validationFilteredPromise, (_err) => {});
+ return rid;
+ },
+ );
+ const { rid, err } = ops.op_webgpu_create_pipeline_layout(
+ device.rid,
+ descriptor.label,
+ bindGroupLayouts,
+ );
+ device.pushError(err);
- const oomStack = ArrayPrototypeFilter(
- this.errorScopeStack,
- ({ filter }) => filter == "out-of-memory",
- );
- const oomScope = oomStack[oomStack.length - 1];
- const oomFilteredPromise = PromisePrototypeCatch(operation, (err) => {
- if (ObjectPrototypeIsPrototypeOf(GPUOutOfMemoryErrorPrototype, err)) {
- return PromiseReject(err);
- }
- return PromiseResolve();
- });
- if (oomScope) {
- ArrayPrototypePush(oomScope.operations, oomFilteredPromise);
- } else {
- PromisePrototypeCatch(oomFilteredPromise, () => {
- // TODO(lucacasonato): emit an UncapturedErrorEvent
- });
- }
- // prevent uncaptured promise rejections
- PromisePrototypeCatch(oomFilteredPromise, (_err) => {});
- }
+ const pipelineLayout = createGPUPipelineLayout(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(pipelineLayout);
+ return pipelineLayout;
}
/**
- * @param {string | null} label
- * @param {InnerGPUDevice} inner
- * @param {GPUQueue} queue
- * @returns {GPUDevice}
+ * @param {GPUBindGroupDescriptor} descriptor
+ * @returns {GPUBindGroup}
*/
- function createGPUDevice(label, inner, queue) {
- /** @type {GPUDevice} */
- const device = webidl.createBranded(GPUDevice);
- device[_label] = label;
- device[_device] = inner;
- device[_queue] = queue;
- return device;
- }
-
- class GPUDevice extends eventTarget.EventTarget {
- /** @type {InnerGPUDevice} */
- [_device];
-
- /** @type {GPUQueue} */
- [_queue];
-
- [_cleanup]() {
- const device = this[_device];
- const resources = device.resources;
- while (resources.length > 0) {
- const resource = ArrayPrototypePop(resources)?.deref();
- if (resource) {
- resource[_cleanup]();
- }
- }
- const rid = device.rid;
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- device.rid = undefined;
- }
- }
-
- get features() {
- webidl.assertBranded(this, GPUDevicePrototype);
- return this[_device].features;
- }
- get limits() {
- webidl.assertBranded(this, GPUDevicePrototype);
- return this[_device].limits;
- }
- get queue() {
- webidl.assertBranded(this, GPUDevicePrototype);
- return this[_queue];
- }
-
- constructor() {
- webidl.illegalConstructor();
- super();
- }
-
- destroy() {
- webidl.assertBranded(this, GPUDevicePrototype);
- this[_cleanup]();
- }
-
- /**
- * @param {GPUBufferDescriptor} descriptor
- * @returns {GPUBuffer}
- */
- createBuffer(descriptor) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createBuffer' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPUBufferDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const { rid, err } = ops.op_webgpu_create_buffer(
- device.rid,
- descriptor.label,
- descriptor.size,
- descriptor.usage,
- descriptor.mappedAtCreation,
- );
- device.pushError(err);
- /** @type {CreateGPUBufferOptions} */
- let options;
- if (descriptor.mappedAtCreation) {
- options = {
- mapping: new ArrayBuffer(descriptor.size),
- mappingRange: [0, descriptor.size],
- mappedRanges: [],
- state: "mapped at creation",
+ createBindGroup(descriptor) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createBindGroup' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUBindGroupDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const layout = assertResource(descriptor.layout, {
+ prefix,
+ context: "layout",
+ });
+ assertDeviceMatch(device, descriptor.layout, {
+ prefix,
+ resourceContext: "layout",
+ selfContext: "this",
+ });
+ const entries = ArrayPrototypeMap(descriptor.entries, (entry, i) => {
+ const context = `entry ${i + 1}`;
+ const resource = entry.resource;
+ if (ObjectPrototypeIsPrototypeOf(GPUSamplerPrototype, resource)) {
+ const rid = assertResource(resource, {
+ prefix,
+ context,
+ });
+ assertDeviceMatch(device, resource, {
+ prefix,
+ resourceContext: context,
+ selfContext: "this",
+ });
+ return {
+ binding: entry.binding,
+ kind: "GPUSampler",
+ resource: rid,
+ };
+ } else if (
+ ObjectPrototypeIsPrototypeOf(GPUTextureViewPrototype, resource)
+ ) {
+ const rid = assertResource(resource, {
+ prefix,
+ context,
+ });
+ assertResource(resource[_texture], {
+ prefix,
+ context,
+ });
+ assertDeviceMatch(device, resource[_texture], {
+ prefix,
+ resourceContext: context,
+ selfContext: "this",
+ });
+ return {
+ binding: entry.binding,
+ kind: "GPUTextureView",
+ resource: rid,
};
} else {
- options = {
- mapping: null,
- mappedRanges: null,
- mappingRange: null,
- state: "unmapped",
+ const rid = assertResource(resource.buffer, { prefix, context });
+ assertDeviceMatch(device, resource.buffer, {
+ prefix,
+ resourceContext: context,
+ selfContext: "this",
+ });
+ return {
+ binding: entry.binding,
+ kind: "GPUBufferBinding",
+ resource: rid,
+ offset: entry.resource.offset,
+ size: entry.resource.size,
};
}
- const buffer = createGPUBuffer(
- descriptor.label,
- device,
- rid,
- descriptor.size,
- descriptor.usage,
- options,
- );
- device.trackResource(buffer);
- return buffer;
- }
+ });
- /**
- * @param {GPUTextureDescriptor} descriptor
- * @returns {GPUTexture}
- */
- createTexture(descriptor) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createTexture' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPUTextureDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const { rid, err } = ops.op_webgpu_create_texture({
- deviceRid: device.rid,
- ...descriptor,
- size: normalizeGPUExtent3D(descriptor.size),
- });
- device.pushError(err);
+ const { rid, err } = ops.op_webgpu_create_bind_group(
+ device.rid,
+ descriptor.label,
+ layout,
+ entries,
+ );
+ device.pushError(err);
- const texture = createGPUTexture(
- descriptor,
- device,
- rid,
- );
- device.trackResource(texture);
- return texture;
- }
+ const bindGroup = createGPUBindGroup(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(bindGroup);
+ return bindGroup;
+ }
- /**
- * @param {GPUSamplerDescriptor} descriptor
- * @returns {GPUSampler}
- */
- createSampler(descriptor = {}) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createSampler' on 'GPUDevice'";
- descriptor = webidl.converters.GPUSamplerDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const { rid, err } = ops.op_webgpu_create_texture({
- deviceRid: device.rid,
- ...descriptor,
- });
- device.pushError(err);
+ /**
+ * @param {GPUShaderModuleDescriptor} descriptor
+ */
+ createShaderModule(descriptor) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createShaderModule' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUShaderModuleDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = ops.op_webgpu_create_shader_module(
+ device.rid,
+ descriptor.label,
+ descriptor.code,
+ );
+ device.pushError(err);
- const sampler = createGPUSampler(
- descriptor.label,
- device,
- rid,
- );
- device.trackResource(sampler);
- return sampler;
- }
+ const shaderModule = createGPUShaderModule(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(shaderModule);
+ return shaderModule;
+ }
- /**
- * @param {GPUBindGroupLayoutDescriptor} descriptor
- * @returns {GPUBindGroupLayout}
- */
- createBindGroupLayout(descriptor) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createBindGroupLayout' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPUBindGroupLayoutDescriptor(descriptor, {
+ /**
+ * @param {GPUComputePipelineDescriptor} descriptor
+ * @returns {GPUComputePipeline}
+ */
+ createComputePipeline(descriptor) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createComputePipeline' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUComputePipelineDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ let layout = descriptor.layout;
+ if (typeof descriptor.layout !== "string") {
+ const context = "layout";
+ layout = assertResource(descriptor.layout, { prefix, context });
+ assertDeviceMatch(device, descriptor.layout, {
prefix,
- context: "Argument 1",
+ resourceContext: context,
+ selfContext: "this",
});
- const device = assertDevice(this, { prefix, context: "this" });
- for (let i = 0; i < descriptor.entries.length; ++i) {
- const entry = descriptor.entries[i];
-
- let j = 0;
- if (entry.buffer) j++;
- if (entry.sampler) j++;
- if (entry.texture) j++;
- if (entry.storageTexture) j++;
-
- if (j !== 1) {
- throw new Error(); // TODO(@crowlKats): correct error
- }
- }
-
- const { rid, err } = ops.op_webgpu_create_bind_group_layout(
- device.rid,
- descriptor.label,
- descriptor.entries,
- );
- device.pushError(err);
-
- const bindGroupLayout = createGPUBindGroupLayout(
- descriptor.label,
- device,
- rid,
- );
- device.trackResource(bindGroupLayout);
- return bindGroupLayout;
}
+ const module = assertResource(descriptor.compute.module, {
+ prefix,
+ context: "compute shader module",
+ });
+ assertDeviceMatch(device, descriptor.compute.module, {
+ prefix,
+ resourceContext: "compute shader module",
+ selfContext: "this",
+ });
- /**
- * @param {GPUPipelineLayoutDescriptor} descriptor
- * @returns {GPUPipelineLayout}
- */
- createPipelineLayout(descriptor) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createPipelineLayout' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPUPipelineLayoutDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const bindGroupLayouts = ArrayPrototypeMap(
- descriptor.bindGroupLayouts,
- (layout, i) => {
- const context = `bind group layout ${i + 1}`;
- const rid = assertResource(layout, { prefix, context });
- assertDeviceMatch(device, layout, {
- prefix,
- selfContext: "this",
- resourceContext: context,
- });
- return rid;
- },
- );
- const { rid, err } = ops.op_webgpu_create_pipeline_layout(
- device.rid,
- descriptor.label,
- bindGroupLayouts,
- );
- device.pushError(err);
+ const { rid, err } = ops.op_webgpu_create_compute_pipeline(
+ device.rid,
+ descriptor.label,
+ layout,
+ {
+ module,
+ entryPoint: descriptor.compute.entryPoint,
+ constants: descriptor.compute.constants,
+ },
+ );
+ device.pushError(err);
- const pipelineLayout = createGPUPipelineLayout(
- descriptor.label,
- device,
- rid,
- );
- device.trackResource(pipelineLayout);
- return pipelineLayout;
- }
+ const computePipeline = createGPUComputePipeline(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(computePipeline);
+ return computePipeline;
+ }
- /**
- * @param {GPUBindGroupDescriptor} descriptor
- * @returns {GPUBindGroup}
- */
- createBindGroup(descriptor) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createBindGroup' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPUBindGroupDescriptor(descriptor, {
+ /**
+ * @param {GPURenderPipelineDescriptor} descriptor
+ * @returns {GPURenderPipeline}
+ */
+ createRenderPipeline(descriptor) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createRenderPipeline' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPURenderPipelineDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ let layout = descriptor.layout;
+ if (typeof descriptor.layout !== "string") {
+ const context = "layout";
+ layout = assertResource(descriptor.layout, { prefix, context });
+ assertDeviceMatch(device, descriptor.layout, {
prefix,
- context: "Argument 1",
+ resourceContext: context,
+ selfContext: "this",
});
- const device = assertDevice(this, { prefix, context: "this" });
- const layout = assertResource(descriptor.layout, {
+ }
+ const module = assertResource(descriptor.vertex.module, {
+ prefix,
+ context: "vertex shader module",
+ });
+ assertDeviceMatch(device, descriptor.vertex.module, {
+ prefix,
+ resourceContext: "vertex shader module",
+ selfContext: "this",
+ });
+ let fragment = undefined;
+ if (descriptor.fragment) {
+ const module = assertResource(descriptor.fragment.module, {
prefix,
- context: "layout",
+ context: "fragment shader module",
});
- assertDeviceMatch(device, descriptor.layout, {
+ assertDeviceMatch(device, descriptor.fragment.module, {
prefix,
- resourceContext: "layout",
+ resourceContext: "fragment shader module",
selfContext: "this",
});
- const entries = ArrayPrototypeMap(descriptor.entries, (entry, i) => {
- const context = `entry ${i + 1}`;
- const resource = entry.resource;
- if (ObjectPrototypeIsPrototypeOf(GPUSamplerPrototype, resource)) {
- const rid = assertResource(resource, {
- prefix,
- context,
- });
- assertDeviceMatch(device, resource, {
- prefix,
- resourceContext: context,
- selfContext: "this",
- });
- return {
- binding: entry.binding,
- kind: "GPUSampler",
- resource: rid,
- };
- } else if (
- ObjectPrototypeIsPrototypeOf(GPUTextureViewPrototype, resource)
- ) {
- const rid = assertResource(resource, {
- prefix,
- context,
- });
- assertResource(resource[_texture], {
- prefix,
- context,
- });
- assertDeviceMatch(device, resource[_texture], {
- prefix,
- resourceContext: context,
- selfContext: "this",
- });
- return {
- binding: entry.binding,
- kind: "GPUTextureView",
- resource: rid,
- };
- } else {
- const rid = assertResource(resource.buffer, { prefix, context });
- assertDeviceMatch(device, resource.buffer, {
- prefix,
- resourceContext: context,
- selfContext: "this",
- });
- return {
- binding: entry.binding,
- kind: "GPUBufferBinding",
- resource: rid,
- offset: entry.resource.offset,
- size: entry.resource.size,
- };
- }
- });
+ fragment = {
+ module,
+ entryPoint: descriptor.fragment.entryPoint,
+ targets: descriptor.fragment.targets,
+ };
+ }
- const { rid, err } = ops.op_webgpu_create_bind_group(
- device.rid,
- descriptor.label,
- layout,
- entries,
- );
- device.pushError(err);
+ const { rid, err } = ops.op_webgpu_create_render_pipeline({
+ deviceRid: device.rid,
+ label: descriptor.label,
+ layout,
+ vertex: {
+ module,
+ entryPoint: descriptor.vertex.entryPoint,
+ buffers: descriptor.vertex.buffers,
+ },
+ primitive: descriptor.primitive,
+ depthStencil: descriptor.depthStencil,
+ multisample: descriptor.multisample,
+ fragment,
+ });
+ device.pushError(err);
- const bindGroup = createGPUBindGroup(
- descriptor.label,
- device,
- rid,
- );
- device.trackResource(bindGroup);
- return bindGroup;
- }
+ const renderPipeline = createGPURenderPipeline(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(renderPipeline);
+ return renderPipeline;
+ }
- /**
- * @param {GPUShaderModuleDescriptor} descriptor
- */
- createShaderModule(descriptor) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createShaderModule' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPUShaderModuleDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const { rid, err } = ops.op_webgpu_create_shader_module(
- device.rid,
- descriptor.label,
- descriptor.code,
- );
- device.pushError(err);
+ createComputePipelineAsync(descriptor) {
+ // TODO(lucacasonato): this should be real async
+ return PromiseResolve(this.createComputePipeline(descriptor));
+ }
- const shaderModule = createGPUShaderModule(
- descriptor.label,
- device,
- rid,
- );
- device.trackResource(shaderModule);
- return shaderModule;
- }
+ createRenderPipelineAsync(descriptor) {
+ // TODO(lucacasonato): this should be real async
+ return PromiseResolve(this.createRenderPipeline(descriptor));
+ }
- /**
- * @param {GPUComputePipelineDescriptor} descriptor
- * @returns {GPUComputePipeline}
- */
- createComputePipeline(descriptor) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createComputePipeline' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPUComputePipelineDescriptor(descriptor, {
+ /**
+ * @param {GPUCommandEncoderDescriptor} descriptor
+ * @returns {GPUCommandEncoder}
+ */
+ createCommandEncoder(descriptor = {}) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createCommandEncoder' on 'GPUDevice'";
+ descriptor = webidl.converters.GPUCommandEncoderDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = ops.op_webgpu_create_command_encoder(
+ device.rid,
+ descriptor.label,
+ );
+ device.pushError(err);
+
+ const commandEncoder = createGPUCommandEncoder(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(commandEncoder);
+ return commandEncoder;
+ }
+
+ /**
+ * @param {GPURenderBundleEncoderDescriptor} descriptor
+ * @returns {GPURenderBundleEncoder}
+ */
+ createRenderBundleEncoder(descriptor) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix =
+ "Failed to execute 'createRenderBundleEncoder' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPURenderBundleEncoderDescriptor(
+ descriptor,
+ {
prefix,
context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- let layout = descriptor.layout;
- if (typeof descriptor.layout !== "string") {
- const context = "layout";
- layout = assertResource(descriptor.layout, { prefix, context });
- assertDeviceMatch(device, descriptor.layout, {
- prefix,
- resourceContext: context,
- selfContext: "this",
- });
- }
- const module = assertResource(descriptor.compute.module, {
- prefix,
- context: "compute shader module",
- });
- assertDeviceMatch(device, descriptor.compute.module, {
- prefix,
- resourceContext: "compute shader module",
- selfContext: "this",
- });
-
- const { rid, err } = ops.op_webgpu_create_compute_pipeline(
- device.rid,
- descriptor.label,
- layout,
- {
- module,
- entryPoint: descriptor.compute.entryPoint,
- constants: descriptor.compute.constants,
- },
- );
- device.pushError(err);
+ },
+ );
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = ops.op_webgpu_create_render_bundle_encoder({
+ deviceRid: device.rid,
+ ...descriptor,
+ });
+ device.pushError(err);
- const computePipeline = createGPUComputePipeline(
- descriptor.label,
- device,
- rid,
- );
- device.trackResource(computePipeline);
- return computePipeline;
- }
+ const renderBundleEncoder = createGPURenderBundleEncoder(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(renderBundleEncoder);
+ return renderBundleEncoder;
+ }
- /**
- * @param {GPURenderPipelineDescriptor} descriptor
- * @returns {GPURenderPipeline}
- */
- createRenderPipeline(descriptor) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createRenderPipeline' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPURenderPipelineDescriptor(descriptor, {
+ /**
+ * @param {GPUQuerySetDescriptor} descriptor
+ * @returns {GPUQuerySet}
+ */
+ createQuerySet(descriptor) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'createQuerySet' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUQuerySetDescriptor(
+ descriptor,
+ {
prefix,
context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- let layout = descriptor.layout;
- if (typeof descriptor.layout !== "string") {
- const context = "layout";
- layout = assertResource(descriptor.layout, { prefix, context });
- assertDeviceMatch(device, descriptor.layout, {
- prefix,
- resourceContext: context,
- selfContext: "this",
- });
- }
- const module = assertResource(descriptor.vertex.module, {
- prefix,
- context: "vertex shader module",
- });
- assertDeviceMatch(device, descriptor.vertex.module, {
- prefix,
- resourceContext: "vertex shader module",
- selfContext: "this",
- });
- let fragment = undefined;
- if (descriptor.fragment) {
- const module = assertResource(descriptor.fragment.module, {
- prefix,
- context: "fragment shader module",
- });
- assertDeviceMatch(device, descriptor.fragment.module, {
- prefix,
- resourceContext: "fragment shader module",
- selfContext: "this",
- });
- fragment = {
- module,
- entryPoint: descriptor.fragment.entryPoint,
- targets: descriptor.fragment.targets,
- };
- }
-
- const { rid, err } = ops.op_webgpu_create_render_pipeline({
- deviceRid: device.rid,
- label: descriptor.label,
- layout,
- vertex: {
- module,
- entryPoint: descriptor.vertex.entryPoint,
- buffers: descriptor.vertex.buffers,
- },
- primitive: descriptor.primitive,
- depthStencil: descriptor.depthStencil,
- multisample: descriptor.multisample,
- fragment,
- });
- device.pushError(err);
+ },
+ );
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = ops.op_webgpu_create_query_set({
+ deviceRid: device.rid,
+ ...descriptor,
+ });
+ device.pushError(err);
- const renderPipeline = createGPURenderPipeline(
- descriptor.label,
- device,
- rid,
- );
- device.trackResource(renderPipeline);
- return renderPipeline;
- }
+ const querySet = createGPUQuerySet(
+ descriptor.label,
+ device,
+ rid,
+ descriptor,
+ );
+ device.trackResource(querySet);
+ return querySet;
+ }
- createComputePipelineAsync(descriptor) {
- // TODO(lucacasonato): this should be real async
- return PromiseResolve(this.createComputePipeline(descriptor));
+ get lost() {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const device = this[_device];
+ if (!device) {
+ return PromiseResolve(true);
}
-
- createRenderPipelineAsync(descriptor) {
- // TODO(lucacasonato): this should be real async
- return PromiseResolve(this.createRenderPipeline(descriptor));
+ if (device.rid === undefined) {
+ return PromiseResolve(true);
}
+ return device.lost;
+ }
- /**
- * @param {GPUCommandEncoderDescriptor} descriptor
- * @returns {GPUCommandEncoder}
- */
- createCommandEncoder(descriptor = {}) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createCommandEncoder' on 'GPUDevice'";
- descriptor = webidl.converters.GPUCommandEncoderDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const { rid, err } = ops.op_webgpu_create_command_encoder(
- device.rid,
- descriptor.label,
- );
- device.pushError(err);
+ /**
+ * @param {GPUErrorFilter} filter
+ */
+ pushErrorScope(filter) {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'pushErrorScope' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ filter = webidl.converters.GPUErrorFilter(filter, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ ArrayPrototypePush(device.errorScopeStack, { filter, operations: [] });
+ }
- const commandEncoder = createGPUCommandEncoder(
- descriptor.label,
- device,
- rid,
+ /**
+ * @returns {Promise<GPUError | null>}
+ */
+ // deno-lint-ignore require-await
+ async popErrorScope() {
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix = "Failed to execute 'popErrorScope' on 'GPUDevice'";
+ const device = assertDevice(this, { prefix, context: "this" });
+ if (device.isLost) {
+ throw new DOMException("Device has been lost.", "OperationError");
+ }
+ const scope = ArrayPrototypePop(device.errorScopeStack);
+ if (!scope) {
+ throw new DOMException(
+ "There are no error scopes on the error scope stack.",
+ "OperationError",
);
- device.trackResource(commandEncoder);
- return commandEncoder;
}
+ const operations = SafePromiseAll(scope.operations);
+ return PromisePrototypeThen(
+ operations,
+ () => PromiseResolve(null),
+ (err) => PromiseResolve(err),
+ );
+ }
- /**
- * @param {GPURenderBundleEncoderDescriptor} descriptor
- * @returns {GPURenderBundleEncoder}
- */
- createRenderBundleEncoder(descriptor) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix =
- "Failed to execute 'createRenderBundleEncoder' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPURenderBundleEncoderDescriptor(
- descriptor,
- {
- prefix,
- context: "Argument 1",
- },
- );
- const device = assertDevice(this, { prefix, context: "this" });
- const { rid, err } = ops.op_webgpu_create_render_bundle_encoder({
- deviceRid: device.rid,
- ...descriptor,
- });
- device.pushError(err);
-
- const renderBundleEncoder = createGPURenderBundleEncoder(
- descriptor.label,
- device,
- rid,
- );
- device.trackResource(renderBundleEncoder);
- return renderBundleEncoder;
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ features: this.features,
+ label: this.label,
+ limits: this.limits,
+ queue: this.queue,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUDevice", GPUDevice);
+const GPUDevicePrototype = GPUDevice.prototype;
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @returns {GPUQueue}
+ */
+function createGPUQueue(label, device) {
+ /** @type {GPUQueue} */
+ const queue = webidl.createBranded(GPUQueue);
+ queue[_label] = label;
+ queue[_device] = device;
+ return queue;
+}
+
+class GPUQueue {
+ /** @type {InnerGPUDevice} */
+ [_device];
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
- /**
- * @param {GPUQuerySetDescriptor} descriptor
- * @returns {GPUQuerySet}
- */
- createQuerySet(descriptor) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'createQuerySet' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPUQuerySetDescriptor(
- descriptor,
- {
+ /**
+ * @param {GPUCommandBuffer[]} commandBuffers
+ */
+ submit(commandBuffers) {
+ webidl.assertBranded(this, GPUQueuePrototype);
+ const prefix = "Failed to execute 'submit' on 'GPUQueue'";
+ webidl.requiredArguments(arguments.length, 1, {
+ prefix,
+ });
+ commandBuffers = webidl.converters["sequence<GPUCommandBuffer>"](
+ commandBuffers,
+ { prefix, context: "Argument 1" },
+ );
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandBufferRids = ArrayPrototypeMap(
+ commandBuffers,
+ (buffer, i) => {
+ const context = `command buffer ${i + 1}`;
+ const rid = assertResource(buffer, { prefix, context });
+ assertDeviceMatch(device, buffer, {
prefix,
- context: "Argument 1",
- },
- );
- const device = assertDevice(this, { prefix, context: "this" });
- const { rid, err } = ops.op_webgpu_create_query_set({
- deviceRid: device.rid,
- ...descriptor,
- });
- device.pushError(err);
-
- const querySet = createGPUQuerySet(
- descriptor.label,
- device,
- rid,
- descriptor,
- );
- device.trackResource(querySet);
- return querySet;
+ selfContext: "this",
+ resourceContext: context,
+ });
+ return rid;
+ },
+ );
+ const { err } = ops.op_webgpu_queue_submit(device.rid, commandBufferRids);
+ for (let i = 0; i < commandBuffers.length; ++i) {
+ commandBuffers[i][_rid] = undefined;
}
+ device.pushError(err);
+ }
- get lost() {
- webidl.assertBranded(this, GPUDevicePrototype);
- const device = this[_device];
- if (!device) {
- return PromiseResolve(true);
- }
- if (device.rid === undefined) {
- return PromiseResolve(true);
- }
- return device.lost;
- }
+ onSubmittedWorkDone() {
+ webidl.assertBranded(this, GPUQueuePrototype);
+ return PromiseResolve();
+ }
- /**
- * @param {GPUErrorFilter} filter
- */
- pushErrorScope(filter) {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'pushErrorScope' on 'GPUDevice'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- filter = webidl.converters.GPUErrorFilter(filter, {
+ /**
+ * @param {GPUBuffer} buffer
+ * @param {number} bufferOffset
+ * @param {BufferSource} data
+ * @param {number} [dataOffset]
+ * @param {number} [size]
+ */
+ writeBuffer(buffer, bufferOffset, data, dataOffset = 0, size) {
+ webidl.assertBranded(this, GPUQueuePrototype);
+ const prefix = "Failed to execute 'writeBuffer' on 'GPUQueue'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ buffer = webidl.converters["GPUBuffer"](buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ bufferOffset = webidl.converters["GPUSize64"](bufferOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ data = webidl.converters.BufferSource(data, {
+ prefix,
+ context: "Argument 3",
+ });
+ dataOffset = webidl.converters["GPUSize64"](dataOffset, {
+ prefix,
+ context: "Argument 4",
+ });
+ size = size === undefined
+ ? undefined
+ : webidl.converters["GPUSize64"](size, {
prefix,
- context: "Argument 1",
+ context: "Argument 5",
});
- const device = assertDevice(this, { prefix, context: "this" });
- ArrayPrototypePush(device.errorScopeStack, { filter, operations: [] });
- }
+ const device = assertDevice(this, { prefix, context: "this" });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ selfContext: "this",
+ resourceContext: "Argument 1",
+ });
+ const { err } = ops.op_webgpu_write_buffer(
+ device.rid,
+ bufferRid,
+ bufferOffset,
+ dataOffset,
+ size,
+ new Uint8Array(ArrayBufferIsView(data) ? data.buffer : data),
+ );
+ device.pushError(err);
+ }
- /**
- * @returns {Promise<GPUError | null>}
- */
- // deno-lint-ignore require-await
- async popErrorScope() {
- webidl.assertBranded(this, GPUDevicePrototype);
- const prefix = "Failed to execute 'popErrorScope' on 'GPUDevice'";
- const device = assertDevice(this, { prefix, context: "this" });
- if (device.isLost) {
- throw new DOMException("Device has been lost.", "OperationError");
- }
- const scope = ArrayPrototypePop(device.errorScopeStack);
- if (!scope) {
- throw new DOMException(
- "There are no error scopes on the error scope stack.",
- "OperationError",
- );
+ /**
+ * @param {GPUImageCopyTexture} destination
+ * @param {BufferSource} data
+ * @param {GPUImageDataLayout} dataLayout
+ * @param {GPUExtent3D} size
+ */
+ writeTexture(destination, data, dataLayout, size) {
+ webidl.assertBranded(this, GPUQueuePrototype);
+ const prefix = "Failed to execute 'writeTexture' on 'GPUQueue'";
+ webidl.requiredArguments(arguments.length, 4, { prefix });
+ destination = webidl.converters.GPUImageCopyTexture(destination, {
+ prefix,
+ context: "Argument 1",
+ });
+ data = webidl.converters.BufferSource(data, {
+ prefix,
+ context: "Argument 2",
+ });
+ dataLayout = webidl.converters.GPUImageDataLayout(dataLayout, {
+ prefix,
+ context: "Argument 3",
+ });
+ size = webidl.converters.GPUExtent3D(size, {
+ prefix,
+ context: "Argument 4",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const textureRid = assertResource(destination.texture, {
+ prefix,
+ context: "texture",
+ });
+ assertDeviceMatch(device, destination.texture, {
+ prefix,
+ selfContext: "this",
+ resourceContext: "texture",
+ });
+ const { err } = ops.op_webgpu_write_texture(
+ device.rid,
+ {
+ texture: textureRid,
+ mipLevel: destination.mipLevel,
+ origin: destination.origin
+ ? normalizeGPUOrigin3D(destination.origin)
+ : undefined,
+ aspect: destination.aspect,
+ },
+ dataLayout,
+ normalizeGPUExtent3D(size),
+ new Uint8Array(ArrayBufferIsView(data) ? data.buffer : data),
+ );
+ device.pushError(err);
+ }
+
+ copyImageBitmapToTexture(_source, _destination, _copySize) {
+ throw new Error("Not yet implemented");
+ }
+
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUQueue", GPUQueue);
+const GPUQueuePrototype = GPUQueue.prototype;
+
+/**
+ * @typedef CreateGPUBufferOptions
+ * @property {ArrayBuffer | null} mapping
+ * @property {number[] | null} mappingRange
+ * @property {[ArrayBuffer, number, number][] | null} mappedRanges
+ * @property {"mapped" | "mapped at creation" | "mapped pending" | "unmapped" | "destroy" } state
+ */
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @param {number} size
+ * @param {number} usage
+ * @param {CreateGPUBufferOptions} options
+ * @returns {GPUBuffer}
+ */
+function createGPUBuffer(label, device, rid, size, usage, options) {
+ /** @type {GPUBuffer} */
+ const buffer = webidl.createBranded(GPUBuffer);
+ buffer[_label] = label;
+ buffer[_device] = device;
+ buffer[_rid] = rid;
+ buffer[_size] = size;
+ buffer[_usage] = usage;
+ buffer[_mappingRange] = options.mappingRange;
+ buffer[_mappedRanges] = options.mappedRanges;
+ buffer[_state] = options.state;
+ return buffer;
+}
+
+class GPUBuffer {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number} */
+ [_rid];
+ /** @type {number} */
+ [_size];
+ /** @type {number} */
+ [_usage];
+ /** @type {"mapped" | "mapped at creation" | "pending" | "unmapped" | "destroy"} */
+ [_state];
+ /** @type {[number, number] | null} */
+ [_mappingRange];
+ /** @type {[ArrayBuffer, number, number][] | null} */
+ [_mappedRanges];
+ /** @type {number} */
+ [_mapMode];
+
+ [_cleanup]() {
+ const mappedRanges = this[_mappedRanges];
+ if (mappedRanges) {
+ while (mappedRanges.length > 0) {
+ const mappedRange = ArrayPrototypePop(mappedRanges);
+ if (mappedRange !== undefined) {
+ core.close(mappedRange[1]);
+ }
}
- const operations = SafePromiseAll(scope.operations);
- return PromisePrototypeThen(
- operations,
- () => PromiseResolve(null),
- (err) => PromiseResolve(err),
- );
}
-
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- features: this.features,
- label: this.label,
- limits: this.limits,
- queue: this.queue,
- })
- }`;
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ this[_state] = "destroy";
}
- GPUObjectBaseMixin("GPUDevice", GPUDevice);
- const GPUDevicePrototype = GPUDevice.prototype;
- /**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @returns {GPUQueue}
- */
- function createGPUQueue(label, device) {
- /** @type {GPUQueue} */
- const queue = webidl.createBranded(GPUQueue);
- queue[_label] = label;
- queue[_device] = device;
- return queue;
+ constructor() {
+ webidl.illegalConstructor();
}
- class GPUQueue {
- /** @type {InnerGPUDevice} */
- [_device];
+ get size() {
+ webidl.assertBranded(this, GPUBufferPrototype);
+ return this[_size];
+ }
- constructor() {
- webidl.illegalConstructor();
+ get usage() {
+ webidl.assertBranded(this, GPUBufferPrototype);
+ return this[_usage];
+ }
+
+ get mapState() {
+ webidl.assertBranded(this, GPUBufferPrototype);
+ const state = this[_state];
+ if (state === "mapped at creation") {
+ return "mapped";
+ } else {
+ return state;
}
+ }
- /**
- * @param {GPUCommandBuffer[]} commandBuffers
- */
- submit(commandBuffers) {
- webidl.assertBranded(this, GPUQueuePrototype);
- const prefix = "Failed to execute 'submit' on 'GPUQueue'";
- webidl.requiredArguments(arguments.length, 1, {
- prefix,
- });
- commandBuffers = webidl.converters["sequence<GPUCommandBuffer>"](
- commandBuffers,
- { prefix, context: "Argument 1" },
+ /**
+ * @param {number} mode
+ * @param {number} offset
+ * @param {number} [size]
+ */
+ async mapAsync(mode, offset = 0, size) {
+ webidl.assertBranded(this, GPUBufferPrototype);
+ const prefix = "Failed to execute 'mapAsync' on 'GPUBuffer'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ mode = webidl.converters.GPUMapModeFlags(mode, {
+ prefix,
+ context: "Argument 1",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 2",
+ });
+ size = size === undefined ? undefined : webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 3",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const bufferRid = assertResource(this, { prefix, context: "this" });
+ /** @type {number} */
+ let rangeSize;
+ if (size === undefined) {
+ rangeSize = MathMax(0, this[_size] - offset);
+ } else {
+ rangeSize = this[_size];
+ }
+ if ((offset % 8) !== 0) {
+ throw new DOMException(
+ `${prefix}: offset must be a multiple of 8.`,
+ "OperationError",
);
- const device = assertDevice(this, { prefix, context: "this" });
- const commandBufferRids = ArrayPrototypeMap(
- commandBuffers,
- (buffer, i) => {
- const context = `command buffer ${i + 1}`;
- const rid = assertResource(buffer, { prefix, context });
- assertDeviceMatch(device, buffer, {
- prefix,
- selfContext: "this",
- resourceContext: context,
- });
- return rid;
- },
+ }
+ if ((rangeSize % 4) !== 0) {
+ throw new DOMException(
+ `${prefix}: rangeSize must be a multiple of 4.`,
+ "OperationError",
);
- const { err } = ops.op_webgpu_queue_submit(device.rid, commandBufferRids);
- for (let i = 0; i < commandBuffers.length; ++i) {
- commandBuffers[i][_rid] = undefined;
- }
- device.pushError(err);
}
-
- onSubmittedWorkDone() {
- webidl.assertBranded(this, GPUQueuePrototype);
- return PromiseResolve();
+ if ((offset + rangeSize) > this[_size]) {
+ throw new DOMException(
+ `${prefix}: offset + rangeSize must be less than or equal to buffer size.`,
+ "OperationError",
+ );
}
-
- /**
- * @param {GPUBuffer} buffer
- * @param {number} bufferOffset
- * @param {BufferSource} data
- * @param {number} [dataOffset]
- * @param {number} [size]
- */
- writeBuffer(buffer, bufferOffset, data, dataOffset = 0, size) {
- webidl.assertBranded(this, GPUQueuePrototype);
- const prefix = "Failed to execute 'writeBuffer' on 'GPUQueue'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- buffer = webidl.converters["GPUBuffer"](buffer, {
- prefix,
- context: "Argument 1",
- });
- bufferOffset = webidl.converters["GPUSize64"](bufferOffset, {
- prefix,
- context: "Argument 2",
- });
- data = webidl.converters.BufferSource(data, {
- prefix,
- context: "Argument 3",
- });
- dataOffset = webidl.converters["GPUSize64"](dataOffset, {
- prefix,
- context: "Argument 4",
- });
- size = size === undefined
- ? undefined
- : webidl.converters["GPUSize64"](size, {
- prefix,
- context: "Argument 5",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const bufferRid = assertResource(buffer, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, buffer, {
- prefix,
- selfContext: "this",
- resourceContext: "Argument 1",
- });
- const { err } = ops.op_webgpu_write_buffer(
- device.rid,
- bufferRid,
- bufferOffset,
- dataOffset,
- size,
- new Uint8Array(ArrayBufferIsView(data) ? data.buffer : data),
+ if (this[_state] !== "unmapped") {
+ throw new DOMException(
+ `${prefix}: GPUBuffer is not currently unmapped.`,
+ "OperationError",
);
- device.pushError(err);
}
-
- /**
- * @param {GPUImageCopyTexture} destination
- * @param {BufferSource} data
- * @param {GPUImageDataLayout} dataLayout
- * @param {GPUExtent3D} size
- */
- writeTexture(destination, data, dataLayout, size) {
- webidl.assertBranded(this, GPUQueuePrototype);
- const prefix = "Failed to execute 'writeTexture' on 'GPUQueue'";
- webidl.requiredArguments(arguments.length, 4, { prefix });
- destination = webidl.converters.GPUImageCopyTexture(destination, {
- prefix,
- context: "Argument 1",
- });
- data = webidl.converters.BufferSource(data, {
- prefix,
- context: "Argument 2",
- });
- dataLayout = webidl.converters.GPUImageDataLayout(dataLayout, {
- prefix,
- context: "Argument 3",
- });
- size = webidl.converters.GPUExtent3D(size, {
- prefix,
- context: "Argument 4",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const textureRid = assertResource(destination.texture, {
- prefix,
- context: "texture",
- });
- assertDeviceMatch(device, destination.texture, {
- prefix,
- selfContext: "this",
- resourceContext: "texture",
- });
- const { err } = ops.op_webgpu_write_texture(
- device.rid,
- {
- texture: textureRid,
- mipLevel: destination.mipLevel,
- origin: destination.origin
- ? normalizeGPUOrigin3D(destination.origin)
- : undefined,
- aspect: destination.aspect,
- },
- dataLayout,
- normalizeGPUExtent3D(size),
- new Uint8Array(ArrayBufferIsView(data) ? data.buffer : data),
+ const readMode = (mode & 0x0001) === 0x0001;
+ const writeMode = (mode & 0x0002) === 0x0002;
+ if ((readMode && writeMode) || (!readMode && !writeMode)) {
+ throw new DOMException(
+ `${prefix}: exactly one of READ or WRITE map mode must be set.`,
+ "OperationError",
);
- device.pushError(err);
}
-
- copyImageBitmapToTexture(_source, _destination, _copySize) {
- throw new Error("Not yet implemented");
+ if (readMode && !((this[_usage] && 0x0001) === 0x0001)) {
+ throw new DOMException(
+ `${prefix}: READ map mode not valid because buffer does not have MAP_READ usage.`,
+ "OperationError",
+ );
+ }
+ if (writeMode && !((this[_usage] && 0x0002) === 0x0002)) {
+ throw new DOMException(
+ `${prefix}: WRITE map mode not valid because buffer does not have MAP_WRITE usage.`,
+ "OperationError",
+ );
}
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
+ this[_mapMode] = mode;
+ this[_state] = "pending";
+ const promise = PromisePrototypeThen(
+ core.opAsync(
+ "op_webgpu_buffer_get_map_async",
+ bufferRid,
+ device.rid,
+ mode,
+ offset,
+ rangeSize,
+ ),
+ ({ err }) => err,
+ );
+ device.pushErrorPromise(promise);
+ const err = await promise;
+ if (err) {
+ throw new DOMException("validation error occured", "OperationError");
}
+ this[_state] = "mapped";
+ this[_mappingRange] = [offset, offset + rangeSize];
+ /** @type {[ArrayBuffer, number, number][] | null} */
+ this[_mappedRanges] = [];
}
- GPUObjectBaseMixin("GPUQueue", GPUQueue);
- const GPUQueuePrototype = GPUQueue.prototype;
/**
- * @typedef CreateGPUBufferOptions
- * @property {ArrayBuffer | null} mapping
- * @property {number[] | null} mappingRange
- * @property {[ArrayBuffer, number, number][] | null} mappedRanges
- * @property {"mapped" | "mapped at creation" | "mapped pending" | "unmapped" | "destroy" } state
- */
-
- /**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
+ * @param {number} offset
* @param {number} size
- * @param {number} usage
- * @param {CreateGPUBufferOptions} options
- * @returns {GPUBuffer}
*/
- function createGPUBuffer(label, device, rid, size, usage, options) {
- /** @type {GPUBuffer} */
- const buffer = webidl.createBranded(GPUBuffer);
- buffer[_label] = label;
- buffer[_device] = device;
- buffer[_rid] = rid;
- buffer[_size] = size;
- buffer[_usage] = usage;
- buffer[_mappingRange] = options.mappingRange;
- buffer[_mappedRanges] = options.mappedRanges;
- buffer[_state] = options.state;
- return buffer;
- }
-
- class GPUBuffer {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number} */
- [_rid];
- /** @type {number} */
- [_size];
- /** @type {number} */
- [_usage];
- /** @type {"mapped" | "mapped at creation" | "pending" | "unmapped" | "destroy"} */
- [_state];
- /** @type {[number, number] | null} */
- [_mappingRange];
- /** @type {[ArrayBuffer, number, number][] | null} */
- [_mappedRanges];
- /** @type {number} */
- [_mapMode];
-
- [_cleanup]() {
- const mappedRanges = this[_mappedRanges];
- if (mappedRanges) {
- while (mappedRanges.length > 0) {
- const mappedRange = ArrayPrototypePop(mappedRanges);
- if (mappedRange !== undefined) {
- core.close(mappedRange[1]);
- }
- }
- }
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- this[_state] = "destroy";
- }
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- get size() {
- webidl.assertBranded(this, GPUBufferPrototype);
- return this[_size];
+ getMappedRange(offset = 0, size) {
+ webidl.assertBranded(this, GPUBufferPrototype);
+ const prefix = "Failed to execute 'getMappedRange' on 'GPUBuffer'";
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 1",
+ });
+ if (size !== undefined) {
+ size = webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 2",
+ });
}
-
- get usage() {
- webidl.assertBranded(this, GPUBufferPrototype);
- return this[_usage];
+ assertDevice(this, { prefix, context: "this" });
+ const bufferRid = assertResource(this, { prefix, context: "this" });
+ /** @type {number} */
+ let rangeSize;
+ if (size === undefined) {
+ rangeSize = MathMax(0, this[_size] - offset);
+ } else {
+ rangeSize = size;
}
- get mapState() {
- webidl.assertBranded(this, GPUBufferPrototype);
- const state = this[_state];
- if (state === "mapped at creation") {
- return "mapped";
- } else {
- return state;
- }
+ const mappedRanges = this[_mappedRanges];
+ if (!mappedRanges) {
+ throw new DOMException(`${prefix}: invalid state.`, "OperationError");
}
-
- /**
- * @param {number} mode
- * @param {number} offset
- * @param {number} [size]
- */
- async mapAsync(mode, offset = 0, size) {
- webidl.assertBranded(this, GPUBufferPrototype);
- const prefix = "Failed to execute 'mapAsync' on 'GPUBuffer'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- mode = webidl.converters.GPUMapModeFlags(mode, {
- prefix,
- context: "Argument 1",
- });
- offset = webidl.converters.GPUSize64(offset, {
- prefix,
- context: "Argument 2",
- });
- size = size === undefined
- ? undefined
- : webidl.converters.GPUSize64(size, {
- prefix,
- context: "Argument 3",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const bufferRid = assertResource(this, { prefix, context: "this" });
- /** @type {number} */
- let rangeSize;
- if (size === undefined) {
- rangeSize = MathMax(0, this[_size] - offset);
- } else {
- rangeSize = this[_size];
- }
- if ((offset % 8) !== 0) {
- throw new DOMException(
- `${prefix}: offset must be a multiple of 8.`,
- "OperationError",
- );
- }
- if ((rangeSize % 4) !== 0) {
- throw new DOMException(
- `${prefix}: rangeSize must be a multiple of 4.`,
- "OperationError",
- );
- }
- if ((offset + rangeSize) > this[_size]) {
- throw new DOMException(
- `${prefix}: offset + rangeSize must be less than or equal to buffer size.`,
- "OperationError",
- );
- }
- if (this[_state] !== "unmapped") {
- throw new DOMException(
- `${prefix}: GPUBuffer is not currently unmapped.`,
- "OperationError",
- );
- }
- const readMode = (mode & 0x0001) === 0x0001;
- const writeMode = (mode & 0x0002) === 0x0002;
- if ((readMode && writeMode) || (!readMode && !writeMode)) {
- throw new DOMException(
- `${prefix}: exactly one of READ or WRITE map mode must be set.`,
- "OperationError",
- );
- }
- if (readMode && !((this[_usage] && 0x0001) === 0x0001)) {
- throw new DOMException(
- `${prefix}: READ map mode not valid because buffer does not have MAP_READ usage.`,
- "OperationError",
- );
- }
- if (writeMode && !((this[_usage] && 0x0002) === 0x0002)) {
+ for (let i = 0; i < mappedRanges.length; ++i) {
+ const { 0: buffer, /* 1: rid, */ 2: start } = mappedRanges[i];
+ // TODO(lucacasonato): is this logic correct?
+ const end = start + buffer.byteLength;
+ if (
+ (start >= offset && start < (offset + rangeSize)) ||
+ (end >= offset && end < (offset + rangeSize))
+ ) {
throw new DOMException(
- `${prefix}: WRITE map mode not valid because buffer does not have MAP_WRITE usage.`,
+ `${prefix}: requested buffer overlaps with another mapped range.`,
"OperationError",
);
}
-
- this[_mapMode] = mode;
- this[_state] = "pending";
- const promise = PromisePrototypeThen(
- core.opAsync(
- "op_webgpu_buffer_get_map_async",
- bufferRid,
- device.rid,
- mode,
- offset,
- rangeSize,
- ),
- ({ err }) => err,
- );
- device.pushErrorPromise(promise);
- const err = await promise;
- if (err) {
- throw new DOMException("validation error occured", "OperationError");
- }
- this[_state] = "mapped";
- this[_mappingRange] = [offset, offset + rangeSize];
- /** @type {[ArrayBuffer, number, number][] | null} */
- this[_mappedRanges] = [];
}
- /**
- * @param {number} offset
- * @param {number} size
- */
- getMappedRange(offset = 0, size) {
- webidl.assertBranded(this, GPUBufferPrototype);
- const prefix = "Failed to execute 'getMappedRange' on 'GPUBuffer'";
- offset = webidl.converters.GPUSize64(offset, {
- prefix,
- context: "Argument 1",
- });
- if (size !== undefined) {
- size = webidl.converters.GPUSize64(size, {
- prefix,
- context: "Argument 2",
- });
- }
- assertDevice(this, { prefix, context: "this" });
- const bufferRid = assertResource(this, { prefix, context: "this" });
- /** @type {number} */
- let rangeSize;
- if (size === undefined) {
- rangeSize = MathMax(0, this[_size] - offset);
- } else {
- rangeSize = size;
- }
+ const buffer = new ArrayBuffer(rangeSize);
+ const { rid } = ops.op_webgpu_buffer_get_mapped_range(
+ bufferRid,
+ offset,
+ size,
+ new Uint8Array(buffer),
+ );
- const mappedRanges = this[_mappedRanges];
- if (!mappedRanges) {
- throw new DOMException(`${prefix}: invalid state.`, "OperationError");
- }
- for (let i = 0; i < mappedRanges.length; ++i) {
- const { 0: buffer, /* 1: rid, */ 2: start } = mappedRanges[i];
- // TODO(lucacasonato): is this logic correct?
- const end = start + buffer.byteLength;
- if (
- (start >= offset && start < (offset + rangeSize)) ||
- (end >= offset && end < (offset + rangeSize))
- ) {
+ ArrayPrototypePush(mappedRanges, [buffer, rid, offset]);
+
+ return buffer;
+ }
+
+ unmap() {
+ webidl.assertBranded(this, GPUBufferPrototype);
+ const prefix = "Failed to execute 'unmap' on 'GPUBuffer'";
+ const device = assertDevice(this, { prefix, context: "this" });
+ const bufferRid = assertResource(this, { prefix, context: "this" });
+ if (this[_state] === "unmapped" || this[_state] === "destroyed") {
+ throw new DOMException(
+ `${prefix}: buffer is not ready to be unmapped.`,
+ "OperationError",
+ );
+ }
+ if (this[_state] === "pending") {
+ // TODO(lucacasonato): this is not spec compliant.
+ throw new DOMException(
+ `${prefix}: can not unmap while mapping. This is a Deno limitation.`,
+ "OperationError",
+ );
+ } else if (
+ this[_state] === "mapped" || this[_state] === "mapped at creation"
+ ) {
+ /** @type {boolean} */
+ let write = false;
+ if (this[_state] === "mapped at creation") {
+ write = true;
+ } else if (this[_state] === "mapped") {
+ const mapMode = this[_mapMode];
+ if (mapMode === undefined) {
throw new DOMException(
- `${prefix}: requested buffer overlaps with another mapped range.`,
+ `${prefix}: invalid state.`,
"OperationError",
);
}
+ if ((mapMode & 0x0002) === 0x0002) {
+ write = true;
+ }
}
- const buffer = new ArrayBuffer(rangeSize);
- const { rid } = ops.op_webgpu_buffer_get_mapped_range(
- bufferRid,
- offset,
- size,
- new Uint8Array(buffer),
- );
-
- ArrayPrototypePush(mappedRanges, [buffer, rid, offset]);
-
- return buffer;
- }
-
- unmap() {
- webidl.assertBranded(this, GPUBufferPrototype);
- const prefix = "Failed to execute 'unmap' on 'GPUBuffer'";
- const device = assertDevice(this, { prefix, context: "this" });
- const bufferRid = assertResource(this, { prefix, context: "this" });
- if (this[_state] === "unmapped" || this[_state] === "destroyed") {
- throw new DOMException(
- `${prefix}: buffer is not ready to be unmapped.`,
- "OperationError",
- );
+ const mappedRanges = this[_mappedRanges];
+ if (!mappedRanges) {
+ throw new DOMException(`${prefix}: invalid state.`, "OperationError");
}
- if (this[_state] === "pending") {
- // TODO(lucacasonato): this is not spec compliant.
- throw new DOMException(
- `${prefix}: can not unmap while mapping. This is a Deno limitation.`,
- "OperationError",
+ for (let i = 0; i < mappedRanges.length; ++i) {
+ const { 0: buffer, 1: mappedRid } = mappedRanges[i];
+ const { err } = ops.op_webgpu_buffer_unmap(
+ bufferRid,
+ mappedRid,
+ ...new SafeArrayIterator(write ? [new Uint8Array(buffer)] : []),
);
- } else if (
- this[_state] === "mapped" || this[_state] === "mapped at creation"
- ) {
- /** @type {boolean} */
- let write = false;
- if (this[_state] === "mapped at creation") {
- write = true;
- } else if (this[_state] === "mapped") {
- const mapMode = this[_mapMode];
- if (mapMode === undefined) {
- throw new DOMException(
- `${prefix}: invalid state.`,
- "OperationError",
- );
- }
- if ((mapMode & 0x0002) === 0x0002) {
- write = true;
- }
- }
-
- const mappedRanges = this[_mappedRanges];
- if (!mappedRanges) {
- throw new DOMException(`${prefix}: invalid state.`, "OperationError");
- }
- for (let i = 0; i < mappedRanges.length; ++i) {
- const { 0: buffer, 1: mappedRid } = mappedRanges[i];
- const { err } = ops.op_webgpu_buffer_unmap(
- bufferRid,
- mappedRid,
- ...new SafeArrayIterator(write ? [new Uint8Array(buffer)] : []),
- );
- device.pushError(err);
- if (err) return;
- }
- this[_mappingRange] = null;
- this[_mappedRanges] = null;
+ device.pushError(err);
+ if (err) return;
}
-
- this[_state] = "unmapped";
+ this[_mappingRange] = null;
+ this[_mappedRanges] = null;
}
- destroy() {
- webidl.assertBranded(this, GPUBufferPrototype);
- this[_cleanup]();
- }
-
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ this[_state] = "unmapped";
}
- GPUObjectBaseMixin("GPUBuffer", GPUBuffer);
- const GPUBufferPrototype = GPUBuffer.prototype;
-
- class GPUBufferUsage {
- constructor() {
- webidl.illegalConstructor();
- }
- static get MAP_READ() {
- return 0x0001;
- }
- static get MAP_WRITE() {
- return 0x0002;
- }
- static get COPY_SRC() {
- return 0x0004;
- }
- static get COPY_DST() {
- return 0x0008;
- }
- static get INDEX() {
- return 0x0010;
- }
- static get VERTEX() {
- return 0x0020;
- }
- static get UNIFORM() {
- return 0x0040;
- }
- static get STORAGE() {
- return 0x0080;
- }
- static get INDIRECT() {
- return 0x0100;
- }
- static get QUERY_RESOLVE() {
- return 0x0200;
- }
+ destroy() {
+ webidl.assertBranded(this, GPUBufferPrototype);
+ this[_cleanup]();
}
- class GPUMapMode {
- constructor() {
- webidl.illegalConstructor();
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUBuffer", GPUBuffer);
+const GPUBufferPrototype = GPUBuffer.prototype;
- static get READ() {
- return 0x0001;
- }
- static get WRITE() {
- return 0x0002;
- }
+class GPUBufferUsage {
+ constructor() {
+ webidl.illegalConstructor();
}
- /**
- * @param {GPUTextureDescriptor} descriptor
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPUTexture}
- */
- function createGPUTexture(descriptor, device, rid) {
- /** @type {GPUTexture} */
- const texture = webidl.createBranded(GPUTexture);
- texture[_label] = descriptor.label;
- texture[_device] = device;
- texture[_rid] = rid;
- texture[_views] = [];
- texture[_width] = descriptor.size.width;
- texture[_height] = descriptor.size.height;
- texture[_depthOrArrayLayers] = descriptor.size.depthOrArrayLayers;
- texture[_mipLevelCount] = descriptor.mipLevelCount;
- texture[_sampleCount] = descriptor.sampleCount;
- texture[_dimension] = descriptor.dimension;
- texture[_format] = descriptor.format;
- texture[_usage] = descriptor.usage;
- return texture;
+ static get MAP_READ() {
+ return 0x0001;
+ }
+ static get MAP_WRITE() {
+ return 0x0002;
+ }
+ static get COPY_SRC() {
+ return 0x0004;
+ }
+ static get COPY_DST() {
+ return 0x0008;
}
+ static get INDEX() {
+ return 0x0010;
+ }
+ static get VERTEX() {
+ return 0x0020;
+ }
+ static get UNIFORM() {
+ return 0x0040;
+ }
+ static get STORAGE() {
+ return 0x0080;
+ }
+ static get INDIRECT() {
+ return 0x0100;
+ }
+ static get QUERY_RESOLVE() {
+ return 0x0200;
+ }
+}
- class GPUTexture {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
- /** @type {WeakRef<GPUTextureView>[]} */
- [_views];
+class GPUMapMode {
+ constructor() {
+ webidl.illegalConstructor();
+ }
- /** @type {number} */
- [_width];
- /** @type {number} */
- [_height];
- /** @type {number} */
- [_depthOrArrayLayers];
- /** @type {number} */
- [_mipLevelCount];
- /** @type {number} */
- [_sampleCount];
- /** @type {GPUTextureDimension} */
- [_dimension];
- /** @type {GPUTextureFormat} */
- [_format];
- /** @type {number} */
- [_usage];
-
- [_cleanup]() {
- const views = this[_views];
- while (views.length > 0) {
- const view = ArrayPrototypePop(views)?.deref();
- if (view) {
- view[_cleanup]();
- }
- }
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
+ static get READ() {
+ return 0x0001;
+ }
+ static get WRITE() {
+ return 0x0002;
+ }
+}
+
+/**
+ * @param {GPUTextureDescriptor} descriptor
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUTexture}
+ */
+function createGPUTexture(descriptor, device, rid) {
+ /** @type {GPUTexture} */
+ const texture = webidl.createBranded(GPUTexture);
+ texture[_label] = descriptor.label;
+ texture[_device] = device;
+ texture[_rid] = rid;
+ texture[_views] = [];
+ texture[_width] = descriptor.size.width;
+ texture[_height] = descriptor.size.height;
+ texture[_depthOrArrayLayers] = descriptor.size.depthOrArrayLayers;
+ texture[_mipLevelCount] = descriptor.mipLevelCount;
+ texture[_sampleCount] = descriptor.sampleCount;
+ texture[_dimension] = descriptor.dimension;
+ texture[_format] = descriptor.format;
+ texture[_usage] = descriptor.usage;
+ return texture;
+}
+
+class GPUTexture {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+ /** @type {WeakRef<GPUTextureView>[]} */
+ [_views];
+
+ /** @type {number} */
+ [_width];
+ /** @type {number} */
+ [_height];
+ /** @type {number} */
+ [_depthOrArrayLayers];
+ /** @type {number} */
+ [_mipLevelCount];
+ /** @type {number} */
+ [_sampleCount];
+ /** @type {GPUTextureDimension} */
+ [_dimension];
+ /** @type {GPUTextureFormat} */
+ [_format];
+ /** @type {number} */
+ [_usage];
+
+ [_cleanup]() {
+ const views = this[_views];
+ while (views.length > 0) {
+ const view = ArrayPrototypePop(views)?.deref();
+ if (view) {
+ view[_cleanup]();
}
}
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- /**
- * @param {GPUTextureViewDescriptor} descriptor
- */
- createView(descriptor = {}) {
- webidl.assertBranded(this, GPUTexturePrototype);
- const prefix = "Failed to execute 'createView' on 'GPUTexture'";
- webidl.requiredArguments(arguments.length, 0, { prefix });
- descriptor = webidl.converters.GPUTextureViewDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const textureRid = assertResource(this, { prefix, context: "this" });
- const { rid, err } = ops.op_webgpu_create_texture_view({
- textureRid,
- ...descriptor,
- });
- device.pushError(err);
-
- const textureView = createGPUTextureView(
- descriptor.label,
- this,
- rid,
- );
- ArrayPrototypePush(this[_views], new WeakRef(textureView));
- return textureView;
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ }
- destroy() {
- webidl.assertBranded(this, GPUTexturePrototype);
- this[_cleanup]();
- }
+ constructor() {
+ webidl.illegalConstructor();
+ }
- get width() {
- webidl.assertBranded(this, GPUTexturePrototype);
- return this[_width];
- }
+ /**
+ * @param {GPUTextureViewDescriptor} descriptor
+ */
+ createView(descriptor = {}) {
+ webidl.assertBranded(this, GPUTexturePrototype);
+ const prefix = "Failed to execute 'createView' on 'GPUTexture'";
+ webidl.requiredArguments(arguments.length, 0, { prefix });
+ descriptor = webidl.converters.GPUTextureViewDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const textureRid = assertResource(this, { prefix, context: "this" });
+ const { rid, err } = ops.op_webgpu_create_texture_view({
+ textureRid,
+ ...descriptor,
+ });
+ device.pushError(err);
- get height() {
- webidl.assertBranded(this, GPUTexturePrototype);
- return this[_height];
- }
+ const textureView = createGPUTextureView(
+ descriptor.label,
+ this,
+ rid,
+ );
+ ArrayPrototypePush(this[_views], new WeakRef(textureView));
+ return textureView;
+ }
- get depthOrArrayLayers() {
- webidl.assertBranded(this, GPUTexturePrototype);
- return this[_depthOrArrayLayers];
- }
+ destroy() {
+ webidl.assertBranded(this, GPUTexturePrototype);
+ this[_cleanup]();
+ }
- get mipLevelCount() {
- webidl.assertBranded(this, GPUTexturePrototype);
- return this[_mipLevelCount];
- }
+ get width() {
+ webidl.assertBranded(this, GPUTexturePrototype);
+ return this[_width];
+ }
- get sampleCount() {
- webidl.assertBranded(this, GPUTexturePrototype);
- return this[_sampleCount];
- }
+ get height() {
+ webidl.assertBranded(this, GPUTexturePrototype);
+ return this[_height];
+ }
- get dimension() {
- webidl.assertBranded(this, GPUTexturePrototype);
- return this[_dimension];
- }
+ get depthOrArrayLayers() {
+ webidl.assertBranded(this, GPUTexturePrototype);
+ return this[_depthOrArrayLayers];
+ }
- get format() {
- webidl.assertBranded(this, GPUTexturePrototype);
- return this[_format];
- }
+ get mipLevelCount() {
+ webidl.assertBranded(this, GPUTexturePrototype);
+ return this[_mipLevelCount];
+ }
- get usage() {
- webidl.assertBranded(this, GPUTexturePrototype);
- return this[_usage];
- }
+ get sampleCount() {
+ webidl.assertBranded(this, GPUTexturePrototype);
+ return this[_sampleCount];
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ get dimension() {
+ webidl.assertBranded(this, GPUTexturePrototype);
+ return this[_dimension];
}
- GPUObjectBaseMixin("GPUTexture", GPUTexture);
- const GPUTexturePrototype = GPUTexture.prototype;
- class GPUTextureUsage {
- constructor() {
- webidl.illegalConstructor();
- }
+ get format() {
+ webidl.assertBranded(this, GPUTexturePrototype);
+ return this[_format];
+ }
- static get COPY_SRC() {
- return 0x01;
- }
- static get COPY_DST() {
- return 0x02;
- }
- static get TEXTURE_BINDING() {
- return 0x04;
- }
- static get STORAGE_BINDING() {
- return 0x08;
- }
- static get RENDER_ATTACHMENT() {
- return 0x10;
- }
+ get usage() {
+ webidl.assertBranded(this, GPUTexturePrototype);
+ return this[_usage];
}
- /**
- * @param {string | null} label
- * @param {GPUTexture} texture
- * @param {number} rid
- * @returns {GPUTextureView}
- */
- function createGPUTextureView(label, texture, rid) {
- /** @type {GPUTextureView} */
- const textureView = webidl.createBranded(GPUTextureView);
- textureView[_label] = label;
- textureView[_texture] = texture;
- textureView[_rid] = rid;
- return textureView;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
}
- class GPUTextureView {
- /** @type {GPUTexture} */
- [_texture];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
+}
+GPUObjectBaseMixin("GPUTexture", GPUTexture);
+const GPUTexturePrototype = GPUTexture.prototype;
- constructor() {
- webidl.illegalConstructor();
- }
+class GPUTextureUsage {
+ constructor() {
+ webidl.illegalConstructor();
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ static get COPY_SRC() {
+ return 0x01;
}
- GPUObjectBaseMixin("GPUTextureView", GPUTextureView);
- const GPUTextureViewPrototype = GPUTextureView.prototype;
- /**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPUSampler}
- */
- function createGPUSampler(label, device, rid) {
- /** @type {GPUSampler} */
- const sampler = webidl.createBranded(GPUSampler);
- sampler[_label] = label;
- sampler[_device] = device;
- sampler[_rid] = rid;
- return sampler;
+ static get COPY_DST() {
+ return 0x02;
}
- class GPUSampler {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
-
- constructor() {
- webidl.illegalConstructor();
+ static get TEXTURE_BINDING() {
+ return 0x04;
+ }
+ static get STORAGE_BINDING() {
+ return 0x08;
+ }
+ static get RENDER_ATTACHMENT() {
+ return 0x10;
+ }
+}
+
+/**
+ * @param {string | null} label
+ * @param {GPUTexture} texture
+ * @param {number} rid
+ * @returns {GPUTextureView}
+ */
+function createGPUTextureView(label, texture, rid) {
+ /** @type {GPUTextureView} */
+ const textureView = webidl.createBranded(GPUTextureView);
+ textureView[_label] = label;
+ textureView[_texture] = texture;
+ textureView[_rid] = rid;
+ return textureView;
+}
+class GPUTextureView {
+ /** @type {GPUTexture} */
+ [_texture];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ constructor() {
+ webidl.illegalConstructor();
}
- GPUObjectBaseMixin("GPUSampler", GPUSampler);
- const GPUSamplerPrototype = GPUSampler.prototype;
- /**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPUBindGroupLayout}
- */
- function createGPUBindGroupLayout(label, device, rid) {
- /** @type {GPUBindGroupLayout} */
- const bindGroupLayout = webidl.createBranded(GPUBindGroupLayout);
- bindGroupLayout[_label] = label;
- bindGroupLayout[_device] = device;
- bindGroupLayout[_rid] = rid;
- return bindGroupLayout;
+
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
}
- class GPUBindGroupLayout {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
+}
+GPUObjectBaseMixin("GPUTextureView", GPUTextureView);
+const GPUTextureViewPrototype = GPUTextureView.prototype;
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUSampler}
+ */
+function createGPUSampler(label, device, rid) {
+ /** @type {GPUSampler} */
+ const sampler = webidl.createBranded(GPUSampler);
+ sampler[_label] = label;
+ sampler[_device] = device;
+ sampler[_rid] = rid;
+ return sampler;
+}
+class GPUSampler {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ }
- constructor() {
- webidl.illegalConstructor();
- }
+ constructor() {
+ webidl.illegalConstructor();
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUSampler", GPUSampler);
+const GPUSamplerPrototype = GPUSampler.prototype;
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUBindGroupLayout}
+ */
+function createGPUBindGroupLayout(label, device, rid) {
+ /** @type {GPUBindGroupLayout} */
+ const bindGroupLayout = webidl.createBranded(GPUBindGroupLayout);
+ bindGroupLayout[_label] = label;
+ bindGroupLayout[_device] = device;
+ bindGroupLayout[_rid] = rid;
+ return bindGroupLayout;
+}
+class GPUBindGroupLayout {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
}
- GPUObjectBaseMixin("GPUBindGroupLayout", GPUBindGroupLayout);
- /**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPUPipelineLayout}
- */
- function createGPUPipelineLayout(label, device, rid) {
- /** @type {GPUPipelineLayout} */
- const pipelineLayout = webidl.createBranded(GPUPipelineLayout);
- pipelineLayout[_label] = label;
- pipelineLayout[_device] = device;
- pipelineLayout[_rid] = rid;
- return pipelineLayout;
+ constructor() {
+ webidl.illegalConstructor();
}
- class GPUPipelineLayout {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
- constructor() {
- webidl.illegalConstructor();
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUBindGroupLayout", GPUBindGroupLayout);
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUPipelineLayout}
+ */
+function createGPUPipelineLayout(label, device, rid) {
+ /** @type {GPUPipelineLayout} */
+ const pipelineLayout = webidl.createBranded(GPUPipelineLayout);
+ pipelineLayout[_label] = label;
+ pipelineLayout[_device] = device;
+ pipelineLayout[_rid] = rid;
+ return pipelineLayout;
+}
+class GPUPipelineLayout {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ constructor() {
+ webidl.illegalConstructor();
}
- GPUObjectBaseMixin("GPUPipelineLayout", GPUPipelineLayout);
- /**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPUBindGroup}
- */
- function createGPUBindGroup(label, device, rid) {
- /** @type {GPUBindGroup} */
- const bindGroup = webidl.createBranded(GPUBindGroup);
- bindGroup[_label] = label;
- bindGroup[_device] = device;
- bindGroup[_rid] = rid;
- return bindGroup;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
}
- class GPUBindGroup {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
+}
+GPUObjectBaseMixin("GPUPipelineLayout", GPUPipelineLayout);
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUBindGroup}
+ */
+function createGPUBindGroup(label, device, rid) {
+ /** @type {GPUBindGroup} */
+ const bindGroup = webidl.createBranded(GPUBindGroup);
+ bindGroup[_label] = label;
+ bindGroup[_device] = device;
+ bindGroup[_rid] = rid;
+ return bindGroup;
+}
+class GPUBindGroup {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ }
- constructor() {
- webidl.illegalConstructor();
- }
+ constructor() {
+ webidl.illegalConstructor();
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUBindGroup", GPUBindGroup);
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUShaderModule}
+ */
+function createGPUShaderModule(label, device, rid) {
+ /** @type {GPUShaderModule} */
+ const bindGroup = webidl.createBranded(GPUShaderModule);
+ bindGroup[_label] = label;
+ bindGroup[_device] = device;
+ bindGroup[_rid] = rid;
+ return bindGroup;
+}
+class GPUShaderModule {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
}
- GPUObjectBaseMixin("GPUBindGroup", GPUBindGroup);
- /**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPUShaderModule}
- */
- function createGPUShaderModule(label, device, rid) {
- /** @type {GPUShaderModule} */
- const bindGroup = webidl.createBranded(GPUShaderModule);
- bindGroup[_label] = label;
- bindGroup[_device] = device;
- bindGroup[_rid] = rid;
- return bindGroup;
+ constructor() {
+ webidl.illegalConstructor();
}
- class GPUShaderModule {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
- constructor() {
- webidl.illegalConstructor();
- }
+ compilationInfo() {
+ throw new Error("Not yet implemented");
+ }
- compilationInfo() {
- throw new Error("Not yet implemented");
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUShaderModule", GPUShaderModule);
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+class GPUShaderStage {
+ constructor() {
+ webidl.illegalConstructor();
}
- GPUObjectBaseMixin("GPUShaderModule", GPUShaderModule);
- class GPUShaderStage {
- constructor() {
- webidl.illegalConstructor();
- }
+ static get VERTEX() {
+ return 0x1;
+ }
- static get VERTEX() {
- return 0x1;
- }
+ static get FRAGMENT() {
+ return 0x2;
+ }
- static get FRAGMENT() {
- return 0x2;
+ static get COMPUTE() {
+ return 0x4;
+ }
+}
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUComputePipeline}
+ */
+function createGPUComputePipeline(label, device, rid) {
+ /** @type {GPUComputePipeline} */
+ const pipeline = webidl.createBranded(GPUComputePipeline);
+ pipeline[_label] = label;
+ pipeline[_device] = device;
+ pipeline[_rid] = rid;
+ return pipeline;
+}
+class GPUComputePipeline {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ }
- static get COMPUTE() {
- return 0x4;
- }
+ constructor() {
+ webidl.illegalConstructor();
}
/**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPUComputePipeline}
+ * @param {number} index
+ * @returns {GPUBindGroupLayout}
*/
- function createGPUComputePipeline(label, device, rid) {
- /** @type {GPUComputePipeline} */
- const pipeline = webidl.createBranded(GPUComputePipeline);
- pipeline[_label] = label;
- pipeline[_device] = device;
- pipeline[_rid] = rid;
- return pipeline;
- }
- class GPUComputePipeline {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
-
- constructor() {
- webidl.illegalConstructor();
- }
+ getBindGroupLayout(index) {
+ webidl.assertBranded(this, GPUComputePipelinePrototype);
+ const prefix =
+ "Failed to execute 'getBindGroupLayout' on 'GPUComputePipeline'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ index = webidl.converters["unsigned long"](index, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const computePipelineRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { rid, label, err } = ops
+ .op_webgpu_compute_pipeline_get_bind_group_layout(
+ computePipelineRid,
+ index,
+ );
+ device.pushError(err);
- /**
- * @param {number} index
- * @returns {GPUBindGroupLayout}
- */
- getBindGroupLayout(index) {
- webidl.assertBranded(this, GPUComputePipelinePrototype);
- const prefix =
- "Failed to execute 'getBindGroupLayout' on 'GPUComputePipeline'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- index = webidl.converters["unsigned long"](index, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const computePipelineRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const { rid, label, err } = ops
- .op_webgpu_compute_pipeline_get_bind_group_layout(
- computePipelineRid,
- index,
- );
- device.pushError(err);
+ const bindGroupLayout = createGPUBindGroupLayout(
+ label,
+ device,
+ rid,
+ );
+ device.trackResource(bindGroupLayout);
+ return bindGroupLayout;
+ }
- const bindGroupLayout = createGPUBindGroupLayout(
- label,
- device,
- rid,
- );
- device.trackResource(bindGroupLayout);
- return bindGroupLayout;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUComputePipeline", GPUComputePipeline);
+const GPUComputePipelinePrototype = GPUComputePipeline.prototype;
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPURenderPipeline}
+ */
+function createGPURenderPipeline(label, device, rid) {
+ /** @type {GPURenderPipeline} */
+ const pipeline = webidl.createBranded(GPURenderPipeline);
+ pipeline[_label] = label;
+ pipeline[_device] = device;
+ pipeline[_rid] = rid;
+ return pipeline;
+}
+class GPURenderPipeline {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ constructor() {
+ webidl.illegalConstructor();
}
- GPUObjectBaseMixin("GPUComputePipeline", GPUComputePipeline);
- const GPUComputePipelinePrototype = GPUComputePipeline.prototype;
/**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPURenderPipeline}
+ * @param {number} index
*/
- function createGPURenderPipeline(label, device, rid) {
- /** @type {GPURenderPipeline} */
- const pipeline = webidl.createBranded(GPURenderPipeline);
- pipeline[_label] = label;
- pipeline[_device] = device;
- pipeline[_rid] = rid;
- return pipeline;
- }
- class GPURenderPipeline {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- /**
- * @param {number} index
- */
- getBindGroupLayout(index) {
- webidl.assertBranded(this, GPURenderPipelinePrototype);
- const prefix =
- "Failed to execute 'getBindGroupLayout' on 'GPURenderPipeline'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- index = webidl.converters["unsigned long"](index, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const renderPipelineRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const { rid, label, err } = ops
- .op_webgpu_render_pipeline_get_bind_group_layout(
- renderPipelineRid,
- index,
- );
- device.pushError(err);
-
- const bindGroupLayout = createGPUBindGroupLayout(
- label,
- device,
- rid,
+ getBindGroupLayout(index) {
+ webidl.assertBranded(this, GPURenderPipelinePrototype);
+ const prefix =
+ "Failed to execute 'getBindGroupLayout' on 'GPURenderPipeline'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ index = webidl.converters["unsigned long"](index, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderPipelineRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { rid, label, err } = ops
+ .op_webgpu_render_pipeline_get_bind_group_layout(
+ renderPipelineRid,
+ index,
);
- device.trackResource(bindGroupLayout);
- return bindGroupLayout;
- }
+ device.pushError(err);
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ const bindGroupLayout = createGPUBindGroupLayout(
+ label,
+ device,
+ rid,
+ );
+ device.trackResource(bindGroupLayout);
+ return bindGroupLayout;
}
- GPUObjectBaseMixin("GPURenderPipeline", GPURenderPipeline);
- const GPURenderPipelinePrototype = GPURenderPipeline.prototype;
- class GPUColorWrite {
- constructor() {
- webidl.illegalConstructor();
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPURenderPipeline", GPURenderPipeline);
+const GPURenderPipelinePrototype = GPURenderPipeline.prototype;
- static get RED() {
- return 0x1;
- }
- static get GREEN() {
- return 0x2;
- }
- static get BLUE() {
- return 0x4;
- }
- static get ALPHA() {
- return 0x8;
+class GPUColorWrite {
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ static get RED() {
+ return 0x1;
+ }
+ static get GREEN() {
+ return 0x2;
+ }
+ static get BLUE() {
+ return 0x4;
+ }
+ static get ALPHA() {
+ return 0x8;
+ }
+ static get ALL() {
+ return 0xF;
+ }
+}
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUCommandEncoder}
+ */
+function createGPUCommandEncoder(label, device, rid) {
+ /** @type {GPUCommandEncoder} */
+ const encoder = webidl.createBranded(GPUCommandEncoder);
+ encoder[_label] = label;
+ encoder[_device] = device;
+ encoder[_rid] = rid;
+ encoder[_encoders] = [];
+ return encoder;
+}
+class GPUCommandEncoder {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+ /** @type {WeakRef<GPURenderPassEncoder | GPUComputePassEncoder>[]} */
+ [_encoders];
+
+ [_cleanup]() {
+ const encoders = this[_encoders];
+ while (encoders.length > 0) {
+ const encoder = ArrayPrototypePop(encoders)?.deref();
+ if (encoder) {
+ encoder[_cleanup]();
+ }
}
- static get ALL() {
- return 0xF;
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
}
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
/**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPUCommandEncoder}
+ * @param {GPURenderPassDescriptor} descriptor
+ * @return {GPURenderPassEncoder}
*/
- function createGPUCommandEncoder(label, device, rid) {
- /** @type {GPUCommandEncoder} */
- const encoder = webidl.createBranded(GPUCommandEncoder);
- encoder[_label] = label;
- encoder[_device] = device;
- encoder[_rid] = rid;
- encoder[_encoders] = [];
- return encoder;
- }
- class GPUCommandEncoder {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
- /** @type {WeakRef<GPURenderPassEncoder | GPUComputePassEncoder>[]} */
- [_encoders];
-
- [_cleanup]() {
- const encoders = this[_encoders];
- while (encoders.length > 0) {
- const encoder = ArrayPrototypePop(encoders)?.deref();
- if (encoder) {
- encoder[_cleanup]();
- }
- }
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
+ beginRenderPass(descriptor) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix = "Failed to execute 'beginRenderPass' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPURenderPassDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
- constructor() {
- webidl.illegalConstructor();
+ if (this[_rid] === undefined) {
+ throw new DOMException(
+ "Failed to execute 'beginRenderPass' on 'GPUCommandEncoder': already consumed",
+ "OperationError",
+ );
}
- /**
- * @param {GPURenderPassDescriptor} descriptor
- * @return {GPURenderPassEncoder}
- */
- beginRenderPass(descriptor) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix =
- "Failed to execute 'beginRenderPass' on 'GPUCommandEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- descriptor = webidl.converters.GPURenderPassDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
+ let depthStencilAttachment;
+ if (descriptor.depthStencilAttachment) {
+ const view = assertResource(descriptor.depthStencilAttachment.view, {
prefix,
- context: "this",
+ context: "texture view for depth stencil attachment",
});
+ assertDeviceMatch(
+ device,
+ descriptor.depthStencilAttachment.view[_texture],
+ {
+ prefix,
+ resourceContext: "texture view for depth stencil attachment",
+ selfContext: "this",
+ },
+ );
- if (this[_rid] === undefined) {
- throw new DOMException(
- "Failed to execute 'beginRenderPass' on 'GPUCommandEncoder': already consumed",
- "OperationError",
- );
- }
-
- let depthStencilAttachment;
- if (descriptor.depthStencilAttachment) {
- const view = assertResource(descriptor.depthStencilAttachment.view, {
+ depthStencilAttachment = {
+ ...descriptor.depthStencilAttachment,
+ view,
+ };
+ }
+ const colorAttachments = ArrayPrototypeMap(
+ descriptor.colorAttachments,
+ (colorAttachment, i) => {
+ const context = `color attachment ${i + 1}`;
+ const view = assertResource(colorAttachment.view, {
+ prefix,
+ context: `texture view for ${context}`,
+ });
+ assertResource(colorAttachment.view[_texture], {
prefix,
- context: "texture view for depth stencil attachment",
+ context: `texture backing texture view for ${context}`,
});
assertDeviceMatch(
device,
- descriptor.depthStencilAttachment.view[_texture],
+ colorAttachment.view[_texture],
{
prefix,
- resourceContext: "texture view for depth stencil attachment",
+ resourceContext: `texture view for ${context}`,
selfContext: "this",
},
);
-
- depthStencilAttachment = {
- ...descriptor.depthStencilAttachment,
- view,
- };
- }
- const colorAttachments = ArrayPrototypeMap(
- descriptor.colorAttachments,
- (colorAttachment, i) => {
- const context = `color attachment ${i + 1}`;
- const view = assertResource(colorAttachment.view, {
- prefix,
- context: `texture view for ${context}`,
- });
- assertResource(colorAttachment.view[_texture], {
+ let resolveTarget;
+ if (colorAttachment.resolveTarget) {
+ resolveTarget = assertResource(
+ colorAttachment.resolveTarget,
+ {
+ prefix,
+ context: `resolve target texture view for ${context}`,
+ },
+ );
+ assertResource(colorAttachment.resolveTarget[_texture], {
prefix,
- context: `texture backing texture view for ${context}`,
+ context:
+ `texture backing resolve target texture view for ${context}`,
});
assertDeviceMatch(
device,
- colorAttachment.view[_texture],
+ colorAttachment.resolveTarget[_texture],
{
prefix,
- resourceContext: `texture view for ${context}`,
+ resourceContext: `resolve target texture view for ${context}`,
selfContext: "this",
},
);
- let resolveTarget;
- if (colorAttachment.resolveTarget) {
- resolveTarget = assertResource(
- colorAttachment.resolveTarget,
- {
- prefix,
- context: `resolve target texture view for ${context}`,
- },
- );
- assertResource(colorAttachment.resolveTarget[_texture], {
- prefix,
- context:
- `texture backing resolve target texture view for ${context}`,
- });
- assertDeviceMatch(
- device,
- colorAttachment.resolveTarget[_texture],
- {
- prefix,
- resourceContext: `resolve target texture view for ${context}`,
- selfContext: "this",
- },
- );
- }
- return {
- view: view,
- resolveTarget,
- storeOp: colorAttachment.storeOp,
- loadOp: colorAttachment.loadOp,
- clearValue: normalizeGPUColor(colorAttachment.clearValue),
- };
- },
- );
+ }
+ return {
+ view: view,
+ resolveTarget,
+ storeOp: colorAttachment.storeOp,
+ loadOp: colorAttachment.loadOp,
+ clearValue: normalizeGPUColor(colorAttachment.clearValue),
+ };
+ },
+ );
- const { rid } = ops.op_webgpu_command_encoder_begin_render_pass(
- commandEncoderRid,
- descriptor.label,
- colorAttachments,
- depthStencilAttachment,
- );
+ const { rid } = ops.op_webgpu_command_encoder_begin_render_pass(
+ commandEncoderRid,
+ descriptor.label,
+ colorAttachments,
+ depthStencilAttachment,
+ );
- const renderPassEncoder = createGPURenderPassEncoder(
- descriptor.label,
- this,
- rid,
- );
- ArrayPrototypePush(this[_encoders], new WeakRef(renderPassEncoder));
- return renderPassEncoder;
- }
+ const renderPassEncoder = createGPURenderPassEncoder(
+ descriptor.label,
+ this,
+ rid,
+ );
+ ArrayPrototypePush(this[_encoders], new WeakRef(renderPassEncoder));
+ return renderPassEncoder;
+ }
- /**
- * @param {GPUComputePassDescriptor} descriptor
- */
- beginComputePass(descriptor = {}) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix =
- "Failed to execute 'beginComputePass' on 'GPUCommandEncoder'";
- descriptor = webidl.converters.GPUComputePassDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
+ /**
+ * @param {GPUComputePassDescriptor} descriptor
+ */
+ beginComputePass(descriptor = {}) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix =
+ "Failed to execute 'beginComputePass' on 'GPUCommandEncoder'";
+ descriptor = webidl.converters.GPUComputePassDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
- assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
+ assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
- const { rid } = ops.op_webgpu_command_encoder_begin_compute_pass(
- commandEncoderRid,
- descriptor.label,
- );
+ const { rid } = ops.op_webgpu_command_encoder_begin_compute_pass(
+ commandEncoderRid,
+ descriptor.label,
+ );
- const computePassEncoder = createGPUComputePassEncoder(
- descriptor.label,
- this,
- rid,
- );
- ArrayPrototypePush(this[_encoders], new WeakRef(computePassEncoder));
- return computePassEncoder;
- }
+ const computePassEncoder = createGPUComputePassEncoder(
+ descriptor.label,
+ this,
+ rid,
+ );
+ ArrayPrototypePush(this[_encoders], new WeakRef(computePassEncoder));
+ return computePassEncoder;
+ }
- /**
- * @param {GPUBuffer} source
- * @param {number} sourceOffset
- * @param {GPUBuffer} destination
- * @param {number} destinationOffset
- * @param {number} size
- */
- copyBufferToBuffer(
- source,
+ /**
+ * @param {GPUBuffer} source
+ * @param {number} sourceOffset
+ * @param {GPUBuffer} destination
+ * @param {number} destinationOffset
+ * @param {number} size
+ */
+ copyBufferToBuffer(
+ source,
+ sourceOffset,
+ destination,
+ destinationOffset,
+ size,
+ ) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix =
+ "Failed to execute 'copyBufferToBuffer' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 5, { prefix });
+ source = webidl.converters.GPUBuffer(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ sourceOffset = webidl.converters.GPUSize64(sourceOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ destination = webidl.converters.GPUBuffer(destination, {
+ prefix,
+ context: "Argument 3",
+ });
+ destinationOffset = webidl.converters.GPUSize64(destinationOffset, {
+ prefix,
+ context: "Argument 4",
+ });
+ size = webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 5",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const sourceRid = assertResource(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, source, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ const destinationRid = assertResource(destination, {
+ prefix,
+ context: "Argument 3",
+ });
+ assertDeviceMatch(device, destination, {
+ prefix,
+ resourceContext: "Argument 3",
+ selfContext: "this",
+ });
+
+ const { err } = ops.op_webgpu_command_encoder_copy_buffer_to_buffer(
+ commandEncoderRid,
+ sourceRid,
sourceOffset,
- destination,
+ destinationRid,
destinationOffset,
size,
- ) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix =
- "Failed to execute 'copyBufferToBuffer' on 'GPUCommandEncoder'";
- webidl.requiredArguments(arguments.length, 5, { prefix });
- source = webidl.converters.GPUBuffer(source, {
- prefix,
- context: "Argument 1",
- });
- sourceOffset = webidl.converters.GPUSize64(sourceOffset, {
- prefix,
- context: "Argument 2",
- });
- destination = webidl.converters.GPUBuffer(destination, {
- prefix,
- context: "Argument 3",
- });
- destinationOffset = webidl.converters.GPUSize64(destinationOffset, {
- prefix,
- context: "Argument 4",
- });
- size = webidl.converters.GPUSize64(size, {
- prefix,
- context: "Argument 5",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const sourceRid = assertResource(source, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, source, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- const destinationRid = assertResource(destination, {
- prefix,
- context: "Argument 3",
- });
- assertDeviceMatch(device, destination, {
- prefix,
- resourceContext: "Argument 3",
- selfContext: "this",
- });
-
- const { err } = ops.op_webgpu_command_encoder_copy_buffer_to_buffer(
- commandEncoderRid,
- sourceRid,
- sourceOffset,
- destinationRid,
- destinationOffset,
- size,
- );
- device.pushError(err);
- }
+ );
+ device.pushError(err);
+ }
- /**
- * @param {GPUImageCopyBuffer} source
- * @param {GPUImageCopyTexture} destination
- * @param {GPUExtent3D} copySize
- */
- copyBufferToTexture(source, destination, copySize) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix =
- "Failed to execute 'copyBufferToTexture' on 'GPUCommandEncoder'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- source = webidl.converters.GPUImageCopyBuffer(source, {
- prefix,
- context: "Argument 1",
- });
- destination = webidl.converters.GPUImageCopyTexture(destination, {
- prefix,
- context: "Argument 2",
- });
- copySize = webidl.converters.GPUExtent3D(copySize, {
- prefix,
- context: "Argument 3",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const sourceBufferRid = assertResource(source.buffer, {
- prefix,
- context: "source in Argument 1",
- });
- assertDeviceMatch(device, source.buffer, {
- prefix,
- resourceContext: "source in Argument 1",
- selfContext: "this",
- });
- const destinationTextureRid = assertResource(destination.texture, {
- prefix,
- context: "texture in Argument 2",
- });
- assertDeviceMatch(device, destination.texture, {
- prefix,
- resourceContext: "texture in Argument 2",
- selfContext: "this",
- });
+ /**
+ * @param {GPUImageCopyBuffer} source
+ * @param {GPUImageCopyTexture} destination
+ * @param {GPUExtent3D} copySize
+ */
+ copyBufferToTexture(source, destination, copySize) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix =
+ "Failed to execute 'copyBufferToTexture' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ source = webidl.converters.GPUImageCopyBuffer(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ destination = webidl.converters.GPUImageCopyTexture(destination, {
+ prefix,
+ context: "Argument 2",
+ });
+ copySize = webidl.converters.GPUExtent3D(copySize, {
+ prefix,
+ context: "Argument 3",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const sourceBufferRid = assertResource(source.buffer, {
+ prefix,
+ context: "source in Argument 1",
+ });
+ assertDeviceMatch(device, source.buffer, {
+ prefix,
+ resourceContext: "source in Argument 1",
+ selfContext: "this",
+ });
+ const destinationTextureRid = assertResource(destination.texture, {
+ prefix,
+ context: "texture in Argument 2",
+ });
+ assertDeviceMatch(device, destination.texture, {
+ prefix,
+ resourceContext: "texture in Argument 2",
+ selfContext: "this",
+ });
- const { err } = ops.op_webgpu_command_encoder_copy_buffer_to_texture(
- commandEncoderRid,
- {
- ...source,
- buffer: sourceBufferRid,
- },
- {
- texture: destinationTextureRid,
- mipLevel: destination.mipLevel,
- origin: destination.origin
- ? normalizeGPUOrigin3D(destination.origin)
- : undefined,
- aspect: destination.aspect,
- },
- normalizeGPUExtent3D(copySize),
- );
- device.pushError(err);
- }
+ const { err } = ops.op_webgpu_command_encoder_copy_buffer_to_texture(
+ commandEncoderRid,
+ {
+ ...source,
+ buffer: sourceBufferRid,
+ },
+ {
+ texture: destinationTextureRid,
+ mipLevel: destination.mipLevel,
+ origin: destination.origin
+ ? normalizeGPUOrigin3D(destination.origin)
+ : undefined,
+ aspect: destination.aspect,
+ },
+ normalizeGPUExtent3D(copySize),
+ );
+ device.pushError(err);
+ }
- /**
- * @param {GPUImageCopyTexture} source
- * @param {GPUImageCopyBuffer} destination
- * @param {GPUExtent3D} copySize
- */
- copyTextureToBuffer(source, destination, copySize) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix =
- "Failed to execute 'copyTextureToBuffer' on 'GPUCommandEncoder'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- source = webidl.converters.GPUImageCopyTexture(source, {
- prefix,
- context: "Argument 1",
- });
- destination = webidl.converters.GPUImageCopyBuffer(destination, {
- prefix,
- context: "Argument 2",
- });
- copySize = webidl.converters.GPUExtent3D(copySize, {
- prefix,
- context: "Argument 3",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const sourceTextureRid = assertResource(source.texture, {
- prefix,
- context: "texture in Argument 1",
- });
- assertDeviceMatch(device, source.texture, {
- prefix,
- resourceContext: "texture in Argument 1",
- selfContext: "this",
- });
- const destinationBufferRid = assertResource(destination.buffer, {
- prefix,
- context: "buffer in Argument 2",
- });
- assertDeviceMatch(device, destination.buffer, {
- prefix,
- resourceContext: "buffer in Argument 2",
- selfContext: "this",
- });
- const { err } = ops.op_webgpu_command_encoder_copy_texture_to_buffer(
- commandEncoderRid,
- {
- texture: sourceTextureRid,
- mipLevel: source.mipLevel,
- origin: source.origin
- ? normalizeGPUOrigin3D(source.origin)
- : undefined,
- aspect: source.aspect,
- },
- {
- ...destination,
- buffer: destinationBufferRid,
- },
- normalizeGPUExtent3D(copySize),
- );
- device.pushError(err);
- }
+ /**
+ * @param {GPUImageCopyTexture} source
+ * @param {GPUImageCopyBuffer} destination
+ * @param {GPUExtent3D} copySize
+ */
+ copyTextureToBuffer(source, destination, copySize) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix =
+ "Failed to execute 'copyTextureToBuffer' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ source = webidl.converters.GPUImageCopyTexture(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ destination = webidl.converters.GPUImageCopyBuffer(destination, {
+ prefix,
+ context: "Argument 2",
+ });
+ copySize = webidl.converters.GPUExtent3D(copySize, {
+ prefix,
+ context: "Argument 3",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const sourceTextureRid = assertResource(source.texture, {
+ prefix,
+ context: "texture in Argument 1",
+ });
+ assertDeviceMatch(device, source.texture, {
+ prefix,
+ resourceContext: "texture in Argument 1",
+ selfContext: "this",
+ });
+ const destinationBufferRid = assertResource(destination.buffer, {
+ prefix,
+ context: "buffer in Argument 2",
+ });
+ assertDeviceMatch(device, destination.buffer, {
+ prefix,
+ resourceContext: "buffer in Argument 2",
+ selfContext: "this",
+ });
+ const { err } = ops.op_webgpu_command_encoder_copy_texture_to_buffer(
+ commandEncoderRid,
+ {
+ texture: sourceTextureRid,
+ mipLevel: source.mipLevel,
+ origin: source.origin ? normalizeGPUOrigin3D(source.origin) : undefined,
+ aspect: source.aspect,
+ },
+ {
+ ...destination,
+ buffer: destinationBufferRid,
+ },
+ normalizeGPUExtent3D(copySize),
+ );
+ device.pushError(err);
+ }
- /**
- * @param {GPUImageCopyTexture} source
- * @param {GPUImageCopyTexture} destination
- * @param {GPUExtent3D} copySize
- */
- copyTextureToTexture(source, destination, copySize) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix =
- "Failed to execute 'copyTextureToTexture' on 'GPUCommandEncoder'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- source = webidl.converters.GPUImageCopyTexture(source, {
- prefix,
- context: "Argument 1",
- });
- destination = webidl.converters.GPUImageCopyTexture(destination, {
- prefix,
- context: "Argument 2",
- });
- copySize = webidl.converters.GPUExtent3D(copySize, {
- prefix,
- context: "Argument 3",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const sourceTextureRid = assertResource(source.texture, {
- prefix,
- context: "texture in Argument 1",
- });
- assertDeviceMatch(device, source.texture, {
- prefix,
- resourceContext: "texture in Argument 1",
- selfContext: "this",
- });
- const destinationTextureRid = assertResource(destination.texture, {
- prefix,
- context: "texture in Argument 2",
- });
- assertDeviceMatch(device, destination.texture, {
- prefix,
- resourceContext: "texture in Argument 2",
- selfContext: "this",
- });
- const { err } = ops.op_webgpu_command_encoder_copy_texture_to_texture(
- commandEncoderRid,
- {
- texture: sourceTextureRid,
- mipLevel: source.mipLevel,
- origin: source.origin
- ? normalizeGPUOrigin3D(source.origin)
- : undefined,
- aspect: source.aspect,
- },
- {
- texture: destinationTextureRid,
- mipLevel: destination.mipLevel,
- origin: destination.origin
- ? normalizeGPUOrigin3D(destination.origin)
- : undefined,
- aspect: source.aspect,
- },
- normalizeGPUExtent3D(copySize),
- );
- device.pushError(err);
- }
+ /**
+ * @param {GPUImageCopyTexture} source
+ * @param {GPUImageCopyTexture} destination
+ * @param {GPUExtent3D} copySize
+ */
+ copyTextureToTexture(source, destination, copySize) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix =
+ "Failed to execute 'copyTextureToTexture' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ source = webidl.converters.GPUImageCopyTexture(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ destination = webidl.converters.GPUImageCopyTexture(destination, {
+ prefix,
+ context: "Argument 2",
+ });
+ copySize = webidl.converters.GPUExtent3D(copySize, {
+ prefix,
+ context: "Argument 3",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const sourceTextureRid = assertResource(source.texture, {
+ prefix,
+ context: "texture in Argument 1",
+ });
+ assertDeviceMatch(device, source.texture, {
+ prefix,
+ resourceContext: "texture in Argument 1",
+ selfContext: "this",
+ });
+ const destinationTextureRid = assertResource(destination.texture, {
+ prefix,
+ context: "texture in Argument 2",
+ });
+ assertDeviceMatch(device, destination.texture, {
+ prefix,
+ resourceContext: "texture in Argument 2",
+ selfContext: "this",
+ });
+ const { err } = ops.op_webgpu_command_encoder_copy_texture_to_texture(
+ commandEncoderRid,
+ {
+ texture: sourceTextureRid,
+ mipLevel: source.mipLevel,
+ origin: source.origin ? normalizeGPUOrigin3D(source.origin) : undefined,
+ aspect: source.aspect,
+ },
+ {
+ texture: destinationTextureRid,
+ mipLevel: destination.mipLevel,
+ origin: destination.origin
+ ? normalizeGPUOrigin3D(destination.origin)
+ : undefined,
+ aspect: source.aspect,
+ },
+ normalizeGPUExtent3D(copySize),
+ );
+ device.pushError(err);
+ }
- /**
- * @param {GPUBuffer} buffer
- * @param {GPUSize64} offset
- * @param {GPUSize64} size
- */
- clearBuffer(buffer, offset = 0, size = undefined) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix = "Failed to execute 'clearBuffer' on 'GPUCommandEncoder'";
- webidl.requiredArguments(arguments.length, 3, { prefix });
- buffer = webidl.converters.GPUBuffer(buffer, {
- prefix,
- context: "Argument 1",
- });
- offset = webidl.converters.GPUSize64(offset, {
- prefix,
- context: "Argument 2",
- });
- size = webidl.converters.GPUSize64(size, {
- prefix,
- context: "Argument 3",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const bufferRid = assertResource(buffer, {
- prefix,
- context: "Argument 1",
- });
- const { err } = ops.op_webgpu_command_encoder_clear_buffer(
- commandEncoderRid,
- bufferRid,
- offset,
- size,
- );
- device.pushError(err);
- }
+ /**
+ * @param {GPUBuffer} buffer
+ * @param {GPUSize64} offset
+ * @param {GPUSize64} size
+ */
+ clearBuffer(buffer, offset = 0, size = undefined) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix = "Failed to execute 'clearBuffer' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ buffer = webidl.converters.GPUBuffer(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 2",
+ });
+ size = webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 3",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ const { err } = ops.op_webgpu_command_encoder_clear_buffer(
+ commandEncoderRid,
+ bufferRid,
+ offset,
+ size,
+ );
+ device.pushError(err);
+ }
- /**
- * @param {string} groupLabel
- */
- pushDebugGroup(groupLabel) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix =
- "Failed to execute 'pushDebugGroup' on 'GPUCommandEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- groupLabel = webidl.converters.USVString(groupLabel, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const { err } = ops.op_webgpu_command_encoder_push_debug_group(
- commandEncoderRid,
- groupLabel,
- );
- device.pushError(err);
- }
+ /**
+ * @param {string} groupLabel
+ */
+ pushDebugGroup(groupLabel) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix = "Failed to execute 'pushDebugGroup' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ groupLabel = webidl.converters.USVString(groupLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { err } = ops.op_webgpu_command_encoder_push_debug_group(
+ commandEncoderRid,
+ groupLabel,
+ );
+ device.pushError(err);
+ }
- popDebugGroup() {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix = "Failed to execute 'popDebugGroup' on 'GPUCommandEncoder'";
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const { err } = ops.op_webgpu_command_encoder_pop_debug_group(
- commandEncoderRid,
- );
- device.pushError(err);
- }
+ popDebugGroup() {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix = "Failed to execute 'popDebugGroup' on 'GPUCommandEncoder'";
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { err } = ops.op_webgpu_command_encoder_pop_debug_group(
+ commandEncoderRid,
+ );
+ device.pushError(err);
+ }
- /**
- * @param {string} markerLabel
- */
- insertDebugMarker(markerLabel) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix =
- "Failed to execute 'insertDebugMarker' on 'GPUCommandEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- markerLabel = webidl.converters.USVString(markerLabel, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const { err } = ops.op_webgpu_command_encoder_insert_debug_marker(
- commandEncoderRid,
- markerLabel,
- );
- device.pushError(err);
- }
+ /**
+ * @param {string} markerLabel
+ */
+ insertDebugMarker(markerLabel) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix =
+ "Failed to execute 'insertDebugMarker' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ markerLabel = webidl.converters.USVString(markerLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { err } = ops.op_webgpu_command_encoder_insert_debug_marker(
+ commandEncoderRid,
+ markerLabel,
+ );
+ device.pushError(err);
+ }
- /**
- * @param {GPUQuerySet} querySet
- * @param {number} queryIndex
- */
- writeTimestamp(querySet, queryIndex) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix =
- "Failed to execute 'writeTimestamp' on 'GPUCommandEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- querySet = webidl.converters.GPUQuerySet(querySet, {
- prefix,
- context: "Argument 1",
- });
- queryIndex = webidl.converters.GPUSize32(queryIndex, {
- prefix,
- context: "Argument 2",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const querySetRid = assertResource(querySet, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, querySet, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- const { err } = ops.op_webgpu_command_encoder_write_timestamp(
- commandEncoderRid,
- querySetRid,
- queryIndex,
- );
- device.pushError(err);
- }
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} queryIndex
+ */
+ writeTimestamp(querySet, queryIndex) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix = "Failed to execute 'writeTimestamp' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ queryIndex = webidl.converters.GPUSize32(queryIndex, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ const { err } = ops.op_webgpu_command_encoder_write_timestamp(
+ commandEncoderRid,
+ querySetRid,
+ queryIndex,
+ );
+ device.pushError(err);
+ }
- /**
- * @param {GPUQuerySet} querySet
- * @param {number} firstQuery
- * @param {number} queryCount
- * @param {GPUBuffer} destination
- * @param {number} destinationOffset
- */
- resolveQuerySet(
- querySet,
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} firstQuery
+ * @param {number} queryCount
+ * @param {GPUBuffer} destination
+ * @param {number} destinationOffset
+ */
+ resolveQuerySet(
+ querySet,
+ firstQuery,
+ queryCount,
+ destination,
+ destinationOffset,
+ ) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix = "Failed to execute 'resolveQuerySet' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 5, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ firstQuery = webidl.converters.GPUSize32(firstQuery, {
+ prefix,
+ context: "Argument 2",
+ });
+ queryCount = webidl.converters.GPUSize32(queryCount, {
+ prefix,
+ context: "Argument 3",
+ });
+ destination = webidl.converters.GPUBuffer(destination, {
+ prefix,
+ context: "Argument 4",
+ });
+ destinationOffset = webidl.converters.GPUSize64(destinationOffset, {
+ prefix,
+ context: "Argument 5",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ const destinationRid = assertResource(destination, {
+ prefix,
+ context: "Argument 3",
+ });
+ assertDeviceMatch(device, destination, {
+ prefix,
+ resourceContext: "Argument 3",
+ selfContext: "this",
+ });
+ const { err } = ops.op_webgpu_command_encoder_resolve_query_set(
+ commandEncoderRid,
+ querySetRid,
firstQuery,
queryCount,
- destination,
+ destinationRid,
destinationOffset,
- ) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix =
- "Failed to execute 'resolveQuerySet' on 'GPUCommandEncoder'";
- webidl.requiredArguments(arguments.length, 5, { prefix });
- querySet = webidl.converters.GPUQuerySet(querySet, {
- prefix,
- context: "Argument 1",
- });
- firstQuery = webidl.converters.GPUSize32(firstQuery, {
- prefix,
- context: "Argument 2",
- });
- queryCount = webidl.converters.GPUSize32(queryCount, {
- prefix,
- context: "Argument 3",
- });
- destination = webidl.converters.GPUBuffer(destination, {
- prefix,
- context: "Argument 4",
- });
- destinationOffset = webidl.converters.GPUSize64(destinationOffset, {
- prefix,
- context: "Argument 5",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const querySetRid = assertResource(querySet, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, querySet, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- const destinationRid = assertResource(destination, {
- prefix,
- context: "Argument 3",
- });
- assertDeviceMatch(device, destination, {
- prefix,
- resourceContext: "Argument 3",
- selfContext: "this",
- });
- const { err } = ops.op_webgpu_command_encoder_resolve_query_set(
- commandEncoderRid,
- querySetRid,
- firstQuery,
- queryCount,
- destinationRid,
- destinationOffset,
- );
- device.pushError(err);
- }
+ );
+ device.pushError(err);
+ }
- /**
- * @param {GPUCommandBufferDescriptor} descriptor
- * @returns {GPUCommandBuffer}
- */
- finish(descriptor = {}) {
- webidl.assertBranded(this, GPUCommandEncoderPrototype);
- const prefix = "Failed to execute 'finish' on 'GPUCommandEncoder'";
- descriptor = webidl.converters.GPUCommandBufferDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const commandEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const { rid, err } = ops.op_webgpu_command_encoder_finish(
- commandEncoderRid,
- descriptor.label,
- );
- device.pushError(err);
+ /**
+ * @param {GPUCommandBufferDescriptor} descriptor
+ * @returns {GPUCommandBuffer}
+ */
+ finish(descriptor = {}) {
+ webidl.assertBranded(this, GPUCommandEncoderPrototype);
+ const prefix = "Failed to execute 'finish' on 'GPUCommandEncoder'";
+ descriptor = webidl.converters.GPUCommandBufferDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { rid, err } = ops.op_webgpu_command_encoder_finish(
+ commandEncoderRid,
+ descriptor.label,
+ );
+ device.pushError(err);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+
+ const commandBuffer = createGPUCommandBuffer(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(commandBuffer);
+ return commandBuffer;
+ }
+
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUCommandEncoder", GPUCommandEncoder);
+const GPUCommandEncoderPrototype = GPUCommandEncoder.prototype;
+
+/**
+ * @param {string | null} label
+ * @param {GPUCommandEncoder} encoder
+ * @param {number} rid
+ * @returns {GPURenderPassEncoder}
+ */
+function createGPURenderPassEncoder(label, encoder, rid) {
+ /** @type {GPURenderPassEncoder} */
+ const passEncoder = webidl.createBranded(GPURenderPassEncoder);
+ passEncoder[_label] = label;
+ passEncoder[_encoder] = encoder;
+ passEncoder[_rid] = rid;
+ return passEncoder;
+}
+
+class GPURenderPassEncoder {
+ /** @type {GPUCommandEncoder} */
+ [_encoder];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
/** @type {number | undefined} */
this[_rid] = undefined;
-
- const commandBuffer = createGPUCommandBuffer(
- descriptor.label,
- device,
- rid,
- );
- device.trackResource(commandBuffer);
- return commandBuffer;
}
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ constructor() {
+ webidl.illegalConstructor();
}
- GPUObjectBaseMixin("GPUCommandEncoder", GPUCommandEncoder);
- const GPUCommandEncoderPrototype = GPUCommandEncoder.prototype;
/**
- * @param {string | null} label
- * @param {GPUCommandEncoder} encoder
- * @param {number} rid
- * @returns {GPURenderPassEncoder}
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ * @param {number} minDepth
+ * @param {number} maxDepth
*/
- function createGPURenderPassEncoder(label, encoder, rid) {
- /** @type {GPURenderPassEncoder} */
- const passEncoder = webidl.createBranded(GPURenderPassEncoder);
- passEncoder[_label] = label;
- passEncoder[_encoder] = encoder;
- passEncoder[_rid] = rid;
- return passEncoder;
- }
-
- class GPURenderPassEncoder {
- /** @type {GPUCommandEncoder} */
- [_encoder];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
-
- constructor() {
- webidl.illegalConstructor();
- }
+ setViewport(x, y, width, height, minDepth, maxDepth) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix = "Failed to execute 'setViewport' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 6, { prefix });
+ x = webidl.converters.float(x, { prefix, context: "Argument 1" });
+ y = webidl.converters.float(y, { prefix, context: "Argument 2" });
+ width = webidl.converters.float(width, { prefix, context: "Argument 3" });
+ height = webidl.converters.float(height, {
+ prefix,
+ context: "Argument 4",
+ });
+ minDepth = webidl.converters.float(minDepth, {
+ prefix,
+ context: "Argument 5",
+ });
+ maxDepth = webidl.converters.float(maxDepth, {
+ prefix,
+ context: "Argument 6",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_render_pass_set_viewport({
+ renderPassRid,
+ x,
+ y,
+ width,
+ height,
+ minDepth,
+ maxDepth,
+ });
+ }
- /**
- * @param {number} x
- * @param {number} y
- * @param {number} width
- * @param {number} height
- * @param {number} minDepth
- * @param {number} maxDepth
- */
- setViewport(x, y, width, height, minDepth, maxDepth) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'setViewport' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 6, { prefix });
- x = webidl.converters.float(x, { prefix, context: "Argument 1" });
- y = webidl.converters.float(y, { prefix, context: "Argument 2" });
- width = webidl.converters.float(width, { prefix, context: "Argument 3" });
- height = webidl.converters.float(height, {
- prefix,
- context: "Argument 4",
- });
- minDepth = webidl.converters.float(minDepth, {
- prefix,
- context: "Argument 5",
- });
- maxDepth = webidl.converters.float(maxDepth, {
- prefix,
- context: "Argument 6",
- });
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_render_pass_set_viewport({
- renderPassRid,
- x,
- y,
- width,
- height,
- minDepth,
- maxDepth,
- });
- }
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ */
+ setScissorRect(x, y, width, height) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'setScissorRect' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 4, { prefix });
+ x = webidl.converters.GPUIntegerCoordinate(x, {
+ prefix,
+ context: "Argument 1",
+ });
+ y = webidl.converters.GPUIntegerCoordinate(y, {
+ prefix,
+ context: "Argument 2",
+ });
+ width = webidl.converters.GPUIntegerCoordinate(width, {
+ prefix,
+ context: "Argument 3",
+ });
+ height = webidl.converters.GPUIntegerCoordinate(height, {
+ prefix,
+ context: "Argument 4",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_render_pass_set_scissor_rect(
+ renderPassRid,
+ x,
+ y,
+ width,
+ height,
+ );
+ }
- /**
- * @param {number} x
- * @param {number} y
- * @param {number} width
- * @param {number} height
- */
- setScissorRect(x, y, width, height) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'setScissorRect' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 4, { prefix });
- x = webidl.converters.GPUIntegerCoordinate(x, {
- prefix,
- context: "Argument 1",
- });
- y = webidl.converters.GPUIntegerCoordinate(y, {
- prefix,
- context: "Argument 2",
- });
- width = webidl.converters.GPUIntegerCoordinate(width, {
- prefix,
- context: "Argument 3",
- });
- height = webidl.converters.GPUIntegerCoordinate(height, {
- prefix,
- context: "Argument 4",
- });
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_render_pass_set_scissor_rect(
- renderPassRid,
- x,
- y,
- width,
- height,
- );
- }
+ /**
+ * @param {GPUColor} color
+ */
+ setBlendConstant(color) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'setBlendConstant' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ color = webidl.converters.GPUColor(color, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_render_pass_set_blend_constant(
+ renderPassRid,
+ normalizeGPUColor(color),
+ );
+ }
- /**
- * @param {GPUColor} color
- */
- setBlendConstant(color) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'setBlendConstant' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- color = webidl.converters.GPUColor(color, {
- prefix,
- context: "Argument 1",
- });
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_render_pass_set_blend_constant(
- renderPassRid,
- normalizeGPUColor(color),
- );
- }
+ /**
+ * @param {number} reference
+ */
+ setStencilReference(reference) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'setStencilReference' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ reference = webidl.converters.GPUStencilValue(reference, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_render_pass_set_stencil_reference(
+ renderPassRid,
+ reference,
+ );
+ }
- /**
- * @param {number} reference
- */
- setStencilReference(reference) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'setStencilReference' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- reference = webidl.converters.GPUStencilValue(reference, {
- prefix,
- context: "Argument 1",
- });
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_render_pass_set_stencil_reference(
- renderPassRid,
- reference,
- );
- }
+ beginOcclusionQuery(_queryIndex) {
+ throw new Error("Not yet implemented");
+ }
- beginOcclusionQuery(_queryIndex) {
- throw new Error("Not yet implemented");
- }
+ endOcclusionQuery() {
+ throw new Error("Not yet implemented");
+ }
- endOcclusionQuery() {
- throw new Error("Not yet implemented");
- }
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} queryIndex
+ */
+ beginPipelineStatisticsQuery(querySet, queryIndex) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'beginPipelineStatisticsQuery' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ queryIndex = webidl.converters.GPUSize32(queryIndex, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_pass_begin_pipeline_statistics_query(
+ renderPassRid,
+ querySetRid,
+ queryIndex,
+ );
+ }
- /**
- * @param {GPUQuerySet} querySet
- * @param {number} queryIndex
- */
- beginPipelineStatisticsQuery(querySet, queryIndex) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'beginPipelineStatisticsQuery' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- querySet = webidl.converters.GPUQuerySet(querySet, {
- prefix,
- context: "Argument 1",
- });
- queryIndex = webidl.converters.GPUSize32(queryIndex, {
- prefix,
- context: "Argument 2",
- });
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- const querySetRid = assertResource(querySet, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, querySet, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_render_pass_begin_pipeline_statistics_query(
- renderPassRid,
- querySetRid,
- queryIndex,
- );
- }
+ endPipelineStatisticsQuery() {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'endPipelineStatisticsQuery' on 'GPURenderPassEncoder'";
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_render_pass_end_pipeline_statistics_query(renderPassRid);
+ }
- endPipelineStatisticsQuery() {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'endPipelineStatisticsQuery' on 'GPURenderPassEncoder'";
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_render_pass_end_pipeline_statistics_query(renderPassRid);
- }
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} queryIndex
+ */
+ writeTimestamp(querySet, queryIndex) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'writeTimestamp' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ queryIndex = webidl.converters.GPUSize32(queryIndex, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_pass_write_timestamp(
+ renderPassRid,
+ querySetRid,
+ queryIndex,
+ );
+ }
- /**
- * @param {GPUQuerySet} querySet
- * @param {number} queryIndex
- */
- writeTimestamp(querySet, queryIndex) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'writeTimestamp' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- querySet = webidl.converters.GPUQuerySet(querySet, {
- prefix,
- context: "Argument 1",
- });
- queryIndex = webidl.converters.GPUSize32(queryIndex, {
- prefix,
- context: "Argument 2",
- });
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- const querySetRid = assertResource(querySet, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, querySet, {
+ /**
+ * @param {GPURenderBundle[]} bundles
+ */
+ executeBundles(bundles) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'executeBundles' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ bundles = webidl.converters["sequence<GPURenderBundle>"](bundles, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const bundleRids = ArrayPrototypeMap(bundles, (bundle, i) => {
+ const context = `bundle ${i + 1}`;
+ const rid = assertResource(bundle, { prefix, context });
+ assertDeviceMatch(device, bundle, {
prefix,
- resourceContext: "Argument 1",
+ resourceContext: context,
selfContext: "this",
});
- ops.op_webgpu_render_pass_write_timestamp(
- renderPassRid,
- querySetRid,
- queryIndex,
- );
- }
+ return rid;
+ });
+ ops.op_webgpu_render_pass_execute_bundles(renderPassRid, bundleRids);
+ }
- /**
- * @param {GPURenderBundle[]} bundles
- */
- executeBundles(bundles) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'executeBundles' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- bundles = webidl.converters["sequence<GPURenderBundle>"](bundles, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- const bundleRids = ArrayPrototypeMap(bundles, (bundle, i) => {
- const context = `bundle ${i + 1}`;
- const rid = assertResource(bundle, { prefix, context });
- assertDeviceMatch(device, bundle, {
- prefix,
- resourceContext: context,
- selfContext: "this",
- });
- return rid;
- });
- ops.op_webgpu_render_pass_execute_bundles(renderPassRid, bundleRids);
- }
+ end() {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix = "Failed to execute 'end' on 'GPURenderPassEncoder'";
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const commandEncoderRid = assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const { err } = ops.op_webgpu_render_pass_end(
+ commandEncoderRid,
+ renderPassRid,
+ );
+ device.pushError(err);
+ this[_rid] = undefined;
+ }
- end() {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix = "Failed to execute 'end' on 'GPURenderPassEncoder'";
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const commandEncoderRid = assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- const { err } = ops.op_webgpu_render_pass_end(
- commandEncoderRid,
- renderPassRid,
- );
- device.pushError(err);
- this[_rid] = undefined;
+ // TODO(lucacasonato): has an overload
+ setBindGroup(
+ index,
+ bindGroup,
+ dynamicOffsetsData,
+ dynamicOffsetsDataStart,
+ dynamicOffsetsDataLength,
+ ) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix = "Failed to execute 'setBindGroup' on 'GPURenderPassEncoder'";
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const bindGroupRid = assertResource(bindGroup, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDeviceMatch(device, bindGroup, {
+ prefix,
+ resourceContext: "Argument 2",
+ selfContext: "this",
+ });
+ if (
+ !(ObjectPrototypeIsPrototypeOf(
+ Uint32ArrayPrototype,
+ dynamicOffsetsData,
+ ))
+ ) {
+ dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
+ dynamicOffsetsDataStart = 0;
+ dynamicOffsetsDataLength = dynamicOffsetsData.length;
}
-
- // TODO(lucacasonato): has an overload
- setBindGroup(
+ ops.op_webgpu_render_pass_set_bind_group(
+ renderPassRid,
index,
- bindGroup,
+ bindGroupRid,
dynamicOffsetsData,
dynamicOffsetsDataStart,
dynamicOffsetsDataLength,
- ) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'setBindGroup' on 'GPURenderPassEncoder'";
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- const bindGroupRid = assertResource(bindGroup, {
- prefix,
- context: "Argument 2",
- });
- assertDeviceMatch(device, bindGroup, {
- prefix,
- resourceContext: "Argument 2",
- selfContext: "this",
- });
- if (
- !(ObjectPrototypeIsPrototypeOf(
- Uint32ArrayPrototype,
- dynamicOffsetsData,
- ))
- ) {
- dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
- dynamicOffsetsDataStart = 0;
- dynamicOffsetsDataLength = dynamicOffsetsData.length;
- }
- ops.op_webgpu_render_pass_set_bind_group(
- renderPassRid,
- index,
- bindGroupRid,
- dynamicOffsetsData,
- dynamicOffsetsDataStart,
- dynamicOffsetsDataLength,
- );
- }
-
- /**
- * @param {string} groupLabel
- */
- pushDebugGroup(groupLabel) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'pushDebugGroup' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- groupLabel = webidl.converters.USVString(groupLabel, {
- prefix,
- context: "Argument 1",
- });
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_render_pass_push_debug_group(renderPassRid, groupLabel);
- }
-
- popDebugGroup() {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'popDebugGroup' on 'GPURenderPassEncoder'";
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_render_pass_pop_debug_group(renderPassRid);
- }
+ );
+ }
- /**
- * @param {string} markerLabel
- */
- insertDebugMarker(markerLabel) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'insertDebugMarker' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- markerLabel = webidl.converters.USVString(markerLabel, {
- prefix,
- context: "Argument 1",
- });
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_render_pass_insert_debug_marker(renderPassRid, markerLabel);
- }
+ /**
+ * @param {string} groupLabel
+ */
+ pushDebugGroup(groupLabel) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'pushDebugGroup' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ groupLabel = webidl.converters.USVString(groupLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_render_pass_push_debug_group(renderPassRid, groupLabel);
+ }
- /**
- * @param {GPURenderPipeline} pipeline
- */
- setPipeline(pipeline) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'setPipeline' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- pipeline = webidl.converters.GPURenderPipeline(pipeline, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- const pipelineRid = assertResource(pipeline, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, pipeline, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_render_pass_set_pipeline(renderPassRid, pipelineRid);
- }
+ popDebugGroup() {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'popDebugGroup' on 'GPURenderPassEncoder'";
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_render_pass_pop_debug_group(renderPassRid);
+ }
- /**
- * @param {GPUBuffer} buffer
- * @param {GPUIndexFormat} indexFormat
- * @param {number} offset
- * @param {number} size
- */
- setIndexBuffer(buffer, indexFormat, offset = 0, size) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'setIndexBuffer' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- buffer = webidl.converters.GPUBuffer(buffer, {
- prefix,
- context: "Argument 1",
- });
- indexFormat = webidl.converters.GPUIndexFormat(indexFormat, {
- prefix,
- context: "Argument 2",
- });
- offset = webidl.converters.GPUSize64(offset, {
- prefix,
- context: "Argument 3",
- });
- if (size !== undefined) {
- size = webidl.converters.GPUSize64(size, {
- prefix,
- context: "Argument 4",
- });
- }
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- const bufferRid = assertResource(buffer, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, buffer, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_render_pass_set_index_buffer(
- renderPassRid,
- bufferRid,
- indexFormat,
- offset,
- size,
- );
- }
+ /**
+ * @param {string} markerLabel
+ */
+ insertDebugMarker(markerLabel) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'insertDebugMarker' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ markerLabel = webidl.converters.USVString(markerLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_render_pass_insert_debug_marker(renderPassRid, markerLabel);
+ }
- /**
- * @param {number} slot
- * @param {GPUBuffer} buffer
- * @param {number} offset
- * @param {number} size
- */
- setVertexBuffer(slot, buffer, offset = 0, size) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'setVertexBuffer' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- slot = webidl.converters.GPUSize32(slot, {
- prefix,
- context: "Argument 2",
- });
- buffer = webidl.converters.GPUBuffer(buffer, {
- prefix,
- context: "Argument 2",
- });
- offset = webidl.converters.GPUSize64(offset, {
- prefix,
- context: "Argument 3",
- });
- if (size !== undefined) {
- size = webidl.converters.GPUSize64(size, {
- prefix,
- context: "Argument 4",
- });
- }
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- const bufferRid = assertResource(buffer, {
- prefix,
- context: "Argument 2",
- });
- assertDeviceMatch(device, buffer, {
- prefix,
- resourceContext: "Argument 2",
- selfContext: "this",
- });
- ops.op_webgpu_render_pass_set_vertex_buffer(
- renderPassRid,
- slot,
- bufferRid,
- offset,
- size,
- );
- }
+ /**
+ * @param {GPURenderPipeline} pipeline
+ */
+ setPipeline(pipeline) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix = "Failed to execute 'setPipeline' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ pipeline = webidl.converters.GPURenderPipeline(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const pipelineRid = assertResource(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, pipeline, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_pass_set_pipeline(renderPassRid, pipelineRid);
+ }
- /**
- * @param {number} vertexCount
- * @param {number} instanceCount
- * @param {number} firstVertex
- * @param {number} firstInstance
- */
- draw(vertexCount, instanceCount = 1, firstVertex = 0, firstInstance = 0) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix = "Failed to execute 'draw' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- vertexCount = webidl.converters.GPUSize32(vertexCount, {
- prefix,
- context: "Argument 1",
- });
- instanceCount = webidl.converters.GPUSize32(instanceCount, {
- prefix,
- context: "Argument 2",
- });
- firstVertex = webidl.converters.GPUSize32(firstVertex, {
- prefix,
- context: "Argument 3",
- });
- firstInstance = webidl.converters.GPUSize32(firstInstance, {
+ /**
+ * @param {GPUBuffer} buffer
+ * @param {GPUIndexFormat} indexFormat
+ * @param {number} offset
+ * @param {number} size
+ */
+ setIndexBuffer(buffer, indexFormat, offset = 0, size) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'setIndexBuffer' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ buffer = webidl.converters.GPUBuffer(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indexFormat = webidl.converters.GPUIndexFormat(indexFormat, {
+ prefix,
+ context: "Argument 2",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 3",
+ });
+ if (size !== undefined) {
+ size = webidl.converters.GPUSize64(size, {
prefix,
context: "Argument 4",
});
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_render_pass_draw(
- renderPassRid,
- vertexCount,
- instanceCount,
- firstVertex,
- firstInstance,
- );
}
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_pass_set_index_buffer(
+ renderPassRid,
+ bufferRid,
+ indexFormat,
+ offset,
+ size,
+ );
+ }
- /**
- * @param {number} indexCount
- * @param {number} instanceCount
- * @param {number} firstIndex
- * @param {number} baseVertex
- * @param {number} firstInstance
- */
- drawIndexed(
- indexCount,
- instanceCount = 1,
- firstIndex = 0,
- baseVertex = 0,
- firstInstance = 0,
- ) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'drawIndexed' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- indexCount = webidl.converters.GPUSize32(indexCount, {
- prefix,
- context: "Argument 1",
- });
- instanceCount = webidl.converters.GPUSize32(instanceCount, {
- prefix,
- context: "Argument 2",
- });
- firstIndex = webidl.converters.GPUSize32(firstIndex, {
- prefix,
- context: "Argument 3",
- });
- baseVertex = webidl.converters.GPUSignedOffset32(baseVertex, {
+ /**
+ * @param {number} slot
+ * @param {GPUBuffer} buffer
+ * @param {number} offset
+ * @param {number} size
+ */
+ setVertexBuffer(slot, buffer, offset = 0, size) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'setVertexBuffer' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ slot = webidl.converters.GPUSize32(slot, {
+ prefix,
+ context: "Argument 2",
+ });
+ buffer = webidl.converters.GPUBuffer(buffer, {
+ prefix,
+ context: "Argument 2",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 3",
+ });
+ if (size !== undefined) {
+ size = webidl.converters.GPUSize64(size, {
prefix,
context: "Argument 4",
});
- firstInstance = webidl.converters.GPUSize32(firstInstance, {
- prefix,
- context: "Argument 5",
- });
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_render_pass_draw_indexed(
- renderPassRid,
- indexCount,
- instanceCount,
- firstIndex,
- baseVertex,
- firstInstance,
- );
- }
-
- /**
- * @param {GPUBuffer} indirectBuffer
- * @param {number} indirectOffset
- */
- drawIndirect(indirectBuffer, indirectOffset) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'drawIndirect' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
- prefix,
- context: "Argument 1",
- });
- indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
- prefix,
- context: "Argument 2",
- });
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- const indirectBufferRid = assertResource(indirectBuffer, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, indirectBuffer, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_render_pass_draw_indirect(
- renderPassRid,
- indirectBufferRid,
- indirectOffset,
- );
}
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ resourceContext: "Argument 2",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_pass_set_vertex_buffer(
+ renderPassRid,
+ slot,
+ bufferRid,
+ offset,
+ size,
+ );
+ }
- /**
- * @param {GPUBuffer} indirectBuffer
- * @param {number} indirectOffset
- */
- drawIndexedIndirect(indirectBuffer, indirectOffset) {
- webidl.assertBranded(this, GPURenderPassEncoderPrototype);
- const prefix =
- "Failed to execute 'drawIndirect' on 'GPURenderPassEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
- prefix,
- context: "Argument 1",
- });
- indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
- prefix,
- context: "Argument 2",
- });
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const renderPassRid = assertResource(this, { prefix, context: "this" });
- const indirectBufferRid = assertResource(indirectBuffer, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, indirectBuffer, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_render_pass_draw_indexed_indirect(
- renderPassRid,
- indirectBufferRid,
- indirectOffset,
- );
- }
+ /**
+ * @param {number} vertexCount
+ * @param {number} instanceCount
+ * @param {number} firstVertex
+ * @param {number} firstInstance
+ */
+ draw(vertexCount, instanceCount = 1, firstVertex = 0, firstInstance = 0) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix = "Failed to execute 'draw' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ vertexCount = webidl.converters.GPUSize32(vertexCount, {
+ prefix,
+ context: "Argument 1",
+ });
+ instanceCount = webidl.converters.GPUSize32(instanceCount, {
+ prefix,
+ context: "Argument 2",
+ });
+ firstVertex = webidl.converters.GPUSize32(firstVertex, {
+ prefix,
+ context: "Argument 3",
+ });
+ firstInstance = webidl.converters.GPUSize32(firstInstance, {
+ prefix,
+ context: "Argument 4",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_render_pass_draw(
+ renderPassRid,
+ vertexCount,
+ instanceCount,
+ firstVertex,
+ firstInstance,
+ );
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ /**
+ * @param {number} indexCount
+ * @param {number} instanceCount
+ * @param {number} firstIndex
+ * @param {number} baseVertex
+ * @param {number} firstInstance
+ */
+ drawIndexed(
+ indexCount,
+ instanceCount = 1,
+ firstIndex = 0,
+ baseVertex = 0,
+ firstInstance = 0,
+ ) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix = "Failed to execute 'drawIndexed' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ indexCount = webidl.converters.GPUSize32(indexCount, {
+ prefix,
+ context: "Argument 1",
+ });
+ instanceCount = webidl.converters.GPUSize32(instanceCount, {
+ prefix,
+ context: "Argument 2",
+ });
+ firstIndex = webidl.converters.GPUSize32(firstIndex, {
+ prefix,
+ context: "Argument 3",
+ });
+ baseVertex = webidl.converters.GPUSignedOffset32(baseVertex, {
+ prefix,
+ context: "Argument 4",
+ });
+ firstInstance = webidl.converters.GPUSize32(firstInstance, {
+ prefix,
+ context: "Argument 5",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_render_pass_draw_indexed(
+ renderPassRid,
+ indexCount,
+ instanceCount,
+ firstIndex,
+ baseVertex,
+ firstInstance,
+ );
}
- GPUObjectBaseMixin("GPURenderPassEncoder", GPURenderPassEncoder);
- const GPURenderPassEncoderPrototype = GPURenderPassEncoder.prototype;
/**
- * @param {string | null} label
- * @param {GPUCommandEncoder} encoder
- * @param {number} rid
- * @returns {GPUComputePassEncoder}
+ * @param {GPUBuffer} indirectBuffer
+ * @param {number} indirectOffset
*/
- function createGPUComputePassEncoder(label, encoder, rid) {
- /** @type {GPUComputePassEncoder} */
- const computePassEncoder = webidl.createBranded(GPUComputePassEncoder);
- computePassEncoder[_label] = label;
- computePassEncoder[_encoder] = encoder;
- computePassEncoder[_rid] = rid;
- return computePassEncoder;
+ drawIndirect(indirectBuffer, indirectOffset) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix = "Failed to execute 'drawIndirect' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const indirectBufferRid = assertResource(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, indirectBuffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_pass_draw_indirect(
+ renderPassRid,
+ indirectBufferRid,
+ indirectOffset,
+ );
}
- class GPUComputePassEncoder {
- /** @type {GPUCommandEncoder} */
- [_encoder];
+ /**
+ * @param {GPUBuffer} indirectBuffer
+ * @param {number} indirectOffset
+ */
+ drawIndexedIndirect(indirectBuffer, indirectOffset) {
+ webidl.assertBranded(this, GPURenderPassEncoderPrototype);
+ const prefix = "Failed to execute 'drawIndirect' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const indirectBufferRid = assertResource(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, indirectBuffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_pass_draw_indexed_indirect(
+ renderPassRid,
+ indirectBufferRid,
+ indirectOffset,
+ );
+ }
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPURenderPassEncoder", GPURenderPassEncoder);
+const GPURenderPassEncoderPrototype = GPURenderPassEncoder.prototype;
+
+/**
+ * @param {string | null} label
+ * @param {GPUCommandEncoder} encoder
+ * @param {number} rid
+ * @returns {GPUComputePassEncoder}
+ */
+function createGPUComputePassEncoder(label, encoder, rid) {
+ /** @type {GPUComputePassEncoder} */
+ const computePassEncoder = webidl.createBranded(GPUComputePassEncoder);
+ computePassEncoder[_label] = label;
+ computePassEncoder[_encoder] = encoder;
+ computePassEncoder[_rid] = rid;
+ return computePassEncoder;
+}
+
+class GPUComputePassEncoder {
+ /** @type {GPUCommandEncoder} */
+ [_encoder];
+
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ }
- constructor() {
- webidl.illegalConstructor();
- }
+ constructor() {
+ webidl.illegalConstructor();
+ }
- /**
- * @param {GPUComputePipeline} pipeline
- */
- setPipeline(pipeline) {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix =
- "Failed to execute 'setPipeline' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- pipeline = webidl.converters.GPUComputePipeline(pipeline, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- const pipelineRid = assertResource(pipeline, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, pipeline, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_compute_pass_set_pipeline(computePassRid, pipelineRid);
- }
+ /**
+ * @param {GPUComputePipeline} pipeline
+ */
+ setPipeline(pipeline) {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix = "Failed to execute 'setPipeline' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ pipeline = webidl.converters.GPUComputePipeline(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const pipelineRid = assertResource(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, pipeline, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_compute_pass_set_pipeline(computePassRid, pipelineRid);
+ }
- /**
- * @param {number} workgroupCountX
- * @param {number} workgroupCountY
- * @param {number} workgroupCountZ
- */
- dispatchWorkgroups(
+ /**
+ * @param {number} workgroupCountX
+ * @param {number} workgroupCountY
+ * @param {number} workgroupCountZ
+ */
+ dispatchWorkgroups(
+ workgroupCountX,
+ workgroupCountY = 1,
+ workgroupCountZ = 1,
+ ) {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'dispatchWorkgroups' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ workgroupCountX = webidl.converters.GPUSize32(workgroupCountX, {
+ prefix,
+ context: "Argument 1",
+ });
+ workgroupCountY = webidl.converters.GPUSize32(workgroupCountY, {
+ prefix,
+ context: "Argument 2",
+ });
+ workgroupCountZ = webidl.converters.GPUSize32(workgroupCountZ, {
+ prefix,
+ context: "Argument 3",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_compute_pass_dispatch_workgroups(
+ computePassRid,
workgroupCountX,
- workgroupCountY = 1,
- workgroupCountZ = 1,
- ) {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix =
- "Failed to execute 'dispatchWorkgroups' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- workgroupCountX = webidl.converters.GPUSize32(workgroupCountX, {
- prefix,
- context: "Argument 1",
- });
- workgroupCountY = webidl.converters.GPUSize32(workgroupCountY, {
- prefix,
- context: "Argument 2",
- });
- workgroupCountZ = webidl.converters.GPUSize32(workgroupCountZ, {
- prefix,
- context: "Argument 3",
- });
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_compute_pass_dispatch_workgroups(
- computePassRid,
- workgroupCountX,
- workgroupCountY,
- workgroupCountZ,
- );
- }
+ workgroupCountY,
+ workgroupCountZ,
+ );
+ }
- /**
- * @param {GPUBuffer} indirectBuffer
- * @param {number} indirectOffset
- */
- dispatchWorkgroupsIndirect(indirectBuffer, indirectOffset) {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix =
- "Failed to execute 'dispatchWorkgroupsIndirect' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
- prefix,
- context: "Argument 1",
- });
- indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
- prefix,
- context: "Argument 2",
- });
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- const indirectBufferRid = assertResource(indirectBuffer, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, indirectBuffer, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_compute_pass_dispatch_workgroups_indirect(
- computePassRid,
- indirectBufferRid,
- indirectOffset,
- );
- }
+ /**
+ * @param {GPUBuffer} indirectBuffer
+ * @param {number} indirectOffset
+ */
+ dispatchWorkgroupsIndirect(indirectBuffer, indirectOffset) {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'dispatchWorkgroupsIndirect' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const indirectBufferRid = assertResource(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, indirectBuffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_compute_pass_dispatch_workgroups_indirect(
+ computePassRid,
+ indirectBufferRid,
+ indirectOffset,
+ );
+ }
- /**
- * @param {GPUQuerySet} querySet
- * @param {number} queryIndex
- */
- beginPipelineStatisticsQuery(querySet, queryIndex) {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix =
- "Failed to execute 'beginPipelineStatisticsQuery' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- querySet = webidl.converters.GPUQuerySet(querySet, {
- prefix,
- context: "Argument 1",
- });
- queryIndex = webidl.converters.GPUSize32(queryIndex, {
- prefix,
- context: "Argument 2",
- });
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- const querySetRid = assertResource(querySet, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, querySet, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_compute_pass_begin_pipeline_statistics_query(
- computePassRid,
- querySetRid,
- queryIndex,
- );
- }
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} queryIndex
+ */
+ beginPipelineStatisticsQuery(querySet, queryIndex) {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'beginPipelineStatisticsQuery' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ queryIndex = webidl.converters.GPUSize32(queryIndex, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_compute_pass_begin_pipeline_statistics_query(
+ computePassRid,
+ querySetRid,
+ queryIndex,
+ );
+ }
- endPipelineStatisticsQuery() {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix =
- "Failed to execute 'endPipelineStatisticsQuery' on 'GPUComputePassEncoder'";
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_compute_pass_end_pipeline_statistics_query(computePassRid);
- }
+ endPipelineStatisticsQuery() {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'endPipelineStatisticsQuery' on 'GPUComputePassEncoder'";
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_compute_pass_end_pipeline_statistics_query(computePassRid);
+ }
- /**
- * @param {GPUQuerySet} querySet
- * @param {number} queryIndex
- */
- writeTimestamp(querySet, queryIndex) {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix =
- "Failed to execute 'writeTimestamp' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- querySet = webidl.converters.GPUQuerySet(querySet, {
- prefix,
- context: "Argument 1",
- });
- queryIndex = webidl.converters.GPUSize32(queryIndex, {
- prefix,
- context: "Argument 2",
- });
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- const querySetRid = assertResource(querySet, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, querySet, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_compute_pass_write_timestamp(
- computePassRid,
- querySetRid,
- queryIndex,
- );
- }
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} queryIndex
+ */
+ writeTimestamp(querySet, queryIndex) {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'writeTimestamp' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ queryIndex = webidl.converters.GPUSize32(queryIndex, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_compute_pass_write_timestamp(
+ computePassRid,
+ querySetRid,
+ queryIndex,
+ );
+ }
- end() {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix = "Failed to execute 'end' on 'GPUComputePassEncoder'";
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const commandEncoderRid = assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- const { err } = ops.op_webgpu_compute_pass_end(
- commandEncoderRid,
- computePassRid,
- );
- device.pushError(err);
- this[_rid] = undefined;
- }
+ end() {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix = "Failed to execute 'end' on 'GPUComputePassEncoder'";
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const commandEncoderRid = assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const { err } = ops.op_webgpu_compute_pass_end(
+ commandEncoderRid,
+ computePassRid,
+ );
+ device.pushError(err);
+ this[_rid] = undefined;
+ }
- // TODO(lucacasonato): has an overload
- setBindGroup(
+ // TODO(lucacasonato): has an overload
+ setBindGroup(
+ index,
+ bindGroup,
+ dynamicOffsetsData,
+ dynamicOffsetsDataStart,
+ dynamicOffsetsDataLength,
+ ) {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const bindGroupRid = assertResource(bindGroup, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDeviceMatch(device, bindGroup, {
+ prefix,
+ resourceContext: "Argument 2",
+ selfContext: "this",
+ });
+ if (
+ !(ObjectPrototypeIsPrototypeOf(
+ Uint32ArrayPrototype,
+ dynamicOffsetsData,
+ ))
+ ) {
+ dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
+ dynamicOffsetsDataStart = 0;
+ dynamicOffsetsDataLength = dynamicOffsetsData.length;
+ }
+ ops.op_webgpu_compute_pass_set_bind_group(
+ computePassRid,
index,
- bindGroup,
+ bindGroupRid,
dynamicOffsetsData,
dynamicOffsetsDataStart,
dynamicOffsetsDataLength,
- ) {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix =
- "Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
- const device = assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- const bindGroupRid = assertResource(bindGroup, {
- prefix,
- context: "Argument 2",
- });
- assertDeviceMatch(device, bindGroup, {
- prefix,
- resourceContext: "Argument 2",
- selfContext: "this",
- });
- if (
- !(ObjectPrototypeIsPrototypeOf(
- Uint32ArrayPrototype,
- dynamicOffsetsData,
- ))
- ) {
- dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
- dynamicOffsetsDataStart = 0;
- dynamicOffsetsDataLength = dynamicOffsetsData.length;
- }
- ops.op_webgpu_compute_pass_set_bind_group(
- computePassRid,
- index,
- bindGroupRid,
- dynamicOffsetsData,
- dynamicOffsetsDataStart,
- dynamicOffsetsDataLength,
- );
- }
-
- /**
- * @param {string} groupLabel
- */
- pushDebugGroup(groupLabel) {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix =
- "Failed to execute 'pushDebugGroup' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- groupLabel = webidl.converters.USVString(groupLabel, {
- prefix,
- context: "Argument 1",
- });
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_compute_pass_push_debug_group(computePassRid, groupLabel);
- }
-
- popDebugGroup() {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix =
- "Failed to execute 'popDebugGroup' on 'GPUComputePassEncoder'";
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_compute_pass_pop_debug_group(computePassRid);
- }
+ );
+ }
- /**
- * @param {string} markerLabel
- */
- insertDebugMarker(markerLabel) {
- webidl.assertBranded(this, GPUComputePassEncoderPrototype);
- const prefix =
- "Failed to execute 'insertDebugMarker' on 'GPUComputePassEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- markerLabel = webidl.converters.USVString(markerLabel, {
- prefix,
- context: "Argument 1",
- });
- assertDevice(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- assertResource(this[_encoder], {
- prefix,
- context: "encoder referenced by this",
- });
- const computePassRid = assertResource(this, { prefix, context: "this" });
- ops.op_webgpu_compute_pass_insert_debug_marker(
- computePassRid,
- markerLabel,
- );
- }
+ /**
+ * @param {string} groupLabel
+ */
+ pushDebugGroup(groupLabel) {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'pushDebugGroup' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ groupLabel = webidl.converters.USVString(groupLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_compute_pass_push_debug_group(computePassRid, groupLabel);
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ popDebugGroup() {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'popDebugGroup' on 'GPUComputePassEncoder'";
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_compute_pass_pop_debug_group(computePassRid);
}
- GPUObjectBaseMixin("GPUComputePassEncoder", GPUComputePassEncoder);
- const GPUComputePassEncoderPrototype = GPUComputePassEncoder.prototype;
/**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPUCommandBuffer}
+ * @param {string} markerLabel
*/
- function createGPUCommandBuffer(label, device, rid) {
- /** @type {GPUCommandBuffer} */
- const commandBuffer = webidl.createBranded(GPUCommandBuffer);
- commandBuffer[_label] = label;
- commandBuffer[_device] = device;
- commandBuffer[_rid] = rid;
- return commandBuffer;
+ insertDebugMarker(markerLabel) {
+ webidl.assertBranded(this, GPUComputePassEncoderPrototype);
+ const prefix =
+ "Failed to execute 'insertDebugMarker' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ markerLabel = webidl.converters.USVString(markerLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ ops.op_webgpu_compute_pass_insert_debug_marker(
+ computePassRid,
+ markerLabel,
+ );
}
- class GPUCommandBuffer {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUComputePassEncoder", GPUComputePassEncoder);
+const GPUComputePassEncoderPrototype = GPUComputePassEncoder.prototype;
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUCommandBuffer}
+ */
+function createGPUCommandBuffer(label, device, rid) {
+ /** @type {GPUCommandBuffer} */
+ const commandBuffer = webidl.createBranded(GPUCommandBuffer);
+ commandBuffer[_label] = label;
+ commandBuffer[_device] = device;
+ commandBuffer[_rid] = rid;
+ return commandBuffer;
+}
+
+class GPUCommandBuffer {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ }
- constructor() {
- webidl.illegalConstructor();
- }
+ constructor() {
+ webidl.illegalConstructor();
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUCommandBuffer", GPUCommandBuffer);
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPURenderBundleEncoder}
+ */
+function createGPURenderBundleEncoder(label, device, rid) {
+ /** @type {GPURenderBundleEncoder} */
+ const bundleEncoder = webidl.createBranded(GPURenderBundleEncoder);
+ bundleEncoder[_label] = label;
+ bundleEncoder[_device] = device;
+ bundleEncoder[_rid] = rid;
+ return bundleEncoder;
+}
+
+class GPURenderBundleEncoder {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
}
- GPUObjectBaseMixin("GPUCommandBuffer", GPUCommandBuffer);
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
/**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPURenderBundleEncoder}
+ * @param {GPURenderBundleDescriptor} descriptor
*/
- function createGPURenderBundleEncoder(label, device, rid) {
- /** @type {GPURenderBundleEncoder} */
- const bundleEncoder = webidl.createBranded(GPURenderBundleEncoder);
- bundleEncoder[_label] = label;
- bundleEncoder[_device] = device;
- bundleEncoder[_rid] = rid;
- return bundleEncoder;
- }
-
- class GPURenderBundleEncoder {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
-
- constructor() {
- webidl.illegalConstructor();
- }
+ finish(descriptor = {}) {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix = "Failed to execute 'finish' on 'GPURenderBundleEncoder'";
+ descriptor = webidl.converters.GPURenderBundleDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { rid, err } = ops.op_webgpu_render_bundle_encoder_finish(
+ renderBundleEncoderRid,
+ descriptor.label,
+ );
+ device.pushError(err);
+ this[_rid] = undefined;
- /**
- * @param {GPURenderBundleDescriptor} descriptor
- */
- finish(descriptor = {}) {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix = "Failed to execute 'finish' on 'GPURenderBundleEncoder'";
- descriptor = webidl.converters.GPURenderBundleDescriptor(descriptor, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const { rid, err } = ops.op_webgpu_render_bundle_encoder_finish(
- renderBundleEncoderRid,
- descriptor.label,
- );
- device.pushError(err);
- this[_rid] = undefined;
+ const renderBundle = createGPURenderBundle(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(renderBundle);
+ return renderBundle;
+ }
- const renderBundle = createGPURenderBundle(
- descriptor.label,
- device,
- rid,
- );
- device.trackResource(renderBundle);
- return renderBundle;
+ // TODO(lucacasonato): has an overload
+ setBindGroup(
+ index,
+ bindGroup,
+ dynamicOffsetsData,
+ dynamicOffsetsDataStart,
+ dynamicOffsetsDataLength,
+ ) {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix =
+ "Failed to execute 'setBindGroup' on 'GPURenderBundleEncoder'";
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const bindGroupRid = assertResource(bindGroup, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDeviceMatch(device, bindGroup, {
+ prefix,
+ resourceContext: "Argument 2",
+ selfContext: "this",
+ });
+ if (
+ !(ObjectPrototypeIsPrototypeOf(
+ Uint32ArrayPrototype,
+ dynamicOffsetsData,
+ ))
+ ) {
+ dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
+ dynamicOffsetsDataStart = 0;
+ dynamicOffsetsDataLength = dynamicOffsetsData.length;
}
-
- // TODO(lucacasonato): has an overload
- setBindGroup(
+ ops.op_webgpu_render_bundle_encoder_set_bind_group(
+ renderBundleEncoderRid,
index,
- bindGroup,
+ bindGroupRid,
dynamicOffsetsData,
dynamicOffsetsDataStart,
dynamicOffsetsDataLength,
- ) {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix =
- "Failed to execute 'setBindGroup' on 'GPURenderBundleEncoder'";
- const device = assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const bindGroupRid = assertResource(bindGroup, {
- prefix,
- context: "Argument 2",
- });
- assertDeviceMatch(device, bindGroup, {
- prefix,
- resourceContext: "Argument 2",
- selfContext: "this",
- });
- if (
- !(ObjectPrototypeIsPrototypeOf(
- Uint32ArrayPrototype,
- dynamicOffsetsData,
- ))
- ) {
- dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
- dynamicOffsetsDataStart = 0;
- dynamicOffsetsDataLength = dynamicOffsetsData.length;
- }
- ops.op_webgpu_render_bundle_encoder_set_bind_group(
- renderBundleEncoderRid,
- index,
- bindGroupRid,
- dynamicOffsetsData,
- dynamicOffsetsDataStart,
- dynamicOffsetsDataLength,
- );
- }
+ );
+ }
- /**
- * @param {string} groupLabel
- */
- pushDebugGroup(groupLabel) {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix =
- "Failed to execute 'pushDebugGroup' on 'GPURenderBundleEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- groupLabel = webidl.converters.USVString(groupLabel, {
- prefix,
- context: "Argument 1",
- });
- assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- ops.op_webgpu_render_bundle_encoder_push_debug_group(
- renderBundleEncoderRid,
- groupLabel,
- );
- }
+ /**
+ * @param {string} groupLabel
+ */
+ pushDebugGroup(groupLabel) {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix =
+ "Failed to execute 'pushDebugGroup' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ groupLabel = webidl.converters.USVString(groupLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ ops.op_webgpu_render_bundle_encoder_push_debug_group(
+ renderBundleEncoderRid,
+ groupLabel,
+ );
+ }
- popDebugGroup() {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix =
- "Failed to execute 'popDebugGroup' on 'GPURenderBundleEncoder'";
- assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- ops.op_webgpu_render_bundle_encoder_pop_debug_group(
- renderBundleEncoderRid,
- );
- }
+ popDebugGroup() {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix =
+ "Failed to execute 'popDebugGroup' on 'GPURenderBundleEncoder'";
+ assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ ops.op_webgpu_render_bundle_encoder_pop_debug_group(
+ renderBundleEncoderRid,
+ );
+ }
- /**
- * @param {string} markerLabel
- */
- insertDebugMarker(markerLabel) {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix =
- "Failed to execute 'insertDebugMarker' on 'GPURenderBundleEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- markerLabel = webidl.converters.USVString(markerLabel, {
- prefix,
- context: "Argument 1",
- });
- assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- ops.op_webgpu_render_bundle_encoder_insert_debug_marker(
- renderBundleEncoderRid,
- markerLabel,
- );
- }
+ /**
+ * @param {string} markerLabel
+ */
+ insertDebugMarker(markerLabel) {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix =
+ "Failed to execute 'insertDebugMarker' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ markerLabel = webidl.converters.USVString(markerLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ ops.op_webgpu_render_bundle_encoder_insert_debug_marker(
+ renderBundleEncoderRid,
+ markerLabel,
+ );
+ }
- /**
- * @param {GPURenderPipeline} pipeline
- */
- setPipeline(pipeline) {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix =
- "Failed to execute 'setPipeline' on 'GPURenderBundleEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- pipeline = webidl.converters.GPURenderPipeline(pipeline, {
- prefix,
- context: "Argument 1",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const pipelineRid = assertResource(pipeline, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, pipeline, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_render_bundle_encoder_set_pipeline(
- renderBundleEncoderRid,
- pipelineRid,
- );
- }
+ /**
+ * @param {GPURenderPipeline} pipeline
+ */
+ setPipeline(pipeline) {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix =
+ "Failed to execute 'setPipeline' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ pipeline = webidl.converters.GPURenderPipeline(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const pipelineRid = assertResource(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, pipeline, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_bundle_encoder_set_pipeline(
+ renderBundleEncoderRid,
+ pipelineRid,
+ );
+ }
- /**
- * @param {GPUBuffer} buffer
- * @param {GPUIndexFormat} indexFormat
- * @param {number} offset
- * @param {number} size
- */
- setIndexBuffer(buffer, indexFormat, offset = 0, size = 0) {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix =
- "Failed to execute 'setIndexBuffer' on 'GPURenderBundleEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- buffer = webidl.converters.GPUBuffer(buffer, {
- prefix,
- context: "Argument 1",
- });
- indexFormat = webidl.converters.GPUIndexFormat(indexFormat, {
- prefix,
- context: "Argument 2",
- });
- offset = webidl.converters.GPUSize64(offset, {
- prefix,
- context: "Argument 3",
- });
- size = webidl.converters.GPUSize64(size, {
- prefix,
- context: "Argument 4",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const bufferRid = assertResource(buffer, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, buffer, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_render_bundle_encoder_set_index_buffer(
- renderBundleEncoderRid,
- bufferRid,
- indexFormat,
- offset,
- size,
- );
- }
+ /**
+ * @param {GPUBuffer} buffer
+ * @param {GPUIndexFormat} indexFormat
+ * @param {number} offset
+ * @param {number} size
+ */
+ setIndexBuffer(buffer, indexFormat, offset = 0, size = 0) {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix =
+ "Failed to execute 'setIndexBuffer' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ buffer = webidl.converters.GPUBuffer(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indexFormat = webidl.converters.GPUIndexFormat(indexFormat, {
+ prefix,
+ context: "Argument 2",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 3",
+ });
+ size = webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 4",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_bundle_encoder_set_index_buffer(
+ renderBundleEncoderRid,
+ bufferRid,
+ indexFormat,
+ offset,
+ size,
+ );
+ }
- /**
- * @param {number} slot
- * @param {GPUBuffer} buffer
- * @param {number} offset
- * @param {number} size
- */
- setVertexBuffer(slot, buffer, offset = 0, size = 0) {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix =
- "Failed to execute 'setVertexBuffer' on 'GPURenderBundleEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- slot = webidl.converters.GPUSize32(slot, {
- prefix,
- context: "Argument 2",
- });
- buffer = webidl.converters.GPUBuffer(buffer, {
- prefix,
- context: "Argument 2",
- });
- offset = webidl.converters.GPUSize64(offset, {
- prefix,
- context: "Argument 3",
- });
- size = webidl.converters.GPUSize64(size, {
- prefix,
- context: "Argument 4",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const bufferRid = assertResource(buffer, {
- prefix,
- context: "Argument 2",
- });
- assertDeviceMatch(device, buffer, {
- prefix,
- resourceContext: "Argument 2",
- selfContext: "this",
- });
- ops.op_webgpu_render_bundle_encoder_set_vertex_buffer(
- renderBundleEncoderRid,
- slot,
- bufferRid,
- offset,
- size,
- );
- }
+ /**
+ * @param {number} slot
+ * @param {GPUBuffer} buffer
+ * @param {number} offset
+ * @param {number} size
+ */
+ setVertexBuffer(slot, buffer, offset = 0, size = 0) {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix =
+ "Failed to execute 'setVertexBuffer' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ slot = webidl.converters.GPUSize32(slot, {
+ prefix,
+ context: "Argument 2",
+ });
+ buffer = webidl.converters.GPUBuffer(buffer, {
+ prefix,
+ context: "Argument 2",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 3",
+ });
+ size = webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 4",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ resourceContext: "Argument 2",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_bundle_encoder_set_vertex_buffer(
+ renderBundleEncoderRid,
+ slot,
+ bufferRid,
+ offset,
+ size,
+ );
+ }
- /**
- * @param {number} vertexCount
- * @param {number} instanceCount
- * @param {number} firstVertex
- * @param {number} firstInstance
- */
- draw(vertexCount, instanceCount = 1, firstVertex = 0, firstInstance = 0) {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix = "Failed to execute 'draw' on 'GPURenderBundleEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- vertexCount = webidl.converters.GPUSize32(vertexCount, {
- prefix,
- context: "Argument 1",
- });
- instanceCount = webidl.converters.GPUSize32(instanceCount, {
- prefix,
- context: "Argument 2",
- });
- firstVertex = webidl.converters.GPUSize32(firstVertex, {
- prefix,
- context: "Argument 3",
- });
- firstInstance = webidl.converters.GPUSize32(firstInstance, {
- prefix,
- context: "Argument 4",
- });
- assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- ops.op_webgpu_render_bundle_encoder_draw(
- renderBundleEncoderRid,
- vertexCount,
- instanceCount,
- firstVertex,
- firstInstance,
- );
- }
+ /**
+ * @param {number} vertexCount
+ * @param {number} instanceCount
+ * @param {number} firstVertex
+ * @param {number} firstInstance
+ */
+ draw(vertexCount, instanceCount = 1, firstVertex = 0, firstInstance = 0) {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix = "Failed to execute 'draw' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ vertexCount = webidl.converters.GPUSize32(vertexCount, {
+ prefix,
+ context: "Argument 1",
+ });
+ instanceCount = webidl.converters.GPUSize32(instanceCount, {
+ prefix,
+ context: "Argument 2",
+ });
+ firstVertex = webidl.converters.GPUSize32(firstVertex, {
+ prefix,
+ context: "Argument 3",
+ });
+ firstInstance = webidl.converters.GPUSize32(firstInstance, {
+ prefix,
+ context: "Argument 4",
+ });
+ assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ ops.op_webgpu_render_bundle_encoder_draw(
+ renderBundleEncoderRid,
+ vertexCount,
+ instanceCount,
+ firstVertex,
+ firstInstance,
+ );
+ }
- /**
- * @param {number} indexCount
- * @param {number} instanceCount
- * @param {number} firstIndex
- * @param {number} baseVertex
- * @param {number} firstInstance
- */
- drawIndexed(
+ /**
+ * @param {number} indexCount
+ * @param {number} instanceCount
+ * @param {number} firstIndex
+ * @param {number} baseVertex
+ * @param {number} firstInstance
+ */
+ drawIndexed(
+ indexCount,
+ instanceCount = 1,
+ firstIndex = 0,
+ baseVertex = 0,
+ firstInstance = 0,
+ ) {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix =
+ "Failed to execute 'drawIndexed' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ indexCount = webidl.converters.GPUSize32(indexCount, {
+ prefix,
+ context: "Argument 1",
+ });
+ instanceCount = webidl.converters.GPUSize32(instanceCount, {
+ prefix,
+ context: "Argument 2",
+ });
+ firstIndex = webidl.converters.GPUSize32(firstIndex, {
+ prefix,
+ context: "Argument 3",
+ });
+ baseVertex = webidl.converters.GPUSignedOffset32(baseVertex, {
+ prefix,
+ context: "Argument 4",
+ });
+ firstInstance = webidl.converters.GPUSize32(firstInstance, {
+ prefix,
+ context: "Argument 5",
+ });
+ assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ ops.op_webgpu_render_bundle_encoder_draw_indexed(
+ renderBundleEncoderRid,
indexCount,
- instanceCount = 1,
- firstIndex = 0,
- baseVertex = 0,
- firstInstance = 0,
- ) {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix =
- "Failed to execute 'drawIndexed' on 'GPURenderBundleEncoder'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- indexCount = webidl.converters.GPUSize32(indexCount, {
- prefix,
- context: "Argument 1",
- });
- instanceCount = webidl.converters.GPUSize32(instanceCount, {
- prefix,
- context: "Argument 2",
- });
- firstIndex = webidl.converters.GPUSize32(firstIndex, {
- prefix,
- context: "Argument 3",
- });
- baseVertex = webidl.converters.GPUSignedOffset32(baseVertex, {
- prefix,
- context: "Argument 4",
- });
- firstInstance = webidl.converters.GPUSize32(firstInstance, {
- prefix,
- context: "Argument 5",
- });
- assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- ops.op_webgpu_render_bundle_encoder_draw_indexed(
- renderBundleEncoderRid,
- indexCount,
- instanceCount,
- firstIndex,
- baseVertex,
- firstInstance,
- );
- }
-
- /**
- * @param {GPUBuffer} indirectBuffer
- * @param {number} indirectOffset
- */
- drawIndirect(indirectBuffer, indirectOffset) {
- webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
- const prefix =
- "Failed to execute 'drawIndirect' on 'GPURenderBundleEncoder'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
- prefix,
- context: "Argument 1",
- });
- indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
- prefix,
- context: "Argument 2",
- });
- const device = assertDevice(this, { prefix, context: "this" });
- const renderBundleEncoderRid = assertResource(this, {
- prefix,
- context: "this",
- });
- const indirectBufferRid = assertResource(indirectBuffer, {
- prefix,
- context: "Argument 1",
- });
- assertDeviceMatch(device, indirectBuffer, {
- prefix,
- resourceContext: "Argument 1",
- selfContext: "this",
- });
- ops.op_webgpu_render_bundle_encoder_draw_indirect(
- renderBundleEncoderRid,
- indirectBufferRid,
- indirectOffset,
- );
- }
-
- drawIndexedIndirect(_indirectBuffer, _indirectOffset) {
- throw new Error("Not yet implemented");
- }
-
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ instanceCount,
+ firstIndex,
+ baseVertex,
+ firstInstance,
+ );
}
- GPUObjectBaseMixin("GPURenderBundleEncoder", GPURenderBundleEncoder);
- const GPURenderBundleEncoderPrototype = GPURenderBundleEncoder.prototype;
/**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPURenderBundle}
+ * @param {GPUBuffer} indirectBuffer
+ * @param {number} indirectOffset
*/
- function createGPURenderBundle(label, device, rid) {
- /** @type {GPURenderBundle} */
- const bundle = webidl.createBranded(GPURenderBundle);
- bundle[_label] = label;
- bundle[_device] = device;
- bundle[_rid] = rid;
- return bundle;
- }
-
- class GPURenderBundle {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
+ drawIndirect(indirectBuffer, indirectOffset) {
+ webidl.assertBranded(this, GPURenderBundleEncoderPrototype);
+ const prefix =
+ "Failed to execute 'drawIndirect' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const indirectBufferRid = assertResource(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, indirectBuffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ ops.op_webgpu_render_bundle_encoder_draw_indirect(
+ renderBundleEncoderRid,
+ indirectBufferRid,
+ indirectOffset,
+ );
+ }
- constructor() {
- webidl.illegalConstructor();
- }
+ drawIndexedIndirect(_indirectBuffer, _indirectOffset) {
+ throw new Error("Not yet implemented");
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPURenderBundleEncoder", GPURenderBundleEncoder);
+const GPURenderBundleEncoderPrototype = GPURenderBundleEncoder.prototype;
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPURenderBundle}
+ */
+function createGPURenderBundle(label, device, rid) {
+ /** @type {GPURenderBundle} */
+ const bundle = webidl.createBranded(GPURenderBundle);
+ bundle[_label] = label;
+ bundle[_device] = device;
+ bundle[_rid] = rid;
+ return bundle;
+}
+
+class GPURenderBundle {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
}
- GPUObjectBaseMixin("GPURenderBundle", GPURenderBundle);
- /**
- * @param {string | null} label
- * @param {InnerGPUDevice} device
- * @param {number} rid
- * @returns {GPUQuerySet}
- */
- function createGPUQuerySet(label, device, rid, descriptor) {
- /** @type {GPUQuerySet} */
- const queue = webidl.createBranded(GPUQuerySet);
- queue[_label] = label;
- queue[_device] = device;
- queue[_rid] = rid;
- queue[_descriptor] = descriptor;
- return queue;
- }
-
- class GPUQuerySet {
- /** @type {InnerGPUDevice} */
- [_device];
- /** @type {number | undefined} */
- [_rid];
- /** @type {GPUQuerySetDescriptor} */
- [_descriptor];
- /** @type {GPUQueryType} */
- [_type];
- /** @type {number} */
- [_count];
-
- [_cleanup]() {
- const rid = this[_rid];
- if (rid !== undefined) {
- core.close(rid);
- /** @type {number | undefined} */
- this[_rid] = undefined;
- }
- }
+ constructor() {
+ webidl.illegalConstructor();
+ }
- constructor() {
- webidl.illegalConstructor();
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPURenderBundle", GPURenderBundle);
+
+/**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUQuerySet}
+ */
+function createGPUQuerySet(label, device, rid, descriptor) {
+ /** @type {GPUQuerySet} */
+ const queue = webidl.createBranded(GPUQuerySet);
+ queue[_label] = label;
+ queue[_device] = device;
+ queue[_rid] = rid;
+ queue[_descriptor] = descriptor;
+ return queue;
+}
+
+class GPUQuerySet {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+ /** @type {GPUQuerySetDescriptor} */
+ [_descriptor];
+ /** @type {GPUQueryType} */
+ [_type];
+ /** @type {number} */
+ [_count];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
}
+ }
- destroy() {
- webidl.assertBranded(this, GPUQuerySetPrototype);
- this[_cleanup]();
- }
+ constructor() {
+ webidl.illegalConstructor();
+ }
- get type() {
- webidl.assertBranded(this, GPUQuerySetPrototype);
- return this[_type]();
- }
+ destroy() {
+ webidl.assertBranded(this, GPUQuerySetPrototype);
+ this[_cleanup]();
+ }
- get count() {
- webidl.assertBranded(this, GPUQuerySetPrototype);
- return this[_count]();
- }
+ get type() {
+ webidl.assertBranded(this, GPUQuerySetPrototype);
+ return this[_type]();
+ }
- [SymbolFor("Deno.privateCustomInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- label: this.label,
- })
- }`;
- }
+ get count() {
+ webidl.assertBranded(this, GPUQuerySetPrototype);
+ return this[_count]();
}
- GPUObjectBaseMixin("GPUQuerySet", GPUQuerySet);
- const GPUQuerySetPrototype = GPUQuerySet.prototype;
-
- window.__bootstrap.webgpu = {
- _device,
- assertDevice,
- createGPUTexture,
- gpu: webidl.createBranded(GPU),
- GPU,
- GPUAdapter,
- GPUAdapterInfo,
- GPUSupportedLimits,
- GPUSupportedFeatures,
- GPUDevice,
- GPUDeviceLostInfo,
- GPUQueue,
- GPUBuffer,
- GPUBufferUsage,
- GPUMapMode,
- GPUTextureUsage,
- GPUTexture,
- GPUTextureView,
- GPUSampler,
- GPUBindGroupLayout,
- GPUPipelineLayout,
- GPUBindGroup,
- GPUShaderModule,
- GPUShaderStage,
- GPUComputePipeline,
- GPURenderPipeline,
- GPUColorWrite,
- GPUCommandEncoder,
- GPURenderPassEncoder,
- GPUComputePassEncoder,
- GPUCommandBuffer,
- GPURenderBundleEncoder,
- GPURenderBundle,
- GPUQuerySet,
- GPUError,
- GPUValidationError,
- GPUOutOfMemoryError,
- };
-})(this);
+
+ [SymbolFor("Deno.privateCustomInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+}
+GPUObjectBaseMixin("GPUQuerySet", GPUQuerySet);
+const GPUQuerySetPrototype = GPUQuerySet.prototype;
+
+const gpu = webidl.createBranded(GPU);
+export {
+ _device,
+ assertDevice,
+ createGPUTexture,
+ GPU,
+ gpu,
+ GPUAdapter,
+ GPUAdapterInfo,
+ GPUBindGroup,
+ GPUBindGroupLayout,
+ GPUBuffer,
+ GPUBufferUsage,
+ GPUColorWrite,
+ GPUCommandBuffer,
+ GPUCommandEncoder,
+ GPUComputePassEncoder,
+ GPUComputePipeline,
+ GPUDevice,
+ GPUDeviceLostInfo,
+ GPUError,
+ GPUMapMode,
+ GPUOutOfMemoryError,
+ GPUPipelineLayout,
+ GPUQuerySet,
+ GPUQueue,
+ GPURenderBundle,
+ GPURenderBundleEncoder,
+ GPURenderPassEncoder,
+ GPURenderPipeline,
+ GPUSampler,
+ GPUShaderModule,
+ GPUShaderStage,
+ GPUSupportedFeatures,
+ GPUSupportedLimits,
+ GPUTexture,
+ GPUTextureUsage,
+ GPUTextureView,
+ GPUValidationError,
+};
diff --git a/ext/webgpu/src/02_idl_types.js b/ext/webgpu/src/02_idl_types.js
index c927f10a5..daafdfa4b 100644
--- a/ext/webgpu/src/02_idl_types.js
+++ b/ext/webgpu/src/02_idl_types.js
@@ -3,2038 +3,2034 @@
// @ts-check
/// <reference path="../web/internal.d.ts" />
-"use strict";
-
-((window) => {
- const webidl = window.__bootstrap.webidl;
- const {
- GPU,
- GPUAdapter,
- GPUSupportedLimits,
- GPUSupportedFeatures,
- GPUDevice,
- GPUQueue,
- GPUBuffer,
- GPUBufferUsage,
- GPUMapMode,
- GPUTextureUsage,
- GPUTexture,
- GPUTextureView,
- GPUSampler,
- GPUBindGroupLayout,
- GPUPipelineLayout,
- GPUBindGroup,
- GPUShaderModule,
- GPUShaderStage,
- GPUComputePipeline,
- GPURenderPipeline,
- GPUColorWrite,
- GPUCommandEncoder,
- GPURenderPassEncoder,
- GPUComputePassEncoder,
- GPUCommandBuffer,
- GPURenderBundleEncoder,
- GPURenderBundle,
- GPUQuerySet,
- GPUOutOfMemoryError,
- GPUValidationError,
- } = window.__bootstrap.webgpu;
- const { SymbolIterator, TypeError } = window.__bootstrap.primordials;
-
- // This needs to be initialized after all of the base classes are implemented,
- // otherwise their converters might not be available yet.
- // DICTIONARY: GPUObjectDescriptorBase
- const dictMembersGPUObjectDescriptorBase = [
- { key: "label", converter: webidl.converters["USVString"] },
- ];
- webidl.converters["GPUObjectDescriptorBase"] = webidl
- .createDictionaryConverter(
- "GPUObjectDescriptorBase",
- dictMembersGPUObjectDescriptorBase,
- );
-
- // INTERFACE: GPUSupportedLimits
- webidl.converters.GPUSupportedLimits = webidl.createInterfaceConverter(
- "GPUSupportedLimits",
- GPUSupportedLimits.prototype,
- );
-
- // INTERFACE: GPUSupportedFeatures
- webidl.converters.GPUSupportedFeatures = webidl.createInterfaceConverter(
- "GPUSupportedFeatures",
- GPUSupportedFeatures.prototype,
- );
-
- // INTERFACE: GPU
- webidl.converters.GPU = webidl.createInterfaceConverter("GPU", GPU.prototype);
-
- // ENUM: GPUPowerPreference
- webidl.converters["GPUPowerPreference"] = webidl.createEnumConverter(
- "GPUPowerPreference",
- [
- "low-power",
- "high-performance",
- ],
- );
-
- // DICTIONARY: GPURequestAdapterOptions
- const dictMembersGPURequestAdapterOptions = [
- {
- key: "powerPreference",
- converter: webidl.converters["GPUPowerPreference"],
- },
- {
- key: "forceFallbackAdapter",
- converter: webidl.converters.boolean,
- defaultValue: false,
- },
- ];
- webidl.converters["GPURequestAdapterOptions"] = webidl
- .createDictionaryConverter(
- "GPURequestAdapterOptions",
- dictMembersGPURequestAdapterOptions,
- );
-
- // INTERFACE: GPUAdapter
- webidl.converters.GPUAdapter = webidl.createInterfaceConverter(
- "GPUAdapter",
- GPUAdapter.prototype,
- );
-
- // ENUM: GPUFeatureName
- webidl.converters["GPUFeatureName"] = webidl.createEnumConverter(
- "GPUFeatureName",
- [
- "depth-clip-control",
- "depth32float-stencil8",
- "pipeline-statistics-query",
- "texture-compression-bc",
- "texture-compression-etc2",
- "texture-compression-astc",
- "timestamp-query",
- "indirect-first-instance",
- "shader-f16",
- // extended from spec
- "mappable-primary-buffers",
- "texture-binding-array",
- "buffer-binding-array",
- "storage-resource-binding-array",
- "sampled-texture-and-storage-buffer-array-non-uniform-indexing",
- "uniform-buffer-and-storage-buffer-texture-non-uniform-indexing",
- "unsized-binding-array",
- "multi-draw-indirect",
- "multi-draw-indirect-count",
- "push-constants",
- "address-mode-clamp-to-border",
- "texture-adapter-specific-format-features",
- "shader-float64",
- "vertex-attribute-64bit",
- "conservative-rasterization",
- "vertex-writable-storage",
- "clear-commands",
- "spirv-shader-passthrough",
- "shader-primitive-index",
- ],
- );
-
- // TYPEDEF: GPUSize32
- webidl.converters["GPUSize32"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
-
- // TYPEDEF: GPUSize64
- webidl.converters["GPUSize64"] = (V, opts) =>
- webidl.converters["unsigned long long"](V, { ...opts, enforceRange: true });
-
- // DICTIONARY: GPUDeviceDescriptor
- const dictMembersGPUDeviceDescriptor = [
- {
- key: "requiredFeatures",
- converter: webidl.createSequenceConverter(
- webidl.converters["GPUFeatureName"],
- ),
- get defaultValue() {
- return [];
- },
- },
- {
- key: "requiredLimits",
- converter: webidl.createRecordConverter(
- webidl.converters["DOMString"],
- webidl.converters["GPUSize64"],
- ),
- },
- ];
- webidl.converters["GPUDeviceDescriptor"] = webidl.createDictionaryConverter(
- "GPUDeviceDescriptor",
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import {
+ GPU,
+ GPUAdapter,
+ GPUBindGroup,
+ GPUBindGroupLayout,
+ GPUBuffer,
+ GPUBufferUsage,
+ GPUColorWrite,
+ GPUCommandBuffer,
+ GPUCommandEncoder,
+ GPUComputePassEncoder,
+ GPUComputePipeline,
+ GPUDevice,
+ GPUMapMode,
+ GPUOutOfMemoryError,
+ GPUPipelineLayout,
+ GPUQuerySet,
+ GPUQueue,
+ GPURenderBundle,
+ GPURenderBundleEncoder,
+ GPURenderPassEncoder,
+ GPURenderPipeline,
+ GPUSampler,
+ GPUShaderModule,
+ GPUShaderStage,
+ GPUSupportedFeatures,
+ GPUSupportedLimits,
+ GPUTexture,
+ GPUTextureUsage,
+ GPUTextureView,
+ GPUValidationError,
+} from "internal:ext/webgpu/01_webgpu.js";
+const primordials = globalThis.__bootstrap.primordials;
+const { SymbolIterator, TypeError } = primordials;
+
+// This needs to be initialized after all of the base classes are implemented,
+// otherwise their converters might not be available yet.
+// DICTIONARY: GPUObjectDescriptorBase
+const dictMembersGPUObjectDescriptorBase = [
+ { key: "label", converter: webidl.converters["USVString"] },
+];
+webidl.converters["GPUObjectDescriptorBase"] = webidl
+ .createDictionaryConverter(
+ "GPUObjectDescriptorBase",
dictMembersGPUObjectDescriptorBase,
- dictMembersGPUDeviceDescriptor,
- );
-
- // INTERFACE: GPUDevice
- webidl.converters.GPUDevice = webidl.createInterfaceConverter(
- "GPUDevice",
- GPUDevice.prototype,
);
- // INTERFACE: GPUBuffer
- webidl.converters.GPUBuffer = webidl.createInterfaceConverter(
- "GPUBuffer",
- GPUBuffer.prototype,
- );
-
- // TYPEDEF: GPUBufferUsageFlags
- webidl.converters["GPUBufferUsageFlags"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
-
- // DICTIONARY: GPUBufferDescriptor
- const dictMembersGPUBufferDescriptor = [
- { key: "size", converter: webidl.converters["GPUSize64"], required: true },
- {
- key: "usage",
- converter: webidl.converters["GPUBufferUsageFlags"],
- required: true,
- },
- {
- key: "mappedAtCreation",
- converter: webidl.converters["boolean"],
- defaultValue: false,
- },
- ];
- webidl.converters["GPUBufferDescriptor"] = webidl.createDictionaryConverter(
- "GPUBufferDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUBufferDescriptor,
- );
-
- // INTERFACE: GPUBufferUsage
- webidl.converters.GPUBufferUsage = webidl.createInterfaceConverter(
- "GPUBufferUsage",
- GPUBufferUsage.prototype,
- );
-
- // TYPEDEF: GPUMapModeFlags
- webidl.converters["GPUMapModeFlags"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
-
- // INTERFACE: GPUMapMode
- webidl.converters.GPUMapMode = webidl.createInterfaceConverter(
- "GPUMapMode",
- GPUMapMode.prototype,
- );
-
- // INTERFACE: GPUTexture
- webidl.converters.GPUTexture = webidl.createInterfaceConverter(
- "GPUTexture",
- GPUTexture.prototype,
- );
-
- // TYPEDEF: GPUIntegerCoordinate
- webidl.converters["GPUIntegerCoordinate"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
- webidl.converters["sequence<GPUIntegerCoordinate>"] = webidl
- .createSequenceConverter(webidl.converters["GPUIntegerCoordinate"]);
-
- // DICTIONARY: GPUExtent3DDict
- const dictMembersGPUExtent3DDict = [
- {
- key: "width",
- converter: webidl.converters["GPUIntegerCoordinate"],
- required: true,
- },
- {
- key: "height",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 1,
- },
- {
- key: "depthOrArrayLayers",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 1,
- },
- ];
- webidl.converters["GPUExtent3DDict"] = webidl.createDictionaryConverter(
- "GPUExtent3DDict",
- dictMembersGPUExtent3DDict,
- );
-
- // TYPEDEF: GPUExtent3D
- webidl.converters["GPUExtent3D"] = (V, opts) => {
- // Union for (sequence<GPUIntegerCoordinate> or GPUExtent3DDict)
- if (V === null || V === undefined) {
- return webidl.converters["GPUExtent3DDict"](V, opts);
- }
- if (typeof V === "object") {
- const method = V[SymbolIterator];
- if (method !== undefined) {
- return webidl.converters["sequence<GPUIntegerCoordinate>"](V, opts);
- }
- return webidl.converters["GPUExtent3DDict"](V, opts);
+// INTERFACE: GPUSupportedLimits
+webidl.converters.GPUSupportedLimits = webidl.createInterfaceConverter(
+ "GPUSupportedLimits",
+ GPUSupportedLimits.prototype,
+);
+
+// INTERFACE: GPUSupportedFeatures
+webidl.converters.GPUSupportedFeatures = webidl.createInterfaceConverter(
+ "GPUSupportedFeatures",
+ GPUSupportedFeatures.prototype,
+);
+
+// INTERFACE: GPU
+webidl.converters.GPU = webidl.createInterfaceConverter("GPU", GPU.prototype);
+
+// ENUM: GPUPowerPreference
+webidl.converters["GPUPowerPreference"] = webidl.createEnumConverter(
+ "GPUPowerPreference",
+ [
+ "low-power",
+ "high-performance",
+ ],
+);
+
+// DICTIONARY: GPURequestAdapterOptions
+const dictMembersGPURequestAdapterOptions = [
+ {
+ key: "powerPreference",
+ converter: webidl.converters["GPUPowerPreference"],
+ },
+ {
+ key: "forceFallbackAdapter",
+ converter: webidl.converters.boolean,
+ defaultValue: false,
+ },
+];
+webidl.converters["GPURequestAdapterOptions"] = webidl
+ .createDictionaryConverter(
+ "GPURequestAdapterOptions",
+ dictMembersGPURequestAdapterOptions,
+ );
+
+// INTERFACE: GPUAdapter
+webidl.converters.GPUAdapter = webidl.createInterfaceConverter(
+ "GPUAdapter",
+ GPUAdapter.prototype,
+);
+
+// ENUM: GPUFeatureName
+webidl.converters["GPUFeatureName"] = webidl.createEnumConverter(
+ "GPUFeatureName",
+ [
+ "depth-clip-control",
+ "depth32float-stencil8",
+ "pipeline-statistics-query",
+ "texture-compression-bc",
+ "texture-compression-etc2",
+ "texture-compression-astc",
+ "timestamp-query",
+ "indirect-first-instance",
+ "shader-f16",
+ // extended from spec
+ "mappable-primary-buffers",
+ "texture-binding-array",
+ "buffer-binding-array",
+ "storage-resource-binding-array",
+ "sampled-texture-and-storage-buffer-array-non-uniform-indexing",
+ "uniform-buffer-and-storage-buffer-texture-non-uniform-indexing",
+ "unsized-binding-array",
+ "multi-draw-indirect",
+ "multi-draw-indirect-count",
+ "push-constants",
+ "address-mode-clamp-to-border",
+ "texture-adapter-specific-format-features",
+ "shader-float64",
+ "vertex-attribute-64bit",
+ "conservative-rasterization",
+ "vertex-writable-storage",
+ "clear-commands",
+ "spirv-shader-passthrough",
+ "shader-primitive-index",
+ ],
+);
+
+// TYPEDEF: GPUSize32
+webidl.converters["GPUSize32"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+
+// TYPEDEF: GPUSize64
+webidl.converters["GPUSize64"] = (V, opts) =>
+ webidl.converters["unsigned long long"](V, { ...opts, enforceRange: true });
+
+// DICTIONARY: GPUDeviceDescriptor
+const dictMembersGPUDeviceDescriptor = [
+ {
+ key: "requiredFeatures",
+ converter: webidl.createSequenceConverter(
+ webidl.converters["GPUFeatureName"],
+ ),
+ get defaultValue() {
+ return [];
+ },
+ },
+ {
+ key: "requiredLimits",
+ converter: webidl.createRecordConverter(
+ webidl.converters["DOMString"],
+ webidl.converters["GPUSize64"],
+ ),
+ },
+];
+webidl.converters["GPUDeviceDescriptor"] = webidl.createDictionaryConverter(
+ "GPUDeviceDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUDeviceDescriptor,
+);
+
+// INTERFACE: GPUDevice
+webidl.converters.GPUDevice = webidl.createInterfaceConverter(
+ "GPUDevice",
+ GPUDevice.prototype,
+);
+
+// INTERFACE: GPUBuffer
+webidl.converters.GPUBuffer = webidl.createInterfaceConverter(
+ "GPUBuffer",
+ GPUBuffer.prototype,
+);
+
+// TYPEDEF: GPUBufferUsageFlags
+webidl.converters["GPUBufferUsageFlags"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+
+// DICTIONARY: GPUBufferDescriptor
+const dictMembersGPUBufferDescriptor = [
+ { key: "size", converter: webidl.converters["GPUSize64"], required: true },
+ {
+ key: "usage",
+ converter: webidl.converters["GPUBufferUsageFlags"],
+ required: true,
+ },
+ {
+ key: "mappedAtCreation",
+ converter: webidl.converters["boolean"],
+ defaultValue: false,
+ },
+];
+webidl.converters["GPUBufferDescriptor"] = webidl.createDictionaryConverter(
+ "GPUBufferDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUBufferDescriptor,
+);
+
+// INTERFACE: GPUBufferUsage
+webidl.converters.GPUBufferUsage = webidl.createInterfaceConverter(
+ "GPUBufferUsage",
+ GPUBufferUsage.prototype,
+);
+
+// TYPEDEF: GPUMapModeFlags
+webidl.converters["GPUMapModeFlags"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+
+// INTERFACE: GPUMapMode
+webidl.converters.GPUMapMode = webidl.createInterfaceConverter(
+ "GPUMapMode",
+ GPUMapMode.prototype,
+);
+
+// INTERFACE: GPUTexture
+webidl.converters.GPUTexture = webidl.createInterfaceConverter(
+ "GPUTexture",
+ GPUTexture.prototype,
+);
+
+// TYPEDEF: GPUIntegerCoordinate
+webidl.converters["GPUIntegerCoordinate"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+webidl.converters["sequence<GPUIntegerCoordinate>"] = webidl
+ .createSequenceConverter(webidl.converters["GPUIntegerCoordinate"]);
+
+// DICTIONARY: GPUExtent3DDict
+const dictMembersGPUExtent3DDict = [
+ {
+ key: "width",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ required: true,
+ },
+ {
+ key: "height",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 1,
+ },
+ {
+ key: "depthOrArrayLayers",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 1,
+ },
+];
+webidl.converters["GPUExtent3DDict"] = webidl.createDictionaryConverter(
+ "GPUExtent3DDict",
+ dictMembersGPUExtent3DDict,
+);
+
+// TYPEDEF: GPUExtent3D
+webidl.converters["GPUExtent3D"] = (V, opts) => {
+ // Union for (sequence<GPUIntegerCoordinate> or GPUExtent3DDict)
+ if (V === null || V === undefined) {
+ return webidl.converters["GPUExtent3DDict"](V, opts);
+ }
+ if (typeof V === "object") {
+ const method = V[SymbolIterator];
+ if (method !== undefined) {
+ return webidl.converters["sequence<GPUIntegerCoordinate>"](V, opts);
}
- throw webidl.makeException(
- TypeError,
- "can not be converted to sequence<GPUIntegerCoordinate> or GPUExtent3DDict.",
- opts,
- );
- };
-
- // ENUM: GPUTextureDimension
- webidl.converters["GPUTextureDimension"] = webidl.createEnumConverter(
- "GPUTextureDimension",
- [
- "1d",
- "2d",
- "3d",
- ],
- );
-
- // ENUM: GPUTextureFormat
- webidl.converters["GPUTextureFormat"] = webidl.createEnumConverter(
- "GPUTextureFormat",
- [
- "r8unorm",
- "r8snorm",
- "r8uint",
- "r8sint",
- "r16uint",
- "r16sint",
- "r16float",
- "rg8unorm",
- "rg8snorm",
- "rg8uint",
- "rg8sint",
- "r32uint",
- "r32sint",
- "r32float",
- "rg16uint",
- "rg16sint",
- "rg16float",
- "rgba8unorm",
- "rgba8unorm-srgb",
- "rgba8snorm",
- "rgba8uint",
- "rgba8sint",
- "bgra8unorm",
- "bgra8unorm-srgb",
- "rgb9e5ufloat",
- "rgb10a2unorm",
- "rg11b10ufloat",
- "rg32uint",
- "rg32sint",
- "rg32float",
- "rgba16uint",
- "rgba16sint",
- "rgba16float",
- "rgba32uint",
- "rgba32sint",
- "rgba32float",
- "stencil8",
- "depth16unorm",
- "depth24plus",
- "depth24plus-stencil8",
- "depth32float",
- "depth32float-stencil8",
- "bc1-rgba-unorm",
- "bc1-rgba-unorm-srgb",
- "bc2-rgba-unorm",
- "bc2-rgba-unorm-srgb",
- "bc3-rgba-unorm",
- "bc3-rgba-unorm-srgb",
- "bc4-r-unorm",
- "bc4-r-snorm",
- "bc5-rg-unorm",
- "bc5-rg-snorm",
- "bc6h-rgb-ufloat",
- "bc6h-rgb-float",
- "bc7-rgba-unorm",
- "bc7-rgba-unorm-srgb",
- "etc2-rgb8unorm",
- "etc2-rgb8unorm-srgb",
- "etc2-rgb8a1unorm",
- "etc2-rgb8a1unorm-srgb",
- "etc2-rgba8unorm",
- "etc2-rgba8unorm-srgb",
- "eac-r11unorm",
- "eac-r11snorm",
- "eac-rg11unorm",
- "eac-rg11snorm",
- "astc-4x4-unorm",
- "astc-4x4-unorm-srgb",
- "astc-5x4-unorm",
- "astc-5x4-unorm-srgb",
- "astc-5x5-unorm",
- "astc-5x5-unorm-srgb",
- "astc-6x5-unorm",
- "astc-6x5-unorm-srgb",
- "astc-6x6-unorm",
- "astc-6x6-unorm-srgb",
- "astc-8x5-unorm",
- "astc-8x5-unorm-srgb",
- "astc-8x6-unorm",
- "astc-8x6-unorm-srgb",
- "astc-8x8-unorm",
- "astc-8x8-unorm-srgb",
- "astc-10x5-unorm",
- "astc-10x5-unorm-srgb",
- "astc-10x6-unorm",
- "astc-10x6-unorm-srgb",
- "astc-10x8-unorm",
- "astc-10x8-unorm-srgb",
- "astc-10x10-unorm",
- "astc-10x10-unorm-srgb",
- "astc-12x10-unorm",
- "astc-12x10-unorm-srgb",
- "astc-12x12-unorm",
- "astc-12x12-unorm-srgb",
- ],
- );
-
- // TYPEDEF: GPUTextureUsageFlags
- webidl.converters["GPUTextureUsageFlags"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
-
- // DICTIONARY: GPUTextureDescriptor
- const dictMembersGPUTextureDescriptor = [
- {
- key: "size",
- converter: webidl.converters["GPUExtent3D"],
- required: true,
- },
- {
- key: "mipLevelCount",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 1,
- },
- {
- key: "sampleCount",
- converter: webidl.converters["GPUSize32"],
- defaultValue: 1,
- },
- {
- key: "dimension",
- converter: webidl.converters["GPUTextureDimension"],
- defaultValue: "2d",
- },
- {
- key: "format",
- converter: webidl.converters["GPUTextureFormat"],
- required: true,
- },
- {
- key: "usage",
- converter: webidl.converters["GPUTextureUsageFlags"],
- required: true,
- },
- {
- key: "viewFormats",
- converter: webidl.createSequenceConverter(
- webidl.converters["GPUTextureFormat"],
- ),
- get defaultValue() {
- return [];
- },
- },
- ];
- webidl.converters["GPUTextureDescriptor"] = webidl.createDictionaryConverter(
- "GPUTextureDescriptor",
+ return webidl.converters["GPUExtent3DDict"](V, opts);
+ }
+ throw webidl.makeException(
+ TypeError,
+ "can not be converted to sequence<GPUIntegerCoordinate> or GPUExtent3DDict.",
+ opts,
+ );
+};
+
+// ENUM: GPUTextureDimension
+webidl.converters["GPUTextureDimension"] = webidl.createEnumConverter(
+ "GPUTextureDimension",
+ [
+ "1d",
+ "2d",
+ "3d",
+ ],
+);
+
+// ENUM: GPUTextureFormat
+webidl.converters["GPUTextureFormat"] = webidl.createEnumConverter(
+ "GPUTextureFormat",
+ [
+ "r8unorm",
+ "r8snorm",
+ "r8uint",
+ "r8sint",
+ "r16uint",
+ "r16sint",
+ "r16float",
+ "rg8unorm",
+ "rg8snorm",
+ "rg8uint",
+ "rg8sint",
+ "r32uint",
+ "r32sint",
+ "r32float",
+ "rg16uint",
+ "rg16sint",
+ "rg16float",
+ "rgba8unorm",
+ "rgba8unorm-srgb",
+ "rgba8snorm",
+ "rgba8uint",
+ "rgba8sint",
+ "bgra8unorm",
+ "bgra8unorm-srgb",
+ "rgb9e5ufloat",
+ "rgb10a2unorm",
+ "rg11b10ufloat",
+ "rg32uint",
+ "rg32sint",
+ "rg32float",
+ "rgba16uint",
+ "rgba16sint",
+ "rgba16float",
+ "rgba32uint",
+ "rgba32sint",
+ "rgba32float",
+ "stencil8",
+ "depth16unorm",
+ "depth24plus",
+ "depth24plus-stencil8",
+ "depth32float",
+ "depth32float-stencil8",
+ "bc1-rgba-unorm",
+ "bc1-rgba-unorm-srgb",
+ "bc2-rgba-unorm",
+ "bc2-rgba-unorm-srgb",
+ "bc3-rgba-unorm",
+ "bc3-rgba-unorm-srgb",
+ "bc4-r-unorm",
+ "bc4-r-snorm",
+ "bc5-rg-unorm",
+ "bc5-rg-snorm",
+ "bc6h-rgb-ufloat",
+ "bc6h-rgb-float",
+ "bc7-rgba-unorm",
+ "bc7-rgba-unorm-srgb",
+ "etc2-rgb8unorm",
+ "etc2-rgb8unorm-srgb",
+ "etc2-rgb8a1unorm",
+ "etc2-rgb8a1unorm-srgb",
+ "etc2-rgba8unorm",
+ "etc2-rgba8unorm-srgb",
+ "eac-r11unorm",
+ "eac-r11snorm",
+ "eac-rg11unorm",
+ "eac-rg11snorm",
+ "astc-4x4-unorm",
+ "astc-4x4-unorm-srgb",
+ "astc-5x4-unorm",
+ "astc-5x4-unorm-srgb",
+ "astc-5x5-unorm",
+ "astc-5x5-unorm-srgb",
+ "astc-6x5-unorm",
+ "astc-6x5-unorm-srgb",
+ "astc-6x6-unorm",
+ "astc-6x6-unorm-srgb",
+ "astc-8x5-unorm",
+ "astc-8x5-unorm-srgb",
+ "astc-8x6-unorm",
+ "astc-8x6-unorm-srgb",
+ "astc-8x8-unorm",
+ "astc-8x8-unorm-srgb",
+ "astc-10x5-unorm",
+ "astc-10x5-unorm-srgb",
+ "astc-10x6-unorm",
+ "astc-10x6-unorm-srgb",
+ "astc-10x8-unorm",
+ "astc-10x8-unorm-srgb",
+ "astc-10x10-unorm",
+ "astc-10x10-unorm-srgb",
+ "astc-12x10-unorm",
+ "astc-12x10-unorm-srgb",
+ "astc-12x12-unorm",
+ "astc-12x12-unorm-srgb",
+ ],
+);
+
+// TYPEDEF: GPUTextureUsageFlags
+webidl.converters["GPUTextureUsageFlags"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+
+// DICTIONARY: GPUTextureDescriptor
+const dictMembersGPUTextureDescriptor = [
+ {
+ key: "size",
+ converter: webidl.converters["GPUExtent3D"],
+ required: true,
+ },
+ {
+ key: "mipLevelCount",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 1,
+ },
+ {
+ key: "sampleCount",
+ converter: webidl.converters["GPUSize32"],
+ defaultValue: 1,
+ },
+ {
+ key: "dimension",
+ converter: webidl.converters["GPUTextureDimension"],
+ defaultValue: "2d",
+ },
+ {
+ key: "format",
+ converter: webidl.converters["GPUTextureFormat"],
+ required: true,
+ },
+ {
+ key: "usage",
+ converter: webidl.converters["GPUTextureUsageFlags"],
+ required: true,
+ },
+ {
+ key: "viewFormats",
+ converter: webidl.createSequenceConverter(
+ webidl.converters["GPUTextureFormat"],
+ ),
+ get defaultValue() {
+ return [];
+ },
+ },
+];
+webidl.converters["GPUTextureDescriptor"] = webidl.createDictionaryConverter(
+ "GPUTextureDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUTextureDescriptor,
+);
+
+// INTERFACE: GPUTextureUsage
+webidl.converters.GPUTextureUsage = webidl.createInterfaceConverter(
+ "GPUTextureUsage",
+ GPUTextureUsage.prototype,
+);
+
+// INTERFACE: GPUTextureView
+webidl.converters.GPUTextureView = webidl.createInterfaceConverter(
+ "GPUTextureView",
+ GPUTextureView.prototype,
+);
+
+// ENUM: GPUTextureViewDimension
+webidl.converters["GPUTextureViewDimension"] = webidl.createEnumConverter(
+ "GPUTextureViewDimension",
+ [
+ "1d",
+ "2d",
+ "2d-array",
+ "cube",
+ "cube-array",
+ "3d",
+ ],
+);
+
+// ENUM: GPUTextureAspect
+webidl.converters["GPUTextureAspect"] = webidl.createEnumConverter(
+ "GPUTextureAspect",
+ [
+ "all",
+ "stencil-only",
+ "depth-only",
+ ],
+);
+
+// DICTIONARY: GPUTextureViewDescriptor
+const dictMembersGPUTextureViewDescriptor = [
+ { key: "format", converter: webidl.converters["GPUTextureFormat"] },
+ {
+ key: "dimension",
+ converter: webidl.converters["GPUTextureViewDimension"],
+ },
+ {
+ key: "aspect",
+ converter: webidl.converters["GPUTextureAspect"],
+ defaultValue: "all",
+ },
+ {
+ key: "baseMipLevel",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 0,
+ },
+ {
+ key: "mipLevelCount",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ },
+ {
+ key: "baseArrayLayer",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 0,
+ },
+ {
+ key: "arrayLayerCount",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ },
+];
+webidl.converters["GPUTextureViewDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPUTextureViewDescriptor",
dictMembersGPUObjectDescriptorBase,
- dictMembersGPUTextureDescriptor,
- );
-
- // INTERFACE: GPUTextureUsage
- webidl.converters.GPUTextureUsage = webidl.createInterfaceConverter(
- "GPUTextureUsage",
- GPUTextureUsage.prototype,
- );
-
- // INTERFACE: GPUTextureView
- webidl.converters.GPUTextureView = webidl.createInterfaceConverter(
- "GPUTextureView",
- GPUTextureView.prototype,
- );
-
- // ENUM: GPUTextureViewDimension
- webidl.converters["GPUTextureViewDimension"] = webidl.createEnumConverter(
- "GPUTextureViewDimension",
- [
- "1d",
- "2d",
- "2d-array",
- "cube",
- "cube-array",
- "3d",
- ],
- );
-
- // ENUM: GPUTextureAspect
- webidl.converters["GPUTextureAspect"] = webidl.createEnumConverter(
- "GPUTextureAspect",
- [
- "all",
- "stencil-only",
- "depth-only",
- ],
- );
-
- // DICTIONARY: GPUTextureViewDescriptor
- const dictMembersGPUTextureViewDescriptor = [
- { key: "format", converter: webidl.converters["GPUTextureFormat"] },
- {
- key: "dimension",
- converter: webidl.converters["GPUTextureViewDimension"],
- },
- {
- key: "aspect",
- converter: webidl.converters["GPUTextureAspect"],
- defaultValue: "all",
- },
- {
- key: "baseMipLevel",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 0,
- },
- {
- key: "mipLevelCount",
- converter: webidl.converters["GPUIntegerCoordinate"],
- },
- {
- key: "baseArrayLayer",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 0,
- },
- {
- key: "arrayLayerCount",
- converter: webidl.converters["GPUIntegerCoordinate"],
- },
- ];
- webidl.converters["GPUTextureViewDescriptor"] = webidl
- .createDictionaryConverter(
- "GPUTextureViewDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUTextureViewDescriptor,
- );
-
- // INTERFACE: GPUSampler
- webidl.converters.GPUSampler = webidl.createInterfaceConverter(
- "GPUSampler",
- GPUSampler.prototype,
- );
-
- // ENUM: GPUAddressMode
- webidl.converters["GPUAddressMode"] = webidl.createEnumConverter(
- "GPUAddressMode",
- [
- "clamp-to-edge",
- "repeat",
- "mirror-repeat",
- ],
- );
-
- // ENUM: GPUFilterMode
- webidl.converters["GPUFilterMode"] = webidl.createEnumConverter(
- "GPUFilterMode",
- [
- "nearest",
- "linear",
- ],
- );
-
- // ENUM: GPUMipmapFilterMode
- webidl.converters["GPUMipmapFilterMode"] = webidl.createEnumConverter(
- "GPUMipmapFilterMode",
- [
- "nearest",
- "linear",
- ],
- );
-
- // ENUM: GPUCompareFunction
- webidl.converters["GPUCompareFunction"] = webidl.createEnumConverter(
- "GPUCompareFunction",
- [
- "never",
- "less",
- "equal",
- "less-equal",
- "greater",
- "not-equal",
- "greater-equal",
- "always",
- ],
- );
-
- // DICTIONARY: GPUSamplerDescriptor
- const dictMembersGPUSamplerDescriptor = [
- {
- key: "addressModeU",
- converter: webidl.converters["GPUAddressMode"],
- defaultValue: "clamp-to-edge",
- },
- {
- key: "addressModeV",
- converter: webidl.converters["GPUAddressMode"],
- defaultValue: "clamp-to-edge",
- },
- {
- key: "addressModeW",
- converter: webidl.converters["GPUAddressMode"],
- defaultValue: "clamp-to-edge",
- },
- {
- key: "magFilter",
- converter: webidl.converters["GPUFilterMode"],
- defaultValue: "nearest",
- },
- {
- key: "minFilter",
- converter: webidl.converters["GPUFilterMode"],
- defaultValue: "nearest",
- },
- {
- key: "mipmapFilter",
- converter: webidl.converters["GPUMipmapFilterMode"],
- defaultValue: "nearest",
- },
- {
- key: "lodMinClamp",
- converter: webidl.converters["float"],
- defaultValue: 0,
- },
- {
- key: "lodMaxClamp",
- converter: webidl.converters["float"],
- defaultValue: 0xffffffff,
- },
- { key: "compare", converter: webidl.converters["GPUCompareFunction"] },
- {
- key: "maxAnisotropy",
- converter: (V, opts) =>
- webidl.converters["unsigned short"](V, { ...opts, clamp: true }),
- defaultValue: 1,
- },
- ];
- webidl.converters["GPUSamplerDescriptor"] = webidl.createDictionaryConverter(
- "GPUSamplerDescriptor",
+ dictMembersGPUTextureViewDescriptor,
+ );
+
+// INTERFACE: GPUSampler
+webidl.converters.GPUSampler = webidl.createInterfaceConverter(
+ "GPUSampler",
+ GPUSampler.prototype,
+);
+
+// ENUM: GPUAddressMode
+webidl.converters["GPUAddressMode"] = webidl.createEnumConverter(
+ "GPUAddressMode",
+ [
+ "clamp-to-edge",
+ "repeat",
+ "mirror-repeat",
+ ],
+);
+
+// ENUM: GPUFilterMode
+webidl.converters["GPUFilterMode"] = webidl.createEnumConverter(
+ "GPUFilterMode",
+ [
+ "nearest",
+ "linear",
+ ],
+);
+
+// ENUM: GPUMipmapFilterMode
+webidl.converters["GPUMipmapFilterMode"] = webidl.createEnumConverter(
+ "GPUMipmapFilterMode",
+ [
+ "nearest",
+ "linear",
+ ],
+);
+
+// ENUM: GPUCompareFunction
+webidl.converters["GPUCompareFunction"] = webidl.createEnumConverter(
+ "GPUCompareFunction",
+ [
+ "never",
+ "less",
+ "equal",
+ "less-equal",
+ "greater",
+ "not-equal",
+ "greater-equal",
+ "always",
+ ],
+);
+
+// DICTIONARY: GPUSamplerDescriptor
+const dictMembersGPUSamplerDescriptor = [
+ {
+ key: "addressModeU",
+ converter: webidl.converters["GPUAddressMode"],
+ defaultValue: "clamp-to-edge",
+ },
+ {
+ key: "addressModeV",
+ converter: webidl.converters["GPUAddressMode"],
+ defaultValue: "clamp-to-edge",
+ },
+ {
+ key: "addressModeW",
+ converter: webidl.converters["GPUAddressMode"],
+ defaultValue: "clamp-to-edge",
+ },
+ {
+ key: "magFilter",
+ converter: webidl.converters["GPUFilterMode"],
+ defaultValue: "nearest",
+ },
+ {
+ key: "minFilter",
+ converter: webidl.converters["GPUFilterMode"],
+ defaultValue: "nearest",
+ },
+ {
+ key: "mipmapFilter",
+ converter: webidl.converters["GPUMipmapFilterMode"],
+ defaultValue: "nearest",
+ },
+ {
+ key: "lodMinClamp",
+ converter: webidl.converters["float"],
+ defaultValue: 0,
+ },
+ {
+ key: "lodMaxClamp",
+ converter: webidl.converters["float"],
+ defaultValue: 0xffffffff,
+ },
+ { key: "compare", converter: webidl.converters["GPUCompareFunction"] },
+ {
+ key: "maxAnisotropy",
+ converter: (V, opts) =>
+ webidl.converters["unsigned short"](V, { ...opts, clamp: true }),
+ defaultValue: 1,
+ },
+];
+webidl.converters["GPUSamplerDescriptor"] = webidl.createDictionaryConverter(
+ "GPUSamplerDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUSamplerDescriptor,
+);
+
+// INTERFACE: GPUBindGroupLayout
+webidl.converters.GPUBindGroupLayout = webidl.createInterfaceConverter(
+ "GPUBindGroupLayout",
+ GPUBindGroupLayout.prototype,
+);
+
+// TYPEDEF: GPUIndex32
+webidl.converters["GPUIndex32"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+
+// TYPEDEF: GPUShaderStageFlags
+webidl.converters["GPUShaderStageFlags"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+
+// ENUM: GPUBufferBindingType
+webidl.converters["GPUBufferBindingType"] = webidl.createEnumConverter(
+ "GPUBufferBindingType",
+ [
+ "uniform",
+ "storage",
+ "read-only-storage",
+ ],
+);
+
+// DICTIONARY: GPUBufferBindingLayout
+const dictMembersGPUBufferBindingLayout = [
+ {
+ key: "type",
+ converter: webidl.converters["GPUBufferBindingType"],
+ defaultValue: "uniform",
+ },
+ {
+ key: "hasDynamicOffset",
+ converter: webidl.converters["boolean"],
+ defaultValue: false,
+ },
+ {
+ key: "minBindingSize",
+ converter: webidl.converters["GPUSize64"],
+ defaultValue: 0,
+ },
+];
+webidl.converters["GPUBufferBindingLayout"] = webidl
+ .createDictionaryConverter(
+ "GPUBufferBindingLayout",
+ dictMembersGPUBufferBindingLayout,
+ );
+
+// ENUM: GPUSamplerBindingType
+webidl.converters["GPUSamplerBindingType"] = webidl.createEnumConverter(
+ "GPUSamplerBindingType",
+ [
+ "filtering",
+ "non-filtering",
+ "comparison",
+ ],
+);
+
+// DICTIONARY: GPUSamplerBindingLayout
+const dictMembersGPUSamplerBindingLayout = [
+ {
+ key: "type",
+ converter: webidl.converters["GPUSamplerBindingType"],
+ defaultValue: "filtering",
+ },
+];
+webidl.converters["GPUSamplerBindingLayout"] = webidl
+ .createDictionaryConverter(
+ "GPUSamplerBindingLayout",
+ dictMembersGPUSamplerBindingLayout,
+ );
+
+// ENUM: GPUTextureSampleType
+webidl.converters["GPUTextureSampleType"] = webidl.createEnumConverter(
+ "GPUTextureSampleType",
+ [
+ "float",
+ "unfilterable-float",
+ "depth",
+ "sint",
+ "uint",
+ ],
+);
+
+// DICTIONARY: GPUTextureBindingLayout
+const dictMembersGPUTextureBindingLayout = [
+ {
+ key: "sampleType",
+ converter: webidl.converters["GPUTextureSampleType"],
+ defaultValue: "float",
+ },
+ {
+ key: "viewDimension",
+ converter: webidl.converters["GPUTextureViewDimension"],
+ defaultValue: "2d",
+ },
+ {
+ key: "multisampled",
+ converter: webidl.converters["boolean"],
+ defaultValue: false,
+ },
+];
+webidl.converters["GPUTextureBindingLayout"] = webidl
+ .createDictionaryConverter(
+ "GPUTextureBindingLayout",
+ dictMembersGPUTextureBindingLayout,
+ );
+
+// ENUM: GPUStorageTextureAccess
+webidl.converters["GPUStorageTextureAccess"] = webidl.createEnumConverter(
+ "GPUStorageTextureAccess",
+ [
+ "write-only",
+ ],
+);
+
+// DICTIONARY: GPUStorageTextureBindingLayout
+const dictMembersGPUStorageTextureBindingLayout = [
+ {
+ key: "access",
+ converter: webidl.converters["GPUStorageTextureAccess"],
+ defaultValue: "write-only",
+ },
+ {
+ key: "format",
+ converter: webidl.converters["GPUTextureFormat"],
+ required: true,
+ },
+ {
+ key: "viewDimension",
+ converter: webidl.converters["GPUTextureViewDimension"],
+ defaultValue: "2d",
+ },
+];
+webidl.converters["GPUStorageTextureBindingLayout"] = webidl
+ .createDictionaryConverter(
+ "GPUStorageTextureBindingLayout",
+ dictMembersGPUStorageTextureBindingLayout,
+ );
+
+// DICTIONARY: GPUBindGroupLayoutEntry
+const dictMembersGPUBindGroupLayoutEntry = [
+ {
+ key: "binding",
+ converter: webidl.converters["GPUIndex32"],
+ required: true,
+ },
+ {
+ key: "visibility",
+ converter: webidl.converters["GPUShaderStageFlags"],
+ required: true,
+ },
+ { key: "buffer", converter: webidl.converters["GPUBufferBindingLayout"] },
+ { key: "sampler", converter: webidl.converters["GPUSamplerBindingLayout"] },
+ { key: "texture", converter: webidl.converters["GPUTextureBindingLayout"] },
+ {
+ key: "storageTexture",
+ converter: webidl.converters["GPUStorageTextureBindingLayout"],
+ },
+];
+webidl.converters["GPUBindGroupLayoutEntry"] = webidl
+ .createDictionaryConverter(
+ "GPUBindGroupLayoutEntry",
+ dictMembersGPUBindGroupLayoutEntry,
+ );
+
+// DICTIONARY: GPUBindGroupLayoutDescriptor
+const dictMembersGPUBindGroupLayoutDescriptor = [
+ {
+ key: "entries",
+ converter: webidl.createSequenceConverter(
+ webidl.converters["GPUBindGroupLayoutEntry"],
+ ),
+ required: true,
+ },
+];
+webidl.converters["GPUBindGroupLayoutDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPUBindGroupLayoutDescriptor",
dictMembersGPUObjectDescriptorBase,
- dictMembersGPUSamplerDescriptor,
- );
-
- // INTERFACE: GPUBindGroupLayout
- webidl.converters.GPUBindGroupLayout = webidl.createInterfaceConverter(
- "GPUBindGroupLayout",
- GPUBindGroupLayout.prototype,
- );
-
- // TYPEDEF: GPUIndex32
- webidl.converters["GPUIndex32"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
-
- // TYPEDEF: GPUShaderStageFlags
- webidl.converters["GPUShaderStageFlags"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
-
- // ENUM: GPUBufferBindingType
- webidl.converters["GPUBufferBindingType"] = webidl.createEnumConverter(
- "GPUBufferBindingType",
- [
- "uniform",
- "storage",
- "read-only-storage",
- ],
- );
-
- // DICTIONARY: GPUBufferBindingLayout
- const dictMembersGPUBufferBindingLayout = [
- {
- key: "type",
- converter: webidl.converters["GPUBufferBindingType"],
- defaultValue: "uniform",
- },
- {
- key: "hasDynamicOffset",
- converter: webidl.converters["boolean"],
- defaultValue: false,
- },
- {
- key: "minBindingSize",
- converter: webidl.converters["GPUSize64"],
- defaultValue: 0,
- },
- ];
- webidl.converters["GPUBufferBindingLayout"] = webidl
- .createDictionaryConverter(
- "GPUBufferBindingLayout",
- dictMembersGPUBufferBindingLayout,
- );
-
- // ENUM: GPUSamplerBindingType
- webidl.converters["GPUSamplerBindingType"] = webidl.createEnumConverter(
- "GPUSamplerBindingType",
- [
- "filtering",
- "non-filtering",
- "comparison",
- ],
- );
-
- // DICTIONARY: GPUSamplerBindingLayout
- const dictMembersGPUSamplerBindingLayout = [
- {
- key: "type",
- converter: webidl.converters["GPUSamplerBindingType"],
- defaultValue: "filtering",
- },
- ];
- webidl.converters["GPUSamplerBindingLayout"] = webidl
- .createDictionaryConverter(
- "GPUSamplerBindingLayout",
- dictMembersGPUSamplerBindingLayout,
- );
-
- // ENUM: GPUTextureSampleType
- webidl.converters["GPUTextureSampleType"] = webidl.createEnumConverter(
- "GPUTextureSampleType",
- [
- "float",
- "unfilterable-float",
- "depth",
- "sint",
- "uint",
- ],
- );
-
- // DICTIONARY: GPUTextureBindingLayout
- const dictMembersGPUTextureBindingLayout = [
- {
- key: "sampleType",
- converter: webidl.converters["GPUTextureSampleType"],
- defaultValue: "float",
- },
- {
- key: "viewDimension",
- converter: webidl.converters["GPUTextureViewDimension"],
- defaultValue: "2d",
- },
- {
- key: "multisampled",
- converter: webidl.converters["boolean"],
- defaultValue: false,
- },
- ];
- webidl.converters["GPUTextureBindingLayout"] = webidl
- .createDictionaryConverter(
- "GPUTextureBindingLayout",
- dictMembersGPUTextureBindingLayout,
- );
-
- // ENUM: GPUStorageTextureAccess
- webidl.converters["GPUStorageTextureAccess"] = webidl.createEnumConverter(
- "GPUStorageTextureAccess",
- [
- "write-only",
- ],
- );
-
- // DICTIONARY: GPUStorageTextureBindingLayout
- const dictMembersGPUStorageTextureBindingLayout = [
- {
- key: "access",
- converter: webidl.converters["GPUStorageTextureAccess"],
- defaultValue: "write-only",
- },
- {
- key: "format",
- converter: webidl.converters["GPUTextureFormat"],
- required: true,
- },
- {
- key: "viewDimension",
- converter: webidl.converters["GPUTextureViewDimension"],
- defaultValue: "2d",
- },
- ];
- webidl.converters["GPUStorageTextureBindingLayout"] = webidl
- .createDictionaryConverter(
- "GPUStorageTextureBindingLayout",
- dictMembersGPUStorageTextureBindingLayout,
- );
-
- // DICTIONARY: GPUBindGroupLayoutEntry
- const dictMembersGPUBindGroupLayoutEntry = [
- {
- key: "binding",
- converter: webidl.converters["GPUIndex32"],
- required: true,
- },
- {
- key: "visibility",
- converter: webidl.converters["GPUShaderStageFlags"],
- required: true,
- },
- { key: "buffer", converter: webidl.converters["GPUBufferBindingLayout"] },
- { key: "sampler", converter: webidl.converters["GPUSamplerBindingLayout"] },
- { key: "texture", converter: webidl.converters["GPUTextureBindingLayout"] },
- {
- key: "storageTexture",
- converter: webidl.converters["GPUStorageTextureBindingLayout"],
- },
- ];
- webidl.converters["GPUBindGroupLayoutEntry"] = webidl
- .createDictionaryConverter(
- "GPUBindGroupLayoutEntry",
- dictMembersGPUBindGroupLayoutEntry,
- );
-
- // DICTIONARY: GPUBindGroupLayoutDescriptor
- const dictMembersGPUBindGroupLayoutDescriptor = [
- {
- key: "entries",
- converter: webidl.createSequenceConverter(
- webidl.converters["GPUBindGroupLayoutEntry"],
- ),
- required: true,
- },
- ];
- webidl.converters["GPUBindGroupLayoutDescriptor"] = webidl
- .createDictionaryConverter(
- "GPUBindGroupLayoutDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUBindGroupLayoutDescriptor,
- );
-
- // INTERFACE: GPUShaderStage
- webidl.converters.GPUShaderStage = webidl.createInterfaceConverter(
- "GPUShaderStage",
- GPUShaderStage.prototype,
- );
-
- // INTERFACE: GPUBindGroup
- webidl.converters.GPUBindGroup = webidl.createInterfaceConverter(
- "GPUBindGroup",
- GPUBindGroup.prototype,
- );
-
- // DICTIONARY: GPUBufferBinding
- const dictMembersGPUBufferBinding = [
- {
- key: "buffer",
- converter: webidl.converters["GPUBuffer"],
- required: true,
- },
- {
- key: "offset",
- converter: webidl.converters["GPUSize64"],
- defaultValue: 0,
- },
- { key: "size", converter: webidl.converters["GPUSize64"] },
- ];
- webidl.converters["GPUBufferBinding"] = webidl.createDictionaryConverter(
- "GPUBufferBinding",
- dictMembersGPUBufferBinding,
- );
-
- // TYPEDEF: GPUBindingResource
- webidl.converters["GPUBindingResource"] =
- webidl.converters.any /** put union here! **/;
-
- // DICTIONARY: GPUBindGroupEntry
- const dictMembersGPUBindGroupEntry = [
- {
- key: "binding",
- converter: webidl.converters["GPUIndex32"],
- required: true,
- },
- {
- key: "resource",
- converter: webidl.converters["GPUBindingResource"],
- required: true,
- },
- ];
- webidl.converters["GPUBindGroupEntry"] = webidl.createDictionaryConverter(
- "GPUBindGroupEntry",
- dictMembersGPUBindGroupEntry,
- );
-
- // DICTIONARY: GPUBindGroupDescriptor
- const dictMembersGPUBindGroupDescriptor = [
- {
- key: "layout",
- converter: webidl.converters["GPUBindGroupLayout"],
- required: true,
- },
- {
- key: "entries",
- converter: webidl.createSequenceConverter(
- webidl.converters["GPUBindGroupEntry"],
- ),
- required: true,
- },
- ];
- webidl.converters["GPUBindGroupDescriptor"] = webidl
- .createDictionaryConverter(
- "GPUBindGroupDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUBindGroupDescriptor,
- );
-
- // INTERFACE: GPUPipelineLayout
- webidl.converters.GPUPipelineLayout = webidl.createInterfaceConverter(
- "GPUPipelineLayout",
- GPUPipelineLayout.prototype,
- );
-
- // DICTIONARY: GPUPipelineLayoutDescriptor
- const dictMembersGPUPipelineLayoutDescriptor = [
- {
- key: "bindGroupLayouts",
- converter: webidl.createSequenceConverter(
- webidl.converters["GPUBindGroupLayout"],
- ),
- required: true,
- },
- ];
- webidl.converters["GPUPipelineLayoutDescriptor"] = webidl
- .createDictionaryConverter(
- "GPUPipelineLayoutDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUPipelineLayoutDescriptor,
- );
-
- // INTERFACE: GPUShaderModule
- webidl.converters.GPUShaderModule = webidl.createInterfaceConverter(
- "GPUShaderModule",
- GPUShaderModule.prototype,
- );
-
- // DICTIONARY: GPUShaderModuleDescriptor
- const dictMembersGPUShaderModuleDescriptor = [
- {
- key: "code",
- converter: webidl.converters["DOMString"],
- required: true,
- },
- ];
- webidl.converters["GPUShaderModuleDescriptor"] = webidl
- .createDictionaryConverter(
- "GPUShaderModuleDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUShaderModuleDescriptor,
- );
-
- // // ENUM: GPUCompilationMessageType
- // webidl.converters["GPUCompilationMessageType"] = webidl.createEnumConverter(
- // "GPUCompilationMessageType",
- // [
- // "error",
- // "warning",
- // "info",
- // ],
- // );
-
- // // INTERFACE: GPUCompilationMessage
- // webidl.converters.GPUCompilationMessage = webidl.createInterfaceConverter(
- // "GPUCompilationMessage",
- // GPUCompilationMessage.prototype,
- // );
-
- // // INTERFACE: GPUCompilationInfo
- // webidl.converters.GPUCompilationInfo = webidl.createInterfaceConverter(
- // "GPUCompilationInfo",
- // GPUCompilationInfo.prototype,
- // );
-
- webidl.converters["GPUAutoLayoutMode"] = webidl.createEnumConverter(
- "GPUAutoLayoutMode",
- [
- "auto",
- ],
- );
-
- webidl.converters["GPUPipelineLayout or GPUAutoLayoutMode"] = (V, opts) => {
- if (typeof V === "object") {
- return webidl.converters["GPUPipelineLayout"](V, opts);
- }
- return webidl.converters["GPUAutoLayoutMode"](V, opts);
- };
-
- // DICTIONARY: GPUPipelineDescriptorBase
- const dictMembersGPUPipelineDescriptorBase = [
- {
- key: "layout",
- converter: webidl.converters["GPUPipelineLayout or GPUAutoLayoutMode"],
- },
- ];
- webidl.converters["GPUPipelineDescriptorBase"] = webidl
- .createDictionaryConverter(
- "GPUPipelineDescriptorBase",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUPipelineDescriptorBase,
- );
-
- // TYPEDEF: GPUPipelineConstantValue
- webidl.converters.GPUPipelineConstantValue = webidl.converters.double;
-
- webidl.converters["record<USVString, GPUPipelineConstantValue>"] = webidl
- .createRecordConverter(
- webidl.converters.USVString,
- webidl.converters.GPUPipelineConstantValue,
- );
-
- // DICTIONARY: GPUProgrammableStage
- const dictMembersGPUProgrammableStage = [
- {
- key: "module",
- converter: webidl.converters["GPUShaderModule"],
- required: true,
- },
- {
- key: "entryPoint",
- converter: webidl.converters["USVString"],
- required: true,
- },
- {
- key: "constants",
- converter:
- webidl.converters["record<USVString, GPUPipelineConstantValue>"],
- },
- ];
- webidl.converters["GPUProgrammableStage"] = webidl.createDictionaryConverter(
- "GPUProgrammableStage",
- dictMembersGPUProgrammableStage,
- );
-
- // INTERFACE: GPUComputePipeline
- webidl.converters.GPUComputePipeline = webidl.createInterfaceConverter(
- "GPUComputePipeline",
- GPUComputePipeline.prototype,
- );
-
- // DICTIONARY: GPUComputePipelineDescriptor
- const dictMembersGPUComputePipelineDescriptor = [
- {
- key: "compute",
- converter: webidl.converters["GPUProgrammableStage"],
- required: true,
- },
- ];
- webidl.converters["GPUComputePipelineDescriptor"] = webidl
- .createDictionaryConverter(
- "GPUComputePipelineDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUPipelineDescriptorBase,
- dictMembersGPUComputePipelineDescriptor,
- );
-
- // INTERFACE: GPURenderPipeline
- webidl.converters.GPURenderPipeline = webidl.createInterfaceConverter(
- "GPURenderPipeline",
- GPURenderPipeline.prototype,
- );
-
- // ENUM: GPUVertexStepMode
- webidl.converters["GPUVertexStepMode"] = webidl.createEnumConverter(
- "GPUVertexStepMode",
- [
- "vertex",
- "instance",
- ],
- );
-
- // ENUM: GPUVertexFormat
- webidl.converters["GPUVertexFormat"] = webidl.createEnumConverter(
- "GPUVertexFormat",
- [
- "uint8x2",
- "uint8x4",
- "sint8x2",
- "sint8x4",
- "unorm8x2",
- "unorm8x4",
- "snorm8x2",
- "snorm8x4",
- "uint16x2",
- "uint16x4",
- "sint16x2",
- "sint16x4",
- "unorm16x2",
- "unorm16x4",
- "snorm16x2",
- "snorm16x4",
- "float16x2",
- "float16x4",
- "float32",
- "float32x2",
- "float32x3",
- "float32x4",
- "uint32",
- "uint32x2",
- "uint32x3",
- "uint32x4",
- "sint32",
- "sint32x2",
- "sint32x3",
- "sint32x4",
- ],
- );
-
- // DICTIONARY: GPUVertexAttribute
- const dictMembersGPUVertexAttribute = [
- {
- key: "format",
- converter: webidl.converters["GPUVertexFormat"],
- required: true,
- },
- {
- key: "offset",
- converter: webidl.converters["GPUSize64"],
- required: true,
- },
- {
- key: "shaderLocation",
- converter: webidl.converters["GPUIndex32"],
- required: true,
- },
- ];
- webidl.converters["GPUVertexAttribute"] = webidl.createDictionaryConverter(
- "GPUVertexAttribute",
- dictMembersGPUVertexAttribute,
- );
-
- // DICTIONARY: GPUVertexBufferLayout
- const dictMembersGPUVertexBufferLayout = [
- {
- key: "arrayStride",
- converter: webidl.converters["GPUSize64"],
- required: true,
- },
- {
- key: "stepMode",
- converter: webidl.converters["GPUVertexStepMode"],
- defaultValue: "vertex",
- },
- {
- key: "attributes",
- converter: webidl.createSequenceConverter(
- webidl.converters["GPUVertexAttribute"],
+ dictMembersGPUBindGroupLayoutDescriptor,
+ );
+
+// INTERFACE: GPUShaderStage
+webidl.converters.GPUShaderStage = webidl.createInterfaceConverter(
+ "GPUShaderStage",
+ GPUShaderStage.prototype,
+);
+
+// INTERFACE: GPUBindGroup
+webidl.converters.GPUBindGroup = webidl.createInterfaceConverter(
+ "GPUBindGroup",
+ GPUBindGroup.prototype,
+);
+
+// DICTIONARY: GPUBufferBinding
+const dictMembersGPUBufferBinding = [
+ {
+ key: "buffer",
+ converter: webidl.converters["GPUBuffer"],
+ required: true,
+ },
+ {
+ key: "offset",
+ converter: webidl.converters["GPUSize64"],
+ defaultValue: 0,
+ },
+ { key: "size", converter: webidl.converters["GPUSize64"] },
+];
+webidl.converters["GPUBufferBinding"] = webidl.createDictionaryConverter(
+ "GPUBufferBinding",
+ dictMembersGPUBufferBinding,
+);
+
+// TYPEDEF: GPUBindingResource
+webidl.converters["GPUBindingResource"] =
+ webidl.converters.any /** put union here! **/;
+
+// DICTIONARY: GPUBindGroupEntry
+const dictMembersGPUBindGroupEntry = [
+ {
+ key: "binding",
+ converter: webidl.converters["GPUIndex32"],
+ required: true,
+ },
+ {
+ key: "resource",
+ converter: webidl.converters["GPUBindingResource"],
+ required: true,
+ },
+];
+webidl.converters["GPUBindGroupEntry"] = webidl.createDictionaryConverter(
+ "GPUBindGroupEntry",
+ dictMembersGPUBindGroupEntry,
+);
+
+// DICTIONARY: GPUBindGroupDescriptor
+const dictMembersGPUBindGroupDescriptor = [
+ {
+ key: "layout",
+ converter: webidl.converters["GPUBindGroupLayout"],
+ required: true,
+ },
+ {
+ key: "entries",
+ converter: webidl.createSequenceConverter(
+ webidl.converters["GPUBindGroupEntry"],
+ ),
+ required: true,
+ },
+];
+webidl.converters["GPUBindGroupDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPUBindGroupDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUBindGroupDescriptor,
+ );
+
+// INTERFACE: GPUPipelineLayout
+webidl.converters.GPUPipelineLayout = webidl.createInterfaceConverter(
+ "GPUPipelineLayout",
+ GPUPipelineLayout.prototype,
+);
+
+// DICTIONARY: GPUPipelineLayoutDescriptor
+const dictMembersGPUPipelineLayoutDescriptor = [
+ {
+ key: "bindGroupLayouts",
+ converter: webidl.createSequenceConverter(
+ webidl.converters["GPUBindGroupLayout"],
+ ),
+ required: true,
+ },
+];
+webidl.converters["GPUPipelineLayoutDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPUPipelineLayoutDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUPipelineLayoutDescriptor,
+ );
+
+// INTERFACE: GPUShaderModule
+webidl.converters.GPUShaderModule = webidl.createInterfaceConverter(
+ "GPUShaderModule",
+ GPUShaderModule.prototype,
+);
+
+// DICTIONARY: GPUShaderModuleDescriptor
+const dictMembersGPUShaderModuleDescriptor = [
+ {
+ key: "code",
+ converter: webidl.converters["DOMString"],
+ required: true,
+ },
+];
+webidl.converters["GPUShaderModuleDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPUShaderModuleDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUShaderModuleDescriptor,
+ );
+
+// // ENUM: GPUCompilationMessageType
+// webidl.converters["GPUCompilationMessageType"] = webidl.createEnumConverter(
+// "GPUCompilationMessageType",
+// [
+// "error",
+// "warning",
+// "info",
+// ],
+// );
+
+// // INTERFACE: GPUCompilationMessage
+// webidl.converters.GPUCompilationMessage = webidl.createInterfaceConverter(
+// "GPUCompilationMessage",
+// GPUCompilationMessage.prototype,
+// );
+
+// // INTERFACE: GPUCompilationInfo
+// webidl.converters.GPUCompilationInfo = webidl.createInterfaceConverter(
+// "GPUCompilationInfo",
+// GPUCompilationInfo.prototype,
+// );
+
+webidl.converters["GPUAutoLayoutMode"] = webidl.createEnumConverter(
+ "GPUAutoLayoutMode",
+ [
+ "auto",
+ ],
+);
+
+webidl.converters["GPUPipelineLayout or GPUAutoLayoutMode"] = (V, opts) => {
+ if (typeof V === "object") {
+ return webidl.converters["GPUPipelineLayout"](V, opts);
+ }
+ return webidl.converters["GPUAutoLayoutMode"](V, opts);
+};
+
+// DICTIONARY: GPUPipelineDescriptorBase
+const dictMembersGPUPipelineDescriptorBase = [
+ {
+ key: "layout",
+ converter: webidl.converters["GPUPipelineLayout or GPUAutoLayoutMode"],
+ },
+];
+webidl.converters["GPUPipelineDescriptorBase"] = webidl
+ .createDictionaryConverter(
+ "GPUPipelineDescriptorBase",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUPipelineDescriptorBase,
+ );
+
+// TYPEDEF: GPUPipelineConstantValue
+webidl.converters.GPUPipelineConstantValue = webidl.converters.double;
+
+webidl.converters["record<USVString, GPUPipelineConstantValue>"] = webidl
+ .createRecordConverter(
+ webidl.converters.USVString,
+ webidl.converters.GPUPipelineConstantValue,
+ );
+
+// DICTIONARY: GPUProgrammableStage
+const dictMembersGPUProgrammableStage = [
+ {
+ key: "module",
+ converter: webidl.converters["GPUShaderModule"],
+ required: true,
+ },
+ {
+ key: "entryPoint",
+ converter: webidl.converters["USVString"],
+ required: true,
+ },
+ {
+ key: "constants",
+ converter: webidl.converters["record<USVString, GPUPipelineConstantValue>"],
+ },
+];
+webidl.converters["GPUProgrammableStage"] = webidl.createDictionaryConverter(
+ "GPUProgrammableStage",
+ dictMembersGPUProgrammableStage,
+);
+
+// INTERFACE: GPUComputePipeline
+webidl.converters.GPUComputePipeline = webidl.createInterfaceConverter(
+ "GPUComputePipeline",
+ GPUComputePipeline.prototype,
+);
+
+// DICTIONARY: GPUComputePipelineDescriptor
+const dictMembersGPUComputePipelineDescriptor = [
+ {
+ key: "compute",
+ converter: webidl.converters["GPUProgrammableStage"],
+ required: true,
+ },
+];
+webidl.converters["GPUComputePipelineDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPUComputePipelineDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUPipelineDescriptorBase,
+ dictMembersGPUComputePipelineDescriptor,
+ );
+
+// INTERFACE: GPURenderPipeline
+webidl.converters.GPURenderPipeline = webidl.createInterfaceConverter(
+ "GPURenderPipeline",
+ GPURenderPipeline.prototype,
+);
+
+// ENUM: GPUVertexStepMode
+webidl.converters["GPUVertexStepMode"] = webidl.createEnumConverter(
+ "GPUVertexStepMode",
+ [
+ "vertex",
+ "instance",
+ ],
+);
+
+// ENUM: GPUVertexFormat
+webidl.converters["GPUVertexFormat"] = webidl.createEnumConverter(
+ "GPUVertexFormat",
+ [
+ "uint8x2",
+ "uint8x4",
+ "sint8x2",
+ "sint8x4",
+ "unorm8x2",
+ "unorm8x4",
+ "snorm8x2",
+ "snorm8x4",
+ "uint16x2",
+ "uint16x4",
+ "sint16x2",
+ "sint16x4",
+ "unorm16x2",
+ "unorm16x4",
+ "snorm16x2",
+ "snorm16x4",
+ "float16x2",
+ "float16x4",
+ "float32",
+ "float32x2",
+ "float32x3",
+ "float32x4",
+ "uint32",
+ "uint32x2",
+ "uint32x3",
+ "uint32x4",
+ "sint32",
+ "sint32x2",
+ "sint32x3",
+ "sint32x4",
+ ],
+);
+
+// DICTIONARY: GPUVertexAttribute
+const dictMembersGPUVertexAttribute = [
+ {
+ key: "format",
+ converter: webidl.converters["GPUVertexFormat"],
+ required: true,
+ },
+ {
+ key: "offset",
+ converter: webidl.converters["GPUSize64"],
+ required: true,
+ },
+ {
+ key: "shaderLocation",
+ converter: webidl.converters["GPUIndex32"],
+ required: true,
+ },
+];
+webidl.converters["GPUVertexAttribute"] = webidl.createDictionaryConverter(
+ "GPUVertexAttribute",
+ dictMembersGPUVertexAttribute,
+);
+
+// DICTIONARY: GPUVertexBufferLayout
+const dictMembersGPUVertexBufferLayout = [
+ {
+ key: "arrayStride",
+ converter: webidl.converters["GPUSize64"],
+ required: true,
+ },
+ {
+ key: "stepMode",
+ converter: webidl.converters["GPUVertexStepMode"],
+ defaultValue: "vertex",
+ },
+ {
+ key: "attributes",
+ converter: webidl.createSequenceConverter(
+ webidl.converters["GPUVertexAttribute"],
+ ),
+ required: true,
+ },
+];
+webidl.converters["GPUVertexBufferLayout"] = webidl.createDictionaryConverter(
+ "GPUVertexBufferLayout",
+ dictMembersGPUVertexBufferLayout,
+);
+
+// DICTIONARY: GPUVertexState
+const dictMembersGPUVertexState = [
+ {
+ key: "buffers",
+ converter: webidl.createSequenceConverter(
+ webidl.createNullableConverter(
+ webidl.converters["GPUVertexBufferLayout"],
),
- required: true,
- },
- ];
- webidl.converters["GPUVertexBufferLayout"] = webidl.createDictionaryConverter(
- "GPUVertexBufferLayout",
- dictMembersGPUVertexBufferLayout,
- );
-
- // DICTIONARY: GPUVertexState
- const dictMembersGPUVertexState = [
- {
- key: "buffers",
- converter: webidl.createSequenceConverter(
- webidl.createNullableConverter(
- webidl.converters["GPUVertexBufferLayout"],
- ),
+ ),
+ get defaultValue() {
+ return [];
+ },
+ },
+];
+webidl.converters["GPUVertexState"] = webidl.createDictionaryConverter(
+ "GPUVertexState",
+ dictMembersGPUProgrammableStage,
+ dictMembersGPUVertexState,
+);
+
+// ENUM: GPUPrimitiveTopology
+webidl.converters["GPUPrimitiveTopology"] = webidl.createEnumConverter(
+ "GPUPrimitiveTopology",
+ [
+ "point-list",
+ "line-list",
+ "line-strip",
+ "triangle-list",
+ "triangle-strip",
+ ],
+);
+
+// ENUM: GPUIndexFormat
+webidl.converters["GPUIndexFormat"] = webidl.createEnumConverter(
+ "GPUIndexFormat",
+ [
+ "uint16",
+ "uint32",
+ ],
+);
+
+// ENUM: GPUFrontFace
+webidl.converters["GPUFrontFace"] = webidl.createEnumConverter(
+ "GPUFrontFace",
+ [
+ "ccw",
+ "cw",
+ ],
+);
+
+// ENUM: GPUCullMode
+webidl.converters["GPUCullMode"] = webidl.createEnumConverter("GPUCullMode", [
+ "none",
+ "front",
+ "back",
+]);
+
+// DICTIONARY: GPUPrimitiveState
+const dictMembersGPUPrimitiveState = [
+ {
+ key: "topology",
+ converter: webidl.converters["GPUPrimitiveTopology"],
+ defaultValue: "triangle-list",
+ },
+ { key: "stripIndexFormat", converter: webidl.converters["GPUIndexFormat"] },
+ {
+ key: "frontFace",
+ converter: webidl.converters["GPUFrontFace"],
+ defaultValue: "ccw",
+ },
+ {
+ key: "cullMode",
+ converter: webidl.converters["GPUCullMode"],
+ defaultValue: "none",
+ },
+ {
+ key: "unclippedDepth",
+ converter: webidl.converters["boolean"],
+ defaultValue: false,
+ },
+];
+webidl.converters["GPUPrimitiveState"] = webidl.createDictionaryConverter(
+ "GPUPrimitiveState",
+ dictMembersGPUPrimitiveState,
+);
+
+// ENUM: GPUStencilOperation
+webidl.converters["GPUStencilOperation"] = webidl.createEnumConverter(
+ "GPUStencilOperation",
+ [
+ "keep",
+ "zero",
+ "replace",
+ "invert",
+ "increment-clamp",
+ "decrement-clamp",
+ "increment-wrap",
+ "decrement-wrap",
+ ],
+);
+
+// DICTIONARY: GPUStencilFaceState
+const dictMembersGPUStencilFaceState = [
+ {
+ key: "compare",
+ converter: webidl.converters["GPUCompareFunction"],
+ defaultValue: "always",
+ },
+ {
+ key: "failOp",
+ converter: webidl.converters["GPUStencilOperation"],
+ defaultValue: "keep",
+ },
+ {
+ key: "depthFailOp",
+ converter: webidl.converters["GPUStencilOperation"],
+ defaultValue: "keep",
+ },
+ {
+ key: "passOp",
+ converter: webidl.converters["GPUStencilOperation"],
+ defaultValue: "keep",
+ },
+];
+webidl.converters["GPUStencilFaceState"] = webidl.createDictionaryConverter(
+ "GPUStencilFaceState",
+ dictMembersGPUStencilFaceState,
+);
+
+// TYPEDEF: GPUStencilValue
+webidl.converters["GPUStencilValue"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+
+// TYPEDEF: GPUDepthBias
+webidl.converters["GPUDepthBias"] = (V, opts) =>
+ webidl.converters["long"](V, { ...opts, enforceRange: true });
+
+// DICTIONARY: GPUDepthStencilState
+const dictMembersGPUDepthStencilState = [
+ {
+ key: "format",
+ converter: webidl.converters["GPUTextureFormat"],
+ required: true,
+ },
+ {
+ key: "depthWriteEnabled",
+ converter: webidl.converters["boolean"],
+ defaultValue: false,
+ },
+ {
+ key: "depthCompare",
+ converter: webidl.converters["GPUCompareFunction"],
+ defaultValue: "always",
+ },
+ {
+ key: "stencilFront",
+ converter: webidl.converters["GPUStencilFaceState"],
+ get defaultValue() {
+ return {};
+ },
+ },
+ {
+ key: "stencilBack",
+ converter: webidl.converters["GPUStencilFaceState"],
+ get defaultValue() {
+ return {};
+ },
+ },
+ {
+ key: "stencilReadMask",
+ converter: webidl.converters["GPUStencilValue"],
+ defaultValue: 0xFFFFFFFF,
+ },
+ {
+ key: "stencilWriteMask",
+ converter: webidl.converters["GPUStencilValue"],
+ defaultValue: 0xFFFFFFFF,
+ },
+ {
+ key: "depthBias",
+ converter: webidl.converters["GPUDepthBias"],
+ defaultValue: 0,
+ },
+ {
+ key: "depthBiasSlopeScale",
+ converter: webidl.converters["float"],
+ defaultValue: 0,
+ },
+ {
+ key: "depthBiasClamp",
+ converter: webidl.converters["float"],
+ defaultValue: 0,
+ },
+];
+webidl.converters["GPUDepthStencilState"] = webidl.createDictionaryConverter(
+ "GPUDepthStencilState",
+ dictMembersGPUDepthStencilState,
+);
+
+// TYPEDEF: GPUSampleMask
+webidl.converters["GPUSampleMask"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+
+// DICTIONARY: GPUMultisampleState
+const dictMembersGPUMultisampleState = [
+ {
+ key: "count",
+ converter: webidl.converters["GPUSize32"],
+ defaultValue: 1,
+ },
+ {
+ key: "mask",
+ converter: webidl.converters["GPUSampleMask"],
+ defaultValue: 0xFFFFFFFF,
+ },
+ {
+ key: "alphaToCoverageEnabled",
+ converter: webidl.converters["boolean"],
+ defaultValue: false,
+ },
+];
+webidl.converters["GPUMultisampleState"] = webidl.createDictionaryConverter(
+ "GPUMultisampleState",
+ dictMembersGPUMultisampleState,
+);
+
+// ENUM: GPUBlendFactor
+webidl.converters["GPUBlendFactor"] = webidl.createEnumConverter(
+ "GPUBlendFactor",
+ [
+ "zero",
+ "one",
+ "src",
+ "one-minus-src",
+ "src-alpha",
+ "one-minus-src-alpha",
+ "dst",
+ "one-minus-dst",
+ "dst-alpha",
+ "one-minus-dst-alpha",
+ "src-alpha-saturated",
+ "constant",
+ "one-minus-constant",
+ ],
+);
+
+// ENUM: GPUBlendOperation
+webidl.converters["GPUBlendOperation"] = webidl.createEnumConverter(
+ "GPUBlendOperation",
+ [
+ "add",
+ "subtract",
+ "reverse-subtract",
+ "min",
+ "max",
+ ],
+);
+
+// DICTIONARY: GPUBlendComponent
+const dictMembersGPUBlendComponent = [
+ {
+ key: "srcFactor",
+ converter: webidl.converters["GPUBlendFactor"],
+ defaultValue: "one",
+ },
+ {
+ key: "dstFactor",
+ converter: webidl.converters["GPUBlendFactor"],
+ defaultValue: "zero",
+ },
+ {
+ key: "operation",
+ converter: webidl.converters["GPUBlendOperation"],
+ defaultValue: "add",
+ },
+];
+webidl.converters["GPUBlendComponent"] = webidl.createDictionaryConverter(
+ "GPUBlendComponent",
+ dictMembersGPUBlendComponent,
+);
+
+// DICTIONARY: GPUBlendState
+const dictMembersGPUBlendState = [
+ {
+ key: "color",
+ converter: webidl.converters["GPUBlendComponent"],
+ required: true,
+ },
+ {
+ key: "alpha",
+ converter: webidl.converters["GPUBlendComponent"],
+ required: true,
+ },
+];
+webidl.converters["GPUBlendState"] = webidl.createDictionaryConverter(
+ "GPUBlendState",
+ dictMembersGPUBlendState,
+);
+
+// TYPEDEF: GPUColorWriteFlags
+webidl.converters["GPUColorWriteFlags"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+
+// DICTIONARY: GPUColorTargetState
+const dictMembersGPUColorTargetState = [
+ {
+ key: "format",
+ converter: webidl.converters["GPUTextureFormat"],
+ required: true,
+ },
+ { key: "blend", converter: webidl.converters["GPUBlendState"] },
+ {
+ key: "writeMask",
+ converter: webidl.converters["GPUColorWriteFlags"],
+ defaultValue: 0xF,
+ },
+];
+webidl.converters["GPUColorTargetState"] = webidl.createDictionaryConverter(
+ "GPUColorTargetState",
+ dictMembersGPUColorTargetState,
+);
+
+// DICTIONARY: GPUFragmentState
+const dictMembersGPUFragmentState = [
+ {
+ key: "targets",
+ converter: webidl.createSequenceConverter(
+ webidl.createNullableConverter(
+ webidl.converters["GPUColorTargetState"],
),
- get defaultValue() {
- return [];
- },
- },
- ];
- webidl.converters["GPUVertexState"] = webidl.createDictionaryConverter(
- "GPUVertexState",
- dictMembersGPUProgrammableStage,
- dictMembersGPUVertexState,
- );
-
- // ENUM: GPUPrimitiveTopology
- webidl.converters["GPUPrimitiveTopology"] = webidl.createEnumConverter(
- "GPUPrimitiveTopology",
- [
- "point-list",
- "line-list",
- "line-strip",
- "triangle-list",
- "triangle-strip",
- ],
- );
-
- // ENUM: GPUIndexFormat
- webidl.converters["GPUIndexFormat"] = webidl.createEnumConverter(
- "GPUIndexFormat",
- [
- "uint16",
- "uint32",
- ],
- );
-
- // ENUM: GPUFrontFace
- webidl.converters["GPUFrontFace"] = webidl.createEnumConverter(
- "GPUFrontFace",
- [
- "ccw",
- "cw",
- ],
- );
-
- // ENUM: GPUCullMode
- webidl.converters["GPUCullMode"] = webidl.createEnumConverter("GPUCullMode", [
- "none",
- "front",
- "back",
- ]);
-
- // DICTIONARY: GPUPrimitiveState
- const dictMembersGPUPrimitiveState = [
- {
- key: "topology",
- converter: webidl.converters["GPUPrimitiveTopology"],
- defaultValue: "triangle-list",
- },
- { key: "stripIndexFormat", converter: webidl.converters["GPUIndexFormat"] },
- {
- key: "frontFace",
- converter: webidl.converters["GPUFrontFace"],
- defaultValue: "ccw",
- },
- {
- key: "cullMode",
- converter: webidl.converters["GPUCullMode"],
- defaultValue: "none",
- },
- {
- key: "unclippedDepth",
- converter: webidl.converters["boolean"],
- defaultValue: false,
- },
- ];
- webidl.converters["GPUPrimitiveState"] = webidl.createDictionaryConverter(
- "GPUPrimitiveState",
- dictMembersGPUPrimitiveState,
- );
-
- // ENUM: GPUStencilOperation
- webidl.converters["GPUStencilOperation"] = webidl.createEnumConverter(
- "GPUStencilOperation",
- [
- "keep",
- "zero",
- "replace",
- "invert",
- "increment-clamp",
- "decrement-clamp",
- "increment-wrap",
- "decrement-wrap",
- ],
- );
-
- // DICTIONARY: GPUStencilFaceState
- const dictMembersGPUStencilFaceState = [
- {
- key: "compare",
- converter: webidl.converters["GPUCompareFunction"],
- defaultValue: "always",
- },
- {
- key: "failOp",
- converter: webidl.converters["GPUStencilOperation"],
- defaultValue: "keep",
- },
- {
- key: "depthFailOp",
- converter: webidl.converters["GPUStencilOperation"],
- defaultValue: "keep",
- },
- {
- key: "passOp",
- converter: webidl.converters["GPUStencilOperation"],
- defaultValue: "keep",
- },
- ];
- webidl.converters["GPUStencilFaceState"] = webidl.createDictionaryConverter(
- "GPUStencilFaceState",
- dictMembersGPUStencilFaceState,
- );
-
- // TYPEDEF: GPUStencilValue
- webidl.converters["GPUStencilValue"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
-
- // TYPEDEF: GPUDepthBias
- webidl.converters["GPUDepthBias"] = (V, opts) =>
- webidl.converters["long"](V, { ...opts, enforceRange: true });
-
- // DICTIONARY: GPUDepthStencilState
- const dictMembersGPUDepthStencilState = [
- {
- key: "format",
- converter: webidl.converters["GPUTextureFormat"],
- required: true,
- },
- {
- key: "depthWriteEnabled",
- converter: webidl.converters["boolean"],
- defaultValue: false,
- },
- {
- key: "depthCompare",
- converter: webidl.converters["GPUCompareFunction"],
- defaultValue: "always",
- },
- {
- key: "stencilFront",
- converter: webidl.converters["GPUStencilFaceState"],
- get defaultValue() {
- return {};
- },
- },
- {
- key: "stencilBack",
- converter: webidl.converters["GPUStencilFaceState"],
- get defaultValue() {
- return {};
- },
- },
- {
- key: "stencilReadMask",
- converter: webidl.converters["GPUStencilValue"],
- defaultValue: 0xFFFFFFFF,
- },
- {
- key: "stencilWriteMask",
- converter: webidl.converters["GPUStencilValue"],
- defaultValue: 0xFFFFFFFF,
- },
- {
- key: "depthBias",
- converter: webidl.converters["GPUDepthBias"],
- defaultValue: 0,
- },
- {
- key: "depthBiasSlopeScale",
- converter: webidl.converters["float"],
- defaultValue: 0,
- },
- {
- key: "depthBiasClamp",
- converter: webidl.converters["float"],
- defaultValue: 0,
- },
- ];
- webidl.converters["GPUDepthStencilState"] = webidl.createDictionaryConverter(
- "GPUDepthStencilState",
- dictMembersGPUDepthStencilState,
- );
-
- // TYPEDEF: GPUSampleMask
- webidl.converters["GPUSampleMask"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
-
- // DICTIONARY: GPUMultisampleState
- const dictMembersGPUMultisampleState = [
- {
- key: "count",
- converter: webidl.converters["GPUSize32"],
- defaultValue: 1,
- },
- {
- key: "mask",
- converter: webidl.converters["GPUSampleMask"],
- defaultValue: 0xFFFFFFFF,
- },
- {
- key: "alphaToCoverageEnabled",
- converter: webidl.converters["boolean"],
- defaultValue: false,
- },
- ];
- webidl.converters["GPUMultisampleState"] = webidl.createDictionaryConverter(
- "GPUMultisampleState",
- dictMembersGPUMultisampleState,
- );
-
- // ENUM: GPUBlendFactor
- webidl.converters["GPUBlendFactor"] = webidl.createEnumConverter(
- "GPUBlendFactor",
- [
- "zero",
- "one",
- "src",
- "one-minus-src",
- "src-alpha",
- "one-minus-src-alpha",
- "dst",
- "one-minus-dst",
- "dst-alpha",
- "one-minus-dst-alpha",
- "src-alpha-saturated",
- "constant",
- "one-minus-constant",
- ],
- );
-
- // ENUM: GPUBlendOperation
- webidl.converters["GPUBlendOperation"] = webidl.createEnumConverter(
- "GPUBlendOperation",
- [
- "add",
- "subtract",
- "reverse-subtract",
- "min",
- "max",
- ],
- );
-
- // DICTIONARY: GPUBlendComponent
- const dictMembersGPUBlendComponent = [
- {
- key: "srcFactor",
- converter: webidl.converters["GPUBlendFactor"],
- defaultValue: "one",
- },
- {
- key: "dstFactor",
- converter: webidl.converters["GPUBlendFactor"],
- defaultValue: "zero",
- },
- {
- key: "operation",
- converter: webidl.converters["GPUBlendOperation"],
- defaultValue: "add",
- },
- ];
- webidl.converters["GPUBlendComponent"] = webidl.createDictionaryConverter(
- "GPUBlendComponent",
- dictMembersGPUBlendComponent,
- );
-
- // DICTIONARY: GPUBlendState
- const dictMembersGPUBlendState = [
- {
- key: "color",
- converter: webidl.converters["GPUBlendComponent"],
- required: true,
- },
- {
- key: "alpha",
- converter: webidl.converters["GPUBlendComponent"],
- required: true,
- },
- ];
- webidl.converters["GPUBlendState"] = webidl.createDictionaryConverter(
- "GPUBlendState",
- dictMembersGPUBlendState,
- );
-
- // TYPEDEF: GPUColorWriteFlags
- webidl.converters["GPUColorWriteFlags"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
-
- // DICTIONARY: GPUColorTargetState
- const dictMembersGPUColorTargetState = [
- {
- key: "format",
- converter: webidl.converters["GPUTextureFormat"],
- required: true,
- },
- { key: "blend", converter: webidl.converters["GPUBlendState"] },
- {
- key: "writeMask",
- converter: webidl.converters["GPUColorWriteFlags"],
- defaultValue: 0xF,
- },
- ];
- webidl.converters["GPUColorTargetState"] = webidl.createDictionaryConverter(
- "GPUColorTargetState",
- dictMembersGPUColorTargetState,
- );
-
- // DICTIONARY: GPUFragmentState
- const dictMembersGPUFragmentState = [
- {
- key: "targets",
- converter: webidl.createSequenceConverter(
- webidl.createNullableConverter(
- webidl.converters["GPUColorTargetState"],
- ),
- ),
- required: true,
- },
- ];
- webidl.converters["GPUFragmentState"] = webidl.createDictionaryConverter(
- "GPUFragmentState",
- dictMembersGPUProgrammableStage,
- dictMembersGPUFragmentState,
- );
-
- // DICTIONARY: GPURenderPipelineDescriptor
- const dictMembersGPURenderPipelineDescriptor = [
- {
- key: "vertex",
- converter: webidl.converters["GPUVertexState"],
- required: true,
- },
- {
- key: "primitive",
- converter: webidl.converters["GPUPrimitiveState"],
- get defaultValue() {
- return {};
- },
- },
- {
- key: "depthStencil",
- converter: webidl.converters["GPUDepthStencilState"],
- },
- {
- key: "multisample",
- converter: webidl.converters["GPUMultisampleState"],
- get defaultValue() {
- return {};
- },
- },
- { key: "fragment", converter: webidl.converters["GPUFragmentState"] },
- ];
- webidl.converters["GPURenderPipelineDescriptor"] = webidl
- .createDictionaryConverter(
- "GPURenderPipelineDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUPipelineDescriptorBase,
- dictMembersGPURenderPipelineDescriptor,
- );
-
- // INTERFACE: GPUColorWrite
- webidl.converters.GPUColorWrite = webidl.createInterfaceConverter(
- "GPUColorWrite",
- GPUColorWrite.prototype,
- );
-
- // INTERFACE: GPUCommandBuffer
- webidl.converters.GPUCommandBuffer = webidl.createInterfaceConverter(
- "GPUCommandBuffer",
- GPUCommandBuffer.prototype,
- );
- webidl.converters["sequence<GPUCommandBuffer>"] = webidl
- .createSequenceConverter(webidl.converters["GPUCommandBuffer"]);
-
- // DICTIONARY: GPUCommandBufferDescriptor
- const dictMembersGPUCommandBufferDescriptor = [];
- webidl.converters["GPUCommandBufferDescriptor"] = webidl
- .createDictionaryConverter(
- "GPUCommandBufferDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUCommandBufferDescriptor,
- );
-
- // INTERFACE: GPUCommandEncoder
- webidl.converters.GPUCommandEncoder = webidl.createInterfaceConverter(
- "GPUCommandEncoder",
- GPUCommandEncoder.prototype,
- );
-
- // DICTIONARY: GPUCommandEncoderDescriptor
- const dictMembersGPUCommandEncoderDescriptor = [];
- webidl.converters["GPUCommandEncoderDescriptor"] = webidl
- .createDictionaryConverter(
- "GPUCommandEncoderDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUCommandEncoderDescriptor,
- );
-
- // DICTIONARY: GPUImageDataLayout
- const dictMembersGPUImageDataLayout = [
- {
- key: "offset",
- converter: webidl.converters["GPUSize64"],
- defaultValue: 0,
- },
- { key: "bytesPerRow", converter: webidl.converters["GPUSize32"] },
- { key: "rowsPerImage", converter: webidl.converters["GPUSize32"] },
- ];
- webidl.converters["GPUImageDataLayout"] = webidl.createDictionaryConverter(
- "GPUImageDataLayout",
- dictMembersGPUImageDataLayout,
- );
-
- // DICTIONARY: GPUImageCopyBuffer
- const dictMembersGPUImageCopyBuffer = [
- {
- key: "buffer",
- converter: webidl.converters["GPUBuffer"],
- required: true,
- },
- ];
- webidl.converters["GPUImageCopyBuffer"] = webidl.createDictionaryConverter(
- "GPUImageCopyBuffer",
- dictMembersGPUImageDataLayout,
- dictMembersGPUImageCopyBuffer,
- );
-
- // DICTIONARY: GPUOrigin3DDict
- const dictMembersGPUOrigin3DDict = [
- {
- key: "x",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 0,
- },
- {
- key: "y",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 0,
- },
- {
- key: "z",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 0,
- },
- ];
- webidl.converters["GPUOrigin3DDict"] = webidl.createDictionaryConverter(
- "GPUOrigin3DDict",
- dictMembersGPUOrigin3DDict,
+ ),
+ required: true,
+ },
+];
+webidl.converters["GPUFragmentState"] = webidl.createDictionaryConverter(
+ "GPUFragmentState",
+ dictMembersGPUProgrammableStage,
+ dictMembersGPUFragmentState,
+);
+
+// DICTIONARY: GPURenderPipelineDescriptor
+const dictMembersGPURenderPipelineDescriptor = [
+ {
+ key: "vertex",
+ converter: webidl.converters["GPUVertexState"],
+ required: true,
+ },
+ {
+ key: "primitive",
+ converter: webidl.converters["GPUPrimitiveState"],
+ get defaultValue() {
+ return {};
+ },
+ },
+ {
+ key: "depthStencil",
+ converter: webidl.converters["GPUDepthStencilState"],
+ },
+ {
+ key: "multisample",
+ converter: webidl.converters["GPUMultisampleState"],
+ get defaultValue() {
+ return {};
+ },
+ },
+ { key: "fragment", converter: webidl.converters["GPUFragmentState"] },
+];
+webidl.converters["GPURenderPipelineDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPURenderPipelineDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUPipelineDescriptorBase,
+ dictMembersGPURenderPipelineDescriptor,
+ );
+
+// INTERFACE: GPUColorWrite
+webidl.converters.GPUColorWrite = webidl.createInterfaceConverter(
+ "GPUColorWrite",
+ GPUColorWrite.prototype,
+);
+
+// INTERFACE: GPUCommandBuffer
+webidl.converters.GPUCommandBuffer = webidl.createInterfaceConverter(
+ "GPUCommandBuffer",
+ GPUCommandBuffer.prototype,
+);
+webidl.converters["sequence<GPUCommandBuffer>"] = webidl
+ .createSequenceConverter(webidl.converters["GPUCommandBuffer"]);
+
+// DICTIONARY: GPUCommandBufferDescriptor
+const dictMembersGPUCommandBufferDescriptor = [];
+webidl.converters["GPUCommandBufferDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPUCommandBufferDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUCommandBufferDescriptor,
);
- // TYPEDEF: GPUOrigin3D
- webidl.converters["GPUOrigin3D"] = (V, opts) => {
- // Union for (sequence<GPUIntegerCoordinate> or GPUOrigin3DDict)
- if (V === null || V === undefined) {
- return webidl.converters["GPUOrigin3DDict"](V, opts);
- }
- if (typeof V === "object") {
- const method = V[SymbolIterator];
- if (method !== undefined) {
- return webidl.converters["sequence<GPUIntegerCoordinate>"](V, opts);
- }
- return webidl.converters["GPUOrigin3DDict"](V, opts);
- }
- throw webidl.makeException(
- TypeError,
- "can not be converted to sequence<GPUIntegerCoordinate> or GPUOrigin3DDict.",
- opts,
- );
- };
-
- // DICTIONARY: GPUImageCopyTexture
- const dictMembersGPUImageCopyTexture = [
- {
- key: "texture",
- converter: webidl.converters["GPUTexture"],
- required: true,
- },
- {
- key: "mipLevel",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 0,
- },
- {
- key: "origin",
- converter: webidl.converters["GPUOrigin3D"],
- get defaultValue() {
- return {};
- },
- },
- {
- key: "aspect",
- converter: webidl.converters["GPUTextureAspect"],
- defaultValue: "all",
- },
- ];
- webidl.converters["GPUImageCopyTexture"] = webidl.createDictionaryConverter(
- "GPUImageCopyTexture",
- dictMembersGPUImageCopyTexture,
- );
+// INTERFACE: GPUCommandEncoder
+webidl.converters.GPUCommandEncoder = webidl.createInterfaceConverter(
+ "GPUCommandEncoder",
+ GPUCommandEncoder.prototype,
+);
- // DICTIONARY: GPUOrigin2DDict
- const dictMembersGPUOrigin2DDict = [
- {
- key: "x",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 0,
- },
- {
- key: "y",
- converter: webidl.converters["GPUIntegerCoordinate"],
- defaultValue: 0,
- },
- ];
- webidl.converters["GPUOrigin2DDict"] = webidl.createDictionaryConverter(
- "GPUOrigin2DDict",
- dictMembersGPUOrigin2DDict,
- );
-
- // TYPEDEF: GPUOrigin2D
- webidl.converters["GPUOrigin2D"] = (V, opts) => {
- // Union for (sequence<GPUIntegerCoordinate> or GPUOrigin2DDict)
- if (V === null || V === undefined) {
- return webidl.converters["GPUOrigin2DDict"](V, opts);
- }
- if (typeof V === "object") {
- const method = V[SymbolIterator];
- if (method !== undefined) {
- return webidl.converters["sequence<GPUIntegerCoordinate>"](V, opts);
- }
- return webidl.converters["GPUOrigin2DDict"](V, opts);
+// DICTIONARY: GPUCommandEncoderDescriptor
+const dictMembersGPUCommandEncoderDescriptor = [];
+webidl.converters["GPUCommandEncoderDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPUCommandEncoderDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUCommandEncoderDescriptor,
+ );
+
+// DICTIONARY: GPUImageDataLayout
+const dictMembersGPUImageDataLayout = [
+ {
+ key: "offset",
+ converter: webidl.converters["GPUSize64"],
+ defaultValue: 0,
+ },
+ { key: "bytesPerRow", converter: webidl.converters["GPUSize32"] },
+ { key: "rowsPerImage", converter: webidl.converters["GPUSize32"] },
+];
+webidl.converters["GPUImageDataLayout"] = webidl.createDictionaryConverter(
+ "GPUImageDataLayout",
+ dictMembersGPUImageDataLayout,
+);
+
+// DICTIONARY: GPUImageCopyBuffer
+const dictMembersGPUImageCopyBuffer = [
+ {
+ key: "buffer",
+ converter: webidl.converters["GPUBuffer"],
+ required: true,
+ },
+];
+webidl.converters["GPUImageCopyBuffer"] = webidl.createDictionaryConverter(
+ "GPUImageCopyBuffer",
+ dictMembersGPUImageDataLayout,
+ dictMembersGPUImageCopyBuffer,
+);
+
+// DICTIONARY: GPUOrigin3DDict
+const dictMembersGPUOrigin3DDict = [
+ {
+ key: "x",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 0,
+ },
+ {
+ key: "y",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 0,
+ },
+ {
+ key: "z",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 0,
+ },
+];
+webidl.converters["GPUOrigin3DDict"] = webidl.createDictionaryConverter(
+ "GPUOrigin3DDict",
+ dictMembersGPUOrigin3DDict,
+);
+
+// TYPEDEF: GPUOrigin3D
+webidl.converters["GPUOrigin3D"] = (V, opts) => {
+ // Union for (sequence<GPUIntegerCoordinate> or GPUOrigin3DDict)
+ if (V === null || V === undefined) {
+ return webidl.converters["GPUOrigin3DDict"](V, opts);
+ }
+ if (typeof V === "object") {
+ const method = V[SymbolIterator];
+ if (method !== undefined) {
+ return webidl.converters["sequence<GPUIntegerCoordinate>"](V, opts);
}
- throw webidl.makeException(
- TypeError,
- "can not be converted to sequence<GPUIntegerCoordinate> or GPUOrigin2DDict.",
- opts,
- );
- };
-
- // INTERFACE: GPUComputePassEncoder
- webidl.converters.GPUComputePassEncoder = webidl.createInterfaceConverter(
- "GPUComputePassEncoder",
- GPUComputePassEncoder.prototype,
- );
-
- // DICTIONARY: GPUComputePassDescriptor
- const dictMembersGPUComputePassDescriptor = [];
- webidl.converters["GPUComputePassDescriptor"] = webidl
- .createDictionaryConverter(
- "GPUComputePassDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPUComputePassDescriptor,
- );
-
- // INTERFACE: GPURenderPassEncoder
- webidl.converters.GPURenderPassEncoder = webidl.createInterfaceConverter(
- "GPURenderPassEncoder",
- GPURenderPassEncoder.prototype,
- );
-
- // ENUM: GPULoadOp
- webidl.converters["GPULoadOp"] = webidl.createEnumConverter("GPULoadOp", [
- "load",
- "clear",
- ]);
-
- // DICTIONARY: GPUColorDict
- const dictMembersGPUColorDict = [
- { key: "r", converter: webidl.converters["double"], required: true },
- { key: "g", converter: webidl.converters["double"], required: true },
- { key: "b", converter: webidl.converters["double"], required: true },
- { key: "a", converter: webidl.converters["double"], required: true },
- ];
- webidl.converters["GPUColorDict"] = webidl.createDictionaryConverter(
- "GPUColorDict",
- dictMembersGPUColorDict,
- );
-
- // TYPEDEF: GPUColor
- webidl.converters["GPUColor"] = (V, opts) => {
- // Union for (sequence<double> or GPUColorDict)
- if (V === null || V === undefined) {
- return webidl.converters["GPUColorDict"](V, opts);
+ return webidl.converters["GPUOrigin3DDict"](V, opts);
+ }
+ throw webidl.makeException(
+ TypeError,
+ "can not be converted to sequence<GPUIntegerCoordinate> or GPUOrigin3DDict.",
+ opts,
+ );
+};
+
+// DICTIONARY: GPUImageCopyTexture
+const dictMembersGPUImageCopyTexture = [
+ {
+ key: "texture",
+ converter: webidl.converters["GPUTexture"],
+ required: true,
+ },
+ {
+ key: "mipLevel",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 0,
+ },
+ {
+ key: "origin",
+ converter: webidl.converters["GPUOrigin3D"],
+ get defaultValue() {
+ return {};
+ },
+ },
+ {
+ key: "aspect",
+ converter: webidl.converters["GPUTextureAspect"],
+ defaultValue: "all",
+ },
+];
+webidl.converters["GPUImageCopyTexture"] = webidl.createDictionaryConverter(
+ "GPUImageCopyTexture",
+ dictMembersGPUImageCopyTexture,
+);
+
+// DICTIONARY: GPUOrigin2DDict
+const dictMembersGPUOrigin2DDict = [
+ {
+ key: "x",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 0,
+ },
+ {
+ key: "y",
+ converter: webidl.converters["GPUIntegerCoordinate"],
+ defaultValue: 0,
+ },
+];
+webidl.converters["GPUOrigin2DDict"] = webidl.createDictionaryConverter(
+ "GPUOrigin2DDict",
+ dictMembersGPUOrigin2DDict,
+);
+
+// TYPEDEF: GPUOrigin2D
+webidl.converters["GPUOrigin2D"] = (V, opts) => {
+ // Union for (sequence<GPUIntegerCoordinate> or GPUOrigin2DDict)
+ if (V === null || V === undefined) {
+ return webidl.converters["GPUOrigin2DDict"](V, opts);
+ }
+ if (typeof V === "object") {
+ const method = V[SymbolIterator];
+ if (method !== undefined) {
+ return webidl.converters["sequence<GPUIntegerCoordinate>"](V, opts);
}
- if (typeof V === "object") {
- const method = V[SymbolIterator];
- if (method !== undefined) {
- return webidl.converters["sequence<double>"](V, opts);
- }
- return webidl.converters["GPUColorDict"](V, opts);
+ return webidl.converters["GPUOrigin2DDict"](V, opts);
+ }
+ throw webidl.makeException(
+ TypeError,
+ "can not be converted to sequence<GPUIntegerCoordinate> or GPUOrigin2DDict.",
+ opts,
+ );
+};
+
+// INTERFACE: GPUComputePassEncoder
+webidl.converters.GPUComputePassEncoder = webidl.createInterfaceConverter(
+ "GPUComputePassEncoder",
+ GPUComputePassEncoder.prototype,
+);
+
+// DICTIONARY: GPUComputePassDescriptor
+const dictMembersGPUComputePassDescriptor = [];
+webidl.converters["GPUComputePassDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPUComputePassDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUComputePassDescriptor,
+ );
+
+// INTERFACE: GPURenderPassEncoder
+webidl.converters.GPURenderPassEncoder = webidl.createInterfaceConverter(
+ "GPURenderPassEncoder",
+ GPURenderPassEncoder.prototype,
+);
+
+// ENUM: GPULoadOp
+webidl.converters["GPULoadOp"] = webidl.createEnumConverter("GPULoadOp", [
+ "load",
+ "clear",
+]);
+
+// DICTIONARY: GPUColorDict
+const dictMembersGPUColorDict = [
+ { key: "r", converter: webidl.converters["double"], required: true },
+ { key: "g", converter: webidl.converters["double"], required: true },
+ { key: "b", converter: webidl.converters["double"], required: true },
+ { key: "a", converter: webidl.converters["double"], required: true },
+];
+webidl.converters["GPUColorDict"] = webidl.createDictionaryConverter(
+ "GPUColorDict",
+ dictMembersGPUColorDict,
+);
+
+// TYPEDEF: GPUColor
+webidl.converters["GPUColor"] = (V, opts) => {
+ // Union for (sequence<double> or GPUColorDict)
+ if (V === null || V === undefined) {
+ return webidl.converters["GPUColorDict"](V, opts);
+ }
+ if (typeof V === "object") {
+ const method = V[SymbolIterator];
+ if (method !== undefined) {
+ return webidl.converters["sequence<double>"](V, opts);
}
- throw webidl.makeException(
- TypeError,
- "can not be converted to sequence<double> or GPUColorDict.",
- opts,
- );
- };
-
- // ENUM: GPUStoreOp
- webidl.converters["GPUStoreOp"] = webidl.createEnumConverter("GPUStoreOp", [
- "store",
- "discard",
- ]);
-
- // DICTIONARY: GPURenderPassColorAttachment
- const dictMembersGPURenderPassColorAttachment = [
- {
- key: "view",
- converter: webidl.converters["GPUTextureView"],
- required: true,
- },
- { key: "resolveTarget", converter: webidl.converters["GPUTextureView"] },
- {
- key: "clearValue",
- converter: webidl.converters["GPUColor"],
- },
- {
- key: "loadOp",
- converter: webidl.converters["GPULoadOp"],
- required: true,
- },
- {
- key: "storeOp",
- converter: webidl.converters["GPUStoreOp"],
- required: true,
- },
- ];
- webidl.converters["GPURenderPassColorAttachment"] = webidl
- .createDictionaryConverter(
- "GPURenderPassColorAttachment",
- dictMembersGPURenderPassColorAttachment,
- );
-
- // DICTIONARY: GPURenderPassDepthStencilAttachment
- const dictMembersGPURenderPassDepthStencilAttachment = [
- {
- key: "view",
- converter: webidl.converters["GPUTextureView"],
- required: true,
- },
- {
- key: "depthClearValue",
- converter: webidl.converters["float"],
- defaultValue: 0,
- },
- {
- key: "depthLoadOp",
- converter: webidl.converters["GPULoadOp"],
- },
- {
- key: "depthStoreOp",
- converter: webidl.converters["GPUStoreOp"],
- },
- {
- key: "depthReadOnly",
- converter: webidl.converters["boolean"],
- defaultValue: false,
- },
- {
- key: "stencilClearValue",
- converter: webidl.converters["GPUStencilValue"],
- defaultValue: 0,
- },
- {
- key: "stencilLoadOp",
- converter: webidl.converters["GPULoadOp"],
- },
- {
- key: "stencilStoreOp",
- converter: webidl.converters["GPUStoreOp"],
- },
- {
- key: "stencilReadOnly",
- converter: webidl.converters["boolean"],
- defaultValue: false,
- },
- ];
- webidl.converters["GPURenderPassDepthStencilAttachment"] = webidl
- .createDictionaryConverter(
- "GPURenderPassDepthStencilAttachment",
- dictMembersGPURenderPassDepthStencilAttachment,
- );
-
- // INTERFACE: GPUQuerySet
- webidl.converters.GPUQuerySet = webidl.createInterfaceConverter(
- "GPUQuerySet",
- GPUQuerySet.prototype,
- );
-
- // DICTIONARY: GPURenderPassDescriptor
- const dictMembersGPURenderPassDescriptor = [
- {
- key: "colorAttachments",
- converter: webidl.createSequenceConverter(
- webidl.createNullableConverter(
- webidl.converters["GPURenderPassColorAttachment"],
- ),
- ),
- required: true,
- },
- {
- key: "depthStencilAttachment",
- converter: webidl.converters["GPURenderPassDepthStencilAttachment"],
- },
- ];
- webidl.converters["GPURenderPassDescriptor"] = webidl
- .createDictionaryConverter(
- "GPURenderPassDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPURenderPassDescriptor,
- );
-
- // INTERFACE: GPURenderBundle
- webidl.converters.GPURenderBundle = webidl.createInterfaceConverter(
- "GPURenderBundle",
- GPURenderBundle.prototype,
- );
- webidl.converters["sequence<GPURenderBundle>"] = webidl
- .createSequenceConverter(webidl.converters["GPURenderBundle"]);
-
- // DICTIONARY: GPURenderBundleDescriptor
- const dictMembersGPURenderBundleDescriptor = [];
- webidl.converters["GPURenderBundleDescriptor"] = webidl
- .createDictionaryConverter(
- "GPURenderBundleDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPURenderBundleDescriptor,
- );
-
- // INTERFACE: GPURenderBundleEncoder
- webidl.converters.GPURenderBundleEncoder = webidl.createInterfaceConverter(
- "GPURenderBundleEncoder",
- GPURenderBundleEncoder.prototype,
- );
-
- // DICTIONARY: GPURenderPassLayout
- const dictMembersGPURenderPassLayout = [
- {
- key: "colorFormats",
- converter: webidl.createSequenceConverter(
- webidl.createNullableConverter(webidl.converters["GPUTextureFormat"]),
- ),
- required: true,
- },
- {
- key: "depthStencilFormat",
- converter: webidl.converters["GPUTextureFormat"],
- },
- {
- key: "sampleCount",
- converter: webidl.converters["GPUSize32"],
- defaultValue: 1,
- },
- ];
- webidl.converters["GPURenderPassLayout"] = webidl
- .createDictionaryConverter(
- "GPURenderPassLayout",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPURenderPassLayout,
- );
-
- // DICTIONARY: GPURenderBundleEncoderDescriptor
- const dictMembersGPURenderBundleEncoderDescriptor = [
- {
- key: "depthReadOnly",
- converter: webidl.converters.boolean,
- defaultValue: false,
- },
- {
- key: "stencilReadOnly",
- converter: webidl.converters.boolean,
- defaultValue: false,
- },
- ];
- webidl.converters["GPURenderBundleEncoderDescriptor"] = webidl
- .createDictionaryConverter(
- "GPURenderBundleEncoderDescriptor",
- dictMembersGPUObjectDescriptorBase,
- dictMembersGPURenderPassLayout,
- dictMembersGPURenderBundleEncoderDescriptor,
- );
-
- // INTERFACE: GPUQueue
- webidl.converters.GPUQueue = webidl.createInterfaceConverter(
- "GPUQueue",
- GPUQueue.prototype,
- );
-
- // ENUM: GPUQueryType
- webidl.converters["GPUQueryType"] = webidl.createEnumConverter(
- "GPUQueryType",
- [
- "occlusion",
- "pipeline-statistics",
- "timestamp",
- ],
- );
-
- // ENUM: GPUPipelineStatisticName
- webidl.converters["GPUPipelineStatisticName"] = webidl.createEnumConverter(
- "GPUPipelineStatisticName",
- [
- "vertex-shader-invocations",
- "clipper-invocations",
- "clipper-primitives-out",
- "fragment-shader-invocations",
- "compute-shader-invocations",
- ],
- );
-
- // DICTIONARY: GPUQuerySetDescriptor
- const dictMembersGPUQuerySetDescriptor = [
- {
- key: "type",
- converter: webidl.converters["GPUQueryType"],
- required: true,
- },
- { key: "count", converter: webidl.converters["GPUSize32"], required: true },
- {
- key: "pipelineStatistics",
- converter: webidl.createSequenceConverter(
- webidl.converters["GPUPipelineStatisticName"],
+ return webidl.converters["GPUColorDict"](V, opts);
+ }
+ throw webidl.makeException(
+ TypeError,
+ "can not be converted to sequence<double> or GPUColorDict.",
+ opts,
+ );
+};
+
+// ENUM: GPUStoreOp
+webidl.converters["GPUStoreOp"] = webidl.createEnumConverter("GPUStoreOp", [
+ "store",
+ "discard",
+]);
+
+// DICTIONARY: GPURenderPassColorAttachment
+const dictMembersGPURenderPassColorAttachment = [
+ {
+ key: "view",
+ converter: webidl.converters["GPUTextureView"],
+ required: true,
+ },
+ { key: "resolveTarget", converter: webidl.converters["GPUTextureView"] },
+ {
+ key: "clearValue",
+ converter: webidl.converters["GPUColor"],
+ },
+ {
+ key: "loadOp",
+ converter: webidl.converters["GPULoadOp"],
+ required: true,
+ },
+ {
+ key: "storeOp",
+ converter: webidl.converters["GPUStoreOp"],
+ required: true,
+ },
+];
+webidl.converters["GPURenderPassColorAttachment"] = webidl
+ .createDictionaryConverter(
+ "GPURenderPassColorAttachment",
+ dictMembersGPURenderPassColorAttachment,
+ );
+
+// DICTIONARY: GPURenderPassDepthStencilAttachment
+const dictMembersGPURenderPassDepthStencilAttachment = [
+ {
+ key: "view",
+ converter: webidl.converters["GPUTextureView"],
+ required: true,
+ },
+ {
+ key: "depthClearValue",
+ converter: webidl.converters["float"],
+ defaultValue: 0,
+ },
+ {
+ key: "depthLoadOp",
+ converter: webidl.converters["GPULoadOp"],
+ },
+ {
+ key: "depthStoreOp",
+ converter: webidl.converters["GPUStoreOp"],
+ },
+ {
+ key: "depthReadOnly",
+ converter: webidl.converters["boolean"],
+ defaultValue: false,
+ },
+ {
+ key: "stencilClearValue",
+ converter: webidl.converters["GPUStencilValue"],
+ defaultValue: 0,
+ },
+ {
+ key: "stencilLoadOp",
+ converter: webidl.converters["GPULoadOp"],
+ },
+ {
+ key: "stencilStoreOp",
+ converter: webidl.converters["GPUStoreOp"],
+ },
+ {
+ key: "stencilReadOnly",
+ converter: webidl.converters["boolean"],
+ defaultValue: false,
+ },
+];
+webidl.converters["GPURenderPassDepthStencilAttachment"] = webidl
+ .createDictionaryConverter(
+ "GPURenderPassDepthStencilAttachment",
+ dictMembersGPURenderPassDepthStencilAttachment,
+ );
+
+// INTERFACE: GPUQuerySet
+webidl.converters.GPUQuerySet = webidl.createInterfaceConverter(
+ "GPUQuerySet",
+ GPUQuerySet.prototype,
+);
+
+// DICTIONARY: GPURenderPassDescriptor
+const dictMembersGPURenderPassDescriptor = [
+ {
+ key: "colorAttachments",
+ converter: webidl.createSequenceConverter(
+ webidl.createNullableConverter(
+ webidl.converters["GPURenderPassColorAttachment"],
),
- get defaultValue() {
- return [];
- },
- },
- ];
- webidl.converters["GPUQuerySetDescriptor"] = webidl.createDictionaryConverter(
- "GPUQuerySetDescriptor",
+ ),
+ required: true,
+ },
+ {
+ key: "depthStencilAttachment",
+ converter: webidl.converters["GPURenderPassDepthStencilAttachment"],
+ },
+];
+webidl.converters["GPURenderPassDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPURenderPassDescriptor",
dictMembersGPUObjectDescriptorBase,
- dictMembersGPUQuerySetDescriptor,
- );
-
- // ENUM: GPUDeviceLostReason
- webidl.converters["GPUDeviceLostReason"] = webidl.createEnumConverter(
- "GPUDeviceLostReason",
- [
- "destroyed",
- ],
- );
-
- // // INTERFACE: GPUDeviceLostInfo
- // webidl.converters.GPUDeviceLostInfo = webidl.createInterfaceConverter(
- // "GPUDeviceLostInfo",
- // GPUDeviceLostInfo.prototype,
- // );
-
- // ENUM: GPUErrorFilter
- webidl.converters["GPUErrorFilter"] = webidl.createEnumConverter(
- "GPUErrorFilter",
- [
- "out-of-memory",
- "validation",
- ],
- );
-
- // INTERFACE: GPUOutOfMemoryError
- webidl.converters.GPUOutOfMemoryError = webidl.createInterfaceConverter(
- "GPUOutOfMemoryError",
- GPUOutOfMemoryError.prototype,
- );
-
- // INTERFACE: GPUValidationError
- webidl.converters.GPUValidationError = webidl.createInterfaceConverter(
- "GPUValidationError",
- GPUValidationError.prototype,
- );
-
- // TYPEDEF: GPUError
- webidl.converters["GPUError"] = webidl.converters.any /** put union here! **/;
-
- // // INTERFACE: GPUUncapturedErrorEvent
- // webidl.converters.GPUUncapturedErrorEvent = webidl.createInterfaceConverter(
- // "GPUUncapturedErrorEvent",
- // GPUUncapturedErrorEvent.prototype,
- // );
-
- // DICTIONARY: GPUUncapturedErrorEventInit
- const dictMembersGPUUncapturedErrorEventInit = [
- { key: "error", converter: webidl.converters["GPUError"], required: true },
- ];
- webidl.converters["GPUUncapturedErrorEventInit"] = webidl
- .createDictionaryConverter(
- "GPUUncapturedErrorEventInit",
- // dictMembersEventInit,
- dictMembersGPUUncapturedErrorEventInit,
- );
-
- // TYPEDEF: GPUBufferDynamicOffset
- webidl.converters["GPUBufferDynamicOffset"] = (V, opts) =>
- webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
-
- // TYPEDEF: GPUSignedOffset32
- webidl.converters["GPUSignedOffset32"] = (V, opts) =>
- webidl.converters["long"](V, { ...opts, enforceRange: true });
-
- // TYPEDEF: GPUFlagsConstant
- webidl.converters["GPUFlagsConstant"] = webidl.converters["unsigned long"];
-})(this);
+ dictMembersGPURenderPassDescriptor,
+ );
+
+// INTERFACE: GPURenderBundle
+webidl.converters.GPURenderBundle = webidl.createInterfaceConverter(
+ "GPURenderBundle",
+ GPURenderBundle.prototype,
+);
+webidl.converters["sequence<GPURenderBundle>"] = webidl
+ .createSequenceConverter(webidl.converters["GPURenderBundle"]);
+
+// DICTIONARY: GPURenderBundleDescriptor
+const dictMembersGPURenderBundleDescriptor = [];
+webidl.converters["GPURenderBundleDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPURenderBundleDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPURenderBundleDescriptor,
+ );
+
+// INTERFACE: GPURenderBundleEncoder
+webidl.converters.GPURenderBundleEncoder = webidl.createInterfaceConverter(
+ "GPURenderBundleEncoder",
+ GPURenderBundleEncoder.prototype,
+);
+
+// DICTIONARY: GPURenderPassLayout
+const dictMembersGPURenderPassLayout = [
+ {
+ key: "colorFormats",
+ converter: webidl.createSequenceConverter(
+ webidl.createNullableConverter(webidl.converters["GPUTextureFormat"]),
+ ),
+ required: true,
+ },
+ {
+ key: "depthStencilFormat",
+ converter: webidl.converters["GPUTextureFormat"],
+ },
+ {
+ key: "sampleCount",
+ converter: webidl.converters["GPUSize32"],
+ defaultValue: 1,
+ },
+];
+webidl.converters["GPURenderPassLayout"] = webidl
+ .createDictionaryConverter(
+ "GPURenderPassLayout",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPURenderPassLayout,
+ );
+
+// DICTIONARY: GPURenderBundleEncoderDescriptor
+const dictMembersGPURenderBundleEncoderDescriptor = [
+ {
+ key: "depthReadOnly",
+ converter: webidl.converters.boolean,
+ defaultValue: false,
+ },
+ {
+ key: "stencilReadOnly",
+ converter: webidl.converters.boolean,
+ defaultValue: false,
+ },
+];
+webidl.converters["GPURenderBundleEncoderDescriptor"] = webidl
+ .createDictionaryConverter(
+ "GPURenderBundleEncoderDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPURenderPassLayout,
+ dictMembersGPURenderBundleEncoderDescriptor,
+ );
+
+// INTERFACE: GPUQueue
+webidl.converters.GPUQueue = webidl.createInterfaceConverter(
+ "GPUQueue",
+ GPUQueue.prototype,
+);
+
+// ENUM: GPUQueryType
+webidl.converters["GPUQueryType"] = webidl.createEnumConverter(
+ "GPUQueryType",
+ [
+ "occlusion",
+ "pipeline-statistics",
+ "timestamp",
+ ],
+);
+
+// ENUM: GPUPipelineStatisticName
+webidl.converters["GPUPipelineStatisticName"] = webidl.createEnumConverter(
+ "GPUPipelineStatisticName",
+ [
+ "vertex-shader-invocations",
+ "clipper-invocations",
+ "clipper-primitives-out",
+ "fragment-shader-invocations",
+ "compute-shader-invocations",
+ ],
+);
+
+// DICTIONARY: GPUQuerySetDescriptor
+const dictMembersGPUQuerySetDescriptor = [
+ {
+ key: "type",
+ converter: webidl.converters["GPUQueryType"],
+ required: true,
+ },
+ { key: "count", converter: webidl.converters["GPUSize32"], required: true },
+ {
+ key: "pipelineStatistics",
+ converter: webidl.createSequenceConverter(
+ webidl.converters["GPUPipelineStatisticName"],
+ ),
+ get defaultValue() {
+ return [];
+ },
+ },
+];
+webidl.converters["GPUQuerySetDescriptor"] = webidl.createDictionaryConverter(
+ "GPUQuerySetDescriptor",
+ dictMembersGPUObjectDescriptorBase,
+ dictMembersGPUQuerySetDescriptor,
+);
+
+// ENUM: GPUDeviceLostReason
+webidl.converters["GPUDeviceLostReason"] = webidl.createEnumConverter(
+ "GPUDeviceLostReason",
+ [
+ "destroyed",
+ ],
+);
+
+// // INTERFACE: GPUDeviceLostInfo
+// webidl.converters.GPUDeviceLostInfo = webidl.createInterfaceConverter(
+// "GPUDeviceLostInfo",
+// GPUDeviceLostInfo.prototype,
+// );
+
+// ENUM: GPUErrorFilter
+webidl.converters["GPUErrorFilter"] = webidl.createEnumConverter(
+ "GPUErrorFilter",
+ [
+ "out-of-memory",
+ "validation",
+ ],
+);
+
+// INTERFACE: GPUOutOfMemoryError
+webidl.converters.GPUOutOfMemoryError = webidl.createInterfaceConverter(
+ "GPUOutOfMemoryError",
+ GPUOutOfMemoryError.prototype,
+);
+
+// INTERFACE: GPUValidationError
+webidl.converters.GPUValidationError = webidl.createInterfaceConverter(
+ "GPUValidationError",
+ GPUValidationError.prototype,
+);
+
+// TYPEDEF: GPUError
+webidl.converters["GPUError"] = webidl.converters.any /** put union here! **/;
+
+// // INTERFACE: GPUUncapturedErrorEvent
+// webidl.converters.GPUUncapturedErrorEvent = webidl.createInterfaceConverter(
+// "GPUUncapturedErrorEvent",
+// GPUUncapturedErrorEvent.prototype,
+// );
+
+// DICTIONARY: GPUUncapturedErrorEventInit
+const dictMembersGPUUncapturedErrorEventInit = [
+ { key: "error", converter: webidl.converters["GPUError"], required: true },
+];
+webidl.converters["GPUUncapturedErrorEventInit"] = webidl
+ .createDictionaryConverter(
+ "GPUUncapturedErrorEventInit",
+ // dictMembersEventInit,
+ dictMembersGPUUncapturedErrorEventInit,
+ );
+
+// TYPEDEF: GPUBufferDynamicOffset
+webidl.converters["GPUBufferDynamicOffset"] = (V, opts) =>
+ webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
+
+// TYPEDEF: GPUSignedOffset32
+webidl.converters["GPUSignedOffset32"] = (V, opts) =>
+ webidl.converters["long"](V, { ...opts, enforceRange: true });
+
+// TYPEDEF: GPUFlagsConstant
+webidl.converters["GPUFlagsConstant"] = webidl.converters["unsigned long"];
diff --git a/ext/webgpu/src/03_surface.js b/ext/webgpu/src/03_surface.js
index f9e422e82..b46db047c 100644
--- a/ext/webgpu/src/03_surface.js
+++ b/ext/webgpu/src/03_surface.js
@@ -6,144 +6,141 @@
/// <reference path="../web/lib.deno_web.d.ts" />
/// <reference path="./lib.deno_webgpu.d.ts" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const { Symbol } = window.__bootstrap.primordials;
- const { _device, assertDevice, createGPUTexture } = window.__bootstrap.webgpu;
-
- const _surfaceRid = Symbol("[[surfaceRid]]");
- const _configuration = Symbol("[[configuration]]");
- const _canvas = Symbol("[[canvas]]");
- const _currentTexture = Symbol("[[currentTexture]]");
- class GPUCanvasContext {
- /** @type {number} */
- [_surfaceRid];
- /** @type {InnerGPUDevice} */
- [_device];
- [_configuration];
- [_canvas];
- /** @type {GPUTexture | undefined} */
- [_currentTexture];
-
- get canvas() {
- webidl.assertBranded(this, GPUCanvasContextPrototype);
- return this[_canvas];
- }
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- configure(configuration) {
- webidl.assertBranded(this, GPUCanvasContextPrototype);
- const prefix = "Failed to execute 'configure' on 'GPUCanvasContext'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- configuration = webidl.converters.GPUCanvasConfiguration(configuration, {
- prefix,
- context: "Argument 1",
- });
-
- this[_device] = configuration.device[_device];
- this[_configuration] = configuration;
- const device = assertDevice(this, {
- prefix,
- context: "configuration.device",
- });
-
- const { err } = ops.op_webgpu_surface_configure({
- surfaceRid: this[_surfaceRid],
- deviceRid: device.rid,
- format: configuration.format,
- viewFormats: configuration.viewFormats,
- usage: configuration.usage,
- width: configuration.width,
- height: configuration.height,
- alphaMode: configuration.alphaMode,
- });
-
- device.pushError(err);
- }
-
- unconfigure() {
- webidl.assertBranded(this, GPUCanvasContextPrototype);
-
- this[_configuration] = null;
- this[_device] = null;
- }
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+const primordials = globalThis.__bootstrap.primordials;
+const { Symbol } = primordials;
+import {
+ _device,
+ assertDevice,
+ createGPUTexture,
+} from "internal:ext/webgpu/01_webgpu.js";
+
+const _surfaceRid = Symbol("[[surfaceRid]]");
+const _configuration = Symbol("[[configuration]]");
+const _canvas = Symbol("[[canvas]]");
+const _currentTexture = Symbol("[[currentTexture]]");
+class GPUCanvasContext {
+ /** @type {number} */
+ [_surfaceRid];
+ /** @type {InnerGPUDevice} */
+ [_device];
+ [_configuration];
+ [_canvas];
+ /** @type {GPUTexture | undefined} */
+ [_currentTexture];
+
+ get canvas() {
+ webidl.assertBranded(this, GPUCanvasContextPrototype);
+ return this[_canvas];
+ }
- getCurrentTexture() {
- webidl.assertBranded(this, GPUCanvasContextPrototype);
- const prefix =
- "Failed to execute 'getCurrentTexture' on 'GPUCanvasContext'";
+ constructor() {
+ webidl.illegalConstructor();
+ }
- if (this[_configuration] === null) {
- throw new DOMException(
- "context is not configured.",
- "InvalidStateError",
- );
- }
+ configure(configuration) {
+ webidl.assertBranded(this, GPUCanvasContextPrototype);
+ const prefix = "Failed to execute 'configure' on 'GPUCanvasContext'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ configuration = webidl.converters.GPUCanvasConfiguration(configuration, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ this[_device] = configuration.device[_device];
+ this[_configuration] = configuration;
+ const device = assertDevice(this, {
+ prefix,
+ context: "configuration.device",
+ });
+
+ const { err } = ops.op_webgpu_surface_configure({
+ surfaceRid: this[_surfaceRid],
+ deviceRid: device.rid,
+ format: configuration.format,
+ viewFormats: configuration.viewFormats,
+ usage: configuration.usage,
+ width: configuration.width,
+ height: configuration.height,
+ alphaMode: configuration.alphaMode,
+ });
+
+ device.pushError(err);
+ }
- const device = assertDevice(this, { prefix, context: "this" });
+ unconfigure() {
+ webidl.assertBranded(this, GPUCanvasContextPrototype);
- if (this[_currentTexture]) {
- return this[_currentTexture];
- }
+ this[_configuration] = null;
+ this[_device] = null;
+ }
- const { rid } = ops.op_webgpu_surface_get_current_texture(
- device.rid,
- this[_surfaceRid],
- );
+ getCurrentTexture() {
+ webidl.assertBranded(this, GPUCanvasContextPrototype);
+ const prefix =
+ "Failed to execute 'getCurrentTexture' on 'GPUCanvasContext'";
- const texture = createGPUTexture(
- {
- size: {
- width: this[_configuration].width,
- height: this[_configuration].height,
- depthOrArrayLayers: 1,
- },
- mipLevelCount: 1,
- sampleCount: 1,
- dimension: "2d",
- format: this[_configuration].format,
- usage: this[_configuration].usage,
- },
- device,
- rid,
+ if (this[_configuration] === null) {
+ throw new DOMException(
+ "context is not configured.",
+ "InvalidStateError",
);
- device.trackResource(texture);
- this[_currentTexture] = texture;
- return texture;
}
- // Extended from spec. Required to present the texture; browser don't need this.
- present() {
- webidl.assertBranded(this, GPUCanvasContextPrototype);
- const prefix = "Failed to execute 'present' on 'GPUCanvasContext'";
- const device = assertDevice(this[_currentTexture], {
- prefix,
- context: "this",
- });
- ops.op_webgpu_surface_present(device.rid, this[_surfaceRid]);
- this[_currentTexture].destroy();
- this[_currentTexture] = undefined;
+ const device = assertDevice(this, { prefix, context: "this" });
+
+ if (this[_currentTexture]) {
+ return this[_currentTexture];
}
+
+ const { rid } = ops.op_webgpu_surface_get_current_texture(
+ device.rid,
+ this[_surfaceRid],
+ );
+
+ const texture = createGPUTexture(
+ {
+ size: {
+ width: this[_configuration].width,
+ height: this[_configuration].height,
+ depthOrArrayLayers: 1,
+ },
+ mipLevelCount: 1,
+ sampleCount: 1,
+ dimension: "2d",
+ format: this[_configuration].format,
+ usage: this[_configuration].usage,
+ },
+ device,
+ rid,
+ );
+ device.trackResource(texture);
+ this[_currentTexture] = texture;
+ return texture;
}
- const GPUCanvasContextPrototype = GPUCanvasContext.prototype;
- function createCanvasContext(options) {
- const canvasContext = webidl.createBranded(GPUCanvasContext);
- canvasContext[_surfaceRid] = options.surfaceRid;
- canvasContext[_canvas] = options.canvas;
- return canvasContext;
+ // Extended from spec. Required to present the texture; browser don't need this.
+ present() {
+ webidl.assertBranded(this, GPUCanvasContextPrototype);
+ const prefix = "Failed to execute 'present' on 'GPUCanvasContext'";
+ const device = assertDevice(this[_currentTexture], {
+ prefix,
+ context: "this",
+ });
+ ops.op_webgpu_surface_present(device.rid, this[_surfaceRid]);
+ this[_currentTexture].destroy();
+ this[_currentTexture] = undefined;
}
+}
+const GPUCanvasContextPrototype = GPUCanvasContext.prototype;
+
+function createCanvasContext(options) {
+ const canvasContext = webidl.createBranded(GPUCanvasContext);
+ canvasContext[_surfaceRid] = options.surfaceRid;
+ canvasContext[_canvas] = options.canvas;
+ return canvasContext;
+}
- window.__bootstrap.webgpu = {
- ...window.__bootstrap.webgpu,
- GPUCanvasContext,
- createCanvasContext,
- };
-})(this);
+export { createCanvasContext, GPUCanvasContext };
diff --git a/ext/webgpu/src/04_surface_idl_types.js b/ext/webgpu/src/04_surface_idl_types.js
index 9dcfa767e..f9665afa6 100644
--- a/ext/webgpu/src/04_surface_idl_types.js
+++ b/ext/webgpu/src/04_surface_idl_types.js
@@ -6,81 +6,77 @@
/// <reference path="../web/lib.deno_web.d.ts" />
/// <reference path="./lib.deno_webgpu.d.ts" />
-"use strict";
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { GPUTextureUsage } from "internal:ext/webgpu/01_webgpu.js";
-((window) => {
- const webidl = window.__bootstrap.webidl;
- const { GPUTextureUsage } = window.__bootstrap.webgpu;
+// ENUM: GPUCanvasAlphaMode
+webidl.converters["GPUCanvasAlphaMode"] = webidl.createEnumConverter(
+ "GPUCanvasAlphaMode",
+ [
+ "opaque",
+ "premultiplied",
+ ],
+);
- // ENUM: GPUCanvasAlphaMode
- webidl.converters["GPUCanvasAlphaMode"] = webidl.createEnumConverter(
- "GPUCanvasAlphaMode",
- [
- "opaque",
- "premultiplied",
- ],
- );
-
- // NON-SPEC: ENUM: GPUPresentMode
- webidl.converters["GPUPresentMode"] = webidl.createEnumConverter(
- "GPUPresentMode",
- [
- "autoVsync",
- "autoNoVsync",
- "fifo",
- "fifoRelaxed",
- "immediate",
- "mailbox",
- ],
- );
+// NON-SPEC: ENUM: GPUPresentMode
+webidl.converters["GPUPresentMode"] = webidl.createEnumConverter(
+ "GPUPresentMode",
+ [
+ "autoVsync",
+ "autoNoVsync",
+ "fifo",
+ "fifoRelaxed",
+ "immediate",
+ "mailbox",
+ ],
+);
- // DICT: GPUCanvasConfiguration
- const dictMembersGPUCanvasConfiguration = [
- { key: "device", converter: webidl.converters.GPUDevice, required: true },
- {
- key: "format",
- converter: webidl.converters.GPUTextureFormat,
- required: true,
- },
- {
- key: "usage",
- converter: webidl.converters["GPUTextureUsageFlags"],
- defaultValue: GPUTextureUsage.RENDER_ATTACHMENT,
- },
- {
- key: "alphaMode",
- converter: webidl.converters["GPUCanvasAlphaMode"],
- defaultValue: "opaque",
- },
+// DICT: GPUCanvasConfiguration
+const dictMembersGPUCanvasConfiguration = [
+ { key: "device", converter: webidl.converters.GPUDevice, required: true },
+ {
+ key: "format",
+ converter: webidl.converters.GPUTextureFormat,
+ required: true,
+ },
+ {
+ key: "usage",
+ converter: webidl.converters["GPUTextureUsageFlags"],
+ defaultValue: GPUTextureUsage.RENDER_ATTACHMENT,
+ },
+ {
+ key: "alphaMode",
+ converter: webidl.converters["GPUCanvasAlphaMode"],
+ defaultValue: "opaque",
+ },
- // Extended from spec
- {
- key: "presentMode",
- converter: webidl.converters["GPUPresentMode"],
- },
- {
- key: "width",
- converter: webidl.converters["long"],
- required: true,
- },
- {
- key: "height",
- converter: webidl.converters["long"],
- required: true,
+ // Extended from spec
+ {
+ key: "presentMode",
+ converter: webidl.converters["GPUPresentMode"],
+ },
+ {
+ key: "width",
+ converter: webidl.converters["long"],
+ required: true,
+ },
+ {
+ key: "height",
+ converter: webidl.converters["long"],
+ required: true,
+ },
+ {
+ key: "viewFormats",
+ converter: webidl.createSequenceConverter(
+ webidl.converters["GPUTextureFormat"],
+ ),
+ get defaultValue() {
+ return [];
},
- {
- key: "viewFormats",
- converter: webidl.createSequenceConverter(
- webidl.converters["GPUTextureFormat"],
- ),
- get defaultValue() {
- return [];
- },
- },
- ];
- webidl.converters["GPUCanvasConfiguration"] = webidl
- .createDictionaryConverter(
- "GPUCanvasConfiguration",
- dictMembersGPUCanvasConfiguration,
- );
-})(this);
+ },
+];
+webidl.converters["GPUCanvasConfiguration"] = webidl
+ .createDictionaryConverter(
+ "GPUCanvasConfiguration",
+ dictMembersGPUCanvasConfiguration,
+ );
diff --git a/ext/webgpu/src/lib.rs b/ext/webgpu/src/lib.rs
index 8e4077e7f..83326b71a 100644
--- a/ext/webgpu/src/lib.rs
+++ b/ext/webgpu/src/lib.rs
@@ -119,7 +119,7 @@ impl Resource for WebGpuQuerySet {
pub fn init(unstable: bool) -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_webidl", "deno_web"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/webgpu",
"01_webgpu.js",
"02_idl_types.js",
diff --git a/ext/webgpu/src/surface.rs b/ext/webgpu/src/surface.rs
index 2ce9cf448..84d17b38d 100644
--- a/ext/webgpu/src/surface.rs
+++ b/ext/webgpu/src/surface.rs
@@ -15,8 +15,8 @@ use wgpu_types::SurfaceStatus;
pub fn init_surface(unstable: bool) -> Extension {
Extension::builder("deno_webgpu_surface")
.dependencies(vec!["deno_webidl", "deno_web", "deno_webgpu"])
- .js(include_js_files!(
- prefix "internal:deno_webgpu",
+ .esm(include_js_files!(
+ prefix "internal:ext/webgpu",
"03_surface.js",
"04_surface_idl_types.js",
))
diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js
index bb90d973e..1357d308e 100644
--- a/ext/webidl/00_webidl.js
+++ b/ext/webidl/00_webidl.js
@@ -6,1186 +6,1182 @@
/// <reference path="../../core/internal.d.ts" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const {
- ArrayBufferPrototype,
- ArrayBufferIsView,
- ArrayPrototypeForEach,
- ArrayPrototypePush,
- ArrayPrototypeSort,
- ArrayIteratorPrototype,
- BigInt,
- BigIntAsIntN,
- BigIntAsUintN,
- Float32Array,
- Float64Array,
- FunctionPrototypeBind,
- Int16Array,
- Int32Array,
- Int8Array,
- isNaN,
- MathFloor,
- MathFround,
- MathMax,
- MathMin,
- MathPow,
- MathRound,
- MathTrunc,
- Number,
- NumberIsFinite,
- NumberIsNaN,
- // deno-lint-ignore camelcase
- NumberMAX_SAFE_INTEGER,
- // deno-lint-ignore camelcase
- NumberMIN_SAFE_INTEGER,
- ObjectAssign,
- ObjectCreate,
- ObjectDefineProperties,
- ObjectDefineProperty,
- ObjectGetOwnPropertyDescriptor,
- ObjectGetOwnPropertyDescriptors,
- ObjectGetPrototypeOf,
- ObjectPrototypeHasOwnProperty,
- ObjectPrototypeIsPrototypeOf,
- ObjectIs,
- PromisePrototypeThen,
- PromiseReject,
- PromiseResolve,
- ReflectApply,
- ReflectDefineProperty,
- ReflectGetOwnPropertyDescriptor,
- ReflectHas,
- ReflectOwnKeys,
- RegExpPrototypeTest,
- Set,
- SetPrototypeEntries,
- SetPrototypeForEach,
- SetPrototypeKeys,
- SetPrototypeValues,
- SetPrototypeHas,
- SetPrototypeClear,
- SetPrototypeDelete,
- SetPrototypeAdd,
- // TODO(lucacasonato): add SharedArrayBuffer to primordials
- // SharedArrayBufferPrototype
- String,
- StringFromCodePoint,
- StringPrototypeCharCodeAt,
- Symbol,
- SymbolIterator,
- SymbolToStringTag,
- TypedArrayPrototypeGetSymbolToStringTag,
- TypeError,
- Uint16Array,
- Uint32Array,
- Uint8Array,
- Uint8ClampedArray,
- } = window.__bootstrap.primordials;
+const core = globalThis.Deno.core;
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayBufferPrototype,
+ ArrayBufferIsView,
+ ArrayPrototypeForEach,
+ ArrayPrototypePush,
+ ArrayPrototypeSort,
+ ArrayIteratorPrototype,
+ BigInt,
+ BigIntAsIntN,
+ BigIntAsUintN,
+ Float32Array,
+ Float64Array,
+ FunctionPrototypeBind,
+ Int16Array,
+ Int32Array,
+ Int8Array,
+ isNaN,
+ MathFloor,
+ MathFround,
+ MathMax,
+ MathMin,
+ MathPow,
+ MathRound,
+ MathTrunc,
+ Number,
+ NumberIsFinite,
+ NumberIsNaN,
+ // deno-lint-ignore camelcase
+ NumberMAX_SAFE_INTEGER,
+ // deno-lint-ignore camelcase
+ NumberMIN_SAFE_INTEGER,
+ ObjectAssign,
+ ObjectCreate,
+ ObjectDefineProperties,
+ ObjectDefineProperty,
+ ObjectGetOwnPropertyDescriptor,
+ ObjectGetOwnPropertyDescriptors,
+ ObjectGetPrototypeOf,
+ ObjectPrototypeHasOwnProperty,
+ ObjectPrototypeIsPrototypeOf,
+ ObjectIs,
+ PromisePrototypeThen,
+ PromiseReject,
+ PromiseResolve,
+ ReflectApply,
+ ReflectDefineProperty,
+ ReflectGetOwnPropertyDescriptor,
+ ReflectHas,
+ ReflectOwnKeys,
+ RegExpPrototypeTest,
+ Set,
+ SetPrototypeEntries,
+ SetPrototypeForEach,
+ SetPrototypeKeys,
+ SetPrototypeValues,
+ SetPrototypeHas,
+ SetPrototypeClear,
+ SetPrototypeDelete,
+ SetPrototypeAdd,
+ // TODO(lucacasonato): add SharedArrayBuffer to primordials
+ // SharedArrayBufferPrototype
+ String,
+ StringFromCodePoint,
+ StringPrototypeCharCodeAt,
+ Symbol,
+ SymbolIterator,
+ SymbolToStringTag,
+ TypedArrayPrototypeGetSymbolToStringTag,
+ TypeError,
+ Uint16Array,
+ Uint32Array,
+ Uint8Array,
+ Uint8ClampedArray,
+} = primordials;
+
+function makeException(ErrorType, message, opts = {}) {
+ return new ErrorType(
+ `${opts.prefix ? opts.prefix + ": " : ""}${
+ opts.context ? opts.context : "Value"
+ } ${message}`,
+ );
+}
- function makeException(ErrorType, message, opts = {}) {
- return new ErrorType(
- `${opts.prefix ? opts.prefix + ": " : ""}${
- opts.context ? opts.context : "Value"
- } ${message}`,
- );
+function toNumber(value) {
+ if (typeof value === "bigint") {
+ throw TypeError("Cannot convert a BigInt value to a number");
}
+ return Number(value);
+}
- function toNumber(value) {
- if (typeof value === "bigint") {
- throw TypeError("Cannot convert a BigInt value to a number");
- }
- return Number(value);
+function type(V) {
+ if (V === null) {
+ return "Null";
}
+ switch (typeof V) {
+ case "undefined":
+ return "Undefined";
+ case "boolean":
+ return "Boolean";
+ case "number":
+ return "Number";
+ case "string":
+ return "String";
+ case "symbol":
+ return "Symbol";
+ case "bigint":
+ return "BigInt";
+ case "object":
+ // Falls through
+ case "function":
+ // Falls through
+ default:
+ // Per ES spec, typeof returns an implemention-defined value that is not any of the existing ones for
+ // uncallable non-standard exotic objects. Yet Type() which the Web IDL spec depends on returns Object for
+ // such cases. So treat the default case as an object.
+ return "Object";
+ }
+}
- function type(V) {
- if (V === null) {
- return "Null";
- }
- switch (typeof V) {
- case "undefined":
- return "Undefined";
- case "boolean":
- return "Boolean";
- case "number":
- return "Number";
- case "string":
- return "String";
- case "symbol":
- return "Symbol";
- case "bigint":
- return "BigInt";
- case "object":
- // Falls through
- case "function":
- // Falls through
- default:
- // Per ES spec, typeof returns an implemention-defined value that is not any of the existing ones for
- // uncallable non-standard exotic objects. Yet Type() which the Web IDL spec depends on returns Object for
- // such cases. So treat the default case as an object.
- return "Object";
- }
+// Round x to the nearest integer, choosing the even integer if it lies halfway between two.
+function evenRound(x) {
+ // There are four cases for numbers with fractional part being .5:
+ //
+ // case | x | floor(x) | round(x) | expected | x <> 0 | x % 1 | x & 1 | example
+ // 1 | 2n + 0.5 | 2n | 2n + 1 | 2n | > | 0.5 | 0 | 0.5 -> 0
+ // 2 | 2n + 1.5 | 2n + 1 | 2n + 2 | 2n + 2 | > | 0.5 | 1 | 1.5 -> 2
+ // 3 | -2n - 0.5 | -2n - 1 | -2n | -2n | < | -0.5 | 0 | -0.5 -> 0
+ // 4 | -2n - 1.5 | -2n - 2 | -2n - 1 | -2n - 2 | < | -0.5 | 1 | -1.5 -> -2
+ // (where n is a non-negative integer)
+ //
+ // Branch here for cases 1 and 4
+ if (
+ (x > 0 && x % 1 === +0.5 && (x & 1) === 0) ||
+ (x < 0 && x % 1 === -0.5 && (x & 1) === 1)
+ ) {
+ return censorNegativeZero(MathFloor(x));
}
- // Round x to the nearest integer, choosing the even integer if it lies halfway between two.
- function evenRound(x) {
- // There are four cases for numbers with fractional part being .5:
- //
- // case | x | floor(x) | round(x) | expected | x <> 0 | x % 1 | x & 1 | example
- // 1 | 2n + 0.5 | 2n | 2n + 1 | 2n | > | 0.5 | 0 | 0.5 -> 0
- // 2 | 2n + 1.5 | 2n + 1 | 2n + 2 | 2n + 2 | > | 0.5 | 1 | 1.5 -> 2
- // 3 | -2n - 0.5 | -2n - 1 | -2n | -2n | < | -0.5 | 0 | -0.5 -> 0
- // 4 | -2n - 1.5 | -2n - 2 | -2n - 1 | -2n - 2 | < | -0.5 | 1 | -1.5 -> -2
- // (where n is a non-negative integer)
- //
- // Branch here for cases 1 and 4
- if (
- (x > 0 && x % 1 === +0.5 && (x & 1) === 0) ||
- (x < 0 && x % 1 === -0.5 && (x & 1) === 1)
- ) {
- return censorNegativeZero(MathFloor(x));
- }
+ return censorNegativeZero(MathRound(x));
+}
- return censorNegativeZero(MathRound(x));
- }
+function integerPart(n) {
+ return censorNegativeZero(MathTrunc(n));
+}
- function integerPart(n) {
- return censorNegativeZero(MathTrunc(n));
- }
+function sign(x) {
+ return x < 0 ? -1 : 1;
+}
- function sign(x) {
- return x < 0 ? -1 : 1;
+function modulo(x, y) {
+ // https://tc39.github.io/ecma262/#eqn-modulo
+ // Note that http://stackoverflow.com/a/4467559/3191 does NOT work for large modulos
+ const signMightNotMatch = x % y;
+ if (sign(y) !== sign(signMightNotMatch)) {
+ return signMightNotMatch + y;
}
-
- function modulo(x, y) {
- // https://tc39.github.io/ecma262/#eqn-modulo
- // Note that http://stackoverflow.com/a/4467559/3191 does NOT work for large modulos
- const signMightNotMatch = x % y;
- if (sign(y) !== sign(signMightNotMatch)) {
- return signMightNotMatch + y;
- }
- return signMightNotMatch;
+ return signMightNotMatch;
+}
+
+function censorNegativeZero(x) {
+ return x === 0 ? 0 : x;
+}
+
+function createIntegerConversion(bitLength, typeOpts) {
+ const isSigned = !typeOpts.unsigned;
+
+ let lowerBound;
+ let upperBound;
+ if (bitLength === 64) {
+ upperBound = NumberMAX_SAFE_INTEGER;
+ lowerBound = !isSigned ? 0 : NumberMIN_SAFE_INTEGER;
+ } else if (!isSigned) {
+ lowerBound = 0;
+ upperBound = MathPow(2, bitLength) - 1;
+ } else {
+ lowerBound = -MathPow(2, bitLength - 1);
+ upperBound = MathPow(2, bitLength - 1) - 1;
}
- function censorNegativeZero(x) {
- return x === 0 ? 0 : x;
- }
+ const twoToTheBitLength = MathPow(2, bitLength);
+ const twoToOneLessThanTheBitLength = MathPow(2, bitLength - 1);
- function createIntegerConversion(bitLength, typeOpts) {
- const isSigned = !typeOpts.unsigned;
-
- let lowerBound;
- let upperBound;
- if (bitLength === 64) {
- upperBound = NumberMAX_SAFE_INTEGER;
- lowerBound = !isSigned ? 0 : NumberMIN_SAFE_INTEGER;
- } else if (!isSigned) {
- lowerBound = 0;
- upperBound = MathPow(2, bitLength) - 1;
- } else {
- lowerBound = -MathPow(2, bitLength - 1);
- upperBound = MathPow(2, bitLength - 1) - 1;
+ return (V, opts = {}) => {
+ let x = toNumber(V);
+ x = censorNegativeZero(x);
+
+ if (opts.enforceRange) {
+ if (!NumberIsFinite(x)) {
+ throw makeException(TypeError, "is not a finite number", opts);
+ }
+
+ x = integerPart(x);
+
+ if (x < lowerBound || x > upperBound) {
+ throw makeException(
+ TypeError,
+ `is outside the accepted range of ${lowerBound} to ${upperBound}, inclusive`,
+ opts,
+ );
+ }
+
+ return x;
}
- const twoToTheBitLength = MathPow(2, bitLength);
- const twoToOneLessThanTheBitLength = MathPow(2, bitLength - 1);
+ if (!NumberIsNaN(x) && opts.clamp) {
+ x = MathMin(MathMax(x, lowerBound), upperBound);
+ x = evenRound(x);
+ return x;
+ }
- return (V, opts = {}) => {
- let x = toNumber(V);
- x = censorNegativeZero(x);
+ if (!NumberIsFinite(x) || x === 0) {
+ return 0;
+ }
+ x = integerPart(x);
- if (opts.enforceRange) {
- if (!NumberIsFinite(x)) {
- throw makeException(TypeError, "is not a finite number", opts);
- }
+ // Math.pow(2, 64) is not accurately representable in JavaScript, so try to avoid these per-spec operations if
+ // possible. Hopefully it's an optimization for the non-64-bitLength cases too.
+ if (x >= lowerBound && x <= upperBound) {
+ return x;
+ }
- x = integerPart(x);
+ // These will not work great for bitLength of 64, but oh well. See the README for more details.
+ x = modulo(x, twoToTheBitLength);
+ if (isSigned && x >= twoToOneLessThanTheBitLength) {
+ return x - twoToTheBitLength;
+ }
+ return x;
+ };
+}
- if (x < lowerBound || x > upperBound) {
- throw makeException(
- TypeError,
- `is outside the accepted range of ${lowerBound} to ${upperBound}, inclusive`,
- opts,
- );
- }
+function createLongLongConversion(bitLength, { unsigned }) {
+ const upperBound = NumberMAX_SAFE_INTEGER;
+ const lowerBound = unsigned ? 0 : NumberMIN_SAFE_INTEGER;
+ const asBigIntN = unsigned ? BigIntAsUintN : BigIntAsIntN;
- return x;
- }
+ return (V, opts = {}) => {
+ let x = toNumber(V);
+ x = censorNegativeZero(x);
- if (!NumberIsNaN(x) && opts.clamp) {
- x = MathMin(MathMax(x, lowerBound), upperBound);
- x = evenRound(x);
- return x;
+ if (opts.enforceRange) {
+ if (!NumberIsFinite(x)) {
+ throw makeException(TypeError, "is not a finite number", opts);
}
- if (!NumberIsFinite(x) || x === 0) {
- return 0;
- }
x = integerPart(x);
- // Math.pow(2, 64) is not accurately representable in JavaScript, so try to avoid these per-spec operations if
- // possible. Hopefully it's an optimization for the non-64-bitLength cases too.
- if (x >= lowerBound && x <= upperBound) {
- return x;
+ if (x < lowerBound || x > upperBound) {
+ throw makeException(
+ TypeError,
+ `is outside the accepted range of ${lowerBound} to ${upperBound}, inclusive`,
+ opts,
+ );
}
- // These will not work great for bitLength of 64, but oh well. See the README for more details.
- x = modulo(x, twoToTheBitLength);
- if (isSigned && x >= twoToOneLessThanTheBitLength) {
- return x - twoToTheBitLength;
- }
return x;
- };
- }
+ }
- function createLongLongConversion(bitLength, { unsigned }) {
- const upperBound = NumberMAX_SAFE_INTEGER;
- const lowerBound = unsigned ? 0 : NumberMIN_SAFE_INTEGER;
- const asBigIntN = unsigned ? BigIntAsUintN : BigIntAsIntN;
+ if (!NumberIsNaN(x) && opts.clamp) {
+ x = MathMin(MathMax(x, lowerBound), upperBound);
+ x = evenRound(x);
+ return x;
+ }
- return (V, opts = {}) => {
- let x = toNumber(V);
- x = censorNegativeZero(x);
+ if (!NumberIsFinite(x) || x === 0) {
+ return 0;
+ }
- if (opts.enforceRange) {
- if (!NumberIsFinite(x)) {
- throw makeException(TypeError, "is not a finite number", opts);
- }
+ let xBigInt = BigInt(integerPart(x));
+ xBigInt = asBigIntN(bitLength, xBigInt);
+ return Number(xBigInt);
+ };
+}
- x = integerPart(x);
+const converters = [];
- if (x < lowerBound || x > upperBound) {
- throw makeException(
- TypeError,
- `is outside the accepted range of ${lowerBound} to ${upperBound}, inclusive`,
- opts,
- );
- }
+converters.any = (V) => {
+ return V;
+};
- return x;
- }
+converters.boolean = function (val) {
+ return !!val;
+};
- if (!NumberIsNaN(x) && opts.clamp) {
- x = MathMin(MathMax(x, lowerBound), upperBound);
- x = evenRound(x);
- return x;
- }
+converters.byte = createIntegerConversion(8, { unsigned: false });
+converters.octet = createIntegerConversion(8, { unsigned: true });
- if (!NumberIsFinite(x) || x === 0) {
- return 0;
- }
+converters.short = createIntegerConversion(16, { unsigned: false });
+converters["unsigned short"] = createIntegerConversion(16, {
+ unsigned: true,
+});
- let xBigInt = BigInt(integerPart(x));
- xBigInt = asBigIntN(bitLength, xBigInt);
- return Number(xBigInt);
- };
+converters.long = createIntegerConversion(32, { unsigned: false });
+converters["unsigned long"] = createIntegerConversion(32, { unsigned: true });
+
+converters["long long"] = createLongLongConversion(64, { unsigned: false });
+converters["unsigned long long"] = createLongLongConversion(64, {
+ unsigned: true,
+});
+
+converters.float = (V, opts) => {
+ const x = toNumber(V);
+
+ if (!NumberIsFinite(x)) {
+ throw makeException(
+ TypeError,
+ "is not a finite floating-point value",
+ opts,
+ );
}
- const converters = [];
+ if (ObjectIs(x, -0)) {
+ return x;
+ }
- converters.any = (V) => {
- return V;
- };
+ const y = MathFround(x);
- converters.boolean = function (val) {
- return !!val;
- };
+ if (!NumberIsFinite(y)) {
+ throw makeException(
+ TypeError,
+ "is outside the range of a single-precision floating-point value",
+ opts,
+ );
+ }
- converters.byte = createIntegerConversion(8, { unsigned: false });
- converters.octet = createIntegerConversion(8, { unsigned: true });
+ return y;
+};
- converters.short = createIntegerConversion(16, { unsigned: false });
- converters["unsigned short"] = createIntegerConversion(16, {
- unsigned: true,
- });
+converters["unrestricted float"] = (V, _opts) => {
+ const x = toNumber(V);
- converters.long = createIntegerConversion(32, { unsigned: false });
- converters["unsigned long"] = createIntegerConversion(32, { unsigned: true });
+ if (isNaN(x)) {
+ return x;
+ }
- converters["long long"] = createLongLongConversion(64, { unsigned: false });
- converters["unsigned long long"] = createLongLongConversion(64, {
- unsigned: true,
- });
+ if (ObjectIs(x, -0)) {
+ return x;
+ }
- converters.float = (V, opts) => {
- const x = toNumber(V);
+ return MathFround(x);
+};
- if (!NumberIsFinite(x)) {
- throw makeException(
- TypeError,
- "is not a finite floating-point value",
- opts,
- );
- }
+converters.double = (V, opts) => {
+ const x = toNumber(V);
- if (ObjectIs(x, -0)) {
- return x;
- }
+ if (!NumberIsFinite(x)) {
+ throw makeException(
+ TypeError,
+ "is not a finite floating-point value",
+ opts,
+ );
+ }
- const y = MathFround(x);
+ return x;
+};
- if (!NumberIsFinite(y)) {
- throw makeException(
- TypeError,
- "is outside the range of a single-precision floating-point value",
- opts,
- );
- }
+converters["unrestricted double"] = (V, _opts) => {
+ const x = toNumber(V);
- return y;
- };
+ return x;
+};
- converters["unrestricted float"] = (V, _opts) => {
- const x = toNumber(V);
+converters.DOMString = function (V, opts = {}) {
+ if (typeof V === "string") {
+ return V;
+ } else if (V === null && opts.treatNullAsEmptyString) {
+ return "";
+ } else if (typeof V === "symbol") {
+ throw makeException(
+ TypeError,
+ "is a symbol, which cannot be converted to a string",
+ opts,
+ );
+ }
- if (isNaN(x)) {
- return x;
- }
+ return String(V);
+};
- if (ObjectIs(x, -0)) {
- return x;
+// deno-lint-ignore no-control-regex
+const IS_BYTE_STRING = /^[\x00-\xFF]*$/;
+converters.ByteString = (V, opts) => {
+ const x = converters.DOMString(V, opts);
+ if (!RegExpPrototypeTest(IS_BYTE_STRING, x)) {
+ throw makeException(TypeError, "is not a valid ByteString", opts);
+ }
+ return x;
+};
+
+converters.USVString = (V, opts) => {
+ const S = converters.DOMString(V, opts);
+ const n = S.length;
+ let U = "";
+ for (let i = 0; i < n; ++i) {
+ const c = StringPrototypeCharCodeAt(S, i);
+ if (c < 0xd800 || c > 0xdfff) {
+ U += StringFromCodePoint(c);
+ } else if (0xdc00 <= c && c <= 0xdfff) {
+ U += StringFromCodePoint(0xfffd);
+ } else if (i === n - 1) {
+ U += StringFromCodePoint(0xfffd);
+ } else {
+ const d = StringPrototypeCharCodeAt(S, i + 1);
+ if (0xdc00 <= d && d <= 0xdfff) {
+ const a = c & 0x3ff;
+ const b = d & 0x3ff;
+ U += StringFromCodePoint((2 << 15) + (2 << 9) * a + b);
+ ++i;
+ } else {
+ U += StringFromCodePoint(0xfffd);
+ }
}
+ }
+ return U;
+};
- return MathFround(x);
- };
+converters.object = (V, opts) => {
+ if (type(V) !== "Object") {
+ throw makeException(TypeError, "is not an object", opts);
+ }
- converters.double = (V, opts) => {
- const x = toNumber(V);
+ return V;
+};
- if (!NumberIsFinite(x)) {
+// Not exported, but used in Function and VoidFunction.
+
+// Neither Function nor VoidFunction is defined with [TreatNonObjectAsNull], so
+// handling for that is omitted.
+function convertCallbackFunction(V, opts) {
+ if (typeof V !== "function") {
+ throw makeException(TypeError, "is not a function", opts);
+ }
+ return V;
+}
+
+function isDataView(V) {
+ return ArrayBufferIsView(V) &&
+ TypedArrayPrototypeGetSymbolToStringTag(V) === undefined;
+}
+
+function isNonSharedArrayBuffer(V) {
+ return ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V);
+}
+
+function isSharedArrayBuffer(V) {
+ // deno-lint-ignore prefer-primordials
+ return ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V);
+}
+
+converters.ArrayBuffer = (V, opts = {}) => {
+ if (!isNonSharedArrayBuffer(V)) {
+ if (opts.allowShared && !isSharedArrayBuffer(V)) {
throw makeException(
TypeError,
- "is not a finite floating-point value",
+ "is not an ArrayBuffer or SharedArrayBuffer",
opts,
);
}
+ throw makeException(TypeError, "is not an ArrayBuffer", opts);
+ }
- return x;
- };
+ return V;
+};
- converters["unrestricted double"] = (V, _opts) => {
- const x = toNumber(V);
+converters.DataView = (V, opts = {}) => {
+ if (!isDataView(V)) {
+ throw makeException(TypeError, "is not a DataView", opts);
+ }
- return x;
- };
+ if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) {
+ throw makeException(
+ TypeError,
+ "is backed by a SharedArrayBuffer, which is not allowed",
+ opts,
+ );
+ }
+
+ return V;
+};
+
+// Returns the unforgeable `TypedArray` constructor name or `undefined`,
+// if the `this` value isn't a valid `TypedArray` object.
+//
+// https://tc39.es/ecma262/#sec-get-%typedarray%.prototype-@@tostringtag
+const typedArrayNameGetter = ObjectGetOwnPropertyDescriptor(
+ ObjectGetPrototypeOf(Uint8Array).prototype,
+ SymbolToStringTag,
+).get;
+ArrayPrototypeForEach(
+ [
+ Int8Array,
+ Int16Array,
+ Int32Array,
+ Uint8Array,
+ Uint16Array,
+ Uint32Array,
+ Uint8ClampedArray,
+ Float32Array,
+ Float64Array,
+ ],
+ (func) => {
+ const name = func.name;
+ const article = RegExpPrototypeTest(/^[AEIOU]/, name) ? "an" : "a";
+ converters[name] = (V, opts = {}) => {
+ if (!ArrayBufferIsView(V) || typedArrayNameGetter.call(V) !== name) {
+ throw makeException(
+ TypeError,
+ `is not ${article} ${name} object`,
+ opts,
+ );
+ }
+ if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) {
+ throw makeException(
+ TypeError,
+ "is a view on a SharedArrayBuffer, which is not allowed",
+ opts,
+ );
+ }
- converters.DOMString = function (V, opts = {}) {
- if (typeof V === "string") {
return V;
- } else if (V === null && opts.treatNullAsEmptyString) {
- return "";
- } else if (typeof V === "symbol") {
+ };
+ },
+);
+
+// Common definitions
+
+converters.ArrayBufferView = (V, opts = {}) => {
+ if (!ArrayBufferIsView(V)) {
+ throw makeException(
+ TypeError,
+ "is not a view on an ArrayBuffer or SharedArrayBuffer",
+ opts,
+ );
+ }
+
+ if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) {
+ throw makeException(
+ TypeError,
+ "is a view on a SharedArrayBuffer, which is not allowed",
+ opts,
+ );
+ }
+
+ return V;
+};
+
+converters.BufferSource = (V, opts = {}) => {
+ if (ArrayBufferIsView(V)) {
+ if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) {
throw makeException(
TypeError,
- "is a symbol, which cannot be converted to a string",
+ "is a view on a SharedArrayBuffer, which is not allowed",
opts,
);
}
- return String(V);
- };
+ return V;
+ }
+
+ if (!opts.allowShared && !isNonSharedArrayBuffer(V)) {
+ throw makeException(
+ TypeError,
+ "is not an ArrayBuffer or a view on one",
+ opts,
+ );
+ }
+ if (
+ opts.allowShared &&
+ !isSharedArrayBuffer(V) &&
+ !isNonSharedArrayBuffer(V)
+ ) {
+ throw makeException(
+ TypeError,
+ "is not an ArrayBuffer, SharedArrayBuffer, or a view on one",
+ opts,
+ );
+ }
- // deno-lint-ignore no-control-regex
- const IS_BYTE_STRING = /^[\x00-\xFF]*$/;
- converters.ByteString = (V, opts) => {
- const x = converters.DOMString(V, opts);
- if (!RegExpPrototypeTest(IS_BYTE_STRING, x)) {
- throw makeException(TypeError, "is not a valid ByteString", opts);
+ return V;
+};
+
+converters.DOMTimeStamp = converters["unsigned long long"];
+converters.DOMHighResTimeStamp = converters["double"];
+
+converters.Function = convertCallbackFunction;
+
+converters.VoidFunction = convertCallbackFunction;
+
+converters["UVString?"] = createNullableConverter(
+ converters.USVString,
+);
+converters["sequence<double>"] = createSequenceConverter(
+ converters.double,
+);
+converters["sequence<object>"] = createSequenceConverter(
+ converters.object,
+);
+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,
+);
+
+converters["sequence<USVString>"] = createSequenceConverter(
+ converters.USVString,
+);
+converters["sequence<sequence<USVString>>"] = createSequenceConverter(
+ converters["sequence<USVString>"],
+);
+converters["record<USVString, USVString>"] = createRecordConverter(
+ converters.USVString,
+ converters.USVString,
+);
+
+converters["sequence<DOMString>"] = createSequenceConverter(
+ converters.DOMString,
+);
+
+function requiredArguments(length, required, opts = {}) {
+ if (length < required) {
+ const errMsg = `${
+ opts.prefix ? opts.prefix + ": " : ""
+ }${required} argument${
+ required === 1 ? "" : "s"
+ } required, but only ${length} present.`;
+ throw new TypeError(errMsg);
+ }
+}
+
+function createDictionaryConverter(name, ...dictionaries) {
+ let hasRequiredKey = false;
+ const allMembers = [];
+ for (let i = 0; i < dictionaries.length; ++i) {
+ const members = dictionaries[i];
+ for (let j = 0; j < members.length; ++j) {
+ const member = members[j];
+ if (member.required) {
+ hasRequiredKey = true;
+ }
+ ArrayPrototypePush(allMembers, member);
}
- return x;
- };
+ }
+ ArrayPrototypeSort(allMembers, (a, b) => {
+ if (a.key == b.key) {
+ return 0;
+ }
+ return a.key < b.key ? -1 : 1;
+ });
- converters.USVString = (V, opts) => {
- const S = converters.DOMString(V, opts);
- const n = S.length;
- let U = "";
- for (let i = 0; i < n; ++i) {
- const c = StringPrototypeCharCodeAt(S, i);
- if (c < 0xd800 || c > 0xdfff) {
- U += StringFromCodePoint(c);
- } else if (0xdc00 <= c && c <= 0xdfff) {
- U += StringFromCodePoint(0xfffd);
- } else if (i === n - 1) {
- U += StringFromCodePoint(0xfffd);
+ const defaultValues = {};
+ for (let i = 0; i < allMembers.length; ++i) {
+ const member = allMembers[i];
+ if (ReflectHas(member, "defaultValue")) {
+ const idlMemberValue = member.defaultValue;
+ const imvType = typeof idlMemberValue;
+ // Copy by value types can be directly assigned, copy by reference types
+ // need to be re-created for each allocation.
+ if (
+ imvType === "number" || imvType === "boolean" ||
+ imvType === "string" || imvType === "bigint" ||
+ imvType === "undefined"
+ ) {
+ defaultValues[member.key] = member.converter(idlMemberValue, {});
} else {
- const d = StringPrototypeCharCodeAt(S, i + 1);
- if (0xdc00 <= d && d <= 0xdfff) {
- const a = c & 0x3ff;
- const b = d & 0x3ff;
- U += StringFromCodePoint((2 << 15) + (2 << 9) * a + b);
- ++i;
- } else {
- U += StringFromCodePoint(0xfffd);
- }
+ ObjectDefineProperty(defaultValues, member.key, {
+ get() {
+ return member.converter(idlMemberValue, member.defaultValue);
+ },
+ enumerable: true,
+ });
}
}
- return U;
- };
+ }
- converters.object = (V, opts) => {
- if (type(V) !== "Object") {
- throw makeException(TypeError, "is not an object", opts);
+ return function (V, opts = {}) {
+ const typeV = type(V);
+ switch (typeV) {
+ case "Undefined":
+ case "Null":
+ case "Object":
+ break;
+ default:
+ throw makeException(
+ TypeError,
+ "can not be converted to a dictionary",
+ opts,
+ );
}
+ const esDict = V;
- return V;
- };
-
- // Not exported, but used in Function and VoidFunction.
+ const idlDict = ObjectAssign({}, defaultValues);
- // Neither Function nor VoidFunction is defined with [TreatNonObjectAsNull], so
- // handling for that is omitted.
- function convertCallbackFunction(V, opts) {
- if (typeof V !== "function") {
- throw makeException(TypeError, "is not a function", opts);
+ // NOTE: fast path Null and Undefined.
+ if ((V === undefined || V === null) && !hasRequiredKey) {
+ return idlDict;
}
- return V;
- }
-
- function isDataView(V) {
- return ArrayBufferIsView(V) &&
- TypedArrayPrototypeGetSymbolToStringTag(V) === undefined;
- }
- function isNonSharedArrayBuffer(V) {
- return ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V);
- }
+ for (let i = 0; i < allMembers.length; ++i) {
+ const member = allMembers[i];
+ const key = member.key;
- function isSharedArrayBuffer(V) {
- // deno-lint-ignore prefer-primordials
- return ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V);
- }
+ let esMemberValue;
+ if (typeV === "Undefined" || typeV === "Null") {
+ esMemberValue = undefined;
+ } else {
+ esMemberValue = esDict[key];
+ }
- converters.ArrayBuffer = (V, opts = {}) => {
- if (!isNonSharedArrayBuffer(V)) {
- if (opts.allowShared && !isSharedArrayBuffer(V)) {
+ if (esMemberValue !== undefined) {
+ const context = `'${key}' of '${name}'${
+ opts.context ? ` (${opts.context})` : ""
+ }`;
+ const converter = member.converter;
+ const idlMemberValue = converter(esMemberValue, { ...opts, context });
+ idlDict[key] = idlMemberValue;
+ } else if (member.required) {
throw makeException(
TypeError,
- "is not an ArrayBuffer or SharedArrayBuffer",
+ `can not be converted to '${name}' because '${key}' is required in '${name}'.`,
opts,
);
}
- throw makeException(TypeError, "is not an ArrayBuffer", opts);
}
- return V;
+ return idlDict;
};
+}
- converters.DataView = (V, opts = {}) => {
- if (!isDataView(V)) {
- throw makeException(TypeError, "is not a DataView", opts);
- }
+// https://heycam.github.io/webidl/#es-enumeration
+function createEnumConverter(name, values) {
+ const E = new Set(values);
- if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) {
- throw makeException(
- TypeError,
- "is backed by a SharedArrayBuffer, which is not allowed",
- opts,
+ return function (V, opts = {}) {
+ const S = String(V);
+
+ if (!E.has(S)) {
+ throw new TypeError(
+ `${
+ opts.prefix ? opts.prefix + ": " : ""
+ }The provided value '${S}' is not a valid enum value of type ${name}.`,
);
}
- return V;
+ return S;
};
+}
+
+function createNullableConverter(converter) {
+ return (V, opts = {}) => {
+ // FIXME: If Type(V) is not Object, and the conversion to an IDL value is
+ // being performed due to V being assigned to an attribute whose type is a
+ // nullable callback function that is annotated with
+ // [LegacyTreatNonObjectAsNull], then return the IDL nullable type T?
+ // value null.
+
+ if (V === null || V === undefined) return null;
+ return converter(V, opts);
+ };
+}
- // Returns the unforgeable `TypedArray` constructor name or `undefined`,
- // if the `this` value isn't a valid `TypedArray` object.
- //
- // https://tc39.es/ecma262/#sec-get-%typedarray%.prototype-@@tostringtag
- const typedArrayNameGetter = ObjectGetOwnPropertyDescriptor(
- ObjectGetPrototypeOf(Uint8Array).prototype,
- SymbolToStringTag,
- ).get;
- ArrayPrototypeForEach(
- [
- Int8Array,
- Int16Array,
- Int32Array,
- Uint8Array,
- Uint16Array,
- Uint32Array,
- Uint8ClampedArray,
- Float32Array,
- Float64Array,
- ],
- (func) => {
- const name = func.name;
- const article = RegExpPrototypeTest(/^[AEIOU]/, name) ? "an" : "a";
- converters[name] = (V, opts = {}) => {
- if (!ArrayBufferIsView(V) || typedArrayNameGetter.call(V) !== name) {
- throw makeException(
- TypeError,
- `is not ${article} ${name} object`,
- opts,
- );
- }
- if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) {
- throw makeException(
- TypeError,
- "is a view on a SharedArrayBuffer, which is not allowed",
- opts,
- );
- }
-
- return V;
- };
- },
- );
-
- // Common definitions
-
- converters.ArrayBufferView = (V, opts = {}) => {
- if (!ArrayBufferIsView(V)) {
+// https://heycam.github.io/webidl/#es-sequence
+function createSequenceConverter(converter) {
+ return function (V, opts = {}) {
+ if (type(V) !== "Object") {
throw makeException(
TypeError,
- "is not a view on an ArrayBuffer or SharedArrayBuffer",
+ "can not be converted to sequence.",
opts,
);
}
-
- if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) {
+ const iter = V?.[SymbolIterator]?.();
+ if (iter === undefined) {
throw makeException(
TypeError,
- "is a view on a SharedArrayBuffer, which is not allowed",
+ "can not be converted to sequence.",
opts,
);
}
-
- return V;
- };
-
- converters.BufferSource = (V, opts = {}) => {
- if (ArrayBufferIsView(V)) {
- if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) {
+ const array = [];
+ while (true) {
+ const res = iter?.next?.();
+ if (res === undefined) {
throw makeException(
TypeError,
- "is a view on a SharedArrayBuffer, which is not allowed",
+ "can not be converted to sequence.",
opts,
);
}
-
- return V;
+ if (res.done === true) break;
+ const val = converter(res.value, {
+ ...opts,
+ context: `${opts.context}, index ${array.length}`,
+ });
+ ArrayPrototypePush(array, val);
}
+ return array;
+ };
+}
- if (!opts.allowShared && !isNonSharedArrayBuffer(V)) {
- throw makeException(
- TypeError,
- "is not an ArrayBuffer or a view on one",
- opts,
- );
- }
- if (
- opts.allowShared &&
- !isSharedArrayBuffer(V) &&
- !isNonSharedArrayBuffer(V)
- ) {
+function createRecordConverter(keyConverter, valueConverter) {
+ return (V, opts) => {
+ if (type(V) !== "Object") {
throw makeException(
TypeError,
- "is not an ArrayBuffer, SharedArrayBuffer, or a view on one",
+ "can not be converted to dictionary.",
opts,
);
}
-
- return V;
- };
-
- converters.DOMTimeStamp = converters["unsigned long long"];
- converters.DOMHighResTimeStamp = converters["double"];
-
- converters.Function = convertCallbackFunction;
-
- converters.VoidFunction = convertCallbackFunction;
-
- converters["UVString?"] = createNullableConverter(
- converters.USVString,
- );
- converters["sequence<double>"] = createSequenceConverter(
- converters.double,
- );
- converters["sequence<object>"] = createSequenceConverter(
- converters.object,
- );
- 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,
- );
-
- converters["sequence<USVString>"] = createSequenceConverter(
- converters.USVString,
- );
- converters["sequence<sequence<USVString>>"] = createSequenceConverter(
- converters["sequence<USVString>"],
- );
- converters["record<USVString, USVString>"] = createRecordConverter(
- converters.USVString,
- converters.USVString,
- );
-
- converters["sequence<DOMString>"] = createSequenceConverter(
- converters.DOMString,
- );
-
- function requiredArguments(length, required, opts = {}) {
- if (length < required) {
- const errMsg = `${
- opts.prefix ? opts.prefix + ": " : ""
- }${required} argument${
- required === 1 ? "" : "s"
- } required, but only ${length} present.`;
- throw new TypeError(errMsg);
- }
- }
-
- function createDictionaryConverter(name, ...dictionaries) {
- let hasRequiredKey = false;
- const allMembers = [];
- for (let i = 0; i < dictionaries.length; ++i) {
- const members = dictionaries[i];
- for (let j = 0; j < members.length; ++j) {
- const member = members[j];
- if (member.required) {
- hasRequiredKey = true;
+ const result = {};
+ // Fast path for common case (not a Proxy)
+ if (!core.isProxy(V)) {
+ for (const key in V) {
+ if (!ObjectPrototypeHasOwnProperty(V, key)) {
+ continue;
}
- ArrayPrototypePush(allMembers, member);
+ const typedKey = keyConverter(key, opts);
+ const value = V[key];
+ const typedValue = valueConverter(value, opts);
+ result[typedKey] = typedValue;
}
+ return result;
}
- ArrayPrototypeSort(allMembers, (a, b) => {
- if (a.key == b.key) {
- return 0;
+ // Slow path if Proxy (e.g: in WPT tests)
+ const keys = ReflectOwnKeys(V);
+ for (let i = 0; i < keys.length; ++i) {
+ const key = keys[i];
+ const desc = ObjectGetOwnPropertyDescriptor(V, key);
+ if (desc !== undefined && desc.enumerable === true) {
+ const typedKey = keyConverter(key, opts);
+ const value = V[key];
+ const typedValue = valueConverter(value, opts);
+ result[typedKey] = typedValue;
}
- return a.key < b.key ? -1 : 1;
+ }
+ return result;
+ };
+}
+
+function createPromiseConverter(converter) {
+ return (V, opts) =>
+ PromisePrototypeThen(PromiseResolve(V), (V) => converter(V, opts));
+}
+
+function invokeCallbackFunction(
+ callable,
+ args,
+ thisArg,
+ returnValueConverter,
+ opts,
+) {
+ try {
+ const rv = ReflectApply(callable, thisArg, args);
+ return returnValueConverter(rv, {
+ prefix: opts.prefix,
+ context: "return value",
});
-
- const defaultValues = {};
- for (let i = 0; i < allMembers.length; ++i) {
- const member = allMembers[i];
- if (ReflectHas(member, "defaultValue")) {
- const idlMemberValue = member.defaultValue;
- const imvType = typeof idlMemberValue;
- // Copy by value types can be directly assigned, copy by reference types
- // need to be re-created for each allocation.
- if (
- imvType === "number" || imvType === "boolean" ||
- imvType === "string" || imvType === "bigint" ||
- imvType === "undefined"
- ) {
- defaultValues[member.key] = member.converter(idlMemberValue, {});
- } else {
- ObjectDefineProperty(defaultValues, member.key, {
- get() {
- return member.converter(idlMemberValue, member.defaultValue);
- },
- enumerable: true,
- });
- }
- }
+ } catch (err) {
+ if (opts.returnsPromise === true) {
+ return PromiseReject(err);
}
+ throw err;
+ }
+}
- return function (V, opts = {}) {
- const typeV = type(V);
- switch (typeV) {
- case "Undefined":
- case "Null":
- case "Object":
- break;
- default:
- throw makeException(
- TypeError,
- "can not be converted to a dictionary",
- opts,
- );
- }
- const esDict = V;
-
- const idlDict = ObjectAssign({}, defaultValues);
-
- // NOTE: fast path Null and Undefined.
- if ((V === undefined || V === null) && !hasRequiredKey) {
- return idlDict;
- }
-
- for (let i = 0; i < allMembers.length; ++i) {
- const member = allMembers[i];
- const key = member.key;
-
- let esMemberValue;
- if (typeV === "Undefined" || typeV === "Null") {
- esMemberValue = undefined;
- } else {
- esMemberValue = esDict[key];
- }
-
- if (esMemberValue !== undefined) {
- const context = `'${key}' of '${name}'${
- opts.context ? ` (${opts.context})` : ""
- }`;
- const converter = member.converter;
- const idlMemberValue = converter(esMemberValue, { ...opts, context });
- idlDict[key] = idlMemberValue;
- } else if (member.required) {
- throw makeException(
- TypeError,
- `can not be converted to '${name}' because '${key}' is required in '${name}'.`,
- opts,
- );
- }
- }
+const brand = Symbol("[[webidl.brand]]");
- return idlDict;
- };
+function createInterfaceConverter(name, prototype) {
+ return (V, opts) => {
+ if (!ObjectPrototypeIsPrototypeOf(prototype, V) || V[brand] !== brand) {
+ throw makeException(TypeError, `is not of type ${name}.`, opts);
+ }
+ return V;
+ };
+}
+
+// TODO(lucacasonato): have the user pass in the prototype, and not the type.
+function createBranded(Type) {
+ const t = ObjectCreate(Type.prototype);
+ t[brand] = brand;
+ return t;
+}
+
+function assertBranded(self, prototype) {
+ if (
+ !ObjectPrototypeIsPrototypeOf(prototype, self) || self[brand] !== brand
+ ) {
+ throw new TypeError("Illegal invocation");
+ }
+}
+
+function illegalConstructor() {
+ throw new TypeError("Illegal constructor");
+}
+
+function define(target, source) {
+ const keys = ReflectOwnKeys(source);
+ for (let i = 0; i < keys.length; ++i) {
+ const key = keys[i];
+ const descriptor = ReflectGetOwnPropertyDescriptor(source, key);
+ if (descriptor && !ReflectDefineProperty(target, key, descriptor)) {
+ throw new TypeError(`Cannot redefine property: ${String(key)}`);
+ }
}
+}
- // https://heycam.github.io/webidl/#es-enumeration
- function createEnumConverter(name, values) {
- const E = new Set(values);
+const _iteratorInternal = Symbol("iterator internal");
- return function (V, opts = {}) {
- const S = String(V);
+const globalIteratorPrototype = ObjectGetPrototypeOf(ArrayIteratorPrototype);
- if (!E.has(S)) {
+function mixinPairIterable(name, prototype, dataSymbol, keyKey, valueKey) {
+ const iteratorPrototype = ObjectCreate(globalIteratorPrototype, {
+ [SymbolToStringTag]: { configurable: true, value: `${name} Iterator` },
+ });
+ define(iteratorPrototype, {
+ next() {
+ const internal = this && this[_iteratorInternal];
+ if (!internal) {
throw new TypeError(
- `${
- opts.prefix ? opts.prefix + ": " : ""
- }The provided value '${S}' is not a valid enum value of type ${name}.`,
+ `next() called on a value that is not a ${name} iterator object`,
);
}
-
- return S;
- };
+ const { target, kind, index } = internal;
+ const values = target[dataSymbol];
+ const len = values.length;
+ if (index >= len) {
+ return { value: undefined, done: true };
+ }
+ const pair = values[index];
+ internal.index = index + 1;
+ let result;
+ switch (kind) {
+ case "key":
+ result = pair[keyKey];
+ break;
+ case "value":
+ result = pair[valueKey];
+ break;
+ case "key+value":
+ result = [pair[keyKey], pair[valueKey]];
+ break;
+ }
+ return { value: result, done: false };
+ },
+ });
+ function createDefaultIterator(target, kind) {
+ const iterator = ObjectCreate(iteratorPrototype);
+ ObjectDefineProperty(iterator, _iteratorInternal, {
+ value: { target, kind, index: 0 },
+ configurable: true,
+ });
+ return iterator;
}
- function createNullableConverter(converter) {
- return (V, opts = {}) => {
- // FIXME: If Type(V) is not Object, and the conversion to an IDL value is
- // being performed due to V being assigned to an attribute whose type is a
- // nullable callback function that is annotated with
- // [LegacyTreatNonObjectAsNull], then return the IDL nullable type T?
- // value null.
-
- if (V === null || V === undefined) return null;
- return converter(V, opts);
- };
+ function entries() {
+ assertBranded(this, prototype.prototype);
+ return createDefaultIterator(this, "key+value");
}
- // https://heycam.github.io/webidl/#es-sequence
- function createSequenceConverter(converter) {
- return function (V, opts = {}) {
- if (type(V) !== "Object") {
- throw makeException(
- TypeError,
- "can not be converted to sequence.",
- opts,
- );
- }
- const iter = V?.[SymbolIterator]?.();
- if (iter === undefined) {
- throw makeException(
- TypeError,
- "can not be converted to sequence.",
- opts,
- );
- }
- const array = [];
- while (true) {
- const res = iter?.next?.();
- if (res === undefined) {
- throw makeException(
- TypeError,
- "can not be converted to sequence.",
- opts,
- );
- }
- if (res.done === true) break;
- const val = converter(res.value, {
- ...opts,
- context: `${opts.context}, index ${array.length}`,
+ const properties = {
+ entries: {
+ value: entries,
+ writable: true,
+ enumerable: true,
+ configurable: true,
+ },
+ [SymbolIterator]: {
+ value: entries,
+ writable: true,
+ enumerable: false,
+ configurable: true,
+ },
+ keys: {
+ value: function keys() {
+ assertBranded(this, prototype.prototype);
+ return createDefaultIterator(this, "key");
+ },
+ writable: true,
+ enumerable: true,
+ configurable: true,
+ },
+ values: {
+ value: function values() {
+ assertBranded(this, prototype.prototype);
+ return createDefaultIterator(this, "value");
+ },
+ writable: true,
+ enumerable: true,
+ configurable: true,
+ },
+ forEach: {
+ value: function forEach(idlCallback, thisArg = undefined) {
+ assertBranded(this, prototype.prototype);
+ const prefix = `Failed to execute 'forEach' on '${name}'`;
+ requiredArguments(arguments.length, 1, { prefix });
+ idlCallback = converters["Function"](idlCallback, {
+ prefix,
+ context: "Argument 1",
});
- ArrayPrototypePush(array, val);
- }
- return array;
- };
- }
-
- function createRecordConverter(keyConverter, valueConverter) {
- return (V, opts) => {
- if (type(V) !== "Object") {
- throw makeException(
- TypeError,
- "can not be converted to dictionary.",
- opts,
+ idlCallback = FunctionPrototypeBind(
+ idlCallback,
+ thisArg ?? globalThis,
);
- }
- const result = {};
- // Fast path for common case (not a Proxy)
- if (!core.isProxy(V)) {
- for (const key in V) {
- if (!ObjectPrototypeHasOwnProperty(V, key)) {
- continue;
- }
- const typedKey = keyConverter(key, opts);
- const value = V[key];
- const typedValue = valueConverter(value, opts);
- result[typedKey] = typedValue;
+ const pairs = this[dataSymbol];
+ for (let i = 0; i < pairs.length; i++) {
+ const entry = pairs[i];
+ idlCallback(entry[valueKey], entry[keyKey], this);
}
- return result;
- }
- // Slow path if Proxy (e.g: in WPT tests)
- const keys = ReflectOwnKeys(V);
- for (let i = 0; i < keys.length; ++i) {
- const key = keys[i];
- const desc = ObjectGetOwnPropertyDescriptor(V, key);
- if (desc !== undefined && desc.enumerable === true) {
- const typedKey = keyConverter(key, opts);
- const value = V[key];
- const typedValue = valueConverter(value, opts);
- result[typedKey] = typedValue;
- }
- }
- return result;
- };
- }
-
- function createPromiseConverter(converter) {
- return (V, opts) =>
- PromisePrototypeThen(PromiseResolve(V), (V) => converter(V, opts));
- }
-
- function invokeCallbackFunction(
- callable,
- args,
- thisArg,
- returnValueConverter,
- opts,
- ) {
- try {
- const rv = ReflectApply(callable, thisArg, args);
- return returnValueConverter(rv, {
- prefix: opts.prefix,
- context: "return value",
- });
- } catch (err) {
- if (opts.returnsPromise === true) {
- return PromiseReject(err);
- }
- throw err;
+ },
+ writable: true,
+ enumerable: true,
+ configurable: true,
+ },
+ };
+ return ObjectDefineProperties(prototype.prototype, properties);
+}
+
+function configurePrototype(prototype) {
+ const descriptors = ObjectGetOwnPropertyDescriptors(prototype.prototype);
+ for (const key in descriptors) {
+ if (!ObjectPrototypeHasOwnProperty(descriptors, key)) {
+ continue;
}
- }
-
- const brand = Symbol("[[webidl.brand]]");
-
- function createInterfaceConverter(name, prototype) {
- return (V, opts) => {
- if (!ObjectPrototypeIsPrototypeOf(prototype, V) || V[brand] !== brand) {
- throw makeException(TypeError, `is not of type ${name}.`, opts);
- }
- return V;
- };
- }
-
- // TODO(lucacasonato): have the user pass in the prototype, and not the type.
- function createBranded(Type) {
- const t = ObjectCreate(Type.prototype);
- t[brand] = brand;
- return t;
- }
-
- function assertBranded(self, prototype) {
+ if (key === "constructor") continue;
+ const descriptor = descriptors[key];
if (
- !ObjectPrototypeIsPrototypeOf(prototype, self) || self[brand] !== brand
+ ReflectHas(descriptor, "value") &&
+ typeof descriptor.value === "function"
) {
- throw new TypeError("Illegal invocation");
- }
- }
-
- function illegalConstructor() {
- throw new TypeError("Illegal constructor");
- }
-
- function define(target, source) {
- const keys = ReflectOwnKeys(source);
- for (let i = 0; i < keys.length; ++i) {
- const key = keys[i];
- const descriptor = ReflectGetOwnPropertyDescriptor(source, key);
- if (descriptor && !ReflectDefineProperty(target, key, descriptor)) {
- throw new TypeError(`Cannot redefine property: ${String(key)}`);
- }
- }
- }
-
- const _iteratorInternal = Symbol("iterator internal");
-
- const globalIteratorPrototype = ObjectGetPrototypeOf(ArrayIteratorPrototype);
-
- function mixinPairIterable(name, prototype, dataSymbol, keyKey, valueKey) {
- const iteratorPrototype = ObjectCreate(globalIteratorPrototype, {
- [SymbolToStringTag]: { configurable: true, value: `${name} Iterator` },
- });
- define(iteratorPrototype, {
- next() {
- const internal = this && this[_iteratorInternal];
- if (!internal) {
- throw new TypeError(
- `next() called on a value that is not a ${name} iterator object`,
- );
- }
- const { target, kind, index } = internal;
- const values = target[dataSymbol];
- const len = values.length;
- if (index >= len) {
- return { value: undefined, done: true };
- }
- const pair = values[index];
- internal.index = index + 1;
- let result;
- switch (kind) {
- case "key":
- result = pair[keyKey];
- break;
- case "value":
- result = pair[valueKey];
- break;
- case "key+value":
- result = [pair[keyKey], pair[valueKey]];
- break;
- }
- return { value: result, done: false };
- },
- });
- function createDefaultIterator(target, kind) {
- const iterator = ObjectCreate(iteratorPrototype);
- ObjectDefineProperty(iterator, _iteratorInternal, {
- value: { target, kind, index: 0 },
+ ObjectDefineProperty(prototype.prototype, key, {
+ enumerable: true,
+ writable: true,
+ configurable: true,
+ });
+ } else if (ReflectHas(descriptor, "get")) {
+ ObjectDefineProperty(prototype.prototype, key, {
+ enumerable: true,
configurable: true,
});
- return iterator;
}
+ }
+ ObjectDefineProperty(prototype.prototype, SymbolToStringTag, {
+ value: prototype.name,
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ });
+}
- function entries() {
- assertBranded(this, prototype.prototype);
- return createDefaultIterator(this, "key+value");
- }
+const setlikeInner = Symbol("[[set]]");
- const properties = {
- entries: {
- value: entries,
- writable: true,
- enumerable: true,
- configurable: true,
+// Ref: https://webidl.spec.whatwg.org/#es-setlike
+function setlike(obj, objPrototype, readonly) {
+ ObjectDefineProperties(obj, {
+ size: {
+ configurable: true,
+ enumerable: true,
+ get() {
+ assertBranded(this, objPrototype);
+ return obj[setlikeInner].size;
},
- [SymbolIterator]: {
- value: entries,
- writable: true,
- enumerable: false,
- configurable: true,
+ },
+ [SymbolIterator]: {
+ configurable: true,
+ enumerable: false,
+ writable: true,
+ value() {
+ assertBranded(this, objPrototype);
+ return obj[setlikeInner][SymbolIterator]();
},
- keys: {
- value: function keys() {
- assertBranded(this, prototype.prototype);
- return createDefaultIterator(this, "key");
- },
- writable: true,
- enumerable: true,
- configurable: true,
+ },
+ entries: {
+ configurable: true,
+ enumerable: true,
+ writable: true,
+ value() {
+ assertBranded(this, objPrototype);
+ return SetPrototypeEntries(obj[setlikeInner]);
},
- values: {
- value: function values() {
- assertBranded(this, prototype.prototype);
- return createDefaultIterator(this, "value");
- },
- writable: true,
- enumerable: true,
- configurable: true,
+ },
+ keys: {
+ configurable: true,
+ enumerable: true,
+ writable: true,
+ value() {
+ assertBranded(this, objPrototype);
+ return SetPrototypeKeys(obj[setlikeInner]);
},
- forEach: {
- value: function forEach(idlCallback, thisArg = undefined) {
- assertBranded(this, prototype.prototype);
- const prefix = `Failed to execute 'forEach' on '${name}'`;
- requiredArguments(arguments.length, 1, { prefix });
- idlCallback = converters["Function"](idlCallback, {
- prefix,
- context: "Argument 1",
- });
- idlCallback = FunctionPrototypeBind(
- idlCallback,
- 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,
+ },
+ values: {
+ configurable: true,
+ enumerable: true,
+ writable: true,
+ value() {
+ assertBranded(this, objPrototype);
+ return SetPrototypeValues(obj[setlikeInner]);
},
- };
- return ObjectDefineProperties(prototype.prototype, properties);
- }
-
- function configurePrototype(prototype) {
- const descriptors = ObjectGetOwnPropertyDescriptors(prototype.prototype);
- for (const key in descriptors) {
- if (!ObjectPrototypeHasOwnProperty(descriptors, key)) {
- continue;
- }
- if (key === "constructor") continue;
- const descriptor = descriptors[key];
- if (
- ReflectHas(descriptor, "value") &&
- typeof descriptor.value === "function"
- ) {
- ObjectDefineProperty(prototype.prototype, key, {
- enumerable: true,
- writable: true,
- configurable: true,
- });
- } else if (ReflectHas(descriptor, "get")) {
- ObjectDefineProperty(prototype.prototype, key, {
- enumerable: true,
- configurable: true,
- });
- }
- }
- ObjectDefineProperty(prototype.prototype, SymbolToStringTag, {
- value: prototype.name,
- enumerable: false,
+ },
+ forEach: {
configurable: true,
- writable: false,
- });
- }
-
- const setlikeInner = Symbol("[[set]]");
-
- // Ref: https://webidl.spec.whatwg.org/#es-setlike
- function setlike(obj, objPrototype, readonly) {
- ObjectDefineProperties(obj, {
- size: {
- configurable: true,
- enumerable: true,
- get() {
- assertBranded(this, objPrototype);
- return obj[setlikeInner].size;
- },
+ enumerable: true,
+ writable: true,
+ value(callbackfn, thisArg) {
+ assertBranded(this, objPrototype);
+ return SetPrototypeForEach(obj[setlikeInner], callbackfn, thisArg);
},
- [SymbolIterator]: {
- configurable: true,
- enumerable: false,
- writable: true,
- value() {
- assertBranded(this, objPrototype);
- return obj[setlikeInner][SymbolIterator]();
- },
+ },
+ has: {
+ configurable: true,
+ enumerable: true,
+ writable: true,
+ value(value) {
+ assertBranded(this, objPrototype);
+ return SetPrototypeHas(obj[setlikeInner], value);
},
- entries: {
+ },
+ });
+
+ if (!readonly) {
+ ObjectDefineProperties(obj, {
+ add: {
configurable: true,
enumerable: true,
writable: true,
- value() {
+ value(value) {
assertBranded(this, objPrototype);
- return SetPrototypeEntries(obj[setlikeInner]);
+ return SetPrototypeAdd(obj[setlikeInner], value);
},
},
- keys: {
+ delete: {
configurable: true,
enumerable: true,
writable: true,
- value() {
+ value(value) {
assertBranded(this, objPrototype);
- return SetPrototypeKeys(obj[setlikeInner]);
+ return SetPrototypeDelete(obj[setlikeInner], value);
},
},
- values: {
+ clear: {
configurable: true,
enumerable: true,
writable: true,
value() {
assertBranded(this, objPrototype);
- return SetPrototypeValues(obj[setlikeInner]);
- },
- },
- forEach: {
- configurable: true,
- enumerable: true,
- writable: true,
- value(callbackfn, thisArg) {
- assertBranded(this, objPrototype);
- return SetPrototypeForEach(obj[setlikeInner], callbackfn, thisArg);
- },
- },
- has: {
- configurable: true,
- enumerable: true,
- writable: true,
- value(value) {
- assertBranded(this, objPrototype);
- return SetPrototypeHas(obj[setlikeInner], value);
+ return SetPrototypeClear(obj[setlikeInner]);
},
},
});
-
- if (!readonly) {
- ObjectDefineProperties(obj, {
- add: {
- configurable: true,
- enumerable: true,
- writable: true,
- value(value) {
- assertBranded(this, objPrototype);
- return SetPrototypeAdd(obj[setlikeInner], value);
- },
- },
- delete: {
- configurable: true,
- enumerable: true,
- writable: true,
- value(value) {
- assertBranded(this, objPrototype);
- return SetPrototypeDelete(obj[setlikeInner], value);
- },
- },
- clear: {
- configurable: true,
- enumerable: true,
- writable: true,
- value() {
- assertBranded(this, objPrototype);
- return SetPrototypeClear(obj[setlikeInner]);
- },
- },
- });
- }
}
-
- window.__bootstrap ??= {};
- window.__bootstrap.webidl = {
- type,
- makeException,
- converters,
- requiredArguments,
- createDictionaryConverter,
- createEnumConverter,
- createNullableConverter,
- createSequenceConverter,
- createRecordConverter,
- createPromiseConverter,
- invokeCallbackFunction,
- createInterfaceConverter,
- brand,
- createBranded,
- assertBranded,
- illegalConstructor,
- mixinPairIterable,
- configurePrototype,
- setlike,
- setlikeInner,
- };
-})(this);
+}
+
+export {
+ assertBranded,
+ brand,
+ configurePrototype,
+ converters,
+ createBranded,
+ createDictionaryConverter,
+ createEnumConverter,
+ createInterfaceConverter,
+ createNullableConverter,
+ createPromiseConverter,
+ createRecordConverter,
+ createSequenceConverter,
+ illegalConstructor,
+ invokeCallbackFunction,
+ makeException,
+ mixinPairIterable,
+ requiredArguments,
+ setlike,
+ setlikeInner,
+ type,
+};
diff --git a/ext/webidl/benches/dict.js b/ext/webidl/benches/dict.js
index 353a630eb..b53326de9 100644
--- a/ext/webidl/benches/dict.js
+++ b/ext/webidl/benches/dict.js
@@ -2,7 +2,10 @@
// deno-lint-ignore-file
-const { createDictionaryConverter, converters } = globalThis.__bootstrap.webidl;
+import {
+ converters,
+ createDictionaryConverter,
+} from "internal:ext/webidl/00_webidl.js";
const TextDecodeOptions = createDictionaryConverter(
"TextDecodeOptions",
@@ -14,6 +17,7 @@ const TextDecodeOptions = createDictionaryConverter(
},
],
);
+globalThis.TextDecodeOptions = TextDecodeOptions;
// Sanity check
{
@@ -33,3 +37,4 @@ function handwrittenConverter(V) {
}
return defaultValue;
}
+globalThis.handwrittenConverter = handwrittenConverter;
diff --git a/ext/webidl/benches/dict.rs b/ext/webidl/benches/dict.rs
index e7df8af62..1400a00ed 100644
--- a/ext/webidl/benches/dict.rs
+++ b/ext/webidl/benches/dict.rs
@@ -11,7 +11,7 @@ fn setup() -> Vec<Extension> {
vec![
deno_webidl::init(),
Extension::builder("deno_webidl_bench")
- .js(vec![("setup", include_str!("dict.js"))])
+ .esm(vec![("internal:setup", include_str!("dict.js"))])
.build(),
]
}
diff --git a/ext/webidl/internal.d.ts b/ext/webidl/internal.d.ts
index 4ab9e33a9..9f47c42e5 100644
--- a/ext/webidl/internal.d.ts
+++ b/ext/webidl/internal.d.ts
@@ -4,338 +4,334 @@
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
-declare namespace globalThis {
- declare namespace __bootstrap {
- declare namespace webidl {
- declare interface ConverterOpts {
- /**
- * The prefix for error messages created by this converter.
- * Examples:
- * - `Failed to construct 'Event'`
- * - `Failed to execute 'removeEventListener' on 'EventTarget'`
- */
- prefix: string;
- }
- declare interface ValueConverterOpts extends ConverterOpts {
- /**
- * The context of this value error messages created by this converter.
- * Examples:
- * - `Argument 1`
- * - `Argument 3`
- */
- context: string;
- }
- declare function makeException(
- ErrorType: any,
- message: string,
- opts: ValueConverterOpts,
- ): any;
- declare interface IntConverterOpts extends ValueConverterOpts {
- /**
- * Wether to throw if the number is outside of the acceptable values for
- * this type.
- */
- enforceRange?: boolean;
- /**
- * Wether to clamp this number to the acceptable values for this type.
- */
- clamp?: boolean;
- }
- declare interface StringConverterOpts extends ValueConverterOpts {
- /**
- * Wether to treat `null` value as an empty string.
- */
- treatNullAsEmptyString?: boolean;
- }
- declare interface BufferConverterOpts extends ValueConverterOpts {
- /**
- * Wether to allow `SharedArrayBuffer` (not just `ArrayBuffer`).
- */
- allowShared?: boolean;
- }
- declare const converters: {
- any(v: any): any;
- /**
- * Convert a value into a `boolean` (bool).
- */
- boolean(v: any, opts?: IntConverterOpts): boolean;
- /**
- * Convert a value into a `byte` (int8).
- */
- byte(v: any, opts?: IntConverterOpts): number;
- /**
- * Convert a value into a `octet` (uint8).
- */
- octet(v: any, opts?: IntConverterOpts): number;
- /**
- * Convert a value into a `short` (int16).
- */
- short(v: any, opts?: IntConverterOpts): number;
- /**
- * Convert a value into a `unsigned short` (uint16).
- */
- ["unsigned short"](v: any, opts?: IntConverterOpts): number;
- /**
- * Convert a value into a `long` (int32).
- */
- long(v: any, opts?: IntConverterOpts): number;
- /**
- * Convert a value into a `unsigned long` (uint32).
- */
- ["unsigned long"](v: any, opts?: IntConverterOpts): number;
- /**
- * Convert a value into a `long long` (int64).
- * **Note this is truncated to a JS number (53 bit precision).**
- */
- ["long long"](v: any, opts?: IntConverterOpts): number;
- /**
- * Convert a value into a `unsigned long long` (uint64).
- * **Note this is truncated to a JS number (53 bit precision).**
- */
- ["unsigned long long"](v: any, opts?: IntConverterOpts): number;
- /**
- * Convert a value into a `float` (f32).
- */
- float(v: any, opts?: ValueConverterOpts): number;
- /**
- * Convert a value into a `unrestricted float` (f32, infinity, or NaN).
- */
- ["unrestricted float"](v: any, opts?: ValueConverterOpts): number;
- /**
- * Convert a value into a `double` (f64).
- */
- double(v: any, opts?: ValueConverterOpts): number;
- /**
- * Convert a value into a `unrestricted double` (f64, infinity, or NaN).
- */
- ["unrestricted double"](v: any, opts?: ValueConverterOpts): number;
- /**
- * Convert a value into a `DOMString` (string).
- */
- DOMString(v: any, opts?: StringConverterOpts): string;
- /**
- * Convert a value into a `ByteString` (string with only u8 codepoints).
- */
- ByteString(v: any, opts?: StringConverterOpts): string;
- /**
- * Convert a value into a `USVString` (string with only valid non
- * surrogate Unicode code points).
- */
- USVString(v: any, opts?: StringConverterOpts): string;
- /**
- * Convert a value into an `object` (object).
- */
- object(v: any, opts?: ValueConverterOpts): object;
- /**
- * Convert a value into an `ArrayBuffer` (ArrayBuffer).
- */
- ArrayBuffer(v: any, opts?: BufferConverterOpts): ArrayBuffer;
- /**
- * Convert a value into a `DataView` (ArrayBuffer).
- */
- DataView(v: any, opts?: BufferConverterOpts): DataView;
- /**
- * Convert a value into a `Int8Array` (Int8Array).
- */
- Int8Array(v: any, opts?: BufferConverterOpts): Int8Array;
- /**
- * Convert a value into a `Int16Array` (Int16Array).
- */
- Int16Array(v: any, opts?: BufferConverterOpts): Int16Array;
- /**
- * Convert a value into a `Int32Array` (Int32Array).
- */
- Int32Array(v: any, opts?: BufferConverterOpts): Int32Array;
- /**
- * Convert a value into a `Uint8Array` (Uint8Array).
- */
- Uint8Array(v: any, opts?: BufferConverterOpts): Uint8Array;
- /**
- * Convert a value into a `Uint16Array` (Uint16Array).
- */
- Uint16Array(v: any, opts?: BufferConverterOpts): Uint16Array;
- /**
- * Convert a value into a `Uint32Array` (Uint32Array).
- */
- Uint32Array(v: any, opts?: BufferConverterOpts): Uint32Array;
- /**
- * Convert a value into a `Uint8ClampedArray` (Uint8ClampedArray).
- */
- Uint8ClampedArray(
- v: any,
- opts?: BufferConverterOpts,
- ): Uint8ClampedArray;
- /**
- * Convert a value into a `Float32Array` (Float32Array).
- */
- Float32Array(v: any, opts?: BufferConverterOpts): Float32Array;
- /**
- * Convert a value into a `Float64Array` (Float64Array).
- */
- Float64Array(v: any, opts?: BufferConverterOpts): Float64Array;
- /**
- * Convert a value into an `ArrayBufferView` (ArrayBufferView).
- */
- ArrayBufferView(v: any, opts?: BufferConverterOpts): ArrayBufferView;
- /**
- * Convert a value into a `BufferSource` (ArrayBuffer or ArrayBufferView).
- */
- BufferSource(
- v: any,
- opts?: BufferConverterOpts,
- ): ArrayBuffer | ArrayBufferView;
- /**
- * Convert a value into a `DOMTimeStamp` (u64). Alias for unsigned long long
- */
- DOMTimeStamp(v: any, opts?: IntConverterOpts): number;
- /**
- * Convert a value into a `Function` ((...args: any[]) => any).
- */
- Function(v: any, opts?: ValueConverterOpts): (...args: any) => any;
- /**
- * Convert a value into a `VoidFunction` (() => void).
- */
- VoidFunction(v: any, opts?: ValueConverterOpts): () => void;
- ["UVString?"](v: any, opts?: ValueConverterOpts): string | null;
- ["sequence<double>"](v: any, opts?: ValueConverterOpts): number[];
+declare module "internal:ext/webidl/00_webidl.js" {
+ interface ConverterOpts {
+ /**
+ * The prefix for error messages created by this converter.
+ * Examples:
+ * - `Failed to construct 'Event'`
+ * - `Failed to execute 'removeEventListener' on 'EventTarget'`
+ */
+ prefix: string;
+ }
+ interface ValueConverterOpts extends ConverterOpts {
+ /**
+ * The context of this value error messages created by this converter.
+ * Examples:
+ * - `Argument 1`
+ * - `Argument 3`
+ */
+ context: string;
+ }
+ function makeException(
+ ErrorType: any,
+ message: string,
+ opts: ValueConverterOpts,
+ ): any;
+ interface IntConverterOpts extends ValueConverterOpts {
+ /**
+ * Wether to throw if the number is outside of the acceptable values for
+ * this type.
+ */
+ enforceRange?: boolean;
+ /**
+ * Wether to clamp this number to the acceptable values for this type.
+ */
+ clamp?: boolean;
+ }
+ interface StringConverterOpts extends ValueConverterOpts {
+ /**
+ * Wether to treat `null` value as an empty string.
+ */
+ treatNullAsEmptyString?: boolean;
+ }
+ interface BufferConverterOpts extends ValueConverterOpts {
+ /**
+ * Wether to allow `SharedArrayBuffer` (not just `ArrayBuffer`).
+ */
+ allowShared?: boolean;
+ }
+ const converters: {
+ any(v: any): any;
+ /**
+ * Convert a value into a `boolean` (bool).
+ */
+ boolean(v: any, opts?: IntConverterOpts): boolean;
+ /**
+ * Convert a value into a `byte` (int8).
+ */
+ byte(v: any, opts?: IntConverterOpts): number;
+ /**
+ * Convert a value into a `octet` (uint8).
+ */
+ octet(v: any, opts?: IntConverterOpts): number;
+ /**
+ * Convert a value into a `short` (int16).
+ */
+ short(v: any, opts?: IntConverterOpts): number;
+ /**
+ * Convert a value into a `unsigned short` (uint16).
+ */
+ ["unsigned short"](v: any, opts?: IntConverterOpts): number;
+ /**
+ * Convert a value into a `long` (int32).
+ */
+ long(v: any, opts?: IntConverterOpts): number;
+ /**
+ * Convert a value into a `unsigned long` (uint32).
+ */
+ ["unsigned long"](v: any, opts?: IntConverterOpts): number;
+ /**
+ * Convert a value into a `long long` (int64).
+ * **Note this is truncated to a JS number (53 bit precision).**
+ */
+ ["long long"](v: any, opts?: IntConverterOpts): number;
+ /**
+ * Convert a value into a `unsigned long long` (uint64).
+ * **Note this is truncated to a JS number (53 bit precision).**
+ */
+ ["unsigned long long"](v: any, opts?: IntConverterOpts): number;
+ /**
+ * Convert a value into a `float` (f32).
+ */
+ float(v: any, opts?: ValueConverterOpts): number;
+ /**
+ * Convert a value into a `unrestricted float` (f32, infinity, or NaN).
+ */
+ ["unrestricted float"](v: any, opts?: ValueConverterOpts): number;
+ /**
+ * Convert a value into a `double` (f64).
+ */
+ double(v: any, opts?: ValueConverterOpts): number;
+ /**
+ * Convert a value into a `unrestricted double` (f64, infinity, or NaN).
+ */
+ ["unrestricted double"](v: any, opts?: ValueConverterOpts): number;
+ /**
+ * Convert a value into a `DOMString` (string).
+ */
+ DOMString(v: any, opts?: StringConverterOpts): string;
+ /**
+ * Convert a value into a `ByteString` (string with only u8 codepoints).
+ */
+ ByteString(v: any, opts?: StringConverterOpts): string;
+ /**
+ * Convert a value into a `USVString` (string with only valid non
+ * surrogate Unicode code points).
+ */
+ USVString(v: any, opts?: StringConverterOpts): string;
+ /**
+ * Convert a value into an `object` (object).
+ */
+ object(v: any, opts?: ValueConverterOpts): object;
+ /**
+ * Convert a value into an `ArrayBuffer` (ArrayBuffer).
+ */
+ ArrayBuffer(v: any, opts?: BufferConverterOpts): ArrayBuffer;
+ /**
+ * Convert a value into a `DataView` (ArrayBuffer).
+ */
+ DataView(v: any, opts?: BufferConverterOpts): DataView;
+ /**
+ * Convert a value into a `Int8Array` (Int8Array).
+ */
+ Int8Array(v: any, opts?: BufferConverterOpts): Int8Array;
+ /**
+ * Convert a value into a `Int16Array` (Int16Array).
+ */
+ Int16Array(v: any, opts?: BufferConverterOpts): Int16Array;
+ /**
+ * Convert a value into a `Int32Array` (Int32Array).
+ */
+ Int32Array(v: any, opts?: BufferConverterOpts): Int32Array;
+ /**
+ * Convert a value into a `Uint8Array` (Uint8Array).
+ */
+ Uint8Array(v: any, opts?: BufferConverterOpts): Uint8Array;
+ /**
+ * Convert a value into a `Uint16Array` (Uint16Array).
+ */
+ Uint16Array(v: any, opts?: BufferConverterOpts): Uint16Array;
+ /**
+ * Convert a value into a `Uint32Array` (Uint32Array).
+ */
+ Uint32Array(v: any, opts?: BufferConverterOpts): Uint32Array;
+ /**
+ * Convert a value into a `Uint8ClampedArray` (Uint8ClampedArray).
+ */
+ Uint8ClampedArray(
+ v: any,
+ opts?: BufferConverterOpts,
+ ): Uint8ClampedArray;
+ /**
+ * Convert a value into a `Float32Array` (Float32Array).
+ */
+ Float32Array(v: any, opts?: BufferConverterOpts): Float32Array;
+ /**
+ * Convert a value into a `Float64Array` (Float64Array).
+ */
+ Float64Array(v: any, opts?: BufferConverterOpts): Float64Array;
+ /**
+ * Convert a value into an `ArrayBufferView` (ArrayBufferView).
+ */
+ ArrayBufferView(v: any, opts?: BufferConverterOpts): ArrayBufferView;
+ /**
+ * Convert a value into a `BufferSource` (ArrayBuffer or ArrayBufferView).
+ */
+ BufferSource(
+ v: any,
+ opts?: BufferConverterOpts,
+ ): ArrayBuffer | ArrayBufferView;
+ /**
+ * Convert a value into a `DOMTimeStamp` (u64). Alias for unsigned long long
+ */
+ DOMTimeStamp(v: any, opts?: IntConverterOpts): number;
+ /**
+ * Convert a value into a `Function` ((...args: any[]) => any).
+ */
+ Function(v: any, opts?: ValueConverterOpts): (...args: any) => any;
+ /**
+ * Convert a value into a `VoidFunction` (() => void).
+ */
+ VoidFunction(v: any, opts?: ValueConverterOpts): () => void;
+ ["UVString?"](v: any, opts?: ValueConverterOpts): string | null;
+ ["sequence<double>"](v: any, opts?: ValueConverterOpts): number[];
- [type: string]: (v: any, opts: ValueConverterOpts) => any;
- };
+ [type: string]: (v: any, opts: ValueConverterOpts) => any;
+ };
- /**
- * Assert that the a function has at least a required amount of arguments.
- */
- declare function requiredArguments(
- length: number,
- required: number,
- opts: ConverterOpts,
- ): void;
- declare type Dictionary = DictionaryMember[];
- declare interface DictionaryMember {
- key: string;
- converter: (v: any, opts: ValueConverterOpts) => any;
- defaultValue?: any;
- required?: boolean;
- }
+ /**
+ * Assert that the a function has at least a required amount of arguments.
+ */
+ function requiredArguments(
+ length: number,
+ required: number,
+ opts: ConverterOpts,
+ ): void;
+ type Dictionary = DictionaryMember[];
+ interface DictionaryMember {
+ key: string;
+ converter: (v: any, opts: ValueConverterOpts) => any;
+ defaultValue?: any;
+ required?: boolean;
+ }
- /**
- * Create a converter for dictionaries.
- */
- declare function createDictionaryConverter<T>(
- name: string,
- ...dictionaries: Dictionary[]
- ): (v: any, opts: ValueConverterOpts) => T;
+ /**
+ * Create a converter for dictionaries.
+ */
+ function createDictionaryConverter<T>(
+ name: string,
+ ...dictionaries: Dictionary[]
+ ): (v: any, opts: ValueConverterOpts) => T;
- /**
- * Create a converter for enums.
- */
- declare function createEnumConverter(
- name: string,
- values: string[],
- ): (v: any, opts: ValueConverterOpts) => string;
+ /**
+ * Create a converter for enums.
+ */
+ function createEnumConverter(
+ name: string,
+ values: string[],
+ ): (v: any, opts: ValueConverterOpts) => string;
- /**
- * Create a converter that makes the contained type nullable.
- */
- declare function createNullableConverter<T>(
- converter: (v: any, opts: ValueConverterOpts) => T,
- ): (v: any, opts: ValueConverterOpts) => T | null;
+ /**
+ * Create a converter that makes the contained type nullable.
+ */
+ function createNullableConverter<T>(
+ converter: (v: any, opts: ValueConverterOpts) => T,
+ ): (v: any, opts: ValueConverterOpts) => T | null;
- /**
- * Create a converter that converts a sequence of the inner type.
- */
- declare function createSequenceConverter<T>(
- converter: (v: any, opts: ValueConverterOpts) => T,
- ): (v: any, opts: ValueConverterOpts) => T[];
+ /**
+ * Create a converter that converts a sequence of the inner type.
+ */
+ function createSequenceConverter<T>(
+ converter: (v: any, opts: ValueConverterOpts) => T,
+ ): (v: any, opts: ValueConverterOpts) => T[];
- /**
- * Create a converter that converts a Promise of the inner type.
- */
- declare function createPromiseConverter<T>(
- converter: (v: any, opts: ValueConverterOpts) => T,
- ): (v: any, opts: ValueConverterOpts) => Promise<T>;
+ /**
+ * Create a converter that converts a Promise of the inner type.
+ */
+ function createPromiseConverter<T>(
+ converter: (v: any, opts: ValueConverterOpts) => T,
+ ): (v: any, opts: ValueConverterOpts) => Promise<T>;
- /**
- * Invoke a callback function.
- */
- declare function invokeCallbackFunction<T>(
- callable: (...args: any) => any,
- args: any[],
- thisArg: any,
- returnValueConverter: (v: any, opts: ValueConverterOpts) => T,
- opts: ConverterOpts & { returnsPromise?: boolean },
- ): T;
+ /**
+ * Invoke a callback function.
+ */
+ function invokeCallbackFunction<T>(
+ callable: (...args: any) => any,
+ args: any[],
+ thisArg: any,
+ returnValueConverter: (v: any, opts: ValueConverterOpts) => T,
+ opts: ConverterOpts & { returnsPromise?: boolean },
+ ): T;
- /**
- * Throw an illegal constructor error.
- */
- declare function illegalConstructor(): never;
+ /**
+ * Throw an illegal constructor error.
+ */
+ function illegalConstructor(): never;
- /**
- * The branding symbol.
- */
- declare const brand: unique symbol;
+ /**
+ * The branding symbol.
+ */
+ const brand: unique symbol;
- /**
- * Create a branded instance of an interface.
- */
- declare function createBranded(self: any): any;
+ /**
+ * Create a branded instance of an interface.
+ */
+ function createBranded(self: any): any;
- /**
- * Assert that self is branded.
- */
- declare function assertBranded(self: any, type: any): void;
+ /**
+ * Assert that self is branded.
+ */
+ function assertBranded(self: any, type: any): void;
- /**
- * Create a converter for interfaces.
- */
- declare function createInterfaceConverter(
- name: string,
- prototype: any,
- ): (v: any, opts: ValueConverterOpts) => any;
+ /**
+ * Create a converter for interfaces.
+ */
+ function createInterfaceConverter(
+ name: string,
+ prototype: any,
+ ): (v: any, opts: ValueConverterOpts) => any;
- declare function createRecordConverter<
- K extends string | number | symbol,
- V,
- >(
- keyConverter: (v: any, opts: ValueConverterOpts) => K,
- valueConverter: (v: any, opts: ValueConverterOpts) => V,
- ): (
- v: Record<K, V>,
- opts: ValueConverterOpts,
- ) => any;
+ function createRecordConverter<
+ K extends string | number | symbol,
+ V,
+ >(
+ keyConverter: (v: any, opts: ValueConverterOpts) => K,
+ valueConverter: (v: any, opts: ValueConverterOpts) => V,
+ ): (
+ v: Record<K, V>,
+ opts: ValueConverterOpts,
+ ) => any;
- /**
- * Mix in the iterable declarations defined in WebIDL.
- * https://heycam.github.io/webidl/#es-iterable
- */
- declare function mixinPairIterable(
- name: string,
- prototype: any,
- dataSymbol: symbol,
- keyKey: string | number | symbol,
- valueKey: string | number | symbol,
- ): void;
+ /**
+ * Mix in the iterable declarations defined in WebIDL.
+ * https://heycam.github.io/webidl/#es-iterable
+ */
+ function mixinPairIterable(
+ name: string,
+ prototype: any,
+ dataSymbol: symbol,
+ keyKey: string | number | symbol,
+ valueKey: string | number | symbol,
+ ): void;
- /**
- * Configure prototype properties enumerability / writability / configurability.
- */
- declare function configurePrototype(prototype: any);
+ /**
+ * Configure prototype properties enumerability / writability / configurability.
+ */
+ function configurePrototype(prototype: any);
- /**
- * Get the WebIDL / ES type of a value.
- */
- declare function type(
- v: any,
- ):
- | "Null"
- | "Undefined"
- | "Boolean"
- | "Number"
- | "String"
- | "Symbol"
- | "BigInt"
- | "Object";
- }
- }
+ /**
+ * Get the WebIDL / ES type of a value.
+ */
+ function type(
+ v: any,
+ ):
+ | "Null"
+ | "Undefined"
+ | "Boolean"
+ | "Number"
+ | "String"
+ | "Symbol"
+ | "BigInt"
+ | "Object";
}
diff --git a/ext/webidl/lib.rs b/ext/webidl/lib.rs
index ae25f04c7..4e21ef796 100644
--- a/ext/webidl/lib.rs
+++ b/ext/webidl/lib.rs
@@ -6,7 +6,7 @@ use deno_core::Extension;
/// Load and execute the javascript code.
pub fn init() -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/webidl",
"00_webidl.js",
))
diff --git a/ext/websocket/01_websocket.js b/ext/websocket/01_websocket.js
index 9b7c45e70..305cf75a7 100644
--- a/ext/websocket/01_websocket.js
+++ b/ext/websocket/01_websocket.js
@@ -1,579 +1,576 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
/// <reference path="../../core/internal.d.ts" />
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const { URL } = window.__bootstrap.url;
- const webidl = window.__bootstrap.webidl;
- const { HTTP_TOKEN_CODE_POINT_RE } = window.__bootstrap.infra;
- const { DOMException } = window.__bootstrap.domException;
- const {
- Event,
- ErrorEvent,
- CloseEvent,
- MessageEvent,
- defineEventHandler,
- _skipInternalInit,
- } = window.__bootstrap.event;
- const { EventTarget } = window.__bootstrap.eventTarget;
- const { Blob, BlobPrototype } = globalThis.__bootstrap.file;
- const {
- ArrayBufferPrototype,
- ArrayBufferIsView,
- ArrayPrototypeJoin,
- ArrayPrototypeMap,
- ArrayPrototypeSome,
- DataView,
- ErrorPrototypeToString,
- ObjectDefineProperties,
- ObjectPrototypeIsPrototypeOf,
- PromisePrototypeThen,
- RegExpPrototypeTest,
- Set,
- // TODO(lucacasonato): add SharedArrayBuffer to primordials
- // SharedArrayBufferPrototype
- String,
- StringPrototypeEndsWith,
- StringPrototypeToLowerCase,
- Symbol,
- SymbolIterator,
- PromisePrototypeCatch,
- SymbolFor,
- } = window.__bootstrap.primordials;
-
- webidl.converters["sequence<DOMString> or DOMString"] = (V, opts) => {
- // Union for (sequence<DOMString> or DOMString)
- if (webidl.type(V) === "Object" && V !== null) {
- if (V[SymbolIterator] !== undefined) {
- return webidl.converters["sequence<DOMString>"](V, opts);
- }
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import { URL } from "internal:ext/url/00_url.js";
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { HTTP_TOKEN_CODE_POINT_RE } from "internal:ext/web/00_infra.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+import {
+ _skipInternalInit,
+ CloseEvent,
+ defineEventHandler,
+ ErrorEvent,
+ Event,
+ EventTarget,
+ MessageEvent,
+} from "internal:ext/web/02_event.js";
+import { Blob, BlobPrototype } from "internal:ext/web/09_file.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayBufferPrototype,
+ ArrayBufferIsView,
+ ArrayPrototypeJoin,
+ ArrayPrototypeMap,
+ ArrayPrototypeSome,
+ DataView,
+ ErrorPrototypeToString,
+ ObjectDefineProperties,
+ ObjectPrototypeIsPrototypeOf,
+ PromisePrototypeThen,
+ RegExpPrototypeTest,
+ Set,
+ // TODO(lucacasonato): add SharedArrayBuffer to primordials
+ // SharedArrayBufferPrototype
+ String,
+ StringPrototypeEndsWith,
+ StringPrototypeToLowerCase,
+ Symbol,
+ SymbolIterator,
+ PromisePrototypeCatch,
+ SymbolFor,
+} = primordials;
+
+webidl.converters["sequence<DOMString> or DOMString"] = (V, opts) => {
+ // Union for (sequence<DOMString> or DOMString)
+ if (webidl.type(V) === "Object" && V !== null) {
+ if (V[SymbolIterator] !== undefined) {
+ return webidl.converters["sequence<DOMString>"](V, opts);
}
- return webidl.converters.DOMString(V, opts);
- };
+ }
+ return webidl.converters.DOMString(V, opts);
+};
- webidl.converters["WebSocketSend"] = (V, opts) => {
- // Union for (Blob or ArrayBufferView or ArrayBuffer or USVString)
- if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) {
- return webidl.converters["Blob"](V, opts);
- }
- if (typeof V === "object") {
- if (
- ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V) ||
- // deno-lint-ignore prefer-primordials
- ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V)
- ) {
- return webidl.converters["ArrayBuffer"](V, opts);
- }
- if (ArrayBufferIsView(V)) {
- return webidl.converters["ArrayBufferView"](V, opts);
- }
+webidl.converters["WebSocketSend"] = (V, opts) => {
+ // Union for (Blob or ArrayBufferView or ArrayBuffer or USVString)
+ if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) {
+ return webidl.converters["Blob"](V, opts);
+ }
+ if (typeof V === "object") {
+ if (
+ ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V) ||
+ // deno-lint-ignore prefer-primordials
+ ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V)
+ ) {
+ return webidl.converters["ArrayBuffer"](V, opts);
}
- return webidl.converters["USVString"](V, opts);
- };
-
- const CONNECTING = 0;
- const OPEN = 1;
- const CLOSING = 2;
- const CLOSED = 3;
-
- const _readyState = Symbol("[[readyState]]");
- const _url = Symbol("[[url]]");
- const _rid = Symbol("[[rid]]");
- const _extensions = Symbol("[[extensions]]");
- const _protocol = Symbol("[[protocol]]");
- const _binaryType = Symbol("[[binaryType]]");
- const _bufferedAmount = Symbol("[[bufferedAmount]]");
- const _eventLoop = Symbol("[[eventLoop]]");
-
- const _server = Symbol("[[server]]");
- const _idleTimeoutDuration = Symbol("[[idleTimeout]]");
- const _idleTimeoutTimeout = Symbol("[[idleTimeoutTimeout]]");
- const _serverHandleIdleTimeout = Symbol("[[serverHandleIdleTimeout]]");
- class WebSocket extends EventTarget {
- [_rid];
-
- [_readyState] = CONNECTING;
- get readyState() {
- webidl.assertBranded(this, WebSocketPrototype);
- return this[_readyState];
+ if (ArrayBufferIsView(V)) {
+ return webidl.converters["ArrayBufferView"](V, opts);
}
+ }
+ return webidl.converters["USVString"](V, opts);
+};
+
+const CONNECTING = 0;
+const OPEN = 1;
+const CLOSING = 2;
+const CLOSED = 3;
+
+const _readyState = Symbol("[[readyState]]");
+const _url = Symbol("[[url]]");
+const _rid = Symbol("[[rid]]");
+const _extensions = Symbol("[[extensions]]");
+const _protocol = Symbol("[[protocol]]");
+const _binaryType = Symbol("[[binaryType]]");
+const _bufferedAmount = Symbol("[[bufferedAmount]]");
+const _eventLoop = Symbol("[[eventLoop]]");
+
+const _server = Symbol("[[server]]");
+const _idleTimeoutDuration = Symbol("[[idleTimeout]]");
+const _idleTimeoutTimeout = Symbol("[[idleTimeoutTimeout]]");
+const _serverHandleIdleTimeout = Symbol("[[serverHandleIdleTimeout]]");
+class WebSocket extends EventTarget {
+ [_rid];
+
+ [_readyState] = CONNECTING;
+ get readyState() {
+ webidl.assertBranded(this, WebSocketPrototype);
+ return this[_readyState];
+ }
- get CONNECTING() {
- webidl.assertBranded(this, WebSocketPrototype);
- return CONNECTING;
- }
- get OPEN() {
- webidl.assertBranded(this, WebSocketPrototype);
- return OPEN;
- }
- get CLOSING() {
- webidl.assertBranded(this, WebSocketPrototype);
- return CLOSING;
- }
- get CLOSED() {
- webidl.assertBranded(this, WebSocketPrototype);
- return CLOSED;
- }
+ get CONNECTING() {
+ webidl.assertBranded(this, WebSocketPrototype);
+ return CONNECTING;
+ }
+ get OPEN() {
+ webidl.assertBranded(this, WebSocketPrototype);
+ return OPEN;
+ }
+ get CLOSING() {
+ webidl.assertBranded(this, WebSocketPrototype);
+ return CLOSING;
+ }
+ get CLOSED() {
+ webidl.assertBranded(this, WebSocketPrototype);
+ return CLOSED;
+ }
+
+ [_extensions] = "";
+ get extensions() {
+ webidl.assertBranded(this, WebSocketPrototype);
+ return this[_extensions];
+ }
- [_extensions] = "";
- get extensions() {
- webidl.assertBranded(this, WebSocketPrototype);
- return this[_extensions];
+ [_protocol] = "";
+ get protocol() {
+ webidl.assertBranded(this, WebSocketPrototype);
+ return this[_protocol];
+ }
+
+ [_url] = "";
+ get url() {
+ webidl.assertBranded(this, WebSocketPrototype);
+ return this[_url];
+ }
+
+ [_binaryType] = "blob";
+ get binaryType() {
+ webidl.assertBranded(this, WebSocketPrototype);
+ return this[_binaryType];
+ }
+ set binaryType(value) {
+ webidl.assertBranded(this, WebSocketPrototype);
+ value = webidl.converters.DOMString(value, {
+ prefix: "Failed to set 'binaryType' on 'WebSocket'",
+ });
+ if (value === "blob" || value === "arraybuffer") {
+ this[_binaryType] = value;
}
+ }
+
+ [_bufferedAmount] = 0;
+ get bufferedAmount() {
+ webidl.assertBranded(this, WebSocketPrototype);
+ return this[_bufferedAmount];
+ }
+
+ constructor(url, protocols = []) {
+ super();
+ this[webidl.brand] = webidl.brand;
+ const prefix = "Failed to construct 'WebSocket'";
+ webidl.requiredArguments(arguments.length, 1, {
+ prefix,
+ });
+ url = webidl.converters.USVString(url, {
+ prefix,
+ context: "Argument 1",
+ });
+ protocols = webidl.converters["sequence<DOMString> or DOMString"](
+ protocols,
+ {
+ prefix,
+ context: "Argument 2",
+ },
+ );
- [_protocol] = "";
- get protocol() {
- webidl.assertBranded(this, WebSocketPrototype);
- return this[_protocol];
+ let wsURL;
+
+ try {
+ wsURL = new URL(url);
+ } catch (e) {
+ throw new DOMException(e.message, "SyntaxError");
}
- [_url] = "";
- get url() {
- webidl.assertBranded(this, WebSocketPrototype);
- return this[_url];
+ if (wsURL.protocol !== "ws:" && wsURL.protocol !== "wss:") {
+ throw new DOMException(
+ "Only ws & wss schemes are allowed in a WebSocket URL.",
+ "SyntaxError",
+ );
}
- [_binaryType] = "blob";
- get binaryType() {
- webidl.assertBranded(this, WebSocketPrototype);
- return this[_binaryType];
+ if (wsURL.hash !== "" || StringPrototypeEndsWith(wsURL.href, "#")) {
+ throw new DOMException(
+ "Fragments are not allowed in a WebSocket URL.",
+ "SyntaxError",
+ );
}
- set binaryType(value) {
- webidl.assertBranded(this, WebSocketPrototype);
- value = webidl.converters.DOMString(value, {
- prefix: "Failed to set 'binaryType' on 'WebSocket'",
- });
- if (value === "blob" || value === "arraybuffer") {
- this[_binaryType] = value;
- }
+
+ this[_url] = wsURL.href;
+
+ ops.op_ws_check_permission_and_cancel_handle(
+ "WebSocket.abort()",
+ this[_url],
+ false,
+ );
+
+ if (typeof protocols === "string") {
+ protocols = [protocols];
}
- [_bufferedAmount] = 0;
- get bufferedAmount() {
- webidl.assertBranded(this, WebSocketPrototype);
- return this[_bufferedAmount];
+ if (
+ protocols.length !==
+ new Set(
+ ArrayPrototypeMap(protocols, (p) => StringPrototypeToLowerCase(p)),
+ ).size
+ ) {
+ throw new DOMException(
+ "Can't supply multiple times the same protocol.",
+ "SyntaxError",
+ );
}
- constructor(url, protocols = []) {
- super();
- this[webidl.brand] = webidl.brand;
- const prefix = "Failed to construct 'WebSocket'";
- webidl.requiredArguments(arguments.length, 1, {
- prefix,
- });
- url = webidl.converters.USVString(url, {
- prefix,
- context: "Argument 1",
- });
- protocols = webidl.converters["sequence<DOMString> or DOMString"](
+ if (
+ ArrayPrototypeSome(
protocols,
- {
- prefix,
- context: "Argument 2",
- },
+ (protocol) => !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, protocol),
+ )
+ ) {
+ throw new DOMException(
+ "Invalid protocol value.",
+ "SyntaxError",
);
+ }
- let wsURL;
-
- try {
- wsURL = new URL(url);
- } catch (e) {
- throw new DOMException(e.message, "SyntaxError");
- }
+ PromisePrototypeThen(
+ core.opAsync(
+ "op_ws_create",
+ "new WebSocket()",
+ wsURL.href,
+ ArrayPrototypeJoin(protocols, ", "),
+ ),
+ (create) => {
+ this[_rid] = create.rid;
+ this[_extensions] = create.extensions;
+ this[_protocol] = create.protocol;
+
+ if (this[_readyState] === CLOSING) {
+ PromisePrototypeThen(
+ core.opAsync("op_ws_close", this[_rid]),
+ () => {
+ this[_readyState] = CLOSED;
+
+ const errEvent = new ErrorEvent("error");
+ this.dispatchEvent(errEvent);
+
+ const event = new CloseEvent("close");
+ this.dispatchEvent(event);
+ core.tryClose(this[_rid]);
+ },
+ );
+ } else {
+ this[_readyState] = OPEN;
+ const event = new Event("open");
+ this.dispatchEvent(event);
- if (wsURL.protocol !== "ws:" && wsURL.protocol !== "wss:") {
- throw new DOMException(
- "Only ws & wss schemes are allowed in a WebSocket URL.",
- "SyntaxError",
- );
- }
+ this[_eventLoop]();
+ }
+ },
+ (err) => {
+ this[_readyState] = CLOSED;
- if (wsURL.hash !== "" || StringPrototypeEndsWith(wsURL.href, "#")) {
- throw new DOMException(
- "Fragments are not allowed in a WebSocket URL.",
- "SyntaxError",
+ const errorEv = new ErrorEvent(
+ "error",
+ { error: err, message: ErrorPrototypeToString(err) },
);
- }
-
- this[_url] = wsURL.href;
+ this.dispatchEvent(errorEv);
- ops.op_ws_check_permission_and_cancel_handle(
- "WebSocket.abort()",
- this[_url],
- false,
- );
+ const closeEv = new CloseEvent("close");
+ this.dispatchEvent(closeEv);
+ },
+ );
+ }
- if (typeof protocols === "string") {
- protocols = [protocols];
- }
+ send(data) {
+ webidl.assertBranded(this, WebSocketPrototype);
+ const prefix = "Failed to execute 'send' on 'WebSocket'";
- if (
- protocols.length !==
- new Set(
- ArrayPrototypeMap(protocols, (p) => StringPrototypeToLowerCase(p)),
- ).size
- ) {
- throw new DOMException(
- "Can't supply multiple times the same protocol.",
- "SyntaxError",
- );
- }
+ webidl.requiredArguments(arguments.length, 1, {
+ prefix,
+ });
+ data = webidl.converters.WebSocketSend(data, {
+ prefix,
+ context: "Argument 1",
+ });
- if (
- ArrayPrototypeSome(
- protocols,
- (protocol) =>
- !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, protocol),
- )
- ) {
- throw new DOMException(
- "Invalid protocol value.",
- "SyntaxError",
- );
- }
+ if (this[_readyState] !== OPEN) {
+ throw new DOMException("readyState not OPEN", "InvalidStateError");
+ }
+ const sendTypedArray = (ta) => {
+ this[_bufferedAmount] += ta.byteLength;
PromisePrototypeThen(
- core.opAsync(
- "op_ws_create",
- "new WebSocket()",
- wsURL.href,
- ArrayPrototypeJoin(protocols, ", "),
- ),
- (create) => {
- this[_rid] = create.rid;
- this[_extensions] = create.extensions;
- this[_protocol] = create.protocol;
-
- if (this[_readyState] === CLOSING) {
- PromisePrototypeThen(
- core.opAsync("op_ws_close", this[_rid]),
- () => {
- this[_readyState] = CLOSED;
-
- const errEvent = new ErrorEvent("error");
- this.dispatchEvent(errEvent);
-
- const event = new CloseEvent("close");
- this.dispatchEvent(event);
- core.tryClose(this[_rid]);
- },
- );
- } else {
- this[_readyState] = OPEN;
- const event = new Event("open");
- this.dispatchEvent(event);
-
- this[_eventLoop]();
- }
+ core.opAsync("op_ws_send", this[_rid], {
+ kind: "binary",
+ value: ta,
+ }),
+ () => {
+ this[_bufferedAmount] -= ta.byteLength;
},
- (err) => {
- this[_readyState] = CLOSED;
-
- const errorEv = new ErrorEvent(
- "error",
- { error: err, message: ErrorPrototypeToString(err) },
- );
- this.dispatchEvent(errorEv);
+ );
+ };
- const closeEv = new CloseEvent("close");
- this.dispatchEvent(closeEv);
+ if (ObjectPrototypeIsPrototypeOf(BlobPrototype, data)) {
+ PromisePrototypeThen(
+ data.slice().arrayBuffer(),
+ (ab) => sendTypedArray(new DataView(ab)),
+ );
+ } else if (ArrayBufferIsView(data)) {
+ sendTypedArray(data);
+ } else if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, data)) {
+ sendTypedArray(new DataView(data));
+ } else {
+ const string = String(data);
+ const d = core.encode(string);
+ this[_bufferedAmount] += d.byteLength;
+ PromisePrototypeThen(
+ core.opAsync("op_ws_send", this[_rid], {
+ kind: "text",
+ value: string,
+ }),
+ () => {
+ this[_bufferedAmount] -= d.byteLength;
},
);
}
+ }
- send(data) {
- webidl.assertBranded(this, WebSocketPrototype);
- const prefix = "Failed to execute 'send' on 'WebSocket'";
+ close(code = undefined, reason = undefined) {
+ webidl.assertBranded(this, WebSocketPrototype);
+ const prefix = "Failed to execute 'close' on 'WebSocket'";
- webidl.requiredArguments(arguments.length, 1, {
- prefix,
- });
- data = webidl.converters.WebSocketSend(data, {
+ if (code !== undefined) {
+ code = webidl.converters["unsigned short"](code, {
prefix,
+ clamp: true,
context: "Argument 1",
});
+ }
- if (this[_readyState] !== OPEN) {
- throw new DOMException("readyState not OPEN", "InvalidStateError");
- }
-
- const sendTypedArray = (ta) => {
- this[_bufferedAmount] += ta.byteLength;
- PromisePrototypeThen(
- core.opAsync("op_ws_send", this[_rid], {
- kind: "binary",
- value: ta,
- }),
- () => {
- this[_bufferedAmount] -= ta.byteLength;
- },
- );
- };
+ if (reason !== undefined) {
+ reason = webidl.converters.USVString(reason, {
+ prefix,
+ context: "Argument 2",
+ });
+ }
- if (ObjectPrototypeIsPrototypeOf(BlobPrototype, data)) {
- PromisePrototypeThen(
- data.slice().arrayBuffer(),
- (ab) => sendTypedArray(new DataView(ab)),
- );
- } else if (ArrayBufferIsView(data)) {
- sendTypedArray(data);
- } else if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, data)) {
- sendTypedArray(new DataView(data));
- } else {
- const string = String(data);
- const d = core.encode(string);
- this[_bufferedAmount] += d.byteLength;
- PromisePrototypeThen(
- core.opAsync("op_ws_send", this[_rid], {
- kind: "text",
- value: string,
- }),
- () => {
- this[_bufferedAmount] -= d.byteLength;
- },
+ if (!this[_server]) {
+ if (
+ code !== undefined &&
+ !(code === 1000 || (3000 <= code && code < 5000))
+ ) {
+ throw new DOMException(
+ "The close code must be either 1000 or in the range of 3000 to 4999.",
+ "InvalidAccessError",
);
}
}
- close(code = undefined, reason = undefined) {
- webidl.assertBranded(this, WebSocketPrototype);
- const prefix = "Failed to execute 'close' on 'WebSocket'";
-
- if (code !== undefined) {
- code = webidl.converters["unsigned short"](code, {
- prefix,
- clamp: true,
- context: "Argument 1",
- });
- }
+ if (reason !== undefined && core.encode(reason).byteLength > 123) {
+ throw new DOMException(
+ "The close reason may not be longer than 123 bytes.",
+ "SyntaxError",
+ );
+ }
- if (reason !== undefined) {
- reason = webidl.converters.USVString(reason, {
- prefix,
- context: "Argument 2",
- });
- }
+ if (this[_readyState] === CONNECTING) {
+ this[_readyState] = CLOSING;
+ } else if (this[_readyState] === OPEN) {
+ this[_readyState] = CLOSING;
- if (!this[_server]) {
- if (
- code !== undefined &&
- !(code === 1000 || (3000 <= code && code < 5000))
- ) {
- throw new DOMException(
- "The close code must be either 1000 or in the range of 3000 to 4999.",
- "InvalidAccessError",
- );
- }
- }
+ PromisePrototypeCatch(
+ core.opAsync("op_ws_close", this[_rid], code, reason),
+ (err) => {
+ this[_readyState] = CLOSED;
- if (reason !== undefined && core.encode(reason).byteLength > 123) {
- throw new DOMException(
- "The close reason may not be longer than 123 bytes.",
- "SyntaxError",
- );
- }
+ const errorEv = new ErrorEvent("error", {
+ error: err,
+ message: ErrorPrototypeToString(err),
+ });
+ this.dispatchEvent(errorEv);
- if (this[_readyState] === CONNECTING) {
- this[_readyState] = CLOSING;
- } else if (this[_readyState] === OPEN) {
- this[_readyState] = CLOSING;
-
- PromisePrototypeCatch(
- core.opAsync("op_ws_close", this[_rid], code, reason),
- (err) => {
- this[_readyState] = CLOSED;
-
- const errorEv = new ErrorEvent("error", {
- error: err,
- message: ErrorPrototypeToString(err),
- });
- this.dispatchEvent(errorEv);
-
- const closeEv = new CloseEvent("close");
- this.dispatchEvent(closeEv);
- core.tryClose(this[_rid]);
- },
- );
- }
+ const closeEv = new CloseEvent("close");
+ this.dispatchEvent(closeEv);
+ core.tryClose(this[_rid]);
+ },
+ );
}
+ }
- async [_eventLoop]() {
- while (this[_readyState] !== CLOSED) {
- const { kind, value } = await core.opAsync(
- "op_ws_next_event",
- this[_rid],
- );
+ async [_eventLoop]() {
+ while (this[_readyState] !== CLOSED) {
+ const { kind, value } = await core.opAsync(
+ "op_ws_next_event",
+ this[_rid],
+ );
+
+ switch (kind) {
+ case "string": {
+ this[_serverHandleIdleTimeout]();
+ const event = new MessageEvent("message", {
+ data: value,
+ origin: this[_url],
+ });
+ this.dispatchEvent(event);
+ break;
+ }
+ case "binary": {
+ this[_serverHandleIdleTimeout]();
+ let data;
- switch (kind) {
- case "string": {
- this[_serverHandleIdleTimeout]();
- const event = new MessageEvent("message", {
- data: value,
- origin: this[_url],
- });
- this.dispatchEvent(event);
- break;
+ if (this.binaryType === "blob") {
+ data = new Blob([value]);
+ } else {
+ data = value.buffer;
}
- case "binary": {
- this[_serverHandleIdleTimeout]();
- let data;
- if (this.binaryType === "blob") {
- data = new Blob([value]);
- } else {
- data = value.buffer;
+ const event = new MessageEvent("message", {
+ data,
+ origin: this[_url],
+ [_skipInternalInit]: true,
+ });
+ this.dispatchEvent(event);
+ break;
+ }
+ case "ping": {
+ core.opAsync("op_ws_send", this[_rid], {
+ kind: "pong",
+ });
+ break;
+ }
+ case "pong": {
+ this[_serverHandleIdleTimeout]();
+ break;
+ }
+ case "closed":
+ case "close": {
+ const prevState = this[_readyState];
+ this[_readyState] = CLOSED;
+ clearTimeout(this[_idleTimeoutTimeout]);
+
+ if (prevState === OPEN) {
+ try {
+ await core.opAsync(
+ "op_ws_close",
+ this[_rid],
+ value.code,
+ value.reason,
+ );
+ } catch {
+ // ignore failures
}
-
- const event = new MessageEvent("message", {
- data,
- origin: this[_url],
- [_skipInternalInit]: true,
- });
- this.dispatchEvent(event);
- break;
- }
- case "ping": {
- core.opAsync("op_ws_send", this[_rid], {
- kind: "pong",
- });
- break;
}
- case "pong": {
- this[_serverHandleIdleTimeout]();
- break;
- }
- case "closed":
- case "close": {
- const prevState = this[_readyState];
- this[_readyState] = CLOSED;
- clearTimeout(this[_idleTimeoutTimeout]);
-
- if (prevState === OPEN) {
- try {
- await core.opAsync(
- "op_ws_close",
- this[_rid],
- value.code,
- value.reason,
- );
- } catch {
- // ignore failures
- }
- }
- const event = new CloseEvent("close", {
- wasClean: true,
- code: value.code,
- reason: value.reason,
- });
- this.dispatchEvent(event);
- core.tryClose(this[_rid]);
- break;
- }
- case "error": {
- this[_readyState] = CLOSED;
-
- const errorEv = new ErrorEvent("error", {
- message: value,
- });
- this.dispatchEvent(errorEv);
-
- const closeEv = new CloseEvent("close");
- this.dispatchEvent(closeEv);
- core.tryClose(this[_rid]);
- break;
- }
+ const event = new CloseEvent("close", {
+ wasClean: true,
+ code: value.code,
+ reason: value.reason,
+ });
+ this.dispatchEvent(event);
+ core.tryClose(this[_rid]);
+ break;
}
- }
- }
+ case "error": {
+ this[_readyState] = CLOSED;
- [_serverHandleIdleTimeout]() {
- if (this[_idleTimeoutDuration]) {
- clearTimeout(this[_idleTimeoutTimeout]);
- this[_idleTimeoutTimeout] = setTimeout(async () => {
- if (this[_readyState] === OPEN) {
- await core.opAsync("op_ws_send", this[_rid], {
- kind: "ping",
- });
- this[_idleTimeoutTimeout] = setTimeout(async () => {
- if (this[_readyState] === OPEN) {
- this[_readyState] = CLOSING;
- const reason = "No response from ping frame.";
- await core.opAsync("op_ws_close", this[_rid], 1001, reason);
- this[_readyState] = CLOSED;
-
- const errEvent = new ErrorEvent("error", {
- message: reason,
- });
- this.dispatchEvent(errEvent);
-
- const event = new CloseEvent("close", {
- wasClean: false,
- code: 1001,
- reason,
- });
- this.dispatchEvent(event);
- core.tryClose(this[_rid]);
- } else {
- clearTimeout(this[_idleTimeoutTimeout]);
- }
- }, (this[_idleTimeoutDuration] / 2) * 1000);
- } else {
- clearTimeout(this[_idleTimeoutTimeout]);
- }
- }, (this[_idleTimeoutDuration] / 2) * 1000);
+ const errorEv = new ErrorEvent("error", {
+ message: value,
+ });
+ this.dispatchEvent(errorEv);
+
+ const closeEv = new CloseEvent("close");
+ this.dispatchEvent(closeEv);
+ core.tryClose(this[_rid]);
+ break;
+ }
}
}
+ }
- [SymbolFor("Deno.customInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- url: this.url,
- readyState: this.readyState,
- extensions: this.extensions,
- protocol: this.protocol,
- binaryType: this.binaryType,
- bufferedAmount: this.bufferedAmount,
- })
- }`;
+ [_serverHandleIdleTimeout]() {
+ if (this[_idleTimeoutDuration]) {
+ clearTimeout(this[_idleTimeoutTimeout]);
+ this[_idleTimeoutTimeout] = setTimeout(async () => {
+ if (this[_readyState] === OPEN) {
+ await core.opAsync("op_ws_send", this[_rid], {
+ kind: "ping",
+ });
+ this[_idleTimeoutTimeout] = setTimeout(async () => {
+ if (this[_readyState] === OPEN) {
+ this[_readyState] = CLOSING;
+ const reason = "No response from ping frame.";
+ await core.opAsync("op_ws_close", this[_rid], 1001, reason);
+ this[_readyState] = CLOSED;
+
+ const errEvent = new ErrorEvent("error", {
+ message: reason,
+ });
+ this.dispatchEvent(errEvent);
+
+ const event = new CloseEvent("close", {
+ wasClean: false,
+ code: 1001,
+ reason,
+ });
+ this.dispatchEvent(event);
+ core.tryClose(this[_rid]);
+ } else {
+ clearTimeout(this[_idleTimeoutTimeout]);
+ }
+ }, (this[_idleTimeoutDuration] / 2) * 1000);
+ } else {
+ clearTimeout(this[_idleTimeoutTimeout]);
+ }
+ }, (this[_idleTimeoutDuration] / 2) * 1000);
}
}
- ObjectDefineProperties(WebSocket, {
- CONNECTING: {
- value: 0,
- },
- OPEN: {
- value: 1,
- },
- CLOSING: {
- value: 2,
- },
- CLOSED: {
- value: 3,
- },
- });
-
- defineEventHandler(WebSocket.prototype, "message");
- defineEventHandler(WebSocket.prototype, "error");
- defineEventHandler(WebSocket.prototype, "close");
- defineEventHandler(WebSocket.prototype, "open");
-
- webidl.configurePrototype(WebSocket);
- const WebSocketPrototype = WebSocket.prototype;
-
- window.__bootstrap.webSocket = {
- WebSocket,
- _rid,
- _readyState,
- _eventLoop,
- _protocol,
- _server,
- _idleTimeoutDuration,
- _idleTimeoutTimeout,
- _serverHandleIdleTimeout,
- };
-})(this);
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ url: this.url,
+ readyState: this.readyState,
+ extensions: this.extensions,
+ protocol: this.protocol,
+ binaryType: this.binaryType,
+ bufferedAmount: this.bufferedAmount,
+ })
+ }`;
+ }
+}
+
+ObjectDefineProperties(WebSocket, {
+ CONNECTING: {
+ value: 0,
+ },
+ OPEN: {
+ value: 1,
+ },
+ CLOSING: {
+ value: 2,
+ },
+ CLOSED: {
+ value: 3,
+ },
+});
+
+defineEventHandler(WebSocket.prototype, "message");
+defineEventHandler(WebSocket.prototype, "error");
+defineEventHandler(WebSocket.prototype, "close");
+defineEventHandler(WebSocket.prototype, "open");
+
+webidl.configurePrototype(WebSocket);
+const WebSocketPrototype = WebSocket.prototype;
+
+export {
+ _eventLoop,
+ _idleTimeoutDuration,
+ _idleTimeoutTimeout,
+ _protocol,
+ _readyState,
+ _rid,
+ _server,
+ _serverHandleIdleTimeout,
+ WebSocket,
+};
diff --git a/ext/websocket/02_websocketstream.js b/ext/websocket/02_websocketstream.js
index 5d7e47cc4..b3d21297f 100644
--- a/ext/websocket/02_websocketstream.js
+++ b/ext/websocket/02_websocketstream.js
@@ -1,426 +1,424 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
/// <reference path="../../core/internal.d.ts" />
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const { writableStreamClose, Deferred } = window.__bootstrap.streams;
- const { DOMException } = window.__bootstrap.domException;
- const { add, remove } = window.__bootstrap.abortSignal;
- const { headersFromHeaderList, headerListFromHeaders, fillHeaders } =
- window.__bootstrap.headers;
-
- const {
- ArrayPrototypeJoin,
- ArrayPrototypeMap,
- Error,
- ObjectPrototypeIsPrototypeOf,
- PromisePrototypeCatch,
- PromisePrototypeThen,
- Set,
- StringPrototypeEndsWith,
- StringPrototypeToLowerCase,
- Symbol,
- SymbolFor,
- TypeError,
- Uint8ArrayPrototype,
- } = window.__bootstrap.primordials;
-
- webidl.converters.WebSocketStreamOptions = webidl.createDictionaryConverter(
- "WebSocketStreamOptions",
- [
- {
- key: "protocols",
- converter: webidl.converters["sequence<USVString>"],
- get defaultValue() {
- return [];
- },
- },
- {
- key: "signal",
- converter: webidl.converters.AbortSignal,
- },
- {
- key: "headers",
- converter: webidl.converters.HeadersInit,
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import { Deferred, writableStreamClose } from "internal:ext/web/06_streams.js";
+import DOMException from "internal:ext/web/01_dom_exception.js";
+import { add, remove } from "internal:ext/web/03_abort_signal.js";
+import {
+ fillHeaders,
+ headerListFromHeaders,
+ headersFromHeaderList,
+} from "internal:ext/fetch/20_headers.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypeJoin,
+ ArrayPrototypeMap,
+ Error,
+ ObjectPrototypeIsPrototypeOf,
+ PromisePrototypeCatch,
+ PromisePrototypeThen,
+ Set,
+ StringPrototypeEndsWith,
+ StringPrototypeToLowerCase,
+ Symbol,
+ SymbolFor,
+ TypeError,
+ Uint8ArrayPrototype,
+} = primordials;
+
+webidl.converters.WebSocketStreamOptions = webidl.createDictionaryConverter(
+ "WebSocketStreamOptions",
+ [
+ {
+ key: "protocols",
+ converter: webidl.converters["sequence<USVString>"],
+ get defaultValue() {
+ return [];
},
- ],
- );
- webidl.converters.WebSocketCloseInfo = webidl.createDictionaryConverter(
- "WebSocketCloseInfo",
- [
- {
- key: "code",
- converter: webidl.converters["unsigned short"],
- },
- {
- key: "reason",
- converter: webidl.converters.USVString,
- defaultValue: "",
- },
- ],
- );
-
- const CLOSE_RESPONSE_TIMEOUT = 5000;
-
- const _rid = Symbol("[[rid]]");
- const _url = Symbol("[[url]]");
- const _connection = Symbol("[[connection]]");
- const _closed = Symbol("[[closed]]");
- const _earlyClose = Symbol("[[earlyClose]]");
- const _closeSent = Symbol("[[closeSent]]");
- class WebSocketStream {
- [_rid];
-
- [_url];
- get url() {
- webidl.assertBranded(this, WebSocketStreamPrototype);
- return this[_url];
+ },
+ {
+ key: "signal",
+ converter: webidl.converters.AbortSignal,
+ },
+ {
+ key: "headers",
+ converter: webidl.converters.HeadersInit,
+ },
+ ],
+);
+webidl.converters.WebSocketCloseInfo = webidl.createDictionaryConverter(
+ "WebSocketCloseInfo",
+ [
+ {
+ key: "code",
+ converter: webidl.converters["unsigned short"],
+ },
+ {
+ key: "reason",
+ converter: webidl.converters.USVString,
+ defaultValue: "",
+ },
+ ],
+);
+
+const CLOSE_RESPONSE_TIMEOUT = 5000;
+
+const _rid = Symbol("[[rid]]");
+const _url = Symbol("[[url]]");
+const _connection = Symbol("[[connection]]");
+const _closed = Symbol("[[closed]]");
+const _earlyClose = Symbol("[[earlyClose]]");
+const _closeSent = Symbol("[[closeSent]]");
+class WebSocketStream {
+ [_rid];
+
+ [_url];
+ get url() {
+ webidl.assertBranded(this, WebSocketStreamPrototype);
+ return this[_url];
+ }
+
+ constructor(url, options) {
+ this[webidl.brand] = webidl.brand;
+ const prefix = "Failed to construct 'WebSocketStream'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ url = webidl.converters.USVString(url, {
+ prefix,
+ context: "Argument 1",
+ });
+ options = webidl.converters.WebSocketStreamOptions(options, {
+ prefix,
+ context: "Argument 2",
+ });
+
+ const wsURL = new URL(url);
+
+ if (wsURL.protocol !== "ws:" && wsURL.protocol !== "wss:") {
+ throw new DOMException(
+ "Only ws & wss schemes are allowed in a WebSocket URL.",
+ "SyntaxError",
+ );
}
- constructor(url, options) {
- this[webidl.brand] = webidl.brand;
- const prefix = "Failed to construct 'WebSocketStream'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- url = webidl.converters.USVString(url, {
- prefix,
- context: "Argument 1",
- });
- options = webidl.converters.WebSocketStreamOptions(options, {
- prefix,
- context: "Argument 2",
- });
-
- const wsURL = new URL(url);
-
- if (wsURL.protocol !== "ws:" && wsURL.protocol !== "wss:") {
- throw new DOMException(
- "Only ws & wss schemes are allowed in a WebSocket URL.",
- "SyntaxError",
- );
- }
-
- if (wsURL.hash !== "" || StringPrototypeEndsWith(wsURL.href, "#")) {
- throw new DOMException(
- "Fragments are not allowed in a WebSocket URL.",
- "SyntaxError",
- );
- }
-
- this[_url] = wsURL.href;
-
- if (
- options.protocols.length !==
- new Set(
- ArrayPrototypeMap(
- options.protocols,
- (p) => StringPrototypeToLowerCase(p),
- ),
- ).size
- ) {
- throw new DOMException(
- "Can't supply multiple times the same protocol.",
- "SyntaxError",
- );
- }
-
- const headers = headersFromHeaderList([], "request");
- if (options.headers !== undefined) {
- fillHeaders(headers, options.headers);
- }
-
- const cancelRid = ops.op_ws_check_permission_and_cancel_handle(
- "WebSocketStream.abort()",
- this[_url],
- true,
+ if (wsURL.hash !== "" || StringPrototypeEndsWith(wsURL.href, "#")) {
+ throw new DOMException(
+ "Fragments are not allowed in a WebSocket URL.",
+ "SyntaxError",
);
+ }
- if (options.signal?.aborted) {
- core.close(cancelRid);
- const err = options.signal.reason;
- this[_connection].reject(err);
- this[_closed].reject(err);
- } else {
- const abort = () => {
- core.close(cancelRid);
- };
- options.signal?.[add](abort);
- PromisePrototypeThen(
- core.opAsync(
- "op_ws_create",
- "new WebSocketStream()",
- this[_url],
- options.protocols
- ? ArrayPrototypeJoin(options.protocols, ", ")
- : "",
- cancelRid,
- headerListFromHeaders(headers),
+ this[_url] = wsURL.href;
+
+ if (
+ options.protocols.length !==
+ new Set(
+ ArrayPrototypeMap(
+ options.protocols,
+ (p) => StringPrototypeToLowerCase(p),
),
- (create) => {
- options.signal?.[remove](abort);
- if (this[_earlyClose]) {
- PromisePrototypeThen(
- core.opAsync("op_ws_close", create.rid),
- () => {
- PromisePrototypeThen(
- (async () => {
- while (true) {
- const { kind } = await core.opAsync(
- "op_ws_next_event",
- create.rid,
- );
-
- if (kind === "close") {
- break;
- }
- }
- })(),
- () => {
- const err = new DOMException(
- "Closed while connecting",
- "NetworkError",
+ ).size
+ ) {
+ throw new DOMException(
+ "Can't supply multiple times the same protocol.",
+ "SyntaxError",
+ );
+ }
+
+ const headers = headersFromHeaderList([], "request");
+ if (options.headers !== undefined) {
+ fillHeaders(headers, options.headers);
+ }
+
+ const cancelRid = ops.op_ws_check_permission_and_cancel_handle(
+ "WebSocketStream.abort()",
+ this[_url],
+ true,
+ );
+
+ if (options.signal?.aborted) {
+ core.close(cancelRid);
+ const err = options.signal.reason;
+ this[_connection].reject(err);
+ this[_closed].reject(err);
+ } else {
+ const abort = () => {
+ core.close(cancelRid);
+ };
+ options.signal?.[add](abort);
+ PromisePrototypeThen(
+ core.opAsync(
+ "op_ws_create",
+ "new WebSocketStream()",
+ this[_url],
+ options.protocols ? ArrayPrototypeJoin(options.protocols, ", ") : "",
+ cancelRid,
+ headerListFromHeaders(headers),
+ ),
+ (create) => {
+ options.signal?.[remove](abort);
+ if (this[_earlyClose]) {
+ PromisePrototypeThen(
+ core.opAsync("op_ws_close", create.rid),
+ () => {
+ PromisePrototypeThen(
+ (async () => {
+ while (true) {
+ const { kind } = await core.opAsync(
+ "op_ws_next_event",
+ create.rid,
);
- this[_connection].reject(err);
- this[_closed].reject(err);
- },
- );
- },
- () => {
- const err = new DOMException(
- "Closed while connecting",
- "NetworkError",
+
+ if (kind === "close") {
+ break;
+ }
+ }
+ })(),
+ () => {
+ const err = new DOMException(
+ "Closed while connecting",
+ "NetworkError",
+ );
+ this[_connection].reject(err);
+ this[_closed].reject(err);
+ },
+ );
+ },
+ () => {
+ const err = new DOMException(
+ "Closed while connecting",
+ "NetworkError",
+ );
+ this[_connection].reject(err);
+ this[_closed].reject(err);
+ },
+ );
+ } else {
+ this[_rid] = create.rid;
+
+ const writable = new WritableStream({
+ write: async (chunk) => {
+ if (typeof chunk === "string") {
+ await core.opAsync("op_ws_send", this[_rid], {
+ kind: "text",
+ value: chunk,
+ });
+ } else if (
+ ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, chunk)
+ ) {
+ await core.opAsync("op_ws_send", this[_rid], {
+ kind: "binary",
+ value: chunk,
+ }, chunk);
+ } else {
+ throw new TypeError(
+ "A chunk may only be either a string or an Uint8Array",
);
- this[_connection].reject(err);
- this[_closed].reject(err);
- },
+ }
+ },
+ close: async (reason) => {
+ try {
+ this.close(reason?.code !== undefined ? reason : {});
+ } catch (_) {
+ this.close();
+ }
+ await this.closed;
+ },
+ abort: async (reason) => {
+ try {
+ this.close(reason?.code !== undefined ? reason : {});
+ } catch (_) {
+ this.close();
+ }
+ await this.closed;
+ },
+ });
+ const pull = async (controller) => {
+ const { kind, value } = await core.opAsync(
+ "op_ws_next_event",
+ this[_rid],
);
- } else {
- this[_rid] = create.rid;
-
- const writable = new WritableStream({
- write: async (chunk) => {
- if (typeof chunk === "string") {
- await core.opAsync("op_ws_send", this[_rid], {
- kind: "text",
- value: chunk,
- });
- } else if (
- ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, chunk)
- ) {
- await core.opAsync("op_ws_send", this[_rid], {
- kind: "binary",
- value: chunk,
- }, chunk);
- } else {
- throw new TypeError(
- "A chunk may only be either a string or an Uint8Array",
- );
- }
- },
- close: async (reason) => {
+
+ switch (kind) {
+ case "string": {
+ controller.enqueue(value);
+ break;
+ }
+ case "binary": {
+ controller.enqueue(value);
+ break;
+ }
+ case "ping": {
+ await core.opAsync("op_ws_send", this[_rid], {
+ kind: "pong",
+ });
+ await pull(controller);
+ break;
+ }
+ case "closed":
+ case "close": {
+ this[_closed].resolve(value);
+ core.tryClose(this[_rid]);
+ break;
+ }
+ case "error": {
+ const err = new Error(value);
+ this[_closed].reject(err);
+ controller.error(err);
+ core.tryClose(this[_rid]);
+ break;
+ }
+ }
+
+ if (
+ this[_closeSent].state === "fulfilled" &&
+ this[_closed].state === "pending"
+ ) {
+ if (
+ new Date().getTime() - await this[_closeSent].promise <=
+ CLOSE_RESPONSE_TIMEOUT
+ ) {
+ return pull(controller);
+ }
+
+ this[_closed].resolve(value);
+ core.tryClose(this[_rid]);
+ }
+ };
+ const readable = new ReadableStream({
+ start: (controller) => {
+ PromisePrototypeThen(this.closed, () => {
try {
- this.close(reason?.code !== undefined ? reason : {});
+ controller.close();
} catch (_) {
- this.close();
+ // needed to ignore warnings & assertions
}
- await this.closed;
- },
- abort: async (reason) => {
try {
- this.close(reason?.code !== undefined ? reason : {});
+ PromisePrototypeCatch(
+ writableStreamClose(writable),
+ () => {},
+ );
} catch (_) {
- this.close();
+ // needed to ignore warnings & assertions
}
- await this.closed;
- },
- });
- const pull = async (controller) => {
- const { kind, value } = await core.opAsync(
- "op_ws_next_event",
- this[_rid],
- );
+ });
- switch (kind) {
- case "string": {
- controller.enqueue(value);
- break;
- }
- case "binary": {
- controller.enqueue(value);
- break;
- }
- case "ping": {
- await core.opAsync("op_ws_send", this[_rid], {
- kind: "pong",
- });
- await pull(controller);
- break;
- }
- case "closed":
- case "close": {
- this[_closed].resolve(value);
- core.tryClose(this[_rid]);
- break;
- }
- case "error": {
- const err = new Error(value);
- this[_closed].reject(err);
- controller.error(err);
- core.tryClose(this[_rid]);
- break;
+ PromisePrototypeThen(this[_closeSent].promise, () => {
+ if (this[_closed].state === "pending") {
+ return pull(controller);
}
+ });
+ },
+ pull,
+ cancel: async (reason) => {
+ try {
+ this.close(reason?.code !== undefined ? reason : {});
+ } catch (_) {
+ this.close();
}
+ await this.closed;
+ },
+ });
+
+ this[_connection].resolve({
+ readable,
+ writable,
+ extensions: create.extensions ?? "",
+ protocol: create.protocol ?? "",
+ });
+ }
+ },
+ (err) => {
+ if (ObjectPrototypeIsPrototypeOf(core.InterruptedPrototype, err)) {
+ // The signal was aborted.
+ err = options.signal.reason;
+ } else {
+ core.tryClose(cancelRid);
+ }
+ this[_connection].reject(err);
+ this[_closed].reject(err);
+ },
+ );
+ }
+ }
- if (
- this[_closeSent].state === "fulfilled" &&
- this[_closed].state === "pending"
- ) {
- if (
- new Date().getTime() - await this[_closeSent].promise <=
- CLOSE_RESPONSE_TIMEOUT
- ) {
- return pull(controller);
- }
+ [_connection] = new Deferred();
+ get connection() {
+ webidl.assertBranded(this, WebSocketStreamPrototype);
+ return this[_connection].promise;
+ }
- this[_closed].resolve(value);
- core.tryClose(this[_rid]);
- }
- };
- const readable = new ReadableStream({
- start: (controller) => {
- PromisePrototypeThen(this.closed, () => {
- try {
- controller.close();
- } catch (_) {
- // needed to ignore warnings & assertions
- }
- try {
- PromisePrototypeCatch(
- writableStreamClose(writable),
- () => {},
- );
- } catch (_) {
- // needed to ignore warnings & assertions
- }
- });
+ [_earlyClose] = false;
+ [_closed] = new Deferred();
+ [_closeSent] = new Deferred();
+ get closed() {
+ webidl.assertBranded(this, WebSocketStreamPrototype);
+ return this[_closed].promise;
+ }
- PromisePrototypeThen(this[_closeSent].promise, () => {
- if (this[_closed].state === "pending") {
- return pull(controller);
- }
- });
- },
- pull,
- cancel: async (reason) => {
- try {
- this.close(reason?.code !== undefined ? reason : {});
- } catch (_) {
- this.close();
- }
- await this.closed;
- },
- });
-
- this[_connection].resolve({
- readable,
- writable,
- extensions: create.extensions ?? "",
- protocol: create.protocol ?? "",
- });
- }
- },
- (err) => {
- if (ObjectPrototypeIsPrototypeOf(core.InterruptedPrototype, err)) {
- // The signal was aborted.
- err = options.signal.reason;
- } else {
- core.tryClose(cancelRid);
- }
- this[_connection].reject(err);
- this[_closed].reject(err);
- },
- );
- }
+ close(closeInfo) {
+ webidl.assertBranded(this, WebSocketStreamPrototype);
+ closeInfo = webidl.converters.WebSocketCloseInfo(closeInfo, {
+ prefix: "Failed to execute 'close' on 'WebSocketStream'",
+ context: "Argument 1",
+ });
+
+ if (
+ closeInfo.code &&
+ !(closeInfo.code === 1000 ||
+ (3000 <= closeInfo.code && closeInfo.code < 5000))
+ ) {
+ throw new DOMException(
+ "The close code must be either 1000 or in the range of 3000 to 4999.",
+ "InvalidAccessError",
+ );
}
- [_connection] = new Deferred();
- get connection() {
- webidl.assertBranded(this, WebSocketStreamPrototype);
- return this[_connection].promise;
+ const encoder = new TextEncoder();
+ if (
+ closeInfo.reason && encoder.encode(closeInfo.reason).byteLength > 123
+ ) {
+ throw new DOMException(
+ "The close reason may not be longer than 123 bytes.",
+ "SyntaxError",
+ );
}
- [_earlyClose] = false;
- [_closed] = new Deferred();
- [_closeSent] = new Deferred();
- get closed() {
- webidl.assertBranded(this, WebSocketStreamPrototype);
- return this[_closed].promise;
+ let code = closeInfo.code;
+ if (closeInfo.reason && code === undefined) {
+ code = 1000;
}
- close(closeInfo) {
- webidl.assertBranded(this, WebSocketStreamPrototype);
- closeInfo = webidl.converters.WebSocketCloseInfo(closeInfo, {
- prefix: "Failed to execute 'close' on 'WebSocketStream'",
- context: "Argument 1",
- });
-
- if (
- closeInfo.code &&
- !(closeInfo.code === 1000 ||
- (3000 <= closeInfo.code && closeInfo.code < 5000))
- ) {
- throw new DOMException(
- "The close code must be either 1000 or in the range of 3000 to 4999.",
- "InvalidAccessError",
- );
- }
-
- const encoder = new TextEncoder();
- if (
- closeInfo.reason && encoder.encode(closeInfo.reason).byteLength > 123
- ) {
- throw new DOMException(
- "The close reason may not be longer than 123 bytes.",
- "SyntaxError",
- );
- }
-
- let code = closeInfo.code;
- if (closeInfo.reason && code === undefined) {
- code = 1000;
- }
-
- if (this[_connection].state === "pending") {
- this[_earlyClose] = true;
- } else if (this[_closed].state === "pending") {
- PromisePrototypeThen(
- core.opAsync("op_ws_close", this[_rid], code, closeInfo.reason),
- () => {
- setTimeout(() => {
- this[_closeSent].resolve(new Date().getTime());
- }, 0);
- },
- (err) => {
- this[_rid] && core.tryClose(this[_rid]);
- this[_closed].reject(err);
- },
- );
- }
+ if (this[_connection].state === "pending") {
+ this[_earlyClose] = true;
+ } else if (this[_closed].state === "pending") {
+ PromisePrototypeThen(
+ core.opAsync("op_ws_close", this[_rid], code, closeInfo.reason),
+ () => {
+ setTimeout(() => {
+ this[_closeSent].resolve(new Date().getTime());
+ }, 0);
+ },
+ (err) => {
+ this[_rid] && core.tryClose(this[_rid]);
+ this[_closed].reject(err);
+ },
+ );
}
+ }
- [SymbolFor("Deno.customInspect")](inspect) {
- return `${this.constructor.name} ${
- inspect({
- url: this.url,
- })
- }`;
- }
+ [SymbolFor("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ url: this.url,
+ })
+ }`;
}
+}
- const WebSocketStreamPrototype = WebSocketStream.prototype;
+const WebSocketStreamPrototype = WebSocketStream.prototype;
- window.__bootstrap.webSocket.WebSocketStream = WebSocketStream;
-})(this);
+export { WebSocketStream };
diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs
index 82a2c5918..da6a48e45 100644
--- a/ext/websocket/lib.rs
+++ b/ext/websocket/lib.rs
@@ -504,7 +504,7 @@ pub fn init<P: WebSocketPermissions + 'static>(
) -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_url", "deno_webidl"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/websocket",
"01_websocket.js",
"02_websocketstream.js",
diff --git a/ext/webstorage/01_webstorage.js b/ext/webstorage/01_webstorage.js
index 27d7aac09..d7abdfbd8 100644
--- a/ext/webstorage/01_webstorage.js
+++ b/ext/webstorage/01_webstorage.js
@@ -2,191 +2,189 @@
/// <reference path="../../core/internal.d.ts" />
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const webidl = window.__bootstrap.webidl;
- const {
- SafeArrayIterator,
- Symbol,
- SymbolFor,
- ObjectDefineProperty,
- ObjectFromEntries,
- ObjectEntries,
- ReflectGet,
- ReflectHas,
- Proxy,
- } = window.__bootstrap.primordials;
-
- const _persistent = Symbol("[[persistent]]");
-
- class Storage {
- [_persistent];
-
- constructor() {
- webidl.illegalConstructor();
- }
-
- get length() {
- webidl.assertBranded(this, StoragePrototype);
- return ops.op_webstorage_length(this[_persistent]);
- }
-
- key(index) {
- webidl.assertBranded(this, StoragePrototype);
- const prefix = "Failed to execute 'key' on 'Storage'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- index = webidl.converters["unsigned long"](index, {
- prefix,
- context: "Argument 1",
- });
-
- return ops.op_webstorage_key(index, this[_persistent]);
- }
-
- setItem(key, value) {
- webidl.assertBranded(this, StoragePrototype);
- const prefix = "Failed to execute 'setItem' on 'Storage'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- key = webidl.converters.DOMString(key, {
- prefix,
- context: "Argument 1",
- });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 2",
- });
-
- ops.op_webstorage_set(key, value, this[_persistent]);
- }
-
- getItem(key) {
- webidl.assertBranded(this, StoragePrototype);
- const prefix = "Failed to execute 'getItem' on 'Storage'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- key = webidl.converters.DOMString(key, {
- prefix,
- context: "Argument 1",
- });
-
- return ops.op_webstorage_get(key, this[_persistent]);
- }
-
- removeItem(key) {
- webidl.assertBranded(this, StoragePrototype);
- const prefix = "Failed to execute 'removeItem' on 'Storage'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- key = webidl.converters.DOMString(key, {
- prefix,
- context: "Argument 1",
- });
-
- ops.op_webstorage_remove(key, this[_persistent]);
- }
-
- clear() {
- webidl.assertBranded(this, StoragePrototype);
- ops.op_webstorage_clear(this[_persistent]);
- }
+const core = globalThis.Deno.core;
+const ops = core.ops;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ SafeArrayIterator,
+ Symbol,
+ SymbolFor,
+ ObjectDefineProperty,
+ ObjectFromEntries,
+ ObjectEntries,
+ ReflectGet,
+ ReflectHas,
+ Proxy,
+} = primordials;
+
+const _persistent = Symbol("[[persistent]]");
+
+class Storage {
+ [_persistent];
+
+ constructor() {
+ webidl.illegalConstructor();
}
- const StoragePrototype = Storage.prototype;
-
- function createStorage(persistent) {
- const storage = webidl.createBranded(Storage);
- storage[_persistent] = persistent;
-
- const proxy = new Proxy(storage, {
- deleteProperty(target, key) {
- if (typeof key == "symbol") {
- delete target[key];
- } else {
- target.removeItem(key);
- }
- return true;
- },
- defineProperty(target, key, descriptor) {
- if (typeof key == "symbol") {
- ObjectDefineProperty(target, key, descriptor);
- } else {
- target.setItem(key, descriptor.value);
- }
- return true;
- },
- get(target, key) {
- if (typeof key == "symbol") return target[key];
- if (ReflectHas(target, key)) {
- return ReflectGet(...new SafeArrayIterator(arguments));
- } else {
- return target.getItem(key) ?? undefined;
- }
- },
- set(target, key, value) {
- if (typeof key == "symbol") {
- ObjectDefineProperty(target, key, {
- value,
- configurable: true,
- });
- } else {
- target.setItem(key, value);
- }
- return true;
- },
- has(target, p) {
- return p === SymbolFor("Deno.customInspect") ||
- (typeof target.getItem(p)) === "string";
- },
- ownKeys() {
- return ops.op_webstorage_iterate_keys(persistent);
- },
- getOwnPropertyDescriptor(target, key) {
- if (arguments.length === 1) {
- return undefined;
- }
- if (ReflectHas(target, key)) {
- return undefined;
- }
- const value = target.getItem(key);
- if (value === null) {
- return undefined;
- }
- return {
- value,
- enumerable: true,
- configurable: true,
- writable: true,
- };
- },
+ get length() {
+ webidl.assertBranded(this, StoragePrototype);
+ return ops.op_webstorage_length(this[_persistent]);
+ }
+
+ key(index) {
+ webidl.assertBranded(this, StoragePrototype);
+ const prefix = "Failed to execute 'key' on 'Storage'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ index = webidl.converters["unsigned long"](index, {
+ prefix,
+ context: "Argument 1",
});
- proxy[SymbolFor("Deno.customInspect")] = function (inspect) {
- return `${this.constructor.name} ${
- inspect({
- length: this.length,
- ...ObjectFromEntries(ObjectEntries(proxy)),
- })
- }`;
- };
+ return ops.op_webstorage_key(index, this[_persistent]);
+ }
+
+ setItem(key, value) {
+ webidl.assertBranded(this, StoragePrototype);
+ const prefix = "Failed to execute 'setItem' on 'Storage'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ key = webidl.converters.DOMString(key, {
+ prefix,
+ context: "Argument 1",
+ });
+ value = webidl.converters.DOMString(value, {
+ prefix,
+ context: "Argument 2",
+ });
- return proxy;
+ ops.op_webstorage_set(key, value, this[_persistent]);
}
- let localStorage;
- let sessionStorage;
+ getItem(key) {
+ webidl.assertBranded(this, StoragePrototype);
+ const prefix = "Failed to execute 'getItem' on 'Storage'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ key = webidl.converters.DOMString(key, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ return ops.op_webstorage_get(key, this[_persistent]);
+ }
+
+ removeItem(key) {
+ webidl.assertBranded(this, StoragePrototype);
+ const prefix = "Failed to execute 'removeItem' on 'Storage'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ key = webidl.converters.DOMString(key, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ ops.op_webstorage_remove(key, this[_persistent]);
+ }
+
+ clear() {
+ webidl.assertBranded(this, StoragePrototype);
+ ops.op_webstorage_clear(this[_persistent]);
+ }
+}
+
+const StoragePrototype = Storage.prototype;
+
+function createStorage(persistent) {
+ const storage = webidl.createBranded(Storage);
+ storage[_persistent] = persistent;
- window.__bootstrap.webStorage = {
- localStorage() {
- if (!localStorage) {
- localStorage = createStorage(true);
+ const proxy = new Proxy(storage, {
+ deleteProperty(target, key) {
+ if (typeof key == "symbol") {
+ delete target[key];
+ } else {
+ target.removeItem(key);
}
- return localStorage;
+ return true;
},
- sessionStorage() {
- if (!sessionStorage) {
- sessionStorage = createStorage(false);
+ defineProperty(target, key, descriptor) {
+ if (typeof key == "symbol") {
+ ObjectDefineProperty(target, key, descriptor);
+ } else {
+ target.setItem(key, descriptor.value);
}
- return sessionStorage;
+ return true;
},
- Storage,
+ get(target, key) {
+ if (typeof key == "symbol") return target[key];
+ if (ReflectHas(target, key)) {
+ return ReflectGet(...new SafeArrayIterator(arguments));
+ } else {
+ return target.getItem(key) ?? undefined;
+ }
+ },
+ set(target, key, value) {
+ if (typeof key == "symbol") {
+ ObjectDefineProperty(target, key, {
+ value,
+ configurable: true,
+ });
+ } else {
+ target.setItem(key, value);
+ }
+ return true;
+ },
+ has(target, p) {
+ return p === SymbolFor("Deno.customInspect") ||
+ (typeof target.getItem(p)) === "string";
+ },
+ ownKeys() {
+ return ops.op_webstorage_iterate_keys(persistent);
+ },
+ getOwnPropertyDescriptor(target, key) {
+ if (arguments.length === 1) {
+ return undefined;
+ }
+ if (ReflectHas(target, key)) {
+ return undefined;
+ }
+ const value = target.getItem(key);
+ if (value === null) {
+ return undefined;
+ }
+ return {
+ value,
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ };
+ },
+ });
+
+ proxy[SymbolFor("Deno.customInspect")] = function (inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ length: this.length,
+ ...ObjectFromEntries(ObjectEntries(proxy)),
+ })
+ }`;
};
-})(this);
+
+ return proxy;
+}
+
+let localStorageStorage;
+function localStorage() {
+ if (!localStorageStorage) {
+ localStorageStorage = createStorage(true);
+ }
+ return localStorageStorage;
+}
+
+let sessionStorageStorage;
+function sessionStorage() {
+ if (!sessionStorageStorage) {
+ sessionStorageStorage = createStorage(false);
+ }
+ return sessionStorageStorage;
+}
+
+export { localStorage, sessionStorage, Storage };
diff --git a/ext/webstorage/lib.rs b/ext/webstorage/lib.rs
index 29deaee84..d878ad701 100644
--- a/ext/webstorage/lib.rs
+++ b/ext/webstorage/lib.rs
@@ -24,7 +24,7 @@ const MAX_STORAGE_BYTES: u32 = 10 * 1024 * 1024;
pub fn init(origin_storage_dir: Option<PathBuf>) -> Extension {
Extension::builder(env!("CARGO_PKG_NAME"))
.dependencies(vec!["deno_webidl"])
- .js(include_js_files!(
+ .esm(include_js_files!(
prefix "internal:ext/webstorage",
"01_webstorage.js",
))