1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-24 08:09:08 -05:00

fix: make WHATWG streams more compliant (#10967)

This commit is contained in:
Luca Casonato 2021-06-15 13:46:02 +02:00 committed by GitHub
parent 1eac527adb
commit 4cbc4a7eb3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 868 additions and 437 deletions

File diff suppressed because it is too large Load diff

View file

@ -40,6 +40,12 @@ interface VoidFunction {
(): void; (): void;
} }
interface ReadableStreamGenericReader<T> {
readonly closed: Promise<void>;
// deno-lint-ignore no-explicit-any
cancel(reason?: any): Promise<void>;
}
// ** Ambient Definitions and Interfaces not provided by fetch ** // ** Ambient Definitions and Interfaces not provided by fetch **
declare function queueMicrotask(callback: VoidFunction): void; declare function queueMicrotask(callback: VoidFunction): void;

View file

@ -566,6 +566,7 @@
converters["sequence<double>"] = createSequenceConverter( converters["sequence<double>"] = createSequenceConverter(
converters["double"], converters["double"],
); );
converters["Promise<undefined>"] = createPromiseConverter(() => undefined);
function requiredArguments(length, required, opts = {}) { function requiredArguments(length, required, opts = {}) {
if (length < required) { if (length < required) {
@ -578,11 +579,6 @@
} }
} }
function isEmptyObject(V) {
for (const _ in V) return false;
return true;
}
function createDictionaryConverter(name, ...dictionaries) { function createDictionaryConverter(name, ...dictionaries) {
let hasRequiredKey = false; let hasRequiredKey = false;
const allMembers = []; const allMembers = [];
@ -642,10 +638,8 @@
const idlDict = { ...defaultValues }; const idlDict = { ...defaultValues };
// NOTE: fast path Null and Undefined and empty objects. // NOTE: fast path Null and Undefined.
if ( if ((V === undefined || V === null) && !hasRequiredKey) {
(V === undefined || V === null || isEmptyObject(V)) && !hasRequiredKey
) {
return idlDict; 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]]"); const brand = Symbol("[[webidl.brand]]");
function createInterfaceConverter(name, prototype) { function createInterfaceConverter(name, prototype) {
@ -927,6 +946,8 @@
createNullableConverter, createNullableConverter,
createSequenceConverter, createSequenceConverter,
createRecordConverter, createRecordConverter,
createPromiseConverter,
invokeCallbackFunction,
createInterfaceConverter, createInterfaceConverter,
brand, brand,
createBranded, createBranded,

View file

@ -248,6 +248,24 @@ declare namespace globalThis {
converter: (v: any, opts: ValueConverterOpts) => T, converter: (v: any, opts: ValueConverterOpts) => T,
): (v: any, opts: ValueConverterOpts) => T[]; ): (v: any, opts: ValueConverterOpts) => T[];
/**
* Create a converter that converts a Promise of the inner type.
*/
declare function createPromiseConverter<T>(
converter: (v: any, opts: ValueConverterOpts) => T,
): (v: any, opts: ValueConverterOpts) => Promise<T>;
/**
* Invoke a callback function.
*/
declare function invokeCallbackFunction<T>(
callable: (...args: any) => any,
args: any[],
thisArg: any,
returnValueConverter: (v: any, opts: ValueConverterOpts) => T,
opts: ConverterOpts & { returnsPromise?: boolean },
): T;
/** /**
* Throw an illegal constructor error. * Throw an illegal constructor error.
*/ */

View file

@ -304,9 +304,15 @@ delete Object.prototype.__proto__;
WritableStreamDefaultWriter: util.nonEnumerable( WritableStreamDefaultWriter: util.nonEnumerable(
streams.WritableStreamDefaultWriter, streams.WritableStreamDefaultWriter,
), ),
WritableStreamDefaultController: util.nonEnumerable(
streams.WritableStreamDefaultController,
),
ReadableByteStreamController: util.nonEnumerable( ReadableByteStreamController: util.nonEnumerable(
streams.ReadableByteStreamController, streams.ReadableByteStreamController,
), ),
ReadableStreamDefaultController: util.nonEnumerable(
streams.ReadableStreamDefaultController,
),
TransformStreamDefaultController: util.nonEnumerable( TransformStreamDefaultController: util.nonEnumerable(
streams.TransformStreamDefaultController, streams.TransformStreamDefaultController,
), ),

View file

@ -256,23 +256,6 @@
}, },
"streams": { "streams": {
"idlharness.any.html": [ "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<any>",
"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: existence and properties of interface object",
"ReadableStreamBYOBReader interface object length", "ReadableStreamBYOBReader interface object length",
"ReadableStreamBYOBReader interface object name", "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 \"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: (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", "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", "ReadableByteStreamController interface: self.readableByteStreamController must inherit property \"byobRequest\" with the proper type",
"ReadableStreamBYOBRequest interface: existence and properties of interface object", "ReadableStreamBYOBRequest interface: existence and properties of interface object",
"ReadableStreamBYOBRequest interface object length", "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: 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: 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: 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", "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"
], ],
"piping": { "piping": {
"abort.any.html": [ "abort.any.html": true,
"a signal argument 'null' should cause pipeTo() to reject", "close-propagation-backward.any.html": true,
"a signal argument 'AbortSignal' should cause pipeTo() to reject", "close-propagation-forward.any.html": true,
"a signal argument 'true' should cause pipeTo() to reject", "error-propagation-backward.any.html": true,
"a signal argument '-1' should cause pipeTo() to reject", "error-propagation-forward.any.html": true,
"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)"
],
"flow-control.any.html": true, "flow-control.any.html": true,
"general.any.html": [ "general.any.html": true,
"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"
],
"multiple-propagation.any.html": true, "multiple-propagation.any.html": true,
"pipe-through.any.html": true, "pipe-through.any.html": true,
"then-interception.any.html": true, "then-interception.any.html": true,
"throwing-options.any.html": false, "throwing-options.any.html": true,
"transform-streams.any.html": true "transform-streams.any.html": true
}, },
"queuing-strategies.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 non-zero-length view (in the readable state)",
"ReadableStream with byte source: respondWithNewView() with a transferred zero-length view (in the closed 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": { "readable-streams": {
"async-iterator.any.html": [ "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", "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", "next() rejects if the stream errors",
"return() does not rejects if the stream has not errored yet", "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()" "next() that succeeds; next() that reports an error; next()"
], ],
"bad-strategies.any.html": true, "bad-strategies.any.html": true,
"bad-underlying-sources.any.html": true, "bad-underlying-sources.any.html": true,
"cancel.any.html": false, "cancel.any.html": false,
"constructor.any.html": false, "constructor.any.html": true,
"count-queuing-strategy-integration.any.html": true, "count-queuing-strategy-integration.any.html": true,
"default-reader.any.html": true, "default-reader.any.html": true,
"floating-point-total-queue-size.any.html": true, "floating-point-total-queue-size.any.html": true,
@ -573,19 +436,11 @@
}, },
"writable-streams": { "writable-streams": {
"aborting.any.html": false, "aborting.any.html": false,
"bad-strategies.any.html": [ "bad-strategies.any.html": true,
"reject any non-function value for strategy.size",
"Writable stream: invalid size beats invalid highWaterMark"
],
"bad-underlying-sinks.any.html": true, "bad-underlying-sinks.any.html": true,
"byte-length-queuing-strategy.any.html": true, "byte-length-queuing-strategy.any.html": true,
"close.any.html": false, "close.any.html": false,
"constructor.any.html": [ "constructor.any.html": true,
"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"
],
"count-queuing-strategy.any.html": true, "count-queuing-strategy.any.html": true,
"error.any.html": true, "error.any.html": true,
"floating-point-total-queue-size.any.html": true, "floating-point-total-queue-size.any.html": true,
@ -594,6 +449,10 @@
"reentrant-strategy.any.html": true, "reentrant-strategy.any.html": true,
"start.any.html": true, "start.any.html": true,
"write.any.html": true "write.any.html": true
},
"queuing-strategies-size-function-per-global.window.html": false,
"transferable": {
"deserialize-error.window.html": false
} }
}, },
"user-timing": { "user-timing": {
@ -951,6 +810,7 @@
"stream-safe-creation.any.html": [ "stream-safe-creation.any.html": [
"throwing Object.prototype.start accessor should not affect stream creation by 'fetch'", "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'", "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'", "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'", "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'", "throwing Object.prototype.highWaterMark accessor should not affect stream creation by 'fetch'",