Skip to content

Commit

Permalink
Add interface IDL to spec skeleton (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
domfarolino authored Nov 29, 2023
1 parent 54008be commit e153f01
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 87 deletions.
89 changes: 2 additions & 87 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,93 +292,8 @@ custom script](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/Even
As a result, developers can use Observables without migrating tons of code on
the platform, since it's an easy drop-in wherever you're handling events today.

The proposed API shape is as follows:

```js
dictionary ObservableEventListenerOptions {
boolean capture = false;
boolean passive;
};

partial interface EventTarget {
Observable on(DOMString type, optional ObservableEventListenerOptions options);
};

// `SubscribeCallback` is where the Observable "creator's" code lives. It's
// called when `subscribe()` is called, to set up a new subscription.
callback SubscribeCallback = undefined (Subscriber subscriber);
callback ObserverCallback = undefined (any value);

dictionary Observer {
ObserverCallback next;
VoidFunction complete;
ObserverCallback error;
};

dictionary SubscribeOptions {
AbortSignal signal;
};

dictionary PromiseOptions {
AbortSignal signal;
};

[Exposed=*]
interface Subscriber {
undefined next(any result);
undefined complete();
undefined error(any error);
undefined addTeardown(VoidFunction teardown);

// True after the Subscriber is created, up until either
// `complete()`/`error()` are invoked, or the subscriber unsubscribes. Inside
// `complete()`/`error()`, this attribute is true.
readonly attribute boolean active;

readonly attribute AbortSignal signal;
};

callback Predicate = boolean (any value);
callback Reducer = any (any accumulator, any currentValue)
callback Mapper = any (any element, unsigned long long index)
// Differs from `Mapper` only in return type, since this callback is exclusively
// used to visit each element in a sequence, not transform it.
callback Visitor = undefined (any element, unsigned long long index)

[Exposed=*]
interface Observable {
constructor(SubscribeCallback callback);
undefined subscribe(optional Observer observer = {}, optional SubscribeOptions = {});

undefined finally(VoidFunction callback);

// Constructs a native Observable from `value` if it's any of the following:
// - Observable
// - AsyncIterable
// - Iterable
// - Promise
static Observable from(any value);

// Observable-returning operators. See "Operators" section below.
// `takeUntil()` can consume promises, iterables, async iterables, and other
// observables.
Observable takeUntil(any notifier);
Observable map(Mapper mapper);
Observable filter(Predicate predicate);
Observable take(unsigned long long);
Observable drop(unsigned long long);
Observable flatMap(Mapper mapper);
Promise<sequence<any>> toArray(optional PromiseOptions options);
Promise<undefined> forEach(Visitor callback, optional PromiseOptions options);

// Promise-returning. See "Concerns" section below.
Promise<boolean> every(Predicate predicate, optional PromiseOptions options);
// Maybe? Promise<any> first(optional PromiseOptions options);
Promise<any> find(Predicate predicate, optional PromiseOptions options);
Promise<boolean> some(Predicate predicate, optional PromiseOptions options);
Promise<any> reduce(Reducer reducer, optional any initialValue, optional PromiseOptions options);
};
```
The proposed API shape can be found in
https://wicg.github.io/observable/#core-infrastructure.

The creator of an Observable passes in a callback that gets invoked
synchronously whenever `subscribe()` is called. The `subscribe()` method can be
Expand Down
114 changes: 114 additions & 0 deletions spec.bs
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,123 @@ dl, dd {

*This section is non-normative.*

<h2 id=core-infrastructure>Core infrastructure</h2>

<h3 id=subscriber-api>The {{Subscriber}} interface</h3>

<xmp class=idl>
[Exposed=*]
interface Subscriber {
undefined next(any result);
undefined error(any error);
undefined complete();
undefined addTeardown(VoidFunction teardown);

// True after the Subscriber is created, up until either
// complete()/error() are invoked, or the subscriber unsubscribes. Inside
// complete()/error(), this attribute is true.
readonly attribute boolean active;

readonly attribute AbortSignal signal;
};
</xmp>

<div>
</div>

<h3 id=observable-api>The {{Observable}} interface</h3>

<xmp class=idl>
// SubscribeCallback is where the Observable "creator's" code lives. It's
// called when subscribe() is called, to set up a new subscription.
callback SubscribeCallback = undefined (Subscriber subscriber);
callback ObserverCallback = undefined (any value);

dictionary Observer {
ObserverCallback next;
ObserverCallback error;
VoidFunction complete;
};

dictionary SubscribeOptions {
AbortSignal signal;
};

dictionary PromiseOptions {
AbortSignal signal;
};

callback Predicate = boolean (any value);
callback Reducer = any (any accumulator, any currentValue);
callback Mapper = any (any element, unsigned long long index);
// Differs from Mapper only in return type, since this callback is exclusively
// used to visit each element in a sequence, not transform it.
callback Visitor = undefined (any element, unsigned long long index);

[Exposed=*]
interface Observable {
constructor(SubscribeCallback callback);
undefined subscribe(optional Observer observer = {}, optional SubscribeOptions options = {});

undefined finally(VoidFunction callback);

// Constructs a native Observable from value if it's any of the following:
// - Observable
// - AsyncIterable
// - Iterable
// - Promise
static Observable from(any value);

// Observable-returning operators. See "Operators" section in the spec.
//
// takeUntil() can consume promises, iterables, async iterables, and other
// observables.
Observable takeUntil(any notifier);
Observable map(Mapper mapper);
Observable filter(Predicate predicate);
Observable take(unsigned long long amount);
Observable drop(unsigned long long amount);
Observable flatMap(Mapper mapper);

// Promise-returning operators.
Promise<sequence<any>> toArray(optional PromiseOptions options = {});
Promise<undefined> forEach(Visitor callback, optional PromiseOptions options = {});
Promise<boolean> every(Predicate predicate, optional PromiseOptions options = {});
// Maybe? Promise<any> first(optional PromiseOptions options = {});
Promise<any> find(Predicate predicate, optional PromiseOptions options = {});
Promise<boolean> some(Predicate predicate, optional PromiseOptions options = {});
Promise<any> reduce(Reducer reducer, optional any initialValue, optional PromiseOptions options = {});
};
</xmp>

<h3 id=operators>Operators</h3>

For now, see [https://github.com/wicg/observable#operators](https://github.com/wicg/observable#operators).

<h2 id=event-target-integration>{{EventTarget}} integration</h2>

<pre class=idl>
dictionary ObservableEventListenerOptions {
boolean capture = false;
boolean passive;
};

partial interface EventTarget {
Observable on(DOMString type, optional ObservableEventListenerOptions options = {});
};
</pre>


<h2 id=security-and-privacy>Security & Privacy Considerations</h2>

This material is being upstreamed from our explainer into this specification, and in the meantime
you can consult the following resources:

* [TAG Security/Privacy Questionnaire](https://github.com/WICG/observable/blob/master/security-privacy-questionnaire.md)

<h2 id=acks>Acknowledgements</h2>

A special thanks to [Ben Lesh](https://benlesh.com/) for much of the design
input for the {{Observable}} API, and his many years of work maintaining
userland Observable code that made this contribution to the web platform
possible.

0 comments on commit e153f01

Please sign in to comment.