@@ -198,6 +198,103 @@ function isAccessorDescriptor(desc) {
198198 return Object . hasOwn ( desc , "get" ) || Object . hasOwn ( desc , "set" ) ;
199199}
200200
201+ function getMethod ( value , property , errPrefix = "The provided value" ) {
202+ const func = value [ property ] ;
203+ if ( func === undefined || func === null ) {
204+ return undefined ;
205+ }
206+ if ( typeof func !== "function" ) {
207+ throw new TypeError ( `${ errPrefix } 's ${ property } property is not a function.` ) ;
208+ }
209+ return func ;
210+ }
211+
212+ function createAsyncFromSyncIterator ( syncIterator ) {
213+ // Instead of re-implementing CreateAsyncFromSyncIterator and %AsyncFromSyncIteratorPrototype%,
214+ // we use yield* inside an async generator function to achieve the same result.
215+
216+ // Wrap the sync iterator inside a sync iterable, so we can use it with yield*.
217+ const syncIterable = {
218+ [ Symbol . iterator ] : ( ) => syncIterator
219+ } ;
220+ // Create an async generator function and immediately invoke it.
221+ const asyncIterator = ( async function * ( ) {
222+ return yield * syncIterable ;
223+ } ) ( ) ;
224+ // Return as an async iterator record.
225+ return asyncIterator ;
226+ }
227+
228+ function convertAsyncSequence ( object , itemConverter , errPrefix = "The provided value" ) {
229+ if ( ! isObject ( object ) ) {
230+ throw new TypeError ( `${ errPrefix } is not an object.` ) ;
231+ }
232+ let method = getMethod ( object , Symbol . asyncIterator , errPrefix ) ;
233+ let type = "async" ;
234+ if ( method === undefined ) {
235+ method = getMethod ( object , Symbol . iterator , errPrefix ) ;
236+ if ( method === undefined ) {
237+ throw new TypeError ( `${ errPrefix } is not an async iterable object.` ) ;
238+ }
239+ type = "sync" ;
240+ }
241+
242+ return {
243+ object,
244+ method,
245+ type,
246+ // The wrapperSymbol ensures that if the async sequence is used as a return value,
247+ // that it exposes the original JavaScript value.
248+ // https://webidl.spec.whatwg.org/#js-async-iterable
249+ [ wrapperSymbol ] : object ,
250+ // Implement the async iterator protocol, so users can iterate
251+ // the async sequence directly (e.g. with for await...of)
252+ // instead of needing to call a separate helper function to open the async sequence.
253+ // https://webidl.spec.whatwg.org/#async-sequence-open
254+ [ Symbol . asyncIterator ] ( ) {
255+ return openAsyncSequence ( object , method , type , itemConverter , `${ errPrefix } 's iterator` ) ;
256+ }
257+ } ;
258+ }
259+
260+ function openAsyncSequence ( object , method , type , itemConverter , errPrefix = "The provided value" ) {
261+ let iterator = call ( method , object ) ;
262+ if ( ! isObject ( iterator ) ) {
263+ throw new TypeError ( `${ errPrefix } 's method must return an object` ) ;
264+ }
265+ if ( type === "sync" ) {
266+ iterator = createAsyncFromSyncIterator ( iterator ) ;
267+ }
268+ const nextMethod = iterator . next ;
269+ return {
270+ async next ( ) {
271+ const nextResult = await call ( nextMethod , iterator ) ;
272+ if ( ! isObject ( nextResult ) ) {
273+ throw new TypeError ( `${ errPrefix } 's next method must return an object` ) ;
274+ }
275+ const { done, value } = nextResult ;
276+ if ( done ) {
277+ return { done : true , value : undefined } ;
278+ }
279+ return { done : false , value : itemConverter ( value ) } ;
280+ } ,
281+ async return ( reason ) {
282+ const returnMethod = getMethod ( iterator , "return" , errPrefix ) ;
283+ if ( returnMethod === undefined ) {
284+ return { done : true , value : undefined } ;
285+ }
286+ const returnResult = await call ( returnMethod , iterator , reason ) ;
287+ if ( ! isObject ( returnResult ) ) {
288+ throw new TypeError ( `${ errPrefix } 's return method must return an object` ) ;
289+ }
290+ return { done : true , value : undefined } ;
291+ } ,
292+ [ Symbol . asyncIterator ] ( ) {
293+ return this ;
294+ }
295+ } ;
296+ }
297+
201298const supportsPropertyIndex = Symbol ( "supports property index" ) ;
202299const supportedPropertyIndices = Symbol ( "supported property indices" ) ;
203300const supportsPropertyName = Symbol ( "supports property name" ) ;
@@ -232,6 +329,8 @@ module.exports = exports = {
232329 isArrayBuffer,
233330 isSharedArrayBuffer,
234331 isArrayIndexPropName,
332+ getMethod,
333+ convertAsyncSequence,
235334 supportsPropertyIndex,
236335 supportedPropertyIndices,
237336 supportsPropertyName,
0 commit comments