diff options
author | Milly <milly.ca@gmail.com> | 2024-05-28 06:29:54 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-27 21:29:54 +0000 |
commit | 35e5159c8d5987497b8980c1cf3996d241612957 (patch) | |
tree | 24056d26007f7bc477dabaabe166823249eafe96 | |
parent | e44c538f37c48f738dea904cffe4cda67f689914 (diff) |
fix(ext/web): `ReadableStream.from()` allows `Iterable` instead of `IterableIterator` (#23903)
`createAsyncFromSyncIterator(x)` which is used in
`ReadableStream.from()` 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
---------
Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com>
-rw-r--r-- | ext/web/06_streams.js | 53 | ||||
-rw-r--r-- | tests/wpt/runner/expectation.json | 10 |
2 files changed, 32 insertions, 31 deletions
diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 0192a54c6..4ab1c3b5b 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[SymbolIterator]()); - } 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; diff --git a/tests/wpt/runner/expectation.json b/tests/wpt/runner/expectation.json index 78a33badf..30c9d692e 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, |