2021-03-09 10:50:51 +00:00
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
2022-07-08 05:53:24 +00:00
|
|
|
import {
|
|
|
|
getObserversByPriority,
|
|
|
|
isErrorResponse,
|
|
|
|
isFailResponse,
|
2023-02-13 11:43:57 +00:00
|
|
|
ObserverResponse,
|
|
|
|
responseTypes,
|
2022-07-08 05:53:24 +00:00
|
|
|
} from './utils';
|
2021-03-09 10:50:51 +00:00
|
|
|
import type { EventObserversType } from './types';
|
2023-02-13 11:43:57 +00:00
|
|
|
import { isObserverResponse } from '../../../types/type-guards/observers';
|
2020-04-03 11:50:54 +00:00
|
|
|
|
2020-03-20 16:46:24 +00:00
|
|
|
/**
|
|
|
|
* Emits events on registered observers for the provided type and passes along
|
|
|
|
* the provided data.
|
|
|
|
*
|
|
|
|
* This event emitter will silently catch promise errors, but doesn't care
|
|
|
|
* otherwise if any errors are caused by observers. So events that do care
|
|
|
|
* should use `emitEventWithAbort` instead.
|
|
|
|
*
|
|
|
|
* @param {Object} observers The registered observers to omit to.
|
|
|
|
* @param {string} eventType The event type being emitted.
|
2021-03-09 10:50:51 +00:00
|
|
|
* @param {*} data Data passed along to the observer when it is invoked.
|
2020-03-20 16:46:24 +00:00
|
|
|
*
|
2021-03-09 10:50:51 +00:00
|
|
|
* @return {Promise} A promise that resolves to true after all observers have executed.
|
2020-03-20 16:46:24 +00:00
|
|
|
*/
|
2021-03-09 10:50:51 +00:00
|
|
|
export const emitEvent = async (
|
|
|
|
observers: EventObserversType,
|
|
|
|
eventType: string,
|
|
|
|
data: unknown
|
|
|
|
): Promise< unknown > => {
|
2020-04-03 11:50:54 +00:00
|
|
|
const observersByType = getObserversByPriority( observers, eventType );
|
2020-04-06 20:36:19 +00:00
|
|
|
const observerResponses = [];
|
2020-04-02 09:27:54 +00:00
|
|
|
for ( const observer of observersByType ) {
|
2020-03-20 16:46:24 +00:00
|
|
|
try {
|
2020-04-06 20:36:19 +00:00
|
|
|
const observerResponse = await Promise.resolve(
|
|
|
|
observer.callback( data )
|
|
|
|
);
|
|
|
|
if ( typeof observerResponse === 'object' ) {
|
|
|
|
observerResponses.push( observerResponse );
|
|
|
|
}
|
2020-03-20 16:46:24 +00:00
|
|
|
} catch ( e ) {
|
2021-03-09 10:50:51 +00:00
|
|
|
// we don't care about errors blocking execution, but will console.error for troubleshooting.
|
2020-03-20 16:46:24 +00:00
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.error( e );
|
|
|
|
}
|
|
|
|
}
|
2020-04-06 20:36:19 +00:00
|
|
|
return observerResponses.length ? observerResponses : true;
|
2020-03-20 16:46:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Emits events on registered observers for the provided type and passes along
|
2021-05-07 20:39:28 +00:00
|
|
|
* the provided data. This event emitter will abort if an observer throws an
|
|
|
|
* error or if the response includes an object with an error type property.
|
|
|
|
*
|
|
|
|
* Any successful observer responses before abort will be included in the returned package.
|
2020-03-20 16:46:24 +00:00
|
|
|
*
|
|
|
|
* @param {Object} observers The registered observers to omit to.
|
|
|
|
* @param {string} eventType The event type being emitted.
|
2021-03-09 10:50:51 +00:00
|
|
|
* @param {*} data Data passed along to the observer when it is invoked.
|
2020-03-20 16:46:24 +00:00
|
|
|
*
|
2021-05-07 20:39:28 +00:00
|
|
|
* @return {Promise} Returns a promise that resolves to either boolean, or an array of responses
|
|
|
|
* from registered observers that were invoked up to the point of an error.
|
2020-03-20 16:46:24 +00:00
|
|
|
*/
|
2021-03-09 10:50:51 +00:00
|
|
|
export const emitEventWithAbort = async (
|
|
|
|
observers: EventObserversType,
|
|
|
|
eventType: string,
|
|
|
|
data: unknown
|
2023-02-13 11:43:57 +00:00
|
|
|
): Promise< ObserverResponse[] > => {
|
|
|
|
const observerResponses: ObserverResponse[] = [];
|
2020-04-03 11:50:54 +00:00
|
|
|
const observersByType = getObserversByPriority( observers, eventType );
|
2020-04-02 09:27:54 +00:00
|
|
|
for ( const observer of observersByType ) {
|
2020-03-20 16:46:24 +00:00
|
|
|
try {
|
2020-04-03 11:50:54 +00:00
|
|
|
const response = await Promise.resolve( observer.callback( data ) );
|
2023-02-13 11:43:57 +00:00
|
|
|
if ( ! isObserverResponse( response ) ) {
|
2020-10-09 08:52:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-03-09 10:50:51 +00:00
|
|
|
if ( ! response.hasOwnProperty( 'type' ) ) {
|
2020-04-21 02:33:16 +00:00
|
|
|
throw new Error(
|
2021-05-07 20:39:28 +00:00
|
|
|
'Returned objects from event emitter observers must return an object with a type property'
|
2020-04-21 02:33:16 +00:00
|
|
|
);
|
|
|
|
}
|
2021-05-07 20:39:28 +00:00
|
|
|
if ( isErrorResponse( response ) || isFailResponse( response ) ) {
|
|
|
|
observerResponses.push( response );
|
|
|
|
// early abort.
|
|
|
|
return observerResponses;
|
|
|
|
}
|
|
|
|
// all potential abort conditions have been considered push the
|
|
|
|
// response to the array.
|
|
|
|
observerResponses.push( response );
|
2020-03-20 16:46:24 +00:00
|
|
|
} catch ( e ) {
|
2020-07-30 10:57:22 +00:00
|
|
|
// We don't handle thrown errors but just console.log for troubleshooting.
|
2020-03-20 16:46:24 +00:00
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.error( e );
|
2023-02-13 11:43:57 +00:00
|
|
|
observerResponses.push( { type: responseTypes.ERROR } );
|
2021-05-07 20:39:28 +00:00
|
|
|
return observerResponses;
|
2020-03-20 16:46:24 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-07 20:39:28 +00:00
|
|
|
return observerResponses;
|
2020-03-20 16:46:24 +00:00
|
|
|
};
|