From acf0d0f007bcfe03b62fcf14a68e6d275228640d Mon Sep 17 00:00:00 2001 From: Leon Yu Date: Sat, 5 Dec 2015 15:45:33 -0500 Subject: [PATCH] eventemitter3 to 1.1.1 --- eventemitter3/eventemitter3-tests.ts | 548 ++++++++++++++++++++++++++- eventemitter3/eventemitter3.d.ts | 81 ++-- 2 files changed, 582 insertions(+), 47 deletions(-) diff --git a/eventemitter3/eventemitter3-tests.ts b/eventemitter3/eventemitter3-tests.ts index da13434135..4fa378bc20 100644 --- a/eventemitter3/eventemitter3-tests.ts +++ b/eventemitter3/eventemitter3-tests.ts @@ -1,16 +1,41 @@ -/// +/// +/// +/// 'use strict'; import EventEmitter = require('eventemitter3'); +import util = require('util'); +import * as EventEmitter3ImportedAsES6Module from 'eventemitter3'; + +declare namespace Assume { + interface Class { + new(...args: any[]): T; + } + + interface Assume { + equals(compare: T): Assume; + equal(compare: T): Assume; + eqls(compare: T): Assume; + is: Assume; + deep: Assume; + to: Assume; + either(arr: T[]): Assume; + instanceOf(clazz: Class): Assume; + a(typeofString: string): Assume; + } + + export function assume(input: T): Assume; +} + +let assume = Assume.assume; class EventEmitterTest { - v: EventEmitter; + v: EventEmitter3.EventEmitter; constructor() { this.v = new EventEmitter(); - this.v = new EventEmitter.EventEmitter(); - this.v = new EventEmitter.EventEmitter2(); - this.v = new EventEmitter.EventEmitter3(); + this.v = new EventEmitter3ImportedAsES6Module(); + var n: NodeJS.EventEmitter = this.v; } listeners() { @@ -27,39 +52,528 @@ class EventEmitterTest { on() { var fn = () => console.log(1); - var v1: EventEmitter = this.v.on('click', fn); - var v2: EventEmitter = this.v.on('click', fn, this); + var v1: EventEmitter3.EventEmitter = this.v.on('click', fn); + var v2: EventEmitter3.EventEmitter = this.v.on('click', fn, this); } once() { var fn = () => console.log(1); - var v1: EventEmitter = this.v.once('click', fn); - var v2: EventEmitter = this.v.once('click', fn, this); + var v1: EventEmitter3.EventEmitter = this.v.once('click', fn); + var v2: EventEmitter3.EventEmitter = this.v.once('click', fn, this); } removeListener() { var fn = () => console.log(1); - var v1: EventEmitter = this.v.removeListener('click', fn); - var v2: EventEmitter = this.v.removeListener('click', fn, true); + var v1: EventEmitter3.EventEmitter = this.v.removeListener('click', fn); + var v2: EventEmitter3.EventEmitter = this.v.removeListener('click', fn, true); } removeAllListeners() { - var v1: EventEmitter = this.v.removeAllListeners('click'); + var v1: EventEmitter3.EventEmitter = this.v.removeAllListeners('click'); } off() { var fn = () => console.log(1); - var v1: EventEmitter = this.v.off('click', fn); - var v2: EventEmitter = this.v.off('click', fn, true); + var v1: EventEmitter3.EventEmitter = this.v.off('click', fn); + var v2: EventEmitter3.EventEmitter = this.v.off('click', fn, true); } addListener() { var fn = () => console.log(1); - var v1: EventEmitter = this.v.addListener('click', fn); - var v2: EventEmitter = this.v.addListener('click', fn, this); + var v1: EventEmitter3.EventEmitter = this.v.addListener('click', fn); + var v2: EventEmitter3.EventEmitter = this.v.addListener('click', fn, this); } setMaxListeners() { - var v1: EventEmitter = this.v.setMaxListeners(); + var v1: EventEmitter3.EventEmitter = this.v.setMaxListeners(); } } + + +describe('EventEmitter', function tests() { + 'use strict'; + + it('exposes a `prefixed` property', function () { + assume(EventEmitter.prefixed).is.either([false, '~']); + }); + + it('inherits when used with require(util).inherits', function () { + class Beast extends EventEmitter { + /* rawr, i'm a beast */ + } + + util.inherits(Beast, EventEmitter); + + var moop = new Beast() + , meap = new Beast(); + + assume(moop).is.instanceOf(Beast); + assume(moop).is.instanceOf(EventEmitter); + + moop.listeners(); + meap.listeners(); + + moop.on('data', function () { + throw new Error('I should not emit'); + }); + + meap.emit('data', 'rawr'); + meap.removeListener('foo'); + meap.removeAllListeners(); + }); + + describe('EventEmitter#emit', function () { + it('should return false when there are not events to emit', function () { + var e = new EventEmitter(); + + assume(e.emit('foo')).equals(false); + assume(e.emit('bar')).equals(false); + }); + + it('emits with context', function (done) { + var context = { bar: 'baz' } + , e = new EventEmitter(); + + e.on('foo', function (bar: string) { + assume(bar).equals('bar'); + assume(this).equals(context); + + done(); + }, context).emit('foo', 'bar'); + }); + + it('emits with context, multiple arguments (force apply)', function (done) { + var context = { bar: 'baz' } + , e = new EventEmitter(); + + e.on('foo', function (bar: string) { + assume(bar).equals('bar'); + assume(this).equals(context); + + done(); + }, context).emit('foo', 'bar', 1,2,3,4,5,6,7,8,9,0); + }); + + it('can emit the function with multiple arguments', function () { + var e = new EventEmitter(); + + for(var i = 0; i < 100; i++) { + (function (j: number) { + for (var i = 0, args: number[] = []; i < j; i++) { + args.push(j); + } + + e.once('args', function () { + assume(arguments.length).equals(args.length); + }); + + e.emit.apply(e, (['args'] as any[]).concat(args)); + })(i); + } + }); + + it('can emit the function with multiple arguments, multiple listeners', function () { + var e = new EventEmitter(); + + for(var i = 0; i < 100; i++) { + (function (j: number) { + for (var i = 0, args: number[] = []; i < j; i++) { + args.push(j); + } + + e.once('args', function () { + assume(arguments.length).equals(args.length); + }); + + e.once('args', function () { + assume(arguments.length).equals(args.length); + }); + + e.once('args', function () { + assume(arguments.length).equals(args.length); + }); + + e.once('args', function () { + assume(arguments.length).equals(args.length); + }); + + e.emit.apply(e, (['args'] as any[]).concat(args)); + })(i); + } + }); + + it('emits with context, multiple listeners (force loop)', function () { + var e = new EventEmitter(); + + e.on('foo', function (bar: string) { + assume(this).eqls({ foo: 'bar' }); + assume(bar).equals('bar'); + }, { foo: 'bar' }); + + e.on('foo', function (bar: string) { + assume(this).eqls({ bar: 'baz' }); + assume(bar).equals('bar'); + }, { bar: 'baz' }); + + e.emit('foo', 'bar'); + }); + + it('emits with different contexts', function () { + var e = new EventEmitter() + , pattern = ''; + + function writer() { + pattern += this; + } + + e.on('write', writer, 'foo'); + e.on('write', writer, 'baz'); + e.once('write', writer, 'bar'); + e.once('write', writer, 'banana'); + + e.emit('write'); + assume(pattern).equals('foobazbarbanana'); + }); + + it('should return true when there are events to emit', function (done) { + var e = new EventEmitter(); + + e.on('foo', function () { + process.nextTick(done); + }); + + assume(e.emit('foo')).equals(true); + assume(e.emit('foob')).equals(false); + }); + + it('receives the emitted events', function (done) { + var e = new EventEmitter(); + + e.on('data', function (a: string, b: EventEmitter3.EventEmitter, c: Date, d: void, undef: void) { + assume(a).equals('foo'); + assume(b).equals(e); + assume(c).is.instanceOf(Date); + assume(undef).equals(undefined); + assume(arguments.length).equals(3); + + done(); + }); + + e.emit('data', 'foo', e, new Date()); + }); + + it('emits to all event listeners', function () { + var e = new EventEmitter() + , pattern: string[] = []; + + e.on('foo', function () { + pattern.push('foo1'); + }); + + e.on('foo', function () { + pattern.push('foo2'); + }); + + e.emit('foo'); + + assume(pattern.join(';')).equals('foo1;foo2'); + }); + + (function each(keys: string[]) { + var key = keys.shift(); + + if (!key) return; + + it('can store event which is a known property: '+ key, function (next) { + var e = new EventEmitter(); + + e.on(key, function (key: string) { + assume(key).equals(key); + next(); + }).emit(key, key); + }); + + each(keys); + })([ + 'hasOwnProperty', + 'constructor', + '__proto__', + 'toString', + 'toValue', + 'unwatch', + 'watch' + ]); + }); + + describe('EventEmitter#listeners', function () { + it('returns an empty array if no listeners are specified', function () { + var e = new EventEmitter(); + + assume(e.listeners('foo')).is.a('array'); + assume(e.listeners('foo').length).equals(0); + }); + + it('returns an array of function', function () { + var e = new EventEmitter(); + + function foo() {} + + e.on('foo', foo); + assume(e.listeners('foo')).is.a('array'); + assume(e.listeners('foo').length).equals(1); + assume(e.listeners('foo')).deep.equals([foo]); + }); + + it('is not vulnerable to modifications', function () { + var e = new EventEmitter(); + + function foo() {} + + e.on('foo', foo); + + assume(e.listeners('foo')).deep.equals([foo]); + + e.listeners('foo').length = 0; + assume(e.listeners('foo')).deep.equals([foo]); + }); + + it('can return a boolean as indication if listeners exist', function () { + var e = new EventEmitter(); + + function foo() {} + + e.once('once', foo); + e.once('multiple', foo); + e.once('multiple', foo); + e.on('on', foo); + e.on('multi', foo); + e.on('multi', foo); + + assume(e.listeners('foo', true)).equals(false); + assume(e.listeners('multiple', true)).equals(true); + assume(e.listeners('on', true)).equals(true); + assume(e.listeners('multi', true)).equals(true); + + e.removeAllListeners(); + + assume(e.listeners('multiple', true)).equals(false); + assume(e.listeners('on', true)).equals(false); + assume(e.listeners('multi', true)).equals(false); + }); + }); + + describe('EventEmitter#once', function () { + it('only emits it once', function () { + var e = new EventEmitter() + , calls = 0; + + e.once('foo', function () { + calls++; + }); + + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + + assume(e.listeners('foo').length).equals(0); + assume(calls).equals(1); + }); + + it('only emits once if emits are nested inside the listener', function () { + var e = new EventEmitter() + , calls = 0; + + e.once('foo', function () { + calls++; + e.emit('foo'); + }); + + e.emit('foo'); + assume(e.listeners('foo').length).equals(0); + assume(calls).equals(1); + }); + + it('only emits once for multiple events', function () { + var e = new EventEmitter() + , multi = 0 + , foo = 0 + , bar = 0; + + e.once('foo', function () { + foo++; + }); + + e.once('foo', function () { + bar++; + }); + + e.on('foo', function () { + multi++; + }); + + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + e.emit('foo'); + + assume(e.listeners('foo').length).equals(1); + assume(multi).equals(5); + assume(foo).equals(1); + assume(bar).equals(1); + }); + + it('only emits once with context', function (done) { + var context = { foo: 'bar' } + , e = new EventEmitter(); + + e.once('foo', function (bar: string) { + assume(this).equals(context); + assume(bar).equals('bar'); + + done(); + }, context).emit('foo', 'bar'); + }); + }); + + describe('EventEmitter#removeListener', function () { + it('should only remove the event with the specified function', function () { + var e = new EventEmitter(); + + function bar() {} + e.on('foo', function () {}); + e.on('bar', function () {}); + e.on('bar', bar); + + assume(e.removeListener('foo', bar)).equals(e); + assume(e.listeners('foo').length).equals(1); + assume(e.listeners('bar').length).equals(2); + + assume(e.removeListener('foo')).equals(e); + assume(e.listeners('foo').length).equals(0); + assume(e.listeners('bar').length).equals(2); + + assume(e.removeListener('bar', bar)).equals(e); + assume(e.listeners('bar').length).equals(1); + assume(e.removeListener('bar')).equals(e); + assume(e.listeners('bar').length).equals(0); + }); + + it('should only remove once events when using the once flag', function () { + var e = new EventEmitter(); + + function foo() {} + e.on('foo', foo); + + assume(e.removeListener('foo', function () {}, undefined, true)).equals(e); + assume(e.listeners('foo').length).equals(1); + assume(e.removeListener('foo', foo, undefined, true)).equals(e); + assume(e.listeners('foo').length).equals(1); + assume(e.removeListener('foo', foo)).equals(e); + assume(e.listeners('foo').length).equals(0); + + e.on('foo', foo); + e.once('foo', foo); + + assume(e.removeListener('foo', function () {}, undefined, true)).equals(e); + assume(e.listeners('foo').length).equals(2); + assume(e.removeListener('foo', foo, undefined, true)).equals(e); + assume(e.listeners('foo').length).equals(1); + + e.once('foo', foo); + + assume(e.removeListener('foo', foo)).equals(e); + assume(e.listeners('foo').length).equals(0); + }); + + it('should only remove listeners matching the correct context', function () { + var e = new EventEmitter() + , context = { foo: 'bar' }; + + function foo() {} + function bar() {} + e.on('foo', foo, context); + + assume(e.listeners('foo').length).equals(1); + assume(e.removeListener('foo', function () {}, context)).equals(e); + assume(e.listeners('foo').length).equals(1); + assume(e.removeListener('foo', foo, { baz: 'quux' })).equals(e); + assume(e.listeners('foo').length).equals(1); + assume(e.removeListener('foo', foo, context)).equals(e); + assume(e.listeners('foo').length).equals(0); + + e.on('foo', foo, context); + e.on('foo', bar); + + assume(e.listeners('foo').length).equals(2); + assume(e.removeListener('foo', foo, { baz: 'quux' })).equals(e); + assume(e.listeners('foo').length).equals(2); + assume(e.removeListener('foo', foo, context)).equals(e); + assume(e.listeners('foo').length).equals(1); + assume(e.listeners('foo')[0]).equals(bar); + + e.on('foo', foo, context); + + assume(e.listeners('foo').length).equals(2); + assume(e.removeAllListeners('foo')).equals(e); + assume(e.listeners('foo').length).equals(0); + }); + }); + + describe('EventEmitter#removeAllListeners', function () { + it('removes all events for the specified events', function () { + var e = new EventEmitter(); + + e.on('foo', function () { throw new Error('oops'); }); + e.on('foo', function () { throw new Error('oops'); }); + e.on('bar', function () { throw new Error('oops'); }); + e.on('aaa', function () { throw new Error('oops'); }); + + assume(e.removeAllListeners('foo')).equals(e); + assume(e.listeners('foo').length).equals(0); + assume(e.listeners('bar').length).equals(1); + assume(e.listeners('aaa').length).equals(1); + + assume(e.removeAllListeners('bar')).equals(e); + assume(e.removeAllListeners('aaa')).equals(e); + + assume(e.emit('foo')).equals(false); + assume(e.emit('bar')).equals(false); + assume(e.emit('aaa')).equals(false); + }); + + it('just nukes the fuck out of everything', function () { + var e = new EventEmitter(); + + e.on('foo', function () { throw new Error('oops'); }); + e.on('foo', function () { throw new Error('oops'); }); + e.on('bar', function () { throw new Error('oops'); }); + e.on('aaa', function () { throw new Error('oops'); }); + + assume(e.removeAllListeners()).equals(e); + assume(e.listeners('foo').length).equals(0); + assume(e.listeners('bar').length).equals(0); + assume(e.listeners('aaa').length).equals(0); + + assume(e.emit('foo')).equals(false); + assume(e.emit('bar')).equals(false); + assume(e.emit('aaa')).equals(false); + }); + }); + + describe('#setMaxListeners', function () { + it('is a function', function () { + var e = new EventEmitter(); + + assume(e.setMaxListeners).is.a('function'); + }); + + it('returns self when called', function () { + var e = new EventEmitter(); + + assume(e.setMaxListeners()).to.equal(e); + }); + }); +}); diff --git a/eventemitter3/eventemitter3.d.ts b/eventemitter3/eventemitter3.d.ts index f5cf9bcb2d..0d692b8247 100644 --- a/eventemitter3/eventemitter3.d.ts +++ b/eventemitter3/eventemitter3.d.ts @@ -1,11 +1,14 @@ -// Type definitions for EventEmitter3 0.1.6 +// Type definitions for EventEmitter3 1.1.1 // Project: https://github.com/primus/eventemitter3 -// Definitions by: Yuichi Murata -// Definitions: https://github.com/borisyankov/DefinitelyTyped +// Definitions by: Yuichi Murata , Leon Yu +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -declare module EventEmitter3 { - // __Base is hack for https://github.com/Microsoft/TypeScript/issues/3602 - class __Base { +declare namespace EventEmitter3 { + interface EventEmitter3Static { + new (): EventEmitter; + prefixed: string | boolean; + } + class EventEmitter { /** * Minimal EventEmitter interface that is molded against the Node.js * EventEmitter interface. @@ -22,7 +25,17 @@ declare module EventEmitter3 { * @returns {Array} * @api public */ - listeners(event: string): Function[]; + listeners(event?: string): Function[]; + + /** + * Return a list of assigned event listeners. + * + * @param {String} event The events that should be listed. + * @param {Boolean} exists We only need to know if there are listeners. + * @returns {Boolean} + * @api public + */ + listeners(event: string, param: boolean): boolean; /** * Emit an event to all registered event listeners. @@ -37,8 +50,8 @@ declare module EventEmitter3 { * Register a new EventListener for the given event. * * @param {String} event Name of the event. - * @param {Functon} fn Callback function. - * @param {Mixed} context The context of the function. + * @param {Function} fn Callback function. + * @param {Mixed} [context=this] The context of the function. * @api public */ on(event: string, fn: Function, context?: any): EventEmitter; @@ -48,7 +61,7 @@ declare module EventEmitter3 { * * @param {String} event Name of the event. * @param {Function} fn Callback function. - * @param {Mixed} context The context of the function. + * @param {Mixed} [context=this] The context of the function. * @api public */ once(event: string, fn: Function, context?: any): EventEmitter; @@ -58,10 +71,11 @@ declare module EventEmitter3 { * * @param {String} event The event we want to remove. * @param {Function} fn The listener that we need to find. + * @param {Mixed} context Only remove listeners matching this context. * @param {Boolean} once Only remove once listeners. * @api public */ - removeListener(event: string, fn: Function, once?: boolean): EventEmitter; + removeListener(event: string, fn?: Function, context?: any, once?: boolean): EventEmitter; /** * Remove all listeners or only the listeners for the specified event. @@ -69,34 +83,41 @@ declare module EventEmitter3 { * @param {String} event The event want to remove all listeners for. * @api public */ - removeAllListeners(event: string): EventEmitter; + removeAllListeners(event?: string): EventEmitter; - // - // Alias methods names because people roll like that. - // - off(event: string, fn: Function, once?: boolean): EventEmitter; + /** + * Remove event listeners. + * + * @param {String} event The event we want to remove. + * @param {Function} fn The listener that we need to find. + * @param {Mixed} context Only remove listeners matching this context. + * @param {Boolean} once Only remove once listeners. + * @api public + */ + off(event: string, fn?: Function, context?: any, once?: boolean): EventEmitter; + + /** + * Register a new EventListener for the given event. + * + * @param {String} event Name of the event. + * @param {Function} fn Callback function. + * @param {Mixed} [context=this] The context of the function. + * @api public + */ addListener(event: string, fn: Function, context?: any): EventEmitter; - // - // This function doesn't apply anymore. - // + /** + * This function doesn't apply anymore. + * @deprecated + */ setMaxListeners(): EventEmitter; } - export class EventEmitter extends __Base { } - export module EventEmitter { - // - // Expose the module. - // - export class EventEmitter extends __Base {} - export class EventEmitter2 extends __Base {} - export class EventEmitter3 extends __Base {} - } } declare module 'eventemitter3' { // // Expose the module. // - class EventEmitter extends EventEmitter3.EventEmitter {} - export = EventEmitter; + var EventEmitter3: EventEmitter3.EventEmitter3Static; + export = EventEmitter3; }