From 9e375d9dff021efececd926528a5b264451a335e Mon Sep 17 00:00:00 2001 From: Milly Date: Tue, 21 May 2024 02:29:55 +0900 Subject: [PATCH 1/3] fix(ext/web): ReadableStream.from() async from iterator `createAsyncFromSyncIterator(x)` expects `x` as `Iterable` but, previous implements specify `Iterator` or `IterableIterator`. If it was `IterableIterator`, it would work, but if it was `Iterator`, an exception will occur. Tests have been merged into WPT. https://github.com/web-platform-tests/wpt/pull/46365 --- ext/web/06_streams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 9c2a0598053061..6dc1704b30ba77 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -5100,7 +5100,7 @@ function getIterator(obj, async = false) { if (obj[SymbolIterator] === undefined) { throw new TypeError("No iterator found"); } - return createAsyncFromSyncIterator(obj[SymbolIterator]()); + return createAsyncFromSyncIterator(obj); } else { return obj[SymbolAsyncIterator](); } From 214cdaae45556e53fa0b521e6878a75c1d8743dc Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Fri, 24 May 2024 08:42:49 +1000 Subject: [PATCH 2/3] update wpt expectations --- tests/wpt/runner/expectation.json | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/wpt/runner/expectation.json b/tests/wpt/runner/expectation.json index 78a33badf644e2..30c9d692eabcb1 100644 --- a/tests/wpt/runner/expectation.json +++ b/tests/wpt/runner/expectation.json @@ -3170,14 +3170,8 @@ "owning-type-message-port.any.worker.html": false, "owning-type.any.html": false, "owning-type.any.worker.html": false, - "from.any.html": [ - "ReadableStream.from accepts a sync iterable of values", - "ReadableStream.from accepts a sync iterable of promises" - ], - "from.any.worker.html": [ - "ReadableStream.from accepts a sync iterable of values", - "ReadableStream.from accepts a sync iterable of promises" - ] + "from.any.html": true, + "from.any.worker.html": true }, "transform-streams": { "backpressure.any.html": true, From e55ddb65b902978905d66dafd4893ffa18d88d4e Mon Sep 17 00:00:00 2001 From: Milly Date: Fri, 24 May 2024 16:40:26 +0900 Subject: [PATCH 3/3] fix(ext/web): `ReadableStream.from()` allows `Iterable` --- ext/web/06_streams.js | 53 ++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index f7427cce864244..4ab1c3b5b0a511 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -5088,28 +5088,32 @@ function initializeCountSizeFunction(globalObject) { WeakMapPrototypeSet(countSizeFunctionWeakMap, globalObject, size); } -async function* createAsyncFromSyncIterator(syncIterator) { - // deno-lint-ignore prefer-primordials - yield* syncIterator; -} - // Ref: https://tc39.es/ecma262/#sec-getiterator -function getIterator(obj, async = false) { - if (async) { - if (obj[SymbolAsyncIterator] == null) { - if (obj[SymbolIterator] == null) { - throw new TypeError("No iterator found"); - } - return createAsyncFromSyncIterator(obj); - } else { - return obj[SymbolAsyncIterator](); +function getAsyncOrSyncIterator(obj) { + let iterator; + if (obj[SymbolAsyncIterator] != null) { + iterator = obj[SymbolAsyncIterator](); + if (!isObject(iterator)) { + throw new TypeError( + "[Symbol.asyncIterator] returned a non-object value", + ); } - } else { - if (obj[SymbolIterator] == null) { - throw new TypeError("No iterator found"); + } else if (obj[SymbolIterator] != null) { + iterator = obj[SymbolIterator](); + if (!isObject(iterator)) { + throw new TypeError("[Symbol.iterator] returned a non-object value"); } - return obj[SymbolIterator](); + } else { + throw new TypeError("No iterator found"); + } + if (typeof iterator.next !== "function") { + throw new TypeError("iterator.next is not a function"); } + return iterator; +} + +function isObject(x) { + return (typeof x === "object" && x != null) || typeof x === "function"; } const _resourceBacking = Symbol("[[resourceBacking]]"); @@ -5204,26 +5208,29 @@ class ReadableStream { ); asyncIterable = webidl.converters.any(asyncIterable); - const iterator = getIterator(asyncIterable, true); + const iterator = getAsyncOrSyncIterator(asyncIterable); const stream = createReadableStream(noop, async () => { // deno-lint-ignore prefer-primordials const res = await iterator.next(); - if (typeof res !== "object") { + if (!isObject(res)) { throw new TypeError("iterator.next value is not an object"); } if (res.done) { readableStreamDefaultControllerClose(stream[_controller]); } else { - readableStreamDefaultControllerEnqueue(stream[_controller], res.value); + readableStreamDefaultControllerEnqueue( + stream[_controller], + await res.value, + ); } }, async (reason) => { - if (typeof iterator.return === "undefined") { + if (iterator.return == null) { return undefined; } else { // deno-lint-ignore prefer-primordials const res = await iterator.return(reason); - if (typeof res !== "object") { + if (!isObject(res)) { throw new TypeError("iterator.return value is not an object"); } else { return undefined;