From 69a9f33e3950362db650084c4a3e382ed092da92 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Wed, 10 Apr 2024 16:24:20 +0200 Subject: [PATCH] refactor: rework the dual CommonJS/ES packages --- index.d.ts => lib/cjs/index.d.ts | 0 index.js => lib/cjs/index.js | 0 lib/cjs/package.json | 4 + lib/esm/index.d.ts | 179 +++++++++++++++++++++++++++++++ index.mjs => lib/esm/index.js | 0 lib/esm/package.json | 4 + package.json | 11 +- 7 files changed, 191 insertions(+), 7 deletions(-) rename index.d.ts => lib/cjs/index.d.ts (100%) rename index.js => lib/cjs/index.js (100%) create mode 100644 lib/cjs/package.json create mode 100644 lib/esm/index.d.ts rename index.mjs => lib/esm/index.js (100%) create mode 100644 lib/esm/package.json diff --git a/index.d.ts b/lib/cjs/index.d.ts similarity index 100% rename from index.d.ts rename to lib/cjs/index.d.ts diff --git a/index.js b/lib/cjs/index.js similarity index 100% rename from index.js rename to lib/cjs/index.js diff --git a/lib/cjs/package.json b/lib/cjs/package.json new file mode 100644 index 0000000..b6cc1b6 --- /dev/null +++ b/lib/cjs/package.json @@ -0,0 +1,4 @@ +{ + "name": "@socket.io/component-emitter", + "type": "commonjs" +} diff --git a/lib/esm/index.d.ts b/lib/esm/index.d.ts new file mode 100644 index 0000000..49a74e1 --- /dev/null +++ b/lib/esm/index.d.ts @@ -0,0 +1,179 @@ +/** + * An events map is an interface that maps event names to their value, which + * represents the type of the `on` listener. + */ +export interface EventsMap { + [event: string]: any; +} + +/** + * The default events map, used if no EventsMap is given. Using this EventsMap + * is equivalent to accepting all event names, and any data. + */ +export interface DefaultEventsMap { + [event: string]: (...args: any[]) => void; +} + +/** + * Returns a union type containing all the keys of an event map. + */ +export type EventNames = keyof Map & (string | symbol); + +/** The tuple type representing the parameters of an event listener */ +export type EventParams< + Map extends EventsMap, + Ev extends EventNames + > = Parameters; + +/** + * The event names that are either in ReservedEvents or in UserEvents + */ +export type ReservedOrUserEventNames< + ReservedEventsMap extends EventsMap, + UserEvents extends EventsMap + > = EventNames | EventNames; + +/** + * Type of a listener of a user event or a reserved event. If `Ev` is in + * `ReservedEvents`, the reserved event listener is returned. + */ +export type ReservedOrUserListener< + ReservedEvents extends EventsMap, + UserEvents extends EventsMap, + Ev extends ReservedOrUserEventNames + > = FallbackToUntypedListener< + Ev extends EventNames + ? ReservedEvents[Ev] + : Ev extends EventNames + ? UserEvents[Ev] + : never + >; + +/** + * Returns an untyped listener type if `T` is `never`; otherwise, returns `T`. + * + * This is a hack to mitigate https://github.com/socketio/socket.io/issues/3833. + * Needed because of https://github.com/microsoft/TypeScript/issues/41778 + */ +type FallbackToUntypedListener = [T] extends [never] + ? (...args: any[]) => void | Promise + : T; + +/** + * Strictly typed version of an `EventEmitter`. A `TypedEventEmitter` takes type + * parameters for mappings of event names to event data types, and strictly + * types method calls to the `EventEmitter` according to these event maps. + * + * @typeParam ListenEvents - `EventsMap` of user-defined events that can be + * listened to with `on` or `once` + * @typeParam EmitEvents - `EventsMap` of user-defined events that can be + * emitted with `emit` + * @typeParam ReservedEvents - `EventsMap` of reserved events, that can be + * emitted by socket.io with `emitReserved`, and can be listened to with + * `listen`. + */ +export class Emitter< + ListenEvents extends EventsMap, + EmitEvents extends EventsMap, + ReservedEvents extends EventsMap = {} + > { + /** + * Adds the `listener` function as an event listener for `ev`. + * + * @param ev Name of the event + * @param listener Callback function + */ + on>( + ev: Ev, + listener: ReservedOrUserListener + ): this; + + /** + * Adds a one-time `listener` function as an event listener for `ev`. + * + * @param ev Name of the event + * @param listener Callback function + */ + once>( + ev: Ev, + listener: ReservedOrUserListener + ): this; + + /** + * Removes the `listener` function as an event listener for `ev`. + * + * @param ev Name of the event + * @param listener Callback function + */ + off>( + ev?: Ev, + listener?: ReservedOrUserListener + ): this; + + /** + * Emits an event. + * + * @param ev Name of the event + * @param args Values to send to listeners of this event + */ + emit>( + ev: Ev, + ...args: EventParams + ): this; + + /** + * Emits a reserved event. + * + * This method is `protected`, so that only a class extending + * `StrictEventEmitter` can emit its own reserved events. + * + * @param ev Reserved event name + * @param args Arguments to emit along with the event + */ + protected emitReserved>( + ev: Ev, + ...args: EventParams + ): this; + + /** + * Returns the listeners listening to an event. + * + * @param event Event name + * @returns Array of listeners subscribed to `event` + */ + listeners>( + event: Ev + ): ReservedOrUserListener[]; + + /** + * Returns true if there is a listener for this event. + * + * @param event Event name + * @returns boolean + */ + hasListeners< + Ev extends ReservedOrUserEventNames + >(event: Ev): boolean; + + /** + * Removes the `listener` function as an event listener for `ev`. + * + * @param ev Name of the event + * @param listener Callback function + */ + removeListener< + Ev extends ReservedOrUserEventNames + >( + ev?: Ev, + listener?: ReservedOrUserListener + ): this; + + /** + * Removes all `listener` function as an event listener for `ev`. + * + * @param ev Name of the event + */ + removeAllListeners< + Ev extends ReservedOrUserEventNames + >(ev?: Ev): this; +} diff --git a/index.mjs b/lib/esm/index.js similarity index 100% rename from index.mjs rename to lib/esm/index.js diff --git a/lib/esm/package.json b/lib/esm/package.json new file mode 100644 index 0000000..0511a0c --- /dev/null +++ b/lib/esm/package.json @@ -0,0 +1,4 @@ +{ + "name": "@socket.io/component-emitter", + "type": "module" +} diff --git a/package.json b/package.json index 03e0a3e..c9e35b6 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,9 @@ "emitter/index.js": "index.js" } }, - "main": "index.js", - "module": "index.mjs", - "types": "index.d.ts", + "main": "./lib/cjs/index.js", + "module": "./lib/esm/index.js", + "types": "./lib/esm/index.d.ts", "repository": { "type": "git", "url": "https://github.com/socketio/emitter.git" @@ -23,9 +23,6 @@ "test": "make test" }, "files": [ - "index.js", - "index.mjs", - "index.d.ts", - "LICENSE" + "lib/" ] }