Skip to content

Commit 3418ea1

Browse files
committed
add from() spec
1 parent f954c91 commit 3418ea1

File tree

1 file changed

+152
-3
lines changed

1 file changed

+152
-3
lines changed

spec.bs

+152-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ WPT Display: open
2626
urlPrefix: https://tc39.es/ecma262/#; spec: ECMASCRIPT
2727
type: dfn
2828
text: current realm
29+
text: an Object; url: sec-object-type
30+
text: IsPromise; url: sec-ispromise
31+
text: GetMethod; url: sec-getmethod
32+
text: GetIteratorFromMethod; url: sec-getiteratorfrommethod
33+
text: IteratorStepValue; url: sec-iteratorstepvalue
34+
text: normal completion; url: sec-normalcompletion
35+
text: throw completion; url: sec-throwcompletion
2936
urlPrefix: https://dom.spec.whatwg.org; spec: DOM
3037
type: dfn
3138
for: event listener
@@ -37,6 +44,11 @@ urlPrefix: https://dom.spec.whatwg.org; spec: DOM
3744
for: AbortSignal
3845
text: dependent signals; url: abortsignal-dependent-signals
3946
text: signal abort; url:abortsignal-signal-abort
47+
urlPrefix: https://webidl.spec.whatwg.org; spec: WEBIDL
48+
type: dfn
49+
text: a promise rejected with
50+
type: dfn
51+
text: react
4052
</pre>
4153

4254
<style>
@@ -354,7 +366,7 @@ interface Observable {
354366
//
355367
// takeUntil() can consume promises, iterables, async iterables, and other
356368
// observables.
357-
Observable takeUntil(any notifier);
369+
Observable takeUntil(any value);
358370
Observable map(Mapper mapper);
359371
Observable filter(Predicate predicate);
360372
Observable take(unsigned long long amount);
@@ -442,6 +454,133 @@ An <dfn>internal observer</dfn> is a [=struct=] with the following [=struct/item
442454
[[#promise-returning-operators]] that make use of this, for example.</p>
443455
</div>
444456

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

557696
<h4 id=observable-from>{{Observable/from()}}</h4>
558697

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

561707
<h4 id=observable-returning-operators>{{Observable}}-returning operators</h4>
562708

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

566712
1. Let |sourceObservable| be [=this=].
567713

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

0 commit comments

Comments
 (0)