easy-signal 1.0.2 → 2.0.1

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
@@ -1,6 +1,10 @@
1
1
  # Easy Signal
2
2
 
3
- A simple interface for creating a defined event or action that can be triggered with a set API and listened to by any number of subscribers.
3
+ A simple interface for creating a defined event or action that can be triggered and listened to by any number of
4
+ subscribers. Producing a single function that can be used to subscribe to the events, subscribe to errors, and dispatch
5
+ events and errors.
6
+
7
+ Full type safety with TypeScript providing good autocomplete.
4
8
 
5
9
  ## Installation
6
10
 
@@ -10,9 +14,13 @@ npm install easy-signal
10
14
 
11
15
  ## Usage
12
16
 
13
- A signal is a subscriber function that represents a single event. A signal function (the subscriber) has a function attached to it called `dispatch()` to trigger the event.
17
+ A signal is a function that represents a single event. The function can be used to subscribe to be notified of the
18
+ events as well as to trigger them.
14
19
 
15
- Signals offer similar functionality as the browser's `eventDispatcher` API, but rather than a general API for any event, each event would use its own signal. This allows each signal to have a specific function signature as opposed to the browser's generic `event` object. This is a great system in TypeScript being able to see the exact data each event produces.
20
+ Signals offer similar functionality as the browser's `eventDispatcher` API, but rather than a general API for any event,
21
+ each event would use its own signal. This allows each signal to have a specific function signature as opposed to the
22
+ browser's generic `event` object. This is a great system in TypeScript being able to see the exact data each event
23
+ produces.
16
24
 
17
25
  ### Basic Usage
18
26
 
@@ -21,9 +29,13 @@ Signals offer similar functionality as the browser's `eventDispatcher` API, but
21
29
  import { signal } from 'easy-signal';
22
30
 
23
31
  // Create the signal and export it for use. Optionally provide the subscriber signature
24
- export const onSecond = signal<(second: number) => any>();
32
+ export const onSecond = signal<number>();
25
33
 
26
- setInterval(() => onSecond.dispatch(Math.floor(Date.now() / 1000)));
34
+ // Passing a non-function value will dispatch the event
35
+ setInterval(() => {
36
+ const currentSecond = Math.floor(Date.now() / 1000);
37
+ onSecond(currentSecond);
38
+ });
27
39
  ```
28
40
 
29
41
  ```ts
@@ -35,15 +47,47 @@ const unsubscribe = onSecond(seconds => {
35
47
  });
36
48
  ```
37
49
 
38
- The TypeScript definition has been extended to allow an `error` signal to be added to an existing signal for situations
39
- where a signal may need to handle errors.
50
+ Errors may also be listened to from the signal by passing `ForErrors` as the second parameter when adding the listener
51
+ and errors may be dispatched by passing an Error object to the signal method.
40
52
 
41
53
  ```ts
42
- import { signal } from 'easy-signal';
54
+ import { signal, ForErrors } from 'easy-signal';
43
55
 
44
56
  const dataStream = signal();
45
- dataStream.error = signal();
46
57
 
47
- stream.on('data', obj => dataStream.dispatch(obj))
48
- stream.on('error', err => dataStream.error.dispatch(err))
58
+ dataStream(data => console.log('data is:' data));
59
+ dataStream(error => console.log('Error is:' error), ForErrors);
60
+
61
+ stream.on('data', obj => dataStream(obj));
62
+ stream.on('error', err => dataStream(err));
63
+ ```
64
+
65
+ To get a subscriber-only method for external use, pass in the `GetOnSignal` constant.
66
+
67
+ ```ts
68
+ import { signal, GetOnSignal } from 'easy-signal';
69
+
70
+
71
+ function getMyAPI() {
72
+ const doSomething = signal();
73
+
74
+ // doSomething() will trigger subscribers that were added in onSomething(...). This protects the signal from being
75
+ // triggered/dispatched outside of `getMyAPI`. Sometimes you may want more control to prevent just anyone from
76
+ // triggering the event.
77
+
78
+ return {
79
+ onSomething: doSomething(GetOnSignal),
80
+ };
81
+ }
82
+ ```
83
+
84
+
85
+ To clear the listeners from the signal, pass in the `ClearSignal` constant.
86
+
87
+ ```ts
88
+ import { signal, ClearSignal } from 'easy-signal';
89
+
90
+ const onSomething = signal();
91
+
92
+ onSomething(ClearSignal); // clears signal
49
93
  ```
package/index.d.ts CHANGED
@@ -1,10 +1,36 @@
1
1
  declare type Args<T> = T extends (...args: infer A) => any ? A : never;
2
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;
7
- error?: Signal<(err: Error) => any>;
3
+ export declare type ErrorSubscriber = (error: Error) => any;
4
+ export declare type Unsubscriber = () => void;
5
+ export declare type OnSignal<T extends Subscriber = Subscriber> = {
6
+ (subscriber: T): Unsubscriber;
7
+ (errorListener: ErrorSubscriber, what: typeof ForErrors): Unsubscriber;
8
8
  };
9
+ export declare type Signal<T extends Subscriber = Subscriber> = OnSignal<T> & {
10
+ (...args: Args<T>): void;
11
+ (data: Error): void;
12
+ (data: typeof ClearSignal): void;
13
+ (data: typeof GetOnSignal): OnSignal<T>;
14
+ };
15
+ export declare const ClearSignal: unique symbol;
16
+ export declare const GetOnSignal: unique symbol;
17
+ export declare const ForErrors: unique symbol;
18
+ /**
19
+ * Creates a signal, a function that can be used to subscribe to events. The signal can be called with a subscriber
20
+ * function, which will be called when the signal is dispatched. The signal can also be called with data, which will
21
+ * dispatch to all subscribers. An optional second argument can be passed to subscribe to errors instead. When the
22
+ * signal is called with an instance of Error, it will dispatch to all error listeners.
23
+ * The signal can also be called with `ClearSignal`, which will clear all subscribers.
24
+ * @example
25
+ * const onLoad = signal();
26
+ *
27
+ * // Subscribe to data
28
+ * onLoad((data) => console.log('loaded', data));
29
+ * onLoad((error) => console.error('error', error), true);
30
+ *
31
+ * // Dispatch data
32
+ * onLoad('data'); // logs 'loaded data'
33
+ * onLoad(new Error('error')); // logs 'error Error: error'
34
+ */
9
35
  export declare function signal<T extends Subscriber = Subscriber>(): Signal<T>;
10
36
  export {};
package/index.js CHANGED
@@ -1,10 +1,51 @@
1
+ export const ClearSignal = Symbol();
2
+ export const GetOnSignal = Symbol();
3
+ export const ForErrors = Symbol();
4
+ /**
5
+ * Creates a signal, a function that can be used to subscribe to events. The signal can be called with a subscriber
6
+ * function, which will be called when the signal is dispatched. The signal can also be called with data, which will
7
+ * dispatch to all subscribers. An optional second argument can be passed to subscribe to errors instead. When the
8
+ * signal is called with an instance of Error, it will dispatch to all error listeners.
9
+ * The signal can also be called with `ClearSignal`, which will clear all subscribers.
10
+ * @example
11
+ * const onLoad = signal();
12
+ *
13
+ * // Subscribe to data
14
+ * onLoad((data) => console.log('loaded', data));
15
+ * onLoad((error) => console.error('error', error), true);
16
+ *
17
+ * // Dispatch data
18
+ * onLoad('data'); // logs 'loaded data'
19
+ * onLoad(new Error('error')); // logs 'error Error: error'
20
+ */
1
21
  export function signal() {
2
- const listeners = new Set();
3
- function subscribe(listener) {
4
- listeners.add(listener);
5
- return () => listeners.delete(listener);
22
+ const subscribers = new Set();
23
+ const errorListeners = new Set();
24
+ function onSignal(subscriber, what) {
25
+ const listeners = what === ForErrors ? errorListeners : subscribers;
26
+ listeners.add(subscriber);
27
+ return () => {
28
+ listeners.delete(subscriber);
29
+ };
6
30
  }
7
- subscribe.dispatch = (...args) => listeners.forEach(listener => listener(...args));
8
- subscribe.clear = listeners.clear.bind(listeners);
9
- return subscribe;
31
+ function signal(...args) {
32
+ const arg = args[0];
33
+ if (typeof arg === 'function') {
34
+ return onSignal(arg);
35
+ }
36
+ else if (arg === ClearSignal) {
37
+ subscribers.clear();
38
+ errorListeners.clear();
39
+ }
40
+ else if (arg === GetOnSignal) {
41
+ return onSignal;
42
+ }
43
+ else if (arg instanceof Error) {
44
+ errorListeners.forEach(listener => listener(arg));
45
+ }
46
+ else {
47
+ subscribers.forEach(listener => listener(...args));
48
+ }
49
+ }
50
+ return signal;
10
51
  }
package/index.ts CHANGED
@@ -1,23 +1,75 @@
1
1
  type Args<T> = T extends (...args: infer A) => any ? A : never;
2
2
  export type Subscriber = (...args: any[]) => any;
3
- export type Unsubscriber = () => boolean;
3
+ export type ErrorSubscriber = (error: Error) => any;
4
+ export type Unsubscriber = () => void;
4
5
 
5
- export type Signal<T extends Subscriber = Subscriber> = {
6
- (listener: T): Unsubscriber;
7
- dispatch: (...args: Args<T>) => void;
8
- error?: Signal<(err: Error) => any>;
6
+ export type OnSignal<T extends Subscriber = Subscriber> = {
7
+ (subscriber: T): Unsubscriber;
8
+ (errorListener: ErrorSubscriber, what: typeof ForErrors): Unsubscriber;
9
9
  }
10
10
 
11
+ export type Signal<T extends Subscriber = Subscriber> = OnSignal<T> & {
12
+ (...args: Args<T>): void;
13
+ (data: Error): void;
14
+ (data: typeof ClearSignal): void;
15
+ (data: typeof GetOnSignal): OnSignal<T>;
16
+ }
17
+
18
+ export const ClearSignal = Symbol();
19
+ export const GetOnSignal = Symbol();
20
+ export const ForErrors = Symbol();
21
+
22
+
23
+ /**
24
+ * Creates a signal, a function that can be used to subscribe to events. The signal can be called with a subscriber
25
+ * function, which will be called when the signal is dispatched. The signal can also be called with data, which will
26
+ * dispatch to all subscribers. An optional second argument can be passed to subscribe to errors instead. When the
27
+ * signal is called with an instance of Error, it will dispatch to all error listeners.
28
+ * The signal can also be called with `ClearSignal`, which will clear all subscribers.
29
+ * @example
30
+ * const onLoad = signal();
31
+ *
32
+ * // Subscribe to data
33
+ * onLoad((data) => console.log('loaded', data));
34
+ * onLoad((error) => console.error('error', error), true);
35
+ *
36
+ * // Dispatch data
37
+ * onLoad('data'); // logs 'loaded data'
38
+ * onLoad(new Error('error')); // logs 'error Error: error'
39
+ */
11
40
  export function signal<T extends Subscriber = Subscriber>(): Signal<T> {
12
- const listeners = new Set<T>();
41
+ const subscribers = new Set<Subscriber>();
42
+ const errorListeners = new Set<Subscriber>();
13
43
 
14
- function subscribe(listener: T) {
15
- listeners.add(listener);
16
- return () => listeners.delete(listener);
44
+ function onSignal(subscriber: T | ErrorSubscriber, what?: typeof ForErrors): Unsubscriber {
45
+ const listeners = what === ForErrors ? errorListeners : subscribers;
46
+ listeners.add(subscriber);
47
+ return () => {
48
+ listeners.delete(subscriber);
49
+ };
17
50
  }
18
51
 
19
- subscribe.dispatch = (...args: Args<T>) => listeners.forEach(listener => listener(...args));
20
- subscribe.clear = listeners.clear.bind(listeners);
52
+ function signal(...args: Args<T>): void;
53
+ function signal(error: Error): void;
54
+ function signal(data: typeof ClearSignal): void;
55
+ function signal(data: typeof GetOnSignal): OnSignal<T>;
56
+ function signal(subscriber: T): Unsubscriber;
57
+ function signal(errorListener: Subscriber, what: typeof ForErrors): Unsubscriber;
58
+ function signal(...args: any[]): Unsubscriber | OnSignal<T> | void {
59
+ const arg = args[0];
60
+ if (typeof arg === 'function') {
61
+ return onSignal(arg);
62
+ } else if (arg === ClearSignal) {
63
+ subscribers.clear();
64
+ errorListeners.clear();
65
+ } else if (arg === GetOnSignal) {
66
+ return onSignal as OnSignal<T>;
67
+ } else if (arg instanceof Error) {
68
+ errorListeners.forEach(listener => listener(arg));
69
+ } else {
70
+ subscribers.forEach(listener => listener(...args));
71
+ }
72
+ }
21
73
 
22
- return subscribe;
74
+ return signal;
23
75
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "easy-signal",
3
- "version": "1.0.2",
4
- "description": "A tiny (10 LOC), simple utility for alerting subscribers when an event happens.",
3
+ "version": "2.0.1",
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",