summaryrefslogtreecommitdiff
path: root/ext/web
diff options
context:
space:
mode:
Diffstat (limited to 'ext/web')
-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
22 files changed, 11140 insertions, 11181 deletions
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",