-
-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
It including declarations in the npm package using default declaration locations. Note that by default it doesn’t allow to map an event data type to each event; in TS, Emittery can be aliased to interface to support it. As of TS 2.6, that optional interface doesn’t support symbol. This PR includes some rather slow tests. To skip those tests, ava should exclude test ending with ‘[slow]’, i.e. `ava —match ‘!*[slow]’` Fix #13
- Loading branch information
Showing
20 changed files
with
576 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ yarn.lock | |
.nyc_output | ||
coverage | ||
/legacy.js | ||
/legacy.d.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/clocktyped.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
#!/usr/bin/env node | ||
|
||
'use strict'; | ||
|
||
const Emittery = require('../'); | ||
|
||
class Clock extends Emittery { | ||
|
||
constructor(tick = 1000) { | ||
super(); | ||
|
||
this._startedAt = 0; | ||
this._tick = tick > 0 ? tick : 1000; | ||
this._timer = null; | ||
} | ||
|
||
async tick() { | ||
if (this._timer === null) { | ||
await this.emit('error', new Error('not started')); | ||
this.stop(); | ||
return; | ||
} | ||
|
||
const now = Date.now(); | ||
const duration = now - this._startedAt; | ||
|
||
return this.emit('tick', {now, duration}); | ||
} | ||
|
||
start() { | ||
this._startedAt = Date.now(); | ||
this._timer = setInterval(this.tick.bind(this), this._tick); | ||
this.emit('started', null); | ||
} | ||
|
||
stop() { | ||
if (this._timer !== null) { | ||
clearInterval(this._timer); | ||
} | ||
|
||
this._timer = null; | ||
this._startedAt = 0; | ||
this.emit('stopped', null); | ||
} | ||
} | ||
|
||
const timer = new Clock(); | ||
const offTick = timer.on('tick', onTick); | ||
const offError = timer.on('error', onError); | ||
|
||
timer.start(); | ||
|
||
function onTick({duration}) { | ||
console.log(Math.floor(duration / 1000)); | ||
|
||
if (duration > 5999) { | ||
stop(); | ||
} | ||
} | ||
|
||
function onError(err) { | ||
stop(); | ||
console.error(err); | ||
process.exit(1); | ||
} | ||
|
||
function stop() { | ||
offTick(); | ||
offError(); | ||
timer.stop(); | ||
} | ||
|
||
// Prints: | ||
// 1 | ||
// 2 | ||
// 3 | ||
// 4 | ||
// 5 | ||
// 6 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
#!/usr/bin/env ts-node | ||
import _Emittery = require('../'); | ||
|
||
// Alias Emittery class to use mapped event types | ||
const Emittery = _Emittery as _Emittery.IMappedCtor; | ||
|
||
interface ITickData { | ||
now: number; | ||
duration: number; | ||
} | ||
|
||
// Define Clock's events and the data they emit. | ||
type ClockEvents = { | ||
tick: ITickData, | ||
error: Error, | ||
stopped: null, | ||
started: null | ||
}; | ||
|
||
class Clock extends Emittery<ClockEvents> { | ||
|
||
private _tick: number; | ||
private _timer: NodeJS.Timer | null; | ||
private _startedAt = 0; | ||
|
||
constructor(tick = 1000) { | ||
super(); | ||
|
||
this._tick = tick > 0 ? tick : 1000; | ||
this._timer = null; | ||
} | ||
|
||
async tick(): Promise<void> { | ||
if (this._timer == null) { | ||
await this.emit('error', new Error('not started')); | ||
this.stop(); | ||
return; | ||
} | ||
|
||
const now = Date.now(); | ||
const duration = now - this._startedAt; | ||
|
||
return this.emit('tick', {now, duration}); | ||
} | ||
|
||
start() { | ||
this._startedAt = Date.now(); | ||
this._timer = setInterval(this.tick.bind(this), this._tick); | ||
|
||
this.emit('started', null); | ||
} | ||
|
||
stop() { | ||
if (this._timer != null) { | ||
clearInterval(this._timer); | ||
} | ||
|
||
this._timer = null; | ||
this._startedAt = 0; | ||
|
||
this.emit('stopped', null); | ||
} | ||
|
||
} | ||
|
||
const timer = new Clock(); | ||
const offTick = timer.on('tick', onTick); | ||
const offError = timer.on('error', onError); | ||
|
||
timer.start(); | ||
|
||
function onTick({duration}: ITickData) { | ||
console.log(Math.floor(duration/1000)); | ||
|
||
if (duration > 5999) { | ||
stop(); | ||
} | ||
} | ||
|
||
function onError(err: Error) { | ||
stop(); | ||
console.error(err); | ||
process.exit(1); | ||
} | ||
|
||
function stop() { | ||
offTick(); | ||
offError(); | ||
timer.stop(); | ||
} | ||
|
||
// Prints: | ||
// 1 | ||
// 2 | ||
// 3 | ||
// 4 | ||
// 5 | ||
// 6 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#!/usr/bin/env node | ||
|
||
'use strict'; | ||
|
||
const Emittery = require('../'); | ||
|
||
const myEmitter = new Emittery(); | ||
|
||
// Emit event in next tick | ||
myEmitter.emit('event'); | ||
|
||
// Register listener | ||
myEmitter.on('event', () => console.log('an event occurred!')); | ||
myEmitter.onAny(eventName => console.log('"%s" event occurred!', eventName)); | ||
|
||
// Prints: | ||
// an event occurred! | ||
// "event" event occurred! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#!/usr/bin/env node | ||
|
||
'use strict'; | ||
|
||
const Emittery = require('../'); | ||
|
||
class MyEmitter extends Emittery {} | ||
|
||
const myEmitter = new MyEmitter(); | ||
|
||
// Emit events in next tick | ||
myEmitter.emit('event', 1); | ||
myEmitter.emit('event', 2); | ||
|
||
// Register listener for only the one event | ||
myEmitter.once('event') | ||
.then(count => console.log('an event occurred (#%d).', count)); | ||
|
||
// Prints: | ||
// an event occurred (#1). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#!/usr/bin/env node | ||
|
||
'use strict'; | ||
|
||
const Emittery = require('../'); | ||
|
||
class MyEmitter extends Emittery {} | ||
|
||
const myEmitter = new MyEmitter(); | ||
|
||
// Only accept one event data parameter | ||
myEmitter.emit('event', {a: true, b: true}, 'not', 'supported'); | ||
|
||
// Does not provide a context either. | ||
myEmitter.on('event', function ({a, b}, ...args) { | ||
console.log(a, b, args, this); | ||
}); | ||
|
||
// Prints: | ||
// true true [] undefined |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
// Type definitions for emittery | ||
// Project: emittery | ||
// Definitions by: Sindre Sorhus <sindresorhus.com> | ||
|
||
export = Emittery; | ||
|
||
/** | ||
* Async event emitter. | ||
*/ | ||
declare class Emittery { | ||
|
||
/** | ||
* Subscribe to an event. | ||
* | ||
* Using the same listener multiple times for the same event will result | ||
* in only one method call per emitted event. | ||
* | ||
* @returns Unsubscribe method. | ||
*/ | ||
on(eventName: string, listener: (eventData?: any) => any): () => void; | ||
|
||
/** | ||
* Subscribe to an event only once. It will be unsubscribed after the first | ||
* event. | ||
* | ||
* @returns Promise for the event data when eventName is emitted | ||
*/ | ||
once(eventName: string): Promise<any>; | ||
|
||
/** | ||
* Unsubscribe to an event. | ||
* | ||
* If you don't pass in a listener, it will remove all listeners for that | ||
* event. | ||
* | ||
* @param [listener] | ||
*/ | ||
off(eventName: string, listener?: (eventData?: any) => any): void; | ||
|
||
/** | ||
* Subscribe to be notified about any event. | ||
* | ||
* @returns A method to unsubscribe | ||
*/ | ||
onAny(listener: (eventName: string, eventData?: any) => any): () => void; | ||
|
||
/** | ||
* Unsubscribe an onAny listener. | ||
* | ||
* If you don't pass in a listener, it will remove all onAny listeners. | ||
* | ||
* @param [listener] | ||
*/ | ||
offAny(listener?: (eventName: string, eventData?: any) => any): void; | ||
|
||
/** | ||
* Trigger an event asynchronously, optionally with some data. Listeners | ||
* are called in the order they were added, but execute concurrently. | ||
* | ||
* Returns a promise for when all the event listeners are done. Done meaning | ||
* executed if synchronous or resolved when an async/promise-returning | ||
* function. You usually wouldn't want to wait for this, but you could for | ||
* example catch possible errors. If any of the listeners throw/reject, the | ||
* returned promise will be rejected with the error, but the other listeners | ||
* will not be affected. | ||
* | ||
* @returns A promise for when all the event listeners are done. | ||
*/ | ||
emit(eventName: string, eventData?: any): Promise<void>; | ||
|
||
/** | ||
* Same as `emit`, but it waits for each listener to resolve before | ||
* triggering the next one. This can be useful if your events depend on each | ||
* other. Although ideally they should not. Prefer emit() whenever possible. | ||
* | ||
* If any of the listeners throw/reject, the returned promise will be | ||
* rejected with the error and the remaining listeners will not be called. | ||
* | ||
* @returns A promise for the last event listener settle or first one rejecting. | ||
*/ | ||
emitSerial(eventName: string, eventData?: any): Promise<void>; | ||
|
||
/** | ||
* Clear all event listeners on the instance. | ||
*/ | ||
clear(): void; | ||
|
||
/** | ||
* Count event listeners for the eventName or all events if not specified. | ||
* | ||
* @param eventName | ||
* @returns Listener count. | ||
*/ | ||
listenerCount(eventName?: string): number; | ||
} | ||
|
||
declare namespace Emittery { | ||
|
||
/** | ||
* A map of event names to the data type they emit. | ||
*/ | ||
interface IEvents { | ||
[eventName: string]: any; | ||
} | ||
|
||
/** | ||
* Alternative interface for an Emittery object; must list supported events | ||
* the data type they emit. | ||
*/ | ||
export interface IMapped<Events extends IEvents> { | ||
on<Name extends keyof Events>(eventName: Name, listener: (eventData: Events[Name]) => any): () => void; | ||
once<Name extends keyof Events>(eventName: Name): Promise<Events[Name]>; | ||
off<Name extends keyof Events>(eventName: Name, listener?: (eventData: Events[Name]) => any): void; | ||
|
||
onAny<Name extends keyof Events>(listener: (eventName: Name, eventData: Events[Name]) => any): () => void; | ||
offAny<Name extends keyof Events>(listener?: (eventName: Name, eventData: Events[Name]) => any): void; | ||
|
||
emit<Name extends keyof Events>(eventName: Name, eventData: Events[Name]): Promise<void>; | ||
emitSerial<Name extends keyof Events>(eventName: Name, eventData: Events[Name]): Promise<void>; | ||
} | ||
|
||
/** | ||
* Alternative signature for the Emittery class; must list supported events | ||
* the data type they emit. | ||
* | ||
* @example | ||
* ```ts | ||
* import _Emittery = require('emittery'); | ||
* | ||
* // Alias Emittery class with Events map generic | ||
* const Emittery = _Emittery as _Emittery.IMappedCtor; | ||
* const ee = new Emittery<{open: null, value: string, close: null}>(); | ||
* | ||
* ee.emit('open', null); | ||
* ee.emit('value', 'foo\n'); | ||
* ee.emit('end', null); // TS emit error | ||
* ``` | ||
*/ | ||
interface IMappedCtor { | ||
new <Events extends IEvents>(): IMapped<Events> | ||
} | ||
|
||
} |
Oops, something went wrong.