diff --git a/extensions/web/06_streams.js b/extensions/web/06_streams.js
index e59f8e9459..b3c55fa85e 100644
--- a/extensions/web/06_streams.js
+++ b/extensions/web/06_streams.js
@@ -1,12 +1,15 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// @ts-check
+///
///
-///
+///
///
"use strict";
((window) => {
+ const webidl = window.__bootstrap.webidl;
+
class AssertionError extends Error {
constructor(msg) {
super(msg);
@@ -74,119 +77,6 @@
}
}
- /**
- * @param {(...args: any[]) => any} fn
- * @param {boolean} enforcePromise
- * @returns {(...args: any[]) => any}
- */
- function reflectApply(fn, enforcePromise) {
- if (typeof fn !== "function") {
- throw new TypeError("The property must be a function.");
- }
- return function (...args) {
- if (enforcePromise) {
- try {
- return resolvePromiseWith(Reflect.apply(fn, this, args));
- } catch (err) {
- return Promise.reject(err);
- }
- }
- return Reflect.apply(fn, this, args);
- };
- }
-
- /**
- * @template I
- * @template O
- * @param {Transformer} transformer
- * @returns {Transformer}
- */
- function convertTransformer(transformer) {
- const transformerDict = Object.create(null);
- if (transformer === null) {
- return transformerDict;
- }
- if ("flush" in transformer) {
- transformerDict.flush = reflectApply(transformer.flush, true);
- }
- if ("readableType" in transformer) {
- transformerDict.readableType = transformer.readableType;
- }
- if ("start" in transformer) {
- transformerDict.start = reflectApply(transformer.start, false);
- }
- if ("transform" in transformer) {
- transformerDict.transform = reflectApply(transformer.transform, true);
- }
- if ("writableType" in transformer) {
- transformerDict.writableType = transformer.writableType;
- }
- return transformerDict;
- }
-
- /**
- * @template W
- * @param {UnderlyingSink} underlyingSink
- * @returns {UnderlyingSink}
- */
- function convertUnderlyingSink(underlyingSink) {
- const underlyingSinkDict = Object.create(null);
- if (underlyingSink === null) {
- return underlyingSinkDict;
- }
- if ("abort" in underlyingSink) {
- underlyingSinkDict.abort = reflectApply(underlyingSink.abort, true);
- }
- if ("close" in underlyingSink) {
- underlyingSinkDict.close = reflectApply(underlyingSink.close, true);
- }
- if ("start" in underlyingSink) {
- underlyingSinkDict.start = reflectApply(underlyingSink.start, false);
- }
- if (underlyingSink.type) {
- underlyingSinkDict.type = underlyingSink.type;
- }
- if ("write" in underlyingSink) {
- underlyingSinkDict.write = reflectApply(underlyingSink.write, true);
- }
- return underlyingSinkDict;
- }
-
- /**
- * @template R
- * @param {UnderlyingSource} underlyingSource
- * @returns {UnderlyingSource}
- */
- function convertUnderlyingSource(underlyingSource) {
- const underlyingSourceDict = Object.create(null);
- if (underlyingSource === null) {
- throw new TypeError("Underlying source cannot be null");
- }
- if (underlyingSource === undefined) {
- return underlyingSourceDict;
- }
- if ("cancel" in underlyingSource) {
- underlyingSourceDict.cancel = reflectApply(underlyingSource.cancel, true);
- }
- if ("pull" in underlyingSource) {
- underlyingSourceDict.pull = reflectApply(underlyingSource.pull, true);
- }
- if ("start" in underlyingSource) {
- underlyingSourceDict.start = reflectApply(underlyingSource.start, false);
- }
- if (underlyingSource.type !== undefined) {
- if (underlyingSourceDict.type === null) {
- throw new TypeError("type cannot be null");
- }
- const type = String(underlyingSource.type);
- if (type !== "bytes") {
- throw new TypeError("invalid underlying source type");
- }
- underlyingSourceDict.type = type;
- }
- return underlyingSourceDict;
- }
-
const originalPromise = Promise;
const originalPromiseThen = Promise.prototype.then;
@@ -323,6 +213,7 @@
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]");
@@ -385,9 +276,9 @@
) {
assert(isNonNegativeNumber(highWaterMark));
/** @type {ReadableStream} */
- const stream = Object.create(ReadableStream.prototype);
+ const stream = webidl.createBranded(ReadableStream);
initializeReadableStream(stream);
- const controller = Object.create(ReadableStreamDefaultController.prototype);
+ const controller = webidl.createBranded(ReadableStreamDefaultController);
setUpReadableStreamDefaultController(
stream,
controller,
@@ -419,9 +310,9 @@
sizeAlgorithm,
) {
assert(isNonNegativeNumber(highWaterMark));
- const stream = Object.create(WritableStream.prototype);
+ const stream = webidl.createBranded(WritableStream);
initializeWritableStream(stream);
- const controller = Object.create(WritableStreamDefaultController.prototype);
+ const controller = webidl.createBranded(WritableStreamDefaultController);
setUpWritableStreamDefaultController(
stream,
controller,
@@ -1750,24 +1641,53 @@
underlyingSourceDict,
highWaterMark,
) {
- const controller = new ReadableByteStreamController();
+ const controller = webidl.createBranded(ReadableByteStreamController);
/** @type {() => void} */
let startAlgorithm = () => undefined;
/** @type {() => Promise} */
let pullAlgorithm = () => resolvePromiseWith(undefined);
/** @type {(reason: any) => Promise} */
let cancelAlgorithm = (_reason) => resolvePromiseWith(undefined);
- if ("start" in underlyingSourceDict) {
+ if (underlyingSourceDict.start !== undefined) {
startAlgorithm = () =>
- underlyingSourceDict.start.call(underlyingSource, controller);
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.start,
+ [controller],
+ underlyingSource,
+ webidl.converters.any,
+ {
+ prefix:
+ "Failed to call 'startAlgorithm' on 'ReadableByteStreamController'",
+ },
+ );
}
- if ("pull" in underlyingSourceDict) {
+ if (underlyingSourceDict.pull !== undefined) {
pullAlgorithm = () =>
- underlyingSourceDict.pull.call(underlyingSource, controller);
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.pull,
+ [controller],
+ underlyingSource,
+ webidl.converters["Promise"],
+ {
+ prefix:
+ "Failed to call 'pullAlgorithm' on 'ReadableByteStreamController'",
+ returnsPromise: true,
+ },
+ );
}
- if ("cancel" in underlyingSourceDict) {
+ if (underlyingSourceDict.cancel !== undefined) {
cancelAlgorithm = (reason) =>
- underlyingSourceDict.cancel.call(underlyingSource, reason);
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.cancel,
+ [reason],
+ underlyingSource,
+ webidl.converters["Promise"],
+ {
+ prefix:
+ "Failed to call 'cancelAlgorithm' on 'ReadableByteStreamController'",
+ returnsPromise: true,
+ },
+ );
}
// 3.13.27.6 Let autoAllocateChunkSize be ? GetV(underlyingByteSource, "autoAllocateChunkSize").
/** @type {undefined} */
@@ -1839,24 +1759,53 @@
highWaterMark,
sizeAlgorithm,
) {
- const controller = new ReadableStreamDefaultController();
- /** @type {(controller: ReadableStreamDefaultController) => Promise} */
+ const controller = webidl.createBranded(ReadableStreamDefaultController);
+ /** @type {() => Promise} */
let startAlgorithm = () => undefined;
- /** @type {(controller: ReadableStreamDefaultController) => Promise} */
+ /** @type {() => Promise} */
let pullAlgorithm = () => resolvePromiseWith(undefined);
/** @type {(reason?: any) => Promise} */
let cancelAlgorithm = () => resolvePromiseWith(undefined);
- if ("start" in underlyingSourceDict) {
+ if (underlyingSourceDict.start !== undefined) {
startAlgorithm = () =>
- underlyingSourceDict.start.call(underlyingSource, controller);
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.start,
+ [controller],
+ underlyingSource,
+ webidl.converters.any,
+ {
+ prefix:
+ "Failed to call 'startAlgorithm' on 'ReadableStreamDefaultController'",
+ },
+ );
}
- if ("pull" in underlyingSourceDict) {
+ if (underlyingSourceDict.pull !== undefined) {
pullAlgorithm = () =>
- underlyingSourceDict.pull.call(underlyingSource, controller);
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.pull,
+ [controller],
+ underlyingSource,
+ webidl.converters["Promise"],
+ {
+ prefix:
+ "Failed to call 'pullAlgorithm' on 'ReadableStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
- if ("cancel" in underlyingSourceDict) {
+ if (underlyingSourceDict.cancel !== undefined) {
cancelAlgorithm = (reason) =>
- underlyingSourceDict.cancel.call(underlyingSource, reason);
+ webidl.invokeCallbackFunction(
+ underlyingSourceDict.cancel,
+ [reason],
+ underlyingSource,
+ webidl.converters["Promise"],
+ {
+ prefix:
+ "Failed to call 'cancelAlgorithm' on 'ReadableStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
setUpReadableStreamDefaultController(
stream,
@@ -1916,7 +1865,7 @@
transformerDict,
) {
/** @type {TransformStreamDefaultController} */
- const controller = new TransformStreamDefaultController();
+ const controller = webidl.createBranded(TransformStreamDefaultController);
/** @type {(chunk: O, controller: TransformStreamDefaultController) => Promise} */
let transformAlgorithm = (chunk) => {
try {
@@ -1928,13 +1877,33 @@
};
/** @type {(controller: TransformStreamDefaultController) => Promise} */
let flushAlgorithm = () => resolvePromiseWith(undefined);
- if ("transform" in transformerDict) {
+ if (transformerDict.transform !== undefined) {
transformAlgorithm = (chunk, controller) =>
- transformerDict.transform.call(transformer, chunk, controller);
+ webidl.invokeCallbackFunction(
+ transformerDict.transform,
+ [chunk, controller],
+ transformer,
+ webidl.converters["Promise"],
+ {
+ prefix:
+ "Failed to call 'transformAlgorithm' on 'TransformStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
- if ("flush" in transformerDict) {
+ if (transformerDict.flush !== undefined) {
flushAlgorithm = (controller) =>
- transformerDict.flush.call(transformer, controller);
+ webidl.invokeCallbackFunction(
+ transformerDict.flush,
+ [controller],
+ transformer,
+ webidl.converters["Promise"],
+ {
+ prefix:
+ "Failed to call 'flushAlgorithm' on 'TransformStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
setUpTransformStreamDefaultController(
stream,
@@ -2008,27 +1977,69 @@
highWaterMark,
sizeAlgorithm,
) {
- const controller = new WritableStreamDefaultController();
+ const controller = webidl.createBranded(WritableStreamDefaultController);
+ /** @type {(controller: WritableStreamDefaultController) => any} */
let startAlgorithm = () => undefined;
- /** @type {(chunk: W) => Promise} */
+ /** @type {(chunk: W, controller: WritableStreamDefaultController) => Promise} */
let writeAlgorithm = () => resolvePromiseWith(undefined);
let closeAlgorithm = () => resolvePromiseWith(undefined);
/** @type {(reason?: any) => Promise} */
let abortAlgorithm = () => resolvePromiseWith(undefined);
- if ("start" in underlyingSinkDict) {
+
+ if (underlyingSinkDict.start !== undefined) {
startAlgorithm = () =>
- underlyingSinkDict.start.call(underlyingSink, controller);
+ webidl.invokeCallbackFunction(
+ underlyingSinkDict.start,
+ [controller],
+ underlyingSink,
+ webidl.converters.any,
+ {
+ prefix:
+ "Failed to call 'startAlgorithm' on 'WritableStreamDefaultController'",
+ },
+ );
}
- if ("write" in underlyingSinkDict) {
+ if (underlyingSinkDict.write !== undefined) {
writeAlgorithm = (chunk) =>
- underlyingSinkDict.write.call(underlyingSink, chunk, controller);
+ webidl.invokeCallbackFunction(
+ underlyingSinkDict.write,
+ [chunk, controller],
+ underlyingSink,
+ webidl.converters["Promise"],
+ {
+ prefix:
+ "Failed to call 'writeAlgorithm' on 'WritableStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
- if ("close" in underlyingSinkDict) {
- closeAlgorithm = () => underlyingSinkDict.close.call(underlyingSink);
+ if (underlyingSinkDict.close !== undefined) {
+ closeAlgorithm = () =>
+ webidl.invokeCallbackFunction(
+ underlyingSinkDict.close,
+ [],
+ underlyingSink,
+ webidl.converters["Promise"],
+ {
+ prefix:
+ "Failed to call 'closeAlgorithm' on 'WritableStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
- if ("abort" in underlyingSinkDict) {
+ if (underlyingSinkDict.abort !== undefined) {
abortAlgorithm = (reason) =>
- underlyingSinkDict.abort.call(underlyingSink, reason);
+ webidl.invokeCallbackFunction(
+ underlyingSinkDict.abort,
+ [reason],
+ underlyingSink,
+ webidl.converters["Promise"],
+ {
+ prefix:
+ "Failed to call 'abortAlgorithm' on 'WritableStreamDefaultController'",
+ returnsPromise: true,
+ },
+ );
}
setUpWritableStreamDefaultController(
stream,
@@ -2955,30 +2966,45 @@
}, asyncIteratorPrototype);
class ByteLengthQueuingStrategy {
- /** @type {number} */
- highWaterMark;
-
/** @param {{ highWaterMark: number }} init */
constructor(init) {
- if (
- typeof init !== "object" || init === null || !("highWaterMark" in init)
- ) {
- throw new TypeError(
- "init must be an object that contains a property named highWaterMark",
- );
- }
- const { highWaterMark } = 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 = Number(highWaterMark);
+ this[_highWaterMark] = init.highWaterMark;
+ }
+
+ /** @returns {number} */
+ get highWaterMark() {
+ webidl.assertBranded(this, ByteLengthQueuingStrategy);
+ return this[_highWaterMark];
}
/** @returns {(chunk: ArrayBufferView) => number} */
get size() {
+ webidl.assertBranded(this, ByteLengthQueuingStrategy);
initializeByteLengthSizeFunction(this[_globalObject]);
return byteSizeFunctionWeakMap.get(this[_globalObject]);
}
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({ highWaterMark: this.highWaterMark, size: this.size })
+ }`;
+ }
+
+ get [Symbol.toStringTag]() {
+ return "ByteLengthQueuingStrategy";
+ }
}
+ webidl.configurePrototype(ByteLengthQueuingStrategy);
+
/** @type {WeakMap number>} */
const byteSizeFunctionWeakMap = new WeakMap();
@@ -2992,30 +3018,45 @@
}
class CountQueuingStrategy {
- /** @type {number} */
- highWaterMark;
-
/** @param {{ highWaterMark: number }} init */
constructor(init) {
- if (
- typeof init !== "object" || init === null || !("highWaterMark" in init)
- ) {
- throw new TypeError(
- "init must be an object that contains a property named highWaterMark",
- );
- }
- const { highWaterMark } = 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 = Number(highWaterMark);
+ this[_highWaterMark] = init.highWaterMark;
+ }
+
+ /** @returns {number} */
+ get highWaterMark() {
+ webidl.assertBranded(this, CountQueuingStrategy);
+ return this[_highWaterMark];
}
/** @returns {(chunk: any) => 1} */
get size() {
+ webidl.assertBranded(this, CountQueuingStrategy);
initializeCountSizeFunction(this[_globalObject]);
return countSizeFunctionWeakMap.get(this[_globalObject]);
}
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({ highWaterMark: this.highWaterMark, size: this.size })
+ }`;
+ }
+
+ get [Symbol.toStringTag]() {
+ return "CountQueuingStrategy";
+ }
}
+ webidl.configurePrototype(CountQueuingStrategy);
+
/** @type {WeakMap 1>} */
const countSizeFunctionWeakMap = new WeakMap();
@@ -3048,13 +3089,31 @@
* @param {UnderlyingSource=} underlyingSource
* @param {QueuingStrategy=} strategy
*/
- constructor(underlyingSource, strategy = {}) {
- const underlyingSourceDict = convertUnderlyingSource(underlyingSource);
+ constructor(underlyingSource = undefined, strategy = {}) {
+ const prefix = "Failed to construct 'ReadableStream'";
+ if (underlyingSource !== undefined) {
+ underlyingSource = webidl.converters.object(underlyingSource, {
+ prefix,
+ context: "Argument 1",
+ });
+ }
+ strategy = webidl.converters.QueuingStrategy(strategy, {
+ prefix,
+ context: "Argument 2",
+ });
+ this[webidl.brand] = webidl.brand;
+ if (underlyingSource === undefined) {
+ underlyingSource = null;
+ }
+ const underlyingSourceDict = webidl.converters.UnderlyingSource(
+ underlyingSource,
+ { prefix, context: "underlyingSource" },
+ );
initializeReadableStream(this);
if (underlyingSourceDict.type === "bytes") {
if (strategy.size !== undefined) {
throw new RangeError(
- `When underlying source is "bytes", strategy.size must be undefined.`,
+ `${prefix}: When underlying source is "bytes", strategy.size must be undefined.`,
);
}
const highWaterMark = extractHighWaterMark(strategy, 0);
@@ -3081,6 +3140,7 @@
/** @returns {boolean} */
get locked() {
+ webidl.assertBranded(this, ReadableStream);
return isReadableStreamLocked(this);
}
@@ -3088,7 +3148,15 @@
* @param {any=} reason
* @returns {Promise}
*/
- cancel(reason) {
+ cancel(reason = undefined) {
+ try {
+ webidl.assertBranded(this, ReadableStream);
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
+ }
+ } catch (err) {
+ return Promise.reject(err);
+ }
if (isReadableStreamLocked(this)) {
Promise.reject(new TypeError("Cannot cancel a locked ReadableStream."));
}
@@ -3109,23 +3177,18 @@
* @returns {ReadableStreamDefaultReader}
*/
getReader(options = {}) {
- if (typeof options !== "object") {
- throw new TypeError("options must be an object");
- }
- if (options === null) {
- options = {};
- }
- /** @type {any} */
- let { mode } = options;
+ webidl.assertBranded(this, ReadableStream);
+ const prefix = "Failed to execute 'getReader' on 'ReadableStream'";
+ options = webidl.converters.ReadableStreamGetReaderOptions(options, {
+ prefix,
+ context: "Argument 1",
+ });
+ const { mode } = options;
if (mode === undefined) {
return acquireReadableStreamDefaultReader(this);
}
- mode = String(mode);
- if (mode !== "byob") {
- throw new TypeError("Invalid mode.");
- }
// 3. Return ? AcquireReadableStreamBYOBReader(this).
- throw new RangeError(`Unsupported mode "${String(mode)}"`);
+ throw new RangeError(`${prefix}: Unsupported mode '${mode}'`);
}
/**
@@ -3134,36 +3197,32 @@
* @param {PipeOptions=} options
* @returns {ReadableStream}
*/
- pipeThrough(
- transform,
- { preventClose, preventAbort, preventCancel, signal } = {},
- ) {
- if (!isReadableStream(this)) {
- throw new TypeError("this must be a ReadableStream");
- }
- const { readable } = transform;
- if (!isReadableStream(readable)) {
- throw new TypeError("readable must be a ReadableStream");
- }
- const { writable } = transform;
- if (!isWritableStream(writable)) {
- throw new TypeError("writable must be a WritableStream");
- }
+ pipeThrough(transform, options = {}) {
+ webidl.assertBranded(this, ReadableStream);
+ 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 (signal !== undefined && !(signal instanceof AbortSignal)) {
- throw new TypeError("signal must be an AbortSignal");
- }
if (isWritableStreamLocked(writable)) {
throw new TypeError("Target WritableStream is already locked.");
}
const promise = readableStreamPipeTo(
this,
writable,
- Boolean(preventClose),
- Boolean(preventAbort),
- Boolean(preventCancel),
+ preventClose,
+ preventAbort,
+ preventCancel,
signal,
);
setPromiseIsHandledToTrue(promise);
@@ -3175,15 +3234,23 @@
* @param {PipeOptions=} options
* @returns {Promise}
*/
- pipeTo(
- destination,
- {
- preventClose = false,
- preventAbort = false,
- preventCancel = false,
- signal,
- } = {},
- ) {
+ pipeTo(destination, options = {}) {
+ try {
+ webidl.assertBranded(this, ReadableStream);
+ 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 Promise.reject(err);
+ }
+ const { preventClose, preventAbort, preventCancel, signal } = options;
if (isReadableStreamLocked(this)) {
return Promise.reject(
new TypeError("ReadableStream is already locked."),
@@ -3206,72 +3273,82 @@
/** @returns {[ReadableStream, ReadableStream]} */
tee() {
+ webidl.assertBranded(this, ReadableStream);
return readableStreamTee(this, false);
}
+ // TODO(lucacasonato): should be moved to webidl crate
/**
* @param {ReadableStreamIteratorOptions=} options
* @returns {AsyncIterableIterator}
*/
- [Symbol.asyncIterator]({ preventCancel } = {}) {
+ values(options = {}) {
+ webidl.assertBranded(this, ReadableStream);
+ const prefix = "Failed to execute 'values' on 'ReadableStream'";
+ options = webidl.converters.ReadableStreamIteratorOptions(options, {
+ prefix,
+ context: "Argument 1",
+ });
/** @type {AsyncIterableIterator} */
const iterator = Object.create(readableStreamAsyncIteratorPrototype);
const reader = acquireReadableStreamDefaultReader(this);
iterator[_reader] = reader;
- iterator[_preventCancel] = preventCancel;
+ iterator[_preventCancel] = options.preventCancel;
return iterator;
}
[Symbol.for("Deno.customInspect")](inspect) {
return `${this.constructor.name} ${inspect({ locked: this.locked })}`;
}
+
+ get [Symbol.toStringTag]() {
+ return "ReadableStream";
+ }
}
+ // TODO(lucacasonato): should be moved to webidl crate
+ ReadableStream.prototype[Symbol.asyncIterator] =
+ ReadableStream.prototype.values;
+ Object.defineProperty(ReadableStream.prototype, Symbol.asyncIterator, {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+ });
+
+ webidl.configurePrototype(ReadableStream);
+
function errorReadableStream(stream, e) {
readableStreamDefaultControllerError(stream[_controller], e);
}
/** @template R */
- class ReadableStreamGenericReader {
+ class ReadableStreamDefaultReader {
/** @type {Deferred} */
[_closedPromise];
/** @type {ReadableStream | undefined} */
[_stream];
-
- get closed() {
- return this[_closedPromise].promise;
- }
-
- /**
- * @param {any} reason
- * @returns {Promise}
- */
- cancel(reason) {
- if (this[_stream] === undefined) {
- return Promise.reject(
- new TypeError("Reader has no associated stream."),
- );
- }
- return readableStreamReaderGenericCancel(this, reason);
- }
- }
-
- /** @template R */
- class ReadableStreamDefaultReader extends ReadableStreamGenericReader {
/** @type {ReadRequest[]} */
[_readRequests];
/** @param {ReadableStream} stream */
constructor(stream) {
- if (!(stream instanceof ReadableStream)) {
- throw new TypeError("stream is not a ReadableStream");
- }
- super();
+ 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>} */
read() {
+ try {
+ webidl.assertBranded(this, ReadableStreamDefaultReader);
+ } catch (err) {
+ return Promise.reject(err);
+ }
if (this[_stream] === undefined) {
return Promise.reject(
new TypeError("Reader has no associated stream."),
@@ -3297,6 +3374,7 @@
/** @returns {void} */
releaseLock() {
+ webidl.assertBranded(this, ReadableStreamDefaultReader);
if (this[_stream] === undefined) {
return;
}
@@ -3308,11 +3386,48 @@
readableStreamReaderGenericRelease(this);
}
+ get closed() {
+ try {
+ webidl.assertBranded(this, ReadableStreamDefaultReader);
+ } catch (err) {
+ return Promise.reject(err);
+ }
+ return this[_closedPromise].promise;
+ }
+
+ /**
+ * @param {any} reason
+ * @returns {Promise}
+ */
+ cancel(reason = undefined) {
+ try {
+ webidl.assertBranded(this, ReadableStreamDefaultReader);
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
+ }
+ } catch (err) {
+ return Promise.reject(err);
+ }
+
+ if (this[_stream] === undefined) {
+ return Promise.reject(
+ new TypeError("Reader has no associated stream."),
+ );
+ }
+ return readableStreamReaderGenericCancel(this, reason);
+ }
+
[Symbol.for("Deno.customInspect")](inspect) {
return `${this.constructor.name} ${inspect({ closed: this.closed })}`;
}
+
+ get [Symbol.toStringTag]() {
+ return "ReadableStreamDefaultReader";
+ }
}
+ webidl.configurePrototype(ReadableStreamDefaultReader);
+
class ReadableByteStreamController {
/** @type {number | undefined} */
[_autoAllocateChunkSize];
@@ -3339,17 +3454,24 @@
/** @type {ReadableStream} */
[_stream];
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
get byobRequest() {
+ webidl.assertBranded(this, ReadableByteStreamController);
return undefined;
}
/** @returns {number | null} */
get desiredSize() {
+ webidl.assertBranded(this, ReadableByteStreamController);
return readableByteStreamControllerGetDesiredSize(this);
}
/** @returns {void} */
close() {
+ webidl.assertBranded(this, ReadableByteStreamController);
if (this[_closeRequested] === true) {
throw new TypeError("Closed already requested.");
}
@@ -3366,11 +3488,27 @@
* @returns {void}
*/
enqueue(chunk) {
+ webidl.assertBranded(this, ReadableByteStreamController);
+ 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 new TypeError("chunk must have a non-zero byteLength.");
+ throw webidl.makeException(TypeError, "length must be non-zero", {
+ prefix,
+ context: arg1,
+ });
}
if (chunk.buffer.byteLength === 0) {
- throw new TypeError("chunk's buffer must have a non-zero byteLength.");
+ throw webidl.makeException(
+ TypeError,
+ "buffer length must be non-zero",
+ { prefix, context: arg1 },
+ );
}
if (this[_closeRequested] === true) {
throw new TypeError(
@@ -3389,10 +3527,24 @@
* @param {any=} e
* @returns {void}
*/
- error(e) {
+ error(e = undefined) {
+ webidl.assertBranded(this, ReadableByteStreamController);
+ if (e !== undefined) {
+ e = webidl.converters.any(e);
+ }
readableByteStreamControllerError(this, e);
}
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({ desiredSize: this.desiredSize })
+ }`;
+ }
+
+ get [Symbol.toStringTag]() {
+ return "ReadableByteStreamController";
+ }
+
/**
* @param {any} reason
* @returns {Promise}
@@ -3433,6 +3585,8 @@
}
}
+ webidl.configurePrototype(ReadableByteStreamController);
+
/** @template R */
class ReadableStreamDefaultController {
/** @type {(reason: any) => Promise} */
@@ -3458,13 +3612,19 @@
/** @type {ReadableStream} */
[_stream];
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
/** @returns {number | null} */
get desiredSize() {
+ webidl.assertBranded(this, ReadableStreamDefaultController);
return readableStreamDefaultControllerGetDesiredSize(this);
}
/** @returns {void} */
close() {
+ webidl.assertBranded(this, ReadableStreamDefaultController);
if (readableStreamDefaultControllerCanCloseOrEnqueue(this) === false) {
throw new TypeError("The stream controller cannot close or enqueue.");
}
@@ -3475,7 +3635,11 @@
* @param {R} chunk
* @returns {void}
*/
- enqueue(chunk) {
+ enqueue(chunk = undefined) {
+ webidl.assertBranded(this, ReadableStreamDefaultController);
+ if (chunk !== undefined) {
+ chunk = webidl.converters.any(chunk);
+ }
if (readableStreamDefaultControllerCanCloseOrEnqueue(this) === false) {
throw new TypeError("The stream controller cannot close or enqueue.");
}
@@ -3486,10 +3650,24 @@
* @param {any=} e
* @returns {void}
*/
- error(e) {
+ error(e = undefined) {
+ webidl.assertBranded(this, ReadableStreamDefaultController);
+ if (e !== undefined) {
+ e = webidl.converters.any(e);
+ }
readableStreamDefaultControllerError(this, e);
}
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({ desiredSize: this.desiredSize })
+ }`;
+ }
+
+ get [Symbol.toStringTag]() {
+ return "ReadableStreamDefaultController";
+ }
+
/**
* @param {any} reason
* @returns {Promise}
@@ -3523,6 +3701,8 @@
}
}
+ webidl.configurePrototype(ReadableStreamDefaultController);
+
/**
* @template I
* @template O
@@ -3548,16 +3728,42 @@
* @param {QueuingStrategy} readableStrategy
*/
constructor(
- transformer = null,
+ transformer = undefined,
writableStrategy = {},
readableStrategy = {},
) {
- const transformerDict = convertTransformer(transformer);
- if (transformerDict.readableType) {
- throw new RangeError("readableType transformers not supported.");
+ const prefix = "Failed to construct 'TransformStream'";
+ if (transformer !== undefined) {
+ transformer = webidl.converters.object(transformer, {
+ prefix,
+ context: "Argument 1",
+ });
}
- if (transformerDict.writableType) {
- throw new RangeError("writableType transformers not supported.");
+ 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);
@@ -3578,9 +3784,18 @@
transformer,
transformerDict,
);
- if ("start" in transformerDict) {
+ if (transformerDict.start) {
startPromise.resolve(
- transformerDict.start.call(transformer, this[_controller]),
+ webidl.invokeCallbackFunction(
+ transformerDict.start,
+ [this[_controller]],
+ transformer,
+ webidl.converters.any,
+ {
+ prefix:
+ "Failed to call 'start' on 'TransformStreamDefaultController'",
+ },
+ ),
);
} else {
startPromise.resolve(undefined);
@@ -3589,11 +3804,13 @@
/** @returns {ReadableStream} */
get readable() {
+ webidl.assertBranded(this, TransformStream);
return this[_readable];
}
/** @returns {WritableStream} */
get writable() {
+ webidl.assertBranded(this, TransformStream);
return this[_writable];
}
@@ -3602,8 +3819,14 @@
inspect({ readable: this.readable, writable: this.writable })
}`;
}
+
+ get [Symbol.toStringTag]() {
+ return "TransformStream";
+ }
}
+ webidl.configurePrototype(TransformStream);
+
/** @template O */
class TransformStreamDefaultController {
/** @type {(controller: this) => Promise} */
@@ -3613,8 +3836,13 @@
/** @type {(chunk: O, controller: this) => Promise} */
[_transformAlgorithm];
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
/** @returns {number | null} */
get desiredSize() {
+ webidl.assertBranded(this, TransformStreamDefaultController);
const readableController = this[_stream][_readable][_controller];
return readableStreamDefaultControllerGetDesiredSize(
/** @type {ReadableStreamDefaultController} */ (readableController),
@@ -3625,7 +3853,11 @@
* @param {O} chunk
* @returns {void}
*/
- enqueue(chunk) {
+ enqueue(chunk = undefined) {
+ webidl.assertBranded(this, TransformStreamDefaultController);
+ if (chunk !== undefined) {
+ chunk = webidl.converters.any(chunk);
+ }
transformStreamDefaultControllerEnqueue(this, chunk);
}
@@ -3633,16 +3865,33 @@
* @param {any=} reason
* @returns {void}
*/
- error(reason) {
+ error(reason = undefined) {
+ webidl.assertBranded(this, TransformStreamDefaultController);
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
+ }
transformStreamDefaultControllerError(this, reason);
}
/** @returns {void} */
terminate() {
+ webidl.assertBranded(this, TransformStreamDefaultController);
transformStreamDefaultControllerTerminate(this);
}
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({ desiredSize: this.desiredSize })
+ }`;
+ }
+
+ get [Symbol.toStringTag]() {
+ return "TransformStreamDefaultController";
+ }
}
+ webidl.configurePrototype(TransformStreamDefaultController);
+
/** @template W */
class WritableStream {
/** @type {boolean} */
@@ -3672,11 +3921,29 @@
* @param {UnderlyingSink=} underlyingSink
* @param {QueuingStrategy=} strategy
*/
- constructor(underlyingSink = null, strategy = {}) {
- const underlyingSinkDict = convertUnderlyingSink(underlyingSink);
+ 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(
- 'WritableStream does not support "type" in the underlying sink.',
+ `${prefix}: WritableStream does not support 'type' in the underlying sink.`,
);
}
initializeWritableStream(this);
@@ -3693,6 +3960,7 @@
/** @returns {boolean} */
get locked() {
+ webidl.assertBranded(this, WritableStream);
return isWritableStreamLocked(this);
}
@@ -3700,7 +3968,15 @@
* @param {any=} reason
* @returns {Promise}
*/
- abort(reason) {
+ abort(reason = undefined) {
+ try {
+ webidl.assertBranded(this, WritableStream);
+ } catch (err) {
+ return Promise.reject(err);
+ }
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
+ }
if (isWritableStreamLocked(this)) {
return Promise.reject(
new TypeError(
@@ -3713,6 +3989,11 @@
/** @returns {Promise} */
close() {
+ try {
+ webidl.assertBranded(this, WritableStream);
+ } catch (err) {
+ return Promise.reject(err);
+ }
if (isWritableStreamLocked(this)) {
return Promise.reject(
new TypeError(
@@ -3730,14 +4011,21 @@
/** @returns {WritableStreamDefaultWriter} */
getWriter() {
+ webidl.assertBranded(this, WritableStream);
return acquireWritableStreamDefaultWriter(this);
}
[Symbol.for("Deno.customInspect")](inspect) {
return `${this.constructor.name} ${inspect({ locked: this.locked })}`;
}
+
+ get [Symbol.toStringTag]() {
+ return "WritableStream";
+ }
}
+ webidl.configurePrototype(WritableStream);
+
/** @template W */
class WritableStreamDefaultWriter {
/** @type {Deferred} */
@@ -3749,17 +4037,33 @@
/** @type {WritableStream} */
[_stream];
+ /**
+ * @param {WritableStream} 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} */
get closed() {
+ try {
+ webidl.assertBranded(this, WritableStreamDefaultWriter);
+ } catch (err) {
+ return Promise.reject(err);
+ }
return this[_closedPromise].promise;
}
/** @returns {number} */
get desiredSize() {
+ webidl.assertBranded(this, WritableStreamDefaultWriter);
if (this[_stream] === undefined) {
throw new TypeError(
"A writable stream is not associated with the writer.",
@@ -3770,6 +4074,11 @@
/** @returns {Promise} */
get ready() {
+ try {
+ webidl.assertBranded(this, WritableStreamDefaultWriter);
+ } catch (err) {
+ return Promise.reject(err);
+ }
return this[_readyPromise].promise;
}
@@ -3777,7 +4086,15 @@
* @param {any} reason
* @returns {Promise}
*/
- abort(reason) {
+ abort(reason = undefined) {
+ try {
+ webidl.assertBranded(this, WritableStreamDefaultWriter);
+ } catch (err) {
+ return Promise.reject(err);
+ }
+ if (reason !== undefined) {
+ reason = webidl.converters.any(reason);
+ }
if (this[_stream] === undefined) {
return Promise.reject(
new TypeError("A writable stream is not associated with the writer."),
@@ -3788,6 +4105,11 @@
/** @returns {Promise} */
close() {
+ try {
+ webidl.assertBranded(this, WritableStreamDefaultWriter);
+ } catch (err) {
+ return Promise.reject(err);
+ }
const stream = this[_stream];
if (stream === undefined) {
return Promise.reject(
@@ -3804,6 +4126,7 @@
/** @returns {void} */
releaseLock() {
+ webidl.assertBranded(this, WritableStreamDefaultWriter);
const stream = this[_stream];
if (stream === undefined) {
return;
@@ -3816,7 +4139,15 @@
* @param {W} chunk
* @returns {Promise}
*/
- write(chunk) {
+ write(chunk = undefined) {
+ try {
+ webidl.assertBranded(this, WritableStreamDefaultWriter);
+ if (chunk !== undefined) {
+ chunk = webidl.converters.any(chunk);
+ }
+ } catch (err) {
+ return Promise.reject(err);
+ }
if (this[_stream] === undefined) {
return Promise.reject(
new TypeError("A writable stream is not associate with the writer."),
@@ -3824,8 +4155,24 @@
}
return writableStreamDefaultWriterWrite(this, chunk);
}
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ closed: this.closed,
+ desiredSize: this.desiredSize,
+ ready: this.ready,
+ })
+ }`;
+ }
+
+ get [Symbol.toStringTag]() {
+ return "WritableStreamDefaultWriter";
+ }
}
+ webidl.configurePrototype(WritableStreamDefaultWriter);
+
/** @template W */
class WritableStreamDefaultController {
/** @type {(reason?: any) => Promise} */
@@ -3847,11 +4194,19 @@
/** @type {(chunk: W, controller: this) => Promise} */
[_writeAlgorithm];
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
/**
* @param {any=} e
* @returns {void}
*/
- error(e) {
+ error(e = undefined) {
+ webidl.assertBranded(this, WritableStreamDefaultController);
+ if (e !== undefined) {
+ e = webidl.converters.any(e);
+ }
const state = this[_stream][_state];
if (state !== "writable") {
return;
@@ -3859,6 +4214,14 @@
writableStreamDefaultControllerError(this, e);
}
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${inspect({})}`;
+ }
+
+ get [Symbol.toStringTag]() {
+ return "WritableStreamDefaultController";
+ }
+
/**
* @param {any=} reason
* @returns {Promise}
@@ -3874,6 +4237,161 @@
}
}
+ webidl.configurePrototype(WritableStreamDefaultController);
+
+ webidl.converters.ReadableStream = webidl
+ .createInterfaceConverter("ReadableStream", ReadableStream);
+ webidl.converters.WritableStream = webidl
+ .createInterfaceConverter("WritableStream", WritableStream);
+
+ 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 },
+ ]);
+
window.__bootstrap.streams = {
// Non-Public
isReadableStreamDisturbed,
@@ -3886,7 +4404,9 @@
TransformStream,
WritableStream,
WritableStreamDefaultWriter,
+ WritableStreamDefaultController,
ReadableByteStreamController,
+ ReadableStreamDefaultController,
TransformStreamDefaultController,
};
})(this);
diff --git a/extensions/web/06_streams_types.d.ts b/extensions/web/06_streams_types.d.ts
index a4c54363f5..61621c0031 100644
--- a/extensions/web/06_streams_types.d.ts
+++ b/extensions/web/06_streams_types.d.ts
@@ -40,6 +40,12 @@ interface VoidFunction {
(): void;
}
+interface ReadableStreamGenericReader {
+ readonly closed: Promise;
+ // deno-lint-ignore no-explicit-any
+ cancel(reason?: any): Promise;
+}
+
// ** Ambient Definitions and Interfaces not provided by fetch **
declare function queueMicrotask(callback: VoidFunction): void;
diff --git a/extensions/webidl/00_webidl.js b/extensions/webidl/00_webidl.js
index 49f5861353..a54d2fe6ef 100644
--- a/extensions/webidl/00_webidl.js
+++ b/extensions/webidl/00_webidl.js
@@ -566,6 +566,7 @@
converters["sequence"] = createSequenceConverter(
converters["double"],
);
+ converters["Promise"] = createPromiseConverter(() => undefined);
function requiredArguments(length, required, opts = {}) {
if (length < required) {
@@ -578,11 +579,6 @@
}
}
- function isEmptyObject(V) {
- for (const _ in V) return false;
- return true;
- }
-
function createDictionaryConverter(name, ...dictionaries) {
let hasRequiredKey = false;
const allMembers = [];
@@ -642,10 +638,8 @@
const idlDict = { ...defaultValues };
- // NOTE: fast path Null and Undefined and empty objects.
- if (
- (V === undefined || V === null || isEmptyObject(V)) && !hasRequiredKey
- ) {
+ // NOTE: fast path Null and Undefined.
+ if ((V === undefined || V === null) && !hasRequiredKey) {
return idlDict;
}
@@ -774,6 +768,31 @@
};
}
+ function createPromiseConverter(converter) {
+ return (V, opts) => Promise.resolve(V).then((V) => converter(V, opts));
+ }
+
+ function invokeCallbackFunction(
+ callable,
+ args,
+ thisArg,
+ returnValueConverter,
+ opts,
+ ) {
+ try {
+ const rv = Reflect.apply(callable, thisArg, args);
+ return returnValueConverter(rv, {
+ prefix: opts.prefix,
+ context: "return value",
+ });
+ } catch (err) {
+ if (opts.returnsPromise === true) {
+ return Promise.reject(err);
+ }
+ throw err;
+ }
+ }
+
const brand = Symbol("[[webidl.brand]]");
function createInterfaceConverter(name, prototype) {
@@ -927,6 +946,8 @@
createNullableConverter,
createSequenceConverter,
createRecordConverter,
+ createPromiseConverter,
+ invokeCallbackFunction,
createInterfaceConverter,
brand,
createBranded,
diff --git a/extensions/webidl/internal.d.ts b/extensions/webidl/internal.d.ts
index 2d23f0ed2d..4d0f1ad45a 100644
--- a/extensions/webidl/internal.d.ts
+++ b/extensions/webidl/internal.d.ts
@@ -248,6 +248,24 @@ declare namespace globalThis {
converter: (v: any, opts: ValueConverterOpts) => T,
): (v: any, opts: ValueConverterOpts) => T[];
+ /**
+ * Create a converter that converts a Promise of the inner type.
+ */
+ declare function createPromiseConverter(
+ converter: (v: any, opts: ValueConverterOpts) => T,
+ ): (v: any, opts: ValueConverterOpts) => Promise;
+
+ /**
+ * Invoke a callback function.
+ */
+ declare function invokeCallbackFunction(
+ callable: (...args: any) => any,
+ args: any[],
+ thisArg: any,
+ returnValueConverter: (v: any, opts: ValueConverterOpts) => T,
+ opts: ConverterOpts & { returnsPromise?: boolean },
+ ): T;
+
/**
* Throw an illegal constructor error.
*/
diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js
index aac6fc0ead..633750675c 100644
--- a/runtime/js/99_main.js
+++ b/runtime/js/99_main.js
@@ -304,9 +304,15 @@ delete Object.prototype.__proto__;
WritableStreamDefaultWriter: util.nonEnumerable(
streams.WritableStreamDefaultWriter,
),
+ WritableStreamDefaultController: util.nonEnumerable(
+ streams.WritableStreamDefaultController,
+ ),
ReadableByteStreamController: util.nonEnumerable(
streams.ReadableByteStreamController,
),
+ ReadableStreamDefaultController: util.nonEnumerable(
+ streams.ReadableStreamDefaultController,
+ ),
TransformStreamDefaultController: util.nonEnumerable(
streams.TransformStreamDefaultController,
),
diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json
index f3aa5997c0..2c1690181d 100644
--- a/tools/wpt/expectation.json
+++ b/tools/wpt/expectation.json
@@ -256,23 +256,6 @@
},
"streams": {
"idlharness.any.html": [
- "ReadableStream interface object length",
- "ReadableStream interface: attribute locked",
- "ReadableStream interface: operation cancel(optional any)",
- "ReadableStream interface: operation getReader(optional ReadableStreamGetReaderOptions)",
- "ReadableStream interface: operation pipeThrough(ReadableWritablePair, optional StreamPipeOptions)",
- "ReadableStream interface: operation pipeTo(WritableStream, optional StreamPipeOptions)",
- "ReadableStream interface: operation tee()",
- "ReadableStream interface: async iterable",
- "Stringification of new ReadableStream()",
- "ReadableStream interface: calling pipeTo(WritableStream, optional StreamPipeOptions) on new ReadableStream() with too few arguments must throw TypeError",
- "ReadableStreamDefaultReader interface: existence and properties of interface object",
- "ReadableStreamDefaultReader interface: existence and properties of interface prototype object",
- "ReadableStreamDefaultReader interface: operation read()",
- "ReadableStreamDefaultReader interface: operation releaseLock()",
- "ReadableStreamDefaultReader interface: attribute closed",
- "ReadableStreamDefaultReader interface: operation cancel(optional any)",
- "Stringification of (new ReadableStream()).getReader()",
"ReadableStreamBYOBReader interface: existence and properties of interface object",
"ReadableStreamBYOBReader interface object length",
"ReadableStreamBYOBReader interface object name",
@@ -291,25 +274,6 @@
"ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property \"closed\" with the proper type",
"ReadableStreamBYOBReader interface: (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) must inherit property \"cancel(optional any)\" with the proper type",
"ReadableStreamBYOBReader interface: calling cancel(optional any) on (new ReadableStream({ type: 'bytes' })).getReader({ mode: 'byob' }) with too few arguments must throw TypeError",
- "ReadableStreamDefaultController interface: existence and properties of interface object",
- "ReadableStreamDefaultController interface object length",
- "ReadableStreamDefaultController interface object name",
- "ReadableStreamDefaultController interface: existence and properties of interface prototype object",
- "ReadableStreamDefaultController interface: existence and properties of interface prototype object's \"constructor\" property",
- "ReadableStreamDefaultController interface: existence and properties of interface prototype object's @@unscopables property",
- "ReadableStreamDefaultController interface: attribute desiredSize",
- "ReadableStreamDefaultController interface: operation close()",
- "ReadableStreamDefaultController interface: operation enqueue(optional any)",
- "ReadableStreamDefaultController interface: operation error(optional any)",
- "ReadableStreamDefaultController must be primary interface of self.readableStreamDefaultController",
- "Stringification of self.readableStreamDefaultController",
- "ReadableByteStreamController interface: existence and properties of interface object",
- "ReadableByteStreamController interface: attribute byobRequest",
- "ReadableByteStreamController interface: attribute desiredSize",
- "ReadableByteStreamController interface: operation close()",
- "ReadableByteStreamController interface: operation enqueue(ArrayBufferView)",
- "ReadableByteStreamController interface: operation error(optional any)",
- "Stringification of self.readableByteStreamController",
"ReadableByteStreamController interface: self.readableByteStreamController must inherit property \"byobRequest\" with the proper type",
"ReadableStreamBYOBRequest interface: existence and properties of interface object",
"ReadableStreamBYOBRequest interface object length",
@@ -326,109 +290,20 @@
"ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property \"respond(unsigned long long)\" with the proper type",
"ReadableStreamBYOBRequest interface: calling respond(unsigned long long) on self.readableStreamByobRequest with too few arguments must throw TypeError",
"ReadableStreamBYOBRequest interface: self.readableStreamByobRequest must inherit property \"respondWithNewView(ArrayBufferView)\" with the proper type",
- "ReadableStreamBYOBRequest interface: calling respondWithNewView(ArrayBufferView) on self.readableStreamByobRequest with too few arguments must throw TypeError",
- "WritableStream interface: attribute locked",
- "WritableStream interface: operation abort(optional any)",
- "WritableStream interface: operation close()",
- "WritableStream interface: operation getWriter()",
- "Stringification of new WritableStream()",
- "WritableStreamDefaultWriter interface: attribute closed",
- "WritableStreamDefaultWriter interface: attribute desiredSize",
- "WritableStreamDefaultWriter interface: attribute ready",
- "WritableStreamDefaultWriter interface: operation abort(optional any)",
- "WritableStreamDefaultWriter interface: operation close()",
- "WritableStreamDefaultWriter interface: operation releaseLock()",
- "WritableStreamDefaultWriter interface: operation write(optional any)",
- "Stringification of (new WritableStream()).getWriter()",
- "WritableStreamDefaultController interface: existence and properties of interface object",
- "WritableStreamDefaultController interface object length",
- "WritableStreamDefaultController interface object name",
- "WritableStreamDefaultController interface: existence and properties of interface prototype object",
- "WritableStreamDefaultController interface: existence and properties of interface prototype object's \"constructor\" property",
- "WritableStreamDefaultController interface: existence and properties of interface prototype object's @@unscopables property",
- "WritableStreamDefaultController interface: operation error(optional any)",
- "WritableStreamDefaultController must be primary interface of self.writableStreamDefaultController",
- "Stringification of self.writableStreamDefaultController",
- "TransformStream interface: attribute readable",
- "TransformStream interface: attribute writable",
- "Stringification of new TransformStream()",
- "TransformStreamDefaultController interface: existence and properties of interface object",
- "TransformStreamDefaultController interface: attribute desiredSize",
- "TransformStreamDefaultController interface: operation enqueue(optional any)",
- "TransformStreamDefaultController interface: operation error(optional any)",
- "TransformStreamDefaultController interface: operation terminate()",
- "Stringification of self.transformStreamDefaultController",
- "ByteLengthQueuingStrategy interface: attribute highWaterMark",
- "ByteLengthQueuingStrategy interface: attribute size",
- "Stringification of new ByteLengthQueuingStrategy({ highWaterMark: 5 })",
- "ByteLengthQueuingStrategy interface: new ByteLengthQueuingStrategy({ highWaterMark: 5 }) must inherit property \"highWaterMark\" with the proper type",
- "CountQueuingStrategy interface: attribute highWaterMark",
- "CountQueuingStrategy interface: attribute size",
- "Stringification of new CountQueuingStrategy({ highWaterMark: 5 })",
- "CountQueuingStrategy interface: new CountQueuingStrategy({ highWaterMark: 5 }) must inherit property \"highWaterMark\" with the proper type"
+ "ReadableStreamBYOBRequest interface: calling respondWithNewView(ArrayBufferView) on self.readableStreamByobRequest with too few arguments must throw TypeError"
],
"piping": {
- "abort.any.html": [
- "a signal argument 'null' should cause pipeTo() to reject",
- "a signal argument 'AbortSignal' should cause pipeTo() to reject",
- "a signal argument 'true' should cause pipeTo() to reject",
- "a signal argument '-1' should cause pipeTo() to reject",
- "a signal argument '[object AbortSignal]' should cause pipeTo() to reject"
- ],
- "close-propagation-backward.any.html": [
- "Closing must be propagated backward: starts closed; preventCancel = null (falsy); fulfilled cancel promise",
- "Closing must be propagated backward: starts closed; preventCancel = 0 (falsy); fulfilled cancel promise",
- "Closing must be propagated backward: starts closed; preventCancel = -0 (falsy); fulfilled cancel promise",
- "Closing must be propagated backward: starts closed; preventCancel = NaN (falsy); fulfilled cancel promise",
- "Closing must be propagated backward: starts closed; preventCancel = (falsy); fulfilled cancel promise",
- "Closing must be propagated backward: starts closed; preventCancel = a (truthy)",
- "Closing must be propagated backward: starts closed; preventCancel = 1 (truthy)",
- "Closing must be propagated backward: starts closed; preventCancel = Symbol() (truthy)",
- "Closing must be propagated backward: starts closed; preventCancel = [object Object] (truthy)"
- ],
- "close-propagation-forward.any.html": [
- "Closing must be propagated forward: starts closed; preventClose = null (falsy); fulfilled close promise",
- "Closing must be propagated forward: starts closed; preventClose = 0 (falsy); fulfilled close promise",
- "Closing must be propagated forward: starts closed; preventClose = -0 (falsy); fulfilled close promise",
- "Closing must be propagated forward: starts closed; preventClose = NaN (falsy); fulfilled close promise",
- "Closing must be propagated forward: starts closed; preventClose = (falsy); fulfilled close promise",
- "Closing must be propagated forward: starts closed; preventClose = a (truthy)",
- "Closing must be propagated forward: starts closed; preventClose = 1 (truthy)",
- "Closing must be propagated forward: starts closed; preventClose = Symbol() (truthy)",
- "Closing must be propagated forward: starts closed; preventClose = [object Object] (truthy)"
- ],
- "error-propagation-backward.any.html": [
- "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = null (falsy); fulfilled cancel promise",
- "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = 0 (falsy); fulfilled cancel promise",
- "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = -0 (falsy); fulfilled cancel promise",
- "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = NaN (falsy); fulfilled cancel promise",
- "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = (falsy); fulfilled cancel promise",
- "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = a (truthy)",
- "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = 1 (truthy)",
- "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = Symbol() (truthy)",
- "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = [object Object] (truthy)"
- ],
- "error-propagation-forward.any.html": [
- "Errors must be propagated forward: starts errored; preventAbort = null (falsy); fulfilled abort promise",
- "Errors must be propagated forward: starts errored; preventAbort = 0 (falsy); fulfilled abort promise",
- "Errors must be propagated forward: starts errored; preventAbort = -0 (falsy); fulfilled abort promise",
- "Errors must be propagated forward: starts errored; preventAbort = NaN (falsy); fulfilled abort promise",
- "Errors must be propagated forward: starts errored; preventAbort = (falsy); fulfilled abort promise",
- "Errors must be propagated forward: starts errored; preventAbort = a (truthy)",
- "Errors must be propagated forward: starts errored; preventAbort = 1 (truthy)",
- "Errors must be propagated forward: starts errored; preventAbort = Symbol() (truthy)",
- "Errors must be propagated forward: starts errored; preventAbort = [object Object] (truthy)"
- ],
+ "abort.any.html": true,
+ "close-propagation-backward.any.html": true,
+ "close-propagation-forward.any.html": true,
+ "error-propagation-backward.any.html": true,
+ "error-propagation-forward.any.html": true,
"flow-control.any.html": true,
- "general.any.html": [
- "pipeTo must check the brand of its ReadableStream this value",
- "pipeTo must check the brand of its WritableStream argument",
- "pipeTo() promise should resolve if null is passed"
- ],
+ "general.any.html": true,
"multiple-propagation.any.html": true,
"pipe-through.any.html": true,
"then-interception.any.html": true,
- "throwing-options.any.html": false,
+ "throwing-options.any.html": true,
"transform-streams.any.html": true
},
"queuing-strategies.any.html": true,
@@ -515,32 +390,20 @@
"ReadableStream with byte source: respondWithNewView() with a transferred non-zero-length view (in the readable state)",
"ReadableStream with byte source: respondWithNewView() with a transferred zero-length view (in the closed state)"
],
- "non-transferable-buffers.any.html": false
+ "non-transferable-buffers.any.html": false,
+ "enqueue-with-detached-buffer.window.html": false
},
"readable-streams": {
"async-iterator.any.html": [
- "Async iterator instances should have the correct list of properties",
- "values() throws if there's already a lock",
- "return() should unlock the stream synchronously when preventCancel = false",
- "return() should unlock the stream synchronously when preventCancel = true",
"Async-iterating a pull source manually",
- "Cancellation behavior when throwing inside loop body; preventCancel = false",
- "Cancellation behavior when throwing inside loop body; preventCancel = true",
- "Cancellation behavior when breaking inside loop body; preventCancel = false",
- "Cancellation behavior when breaking inside loop body; preventCancel = true",
- "Cancellation behavior when returning inside loop body; preventCancel = false",
- "Cancellation behavior when returning inside loop body; preventCancel = true",
- "Cancellation behavior when manually calling return(); preventCancel = false",
- "Cancellation behavior when manually calling return(); preventCancel = true",
"next() rejects if the stream errors",
"return() does not rejects if the stream has not errored yet",
- "return() rejects if the stream has errored",
"next() that succeeds; next() that reports an error; next()"
],
"bad-strategies.any.html": true,
"bad-underlying-sources.any.html": true,
"cancel.any.html": false,
- "constructor.any.html": false,
+ "constructor.any.html": true,
"count-queuing-strategy-integration.any.html": true,
"default-reader.any.html": true,
"floating-point-total-queue-size.any.html": true,
@@ -573,19 +436,11 @@
},
"writable-streams": {
"aborting.any.html": false,
- "bad-strategies.any.html": [
- "reject any non-function value for strategy.size",
- "Writable stream: invalid size beats invalid highWaterMark"
- ],
+ "bad-strategies.any.html": true,
"bad-underlying-sinks.any.html": true,
"byte-length-queuing-strategy.any.html": true,
"close.any.html": false,
- "constructor.any.html": [
- "underlyingSink argument should be converted after queuingStrategy argument",
- "WritableStreamDefaultController constructor should throw",
- "WritableStreamDefaultController constructor should throw when passed an initialised WritableStream",
- "WritableStreamDefaultWriter should throw unless passed a WritableStream"
- ],
+ "constructor.any.html": true,
"count-queuing-strategy.any.html": true,
"error.any.html": true,
"floating-point-total-queue-size.any.html": true,
@@ -594,6 +449,10 @@
"reentrant-strategy.any.html": true,
"start.any.html": true,
"write.any.html": true
+ },
+ "queuing-strategies-size-function-per-global.window.html": false,
+ "transferable": {
+ "deserialize-error.window.html": false
}
},
"user-timing": {
@@ -951,6 +810,7 @@
"stream-safe-creation.any.html": [
"throwing Object.prototype.start accessor should not affect stream creation by 'fetch'",
"Object.prototype.start accessor returning invalid value should not affect stream creation by 'fetch'",
+ "throwing Object.prototype.type accessor should not affect stream creation by 'fetch'",
"throwing Object.prototype.size accessor should not affect stream creation by 'fetch'",
"Object.prototype.size accessor returning invalid value should not affect stream creation by 'fetch'",
"throwing Object.prototype.highWaterMark accessor should not affect stream creation by 'fetch'",