Skip to content

Commit

Permalink
feat: method added
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergey Krasnov committed Mar 18, 2024
1 parent 6eb8d12 commit f403b72
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 15 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
## to install the package

```bash
npm install event-notifier
npm install @ksv90/event-notifier
```

## after that you can use
Expand Down
8 changes: 5 additions & 3 deletions src/__tests__/notifier.bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ import { EventNotifier } from '../index';
import { Data } from './context';

describe('benchmarking', () => {
const fn = ({ value = 1 }) => value + 1;
const fn = ({ value = 1 }) => {
value + 1;
};

bench('on method without data', () => {
const eventNotifier = new EventNotifier<Data>();
eventNotifier.on('test', fn);
eventNotifier.notify({ type: 'test' });
eventNotifier.emit({ type: 'test' });
eventNotifier.off('test', fn);
});

bench('on method with data', () => {
const eventNotifier = new EventNotifier<Data>();
eventNotifier.on('balance', fn);
eventNotifier.notify({ type: 'balance', value: 42 });
eventNotifier.emit({ type: 'balance', value: 42 });
eventNotifier.off('balance', fn);
});
});
60 changes: 49 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,69 @@
export type EventNotifierListener<TData> = (data: TData extends object ? TData : object) => void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type EventNotifierListener<TData = any> = (data: TData extends object ? TData : object) => void | Promise<void>;

export type NotifyType<TType> = { type: TType };

export type NotifyListenerOptions = {
readonly once?: boolean;
};

export class EventNotifier<TEventNotifierData extends Record<string, object | undefined>> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
protected listenerMap = new Map<keyof TEventNotifierData, Set<EventNotifierListener<any>>>();
protected listenerMap = new Map<
keyof TEventNotifierData,
Map<EventNotifierListener, NotifyListenerOptions | undefined>
>();

public emit<TType extends keyof TEventNotifierData>(
event: TEventNotifierData[TType] extends object ? NotifyType<TType> & TEventNotifierData[TType] : NotifyType<TType>,
): void {
const { type, ...data } = event;
this.listenerMap.get(type)?.forEach((options, listener, map) => {
if (options?.once) map.delete(listener);
void listener(data);
});
}

public on<TType extends keyof TEventNotifierData>(
type: TType,
listener: EventNotifierListener<TEventNotifierData[TType]>,
options?: NotifyListenerOptions,
): void {
const listeners = this.listenerMap.get(type) ?? new Set();
const listeners = this.listenerMap.get(type) ?? new Map<EventNotifierListener, NotifyListenerOptions>();
listeners.set(listener, options);
this.listenerMap.set(type, listeners);
listeners.add(listener);
}

public off<TType extends keyof TEventNotifierData>(
type: TType,
listener: EventNotifierListener<TEventNotifierData[TType]>,
): void {
this.listenerMap.get(type)?.delete(listener);
this.listenerMap.get(type)?.forEach((_, currentListener, map) => {
if (currentListener !== listener) return;
map.delete(listener);
});
}

public notify<TType extends keyof TEventNotifierData>(
event: TEventNotifierData[TType] extends object ? NotifyType<TType> & TEventNotifierData[TType] : NotifyType<TType>,
): void {
const { type, ...data } = event;
this.listenerMap.get(type)?.forEach((listener) => listener(data));
public once<TType extends keyof TEventNotifierData>(
type: TType,
listener: EventNotifierListener<TEventNotifierData[TType]>,
options?: Omit<NotifyListenerOptions, 'once'>,
) {
this.on(type, listener, { ...options, once: true });
}

public has<TType extends keyof TEventNotifierData>(
type: TType,
listener: EventNotifierListener<TEventNotifierData[TType]>,
): boolean {
const listeners = this.listenerMap.get(type);
return !!listeners && listeners.has(listener);
}

public delete<TType extends keyof TEventNotifierData>(type: TType): void {
this.listenerMap.delete(type);
}

public clear(): void {
this.listenerMap.clear();
}
}

0 comments on commit f403b72

Please sign in to comment.