diff --git a/extensions/websocket/01_websocket.js b/extensions/websocket/01_websocket.js
index 38cba866242d7b..f6e285b7653f54 100644
--- a/extensions/websocket/01_websocket.js
+++ b/extensions/websocket/01_websocket.js
@@ -1,12 +1,37 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
"use strict";
+///
+
((window) => {
const core = window.Deno.core;
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 { Blob } = globalThis.__bootstrap.file;
+ const {
+ ArrayBuffer,
+ ArrayBufferIsView,
+ ArrayPrototypeJoin,
+ DataView,
+ ErrorPrototypeToString,
+ ObjectDefineProperty,
+ Map,
+ MapPrototypeGet,
+ MapPrototypeSet,
+ Set,
+ Symbol,
+ String,
+ StringPrototypeToLowerCase,
+ StringPrototypeEndsWith,
+ FunctionPrototypeCall,
+ RegExpPrototypeTest,
+ ObjectDefineProperties,
+ ArrayPrototypeMap,
+ ArrayPrototypeSome,
+ PromisePrototypeThen,
+ } = window.__bootstrap.primordials;
webidl.converters["sequence or DOMString"] = (V, opts) => {
// Union for (sequence or DOMString)
@@ -24,10 +49,11 @@
return webidl.converters["Blob"](V, opts);
}
if (typeof V === "object") {
+ // TODO(littledivy): use primordial for SharedArrayBuffer
if (V instanceof ArrayBuffer || V instanceof SharedArrayBuffer) {
return webidl.converters["ArrayBuffer"](V, opts);
}
- if (ArrayBuffer.isView(V)) {
+ if (ArrayBufferIsView(V)) {
return webidl.converters["ArrayBufferView"](V, opts);
}
}
@@ -58,7 +84,7 @@
if (typeof wrappedHandler.handler !== "function") {
return;
}
- return wrappedHandler.handler.call(this, ...args);
+ return FunctionPrototypeCall(wrappedHandler.handler, this, ...args);
}
wrappedHandler.handler = handler;
return wrappedHandler;
@@ -66,22 +92,25 @@
// TODO(lucacasonato) reuse when we can reuse code between web crates
function defineEventHandler(emitter, name) {
// HTML specification section 8.1.5.1
- Object.defineProperty(emitter, `on${name}`, {
+ ObjectDefineProperty(emitter, `on${name}`, {
get() {
- return this[handlerSymbol]?.get(name)?.handler;
+ if (!this[handlerSymbol]) {
+ return null;
+ }
+ return MapPrototypeGet(this[handlerSymbol], name)?.handler;
},
set(value) {
if (!this[handlerSymbol]) {
this[handlerSymbol] = new Map();
}
- let handlerWrapper = this[handlerSymbol]?.get(name);
+ let handlerWrapper = MapPrototypeGet(this[handlerSymbol], name);
if (handlerWrapper) {
handlerWrapper.handler = value;
} else {
handlerWrapper = makeWrappedHandler(value);
this.addEventListener(name, handlerWrapper);
}
- this[handlerSymbol].set(name, handlerWrapper);
+ MapPrototypeSet(this[handlerSymbol], name, handlerWrapper);
},
configurable: true,
enumerable: true,
@@ -194,7 +223,7 @@
);
}
- if (wsURL.hash !== "" || wsURL.href.endsWith("#")) {
+ if (wsURL.hash !== "" || StringPrototypeEndsWith(wsURL.href, "#")) {
throw new DOMException(
"Fragments are not allowed in a WebSocket URL.",
"SyntaxError",
@@ -210,7 +239,10 @@
}
if (
- protocols.length !== new Set(protocols.map((p) => p.toLowerCase())).size
+ protocols.length !==
+ new Set(
+ ArrayPrototypeMap(protocols, (p) => StringPrototypeToLowerCase(p)),
+ ).size
) {
throw new DOMException(
"Can't supply multiple times the same protocol.",
@@ -219,7 +251,11 @@
}
if (
- protocols.some((protocol) => !HTTP_TOKEN_CODE_POINT_RE.test(protocol))
+ ArrayPrototypeSome(
+ protocols,
+ (protocol) =>
+ !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, protocol),
+ )
) {
throw new DOMException(
"Invalid protocol value.",
@@ -227,46 +263,53 @@
);
}
- core.opAsync("op_ws_create", {
- url: wsURL.href,
- protocols: protocols.join(", "),
- }).then((create) => {
- this[_rid] = create.rid;
- this[_extensions] = create.extensions;
- this[_protocol] = create.protocol;
-
- if (this[_readyState] === CLOSING) {
- core.opAsync("op_ws_close", {
- rid: this[_rid],
- }).then(() => {
- this[_readyState] = CLOSED;
-
- const errEvent = new ErrorEvent("error");
- this.dispatchEvent(errEvent);
-
- const event = new CloseEvent("close");
+ PromisePrototypeThen(
+ core.opAsync("op_ws_create", {
+ url: wsURL.href,
+ protocols: 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", {
+ rid: this[_rid],
+ }),
+ () => {
+ this[_readyState] = CLOSED;
+
+ const errEvent = new ErrorEvent("error");
+ this.dispatchEvent(errEvent);
+
+ const event = new CloseEvent("close");
+ this.dispatchEvent(event);
+ tryClose(this[_rid]);
+ },
+ );
+ } else {
+ this[_readyState] = OPEN;
+ const event = new Event("open");
this.dispatchEvent(event);
- tryClose(this[_rid]);
- });
- } else {
- this[_readyState] = OPEN;
- const event = new Event("open");
- this.dispatchEvent(event);
- this.#eventLoop();
- }
- }).catch((err) => {
- this[_readyState] = CLOSED;
+ this.#eventLoop();
+ }
+ },
+ (err) => {
+ this[_readyState] = CLOSED;
- const errorEv = new ErrorEvent(
- "error",
- { error: err, message: err.toString() },
- );
- this.dispatchEvent(errorEv);
+ const errorEv = new ErrorEvent(
+ "error",
+ { error: err, message: ErrorPrototypeToString(err) },
+ );
+ this.dispatchEvent(errorEv);
- const closeEv = new CloseEvent("close");
- this.dispatchEvent(closeEv);
- });
+ const closeEv = new CloseEvent("close");
+ this.dispatchEvent(closeEv);
+ },
+ );
}
send(data) {
@@ -287,19 +330,23 @@
const sendTypedArray = (ta) => {
this[_bufferedAmount] += ta.byteLength;
- core.opAsync("op_ws_send", {
- rid: this[_rid],
- kind: "binary",
- }, ta).then(() => {
- this[_bufferedAmount] -= ta.byteLength;
- });
+ PromisePrototypeThen(
+ core.opAsync("op_ws_send", {
+ rid: this[_rid],
+ kind: "binary",
+ }, ta),
+ () => {
+ this[_bufferedAmount] -= ta.byteLength;
+ },
+ );
};
if (data instanceof Blob) {
- data.slice().arrayBuffer().then((ab) =>
- sendTypedArray(new DataView(ab))
+ PromisePrototypeThen(
+ data.slice().arrayBuffer(),
+ (ab) => sendTypedArray(new DataView(ab)),
);
- } else if (ArrayBuffer.isView(data)) {
+ } else if (ArrayBufferIsView(data)) {
sendTypedArray(data);
} else if (data instanceof ArrayBuffer) {
sendTypedArray(new DataView(data));
@@ -307,13 +354,16 @@
const string = String(data);
const d = core.encode(string);
this[_bufferedAmount] += d.byteLength;
- core.opAsync("op_ws_send", {
- rid: this[_rid],
- kind: "text",
- text: string,
- }).then(() => {
- this[_bufferedAmount] -= d.byteLength;
- });
+ PromisePrototypeThen(
+ core.opAsync("op_ws_send", {
+ rid: this[_rid],
+ kind: "text",
+ text: string,
+ }),
+ () => {
+ this[_bufferedAmount] -= d.byteLength;
+ },
+ );
}
}
@@ -357,20 +407,23 @@
} else if (this[_readyState] === OPEN) {
this[_readyState] = CLOSING;
- core.opAsync("op_ws_close", {
- rid: this[_rid],
- code,
- reason,
- }).then(() => {
- this[_readyState] = CLOSED;
- const event = new CloseEvent("close", {
- wasClean: true,
- code: code ?? 1005,
+ PromisePrototypeThen(
+ core.opAsync("op_ws_close", {
+ rid: this[_rid],
+ code,
reason,
- });
- this.dispatchEvent(event);
- tryClose(this[_rid]);
- });
+ }),
+ () => {
+ this[_readyState] = CLOSED;
+ const event = new CloseEvent("close", {
+ wasClean: true,
+ code: code ?? 1005,
+ reason,
+ });
+ this.dispatchEvent(event);
+ tryClose(this[_rid]);
+ },
+ );
}
}
@@ -443,7 +496,7 @@
}
}
- Object.defineProperties(WebSocket, {
+ ObjectDefineProperties(WebSocket, {
CONNECTING: {
value: 0,
},