easy-signal 1.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,9 +21,10 @@ Signals offer similar functionality as the browser's `eventDispatcher` API, but
21
21
  import { signal } from 'easy-signal';
22
22
 
23
23
  // Create the signal and export it for use. Optionally provide the subscriber signature
24
- export const onSecond = signal<(second: number) => any>();
24
+ export const onSecond = signal<number>();
25
25
 
26
- setInterval(() => onSecond.dispatch(Math.floor(Date.now() / 1000)));
26
+ // Passing a non-function value will dispatch the event
27
+ setInterval(() => onSecond(Math.floor(Date.now() / 1000)));
27
28
  ```
28
29
 
29
30
  ```ts
@@ -34,3 +35,28 @@ const unsubscribe = onSecond(seconds => {
34
35
  console.log(seconds, 'since epoc');
35
36
  });
36
37
  ```
38
+
39
+ Errors may also be listened to and dispatched from the signal by using the second parameter when adding the listener
40
+ and by passing an Error object to the dispatch.
41
+
42
+ ```ts
43
+ import { signal } from 'easy-signal';
44
+
45
+ const dataStream = signal();
46
+
47
+ dataStream(data => console.log('data is:' data));
48
+ dataStream(error => console.log('Error is:' error), { captureErrors: true });
49
+
50
+ stream.on('data', obj => dataStream(obj));
51
+ stream.on('error', err => dataStream(err));
52
+ ```
53
+
54
+ To clear the listeners from the signal, pass in the `ClearSignal` constant.
55
+
56
+ ```ts
57
+ import { signal, ClearSignal } from 'easy-signal';
58
+
59
+ const onSomething = signal();
60
+
61
+ onSomething(ClearSignal); // clears signal
62
+ ```
package/index.d.ts CHANGED
@@ -1,9 +1,29 @@
1
- declare type Args<T> = T extends (...args: infer A) => any ? A : never;
2
- export declare type Subscriber = (...args: any[]) => any;
3
- export declare type Unsubscriber = () => boolean;
4
- export declare type Signal<T extends Subscriber = Subscriber> = {
5
- (listener: T): Unsubscriber;
6
- dispatch: (...args: Args<T>) => void;
1
+ export declare type Subscriber<T> = (data: T) => any;
2
+ export declare type Unsubscriber = () => void;
3
+ export declare type Signal<T> = {
4
+ (data: T): void;
5
+ (data: Error): void;
6
+ (subscriber: Subscriber<T>): Unsubscriber;
7
+ (errorListener: Subscriber<Error>, options: {
8
+ captureErrors: true;
9
+ }): Unsubscriber;
7
10
  };
8
- export declare function signal<T extends Subscriber = Subscriber>(): Signal<T>;
9
- export {};
11
+ export declare const ClearSignal: {};
12
+ /**
13
+ * Creates a signal, a function that can be used to subscribe to events. The signal can be called with a subscriber
14
+ * function, which will be called when the signal is dispatched. The signal can also be called with data, which will
15
+ * dispatch to all subscribers. An optional second argument can be passed to subscribe to errors instead. When the
16
+ * signal is called with an instance of Error, it will dispatch to all error listeners.
17
+ * The signal can also be called with `ClearSignal`, which will clear all subscribers.
18
+ * @example
19
+ * const onLoad = signal();
20
+ *
21
+ * // Subscribe to data
22
+ * onLoad((data) => console.log('loaded', data));
23
+ * onLoad((error) => console.error('error', error), true);
24
+ *
25
+ * // Dispatch data
26
+ * onLoad('data'); // logs 'loaded data'
27
+ * onLoad(new Error('error')); // logs 'error Error: error'
28
+ */
29
+ export declare function signal<T = any>(): Signal<T>;
package/index.js CHANGED
@@ -1,10 +1,42 @@
1
+ export const ClearSignal = {};
2
+ /**
3
+ * Creates a signal, a function that can be used to subscribe to events. The signal can be called with a subscriber
4
+ * function, which will be called when the signal is dispatched. The signal can also be called with data, which will
5
+ * dispatch to all subscribers. An optional second argument can be passed to subscribe to errors instead. When the
6
+ * signal is called with an instance of Error, it will dispatch to all error listeners.
7
+ * The signal can also be called with `ClearSignal`, which will clear all subscribers.
8
+ * @example
9
+ * const onLoad = signal();
10
+ *
11
+ * // Subscribe to data
12
+ * onLoad((data) => console.log('loaded', data));
13
+ * onLoad((error) => console.error('error', error), true);
14
+ *
15
+ * // Dispatch data
16
+ * onLoad('data'); // logs 'loaded data'
17
+ * onLoad(new Error('error')); // logs 'error Error: error'
18
+ */
1
19
  export function signal() {
2
- const listeners = new Set();
3
- function subscribe(listener) {
4
- listeners.add(listener);
5
- return () => listeners.delete(listener);
20
+ const subscribers = new Set();
21
+ const errorListeners = new Set();
22
+ function subscribe(arg, options) {
23
+ if (typeof arg === 'function') {
24
+ const listeners = options?.captureErrors ? errorListeners : subscribers;
25
+ listeners.add(arg);
26
+ return () => {
27
+ listeners.delete(arg);
28
+ };
29
+ }
30
+ else if (arg === ClearSignal) {
31
+ subscribers.clear();
32
+ errorListeners.clear();
33
+ }
34
+ else if (arg instanceof Error) {
35
+ errorListeners.forEach(listener => listener(arg));
36
+ }
37
+ else {
38
+ subscribers.forEach(listener => listener(arg));
39
+ }
6
40
  }
7
- subscribe.dispatch = (...args) => listeners.forEach(listener => listener(...args));
8
- subscribe.clear = listeners.clear.bind(listeners);
9
41
  return subscribe;
10
42
  }
package/index.ts CHANGED
@@ -1,22 +1,56 @@
1
- type Args<T> = T extends (...args: infer A) => any ? A : never;
2
- export type Subscriber = (...args: any[]) => any;
3
- export type Unsubscriber = () => boolean;
1
+ export type Subscriber<T> = (data: T) => any;
2
+ export type Unsubscriber = () => void;
4
3
 
5
- export type Signal<T extends Subscriber = Subscriber> = {
6
- (listener: T): Unsubscriber;
7
- dispatch: (...args: Args<T>) => void;
4
+ export type Signal<T> = {
5
+ (data: T): void;
6
+ (data: Error): void;
7
+ (subscriber: Subscriber<T>): Unsubscriber;
8
+ (errorListener: Subscriber<Error>, options: { captureErrors: true }): Unsubscriber;
8
9
  }
9
10
 
10
- export function signal<T extends Subscriber = Subscriber>(): Signal<T> {
11
- const listeners = new Set<T>();
11
+ export const ClearSignal = {};
12
12
 
13
- function subscribe(listener: T) {
14
- listeners.add(listener);
15
- return () => listeners.delete(listener);
16
- }
13
+ /**
14
+ * Creates a signal, a function that can be used to subscribe to events. The signal can be called with a subscriber
15
+ * function, which will be called when the signal is dispatched. The signal can also be called with data, which will
16
+ * dispatch to all subscribers. An optional second argument can be passed to subscribe to errors instead. When the
17
+ * signal is called with an instance of Error, it will dispatch to all error listeners.
18
+ * The signal can also be called with `ClearSignal`, which will clear all subscribers.
19
+ * @example
20
+ * const onLoad = signal();
21
+ *
22
+ * // Subscribe to data
23
+ * onLoad((data) => console.log('loaded', data));
24
+ * onLoad((error) => console.error('error', error), true);
25
+ *
26
+ * // Dispatch data
27
+ * onLoad('data'); // logs 'loaded data'
28
+ * onLoad(new Error('error')); // logs 'error Error: error'
29
+ */
30
+ export function signal<T = any>(): Signal<T> {
31
+ const subscribers = new Set<Subscriber<T>>();
32
+ const errorListeners = new Set<Subscriber<Error>>();
17
33
 
18
- subscribe.dispatch = (...args: Args<T>) => listeners.forEach(listener => listener(...args));
19
- subscribe.clear = listeners.clear.bind(listeners);
34
+ function subscribe(data: T): void;
35
+ function subscribe(error: Error): void;
36
+ function subscribe(subscriber: Subscriber<T>): Unsubscriber;
37
+ function subscribe(listener: Subscriber<Error>, options: { captureErrors: true }): Unsubscriber;
38
+ function subscribe(arg: T | Error | Subscriber<T> | Subscriber<Error>, options?: { captureErrors: true }): Unsubscriber {
39
+ if (typeof arg === 'function') {
40
+ const listeners = options?.captureErrors ? errorListeners : subscribers;
41
+ listeners.add(arg as any);
42
+ return () => {
43
+ listeners.delete(arg as any);
44
+ };
45
+ } else if (arg === ClearSignal) {
46
+ subscribers.clear();
47
+ errorListeners.clear();
48
+ } else if (arg instanceof Error) {
49
+ errorListeners.forEach(listener => listener(arg));
50
+ } else {
51
+ subscribers.forEach(listener => listener(arg));
52
+ }
53
+ }
20
54
 
21
55
  return subscribe;
22
56
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "easy-signal",
3
- "version": "1.0.1",
4
- "description": "A tiny (10 LOC), simple utility for alerting subscribers when an event happens.",
3
+ "version": "2.0.0",
4
+ "description": "A tiny (25 LOC), simple utility for alerting subscribers when an event happens, allowing for error handling and clearing.",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "build": "tsc",