Skip to content

Commit 55ee428

Browse files
committed
add from() spec
1 parent f954c91 commit 55ee428

File tree

1 file changed

+150
-3
lines changed

1 file changed

+150
-3
lines changed

spec.bs

Lines changed: 150 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ WPT Display: open
2626
urlPrefix: https://tc39.es/ecma262/#; spec: ECMASCRIPT
2727
type: dfn
2828
text: current realm
29+
text: IsPromise; url: sec-ispromise
30+
text: GetMethod; url: sec-getmethod
31+
text: GetIteratorFromMethod; url: sec-getiteratorfrommethod
32+
text: IteratorStepValue; url: sec-iteratorstepvalue
33+
text: normal completion; url: sec-normalcompletion
34+
text: throw completion; url: sec-throwcompletion
2935
urlPrefix: https://dom.spec.whatwg.org; spec: DOM
3036
type: dfn
3137
for: event listener
@@ -37,6 +43,13 @@ urlPrefix: https://dom.spec.whatwg.org; spec: DOM
3743
for: AbortSignal
3844
text: dependent signals; url: abortsignal-dependent-signals
3945
text: signal abort; url:abortsignal-signal-abort
46+
urlPrefix: https://webidl.spec.whatwg.org; spec: WEBIDL
47+
type: dfn
48+
text: a promise rejected with
49+
type: dfn
50+
text: Upon fulfillment
51+
type: dfn
52+
text: Upon rejection
4053
</pre>
4154

4255
<style>
@@ -354,7 +367,7 @@ interface Observable {
354367
//
355368
// takeUntil() can consume promises, iterables, async iterables, and other
356369
// observables.
357-
Observable takeUntil(any notifier);
370+
Observable takeUntil(any value);
358371
Observable map(Mapper mapper);
359372
Observable filter(Predicate predicate);
360373
Observable take(unsigned long long amount);
@@ -442,6 +455,130 @@ An <dfn>internal observer</dfn> is a [=struct=] with the following [=struct/item
442455
[[#promise-returning-operators]] that make use of this, for example.</p>
443456
</div>
444457

458+
<div algorithm>
459+
To <dfn for=Observable>convert to an Observable</dfn> given an {{any}} |value|, run these steps:
460+
461+
Note: We split this algorithm out from the Web IDL {{Observable/from()}} method, so that
462+
spec prose can <a for=Observable lt="convert to an observable">convert</a> an {{Observable}}
463+
without going through the Web IDL bindings.
464+
465+
Note: The resolution of value to its descrete types happens before
466+
[=Observable/subscribe callback=] is called. This means mutations of values, such as adding
467+
the iterable protocols to the object, will not take affect between the creation of the returned
468+
observable, and when it is subscribed to.
469+
470+
1. If |value| is an {{Observable}}, then return |value|.
471+
472+
1. Let |asyncIteratorMethodRecord| be [=GetMethod=](|value|, %Symbol.asyncIterator%).
473+
474+
1. If |asyncIteratorMethodRecord| is a [=normal completion=] and
475+
|asyncIteratorMethodRecord|'s \[[Value]] is not undefined, then:
476+
477+
Note: [=GetMethod=] may return a [=normal completion=] with an undefined value when the object
478+
simply has no asyncIterator method.
479+
480+
1. Let |nextAlgorithm| be the following steps, given |subscriber| and |iterator|:
481+
482+
1. If |iterator|'s \[[Done]] is true, then:
483+
484+
1. Run |subscriber|'s {{Subscriber/complete()}} method and abort these steps.
485+
486+
1. Let |nextRecord| be [=IteratorStepValue=](|iterator|).
487+
488+
1. Let |nextPromise| be undefined.
489+
490+
1. If |nextRecord| is a [=throw completion=] then:
491+
492+
1. Set |nextPromise| to [=a promise rejected with=] |nextRecord|'s \[[Value]].
493+
494+
1. Otherwise, set |nextPromise| to |nextRecord|'s \[[Value]].
495+
496+
1. [=Upon fulfillment=] of |nextPromise|, run the following steps, given |resolution|:
497+
498+
1. Run |subscriber|'s {{Subscriber/next()}} method, given |resolution|.
499+
500+
1. Run |nextAlgorithm|, given |subscriber| and |iterator|.
501+
502+
1. [=Upon rejection=] of |nextPromise|, run the following steps, given |rejection|:
503+
504+
1. Run |subscriber|'s {{Subscriber/error()}} method, given |rejection|.
505+
506+
1. Return a [=new=] {{Observable}} whose [=Observable/subscribe callback=] is an
507+
algorithm that takes a {{Subscriber}} |subscriber| and does the following:
508+
509+
1. Let |iteratorRecord| be [=GetIteratorFromMethod=](|value|, %Symbol.asyncIterator%).
510+
511+
1. If |iteratorRecord| is a [=throw completion=] then:
512+
513+
1. [=queue a microtask=] to perform the following steps:
514+
515+
1. Run |subscriber|'s {{Subscriber/error()}} method, given |iteratorRecord|'s \[[Value]].
516+
517+
1. Otherwise, [=queue a microtask=] to perform the following steps:
518+
519+
1. Run |nextAlgorithm| given |subscriber| and |iteratorRecord|'s \[[Value]].
520+
521+
Note: It is important to [=queue a microtask=] in both branches here to guarantee that
522+
coercing an AsyncIterable never stops the Subscription synchronously, thereby releasing
523+
Zalgo.
524+
525+
1. Let |iteratorMethodRecord| be [=GetMethod=](|value|, %Symbol.iterator%).
526+
527+
1. If |iteratorMethodRecord| is a [=normal completion=] and
528+
|iteratorMethodRecord|'s \[[Value]] is not undefined, then:
529+
530+
Note: [=GetMethod=] may return a [=normal completion=] with an undefined value when the object
531+
simply has no asyncIterator method.
532+
533+
1. Return a [=new=] {{Observable}} whose [=Observable/subscribe callback=] is an
534+
algorithm that takes a {{Subscriber}} |subscriber| and does the following:
535+
536+
1. Let |iteratorRecord| be [=GetIteratorFromMethod=](|value|, %Symbol.iterator%).
537+
538+
1. If |iteratorRecord| is a [=throw completion=] then:
539+
540+
1. Run |subscriber|'s {{Subscriber/error()}} method, given |iteratorRecord|'s \[[Value]].
541+
542+
1. Abort these steps.
543+
544+
1. Let |iterator| be |iteratorRecord|'s \[[Value]].
545+
546+
1. Repeat:
547+
548+
1. If |iterator|'s \[[Done]] is true, then:
549+
550+
1. Run |subscriber|'s {{Subscriber/complete()}} method and abort these steps.
551+
552+
1. Let |nextRecord| be [=IteratorStepValue=](|iterator|).
553+
554+
1. If |nextRecord| is a [=throw completion=] then:
555+
556+
1. Run |subscriber|'s {{Subscriber/error()}} method, given |nextRecord|'s \[[Value]].
557+
558+
1. Abort these steps.
559+
560+
1. Run |subscriber|'s {{Subscriber/next()}} given |nextRecord|'s \[[Value]].
561+
562+
1. If [=IsPromise=](|value|) is true, then:
563+
564+
1. Return a [=new=] {{Observable}} whose [=Observable/subscribe callback=] is an
565+
algorithm that takes a {{Subscriber}} |subscriber| and does the following:
566+
567+
1. [=Upon fulfillment=] of |value|, run the following steps, given |resolution|:
568+
569+
1. Run |subscriber|'s {{Subscriber/next()}} method, given |resolution|.
570+
571+
1. Run |subscriber|'s {{Subscriber/complete()}} method.
572+
573+
1. [=Upon rejection=] of |value|, run the following steps, given |rejection|:
574+
575+
1. Run |subscriber|'s {{Subscriber/error()}} method, given |rejection|.
576+
577+
1. Throw a {{TypeError}}.
578+
579+
</div>
580+
581+
445582
<div algorithm>
446583
To <dfn for=Observable>subscribe to an {{Observable}}</dfn> given an
447584
{{ObserverUnion}}-or-[=internal observer=] |observer|, and a {{SubscribeOptions}} |options|, run
@@ -556,15 +693,25 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
556693

557694
<h4 id=observable-from>{{Observable/from()}}</h4>
558695

559-
<p class=XXX>Spec the exact semantics of {{Observable/from()}} conversion.</p>
696+
<div algorithm>
697+
The <dfn for=Observable method><code>from(|value|)</code></dfn> method steps
698+
are:
699+
700+
1. Return the result of <a for=Observable lt="convert to an Observable">
701+
converting</a> |value| to an Observable.
702+
703+
</div>
560704

561705
<h4 id=observable-returning-operators>{{Observable}}-returning operators</h4>
562706

563707
<div algorithm>
564-
The <dfn for=Observable method><code>takeUntil(|notifier|)</code></dfn> method steps are:
708+
The <dfn for=Observable method><code>takeUntil(|value|)</code></dfn> method steps are:
565709

566710
1. Let |sourceObservable| be [=this=].
567711

712+
1. Let |notifier| be the result of <a for=Observable lt="convert to an Observable">
713+
converting</a> |value| to an Observable.
714+
568715
1. Let |observable| be a [=new=] {{Observable}} whose [=Observable/subscribe callback=] is an
569716
algorithm that takes a {{Subscriber}} |subscriber| and does the following:
570717

0 commit comments

Comments
 (0)