@@ -20,6 +20,113 @@ const [Observable, Subscriber] = (() => {
2020 } ) ;
2121 }
2222
23+ const pTry = "try" in Promise ? Promise . try . bind ( Promise ) : ( fn , ...args ) => new Promise ( ( r ) => r ( fn ( ...args ) ) ) ;
24+
25+ const pWithResolvers = 'withResolvers' in Promise ? Promise . withResolvers . bind ( Promise ) : ( ) => {
26+ let resolve , reject ;
27+ const promise = new Promise ( ( res , rej ) => ( ( resolve = res ) , ( reject = rej ) ) ) ;
28+ return { promise, resolve, reject } ;
29+ }
30+
31+ function getIteratorFromMethod ( obj , method ) {
32+ // 1. Let iterator be ? Call(method, obj).
33+ const iterator = method . call ( obj ) ;
34+ // 2. If iterator is not an Object, throw a TypeError exception.
35+ if ( iterator === null || typeof iterator !== "object" ) throw new TypeError ( "Iterator is not an object" ) ;
36+ // 3. Return ? GetIteratorDirect(iterator)
37+ return iterator ;
38+ }
39+
40+ const privateState = new WeakMap ( ) ;
41+
42+ const AsyncFromSyncIteratorPrototype = {
43+ next ( ...args ) {
44+ // 1. Let O be the this value.
45+ const O = this ;
46+ // 2. Assert: O is an Object that has a [[SyncIteratorRecord]] internal slot.
47+ const state = privateState . get ( O ) ;
48+ if ( ! state ?. syncIteratorRecord )
49+ throw new TypeError (
50+ "AsyncFromSyncIteratorPrototype.next called on invalid object"
51+ ) ;
52+ // 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
53+ const { syncIteratorRecord } = state ;
54+ return pTry ( ( ) => syncIteratorRecord . next ( ...args ) ) ;
55+ } ,
56+ return ( ...args ) {
57+ // 1. Let O be the this value.
58+ const O = this ;
59+ // 2. Assert: O is an Object that has a [[SyncIteratorRecord]] internal slot.
60+ const state = privateState . get ( O ) ;
61+ if ( ! state ?. syncIteratorRecord )
62+ throw new TypeError (
63+ "AsyncFromSyncIteratorPrototype.return called on invalid object"
64+ ) ;
65+ // 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
66+ const { syncIteratorRecord } = state ;
67+ return pTry ( ( ) => {
68+ if ( ! syncIteratorRecord . return ) return { value : undefined , done : true } ;
69+ return syncIteratorRecord . return ( ...args ) ;
70+ } ) ;
71+ } ,
72+ throw ( ...args ) {
73+ // 1. Let O be the this value.
74+ const O = this ;
75+ // 2. Assert: O is an Object that has a [[SyncIteratorRecord]] internal slot.
76+ const state = privateState . get ( O ) ;
77+ if ( ! state ?. syncIteratorRecord )
78+ throw new TypeError (
79+ "AsyncFromSyncIteratorPrototype.throw called on invalid object"
80+ ) ;
81+ // 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
82+ const { syncIteratorRecord } = state ;
83+ return pTry ( ( ) => {
84+ if ( ! syncIteratorRecord . throw ) {
85+ // a. NOTE: If syncIterator does not have a throw method, close it to give it a chance to clean up before we reject the capability.
86+ syncIteratorRecord . return ( ) ;
87+ throw new TypeError ( "no throw method" ) ;
88+ }
89+ return syncIteratorRecord . throw ( ...args ) ;
90+ } ) ;
91+ } ,
92+ } ;
93+
94+ function createAsyncFromSyncIterator ( syncIteratorRecord ) {
95+ // 1. Let asyncIterator be OrdinaryObjectCreate(%AsyncFromSyncIteratorPrototype%, « [[SyncIteratorRecord]] »).
96+ const asyncIterator = Object . create ( AsyncFromSyncIteratorPrototype ) ;
97+ // 2. Set asyncIterator.[[SyncIteratorRecord]] to syncIteratorRecord.
98+ privateState . set ( asyncIterator , { syncIteratorRecord } ) ;
99+ return asyncIterator ;
100+ }
101+
102+ function getIterator ( obj , isAsync ) {
103+ let method = undefined ;
104+ // 1. if kind is ASYNC, then
105+ if ( isAsync ) {
106+ // 1.a. Let method be ? GetMethod(obj, %Symbol.asyncIterator%).
107+ method = obj [ Symbol . asyncIterator ] ;
108+ // 1.b. If method is undefined, then
109+ if ( method == undefined ) {
110+ // 1.b.i. Let method be ? GetMethod(obj, %Symbol.iterator%).
111+ method = obj [ Symbol . iterator ] ;
112+ // 1.b.ii. If method is undefined, throw a TypeError exception.
113+ if ( method == undefined ) throw new TypeError ( "Object is not async iterable" ) ;
114+ // 1.b.iii. Let syncIteratorRecord be ? GetIteratorFromMethod(obj, syncMethod).
115+ const syncIteratorRecord = getIteratorFromMethod ( obj , method ) ;
116+ // 1.b.iv. Return ! CreateAsyncFromSyncIterator(syncIteratorRecord).
117+ return createAsyncFromSyncIterator ( syncIteratorRecord ) ;
118+ }
119+ // 2. Else,
120+ } else {
121+ // 2.a. Let method be ? GetMethod(obj, %Symbol.iterator%).
122+ method = obj [ Symbol . iterator ] ;
123+ }
124+ // 3. If method is undefined, throw a TypeError exception.
125+ if ( method == undefined ) throw new TypeError ( "Object is not iterable" ) ;
126+ // 4. Return ? GetIteratorFromMethod(obj, method).
127+ return getIteratorFromMethod ( obj , method ) ;
128+ }
129+
23130 const abortSignalAny = "any" in AbortSignal ? AbortSignal . any . bind ( AbortSignal ) : ( signals ) => {
24131 // create a signal that will abort when any of the signals aborts.
25132 const ac = new AbortController ( ) ;
@@ -43,14 +150,6 @@ const [Observable, Subscriber] = (() => {
43150 // wrapper for AbortSignal.any that removes null and undefined, for convenience.
44151 const anySignal = ( signalArray ) => abortSignalAny ( signalArray . filter ( Boolean ) ) ;
45152
46- const pWithResolvers = 'withResolvers' in Promise ? Promise . withResolvers . bind ( Promise ) : ( ) => {
47- let resolve , reject ;
48- const promise = new Promise ( ( res , rej ) => ( ( resolve = res ) , ( reject = rej ) ) ) ;
49- return { promise, resolve, reject } ;
50- }
51-
52- const privateState = new WeakMap ( ) ;
53-
54153 class InternalObserver {
55154 constructor ( { next, error, complete } = { } ) {
56155 privateState . set ( this , { next, error, complete } ) ;
@@ -363,6 +462,7 @@ const [Observable, Subscriber] = (() => {
363462 const asyncIteratorMethodRecord = Symbol . asyncIterator in value && value [ Symbol . asyncIterator ] ;
364463 // 4. If asyncIteratorMethod’s is undefined or null, then jump to the step labeled From iterable.
365464 if ( typeof asyncIteratorMethodRecord === "function" ) {
465+ let done = false ;
366466 // 5. Let nextAlgorithm be the following steps, given a Subscriber subscriber and an Iterator Record iteratorRecord:
367467 function nextAlgorithm ( subscriber , iteratorRecord ) {
368468 // 5.1. If subscriber’s subscription controller’s signal is aborted, then return.
@@ -389,10 +489,9 @@ const [Observable, Subscriber] = (() => {
389489 subscriber . error ( new TypeError ( "Not an IteratorResult." ) ) ;
390490 return ;
391491 }
392- let done ;
393492 try {
394493 // 5.6.2 Let done be IteratorComplete(iteratorResult).
395- done = iteratorResult . done ;
494+ ( { done } = iteratorResult ) ;
396495 } catch ( error ) {
397496 // 5.6.3 If done is a throw completion, then run subscriber’s error() method with done’s [[Value]] and abort these steps.
398497 subscriber . error ( error ) ;
@@ -430,7 +529,7 @@ const [Observable, Subscriber] = (() => {
430529 let iteratorRecordCompletion ;
431530 try {
432531 // 6.2. Let iteratorRecordCompletion be GetIterator(value, async).
433- iteratorRecordCompletion = value [ Symbol . asyncIterator ] ( ) ;
532+ iteratorRecordCompletion = getIterator ( value , true ) ;
434533 } catch ( error ) {
435534 // 6.3. If iteratorRecordCompletion is a throw completion, then run subscriber’s error() method with iteratorRecordCompletion’s [[Value]] and abort these steps.
436535 subscriber . error ( error ) ;
@@ -444,11 +543,13 @@ const [Observable, Subscriber] = (() => {
444543 // 6.7. Add the following abort algorithm to subscriber’s subscription controller’s signal:
445544 subscriber . signal . addEventListener ( "abort" , ( ) => {
446545 // 6.7.1. Run AsyncIteratorClose(iteratorRecord, NormalCompletion(subscriber’s subscription controller’s abort reason)).
447- if ( typeof iteratorRecord . return !== "function" ) return ;
448- const returnResult = iteratorRecord . return ( subscriber . signal . reason ) ;
449- if ( returnResult === null || typeof returnResult !== "object" ) {
546+ if ( typeof iteratorRecord . return !== "function" || done ) return ;
547+ const returnPromise = pTry ( ( ) => iteratorRecord . return ( subscriber . signal . reason ) ) ;
548+ returnPromise . then ( ( result ) => {
549+ if ( result === null || typeof result !== "object" ) {
450550 throw new TypeError ( "Iterator .return() must return an Object" ) ;
451- }
551+ }
552+ } ) ;
452553 } ) ;
453554 // 6.8. Run nextAlgorithm given subscriber and iteratorRecord.
454555 nextAlgorithm ( subscriber , iteratorRecord ) ;
@@ -466,20 +567,21 @@ const [Observable, Subscriber] = (() => {
466567 let iteratorRecordCompletion ;
467568 try {
468569 // 8.2. Let iteratorRecordCompletion be GetIterator(value, sync).
469- iteratorRecordCompletion = value [ Symbol . iterator ] ( ) ;
570+ iteratorRecordCompletion = getIterator ( value , false ) ;
470571 } catch ( error ) {
471572 // 8.3. If iteratorRecordCompletion is a throw completion, then run subscriber’s error() method, given iteratorRecordCompletion’s [[Value]], and abort these steps.
472573 subscriber . error ( error ) ;
473574 return ;
474575 }
576+ let done = false ;
475577 // 8.4. Let iteratorRecord be ! iteratorRecordCompletion.
476578 let iteratorRecord = iteratorRecordCompletion ;
477579 // 8.5 If subscriber’s subscription controller’s signal is aborted, then return.
478580 if ( subscriber . signal . aborted ) return ;
479581 // 8.6. Add the following abort algorithm to subscriber’s subscription controller’s signal:
480582 subscriber . signal . addEventListener ( "abort" , ( ) => {
481583 // 8.6.1. Run IteratorClose(iteratorRecord, NormalCompletion(UNUSED)).
482- if ( typeof iteratorRecord . return !== "function" ) return ;
584+ if ( typeof iteratorRecord . return !== "function" || done ) return ;
483585 const returnResult = iteratorRecord . return ( ) ;
484586 if ( returnResult === null || typeof returnResult !== "object" ) {
485587 throw new TypeError ( "Iterator .return() must return an Object" ) ;
@@ -490,9 +592,10 @@ const [Observable, Subscriber] = (() => {
490592 try {
491593 // 8.7.1. Let next be IteratorStepValue(iteratorRecord).
492594 let next = iteratorRecord . next ( ) ;
595+ ( { done } = next ) ;
493596 // 8.7.3. Set next to ! to next.
494597 // 8.7.4. If next is done, then:
495- if ( next . done ) {
598+ if ( done ) {
496599 // 8.7.4.1. Assert: iteratorRecord’s [[Done]] is true.
497600 // 8.7.4.2. Run subscriber’s complete().
498601 subscriber . complete ( ) ;
0 commit comments