@@ -85,3 +85,87 @@ export class EventEmitterWrapper implements EventEmitter {
8585 return this . _wrapped . listenerCount ( type ) ;
8686 }
8787}
88+
89+
90+ type Handler = ( ...args : any [ ] ) => void ;
91+ interface EventMap {
92+ [ k : string ] : Handler | Handler [ ] | undefined ;
93+ }
94+
95+ /** @function safeApply */
96+ function safeApply < T , A extends any [ ] > ( handler : ( this : T , ...args : A ) => void , context : T , args : A ) : void {
97+ try {
98+ Reflect . apply ( handler , context , args ) ;
99+ } catch ( err ) {
100+ // Throw error after timeout so as not to interrupt the stack
101+ setTimeout ( ( ) => {
102+ throw err ;
103+ } ) ;
104+ }
105+ }
106+
107+ /** @function arrayClone */
108+ function arrayClone < T > ( arr : T [ ] ) : T [ ] {
109+ const n = arr . length ;
110+ const copy = new Array ( n ) ;
111+ for ( let i = 0 ; i < n ; i += 1 ) {
112+ copy [ i ] = arr [ i ] ;
113+ }
114+ return copy ;
115+ }
116+
117+ /**
118+ * SafeEventEmitter
119+ * @license ISC License
120+ * Copyright (c) 2020 MetaMask
121+ *
122+ */
123+
124+ /** @class SafeEventEmitter */
125+ export default class SafeEventEmitter extends EventEmitter {
126+ emit ( type : string , ...args : any [ ] ) : boolean {
127+ let doError = type === 'error' ;
128+
129+ const events : EventMap = ( this as any ) . _events ;
130+ if ( events !== undefined ) {
131+ doError = doError && events . error === undefined ;
132+ } else if ( ! doError ) {
133+ return false ;
134+ }
135+
136+ // If there is no 'error' event listener then throw.
137+ if ( doError ) {
138+ let er ;
139+ if ( args . length > 0 ) {
140+ [ er ] = args ;
141+ }
142+ if ( er instanceof Error ) {
143+ // Note: The comments on the `throw` lines are intentional, they show
144+ // up in Node's output if this results in an unhandled exception.
145+ throw er ; // Unhandled 'error' event
146+ }
147+ // At least give some kind of context to the user
148+ const err = new Error ( `Unhandled error.${ er ? ` (${ er . message } )` : '' } ` ) ;
149+ ( err as any ) . context = er ;
150+ throw err ; // Unhandled 'error' event
151+ }
152+
153+ const handler = events [ type ] ;
154+
155+ if ( handler === undefined ) {
156+ return false ;
157+ }
158+
159+ if ( typeof handler === 'function' ) {
160+ safeApply ( handler , this , args ) ;
161+ } else {
162+ const len = handler . length ;
163+ const listeners = arrayClone ( handler ) ;
164+ for ( let i = 0 ; i < len ; i += 1 ) {
165+ safeApply ( listeners [ i ] , this , args ) ;
166+ }
167+ }
168+
169+ return true ;
170+ }
171+ }
0 commit comments