Skip to content

Commit

Permalink
Inlined DevTools event emitter impl
Browse files Browse the repository at this point in the history
When dispatching an event, if a listener throws- the event emitter should still call other listeners before re-throwing. If we don't do this, certain stores (e.g. ProfilerStore) may miss events and be left in an unknown state.
  • Loading branch information
Brian Vaughn committed Mar 24, 2020
1 parent a600408 commit 7788cec
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 21 deletions.
1 change: 0 additions & 1 deletion packages/react-devtools-shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"@reach/menu-button": "^0.1.17",
"@reach/tooltip": "^0.2.2",
"clipboard-js": "^0.3.6",
"events": "^3.0.0",
"local-storage-fallback": "^4.1.1",
"lodash.throttle": "^4.1.1",
"memoize-one": "^3.1.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @flow
*/

import EventEmitter from 'events';
import EventEmitter from '../events';
import throttle from 'lodash.throttle';
import {
SESSION_STORAGE_LAST_SELECTION_KEY,
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-shared/src/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @flow
*/

import EventEmitter from 'events';
import EventEmitter from './events';

import type {ComponentFilter, Wall} from './types';
import type {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @flow
*/

import EventEmitter from 'events';
import EventEmitter from '../events';
import {prepareProfilingDataFrontendFromBackendAndStore} from './views/Profiler/utils';
import ProfilingCache from './ProfilingCache';
import Store from './store';
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-shared/src/devtools/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @flow
*/

import EventEmitter from 'events';
import EventEmitter from '../events';
import {inspect} from 'util';
import {
TREE_OPERATION_ADD,
Expand Down
65 changes: 65 additions & 0 deletions packages/react-devtools-shared/src/events.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

export default class EventEmitter<Events: Object> {
listenersMap: Map<string, Set<Function>> = new Map();

addListener<Event: $Keys<Events>>(
event: Event,
listener: (...$ElementType<Events, Event>) => any,
): void {
let listeners = this.listenersMap.get(event);
if (listeners === undefined) {
listeners = new Set();

this.listenersMap.set(event, listeners);
}

listeners.add(listener);
}

emit<Event: $Keys<Events>>(
event: Event,
...args: $ElementType<Events, Event>
): void {
const listeners = this.listenersMap.get(event);
if (listeners !== undefined) {
let caughtError = null;

listeners.forEach(listener => {
try {
listener.apply(null, args);
} catch (error) {
if (caughtError === null) {
caughtError = error;
}
}
});

if (caughtError !== null) {
throw caughtError;
}
}
}

removeAllListeners(event?: $Keys<Events>): void {
if (event != null) {
this.listenersMap.delete(event);
} else {
this.listenersMap.clear();
}
}

removeListener(event: $Keys<Events>, listener: Function): void {
const listeners = this.listenersMap.get(event);
if (listeners !== undefined) {
listeners.delete(listener);
}
}
}
17 changes: 1 addition & 16 deletions scripts/flow/react-devtools.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,4 @@
* @flow
*/

declare module 'events' {
declare class EventEmitter<Events: Object> {
addListener<Event: $Keys<Events>>(
event: Event,
listener: (...$ElementType<Events, Event>) => any,
): void;
emit: <Event: $Keys<Events>>(
event: Event,
...$ElementType<Events, Event>
) => void;
removeListener(event: $Keys<Events>, listener: Function): void;
removeAllListeners(event?: $Keys<Events>): void;
}

declare export default typeof EventEmitter;
}
// No types

0 comments on commit 7788cec

Please sign in to comment.