Skip to content

Commit 35e5159

Browse files
Millyiuioiua
andauthored
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. web-platform-tests/wpt#46365 --------- Co-authored-by: Asher Gomez <[email protected]>
1 parent e44c538 commit 35e5159

File tree

2 files changed

+32
-31
lines changed

2 files changed

+32
-31
lines changed

ext/web/06_streams.js

+30-23
Original file line numberDiff line numberDiff line change
@@ -5088,28 +5088,32 @@ function initializeCountSizeFunction(globalObject) {
50885088
WeakMapPrototypeSet(countSizeFunctionWeakMap, globalObject, size);
50895089
}
50905090

5091-
async function* createAsyncFromSyncIterator(syncIterator) {
5092-
// deno-lint-ignore prefer-primordials
5093-
yield* syncIterator;
5094-
}
5095-
50965091
// Ref: https://tc39.es/ecma262/#sec-getiterator
5097-
function getIterator(obj, async = false) {
5098-
if (async) {
5099-
if (obj[SymbolAsyncIterator] == null) {
5100-
if (obj[SymbolIterator] == null) {
5101-
throw new TypeError("No iterator found");
5102-
}
5103-
return createAsyncFromSyncIterator(obj[SymbolIterator]());
5104-
} else {
5105-
return obj[SymbolAsyncIterator]();
5092+
function getAsyncOrSyncIterator(obj) {
5093+
let iterator;
5094+
if (obj[SymbolAsyncIterator] != null) {
5095+
iterator = obj[SymbolAsyncIterator]();
5096+
if (!isObject(iterator)) {
5097+
throw new TypeError(
5098+
"[Symbol.asyncIterator] returned a non-object value",
5099+
);
51065100
}
5107-
} else {
5108-
if (obj[SymbolIterator] == null) {
5109-
throw new TypeError("No iterator found");
5101+
} else if (obj[SymbolIterator] != null) {
5102+
iterator = obj[SymbolIterator]();
5103+
if (!isObject(iterator)) {
5104+
throw new TypeError("[Symbol.iterator] returned a non-object value");
51105105
}
5111-
return obj[SymbolIterator]();
5106+
} else {
5107+
throw new TypeError("No iterator found");
5108+
}
5109+
if (typeof iterator.next !== "function") {
5110+
throw new TypeError("iterator.next is not a function");
51125111
}
5112+
return iterator;
5113+
}
5114+
5115+
function isObject(x) {
5116+
return (typeof x === "object" && x != null) || typeof x === "function";
51135117
}
51145118

51155119
const _resourceBacking = Symbol("[[resourceBacking]]");
@@ -5204,26 +5208,29 @@ class ReadableStream {
52045208
);
52055209
asyncIterable = webidl.converters.any(asyncIterable);
52065210

5207-
const iterator = getIterator(asyncIterable, true);
5211+
const iterator = getAsyncOrSyncIterator(asyncIterable);
52085212

52095213
const stream = createReadableStream(noop, async () => {
52105214
// deno-lint-ignore prefer-primordials
52115215
const res = await iterator.next();
5212-
if (typeof res !== "object") {
5216+
if (!isObject(res)) {
52135217
throw new TypeError("iterator.next value is not an object");
52145218
}
52155219
if (res.done) {
52165220
readableStreamDefaultControllerClose(stream[_controller]);
52175221
} else {
5218-
readableStreamDefaultControllerEnqueue(stream[_controller], res.value);
5222+
readableStreamDefaultControllerEnqueue(
5223+
stream[_controller],
5224+
await res.value,
5225+
);
52195226
}
52205227
}, async (reason) => {
5221-
if (typeof iterator.return === "undefined") {
5228+
if (iterator.return == null) {
52225229
return undefined;
52235230
} else {
52245231
// deno-lint-ignore prefer-primordials
52255232
const res = await iterator.return(reason);
5226-
if (typeof res !== "object") {
5233+
if (!isObject(res)) {
52275234
throw new TypeError("iterator.return value is not an object");
52285235
} else {
52295236
return undefined;

tests/wpt/runner/expectation.json

+2-8
Original file line numberDiff line numberDiff line change
@@ -3170,14 +3170,8 @@
31703170
"owning-type-message-port.any.worker.html": false,
31713171
"owning-type.any.html": false,
31723172
"owning-type.any.worker.html": false,
3173-
"from.any.html": [
3174-
"ReadableStream.from accepts a sync iterable of values",
3175-
"ReadableStream.from accepts a sync iterable of promises"
3176-
],
3177-
"from.any.worker.html": [
3178-
"ReadableStream.from accepts a sync iterable of values",
3179-
"ReadableStream.from accepts a sync iterable of promises"
3180-
]
3173+
"from.any.html": true,
3174+
"from.any.worker.html": true
31813175
},
31823176
"transform-streams": {
31833177
"backpressure.any.html": true,

0 commit comments

Comments
 (0)