Skip to content

Commit

Permalink
feat: AbstractError no longer extends CustomEvent and instead `de…
Browse files Browse the repository at this point in the history
…tail` is defaulted to `undefined`
  • Loading branch information
CMCDragonkai committed Sep 20, 2023
1 parent 0da31bb commit 97caa8f
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 200 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Events for push-flow abstractions.

```ts
// For when you just want a regular event without `detail`
// Note that the `detail` type is `null`
// Note that the `detail` type is `undefined`, unlike `CustomEvent`
class Event1 extends AbstractEvent {}

// For when you want a event with `detail`
Expand All @@ -21,13 +21,11 @@ class Event2 extends AbstractEvent<string> {}
class Event3<T> extends AbstractEvent<T> {}

// Allow caller to customise the `detail` type
// But this is more accurate as not passing anything
// Would mean the `detail` is in fact `null`
class Event4<T = null> extends AbstractEvent<T> {}
class Event4<T extends Event = Event> extends AbstractEvent<T> {}

// When you need to customise the constructor signature
class Event5 extends AbstractEvent<string> {
constructor(options: CustomEventInit<string>) {
constructor(options: EventInit & { detail: string }) {
// Make sure you pass `arguments`!
super(Event5.name, options, arguments);
}
Expand Down Expand Up @@ -82,6 +80,8 @@ This will terminate the infinite loop on the first time it gets handled.

Therefore it is a good idea to always be as specific with your event types as possible.

Furthermore any unhandled rejections or uncaught exceptions will be redispatched as `EventError`. However if there's no listener registered for this, it will be thrown up as an uncaught exception.

## Installation

```sh
Expand Down
2 changes: 1 addition & 1 deletion docs/assets/search.js

Large diffs are not rendered by default.

142 changes: 72 additions & 70 deletions docs/classes/AbstractEvent.html

Large diffs are not rendered by default.

81 changes: 42 additions & 39 deletions docs/classes/EventAll.html

Large diffs are not rendered by default.

81 changes: 42 additions & 39 deletions docs/classes/EventDefault.html

Large diffs are not rendered by default.

77 changes: 40 additions & 37 deletions docs/classes/EventError.html

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ <h2>@matrixai/events</h2></div>
<div class="tsd-panel tsd-typography"><a id="md:js-events" class="tsd-anchor"></a><h1><a href="#md:js-events">js-events</a></h1><p>staging:<a href="https://gitlab.com/MatrixAI/open-source/js-events/commits/staging"><img src="https://gitlab.com/MatrixAI/open-source/js-events/badges/staging/pipeline.svg" alt="pipeline status"></a>
master:<a href="https://gitlab.com/MatrixAI/open-source/js-events/commits/master"><img src="https://gitlab.com/MatrixAI/open-source/js-events/badges/master/pipeline.svg" alt="pipeline status"></a></p>
<p>Events for push-flow abstractions.</p>
<a id="md:abstractevent" class="tsd-anchor"></a><h3><a href="#md:abstractevent"><code>AbstractEvent</code></a></h3><pre><code class="language-ts"><span class="hl-0">// For when you just want a regular event without `detail`</span><br/><span class="hl-0">// Note that the `detail` type is `null`</span><br/><span class="hl-1">class</span><span class="hl-2"> </span><span class="hl-3">Event1</span><span class="hl-2"> </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">AbstractEvent</span><span class="hl-2"> {}</span><br/><br/><span class="hl-0">// For when you want a event with `detail`</span><br/><span class="hl-1">class</span><span class="hl-2"> </span><span class="hl-3">Event2</span><span class="hl-2"> </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">AbstractEvent</span><span class="hl-2">&lt;</span><span class="hl-3">string</span><span class="hl-2">&gt; {}</span><br/><br/><span class="hl-0">// Allow caller to customise the `detail` type</span><br/><span class="hl-0">// Note that the `detail` type is `unknown`</span><br/><span class="hl-0">// This would be rare to use, prefer `Event4`</span><br/><span class="hl-1">class</span><span class="hl-2"> </span><span class="hl-3">Event3</span><span class="hl-2">&lt;</span><span class="hl-3">T</span><span class="hl-2">&gt; </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">AbstractEvent</span><span class="hl-2">&lt;</span><span class="hl-3">T</span><span class="hl-2">&gt; {}</span><br/><br/><span class="hl-0">// Allow caller to customise the `detail` type</span><br/><span class="hl-0">// But this is more accurate as not passing anything</span><br/><span class="hl-0">// Would mean the `detail` is in fact `null`</span><br/><span class="hl-1">class</span><span class="hl-2"> </span><span class="hl-3">Event4</span><span class="hl-2">&lt;</span><span class="hl-3">T</span><span class="hl-2"> = </span><span class="hl-3">null</span><span class="hl-2">&gt; </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">AbstractEvent</span><span class="hl-2">&lt;</span><span class="hl-3">T</span><span class="hl-2">&gt; {}</span><br/><br/><span class="hl-0">// When you need to customise the constructor signature</span><br/><span class="hl-1">class</span><span class="hl-2"> </span><span class="hl-3">Event5</span><span class="hl-2"> </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">AbstractEvent</span><span class="hl-2">&lt;</span><span class="hl-3">string</span><span class="hl-2">&gt; {</span><br/><span class="hl-2"> </span><span class="hl-1">constructor</span><span class="hl-2">(</span><span class="hl-4">options</span><span class="hl-2">: </span><span class="hl-3">CustomEventInit</span><span class="hl-2">&lt;</span><span class="hl-3">string</span><span class="hl-2">&gt;) {</span><br/><span class="hl-2"> </span><span class="hl-0">// Make sure you pass `arguments`!</span><br/><span class="hl-2"> </span><span class="hl-1">super</span><span class="hl-2">(</span><span class="hl-4">Event5</span><span class="hl-2">.</span><span class="hl-4">name</span><span class="hl-2">, </span><span class="hl-4">options</span><span class="hl-2">, </span><span class="hl-1">arguments</span><span class="hl-2">);</span><br/><span class="hl-2"> }</span><br/><span class="hl-2">}</span>
<a id="md:abstractevent" class="tsd-anchor"></a><h3><a href="#md:abstractevent"><code>AbstractEvent</code></a></h3><pre><code class="language-ts"><span class="hl-0">// For when you just want a regular event without `detail`</span><br/><span class="hl-0">// Note that the `detail` type is `undefined`, unlike `CustomEvent`</span><br/><span class="hl-1">class</span><span class="hl-2"> </span><span class="hl-3">Event1</span><span class="hl-2"> </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">AbstractEvent</span><span class="hl-2"> {}</span><br/><br/><span class="hl-0">// For when you want a event with `detail`</span><br/><span class="hl-1">class</span><span class="hl-2"> </span><span class="hl-3">Event2</span><span class="hl-2"> </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">AbstractEvent</span><span class="hl-2">&lt;</span><span class="hl-3">string</span><span class="hl-2">&gt; {}</span><br/><br/><span class="hl-0">// Allow caller to customise the `detail` type</span><br/><span class="hl-0">// Note that the `detail` type is `unknown`</span><br/><span class="hl-0">// This would be rare to use, prefer `Event4`</span><br/><span class="hl-1">class</span><span class="hl-2"> </span><span class="hl-3">Event3</span><span class="hl-2">&lt;</span><span class="hl-3">T</span><span class="hl-2">&gt; </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">AbstractEvent</span><span class="hl-2">&lt;</span><span class="hl-3">T</span><span class="hl-2">&gt; {}</span><br/><br/><span class="hl-0">// Allow caller to customise the `detail` type</span><br/><span class="hl-1">class</span><span class="hl-2"> </span><span class="hl-3">Event4</span><span class="hl-2">&lt;</span><span class="hl-3">T</span><span class="hl-2"> </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">Event</span><span class="hl-2"> = </span><span class="hl-3">Event</span><span class="hl-2">&gt; </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">AbstractEvent</span><span class="hl-2">&lt;</span><span class="hl-3">T</span><span class="hl-2">&gt; {}</span><br/><br/><span class="hl-0">// When you need to customise the constructor signature</span><br/><span class="hl-1">class</span><span class="hl-2"> </span><span class="hl-3">Event5</span><span class="hl-2"> </span><span class="hl-1">extends</span><span class="hl-2"> </span><span class="hl-3">AbstractEvent</span><span class="hl-2">&lt;</span><span class="hl-3">string</span><span class="hl-2">&gt; {</span><br/><span class="hl-2"> </span><span class="hl-1">constructor</span><span class="hl-2">(</span><span class="hl-4">options</span><span class="hl-2">: </span><span class="hl-3">EventInit</span><span class="hl-2"> &amp; { </span><span class="hl-4">detail</span><span class="hl-2">: </span><span class="hl-3">string</span><span class="hl-2"> }) {</span><br/><span class="hl-2"> </span><span class="hl-0">// Make sure you pass `arguments`!</span><br/><span class="hl-2"> </span><span class="hl-1">super</span><span class="hl-2">(</span><span class="hl-4">Event5</span><span class="hl-2">.</span><span class="hl-4">name</span><span class="hl-2">, </span><span class="hl-4">options</span><span class="hl-2">, </span><span class="hl-1">arguments</span><span class="hl-2">);</span><br/><span class="hl-2"> }</span><br/><span class="hl-2">}</span>
</code><button>Copy</button></pre>
<p>When redispatching an event, you must call <code>event.clone()</code>. The same instance cannot be redispatched. When the event is cloned, all constructor parameters are shallow-copied.</p>
<a id="md:evented" class="tsd-anchor"></a><h3><a href="#md:evented"><code>Evented</code></a></h3><p>We combine <code>Evented</code> with <code>AbstractEvent</code> to gain type-safety and convenience of the wildcard any handler.</p>
Expand All @@ -27,6 +27,7 @@ <h2>@matrixai/events</h2></div>
</code><button>Copy</button></pre>
<p>This will terminate the infinite loop on the first time it gets handled.</p>
<p>Therefore it is a good idea to always be as specific with your event types as possible.</p>
<p>Furthermore any unhandled rejections or uncaught exceptions will be redispatched as <code>EventError</code>. However if there&#39;s no listener registered for this, it will be thrown up as an uncaught exception.</p>
<a id="md:installation" class="tsd-anchor"></a><h2><a href="#md:installation">Installation</a></h2><pre><code class="language-sh"><span class="hl-5">npm</span><span class="hl-2"> </span><span class="hl-8">install</span><span class="hl-2"> </span><span class="hl-1">--save</span><span class="hl-2"> </span><span class="hl-8">@matrixai/events</span>
</code><button>Copy</button></pre>
<a id="md:development" class="tsd-anchor"></a><h2><a href="#md:development">Development</a></h2><p>Run <code>nix-shell</code>, and once you&#39;re inside, you can use:</p>
Expand Down
10 changes: 7 additions & 3 deletions src/AbstractEvent.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/**
* By default the `detail` property of `CustomEvent` is `null`.
* So the default type has to be `null` too.
* Unlike `CustomEvent`, the `detail` property can be `undefined`.
* It will not default to `null`.
*/
class AbstractEvent<T = null> extends CustomEvent<T> {
class AbstractEvent<T = undefined> extends Event {
public readonly detail: T;

protected constructorParams: IArguments;

public constructor(
Expand All @@ -21,8 +23,10 @@ class AbstractEvent<T = null> extends CustomEvent<T> {
) {
if (typeof type === 'string') {
super(type, options as CustomEventInit<T> | undefined);
this.detail = (options as CustomEventInit<T> | undefined)?.detail as T;
} else {
super(new.target.name, type);
this.detail = type.detail as T;
constructorParams = options as IArguments | undefined;
}
this.constructorParams = constructorParams ?? arguments;
Expand Down
2 changes: 1 addition & 1 deletion src/EventAll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import AbstractEvent from './AbstractEvent';
/**
* EventAll wraps all dispatched events including already handled events.
*/
class EventAll<T = Event> extends AbstractEvent<T> {
class EventAll<T extends Event = Event> extends AbstractEvent<T> {
public constructor(options: EventInit & { detail: T }) {
super(EventAll.name, options, arguments);
}
Expand Down
2 changes: 1 addition & 1 deletion src/EventDefault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import AbstractEvent from './AbstractEvent';
/**
* EventDefault wraps dispatched events that were not handled.
*/
class EventDefault<T = Event> extends AbstractEvent<T> {
class EventDefault<T extends Event = Event> extends AbstractEvent<T> {
public constructor(options: EventInit & { detail: T }) {
super(EventDefault.name, options, arguments);
}
Expand Down
6 changes: 3 additions & 3 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ describe('index', () => {
class Event2 extends AbstractEvent<string> {}
class Event3 extends AbstractEvent<object> {}
const e0 = new Event0();
expect(e0.detail).toBeNull();
expect(e0.detail).toBeUndefined();
const e1 = new Event1();
expect(e1.detail).toBeNull();
expect(e1.detail).toBeUndefined();
const e1_ = new Event1({ detail: 'string' });
expect(e1_.detail).toBe('string');
// This is not caught by the type system
const e2 = new Event2();
expect(e2.detail).toBeNull();
expect(e2.detail).toBeUndefined();
const e2_ = new Event2({ detail: 'string' });
expect(e2_.detail).toBe('string');
const e11 = e1.clone();
Expand Down

0 comments on commit 97caa8f

Please sign in to comment.