Skip to content

Commit

Permalink
add from() spec
Browse files Browse the repository at this point in the history
  • Loading branch information
keithamus committed Jul 26, 2024
1 parent f954c91 commit 55ee428
Showing 1 changed file with 150 additions and 3 deletions.
153 changes: 150 additions & 3 deletions spec.bs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ WPT Display: open
urlPrefix: https://tc39.es/ecma262/#; spec: ECMASCRIPT
type: dfn
text: current realm
text: IsPromise; url: sec-ispromise
text: GetMethod; url: sec-getmethod
text: GetIteratorFromMethod; url: sec-getiteratorfrommethod
text: IteratorStepValue; url: sec-iteratorstepvalue
text: normal completion; url: sec-normalcompletion
text: throw completion; url: sec-throwcompletion
urlPrefix: https://dom.spec.whatwg.org; spec: DOM
type: dfn
for: event listener
Expand All @@ -37,6 +43,13 @@ urlPrefix: https://dom.spec.whatwg.org; spec: DOM
for: AbortSignal
text: dependent signals; url: abortsignal-dependent-signals
text: signal abort; url:abortsignal-signal-abort
urlPrefix: https://webidl.spec.whatwg.org; spec: WEBIDL
type: dfn
text: a promise rejected with
type: dfn
text: Upon fulfillment
type: dfn
text: Upon rejection
</pre>

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

<div algorithm>
To <dfn for=Observable>convert to an Observable</dfn> given an {{any}} |value|, run these steps:

Note: We split this algorithm out from the Web IDL {{Observable/from()}} method, so that
spec prose can <a for=Observable lt="convert to an observable">convert</a> an {{Observable}}
without going through the Web IDL bindings.

Note: The resolution of value to its descrete types happens before
[=Observable/subscribe callback=] is called. This means mutations of values, such as adding
the iterable protocols to the object, will not take affect between the creation of the returned
observable, and when it is subscribed to.

1. If |value| is an {{Observable}}, then return |value|.

1. Let |asyncIteratorMethodRecord| be [=GetMethod=](|value|, %Symbol.asyncIterator%).

1. If |asyncIteratorMethodRecord| is a [=normal completion=] and
|asyncIteratorMethodRecord|'s \[[Value]] is not undefined, then:

Note: [=GetMethod=] may return a [=normal completion=] with an undefined value when the object
simply has no asyncIterator method.

1. Let |nextAlgorithm| be the following steps, given |subscriber| and |iterator|:

1. If |iterator|'s \[[Done]] is true, then:

1. Run |subscriber|'s {{Subscriber/complete()}} method and abort these steps.

1. Let |nextRecord| be [=IteratorStepValue=](|iterator|).

1. Let |nextPromise| be undefined.

1. If |nextRecord| is a [=throw completion=] then:

1. Set |nextPromise| to [=a promise rejected with=] |nextRecord|'s \[[Value]].

1. Otherwise, set |nextPromise| to |nextRecord|'s \[[Value]].

1. [=Upon fulfillment=] of |nextPromise|, run the following steps, given |resolution|:

1. Run |subscriber|'s {{Subscriber/next()}} method, given |resolution|.

1. Run |nextAlgorithm|, given |subscriber| and |iterator|.

1. [=Upon rejection=] of |nextPromise|, run the following steps, given |rejection|:

1. Run |subscriber|'s {{Subscriber/error()}} method, given |rejection|.

1. Return a [=new=] {{Observable}} whose [=Observable/subscribe callback=] is an
algorithm that takes a {{Subscriber}} |subscriber| and does the following:

1. Let |iteratorRecord| be [=GetIteratorFromMethod=](|value|, %Symbol.asyncIterator%).

1. If |iteratorRecord| is a [=throw completion=] then:

1. [=queue a microtask=] to perform the following steps:

1. Run |subscriber|'s {{Subscriber/error()}} method, given |iteratorRecord|'s \[[Value]].

1. Otherwise, [=queue a microtask=] to perform the following steps:

1. Run |nextAlgorithm| given |subscriber| and |iteratorRecord|'s \[[Value]].

Note: It is important to [=queue a microtask=] in both branches here to guarantee that
coercing an AsyncIterable never stops the Subscription synchronously, thereby releasing
Zalgo.

1. Let |iteratorMethodRecord| be [=GetMethod=](|value|, %Symbol.iterator%).

1. If |iteratorMethodRecord| is a [=normal completion=] and
|iteratorMethodRecord|'s \[[Value]] is not undefined, then:

Note: [=GetMethod=] may return a [=normal completion=] with an undefined value when the object
simply has no asyncIterator method.

1. Return a [=new=] {{Observable}} whose [=Observable/subscribe callback=] is an
algorithm that takes a {{Subscriber}} |subscriber| and does the following:

1. Let |iteratorRecord| be [=GetIteratorFromMethod=](|value|, %Symbol.iterator%).

1. If |iteratorRecord| is a [=throw completion=] then:

1. Run |subscriber|'s {{Subscriber/error()}} method, given |iteratorRecord|'s \[[Value]].

1. Abort these steps.

1. Let |iterator| be |iteratorRecord|'s \[[Value]].

1. Repeat:

1. If |iterator|'s \[[Done]] is true, then:

1. Run |subscriber|'s {{Subscriber/complete()}} method and abort these steps.

1. Let |nextRecord| be [=IteratorStepValue=](|iterator|).

1. If |nextRecord| is a [=throw completion=] then:

1. Run |subscriber|'s {{Subscriber/error()}} method, given |nextRecord|'s \[[Value]].

1. Abort these steps.

1. Run |subscriber|'s {{Subscriber/next()}} given |nextRecord|'s \[[Value]].

1. If [=IsPromise=](|value|) is true, then:

1. Return a [=new=] {{Observable}} whose [=Observable/subscribe callback=] is an
algorithm that takes a {{Subscriber}} |subscriber| and does the following:

1. [=Upon fulfillment=] of |value|, run the following steps, given |resolution|:

1. Run |subscriber|'s {{Subscriber/next()}} method, given |resolution|.

1. Run |subscriber|'s {{Subscriber/complete()}} method.

1. [=Upon rejection=] of |value|, run the following steps, given |rejection|:

1. Run |subscriber|'s {{Subscriber/error()}} method, given |rejection|.

1. Throw a {{TypeError}}.

</div>


<div algorithm>
To <dfn for=Observable>subscribe to an {{Observable}}</dfn> given an
{{ObserverUnion}}-or-[=internal observer=] |observer|, and a {{SubscribeOptions}} |options|, run
Expand Down Expand Up @@ -556,15 +693,25 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w

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

<p class=XXX>Spec the exact semantics of {{Observable/from()}} conversion.</p>
<div algorithm>
The <dfn for=Observable method><code>from(|value|)</code></dfn> method steps
are:

1. Return the result of <a for=Observable lt="convert to an Observable">
converting</a> |value| to an Observable.

</div>

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

<div algorithm>
The <dfn for=Observable method><code>takeUntil(|notifier|)</code></dfn> method steps are:
The <dfn for=Observable method><code>takeUntil(|value|)</code></dfn> method steps are:

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

1. Let |notifier| be the result of <a for=Observable lt="convert to an Observable">
converting</a> |value| to an Observable.

1. Let |observable| be a [=new=] {{Observable}} whose [=Observable/subscribe callback=] is an
algorithm that takes a {{Subscriber}} |subscriber| and does the following:

Expand Down

0 comments on commit 55ee428

Please sign in to comment.