diff --git a/lib/internal/streams/iter/from.js b/lib/internal/streams/iter/from.js index 1efe83e9a04162..80ba7cadf42bdb 100644 --- a/lib/internal/streams/iter/from.js +++ b/lib/internal/streams/iter/from.js @@ -484,8 +484,10 @@ function fromSync(input) { return fromSync(input[toStreamable]()); } - // Reject explicit async inputs - if (isAsyncIterable(input)) { + const isIterable = isSyncIterable(input); + + // Reject explicit async-only inputs + if (!isIterable && isAsyncIterable(input)) { throw new ERR_INVALID_ARG_TYPE( 'input', 'a synchronous input (not AsyncIterable)', @@ -501,7 +503,7 @@ function fromSync(input) { } // Must be a SyncStreamable - if (!isSyncIterable(input)) { + if (!isIterable) { throw new ERR_INVALID_ARG_TYPE( 'input', ['string', 'ArrayBuffer', 'ArrayBufferView', 'Iterable', 'toStreamable'], diff --git a/test/parallel/test-stream-iter-from-sync.js b/test/parallel/test-stream-iter-from-sync.js index d3a5cf671e10d8..5781317522e708 100644 --- a/test/parallel/test-stream-iter-from-sync.js +++ b/test/parallel/test-stream-iter-from-sync.js @@ -3,7 +3,7 @@ const common = require('../common'); const assert = require('assert'); -const { fromSync } = require('stream/iter'); +const { fromSync, textSync } = require('stream/iter'); function testFromSyncString() { // String input should be UTF-8 encoded @@ -186,6 +186,19 @@ function testFromSyncRejectsAsyncIterable() { assert.throws(() => fromSync(gen()), { code: 'ERR_INVALID_ARG_TYPE' }); } +function testFromSyncPrefersIteratorForDualIterable() { + const input = { + *[Symbol.iterator]() { + yield new TextEncoder().encode('sync'); + }, + async *[Symbol.asyncIterator]() { + yield new TextEncoder().encode('async'); + }, + }; + + assert.strictEqual(textSync(fromSync(input)), 'sync'); +} + // Promise rejected function testFromSyncRejectsPromise() { assert.throws(() => fromSync(Promise.resolve('hello')), @@ -232,6 +245,7 @@ Promise.all([ testFromSyncTopLevelProtocolOverIterator(), testFromSyncIgnoresAsyncStreamable(), testFromSyncRejectsAsyncIterable(), + testFromSyncPrefersIteratorForDualIterable(), testFromSyncRejectsPromise(), testFromSyncDataView(), ]).then(common.mustCall());