diff --git a/src/EventEmitter.js b/src/EventEmitter.js deleted file mode 100644 index 3661894..0000000 --- a/src/EventEmitter.js +++ /dev/null @@ -1,64 +0,0 @@ -/** - * @license MIT - */ - -function EventEmitter() { - this._events = this._events || {}; -} - -EventEmitter.prototype.addListener = function(type, listener) { - this._events[type] = this._events[type] || []; - this._events[type].push(listener); -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.removeListener = function(type, listener) { - if (!this._events[type]) return; - - var obj = this._events[type] - , i = obj.length; - - while (i--) { - if (obj[i] === listener || obj[i].listener === listener) { - obj.splice(i, 1); - return; - } - } -}; - -EventEmitter.prototype.off = EventEmitter.prototype.removeListener; - -EventEmitter.prototype.removeAllListeners = function(type) { - if (this._events[type]) delete this._events[type]; -}; - -EventEmitter.prototype.once = function(type, listener) { - var self = this; - function on() { - var args = Array.prototype.slice.call(arguments); - this.removeListener(type, on); - return listener.apply(this, args); - } - on.listener = listener; - return this.on(type, on); -}; - -EventEmitter.prototype.emit = function(type) { - if (!this._events[type]) return; - - var args = Array.prototype.slice.call(arguments, 1) - , obj = this._events[type] - , l = obj.length - , i = 0; - - for (; i < l; i++) { - obj[i].apply(this, args); - } -}; - -EventEmitter.prototype.listeners = function(type) { - return this._events[type] = this._events[type] || []; -}; - -export { EventEmitter }; diff --git a/src/EventEmitter.test.ts b/src/EventEmitter.test.ts new file mode 100644 index 0000000..7ae381c --- /dev/null +++ b/src/EventEmitter.test.ts @@ -0,0 +1,84 @@ +import { assert } from 'chai'; +import { EventEmitter } from './EventEmitter'; + +describe('EventEmitter', () => { + let eventEmitter: EventEmitter; + + beforeEach(() => { + eventEmitter = new EventEmitter(); + }); + + describe('once', () => { + it('should trigger the listener only once', () => { + let count = 0; + const listener = () => count++; + eventEmitter.once('test', listener); + eventEmitter.emit('test'); + assert.equal(count, 1); + eventEmitter.emit('test'); + assert.equal(count, 1); + }); + }); + + describe('emit', () => { + it('should emit events to listeners', () => { + let count1 = 0; + let count2 = 0; + const listener1 = () => count1++; + const listener2 = () => count2++; + eventEmitter.on('test', listener1); + eventEmitter.on('test', listener2); + eventEmitter.emit('test'); + assert.equal(count1, 1); + assert.equal(count2, 1); + eventEmitter.emit('test'); + assert.equal(count1, 2); + assert.equal(count2, 2); + }); + + it('should manage multiple listener types', () => { + let count1 = 0; + let count2 = 0; + const listener1 = () => count1++; + const listener2 = () => count2++; + eventEmitter.on('test', listener1); + eventEmitter.on('foo', listener2); + eventEmitter.emit('test'); + assert.equal(count1, 1); + assert.equal(count2, 0); + eventEmitter.emit('foo'); + assert.equal(count1, 1); + assert.equal(count2, 1); + }); + }); + + describe('listeners', () => { + it('should return listeners for the type requested', () => { + assert.equal(eventEmitter.listeners('test').length, 0); + const listener = () => {}; + eventEmitter.on('test', listener); + assert.deepEqual(eventEmitter.listeners('test'), [listener]); + }); + }); + + describe('off', () => { + it('should remove the specific listener', () => { + const listener1 = () => {}; + const listener2 = () => {}; + eventEmitter.on('foo', listener1); + eventEmitter.on('foo', listener2); + assert.equal(eventEmitter.listeners('foo').length, 2); + eventEmitter.off('foo', listener1); + assert.deepEqual(eventEmitter.listeners('foo'), [listener2]); + }); + }); + + describe('removeAllListeners', () => { + it('should clear all listeners', () => { + eventEmitter.on('foo', () => {}); + assert.equal(eventEmitter.listeners('foo').length, 1); + eventEmitter.removeAllListeners('foo'); + assert.equal(eventEmitter.listeners('foo').length, 0); + }); + }); +}); diff --git a/src/EventEmitter.ts b/src/EventEmitter.ts new file mode 100644 index 0000000..d05e386 --- /dev/null +++ b/src/EventEmitter.ts @@ -0,0 +1,70 @@ +/** + * @license MIT + */ + +interface ListenerType { + (): void; + listener?: () => void; +}; + +export class EventEmitter { + private _events: {[type: string]: ListenerType[]}; + + constructor() { + this._events = {}; + } + + public on(type, listener): void { + this._events[type] = this._events[type] || []; + this._events[type].push(listener); + } + + public off(type, listener): void { + if (!this._events[type]) { + return; + } + + let obj = this._events[type]; + let i = obj.length; + + while (i--) { + if (obj[i] === listener || obj[i].listener === listener) { + obj.splice(i, 1); + return; + } + } + } + + public removeAllListeners(type): void { + if (this._events[type]) { + delete this._events[type]; + } + } + + public once(type, listener): any { + function on() { + let args = Array.prototype.slice.call(arguments); + this.off(type, on); + return listener.apply(this, args); + } + (on).listener = listener; + return this.on(type, on); + } + + public emit(type): void { + if (!this._events[type]) { + return; + } + + let args = Array.prototype.slice.call(arguments, 1); + let obj = this._events[type]; + + for (let i = 0; i < obj.length; i++) { + obj[i].apply(this, args); + } + } + + public listeners(type): ListenerType[] { + return this._events[type] || []; + } +}