Skip to content

Commit

Permalink
Use a different approach to prevent consumers from emitting meta even…
Browse files Browse the repository at this point in the history
…ts (#98)
  • Loading branch information
lukehorvat committed Aug 11, 2022
1 parent fb190e1 commit c07c783
Showing 1 changed file with 33 additions and 20 deletions.
53 changes: 33 additions & 20 deletions index.js
Expand Up @@ -10,19 +10,13 @@ const resolvedPromise = Promise.resolve();
const listenerAdded = Symbol('listenerAdded');
const listenerRemoved = Symbol('listenerRemoved');

// Define a symbol that allows internal code to emit meta events, but prevents userland from doing so.
const metaEventsAllowed = Symbol('metaEventsAllowed');

let canEmitMetaEvents = false;
let isGlobalDebugEnabled = false;

function assertEventName(eventName, allowMetaEvents) {
function assertEventName(eventName) {
if (typeof eventName !== 'string' && typeof eventName !== 'symbol' && typeof eventName !== 'number') {
throw new TypeError('`eventName` must be a string, symbol, or number');
}

if (isMetaEvent(eventName) && allowMetaEvents !== metaEventsAllowed) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');
}
}

function assertListener(listener) {
Expand Down Expand Up @@ -157,6 +151,17 @@ function defaultMethodNamesOrAssert(methodNames) {

const isMetaEvent = eventName => eventName === listenerAdded || eventName === listenerRemoved;

function emitMetaEvent(emitter, eventName, eventData) {
if (isMetaEvent(eventName)) {
try {
canEmitMetaEvents = true;
emitter.emit(eventName, eventData);
} finally {
canEmitMetaEvents = false;
}
}
}

class Emittery {
static mixin(emitteryPropertyName, methodNames) {
methodNames = defaultMethodNamesOrAssert(methodNames);
Expand Down Expand Up @@ -253,13 +258,13 @@ class Emittery {

eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
for (const eventName of eventNames) {
assertEventName(eventName, metaEventsAllowed);
assertEventName(eventName);
getListeners(this, eventName).add(listener);

this.logIfDebugEnabled('subscribe', eventName, undefined);

if (!isMetaEvent(eventName)) {
this.emit(listenerAdded, {eventName, listener}, metaEventsAllowed);
emitMetaEvent(this, listenerAdded, {eventName, listener});
}
}

Expand All @@ -271,13 +276,13 @@ class Emittery {

eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
for (const eventName of eventNames) {
assertEventName(eventName, metaEventsAllowed);
assertEventName(eventName);
getListeners(this, eventName).delete(listener);

this.logIfDebugEnabled('unsubscribe', eventName, undefined);

if (!isMetaEvent(eventName)) {
this.emit(listenerRemoved, {eventName, listener}, metaEventsAllowed);
emitMetaEvent(this, listenerRemoved, {eventName, listener});
}
}
}
Expand All @@ -299,14 +304,18 @@ class Emittery {
events(eventNames) {
eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
for (const eventName of eventNames) {
assertEventName(eventName, metaEventsAllowed);
assertEventName(eventName);
}

return iterator(this, eventNames);
}

async emit(eventName, eventData, allowMetaEvents) {
assertEventName(eventName, allowMetaEvents);
async emit(eventName, eventData) {
assertEventName(eventName);

if (isMetaEvent(eventName) && !canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');
}

this.logIfDebugEnabled('emit', eventName, eventData);

Expand All @@ -332,8 +341,12 @@ class Emittery {
]);
}

async emitSerial(eventName, eventData, allowMetaEvents) {
assertEventName(eventName, allowMetaEvents);
async emitSerial(eventName, eventData) {
assertEventName(eventName);

if (isMetaEvent(eventName) && !canEmitMetaEvents) {
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');
}

this.logIfDebugEnabled('emitSerial', eventName, eventData);

Expand Down Expand Up @@ -364,7 +377,7 @@ class Emittery {
this.logIfDebugEnabled('subscribeAny', undefined, undefined);

anyMap.get(this).add(listener);
this.emit(listenerAdded, {listener}, metaEventsAllowed);
emitMetaEvent(this, listenerAdded, {listener});
return this.offAny.bind(this, listener);
}

Expand All @@ -377,7 +390,7 @@ class Emittery {

this.logIfDebugEnabled('unsubscribeAny', undefined, undefined);

this.emit(listenerRemoved, {listener}, metaEventsAllowed);
emitMetaEvent(this, listenerRemoved, {listener});
anyMap.get(this).delete(listener);
}

Expand Down Expand Up @@ -427,7 +440,7 @@ class Emittery {
}

if (typeof eventName !== 'undefined') {
assertEventName(eventName, metaEventsAllowed);
assertEventName(eventName);
}

count += anyMap.get(this).size;
Expand Down

0 comments on commit c07c783

Please sign in to comment.