UNPKG

@wordpress/hooks

Version:
101 lines (88 loc) 2.6 kB
/** * Internal dependencies */ import type { Hooks, StoreKey } from './types'; export type RunHook = ( hookName: string, ...args: unknown[] ) => undefined | unknown; /** * Returns a function which, when invoked, will execute all callbacks * registered to a hook of the specified type, optionally returning the final * value of the call chain. * * @param hooks Hooks instance. * @param storeKey * @param returnFirstArg Whether each hook callback is expected to return its first argument. * @param async Whether the hook callback should be run asynchronously * * @return Function that runs hook callbacks. */ function createRunHook( hooks: Hooks, storeKey: StoreKey, returnFirstArg: boolean, async: boolean ): RunHook { return function runHook( hookName, ...args ) { const hooksStore = hooks[ storeKey ]; if ( ! hooksStore[ hookName ] ) { hooksStore[ hookName ] = { handlers: [], runs: 0, }; } hooksStore[ hookName ].runs++; const handlers = hooksStore[ hookName ].handlers; // The following code is stripped from production builds. if ( 'production' !== process.env.NODE_ENV ) { // Handle any 'all' hooks registered. if ( 'hookAdded' !== hookName && hooksStore.all ) { handlers.push( ...hooksStore.all.handlers ); } } if ( ! handlers || ! handlers.length ) { return returnFirstArg ? args[ 0 ] : undefined; } const hookInfo = { name: hookName, currentIndex: 0, }; async function asyncRunner() { try { hooksStore.__current.add( hookInfo ); let result = returnFirstArg ? args[ 0 ] : undefined; while ( hookInfo.currentIndex < handlers.length ) { const handler = handlers[ hookInfo.currentIndex ]; result = await handler.callback.apply( null, args ); if ( returnFirstArg ) { args[ 0 ] = result; } hookInfo.currentIndex++; } return returnFirstArg ? result : undefined; } finally { hooksStore.__current.delete( hookInfo ); } } function syncRunner() { try { hooksStore.__current.add( hookInfo ); let result = returnFirstArg ? args[ 0 ] : undefined; while ( hookInfo.currentIndex < handlers.length ) { const handler = handlers[ hookInfo.currentIndex ]; result = handler.callback.apply( null, args ); if ( returnFirstArg ) { args[ 0 ] = result; } hookInfo.currentIndex++; } return returnFirstArg ? result : undefined; } finally { hooksStore.__current.delete( hookInfo ); } } return ( async ? asyncRunner : syncRunner )(); }; } export default createRunHook;