diff --git a/types/async-eventemitter/async-eventemitter-tests.ts b/types/async-eventemitter/async-eventemitter-tests.ts new file mode 100644 index 0000000000..870d3ccfa0 --- /dev/null +++ b/types/async-eventemitter/async-eventemitter-tests.ts @@ -0,0 +1,38 @@ +import * as AsyncEventEmitter from 'async-eventemitter'; + +const ee = new AsyncEventEmitter<{ + sync: (a: string) => void; + // "sync-multiple": (a: string, b: number) => void, + async: (data?: { a: string; b: boolean }) => Promise; + // "illegal-async": (data: string, data2: number) => Promise, + 'premature-resolve': ( + data: number, + resolve?: (result: any) => void, + ) => Promise; + 'premature-resolve-empty': ( + data: number, + resolve?: () => void, + ) => Promise; + 'is-empty': () => any; +}>(); + +ee.emit('sync', 'yes'); +ee.emit('async', { a: 'a', b: true }); +ee.emit('async'); +ee.emit('is-empty'); +ee.emit('premature-resolve', 1); + +(async () => { + // await new Promise((resolve) => ee.emit("async", undefined, resolve)); // fail + // await new Promise((resolve) => ee.emit("premature-resolve", undefined, resolve)); // Should fail + await new Promise(resolve => ee.emit('premature-resolve', 1, resolve)); +})(); + +ee.on('is-empty', () => {}); +ee.on('async', async data => { + `Reach the end of async function and ${data}`; +}); +ee.on('premature-resolve', async (data, resolve) => { + if (resolve) resolve(true); + 'does not reach here'; +}); diff --git a/types/async-eventemitter/index.d.ts b/types/async-eventemitter/index.d.ts new file mode 100644 index 0000000000..3d41ec268f --- /dev/null +++ b/types/async-eventemitter/index.d.ts @@ -0,0 +1,107 @@ +// Type definitions for async-eventemitter 0.2 +// Project: https://www.npmjs.com/package/async-eventemitter (Does not have to be to GitHub, but prefer linking to a source code repository rather than to a project website.) +// Definitions by: patarapolw +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 3.5 + +import { EventEmitter } from "events"; + +/** + * The API and behavior of AsyncEventEmitter is as far as possible and meaningful identical to + * that of the native EventEmitter. However there are some important differences which should be noted. + * - Data sent to event listeners (eg emit(data)) must always be zero or one argument, and can not be a function. + * - Event listeners will always recieve the data object, which may or may not be undefined. + * - The second argument can only be a callback, and will only be supplied if the event listener has an arity of two or more (eg function(e, next){}). + * - Event listeners with an arity of one or zero (eg without a callback argument specified) will be treated as synchronous. + * - Even if all event listeners are synchronous, they will still be executed asynchronously (through setImmediate) and thus code suceeding .emit() will be executed before any event listeners. + * - Interupt the callback chain in async listeners by calling the callback with the error as the first parameter; in sync listeners by throwing an Error. + * @see https://www.npmjs.com/package/async-eventemitter#important-differences-between-asynceventemitter-the-native-eventemitter + */ +export = AsyncEventEmitter; + +/** + * An EventEmitter that supports serial execution of asynchronous event listeners. + * It also supports event listeners without callbacks (synchronous), as well as + * interrupting the call-chain (similar to the DOM's e.stopPropagation()). + */ +declare class AsyncEventEmitter< + T extends AsyncEventEmitter.EventMap +> extends EventEmitter { + /** + * Executes all listeners for the event in order with the supplied data argument. + * The optional callback is called when all of the listeners are done. + * @param event EventMap key (event name) + * @param args EventMap parameters + * @see https://www.npmjs.com/package/async-eventemitter#important-differences-between-asynceventemitter-the-native-eventemitter + */ + emit( + event: E & string, + ...args: Parameters + ): boolean; + /** + * Adds a listener to the beginning of the listeners array for the specified event. + * @param event EventMap key (event name) + * @param listener EventMap value (event function) + * @see https://www.npmjs.com/package/async-eventemitter#important-differences-between-asynceventemitter-the-native-eventemitter + */ + first(event: E & string, listener: T[E]): this; + /** + * Adds a listener at the specified index in the listeners array for the specified event. + * @param event EventMap key (event name) + * @param index Index to insert at + * @param listener EventMap value (event function) + * @see https://www.npmjs.com/package/async-eventemitter#important-differences-between-asynceventemitter-the-native-eventemitter + */ + at(event: E & string, index: number, listener: T[E]): this; + /** + * Adds a listener before the target listener in the listeners array for the specified event. + * @param event EventMap key (event name) + * @param target Listener to insert before + * @param listener EventMap value (event function) + * @see https://www.npmjs.com/package/async-eventemitter#important-differences-between-asynceventemitter-the-native-eventemitter + */ + before( + event: E & string, + target: T[E], + listener: T[E], + ): this; + /** + * Adds a listener after the target listener in the listeners array for the specified event. + * @param event EventMap key (event name) + * @param target Listener to insert before + * @param listener EventMap value (event function) + * @see https://www.npmjs.com/package/async-eventemitter#important-differences-between-asynceventemitter-the-native-eventemitter + */ + after( + event: E & string, + target: T[E], + listener: T[E], + ): this; + + // https://github.com/andywer/typed-emitter/blob/master/index.d.ts + addListener(event: E & string, listener: T[E]): this; + on(event: E & string, listener: T[E]): this; + once(event: E & string, listener: T[E]): this; + prependListener(event: E & string, listener: T[E]): this; + prependOnceListener( + event: E & string, + listener: T[E], + ): this; + + removeAllListeners(event?: keyof T & string): this; + removeListener(event: E & string, listener: T[E]): this; + + eventNames(): Array; + listeners(event: E & string): Array; + listenerCount(event: keyof T & string): number; + + getMaxListeners(): number; + setMaxListeners(maxListeners: number): this; +} + +declare namespace AsyncEventEmitter { + type AsyncListener = ((data: T, callback: (result?: R) => void) => Promise) | ((data: T, callback: (result?: R) => void) => void); + interface EventMap { + [event: string]: AsyncListener; + } +} diff --git a/types/async-eventemitter/tsconfig.json b/types/async-eventemitter/tsconfig.json new file mode 100644 index 0000000000..e0c4d2391d --- /dev/null +++ b/types/async-eventemitter/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "async-eventemitter-tests.ts" + ] +} diff --git a/types/async-eventemitter/tslint.json b/types/async-eventemitter/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/async-eventemitter/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" }