From 6bca9da3e41141ac77ea3aecec278889472186ab Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Tue, 18 Jul 2017 15:17:34 -0400 Subject: [PATCH 01/91] add wp-hooks, first pass --- packages/hooks/package.json | 18 ++ packages/hooks/src/index.js | 333 ++++++++++++++++++++++++++ packages/hooks/src/test/index.test.js | 4 + 3 files changed, 355 insertions(+) create mode 100644 packages/hooks/package.json create mode 100644 packages/hooks/src/index.js create mode 100644 packages/hooks/src/test/index.test.js diff --git a/packages/hooks/package.json b/packages/hooks/package.json new file mode 100644 index 0000000..af78230 --- /dev/null +++ b/packages/hooks/package.json @@ -0,0 +1,18 @@ +{ + "name": "@wordpress/hooks", + "version": "1.0.0", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/packages.git" + }, + "description": "WordPress Hooks library", + "main": "build/index.js", + "module": "build-module/index.js", + "browser": "build-browser/index.js", + "author": "WordPress", + "license": "GPL-2.0+", + "dependencies": { + "querystring": "^0.2.0", + "url": "^0.11.0" + } +} diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js new file mode 100644 index 0000000..521bcb5 --- /dev/null +++ b/packages/hooks/src/index.js @@ -0,0 +1,333 @@ + +//export function addQueryArgs( url, args ) { + + +/** + * Contains the registered hooks, keyed by hook type. Each hook type is an + * array of objects with priority and callback of each registered hook. + */ +var HOOKS = {}; + +/** + * Returns a function which, when invoked, will add a hook. + * + * @param {string} type Type for which hooks are to be added + * @return {Function} Hook added + */ +function createAddHookByType( type ) { + /** + * Adds the hook to the appropriate hooks container + * + * @param {string} hook Name of hook to add + * @param {Function} callback Function to call when the hook is run + * @param {?number} priority Priority of this hook (default=10) + */ + return function( hook, callback, priority ) { + var hookObject, hooks; + if ( typeof hook !== 'string' || typeof callback !== 'function' ) { + return; + } + + // Assign default priority + if ( 'undefined' === typeof priority ) { + priority = 10; + } else { + priority = parseInt( priority, 10 ); + } + + // Validate numeric priority + if ( isNaN( priority ) ) { + return; + } + + // Check if adding first of type + if ( ! HOOKS[ type ] ) { + HOOKS[ type ] = {}; + } + + hookObject = { + callback: callback, + priority: priority + }; + + if ( HOOKS[ type ].hasOwnProperty( hook ) ) { + // Append and re-sort amongst existing + hooks = HOOKS[ type ][ hook ]; + hooks.push( hookObject ); + hooks = sortHooks( hooks ); + } else { + // First of its type needs no sort + hooks = [ hookObject ]; + } + + HOOKS[ type ][ hook ] = hooks; + }; +} + +/** + * Returns a function which, when invoked, will remove a specified hook. + * + * @param {string} type Type for which hooks are to be removed + * @return {Function} Hook remover + */ +function createRemoveHookByType( type ) { + /** + * Removes the specified hook by resetting its value. + * + * @param {string} hook Name of hook to remove + * @param {?Function} callback The specific callback to be removed. If + * omitted, clears all callbacks. + */ + return function( hook, callback ) { + var handlers, i; + + // Baily early if no hooks exist by this name + if ( ! HOOKS[ type ] || ! HOOKS[ type ].hasOwnProperty( hook ) ) { + return; + } + + if ( callback ) { + // Try to find specified callback to remove + handlers = HOOKS[ type ][ hook ]; + for ( i = handlers.length - 1; i >= 0; i-- ) { + if ( handlers[ i ].callback === callback ) { + handlers.splice( i, 1 ); + } + } + } else { + // Reset hooks to empty + delete HOOKS[ type ][ hook ]; + } + }; +} + +/** + * Returns a function which, when invoked, will execute all registered + * hooks of the specified type by calling upon runner with its hook name + * and arguments. + * + * @param {string} type Type for which hooks are to be run, one of 'action' or 'filter'. + * @param {Function} runner Function to invoke for each hook callback + * @return {Function} Hook runner + */ +function createRunHookByType( type, runner ) { + /** + * Runs the specified hook. + * + * @param {string} hook The hook to run + * @param {...*} args Arguments to pass to the action/filter + * @return {*} Return value of runner, if applicable + * @private + */ + return function( /* hook, ...args */ ) { + var args, hook; + + args = Array.prototype.slice.call( arguments ); + hook = args.shift(); + + if ( typeof hook === 'string' ) { + return runner( hook, args ); + } + }; +} + +/** + * Performs an action if it exists. + * + * @param {string} action The action to perform. + * @param {...*} args Optional args to pass to the action. + * @private + */ +function runDoAction( action, args ) { + var handlers, i; + if ( HOOKS.actions ) { + handlers = HOOKS.actions[ action ]; + } + + if ( ! handlers ) { + return; + } + + HOOKS.actions.current = action; + + for ( i = 0; i < handlers.length; i++ ) { + handlers[ i ].callback.apply( null, args ); + HOOKS.actions[ action ].runs = HOOKS.actions[ action ].runs ? HOOKS.actions[ action ].runs + 1 : 1; + } + +} + +/** + * Performs a filter if it exists. + * + * @param {string} filter The filter to apply. + * @param {...*} args Optional args to pass to the filter. + * @return {*} The filtered value + * @private + */ +function runApplyFilters( filter, args ) { + var handlers, i; + if ( HOOKS.filters ) { + handlers = HOOKS.filters[ filter ]; + } + + if ( ! handlers ) { + return args[ 0 ]; + } + + HOOKS.filters.current = filter; + HOOKS.filters[ filter ].runs = HOOKS.filters[ filter ].runs ? HOOKS.filters[ filter ].runs + 1 : 1; + + for ( i = 0; i < handlers.length; i++ ) { + args[ 0 ] = handlers[ i ].callback.apply( null, args ); + } + delete( HOOKS.filters.current ); + + return args[ 0 ]; +} + +/** + * Use an insert sort for keeping our hooks organized based on priority. + * + * @see http://jsperf.com/javascript-sort + * + * @param {Array} hooks Array of the hooks to sort + * @return {Array} The sorted array + * @private + */ +function sortHooks( hooks ) { + var i, tmpHook, j, prevHook; + for ( i = 1; i < hooks.length; i++ ) { + tmpHook = hooks[ i ]; + j = i; + while ( ( prevHook = hooks[ j - 1 ] ) && prevHook.priority > tmpHook.priority ) { + hooks[ j ] = hooks[ j - 1 ]; + --j; + } + hooks[ j ] = tmpHook; + } + + return hooks; +} + + +/** + * See what action is currently being executed. + * + * @param {string} type Type of hooks to check, one of 'action' or 'filter'. + * @param {string} action The name of the action to check for. + * + * @return {[type]} [description] + */ +function createCurrentHookByType( type ) { + return function( action ) { + + // If the action was not passed, check for any current hook. + if ( 'undefined' === typeof action ) { + return false; + } + + // Return the current hook. + return HOOKS[ type ] && HOOKS[ type ].current ? + HOOKS[ type ].current : + false; + }; +} + + + +/** + * Checks to see if an action is currently being executed. + * + * @param {string} type Type of hooks to check, one of 'action' or 'filter'. + * @param {string} action The name of the action to check for, if omitted will check for any action being performed. + * + * @return {[type]} [description] + */ +function createDoingHookByType( type ) { + return function( action ) { + + // If the action was not passed, check for any current hook. + if ( 'undefined' === typeof action ) { + return 'undefined' !== typeof HOOKS[ type ].current; + } + + // Return the current hook. + return HOOKS[ type ] && HOOKS[ type ].current ? + action === HOOKS[ type ].current : + false; + }; +} + +/** + * Retrieve the number of times an action is fired. + * + * @param {string} type Type for which hooks to check, one of 'action' or 'filter'. + * @param {string} action The action to check. + * + * @return {[type]} [description] + */ +function createDidHookByType( type ) { + return function( action ) { + return HOOKS[ type ] && HOOKS[ type ][ action ] && HOOKS[ type ][ action ].runs ? + HOOKS[ type ][ action ].runs : + 0; + }; +} + +/** + * Check to see if an action is registered for a hook. + * + * @param {string} type Type for which hooks to check, one of 'action' or 'filter'. + * @param {string} action The action to check. + * + * @return {bool} Whether an action has been registered for a hook. + */ +function createHasHookByType( type ) { + return function( action ) { + return HOOKS[ type ] && HOOKS[ type ][ action ] ? + !! HOOKS[ type ][ action ] : + false; + }; +} + +/** + * Remove all the actions registered to a hook, + */ +function createRemoveAllByType( type ) { + return function( action, type ) { + + }; +} + +// Remove functions. +export removeFilter = createRemoveHookByType( 'filters' ); +export removeAction = createRemoveHookByType( 'actions' ); + + +// Do action/apply filter functions. +export doAction = createRunHookByType( 'actions', runDoAction ); +export applyFilters = createRunHookByType( 'filters', runApplyFilters ); + +// Add functions. +export addAction = createAddHookByType( 'actions' ); +export addFilter = createAddHookByType( 'filters' ); + +// Doing functions. +export doingAction = createDoingHookByType( 'actions' ), /* True for actions until;next action fired. */ +export doingFilter = createDoingHookByType( 'filters' ), /* True for filters while;filter is being applied. */ + +// Did functions. +export didAction = createDidHookByType( 'actions' ); +export didFilter = createDidHookByType( 'filters' ); + +// Has functions. +export hasAction = createHasHookByType( 'actions' ); +export hasFilter = createHasHookByType( 'filters' ); + +// Remove all functions. +export removeAllActions = createRemoveAllByType( 'actions' ); +export removeAllFilters = createRemoveAllByType( 'filters' ); + +// Current filter. +export currentFilter = createCurrentHookByType( 'filters' ); diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js new file mode 100644 index 0000000..27d9ce5 --- /dev/null +++ b/packages/hooks/src/test/index.test.js @@ -0,0 +1,4 @@ +/** + * Internal Dependencies + */ +import { doAction, applyFilters, addAction, addFilter, doingAction, doingFilter, didAction, didFilter, hasAction, hasFilter, removeAllActions, removeAllFilters, currentFilter } from '../'; From 85c73bea6defa1a63c4c8d10a33c23c07f60d0c2 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 19 Jul 2017 10:28:00 -0400 Subject: [PATCH 02/91] updates from ticket, flesh out removeAll, cleanup --- packages/hooks/src/index.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index 521bcb5..d37d6d9 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -67,10 +67,12 @@ function createAddHookByType( type ) { /** * Returns a function which, when invoked, will remove a specified hook. * - * @param {string} type Type for which hooks are to be removed - * @return {Function} Hook remover + * @param {string} type Type for which hooks are to be removed. + * @param {bool} removeAll Whether to always remove all hooked callbacks. + * + * @return {Function} Hook remover. */ -function createRemoveHookByType( type ) { +function createRemoveHookByType( type, removeAll ) { /** * Removes the specified hook by resetting its value. * @@ -86,7 +88,7 @@ function createRemoveHookByType( type ) { return; } - if ( callback ) { + if ( callback && ! removeAll ) { // Try to find specified callback to remove handlers = HOOKS[ type ][ hook ]; for ( i = handlers.length - 1; i >= 0; i-- ) { @@ -154,7 +156,6 @@ function runDoAction( action, args ) { handlers[ i ].callback.apply( null, args ); HOOKS.actions[ action ].runs = HOOKS.actions[ action ].runs ? HOOKS.actions[ action ].runs + 1 : 1; } - } /** @@ -292,12 +293,10 @@ function createHasHookByType( type ) { } /** - * Remove all the actions registered to a hook, + * Remove all the actions registered to a hook. */ function createRemoveAllByType( type ) { - return function( action, type ) { - - }; + return createRemoveHookByType( type, true ); } // Remove functions. From dc71cd1d7766892e2f2430d2b8c40cf153546d88 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 19 Jul 2017 10:32:29 -0400 Subject: [PATCH 03/91] inline docs cleanup --- packages/hooks/src/index.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index d37d6d9..259c14e 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -303,7 +303,6 @@ function createRemoveAllByType( type ) { export removeFilter = createRemoveHookByType( 'filters' ); export removeAction = createRemoveHookByType( 'actions' ); - // Do action/apply filter functions. export doAction = createRunHookByType( 'actions', runDoAction ); export applyFilters = createRunHookByType( 'filters', runApplyFilters ); @@ -312,9 +311,11 @@ export applyFilters = createRunHookByType( 'filters', runApplyFilters ); export addAction = createAddHookByType( 'actions' ); export addFilter = createAddHookByType( 'filters' ); -// Doing functions. -export doingAction = createDoingHookByType( 'actions' ), /* True for actions until;next action fired. */ -export doingFilter = createDoingHookByType( 'filters' ), /* True for filters while;filter is being applied. */ +// Doing action: true until next action fired. +export doingAction = createDoingHookByType( 'actions' ), + +// Doing filter: true while filter is being applied. +export doingFilter = createDoingHookByType( 'filters' ), // Did functions. export didAction = createDidHookByType( 'actions' ); From 4013c9a4e2ec3f297c97aea807c373dba97f0567 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 19 Jul 2017 10:33:41 -0400 Subject: [PATCH 04/91] remove some commented code --- packages/hooks/src/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index 259c14e..a9bae33 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -1,7 +1,3 @@ - -//export function addQueryArgs( url, args ) { - - /** * Contains the registered hooks, keyed by hook type. Each hook type is an * array of objects with priority and callback of each registered hook. From ff65810fbe8d83f66ad6f237c1e24c55ca3c5ed8 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 19 Jul 2017 10:33:56 -0400 Subject: [PATCH 05/91] downgrade initial version --- packages/hooks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hooks/package.json b/packages/hooks/package.json index af78230..4724aff 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/hooks", - "version": "1.0.0", + "version": "0.1.0", "repository": { "type": "git", "url": "https://github.com/WordPress/packages.git" From be62409416336566ae6db268a33fd4556fa067b7 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 19 Jul 2017 10:35:23 -0400 Subject: [PATCH 06/91] clean up imports for (empty) tests file --- packages/hooks/src/test/index.test.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 27d9ce5..247e922 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -1,4 +1,20 @@ /** - * Internal Dependencies + * Internal Dependencies. */ -import { doAction, applyFilters, addAction, addFilter, doingAction, doingFilter, didAction, didFilter, hasAction, hasFilter, removeAllActions, removeAllFilters, currentFilter } from '../'; +import { + doAction + applyFilters + addAction + addFilter + doingAction + doingFilter + didAction + didFilter + hasAction + hasFilter + removeAllActions + removeAllFilters + currentFilter +} from '../'; + +// @todo port over qunit tests from core. From 45d70c38df2485d73f248b28562706d5a8f24ccc Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 19 Jul 2017 23:42:30 -0400 Subject: [PATCH 07/91] bring over object approach from core instead of passing around string --- packages/hooks/src/index.js | 132 ++++++++++++++------------ packages/hooks/src/test/index.test.js | 24 ++--- 2 files changed, 84 insertions(+), 72 deletions(-) diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index a9bae33..f5544c1 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -2,15 +2,18 @@ * Contains the registered hooks, keyed by hook type. Each hook type is an * array of objects with priority and callback of each registered hook. */ -var HOOKS = {}; +var HOOKS = { + actions: [], + filters: [] +}; /** * Returns a function which, when invoked, will add a hook. * - * @param {string} type Type for which hooks are to be added - * @return {Function} Hook added + * @param {string} hooksArray Hooks array to which hooks are to be added + * @return {Function} Hook added. */ -function createAddHookByType( type ) { +function createAddHook( hooksArray ) { /** * Adds the hook to the appropriate hooks container * @@ -36,19 +39,14 @@ function createAddHookByType( type ) { return; } - // Check if adding first of type - if ( ! HOOKS[ type ] ) { - HOOKS[ type ] = {}; - } - hookObject = { callback: callback, priority: priority }; - if ( HOOKS[ type ].hasOwnProperty( hook ) ) { + if ( hooksArray.hasOwnProperty( hook ) ) { // Append and re-sort amongst existing - hooks = HOOKS[ type ][ hook ]; + hooks = hooksArray[ hook ]; hooks.push( hookObject ); hooks = sortHooks( hooks ); } else { @@ -56,37 +54,37 @@ function createAddHookByType( type ) { hooks = [ hookObject ]; } - HOOKS[ type ][ hook ] = hooks; + hooksArray[ hook ] = hooks; }; } /** * Returns a function which, when invoked, will remove a specified hook. * - * @param {string} type Type for which hooks are to be removed. - * @param {bool} removeAll Whether to always remove all hooked callbacks. + * @param {string} hooksArray Hooks array from which hooks are to be removed. + * @param {bool} removeAll Whether to always remove all hooked callbacks. * * @return {Function} Hook remover. */ -function createRemoveHookByType( type, removeAll ) { +function createRemoveHook( hooksArray, removeAll ) { /** * Removes the specified hook by resetting its value. * * @param {string} hook Name of hook to remove - * @param {?Function} callback The specific callback to be removed. If + * @param {?Function} callback The specific callback to be removed. Optional, if * omitted, clears all callbacks. */ return function( hook, callback ) { var handlers, i; // Baily early if no hooks exist by this name - if ( ! HOOKS[ type ] || ! HOOKS[ type ].hasOwnProperty( hook ) ) { + if ( ! hooksArray || ! hooksArray.hasOwnProperty( hook ) ) { return; } if ( callback && ! removeAll ) { // Try to find specified callback to remove - handlers = HOOKS[ type ][ hook ]; + handlers = hooksArray[ hook ]; for ( i = handlers.length - 1; i >= 0; i-- ) { if ( handlers[ i ].callback === callback ) { handlers.splice( i, 1 ); @@ -94,7 +92,7 @@ function createRemoveHookByType( type, removeAll ) { } } else { // Reset hooks to empty - delete HOOKS[ type ][ hook ]; + delete hooksArray[ hook ]; } }; } @@ -104,11 +102,10 @@ function createRemoveHookByType( type, removeAll ) { * hooks of the specified type by calling upon runner with its hook name * and arguments. * - * @param {string} type Type for which hooks are to be run, one of 'action' or 'filter'. * @param {Function} runner Function to invoke for each hook callback * @return {Function} Hook runner */ -function createRunHookByType( type, runner ) { +function createRunHook( runner ) { /** * Runs the specified hook. * @@ -152,6 +149,7 @@ function runDoAction( action, args ) { handlers[ i ].callback.apply( null, args ); HOOKS.actions[ action ].runs = HOOKS.actions[ action ].runs ? HOOKS.actions[ action ].runs + 1 : 1; } + } /** @@ -211,13 +209,21 @@ function sortHooks( hooks ) { /** * See what action is currently being executed. * - * @param {string} type Type of hooks to check, one of 'action' or 'filter'. - * @param {string} action The name of the action to check for. + * @param {string} hooksArray Hooks array of hooks to check. + * @param {string} action The name of the action to check for. * - * @return {[type]} [description] + * @return {Function} A function that gets the currently executing filter, */ -function createCurrentHookByType( type ) { - return function( action ) { +function createCurrentHook( hooksArray ) { + + /** + * Get the current active hook. + * + * @param {string} action The name of the action to check for, if omitted will check for any action being performed. + * + * @return {string} Returns the currently executing action, or false if none. + */ + return function() { // If the action was not passed, check for any current hook. if ( 'undefined' === typeof action ) { @@ -225,8 +231,8 @@ function createCurrentHookByType( type ) { } // Return the current hook. - return HOOKS[ type ] && HOOKS[ type ].current ? - HOOKS[ type ].current : + return hooksArray && hooksArray.current ? + hooksArray.current : false; }; } @@ -236,22 +242,22 @@ function createCurrentHookByType( type ) { /** * Checks to see if an action is currently being executed. * - * @param {string} type Type of hooks to check, one of 'action' or 'filter'. + * @param {string} type Type of hooks to check. * @param {string} action The name of the action to check for, if omitted will check for any action being performed. * * @return {[type]} [description] */ -function createDoingHookByType( type ) { +function createDoingHook( hooksArray ) { return function( action ) { // If the action was not passed, check for any current hook. if ( 'undefined' === typeof action ) { - return 'undefined' !== typeof HOOKS[ type ].current; + return 'undefined' !== typeof hooksArray.current; } // Return the current hook. - return HOOKS[ type ] && HOOKS[ type ].current ? - action === HOOKS[ type ].current : + return hooksArray && hooksArray.current ? + action === hooksArray.current : false; }; } @@ -259,15 +265,15 @@ function createDoingHookByType( type ) { /** * Retrieve the number of times an action is fired. * - * @param {string} type Type for which hooks to check, one of 'action' or 'filter'. - * @param {string} action The action to check. + * @param {string} hooksArray Hooks array of hooks to check. + * @param {string} action The action to check. * * @return {[type]} [description] */ -function createDidHookByType( type ) { +function createDidHook( hooksArray ) { return function( action ) { - return HOOKS[ type ] && HOOKS[ type ][ action ] && HOOKS[ type ][ action ].runs ? - HOOKS[ type ][ action ].runs : + return hooksArray && hooksArray[ action ] && hooksArray[ action ].runs ? + hooksArray[ action ].runs : 0; }; } @@ -275,55 +281,61 @@ function createDidHookByType( type ) { /** * Check to see if an action is registered for a hook. * - * @param {string} type Type for which hooks to check, one of 'action' or 'filter'. - * @param {string} action The action to check. + * @param {string} hooksArray Hooks array of hooks to check. + * @param {string} action The action to check. * * @return {bool} Whether an action has been registered for a hook. */ -function createHasHookByType( type ) { +function createHasHook( hooksArray ) { return function( action ) { - return HOOKS[ type ] && HOOKS[ type ][ action ] ? - !! HOOKS[ type ][ action ] : + return hooksArray && hooksArray[ action ] ? + !! hooksArray[ action ] : false; }; } /** * Remove all the actions registered to a hook. + * + * @param {string} hooksArray Hooks array of hooks to check. + * + * @return {Function} All hook remover. */ -function createRemoveAllByType( type ) { - return createRemoveHookByType( type, true ); +function createRemoveAllHook( hooksArray ) { + return createRemoveHook( hooksArray, true ); } // Remove functions. -export removeFilter = createRemoveHookByType( 'filters' ); -export removeAction = createRemoveHookByType( 'actions' ); +export const removeFilter = createRemoveHook( HOOKS.filters ); +export const removeAction = createRemoveHook( HOOKS.actions ); + // Do action/apply filter functions. -export doAction = createRunHookByType( 'actions', runDoAction ); -export applyFilters = createRunHookByType( 'filters', runApplyFilters ); +export const doAction = createRunHook( runDoAction ); +export const applyFilters = createRunHook( runApplyFilters ); // Add functions. -export addAction = createAddHookByType( 'actions' ); -export addFilter = createAddHookByType( 'filters' ); +export const addAction = createAddHook( HOOKS.actions ); +export const addFilter = createAddHook( HOOKS.filters ); // Doing action: true until next action fired. -export doingAction = createDoingHookByType( 'actions' ), +export const doingAction = createDoingHook( HOOKS.actions ); // Doing filter: true while filter is being applied. -export doingFilter = createDoingHookByType( 'filters' ), +export const doingFilter = createDoingHook( HOOKS.filters ); // Did functions. -export didAction = createDidHookByType( 'actions' ); -export didFilter = createDidHookByType( 'filters' ); +export const didAction = createDidHook( HOOKS.actions ); +export const didFilter = createDidHook( HOOKS.filters ); // Has functions. -export hasAction = createHasHookByType( 'actions' ); -export hasFilter = createHasHookByType( 'filters' ); +export const hasAction = createHasHook( HOOKS.actions ); +export const hasFilter = createHasHook( HOOKS.filters ); // Remove all functions. -export removeAllActions = createRemoveAllByType( 'actions' ); -export removeAllFilters = createRemoveAllByType( 'filters' ); +export const removeAllActions = createRemoveAllHook( HOOKS.actions ); +export const removeAllFilters = createRemoveAllHook( HOOKS.filters ); // Current filter. -export currentFilter = createCurrentHookByType( 'filters' ); +export const currentFilter = createCurrentHook( HOOKS.filters ); + diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 247e922..09c1dbd 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -2,18 +2,18 @@ * Internal Dependencies. */ import { - doAction - applyFilters - addAction - addFilter - doingAction - doingFilter - didAction - didFilter - hasAction - hasFilter - removeAllActions - removeAllFilters + doAction, + applyFilters, + addAction, + addFilter, + doingAction, + doingFilter, + didAction, + didFilter, + hasAction, + hasFilter, + removeAllActions, + removeAllFilters, currentFilter } from '../'; From 632c98a066e7e900e6a9146d9aecfe1d0e95f36e Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 19 Jul 2017 23:57:11 -0400 Subject: [PATCH 08/91] First pass, jest tests --- packages/hooks/src/test/index.test.js | 73 ++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 09c1dbd..bf067cf 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -12,9 +12,80 @@ import { didFilter, hasAction, hasFilter, + removeFilter, + removeAction, removeAllActions, removeAllFilters, currentFilter } from '../'; -// @todo port over qunit tests from core. +function filter_a( str ) { + return str + 'a'; +} +function filter_b( str ) { + return str + 'b'; +} +function filter_c( str ) { + return str + 'c'; +} +function action_a() { + window.actionValue += 'a'; +} +function action_b() { + window.actionValue += 'b'; +} +function action_c() { + window.actionValue += 'c'; +} +function filter_check() { + ok( doingFilter( 'runtest.filter' ), 'The runtest.filter is running.' ); +} +window.actionValue = ''; + +describe( 'add and remove a filter', () => { + it( 'should leave the value unfiltered', () => { + addFilter( 'test.filter', filter_a ); + removeFilter( 'test.filter' ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); + } ); +} ); + +describe( 'add a filter and run it', () => { + it( 'should filter the value', () => { + addFilter( 'test.filter', filter_a ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testa' ); + removeFilter( 'test.filter' ); + } ); +} ); + +describe( 'add 2 filters in a row and run them', () => { + it( 'both filters should apply', () => { + addFilter( 'test.filter', filter_a ); + addFilter( 'test.filter', filter_b ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); + removeFilter( 'test.filter' ); + } ); +} ); + +describe( 'add 3 filters with different priorities and run them', () => { + it( 'should run in order', () => { + addFilter( 'test.filter', filter_a ); + addFilter( 'test.filter', filter_b, 2 ); + addFilter( 'test.filter', filter_c, 8 ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testbca' ); + removeFilter( 'test.filter' ); + } ); +} ); + +describe( 'add and remove an action', () => { + it( 'should leave the action unhooked', () => { + window.actionValue = ''; + addAction( 'test.action', action_a ); + removeAction( 'test.action' ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( '' ); + } ); +} ); + + + From 77c9906273791f394607abff4a92af95063c7d0c Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 20 Jul 2017 08:01:37 -0400 Subject: [PATCH 09/91] add remainder of tests --- packages/hooks/src/test/index.test.js | 179 +++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 1 deletion(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index bf067cf..2ef6986 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -38,7 +38,7 @@ function action_c() { window.actionValue += 'c'; } function filter_check() { - ok( doingFilter( 'runtest.filter' ), 'The runtest.filter is running.' ); + expect( doingFilter( 'runtest.filter' ) ).toBeTruthy(); } window.actionValue = ''; @@ -87,5 +87,182 @@ describe( 'add and remove an action', () => { } ); } ); +describe( 'add an action and run it', function() { + it( 'should', () => { + window.actionValue = ''; + addAction( 'test.action', action_a ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( 'a' ); + removeAction( 'test.action' ); + } ); +} ); + +describe( 'add 2 actions in a row and then run them', function() { + it( 'should', () => { + window.actionValue = ''; + addAction( 'test.action', action_a ); + addAction( 'test.action', action_b ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( 'ab' ); + removeAction( 'test.action' ); + } ); +} ); + +describe( 'add 3 actions with different priorities and run them', function() { + it( 'should', () => { + window.actionValue = ''; + addAction( 'test.action', action_a ); + addAction( 'test.action', action_b, 2 ); + addAction( 'test.action', action_c, 8 ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( 'bca' ); + removeAction( 'test.action' ); + } ); +} ); + +describe( 'pass in two arguments to an action', function() { + it( 'should', () => { + var arg1 = 10, + arg2 = 20; + + addAction( 'test.action', function( a, b ) { + expect( arg1 ).toBe( a ); + expect( arg2 ).toBe( b ); + } ); + doAction( 'test.action', arg1, arg2 ); + removeAction( 'test.action' ); + + expect( arg1 ).toBe( 10 ); + expect( arg2 ).toBe( 20 ); + } ); +} ); + +describe( 'fire action multiple times', function() { + it( 'should', () => { + var func; + expect.assertions(2); + + func = function() { + expect( true ).toBe( true ); + }; + + addAction( 'test.action', func ); + doAction( 'test.action' ); + doAction( 'test.action' ); + removeAction( 'test.action' ); + } ); +} ); + +describe( 'remove specific action callback', function() { + it( 'should', () => { + window.actionValue = ''; + addAction( 'test.action', action_a ); + addAction( 'test.action', action_b, 2 ); + addAction( 'test.action', action_c, 8 ); + + removeAction( 'test.action', action_b ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( 'ca' ); + removeAction( 'test.action' ); + } ); +} ); + +describe( 'remove all action callbacks', function() { + it( 'should', () => { + window.actionValue = ''; + addAction( 'test.action', action_a ); + addAction( 'test.action', action_b, 2 ); + addAction( 'test.action', action_c, 8 ); + + removeAllActions( 'test.action' ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( '' ); + } ); +} ); + +describe( 'remove specific filter callback', function() { + it( 'should', () => { + addFilter( 'test.filter', filter_a ); + addFilter( 'test.filter', filter_b, 2 ); + addFilter( 'test.filter', filter_c, 8 ); + + removeFilter( 'test.filter', filter_b ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); + removeFilter( 'test.filter' ); + } ); +} ); + +describe( 'remove all filter callbacks', function() { + it( 'should', () => { + addFilter( 'test.filter', filter_a ); + addFilter( 'test.filter', filter_b, 2 ); + addFilter( 'test.filter', filter_c, 8 ); + + removeAllFilters( 'test.filter' ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); + } ); +} ); + +// Test doingAction, didAction, hasAction. +describe( 'Test doingAction, didAction and hasAction.', function() { + it( 'should', () => { + + // Reset state for testing. + removeAction( 'test.action' ); + addAction( 'another.action', function(){} ); + doAction( 'another.action' ); + + // Verify no action is running yet. + expect( ! doingAction( 'test.action' ) ).toBeTruthy(); + + expect( didAction( 'test.action' ) ).toBe( 0 ); + expect( ! hasAction( 'test.action' ) ).toBeTruthy(); + + addAction( 'test.action', action_a ); + + // Verify action added, not running yet. + expect( ! doingAction( 'test.action' ) ).toBeTruthy(); + expect( didAction( 'test.action' ) ).toBe( 0 ); + expect( hasAction( 'test.action' ) ).toBeTruthy(); + + doAction( 'test.action' ); + + // Verify action added and running. + expect( doingAction( 'test.action' ) ).toBeTruthy(); + expect( didAction( 'test.action' ) ).toBe( 1 ); + expect( hasAction( 'test.action' ) ).toBeTruthy(); + + doAction( 'test.action' ); + expect( didAction( 'test.action' ) ).toBe( 2 ); + + removeAction( 'test.action' ); + + // Verify state is reset appropriately. + expect( doingAction( 'test.action' ) ).toBeTruthy(); + expect( didAction( 'test.action' ) ).toBe( 0 ); + expect( ! hasAction( 'test.action' ) ).toBeTruthy(); + + doAction( 'another.action' ); + expect( ! doingAction( 'test.action' ) ).toBeTruthy(); + + // Verify hasAction returns false when no matching action. + expect( ! hasAction( 'notatest.action' ) ).toBeTruthy(); + + } ); +} ); + +describe( 'Verify doingFilter, didFilter and hasFilter.', function() { + it( 'should', () => { + addFilter( 'runtest.filter', filter_check ); + + // Verify filter added and running. + var test = applyFilters( 'runtest.filter', true ); + expect( didFilter( 'runtest.filter' ), 1, 'The runtest.filter has run once.' ); + expect( hasFilter( 'runtest.filter' ), 'The runtest.filter is registered.' ); + expect( ! hasFilter( 'notatest.filter' ), 'The notatest.filter is not registered.' ); + + removeFilter( 'runtest.filter' ); + } ); +} ); From b4b713d02a910b4a3c7a933debac0e962914b204 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 20 Jul 2017 08:06:25 -0400 Subject: [PATCH 10/91] Docs refinements --- packages/hooks/src/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index f5544c1..18fa610 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -245,7 +245,7 @@ function createCurrentHook( hooksArray ) { * @param {string} type Type of hooks to check. * @param {string} action The name of the action to check for, if omitted will check for any action being performed. * - * @return {[type]} [description] + * @return {bool} Whether the hook is being executed. */ function createDoingHook( hooksArray ) { return function( action ) { @@ -268,7 +268,7 @@ function createDoingHook( hooksArray ) { * @param {string} hooksArray Hooks array of hooks to check. * @param {string} action The action to check. * - * @return {[type]} [description] + * @return {number} The number of times the hook has run. */ function createDidHook( hooksArray ) { return function( action ) { From 9d24e77cb9f0877c048e1298e000136a58bd177d Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 20 Jul 2017 08:32:59 -0400 Subject: [PATCH 11/91] Break out code into one file per funciton --- packages/hooks/src/createAddHook.js | 54 ++++ packages/hooks/src/createCurrentHook.js | 32 +++ packages/hooks/src/createDidHook.js | 17 ++ packages/hooks/src/createDoingHook.js | 24 ++ packages/hooks/src/createHasHook.js | 17 ++ packages/hooks/src/createRemoveAllHook.js | 14 + packages/hooks/src/createRemoveHook.js | 40 +++ packages/hooks/src/createRunHook.js | 30 ++ packages/hooks/src/hooks.js | 10 + packages/hooks/src/index.js | 316 +--------------------- packages/hooks/src/runApplyFilters.js | 32 +++ packages/hooks/src/runDoAction.js | 28 ++ packages/hooks/src/sortHooks.js | 25 ++ 13 files changed, 334 insertions(+), 305 deletions(-) create mode 100644 packages/hooks/src/createAddHook.js create mode 100644 packages/hooks/src/createCurrentHook.js create mode 100644 packages/hooks/src/createDidHook.js create mode 100644 packages/hooks/src/createDoingHook.js create mode 100644 packages/hooks/src/createHasHook.js create mode 100644 packages/hooks/src/createRemoveAllHook.js create mode 100644 packages/hooks/src/createRemoveHook.js create mode 100644 packages/hooks/src/createRunHook.js create mode 100644 packages/hooks/src/hooks.js create mode 100644 packages/hooks/src/runApplyFilters.js create mode 100644 packages/hooks/src/runDoAction.js create mode 100644 packages/hooks/src/sortHooks.js diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js new file mode 100644 index 0000000..2d48450 --- /dev/null +++ b/packages/hooks/src/createAddHook.js @@ -0,0 +1,54 @@ +import sortHooks from './sortHooks'; + +/** + * Returns a function which, when invoked, will add a hook. + * + * @param {string} hooksArray Hooks array to which hooks are to be added + * @return {Function} Hook added. + */ +const createAddHook = function( hooksArray ) { + /** + * Adds the hook to the appropriate hooks container + * + * @param {string} hook Name of hook to add + * @param {Function} callback Function to call when the hook is run + * @param {?number} priority Priority of this hook (default=10) + */ + return function( hook, callback, priority ) { + var hookObject, hooks; + if ( typeof hook !== 'string' || typeof callback !== 'function' ) { + return; + } + + // Assign default priority + if ( 'undefined' === typeof priority ) { + priority = 10; + } else { + priority = parseInt( priority, 10 ); + } + + // Validate numeric priority + if ( isNaN( priority ) ) { + return; + } + + hookObject = { + callback: callback, + priority: priority + }; + + if ( hooksArray.hasOwnProperty( hook ) ) { + // Append and re-sort amongst existing + hooks = hooksArray[ hook ]; + hooks.push( hookObject ); + hooks = sortHooks( hooks ); + } else { + // First of its type needs no sort + hooks = [ hookObject ]; + } + + hooksArray[ hook ] = hooks; + }; +} + +export default createAddHook; diff --git a/packages/hooks/src/createCurrentHook.js b/packages/hooks/src/createCurrentHook.js new file mode 100644 index 0000000..351808a --- /dev/null +++ b/packages/hooks/src/createCurrentHook.js @@ -0,0 +1,32 @@ +/** + * See what action is currently being executed. + * + * @param {string} hooksArray Hooks array of hooks to check. + * @param {string} action The name of the action to check for. + * + * @return {Function} A function that gets the currently executing filter, + */ +const createCurrentHook = function( hooksArray ) { + + /** + * Get the current active hook. + * + * @param {string} action The name of the action to check for, if omitted will check for any action being performed. + * + * @return {string} Returns the currently executing action, or false if none. + */ + return function() { + + // If the action was not passed, check for any current hook. + if ( 'undefined' === typeof action ) { + return false; + } + + // Return the current hook. + return hooksArray && hooksArray.current ? + hooksArray.current : + false; + }; +} + +export default createCurrentHook; diff --git a/packages/hooks/src/createDidHook.js b/packages/hooks/src/createDidHook.js new file mode 100644 index 0000000..a7223ae --- /dev/null +++ b/packages/hooks/src/createDidHook.js @@ -0,0 +1,17 @@ +/** + * Retrieve the number of times an action is fired. + * + * @param {string} hooksArray Hooks array of hooks to check. + * @param {string} action The action to check. + * + * @return {number} The number of times the hook has run. + */ +const createDidHook = function( hooksArray ) { + return function( action ) { + return hooksArray && hooksArray[ action ] && hooksArray[ action ].runs ? + hooksArray[ action ].runs : + 0; + }; +} + +export default createDidHook; diff --git a/packages/hooks/src/createDoingHook.js b/packages/hooks/src/createDoingHook.js new file mode 100644 index 0000000..95932c1 --- /dev/null +++ b/packages/hooks/src/createDoingHook.js @@ -0,0 +1,24 @@ +/** + * Checks to see if an action is currently being executed. + * + * @param {string} type Type of hooks to check. + * @param {string} action The name of the action to check for, if omitted will check for any action being performed. + * + * @return {bool} Whether the hook is being executed. + */ +const createDoingHook = function( hooksArray ) { + return function( action ) { + + // If the action was not passed, check for any current hook. + if ( 'undefined' === typeof action ) { + return 'undefined' !== typeof hooksArray.current; + } + + // Return the current hook. + return hooksArray && hooksArray.current ? + action === hooksArray.current : + false; + }; +} + +export default createDoingHook; diff --git a/packages/hooks/src/createHasHook.js b/packages/hooks/src/createHasHook.js new file mode 100644 index 0000000..6419cb5 --- /dev/null +++ b/packages/hooks/src/createHasHook.js @@ -0,0 +1,17 @@ +/** + * Check to see if an action is registered for a hook. + * + * @param {string} hooksArray Hooks array of hooks to check. + * @param {string} action The action to check. + * + * @return {bool} Whether an action has been registered for a hook. + */ +const createHasHook = function( hooksArray ) { + return function( action ) { + return hooksArray && hooksArray[ action ] ? + !! hooksArray[ action ] : + false; + }; +} + +export default createHasHook; diff --git a/packages/hooks/src/createRemoveAllHook.js b/packages/hooks/src/createRemoveAllHook.js new file mode 100644 index 0000000..b4bfd9c --- /dev/null +++ b/packages/hooks/src/createRemoveAllHook.js @@ -0,0 +1,14 @@ +import createRemoveHook from './createRemoveHook'; + +/** + * Remove all the actions registered to a hook. + * + * @param {string} hooksArray Hooks array of hooks to check. + * + * @return {Function} All hook remover. + */ +const createRemoveAllHook = function( hooksArray ) { + return createRemoveHook( hooksArray, true ); +} + +export default createRemoveAllHook; diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js new file mode 100644 index 0000000..e0c3c0a --- /dev/null +++ b/packages/hooks/src/createRemoveHook.js @@ -0,0 +1,40 @@ +/** + * Returns a function which, when invoked, will remove a specified hook. + * + * @param {string} hooksArray Hooks array from which hooks are to be removed. + * @param {bool} removeAll Whether to always remove all hooked callbacks. + * + * @return {Function} Hook remover. + */ +const createRemoveHook = function ( hooksArray, removeAll ) { + /** + * Removes the specified hook by resetting its value. + * + * @param {string} hook Name of hook to remove + * @param {?Function} callback The specific callback to be removed. Optional, if + * omitted, clears all callbacks. + */ + return function( hook, callback ) { + var handlers, i; + + // Baily early if no hooks exist by this name + if ( ! hooksArray || ! hooksArray.hasOwnProperty( hook ) ) { + return; + } + + if ( callback && ! removeAll ) { + // Try to find specified callback to remove + handlers = hooksArray[ hook ]; + for ( i = handlers.length - 1; i >= 0; i-- ) { + if ( handlers[ i ].callback === callback ) { + handlers.splice( i, 1 ); + } + } + } else { + // Reset hooks to empty + delete hooksArray[ hook ]; + } + }; +} + +export default createRemoveHook; \ No newline at end of file diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js new file mode 100644 index 0000000..7d678b2 --- /dev/null +++ b/packages/hooks/src/createRunHook.js @@ -0,0 +1,30 @@ +/** + * Returns a function which, when invoked, will execute all registered + * hooks of the specified type by calling upon runner with its hook name + * and arguments. + * + * @param {Function} runner Function to invoke for each hook callback + * @return {Function} Hook runner + */ +const createRunHook = function( runner ) { + /** + * Runs the specified hook. + * + * @param {string} hook The hook to run + * @param {...*} args Arguments to pass to the action/filter + * @return {*} Return value of runner, if applicable + * @private + */ + return function( /* hook, ...args */ ) { + var args, hook; + + args = Array.prototype.slice.call( arguments ); + hook = args.shift(); + + if ( typeof hook === 'string' ) { + return runner( hook, args ); + } + }; +} + +export default createRunHook; diff --git a/packages/hooks/src/hooks.js b/packages/hooks/src/hooks.js new file mode 100644 index 0000000..e501794 --- /dev/null +++ b/packages/hooks/src/hooks.js @@ -0,0 +1,10 @@ +/** + * Contains the registered hooks, keyed by hook type. Each hook type is an + * array of objects with priority and callback of each registered hook. + */ +var HOOKS = { + actions: [], + filters: [] +}; + +export default HOOKS; diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index 18fa610..0b5975b 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -1,309 +1,15 @@ -/** - * Contains the registered hooks, keyed by hook type. Each hook type is an - * array of objects with priority and callback of each registered hook. - */ -var HOOKS = { - actions: [], - filters: [] -}; +import HOOKS from './hooks'; +import createAddHook from './createAddHook'; +import createRemoveHook from './createRemoveHook'; +import createRunHook from './createRunHook'; +import runDoAction from './runDoAction'; +import runApplyFilters from './runApplyFilters'; +import createCurrentHook from './createCurrentHook'; +import createDoingHook from './createDoingHook'; +import createDidHook from './createDidHook'; +import createHasHook from './createHasHook'; +import createRemoveAllHook from './createRemoveAllHook'; -/** - * Returns a function which, when invoked, will add a hook. - * - * @param {string} hooksArray Hooks array to which hooks are to be added - * @return {Function} Hook added. - */ -function createAddHook( hooksArray ) { - /** - * Adds the hook to the appropriate hooks container - * - * @param {string} hook Name of hook to add - * @param {Function} callback Function to call when the hook is run - * @param {?number} priority Priority of this hook (default=10) - */ - return function( hook, callback, priority ) { - var hookObject, hooks; - if ( typeof hook !== 'string' || typeof callback !== 'function' ) { - return; - } - - // Assign default priority - if ( 'undefined' === typeof priority ) { - priority = 10; - } else { - priority = parseInt( priority, 10 ); - } - - // Validate numeric priority - if ( isNaN( priority ) ) { - return; - } - - hookObject = { - callback: callback, - priority: priority - }; - - if ( hooksArray.hasOwnProperty( hook ) ) { - // Append and re-sort amongst existing - hooks = hooksArray[ hook ]; - hooks.push( hookObject ); - hooks = sortHooks( hooks ); - } else { - // First of its type needs no sort - hooks = [ hookObject ]; - } - - hooksArray[ hook ] = hooks; - }; -} - -/** - * Returns a function which, when invoked, will remove a specified hook. - * - * @param {string} hooksArray Hooks array from which hooks are to be removed. - * @param {bool} removeAll Whether to always remove all hooked callbacks. - * - * @return {Function} Hook remover. - */ -function createRemoveHook( hooksArray, removeAll ) { - /** - * Removes the specified hook by resetting its value. - * - * @param {string} hook Name of hook to remove - * @param {?Function} callback The specific callback to be removed. Optional, if - * omitted, clears all callbacks. - */ - return function( hook, callback ) { - var handlers, i; - - // Baily early if no hooks exist by this name - if ( ! hooksArray || ! hooksArray.hasOwnProperty( hook ) ) { - return; - } - - if ( callback && ! removeAll ) { - // Try to find specified callback to remove - handlers = hooksArray[ hook ]; - for ( i = handlers.length - 1; i >= 0; i-- ) { - if ( handlers[ i ].callback === callback ) { - handlers.splice( i, 1 ); - } - } - } else { - // Reset hooks to empty - delete hooksArray[ hook ]; - } - }; -} - -/** - * Returns a function which, when invoked, will execute all registered - * hooks of the specified type by calling upon runner with its hook name - * and arguments. - * - * @param {Function} runner Function to invoke for each hook callback - * @return {Function} Hook runner - */ -function createRunHook( runner ) { - /** - * Runs the specified hook. - * - * @param {string} hook The hook to run - * @param {...*} args Arguments to pass to the action/filter - * @return {*} Return value of runner, if applicable - * @private - */ - return function( /* hook, ...args */ ) { - var args, hook; - - args = Array.prototype.slice.call( arguments ); - hook = args.shift(); - - if ( typeof hook === 'string' ) { - return runner( hook, args ); - } - }; -} - -/** - * Performs an action if it exists. - * - * @param {string} action The action to perform. - * @param {...*} args Optional args to pass to the action. - * @private - */ -function runDoAction( action, args ) { - var handlers, i; - if ( HOOKS.actions ) { - handlers = HOOKS.actions[ action ]; - } - - if ( ! handlers ) { - return; - } - - HOOKS.actions.current = action; - - for ( i = 0; i < handlers.length; i++ ) { - handlers[ i ].callback.apply( null, args ); - HOOKS.actions[ action ].runs = HOOKS.actions[ action ].runs ? HOOKS.actions[ action ].runs + 1 : 1; - } - -} - -/** - * Performs a filter if it exists. - * - * @param {string} filter The filter to apply. - * @param {...*} args Optional args to pass to the filter. - * @return {*} The filtered value - * @private - */ -function runApplyFilters( filter, args ) { - var handlers, i; - if ( HOOKS.filters ) { - handlers = HOOKS.filters[ filter ]; - } - - if ( ! handlers ) { - return args[ 0 ]; - } - - HOOKS.filters.current = filter; - HOOKS.filters[ filter ].runs = HOOKS.filters[ filter ].runs ? HOOKS.filters[ filter ].runs + 1 : 1; - - for ( i = 0; i < handlers.length; i++ ) { - args[ 0 ] = handlers[ i ].callback.apply( null, args ); - } - delete( HOOKS.filters.current ); - - return args[ 0 ]; -} - -/** - * Use an insert sort for keeping our hooks organized based on priority. - * - * @see http://jsperf.com/javascript-sort - * - * @param {Array} hooks Array of the hooks to sort - * @return {Array} The sorted array - * @private - */ -function sortHooks( hooks ) { - var i, tmpHook, j, prevHook; - for ( i = 1; i < hooks.length; i++ ) { - tmpHook = hooks[ i ]; - j = i; - while ( ( prevHook = hooks[ j - 1 ] ) && prevHook.priority > tmpHook.priority ) { - hooks[ j ] = hooks[ j - 1 ]; - --j; - } - hooks[ j ] = tmpHook; - } - - return hooks; -} - - -/** - * See what action is currently being executed. - * - * @param {string} hooksArray Hooks array of hooks to check. - * @param {string} action The name of the action to check for. - * - * @return {Function} A function that gets the currently executing filter, - */ -function createCurrentHook( hooksArray ) { - - /** - * Get the current active hook. - * - * @param {string} action The name of the action to check for, if omitted will check for any action being performed. - * - * @return {string} Returns the currently executing action, or false if none. - */ - return function() { - - // If the action was not passed, check for any current hook. - if ( 'undefined' === typeof action ) { - return false; - } - - // Return the current hook. - return hooksArray && hooksArray.current ? - hooksArray.current : - false; - }; -} - - - -/** - * Checks to see if an action is currently being executed. - * - * @param {string} type Type of hooks to check. - * @param {string} action The name of the action to check for, if omitted will check for any action being performed. - * - * @return {bool} Whether the hook is being executed. - */ -function createDoingHook( hooksArray ) { - return function( action ) { - - // If the action was not passed, check for any current hook. - if ( 'undefined' === typeof action ) { - return 'undefined' !== typeof hooksArray.current; - } - - // Return the current hook. - return hooksArray && hooksArray.current ? - action === hooksArray.current : - false; - }; -} - -/** - * Retrieve the number of times an action is fired. - * - * @param {string} hooksArray Hooks array of hooks to check. - * @param {string} action The action to check. - * - * @return {number} The number of times the hook has run. - */ -function createDidHook( hooksArray ) { - return function( action ) { - return hooksArray && hooksArray[ action ] && hooksArray[ action ].runs ? - hooksArray[ action ].runs : - 0; - }; -} - -/** - * Check to see if an action is registered for a hook. - * - * @param {string} hooksArray Hooks array of hooks to check. - * @param {string} action The action to check. - * - * @return {bool} Whether an action has been registered for a hook. - */ -function createHasHook( hooksArray ) { - return function( action ) { - return hooksArray && hooksArray[ action ] ? - !! hooksArray[ action ] : - false; - }; -} - -/** - * Remove all the actions registered to a hook. - * - * @param {string} hooksArray Hooks array of hooks to check. - * - * @return {Function} All hook remover. - */ -function createRemoveAllHook( hooksArray ) { - return createRemoveHook( hooksArray, true ); -} // Remove functions. export const removeFilter = createRemoveHook( HOOKS.filters ); diff --git a/packages/hooks/src/runApplyFilters.js b/packages/hooks/src/runApplyFilters.js new file mode 100644 index 0000000..b584cbe --- /dev/null +++ b/packages/hooks/src/runApplyFilters.js @@ -0,0 +1,32 @@ +import HOOKS from './hooks'; + +/** + * Performs a filter if it exists. + * + * @param {string} filter The filter to apply. + * @param {...*} args Optional args to pass to the filter. + * @return {*} The filtered value + * @private + */ +const runApplyFilters = function( filter, args ) { + var handlers, i; + if ( HOOKS.filters ) { + handlers = HOOKS.filters[ filter ]; + } + + if ( ! handlers ) { + return args[ 0 ]; + } + + HOOKS.filters.current = filter; + HOOKS.filters[ filter ].runs = HOOKS.filters[ filter ].runs ? HOOKS.filters[ filter ].runs + 1 : 1; + + for ( i = 0; i < handlers.length; i++ ) { + args[ 0 ] = handlers[ i ].callback.apply( null, args ); + } + delete( HOOKS.filters.current ); + + return args[ 0 ]; +} + +export default runApplyFilters; diff --git a/packages/hooks/src/runDoAction.js b/packages/hooks/src/runDoAction.js new file mode 100644 index 0000000..0688e73 --- /dev/null +++ b/packages/hooks/src/runDoAction.js @@ -0,0 +1,28 @@ +import HOOKS from './hooks'; + +/** + * Performs an action if it exists. + * + * @param {string} action The action to perform. + * @param {...*} args Optional args to pass to the action. + * @private + */ +const runDoAction = function( action, args ) { + var handlers, i; + if ( HOOKS.actions ) { + handlers = HOOKS.actions[ action ]; + } + + if ( ! handlers ) { + return; + } + + HOOKS.actions.current = action; + + for ( i = 0; i < handlers.length; i++ ) { + handlers[ i ].callback.apply( null, args ); + HOOKS.actions[ action ].runs = HOOKS.actions[ action ].runs ? HOOKS.actions[ action ].runs + 1 : 1; + } +} + +export default runDoAction; diff --git a/packages/hooks/src/sortHooks.js b/packages/hooks/src/sortHooks.js new file mode 100644 index 0000000..1b1b16b --- /dev/null +++ b/packages/hooks/src/sortHooks.js @@ -0,0 +1,25 @@ +/** + * Use an insert sort for keeping our hooks organized based on priority. + * + * @see http://jsperf.com/javascript-sort + * + * @param {Array} hooks Array of the hooks to sort + * @return {Array} The sorted array + * @private + */ +const sortHooks = function( hooks ) { + var i, tmpHook, j, prevHook; + for ( i = 1; i < hooks.length; i++ ) { + tmpHook = hooks[ i ]; + j = i; + while ( ( prevHook = hooks[ j - 1 ] ) && prevHook.priority > tmpHook.priority ) { + hooks[ j ] = hooks[ j - 1 ]; + --j; + } + hooks[ j ] = tmpHook; + } + + return hooks; +} + +export default sortHooks; From 57f6038c9e895b960649a11ef4eceab2907a574b Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 16:44:31 +0200 Subject: [PATCH 12/91] Centralize all run logic into `createRunHook` Also fixes a bug that `doingAction` would remain true after its action was completed. Effectively it would always be true. --- packages/hooks/src/createRunHook.js | 38 +++++++++++++++++++-------- packages/hooks/src/index.js | 11 +++----- packages/hooks/src/runApplyFilters.js | 32 ---------------------- packages/hooks/src/runDoAction.js | 28 -------------------- packages/hooks/src/test/index.test.js | 30 ++++++++++++--------- 5 files changed, 48 insertions(+), 91 deletions(-) delete mode 100644 packages/hooks/src/runApplyFilters.js delete mode 100644 packages/hooks/src/runDoAction.js diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index 7d678b2..af248e9 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -3,26 +3,42 @@ * hooks of the specified type by calling upon runner with its hook name * and arguments. * - * @param {Function} runner Function to invoke for each hook callback + * @param {Function} hooks Object that contains the hooks to run. + * @param {bool} returnFirstArg Whether each hook callback is expected to + * return its first argument. * @return {Function} Hook runner */ -const createRunHook = function( runner ) { +const createRunHook = function( hooks, returnFirstArg ) { /** * Runs the specified hook. * - * @param {string} hook The hook to run - * @param {...*} args Arguments to pass to the action/filter - * @return {*} Return value of runner, if applicable + * @param {string} hookName The hook to run + * @param {...*} args Arguments to pass to the hook callbacks + * @return {*} Return value of runner, if applicable * @private */ - return function( /* hook, ...args */ ) { - var args, hook; + return function runner( hookName, ...args ) { + const handlers = hooks[ hookName ]; + let maybeReturnValue = args[ 0 ]; - args = Array.prototype.slice.call( arguments ); - hook = args.shift(); + if ( ! handlers ) { + return ( returnFirstArg ? maybeReturnValue : undefined ); + } + + hooks.current = hookName; + handlers.runs = ( handlers.runs || 0 ) + 1; + + handlers.forEach( handler => { + maybeReturnValue = handler.callback.apply( null, args ); + if ( returnFirstArg ) { + args[ 0 ] = maybeReturnValue; + } + } ); + + delete hooks.current; - if ( typeof hook === 'string' ) { - return runner( hook, args ); + if ( returnFirstArg ) { + return maybeReturnValue; } }; } diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index 0b5975b..18e94a5 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -2,8 +2,6 @@ import HOOKS from './hooks'; import createAddHook from './createAddHook'; import createRemoveHook from './createRemoveHook'; import createRunHook from './createRunHook'; -import runDoAction from './runDoAction'; -import runApplyFilters from './runApplyFilters'; import createCurrentHook from './createCurrentHook'; import createDoingHook from './createDoingHook'; import createDidHook from './createDidHook'; @@ -15,19 +13,16 @@ import createRemoveAllHook from './createRemoveAllHook'; export const removeFilter = createRemoveHook( HOOKS.filters ); export const removeAction = createRemoveHook( HOOKS.actions ); - // Do action/apply filter functions. -export const doAction = createRunHook( runDoAction ); -export const applyFilters = createRunHook( runApplyFilters ); +export const doAction = createRunHook( HOOKS.actions ); +export const applyFilters = createRunHook( HOOKS.filters, true ); // Add functions. export const addAction = createAddHook( HOOKS.actions ); export const addFilter = createAddHook( HOOKS.filters ); -// Doing action: true until next action fired. +// Doing action/filter: true while a hook is being run. export const doingAction = createDoingHook( HOOKS.actions ); - -// Doing filter: true while filter is being applied. export const doingFilter = createDoingHook( HOOKS.filters ); // Did functions. diff --git a/packages/hooks/src/runApplyFilters.js b/packages/hooks/src/runApplyFilters.js deleted file mode 100644 index b584cbe..0000000 --- a/packages/hooks/src/runApplyFilters.js +++ /dev/null @@ -1,32 +0,0 @@ -import HOOKS from './hooks'; - -/** - * Performs a filter if it exists. - * - * @param {string} filter The filter to apply. - * @param {...*} args Optional args to pass to the filter. - * @return {*} The filtered value - * @private - */ -const runApplyFilters = function( filter, args ) { - var handlers, i; - if ( HOOKS.filters ) { - handlers = HOOKS.filters[ filter ]; - } - - if ( ! handlers ) { - return args[ 0 ]; - } - - HOOKS.filters.current = filter; - HOOKS.filters[ filter ].runs = HOOKS.filters[ filter ].runs ? HOOKS.filters[ filter ].runs + 1 : 1; - - for ( i = 0; i < handlers.length; i++ ) { - args[ 0 ] = handlers[ i ].callback.apply( null, args ); - } - delete( HOOKS.filters.current ); - - return args[ 0 ]; -} - -export default runApplyFilters; diff --git a/packages/hooks/src/runDoAction.js b/packages/hooks/src/runDoAction.js deleted file mode 100644 index 0688e73..0000000 --- a/packages/hooks/src/runDoAction.js +++ /dev/null @@ -1,28 +0,0 @@ -import HOOKS from './hooks'; - -/** - * Performs an action if it exists. - * - * @param {string} action The action to perform. - * @param {...*} args Optional args to pass to the action. - * @private - */ -const runDoAction = function( action, args ) { - var handlers, i; - if ( HOOKS.actions ) { - handlers = HOOKS.actions[ action ]; - } - - if ( ! handlers ) { - return; - } - - HOOKS.actions.current = action; - - for ( i = 0; i < handlers.length; i++ ) { - handlers[ i ].callback.apply( null, args ); - HOOKS.actions[ action ].runs = HOOKS.actions[ action ].runs ? HOOKS.actions[ action ].runs + 1 : 1; - } -} - -export default runDoAction; diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 2ef6986..40266b7 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -206,47 +206,53 @@ describe( 'remove all filter callbacks', function() { // Test doingAction, didAction, hasAction. describe( 'Test doingAction, didAction and hasAction.', function() { it( 'should', () => { + let actionCalls = 0; // Reset state for testing. removeAction( 'test.action' ); - addAction( 'another.action', function(){} ); + addAction( 'another.action', () => {} ); doAction( 'another.action' ); // Verify no action is running yet. - expect( ! doingAction( 'test.action' ) ).toBeTruthy(); + expect( doingAction( 'test.action' ) ).toBe( false ); expect( didAction( 'test.action' ) ).toBe( 0 ); - expect( ! hasAction( 'test.action' ) ).toBeTruthy(); + expect( hasAction( 'test.action' ) ).toBe( false ); - addAction( 'test.action', action_a ); + addAction( 'test.action', () => { + actionCalls++; + expect( doingAction( 'test.action' ) ).toBe( true ); + } ); // Verify action added, not running yet. - expect( ! doingAction( 'test.action' ) ).toBeTruthy(); + expect( doingAction( 'test.action' ) ).toBe( false ); expect( didAction( 'test.action' ) ).toBe( 0 ); - expect( hasAction( 'test.action' ) ).toBeTruthy(); + expect( hasAction( 'test.action' ) ).toBe( true ); doAction( 'test.action' ); // Verify action added and running. - expect( doingAction( 'test.action' ) ).toBeTruthy(); + expect( actionCalls ).toBe( 1 ); + expect( doingAction( 'test.action' ) ).toBe( false ); expect( didAction( 'test.action' ) ).toBe( 1 ); - expect( hasAction( 'test.action' ) ).toBeTruthy(); + expect( hasAction( 'test.action' ) ).toBe( true ); doAction( 'test.action' ); + expect( actionCalls ).toBe( 2 ); expect( didAction( 'test.action' ) ).toBe( 2 ); removeAction( 'test.action' ); // Verify state is reset appropriately. - expect( doingAction( 'test.action' ) ).toBeTruthy(); + expect( doingAction( 'test.action' ) ).toBe( false ); expect( didAction( 'test.action' ) ).toBe( 0 ); - expect( ! hasAction( 'test.action' ) ).toBeTruthy(); + expect( hasAction( 'test.action' ) ).toBe( false ); doAction( 'another.action' ); - expect( ! doingAction( 'test.action' ) ).toBeTruthy(); + expect( doingAction( 'test.action' ) ).toBe( false ); // Verify hasAction returns false when no matching action. - expect( ! hasAction( 'notatest.action' ) ).toBeTruthy(); + expect( hasAction( 'notatest.action' ) ).toBe( false ); } ); } ); From 1901b435371fa9020c7b8a83f1b596a4d1310ef1 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 16:54:24 +0200 Subject: [PATCH 13/91] Use a consistent order for functions --- packages/hooks/src/index.js | 42 +++++++++++++-------------- packages/hooks/src/test/index.test.js | 18 ++++++------ 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index 18e94a5..3b71ace 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -1,42 +1,40 @@ import HOOKS from './hooks'; import createAddHook from './createAddHook'; import createRemoveHook from './createRemoveHook'; +import createRemoveAllHook from './createRemoveAllHook'; +import createHasHook from './createHasHook'; import createRunHook from './createRunHook'; import createCurrentHook from './createCurrentHook'; import createDoingHook from './createDoingHook'; import createDidHook from './createDidHook'; -import createHasHook from './createHasHook'; -import createRemoveAllHook from './createRemoveAllHook'; - -// Remove functions. -export const removeFilter = createRemoveHook( HOOKS.filters ); -export const removeAction = createRemoveHook( HOOKS.actions ); - -// Do action/apply filter functions. -export const doAction = createRunHook( HOOKS.actions ); -export const applyFilters = createRunHook( HOOKS.filters, true ); - -// Add functions. +// Add action/filter functions. export const addAction = createAddHook( HOOKS.actions ); export const addFilter = createAddHook( HOOKS.filters ); -// Doing action/filter: true while a hook is being run. -export const doingAction = createDoingHook( HOOKS.actions ); -export const doingFilter = createDoingHook( HOOKS.filters ); - -// Did functions. -export const didAction = createDidHook( HOOKS.actions ); -export const didFilter = createDidHook( HOOKS.filters ); +// Remove action/filter functions. +export const removeAction = createRemoveHook( HOOKS.actions ); +export const removeFilter = createRemoveHook( HOOKS.filters ); -// Has functions. +// Has action/filter functions. export const hasAction = createHasHook( HOOKS.actions ); export const hasFilter = createHasHook( HOOKS.filters ); -// Remove all functions. +// Remove all actions/filters functions. export const removeAllActions = createRemoveAllHook( HOOKS.actions ); export const removeAllFilters = createRemoveAllHook( HOOKS.filters ); -// Current filter. +// Do action/apply filters functions. +export const doAction = createRunHook( HOOKS.actions ); +export const applyFilters = createRunHook( HOOKS.filters, true ); + +// Current action/filter functions. export const currentFilter = createCurrentHook( HOOKS.filters ); +// Doing action/filter: true while a hook is being run. +export const doingAction = createDoingHook( HOOKS.actions ); +export const doingFilter = createDoingHook( HOOKS.filters ); + +// Did action/filter functions. +export const didAction = createDidHook( HOOKS.actions ); +export const didFilter = createDidHook( HOOKS.filters ); diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 40266b7..6650977 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -2,21 +2,21 @@ * Internal Dependencies. */ import { - doAction, - applyFilters, addAction, addFilter, + removeAction, + removeFilter, + removeAllActions, + removeAllFilters, + hasAction, + hasFilter, + doAction, + applyFilters, + currentFilter, doingAction, doingFilter, didAction, didFilter, - hasAction, - hasFilter, - removeFilter, - removeAction, - removeAllActions, - removeAllFilters, - currentFilter } from '../'; function filter_a( str ) { From f6c2b45765968ab93bc134369fcb1183fe5afe76 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 17:00:40 +0200 Subject: [PATCH 14/91] Fix `currentFilter` and unit-test it --- packages/hooks/src/createCurrentHook.js | 32 ------------------------- packages/hooks/src/index.js | 3 +-- packages/hooks/src/test/index.test.js | 26 +++++++++++++------- 3 files changed, 19 insertions(+), 42 deletions(-) delete mode 100644 packages/hooks/src/createCurrentHook.js diff --git a/packages/hooks/src/createCurrentHook.js b/packages/hooks/src/createCurrentHook.js deleted file mode 100644 index 351808a..0000000 --- a/packages/hooks/src/createCurrentHook.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * See what action is currently being executed. - * - * @param {string} hooksArray Hooks array of hooks to check. - * @param {string} action The name of the action to check for. - * - * @return {Function} A function that gets the currently executing filter, - */ -const createCurrentHook = function( hooksArray ) { - - /** - * Get the current active hook. - * - * @param {string} action The name of the action to check for, if omitted will check for any action being performed. - * - * @return {string} Returns the currently executing action, or false if none. - */ - return function() { - - // If the action was not passed, check for any current hook. - if ( 'undefined' === typeof action ) { - return false; - } - - // Return the current hook. - return hooksArray && hooksArray.current ? - hooksArray.current : - false; - }; -} - -export default createCurrentHook; diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index 3b71ace..af4870e 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -4,7 +4,6 @@ import createRemoveHook from './createRemoveHook'; import createRemoveAllHook from './createRemoveAllHook'; import createHasHook from './createHasHook'; import createRunHook from './createRunHook'; -import createCurrentHook from './createCurrentHook'; import createDoingHook from './createDoingHook'; import createDidHook from './createDidHook'; @@ -29,7 +28,7 @@ export const doAction = createRunHook( HOOKS.actions ); export const applyFilters = createRunHook( HOOKS.filters, true ); // Current action/filter functions. -export const currentFilter = createCurrentHook( HOOKS.filters ); +export const currentFilter = () => HOOKS.filters.current || null; // Doing action/filter: true while a hook is being run. export const doingAction = createDoingHook( HOOKS.actions ); diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 6650977..33a36f2 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -37,9 +37,6 @@ function action_b() { function action_c() { window.actionValue += 'c'; } -function filter_check() { - expect( doingFilter( 'runtest.filter' ) ).toBeTruthy(); -} window.actionValue = ''; describe( 'add and remove a filter', () => { @@ -259,13 +256,26 @@ describe( 'Test doingAction, didAction and hasAction.', function() { describe( 'Verify doingFilter, didFilter and hasFilter.', function() { it( 'should', () => { - addFilter( 'runtest.filter', filter_check ); + let filterCalls = 0; + + addFilter( 'runtest.filter', arg => { + filterCalls++; + expect( currentFilter() ).toBe( 'runtest.filter' ); + expect( doingFilter( 'runtest.filter' ) ).toBeTruthy(); + return arg; + } ); // Verify filter added and running. - var test = applyFilters( 'runtest.filter', true ); - expect( didFilter( 'runtest.filter' ), 1, 'The runtest.filter has run once.' ); - expect( hasFilter( 'runtest.filter' ), 'The runtest.filter is registered.' ); - expect( ! hasFilter( 'notatest.filter' ), 'The notatest.filter is not registered.' ); + const test = applyFilters( 'runtest.filter', 'someValue' ); + expect( test ).toBe( 'someValue' ); + expect( filterCalls ).toBe( 1 ); + expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); + expect( hasFilter( 'runtest.filter' ) ).toBe( true ); + expect( hasFilter( 'notatest.filter' ) ).toBe( false ); + expect( doingFilter() ).toBe( false ); + expect( doingFilter( 'runtest.filter' ) ).toBe( false ); + expect( doingFilter( 'notatest.filter' ) ).toBe( false ); + expect( currentFilter() ).toBe( null ); removeFilter( 'runtest.filter' ); } ); From f50aadb4a41441d68759d88e26ca62445a94c5f9 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 17:09:40 +0200 Subject: [PATCH 15/91] Add `currentAction` and unit-test it --- packages/hooks/src/index.js | 1 + packages/hooks/src/test/index.test.js | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index af4870e..c6714cc 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -28,6 +28,7 @@ export const doAction = createRunHook( HOOKS.actions ); export const applyFilters = createRunHook( HOOKS.filters, true ); // Current action/filter functions. +export const currentAction = () => HOOKS.actions.current || null; export const currentFilter = () => HOOKS.filters.current || null; // Doing action/filter: true while a hook is being run. diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 33a36f2..36e5781 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -12,6 +12,7 @@ import { hasFilter, doAction, applyFilters, + currentAction, currentFilter, doingAction, doingFilter, @@ -218,6 +219,7 @@ describe( 'Test doingAction, didAction and hasAction.', function() { addAction( 'test.action', () => { actionCalls++; + expect( currentAction() ).toBe( 'test.action' ); expect( doingAction( 'test.action' ) ).toBe( true ); } ); @@ -233,6 +235,10 @@ describe( 'Test doingAction, didAction and hasAction.', function() { expect( doingAction( 'test.action' ) ).toBe( false ); expect( didAction( 'test.action' ) ).toBe( 1 ); expect( hasAction( 'test.action' ) ).toBe( true ); + expect( doingAction() ).toBe( false ); + expect( doingAction( 'test.action' ) ).toBe( false ); + expect( doingAction( 'notatest.action' ) ).toBe( false ); + expect( currentAction() ).toBe( null ); doAction( 'test.action' ); expect( actionCalls ).toBe( 2 ); From bee29d7df6c7708bb6444b93becf1be86fd54f23 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 17:09:50 +0200 Subject: [PATCH 16/91] Declare base hooks objects as objects, not arrays --- packages/hooks/src/hooks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hooks/src/hooks.js b/packages/hooks/src/hooks.js index e501794..a133b76 100644 --- a/packages/hooks/src/hooks.js +++ b/packages/hooks/src/hooks.js @@ -3,8 +3,8 @@ * array of objects with priority and callback of each registered hook. */ var HOOKS = { - actions: [], - filters: [] + actions: {}, + filters: {}, }; export default HOOKS; From b02296c847a8675c5ab7ef037584371634fe035e Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 17:30:46 +0200 Subject: [PATCH 17/91] Several fixes to hook removal behavior - Calling `removeAction` and `removeFilter` without a callback should not remove all hooks. This operation should be explicitly requested. - Calling `removeAllActions` and `removeAllFilters` should not reset `didAction` and `didFilter` counts. Also correctly reset state (clear all hooks and all hook call counts) before each test. --- packages/hooks/src/createDidHook.js | 6 +-- packages/hooks/src/createRemoveHook.js | 24 +++++++----- packages/hooks/src/hooks.js | 2 +- packages/hooks/src/index.js | 5 +-- packages/hooks/src/test/index.test.js | 52 ++++++++++++++++---------- 5 files changed, 52 insertions(+), 37 deletions(-) diff --git a/packages/hooks/src/createDidHook.js b/packages/hooks/src/createDidHook.js index a7223ae..2607a54 100644 --- a/packages/hooks/src/createDidHook.js +++ b/packages/hooks/src/createDidHook.js @@ -8,9 +8,9 @@ */ const createDidHook = function( hooksArray ) { return function( action ) { - return hooksArray && hooksArray[ action ] && hooksArray[ action ].runs ? - hooksArray[ action ].runs : - 0; + return hooksArray[ action ] && hooksArray[ action ].runs + ? hooksArray[ action ].runs + : 0; }; } diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index e0c3c0a..88eab2d 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -2,27 +2,34 @@ * Returns a function which, when invoked, will remove a specified hook. * * @param {string} hooksArray Hooks array from which hooks are to be removed. - * @param {bool} removeAll Whether to always remove all hooked callbacks. + * @param {bool} removeAll Whether to remove all hooked callbacks. * * @return {Function} Hook remover. */ -const createRemoveHook = function ( hooksArray, removeAll ) { +const createRemoveHook = function( hooksArray, removeAll ) { /** * Removes the specified hook by resetting its value. * * @param {string} hook Name of hook to remove - * @param {?Function} callback The specific callback to be removed. Optional, if - * omitted, clears all callbacks. + * @param {?Function} callback The specific callback to be removed. If + * omitted (and `removeAll` is truthy), clears + * all callbacks. */ return function( hook, callback ) { var handlers, i; - // Baily early if no hooks exist by this name + // Bail early if no hooks exist by this name if ( ! hooksArray || ! hooksArray.hasOwnProperty( hook ) ) { return; } - if ( callback && ! removeAll ) { + if ( removeAll ) { + const runs = hooksArray[ hook ].runs; + hooksArray[ hook ] = []; + if ( runs ) { + hooksArray[ hook ].runs = runs; + } + } else if ( callback ) { // Try to find specified callback to remove handlers = hooksArray[ hook ]; for ( i = handlers.length - 1; i >= 0; i-- ) { @@ -30,11 +37,8 @@ const createRemoveHook = function ( hooksArray, removeAll ) { handlers.splice( i, 1 ); } } - } else { - // Reset hooks to empty - delete hooksArray[ hook ]; } }; } -export default createRemoveHook; \ No newline at end of file +export default createRemoveHook; diff --git a/packages/hooks/src/hooks.js b/packages/hooks/src/hooks.js index a133b76..2fa576f 100644 --- a/packages/hooks/src/hooks.js +++ b/packages/hooks/src/hooks.js @@ -2,7 +2,7 @@ * Contains the registered hooks, keyed by hook type. Each hook type is an * array of objects with priority and callback of each registered hook. */ -var HOOKS = { +const HOOKS = { actions: {}, filters: {}, }; diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index c6714cc..992930e 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -1,7 +1,6 @@ import HOOKS from './hooks'; import createAddHook from './createAddHook'; import createRemoveHook from './createRemoveHook'; -import createRemoveAllHook from './createRemoveAllHook'; import createHasHook from './createHasHook'; import createRunHook from './createRunHook'; import createDoingHook from './createDoingHook'; @@ -20,8 +19,8 @@ export const hasAction = createHasHook( HOOKS.actions ); export const hasFilter = createHasHook( HOOKS.filters ); // Remove all actions/filters functions. -export const removeAllActions = createRemoveAllHook( HOOKS.actions ); -export const removeAllFilters = createRemoveAllHook( HOOKS.filters ); +export const removeAllActions = createRemoveHook( HOOKS.actions, true ); +export const removeAllFilters = createRemoveHook( HOOKS.filters, true ); // Do action/apply filters functions. export const doAction = createRunHook( HOOKS.actions ); diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 36e5781..0737027 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -1,6 +1,7 @@ /** - * Internal Dependencies. + * Internal dependencies */ +import HOOKS from '../hooks'; import { addAction, addFilter, @@ -38,12 +39,23 @@ function action_b() { function action_c() { window.actionValue += 'c'; } -window.actionValue = ''; + +beforeEach( () => { + window.actionValue = ''; + // Reset state in between tests (clear all callbacks, `didAction` counts, + // etc.) Just reseting HOOKS.actions and HOOKS.filters is not enough + // because the internal functions have references to the original objects. + [ HOOKS.actions, HOOKS.filters ].forEach( hooks => { + for ( const k in hooks ) { + delete hooks[ k ]; + } + } ); +} ); describe( 'add and remove a filter', () => { it( 'should leave the value unfiltered', () => { addFilter( 'test.filter', filter_a ); - removeFilter( 'test.filter' ); + removeAllFilters( 'test.filter' ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); } ); } ); @@ -52,7 +64,7 @@ describe( 'add a filter and run it', () => { it( 'should filter the value', () => { addFilter( 'test.filter', filter_a ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testa' ); - removeFilter( 'test.filter' ); + removeAllFilters( 'test.filter' ); } ); } ); @@ -61,7 +73,7 @@ describe( 'add 2 filters in a row and run them', () => { addFilter( 'test.filter', filter_a ); addFilter( 'test.filter', filter_b ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); - removeFilter( 'test.filter' ); + removeAllFilters( 'test.filter' ); } ); } ); @@ -71,7 +83,7 @@ describe( 'add 3 filters with different priorities and run them', () => { addFilter( 'test.filter', filter_b, 2 ); addFilter( 'test.filter', filter_c, 8 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testbca' ); - removeFilter( 'test.filter' ); + removeAllFilters( 'test.filter' ); } ); } ); @@ -79,7 +91,7 @@ describe( 'add and remove an action', () => { it( 'should leave the action unhooked', () => { window.actionValue = ''; addAction( 'test.action', action_a ); - removeAction( 'test.action' ); + removeAllActions( 'test.action' ); doAction( 'test.action' ); expect( window.actionValue ).toBe( '' ); } ); @@ -91,7 +103,7 @@ describe( 'add an action and run it', function() { addAction( 'test.action', action_a ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'a' ); - removeAction( 'test.action' ); + removeAllActions( 'test.action' ); } ); } ); @@ -102,7 +114,7 @@ describe( 'add 2 actions in a row and then run them', function() { addAction( 'test.action', action_b ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'ab' ); - removeAction( 'test.action' ); + removeAllActions( 'test.action' ); } ); } ); @@ -114,7 +126,7 @@ describe( 'add 3 actions with different priorities and run them', function() { addAction( 'test.action', action_c, 8 ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'bca' ); - removeAction( 'test.action' ); + removeAllActions( 'test.action' ); } ); } ); @@ -128,7 +140,7 @@ describe( 'pass in two arguments to an action', function() { expect( arg2 ).toBe( b ); } ); doAction( 'test.action', arg1, arg2 ); - removeAction( 'test.action' ); + removeAllActions( 'test.action' ); expect( arg1 ).toBe( 10 ); expect( arg2 ).toBe( 20 ); @@ -147,7 +159,7 @@ describe( 'fire action multiple times', function() { addAction( 'test.action', func ); doAction( 'test.action' ); doAction( 'test.action' ); - removeAction( 'test.action' ); + removeAllActions( 'test.action' ); } ); } ); @@ -161,7 +173,7 @@ describe( 'remove specific action callback', function() { removeAction( 'test.action', action_b ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'ca' ); - removeAction( 'test.action' ); + removeAllActions( 'test.action' ); } ); } ); @@ -186,7 +198,7 @@ describe( 'remove specific filter callback', function() { removeFilter( 'test.filter', filter_b ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); - removeFilter( 'test.filter' ); + removeAllFilters( 'test.filter' ); } ); } ); @@ -206,8 +218,6 @@ describe( 'Test doingAction, didAction and hasAction.', function() { it( 'should', () => { let actionCalls = 0; - // Reset state for testing. - removeAction( 'test.action' ); addAction( 'another.action', () => {} ); doAction( 'another.action' ); @@ -244,11 +254,11 @@ describe( 'Test doingAction, didAction and hasAction.', function() { expect( actionCalls ).toBe( 2 ); expect( didAction( 'test.action' ) ).toBe( 2 ); - removeAction( 'test.action' ); + removeAllActions( 'test.action' ); // Verify state is reset appropriately. expect( doingAction( 'test.action' ) ).toBe( false ); - expect( didAction( 'test.action' ) ).toBe( 0 ); + expect( didAction( 'test.action' ) ).toBe( 2 ); expect( hasAction( 'test.action' ) ).toBe( false ); doAction( 'another.action' ); @@ -256,7 +266,6 @@ describe( 'Test doingAction, didAction and hasAction.', function() { // Verify hasAction returns false when no matching action. expect( hasAction( 'notatest.action' ) ).toBe( false ); - } ); } ); @@ -283,7 +292,10 @@ describe( 'Verify doingFilter, didFilter and hasFilter.', function() { expect( doingFilter( 'notatest.filter' ) ).toBe( false ); expect( currentFilter() ).toBe( null ); - removeFilter( 'runtest.filter' ); + removeAllFilters( 'runtest.filter' ); + + expect( hasFilter( 'runtest.filter' ) ).toBe( false ); + expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); } ); } ); From aeca7dfe1ffa530ca060ff7608c1a22ee1c0bb61 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 17:33:24 +0200 Subject: [PATCH 18/91] Fix `hasAction` and `hasFilter` if all hooks have been removed --- packages/hooks/src/createHasHook.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/hooks/src/createHasHook.js b/packages/hooks/src/createHasHook.js index 6419cb5..0811847 100644 --- a/packages/hooks/src/createHasHook.js +++ b/packages/hooks/src/createHasHook.js @@ -8,9 +8,9 @@ */ const createHasHook = function( hooksArray ) { return function( action ) { - return hooksArray && hooksArray[ action ] ? - !! hooksArray[ action ] : - false; + return hooksArray && hooksArray[ action ] + ? hooksArray[ action ].length > 0 + : false; }; } From 678f79037b940770b6fca3845529e5adbb62d412 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 17:42:43 +0200 Subject: [PATCH 19/91] Remove now-unused `createRemoveAllHook` --- packages/hooks/src/createRemoveAllHook.js | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 packages/hooks/src/createRemoveAllHook.js diff --git a/packages/hooks/src/createRemoveAllHook.js b/packages/hooks/src/createRemoveAllHook.js deleted file mode 100644 index b4bfd9c..0000000 --- a/packages/hooks/src/createRemoveAllHook.js +++ /dev/null @@ -1,14 +0,0 @@ -import createRemoveHook from './createRemoveHook'; - -/** - * Remove all the actions registered to a hook. - * - * @param {string} hooksArray Hooks array of hooks to check. - * - * @return {Function} All hook remover. - */ -const createRemoveAllHook = function( hooksArray ) { - return createRemoveHook( hooksArray, true ); -} - -export default createRemoveAllHook; From 78acfe185aae0dc467ac106ca9a6cc748914bfa4 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 18:06:55 +0200 Subject: [PATCH 20/91] Naming and documentation cleanup - `hooks`: A hooks object, keyed by hook name - `hookName`: A hook name - `handlers`: The handlers for a single hook - All top-level and inner (returned) functions have names. --- packages/hooks/src/createAddHook.js | 37 +++++++++++++------------- packages/hooks/src/createDidHook.js | 23 ++++++++++------ packages/hooks/src/createDoingHook.js | 34 ++++++++++++++--------- packages/hooks/src/createHasHook.js | 25 +++++++++++------ packages/hooks/src/createRemoveHook.js | 34 +++++++++++------------ packages/hooks/src/createRunHook.js | 25 ++++++++--------- packages/hooks/src/sortHooks.js | 23 +++++++++------- packages/hooks/src/test/index.test.js | 4 ++- 8 files changed, 118 insertions(+), 87 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 2d48450..2672b59 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -3,20 +3,20 @@ import sortHooks from './sortHooks'; /** * Returns a function which, when invoked, will add a hook. * - * @param {string} hooksArray Hooks array to which hooks are to be added - * @return {Function} Hook added. + * @param {Object} hooks Stored hooks, keyed by hook name. + * + * @return {Function} Function that adds a new hook. */ -const createAddHook = function( hooksArray ) { +function createAddHook( hooks ) { /** - * Adds the hook to the appropriate hooks container + * Adds the hook to the appropriate hooks container. * - * @param {string} hook Name of hook to add + * @param {string} hookName Name of hook to add * @param {Function} callback Function to call when the hook is run * @param {?number} priority Priority of this hook (default=10) */ - return function( hook, callback, priority ) { - var hookObject, hooks; - if ( typeof hook !== 'string' || typeof callback !== 'function' ) { + return function addHook( hookName, callback, priority ) { + if ( typeof hookName !== 'string' || typeof callback !== 'function' ) { return; } @@ -32,22 +32,23 @@ const createAddHook = function( hooksArray ) { return; } - hookObject = { + const handler = { callback: callback, - priority: priority + priority: priority, }; + let handlers; - if ( hooksArray.hasOwnProperty( hook ) ) { - // Append and re-sort amongst existing - hooks = hooksArray[ hook ]; - hooks.push( hookObject ); - hooks = sortHooks( hooks ); + if ( hooks.hasOwnProperty( hookName ) ) { + // Append and re-sort amongst the existing callbacks. + handlers = hooks[ hookName ]; + handlers.push( handler ); + handlers = sortHooks( handlers ); } else { - // First of its type needs no sort - hooks = [ hookObject ]; + // This is the first hook of its type. + handlers = [ handler ]; } - hooksArray[ hook ] = hooks; + hooks[ hookName ] = handlers; }; } diff --git a/packages/hooks/src/createDidHook.js b/packages/hooks/src/createDidHook.js index 2607a54..cdbcee8 100644 --- a/packages/hooks/src/createDidHook.js +++ b/packages/hooks/src/createDidHook.js @@ -1,15 +1,22 @@ /** - * Retrieve the number of times an action is fired. + * Returns a function which, when invoked, will return the number of times a + * hook has been called. * - * @param {string} hooksArray Hooks array of hooks to check. - * @param {string} action The action to check. + * @param {Object} hooks Stored hooks, keyed by hook name. * - * @return {number} The number of times the hook has run. + * @return {Function} Function that returns a hook's call count. */ -const createDidHook = function( hooksArray ) { - return function( action ) { - return hooksArray[ action ] && hooksArray[ action ].runs - ? hooksArray[ action ].runs +function createDidHook( hooks ) { + /** + * Returns the number of times an action has been fired. + * + * @param {string} hookName The hook name to check. + * + * @return {number} The number of times the hook has run. + */ + return function didHook( hookName ) { + return hooks.hasOwnProperty( hookName ) && hooks[ hookName ].runs + ? hooks[ hookName ].runs : 0; }; } diff --git a/packages/hooks/src/createDoingHook.js b/packages/hooks/src/createDoingHook.js index 95932c1..ba7aa02 100644 --- a/packages/hooks/src/createDoingHook.js +++ b/packages/hooks/src/createDoingHook.js @@ -1,23 +1,31 @@ /** - * Checks to see if an action is currently being executed. + * Returns a function which, when invoked, will return whether a hook is + * currently being executed. * - * @param {string} type Type of hooks to check. - * @param {string} action The name of the action to check for, if omitted will check for any action being performed. + * @param {Object} hooks Stored hooks, keyed by hook name. * - * @return {bool} Whether the hook is being executed. + * @return {Function} Function that returns whether a hook is currently + * being executed. */ -const createDoingHook = function( hooksArray ) { - return function( action ) { - - // If the action was not passed, check for any current hook. - if ( 'undefined' === typeof action ) { - return 'undefined' !== typeof hooksArray.current; +function createDoingHook( hooks ) { + /** + * Returns whether a hook is currently being executed. + * + * @param {?string} hookName The name of the hook to check for. If + * omitted, will check for any hook being executed. + * + * @return {bool} Whether the hook is being executed. + */ + return function doingHook( hookName ) { + // If the hookName was not passed, check for any current hook. + if ( 'undefined' === typeof hookName ) { + return 'undefined' !== typeof hooks.current; } // Return the current hook. - return hooksArray && hooksArray.current ? - action === hooksArray.current : - false; + return hooks.current + ? hookName === hooks.current + : false; }; } diff --git a/packages/hooks/src/createHasHook.js b/packages/hooks/src/createHasHook.js index 0811847..4b3567e 100644 --- a/packages/hooks/src/createHasHook.js +++ b/packages/hooks/src/createHasHook.js @@ -1,15 +1,24 @@ /** - * Check to see if an action is registered for a hook. + * Returns a function which, when invoked, will return whether any handlers are + * attached to a particular hook. * - * @param {string} hooksArray Hooks array of hooks to check. - * @param {string} action The action to check. + * @param {Object} hooks Stored hooks, keyed by hook name. * - * @return {bool} Whether an action has been registered for a hook. + * @return {Function} Function that returns whether any handlers are + * attached to a particular hook. */ -const createHasHook = function( hooksArray ) { - return function( action ) { - return hooksArray && hooksArray[ action ] - ? hooksArray[ action ].length > 0 +function createHasHook( hooks ) { + /** + * Returns how many handlers are attached for the given hook. + * + * @param {string} hookName The name of the hook to check for. + * + * @return {bool} Whether any handlers are attached to the + * given hook. + */ + return function hasHook( hookName ) { + return hooks && hooks.hasOwnProperty( hookName ) + ? hooks[ hookName ].length > 0 : false; }; } diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index 88eab2d..ab6e3ce 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -1,38 +1,38 @@ /** - * Returns a function which, when invoked, will remove a specified hook. + * Returns a function which, when invoked, will remove a specified hook or all + * hooks by the given name. * - * @param {string} hooksArray Hooks array from which hooks are to be removed. + * @param {Object} hooks Stored hooks, keyed by hook name. * @param {bool} removeAll Whether to remove all hooked callbacks. * - * @return {Function} Hook remover. + * @return {Function} Function that removes hooks. */ -const createRemoveHook = function( hooksArray, removeAll ) { +const createRemoveHook = function( hooks, removeAll ) { /** - * Removes the specified hook by resetting its value. + * Removes the specified callback (or all callbacks) from the hook with a + * given name. * - * @param {string} hook Name of hook to remove + * @param {string} hookName The name of the hook to modify. * @param {?Function} callback The specific callback to be removed. If * omitted (and `removeAll` is truthy), clears * all callbacks. */ - return function( hook, callback ) { - var handlers, i; - - // Bail early if no hooks exist by this name - if ( ! hooksArray || ! hooksArray.hasOwnProperty( hook ) ) { + return function removeHook( hookName, callback ) { + // Bail if no hooks exist by this name + if ( ! hooks.hasOwnProperty( hookName ) ) { return; } if ( removeAll ) { - const runs = hooksArray[ hook ].runs; - hooksArray[ hook ] = []; + const runs = hooks[ hookName ].runs; + hooks[ hookName ] = []; if ( runs ) { - hooksArray[ hook ].runs = runs; + hooks[ hookName ].runs = runs; } } else if ( callback ) { - // Try to find specified callback to remove - handlers = hooksArray[ hook ]; - for ( i = handlers.length - 1; i >= 0; i-- ) { + // Try to find the specified callback to remove. + const handlers = hooks[ hookName ]; + for ( let i = handlers.length - 1; i >= 0; i-- ) { if ( handlers[ i ].callback === callback ) { handlers.splice( i, 1 ); } diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index af248e9..ca07b64 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -1,23 +1,24 @@ /** - * Returns a function which, when invoked, will execute all registered - * hooks of the specified type by calling upon runner with its hook name - * and arguments. + * 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 {Function} hooks Object that contains the hooks to run. - * @param {bool} returnFirstArg Whether each hook callback is expected to + * @param {Object} hooks Stored hooks, keyed by hook name. + * @param {?bool} returnFirstArg Whether each hook callback is expected to * return its first argument. - * @return {Function} Hook runner + * + * @return {Function} Function that runs hook callbacks. */ const createRunHook = function( hooks, returnFirstArg ) { /** - * Runs the specified hook. + * Runs all callbacks for the specified hook. + * + * @param {string} hookName The name of the hook to run. + * @param {...*} args Arguments to pass to the hook callbacks. * - * @param {string} hookName The hook to run - * @param {...*} args Arguments to pass to the hook callbacks - * @return {*} Return value of runner, if applicable - * @private + * @return {*} Return value of runner, if applicable. */ - return function runner( hookName, ...args ) { + return function runHooks( hookName, ...args ) { const handlers = hooks[ hookName ]; let maybeReturnValue = args[ 0 ]; diff --git a/packages/hooks/src/sortHooks.js b/packages/hooks/src/sortHooks.js index 1b1b16b..8e6ed00 100644 --- a/packages/hooks/src/sortHooks.js +++ b/packages/hooks/src/sortHooks.js @@ -1,25 +1,28 @@ /** - * Use an insert sort for keeping our hooks organized based on priority. + * Use an insert sort to keep hook handlers organized based on priority. * * @see http://jsperf.com/javascript-sort * - * @param {Array} hooks Array of the hooks to sort - * @return {Array} The sorted array + * @param {Array} handlers Array of the handlers to sort + * @return {Array} The sorted array * @private */ -const sortHooks = function( hooks ) { +const sortHooks = function( handlers ) { var i, tmpHook, j, prevHook; - for ( i = 1; i < hooks.length; i++ ) { - tmpHook = hooks[ i ]; + for ( i = 1; i < handlers.length; i++ ) { + tmpHook = handlers[ i ]; j = i; - while ( ( prevHook = hooks[ j - 1 ] ) && prevHook.priority > tmpHook.priority ) { - hooks[ j ] = hooks[ j - 1 ]; + while ( + ( prevHook = handlers[ j - 1 ] ) && + prevHook.priority > tmpHook.priority + ) { + handlers[ j ] = handlers[ j - 1 ]; --j; } - hooks[ j ] = tmpHook; + handlers[ j ] = tmpHook; } - return hooks; + return handlers; } export default sortHooks; diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 0737027..7fbe4d6 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -230,6 +230,7 @@ describe( 'Test doingAction, didAction and hasAction.', function() { addAction( 'test.action', () => { actionCalls++; expect( currentAction() ).toBe( 'test.action' ); + expect( doingAction() ).toBe( true ); expect( doingAction( 'test.action' ) ).toBe( true ); } ); @@ -276,7 +277,8 @@ describe( 'Verify doingFilter, didFilter and hasFilter.', function() { addFilter( 'runtest.filter', arg => { filterCalls++; expect( currentFilter() ).toBe( 'runtest.filter' ); - expect( doingFilter( 'runtest.filter' ) ).toBeTruthy(); + expect( doingFilter() ).toBe( true ); + expect( doingFilter( 'runtest.filter' ) ).toBe( true ); return arg; } ); From 637af4d4fc28252fa0fc56c1583ac7e8de908f5c Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 18:10:43 +0200 Subject: [PATCH 21/91] Make `hasAction` and `hasFilter` return the number of registered hooks This is different than PHP, because the existing PHP API that these functions accept a callback and return its priority won't work well in JavaScript. Instead, when we implement namespaced hooks, these functions should work the same way: return the number of handlers registered under the given hook and namespace. --- packages/hooks/src/createHasHook.js | 10 +++++----- packages/hooks/src/test/index.test.js | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/hooks/src/createHasHook.js b/packages/hooks/src/createHasHook.js index 4b3567e..6d9cd10 100644 --- a/packages/hooks/src/createHasHook.js +++ b/packages/hooks/src/createHasHook.js @@ -13,13 +13,13 @@ function createHasHook( hooks ) { * * @param {string} hookName The name of the hook to check for. * - * @return {bool} Whether any handlers are attached to the - * given hook. + * @return {number} The number of handlers that are attached to + * the given hook. */ return function hasHook( hookName ) { - return hooks && hooks.hasOwnProperty( hookName ) - ? hooks[ hookName ].length > 0 - : false; + return hooks.hasOwnProperty( hookName ) + ? hooks[ hookName ].length + : 0; }; } diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 7fbe4d6..c5ae0a9 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -225,7 +225,7 @@ describe( 'Test doingAction, didAction and hasAction.', function() { expect( doingAction( 'test.action' ) ).toBe( false ); expect( didAction( 'test.action' ) ).toBe( 0 ); - expect( hasAction( 'test.action' ) ).toBe( false ); + expect( hasAction( 'test.action' ) ).toBe( 0 ); addAction( 'test.action', () => { actionCalls++; @@ -237,7 +237,7 @@ describe( 'Test doingAction, didAction and hasAction.', function() { // Verify action added, not running yet. expect( doingAction( 'test.action' ) ).toBe( false ); expect( didAction( 'test.action' ) ).toBe( 0 ); - expect( hasAction( 'test.action' ) ).toBe( true ); + expect( hasAction( 'test.action' ) ).toBe( 1 ); doAction( 'test.action' ); @@ -245,7 +245,7 @@ describe( 'Test doingAction, didAction and hasAction.', function() { expect( actionCalls ).toBe( 1 ); expect( doingAction( 'test.action' ) ).toBe( false ); expect( didAction( 'test.action' ) ).toBe( 1 ); - expect( hasAction( 'test.action' ) ).toBe( true ); + expect( hasAction( 'test.action' ) ).toBe( 1 ); expect( doingAction() ).toBe( false ); expect( doingAction( 'test.action' ) ).toBe( false ); expect( doingAction( 'notatest.action' ) ).toBe( false ); @@ -260,13 +260,13 @@ describe( 'Test doingAction, didAction and hasAction.', function() { // Verify state is reset appropriately. expect( doingAction( 'test.action' ) ).toBe( false ); expect( didAction( 'test.action' ) ).toBe( 2 ); - expect( hasAction( 'test.action' ) ).toBe( false ); + expect( hasAction( 'test.action' ) ).toBe( 0 ); doAction( 'another.action' ); expect( doingAction( 'test.action' ) ).toBe( false ); - // Verify hasAction returns false when no matching action. - expect( hasAction( 'notatest.action' ) ).toBe( false ); + // Verify hasAction returns 0 when no matching action. + expect( hasAction( 'notatest.action' ) ).toBe( 0 ); } ); } ); @@ -287,8 +287,8 @@ describe( 'Verify doingFilter, didFilter and hasFilter.', function() { expect( test ).toBe( 'someValue' ); expect( filterCalls ).toBe( 1 ); expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); - expect( hasFilter( 'runtest.filter' ) ).toBe( true ); - expect( hasFilter( 'notatest.filter' ) ).toBe( false ); + expect( hasFilter( 'runtest.filter' ) ).toBe( 1 ); + expect( hasFilter( 'notatest.filter' ) ).toBe( 0 ); expect( doingFilter() ).toBe( false ); expect( doingFilter( 'runtest.filter' ) ).toBe( false ); expect( doingFilter( 'notatest.filter' ) ).toBe( false ); @@ -296,7 +296,7 @@ describe( 'Verify doingFilter, didFilter and hasFilter.', function() { removeAllFilters( 'runtest.filter' ); - expect( hasFilter( 'runtest.filter' ) ).toBe( false ); + expect( hasFilter( 'runtest.filter' ) ).toBe( 0 ); expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); } ); } ); From b7b30f4a01388be6fe45c2fca69f396be3847d92 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 18:15:12 +0200 Subject: [PATCH 22/91] Remove unnecessary `describe`/`it` pairs Just replace them with `test` instead, per the Jest examples. --- packages/hooks/src/test/index.test.js | 384 ++++++++++++-------------- 1 file changed, 175 insertions(+), 209 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index c5ae0a9..5d624b0 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -52,253 +52,219 @@ beforeEach( () => { } ); } ); -describe( 'add and remove a filter', () => { - it( 'should leave the value unfiltered', () => { - addFilter( 'test.filter', filter_a ); - removeAllFilters( 'test.filter' ); - expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); - } ); +test( 'add and remove a filter', () => { + addFilter( 'test.filter', filter_a ); + removeAllFilters( 'test.filter' ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); } ); -describe( 'add a filter and run it', () => { - it( 'should filter the value', () => { - addFilter( 'test.filter', filter_a ); - expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testa' ); - removeAllFilters( 'test.filter' ); - } ); +test( 'add a filter and run it', () => { + addFilter( 'test.filter', filter_a ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testa' ); + removeAllFilters( 'test.filter' ); } ); -describe( 'add 2 filters in a row and run them', () => { - it( 'both filters should apply', () => { - addFilter( 'test.filter', filter_a ); - addFilter( 'test.filter', filter_b ); - expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); - removeAllFilters( 'test.filter' ); - } ); +test( 'add 2 filters in a row and run them', () => { + addFilter( 'test.filter', filter_a ); + addFilter( 'test.filter', filter_b ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); + removeAllFilters( 'test.filter' ); } ); -describe( 'add 3 filters with different priorities and run them', () => { - it( 'should run in order', () => { - addFilter( 'test.filter', filter_a ); - addFilter( 'test.filter', filter_b, 2 ); - addFilter( 'test.filter', filter_c, 8 ); - expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testbca' ); - removeAllFilters( 'test.filter' ); - } ); +test( 'add 3 filters with different priorities and run them', () => { + addFilter( 'test.filter', filter_a ); + addFilter( 'test.filter', filter_b, 2 ); + addFilter( 'test.filter', filter_c, 8 ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testbca' ); + removeAllFilters( 'test.filter' ); } ); -describe( 'add and remove an action', () => { - it( 'should leave the action unhooked', () => { - window.actionValue = ''; - addAction( 'test.action', action_a ); - removeAllActions( 'test.action' ); - doAction( 'test.action' ); - expect( window.actionValue ).toBe( '' ); - } ); +test( 'add and remove an action', () => { + window.actionValue = ''; + addAction( 'test.action', action_a ); + removeAllActions( 'test.action' ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( '' ); } ); -describe( 'add an action and run it', function() { - it( 'should', () => { - window.actionValue = ''; - addAction( 'test.action', action_a ); - doAction( 'test.action' ); - expect( window.actionValue ).toBe( 'a' ); - removeAllActions( 'test.action' ); - } ); +test( 'add an action and run it', function() { + window.actionValue = ''; + addAction( 'test.action', action_a ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( 'a' ); + removeAllActions( 'test.action' ); } ); -describe( 'add 2 actions in a row and then run them', function() { - it( 'should', () => { - window.actionValue = ''; - addAction( 'test.action', action_a ); - addAction( 'test.action', action_b ); - doAction( 'test.action' ); - expect( window.actionValue ).toBe( 'ab' ); - removeAllActions( 'test.action' ); - } ); +test( 'add 2 actions in a row and then run them', function() { + window.actionValue = ''; + addAction( 'test.action', action_a ); + addAction( 'test.action', action_b ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( 'ab' ); + removeAllActions( 'test.action' ); } ); -describe( 'add 3 actions with different priorities and run them', function() { - it( 'should', () => { - window.actionValue = ''; - addAction( 'test.action', action_a ); - addAction( 'test.action', action_b, 2 ); - addAction( 'test.action', action_c, 8 ); - doAction( 'test.action' ); - expect( window.actionValue ).toBe( 'bca' ); - removeAllActions( 'test.action' ); - } ); +test( 'add 3 actions with different priorities and run them', function() { + window.actionValue = ''; + addAction( 'test.action', action_a ); + addAction( 'test.action', action_b, 2 ); + addAction( 'test.action', action_c, 8 ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( 'bca' ); + removeAllActions( 'test.action' ); } ); -describe( 'pass in two arguments to an action', function() { - it( 'should', () => { - var arg1 = 10, - arg2 = 20; - - addAction( 'test.action', function( a, b ) { - expect( arg1 ).toBe( a ); - expect( arg2 ).toBe( b ); - } ); - doAction( 'test.action', arg1, arg2 ); - removeAllActions( 'test.action' ); +test( 'pass in two arguments to an action', function() { + var arg1 = 10, + arg2 = 20; - expect( arg1 ).toBe( 10 ); - expect( arg2 ).toBe( 20 ); + addAction( 'test.action', function( a, b ) { + expect( arg1 ).toBe( a ); + expect( arg2 ).toBe( b ); } ); + doAction( 'test.action', arg1, arg2 ); + removeAllActions( 'test.action' ); + + expect( arg1 ).toBe( 10 ); + expect( arg2 ).toBe( 20 ); } ); -describe( 'fire action multiple times', function() { - it( 'should', () => { - var func; - expect.assertions(2); +test( 'fire action multiple times', function() { + var func; + expect.assertions(2); - func = function() { - expect( true ).toBe( true ); - }; + func = function() { + expect( true ).toBe( true ); + }; - addAction( 'test.action', func ); - doAction( 'test.action' ); - doAction( 'test.action' ); - removeAllActions( 'test.action' ); - } ); + addAction( 'test.action', func ); + doAction( 'test.action' ); + doAction( 'test.action' ); + removeAllActions( 'test.action' ); } ); -describe( 'remove specific action callback', function() { - it( 'should', () => { - window.actionValue = ''; - addAction( 'test.action', action_a ); - addAction( 'test.action', action_b, 2 ); - addAction( 'test.action', action_c, 8 ); - - removeAction( 'test.action', action_b ); - doAction( 'test.action' ); - expect( window.actionValue ).toBe( 'ca' ); - removeAllActions( 'test.action' ); - } ); +test( 'remove specific action callback', function() { + window.actionValue = ''; + addAction( 'test.action', action_a ); + addAction( 'test.action', action_b, 2 ); + addAction( 'test.action', action_c, 8 ); + + removeAction( 'test.action', action_b ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( 'ca' ); + removeAllActions( 'test.action' ); } ); -describe( 'remove all action callbacks', function() { - it( 'should', () => { - window.actionValue = ''; - addAction( 'test.action', action_a ); - addAction( 'test.action', action_b, 2 ); - addAction( 'test.action', action_c, 8 ); +test( 'remove all action callbacks', function() { + window.actionValue = ''; + addAction( 'test.action', action_a ); + addAction( 'test.action', action_b, 2 ); + addAction( 'test.action', action_c, 8 ); - removeAllActions( 'test.action' ); - doAction( 'test.action' ); - expect( window.actionValue ).toBe( '' ); - } ); + removeAllActions( 'test.action' ); + doAction( 'test.action' ); + expect( window.actionValue ).toBe( '' ); } ); -describe( 'remove specific filter callback', function() { - it( 'should', () => { - addFilter( 'test.filter', filter_a ); - addFilter( 'test.filter', filter_b, 2 ); - addFilter( 'test.filter', filter_c, 8 ); +test( 'remove specific filter callback', function() { + addFilter( 'test.filter', filter_a ); + addFilter( 'test.filter', filter_b, 2 ); + addFilter( 'test.filter', filter_c, 8 ); - removeFilter( 'test.filter', filter_b ); - expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); - removeAllFilters( 'test.filter' ); - } ); + removeFilter( 'test.filter', filter_b ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); + removeAllFilters( 'test.filter' ); } ); -describe( 'remove all filter callbacks', function() { - it( 'should', () => { - addFilter( 'test.filter', filter_a ); - addFilter( 'test.filter', filter_b, 2 ); - addFilter( 'test.filter', filter_c, 8 ); +test( 'remove all filter callbacks', function() { + addFilter( 'test.filter', filter_a ); + addFilter( 'test.filter', filter_b, 2 ); + addFilter( 'test.filter', filter_c, 8 ); - removeAllFilters( 'test.filter' ); - expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); - } ); + removeAllFilters( 'test.filter' ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); } ); // Test doingAction, didAction, hasAction. -describe( 'Test doingAction, didAction and hasAction.', function() { - it( 'should', () => { - let actionCalls = 0; - - addAction( 'another.action', () => {} ); - doAction( 'another.action' ); - - // Verify no action is running yet. - expect( doingAction( 'test.action' ) ).toBe( false ); - - expect( didAction( 'test.action' ) ).toBe( 0 ); - expect( hasAction( 'test.action' ) ).toBe( 0 ); - - addAction( 'test.action', () => { - actionCalls++; - expect( currentAction() ).toBe( 'test.action' ); - expect( doingAction() ).toBe( true ); - expect( doingAction( 'test.action' ) ).toBe( true ); - } ); - - // Verify action added, not running yet. - expect( doingAction( 'test.action' ) ).toBe( false ); - expect( didAction( 'test.action' ) ).toBe( 0 ); - expect( hasAction( 'test.action' ) ).toBe( 1 ); - - doAction( 'test.action' ); - - // Verify action added and running. - expect( actionCalls ).toBe( 1 ); - expect( doingAction( 'test.action' ) ).toBe( false ); - expect( didAction( 'test.action' ) ).toBe( 1 ); - expect( hasAction( 'test.action' ) ).toBe( 1 ); - expect( doingAction() ).toBe( false ); - expect( doingAction( 'test.action' ) ).toBe( false ); - expect( doingAction( 'notatest.action' ) ).toBe( false ); - expect( currentAction() ).toBe( null ); - - doAction( 'test.action' ); - expect( actionCalls ).toBe( 2 ); - expect( didAction( 'test.action' ) ).toBe( 2 ); - - removeAllActions( 'test.action' ); - - // Verify state is reset appropriately. - expect( doingAction( 'test.action' ) ).toBe( false ); - expect( didAction( 'test.action' ) ).toBe( 2 ); - expect( hasAction( 'test.action' ) ).toBe( 0 ); - - doAction( 'another.action' ); - expect( doingAction( 'test.action' ) ).toBe( false ); - - // Verify hasAction returns 0 when no matching action. - expect( hasAction( 'notatest.action' ) ).toBe( 0 ); - } ); -} ); +test( 'Test doingAction, didAction and hasAction.', function() { + let actionCalls = 0; + + addAction( 'another.action', () => {} ); + doAction( 'another.action' ); -describe( 'Verify doingFilter, didFilter and hasFilter.', function() { - it( 'should', () => { - let filterCalls = 0; - - addFilter( 'runtest.filter', arg => { - filterCalls++; - expect( currentFilter() ).toBe( 'runtest.filter' ); - expect( doingFilter() ).toBe( true ); - expect( doingFilter( 'runtest.filter' ) ).toBe( true ); - return arg; - } ); - - // Verify filter added and running. - const test = applyFilters( 'runtest.filter', 'someValue' ); - expect( test ).toBe( 'someValue' ); - expect( filterCalls ).toBe( 1 ); - expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); - expect( hasFilter( 'runtest.filter' ) ).toBe( 1 ); - expect( hasFilter( 'notatest.filter' ) ).toBe( 0 ); - expect( doingFilter() ).toBe( false ); - expect( doingFilter( 'runtest.filter' ) ).toBe( false ); - expect( doingFilter( 'notatest.filter' ) ).toBe( false ); - expect( currentFilter() ).toBe( null ); - - removeAllFilters( 'runtest.filter' ); - - expect( hasFilter( 'runtest.filter' ) ).toBe( 0 ); - expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); + // Verify no action is running yet. + expect( doingAction( 'test.action' ) ).toBe( false ); + + expect( didAction( 'test.action' ) ).toBe( 0 ); + expect( hasAction( 'test.action' ) ).toBe( 0 ); + + addAction( 'test.action', () => { + actionCalls++; + expect( currentAction() ).toBe( 'test.action' ); + expect( doingAction() ).toBe( true ); + expect( doingAction( 'test.action' ) ).toBe( true ); } ); + + // Verify action added, not running yet. + expect( doingAction( 'test.action' ) ).toBe( false ); + expect( didAction( 'test.action' ) ).toBe( 0 ); + expect( hasAction( 'test.action' ) ).toBe( 1 ); + + doAction( 'test.action' ); + + // Verify action added and running. + expect( actionCalls ).toBe( 1 ); + expect( doingAction( 'test.action' ) ).toBe( false ); + expect( didAction( 'test.action' ) ).toBe( 1 ); + expect( hasAction( 'test.action' ) ).toBe( 1 ); + expect( doingAction() ).toBe( false ); + expect( doingAction( 'test.action' ) ).toBe( false ); + expect( doingAction( 'notatest.action' ) ).toBe( false ); + expect( currentAction() ).toBe( null ); + + doAction( 'test.action' ); + expect( actionCalls ).toBe( 2 ); + expect( didAction( 'test.action' ) ).toBe( 2 ); + + removeAllActions( 'test.action' ); + + // Verify state is reset appropriately. + expect( doingAction( 'test.action' ) ).toBe( false ); + expect( didAction( 'test.action' ) ).toBe( 2 ); + expect( hasAction( 'test.action' ) ).toBe( 0 ); + + doAction( 'another.action' ); + expect( doingAction( 'test.action' ) ).toBe( false ); + + // Verify hasAction returns 0 when no matching action. + expect( hasAction( 'notatest.action' ) ).toBe( 0 ); } ); +test( 'Verify doingFilter, didFilter and hasFilter.', function() { + let filterCalls = 0; + + addFilter( 'runtest.filter', arg => { + filterCalls++; + expect( currentFilter() ).toBe( 'runtest.filter' ); + expect( doingFilter() ).toBe( true ); + expect( doingFilter( 'runtest.filter' ) ).toBe( true ); + return arg; + } ); + // Verify filter added and running. + const test = applyFilters( 'runtest.filter', 'someValue' ); + expect( test ).toBe( 'someValue' ); + expect( filterCalls ).toBe( 1 ); + expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); + expect( hasFilter( 'runtest.filter' ) ).toBe( 1 ); + expect( hasFilter( 'notatest.filter' ) ).toBe( 0 ); + expect( doingFilter() ).toBe( false ); + expect( doingFilter( 'runtest.filter' ) ).toBe( false ); + expect( doingFilter( 'notatest.filter' ) ).toBe( false ); + expect( currentFilter() ).toBe( null ); + + removeAllFilters( 'runtest.filter' ); + + expect( hasFilter( 'runtest.filter' ) ).toBe( 0 ); + expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); +} ); From b351db4abf1a9ad24b1fa419e6c65b5c8f79063e Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 18:53:52 +0200 Subject: [PATCH 23/91] A bit more function declaration cleanup --- packages/hooks/src/createRemoveHook.js | 2 +- packages/hooks/src/createRunHook.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index ab6e3ce..33d1bd5 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -7,7 +7,7 @@ * * @return {Function} Function that removes hooks. */ -const createRemoveHook = function( hooks, removeAll ) { +function createRemoveHook( hooks, removeAll ) { /** * Removes the specified callback (or all callbacks) from the hook with a * given name. diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index ca07b64..e9ab4eb 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -9,7 +9,7 @@ * * @return {Function} Function that runs hook callbacks. */ -const createRunHook = function( hooks, returnFirstArg ) { +function createRunHook( hooks, returnFirstArg ) { /** * Runs all callbacks for the specified hook. * From 498e15be0f9d0d2cabd4994f6bb6c741af2c6bfc Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 18:56:07 +0200 Subject: [PATCH 24/91] Use ES6 object shorthand --- packages/hooks/src/createAddHook.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 2672b59..298b112 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -32,10 +32,7 @@ function createAddHook( hooks ) { return; } - const handler = { - callback: callback, - priority: priority, - }; + const handler = { callback, priority }; let handlers; if ( hooks.hasOwnProperty( hookName ) ) { From e3392c3d65916d3379c09ba976451edcfc7d84d9 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 19:09:58 +0200 Subject: [PATCH 25/91] Add explicit error reporting --- packages/hooks/src/createAddHook.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 298b112..f172e84 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -16,7 +16,13 @@ function createAddHook( hooks ) { * @param {?number} priority Priority of this hook (default=10) */ return function addHook( hookName, callback, priority ) { - if ( typeof hookName !== 'string' || typeof callback !== 'function' ) { + if ( typeof hookName !== 'string' ) { + console.error( 'The hook name must be a string.' ); + return; + } + + if ( typeof callback !== 'function' ) { + console.error( 'The hook callback must be a function.' ); return; } @@ -29,6 +35,7 @@ function createAddHook( hooks ) { // Validate numeric priority if ( isNaN( priority ) ) { + console.error( 'The hook priority must be omitted or a number.' ); return; } From 53294fd0f0df33d13e7284382a2f09db25bc991d Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 19:16:26 +0200 Subject: [PATCH 26/91] Test adding and removing multiple filters at the same priority --- packages/hooks/src/test/index.test.js | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 5d624b0..9a76451 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -79,6 +79,55 @@ test( 'add 3 filters with different priorities and run them', () => { removeAllFilters( 'test.filter' ); } ); +test( 'filters with the same and different priorities', () => { + const callbacks = {}; + + [ 1, 2, 3, 4 ].forEach( priority => { + [ 'a', 'b', 'c', 'd' ].forEach( string => { + callbacks[ 'fn_' + priority + string ] = value => { + return value.concat( priority + string ); + }; + } ); + } ); + + addFilter( 'test_order', callbacks.fn_3a, 3 ); + addFilter( 'test_order', callbacks.fn_3b, 3 ); + addFilter( 'test_order', callbacks.fn_3c, 3 ); + addFilter( 'test_order', callbacks.fn_2a, 2 ); + addFilter( 'test_order', callbacks.fn_2b, 2 ); + addFilter( 'test_order', callbacks.fn_2c, 2 ); + + expect( applyFilters( 'test_order', [] ) ).toEqual( + [ '2a', '2b', '2c', '3a', '3b', '3c' ] + ); + + removeFilter( 'test_order', callbacks.fn_2b ); + removeFilter( 'test_order', callbacks.fn_3a ); + + expect( applyFilters( 'test_order', [] ) ).toEqual( + [ '2a', '2c', '3b', '3c' ] + ); + + addFilter( 'test_order', callbacks.fn_4a, 4 ); + addFilter( 'test_order', callbacks.fn_4b, 4 ); + addFilter( 'test_order', callbacks.fn_1a, 1 ); + addFilter( 'test_order', callbacks.fn_4c, 4 ); + addFilter( 'test_order', callbacks.fn_1b, 1 ); + addFilter( 'test_order', callbacks.fn_3d, 3 ); + addFilter( 'test_order', callbacks.fn_4d, 4 ); + addFilter( 'test_order', callbacks.fn_1c, 1 ); + addFilter( 'test_order', callbacks.fn_2d, 2 ); + addFilter( 'test_order', callbacks.fn_1d, 1 ); + + expect( applyFilters( 'test_order', [] ) ).toEqual( [ + // all except 2b and 3a, which we removed earlier + '1a', '1b', '1c', '1d', + '2a', '2c', '2d', + '3b', '3c', '3d', + '4a', '4b', '4c', '4d', + ] ); +} ); + test( 'add and remove an action', () => { window.actionValue = ''; addAction( 'test.action', action_a ); From 07b61a08ea22026cafe20f3eba0548daecfef8f6 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 19:25:46 +0200 Subject: [PATCH 27/91] Keep the hooks list always sorted instead of explicitly sorting it --- packages/hooks/src/createAddHook.js | 15 ++++++++++----- packages/hooks/src/sortHooks.js | 28 ---------------------------- 2 files changed, 10 insertions(+), 33 deletions(-) delete mode 100644 packages/hooks/src/sortHooks.js diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index f172e84..71febb8 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -1,5 +1,3 @@ -import sortHooks from './sortHooks'; - /** * Returns a function which, when invoked, will add a hook. * @@ -43,10 +41,17 @@ function createAddHook( hooks ) { let handlers; if ( hooks.hasOwnProperty( hookName ) ) { - // Append and re-sort amongst the existing callbacks. + // Find the correct insert index of the new hook. handlers = hooks[ hookName ]; - handlers.push( handler ); - handlers = sortHooks( handlers ); + let i = 0; + while ( i < handlers.length ) { + if ( handlers[ i ].priority > priority ) { + break; + } + i++; + } + // Insert (or append) the new hook. + handlers.splice( i, 0, handler ); } else { // This is the first hook of its type. handlers = [ handler ]; diff --git a/packages/hooks/src/sortHooks.js b/packages/hooks/src/sortHooks.js deleted file mode 100644 index 8e6ed00..0000000 --- a/packages/hooks/src/sortHooks.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Use an insert sort to keep hook handlers organized based on priority. - * - * @see http://jsperf.com/javascript-sort - * - * @param {Array} handlers Array of the handlers to sort - * @return {Array} The sorted array - * @private - */ -const sortHooks = function( handlers ) { - var i, tmpHook, j, prevHook; - for ( i = 1; i < handlers.length; i++ ) { - tmpHook = handlers[ i ]; - j = i; - while ( - ( prevHook = handlers[ j - 1 ] ) && - prevHook.priority > tmpHook.priority - ) { - handlers[ j ] = handlers[ j - 1 ]; - --j; - } - handlers[ j ] = tmpHook; - } - - return handlers; -} - -export default sortHooks; From ee303e6795f924f003e044893e3ce0802b45b205 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 19:29:40 +0200 Subject: [PATCH 28/91] Remove remaining `var` statements --- packages/hooks/src/test/index.test.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 9a76451..06c9ee4 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -164,25 +164,21 @@ test( 'add 3 actions with different priorities and run them', function() { } ); test( 'pass in two arguments to an action', function() { - var arg1 = 10, - arg2 = 20; + const arg1 = { a: 10 }; + const arg2 = { b: 20 }; addAction( 'test.action', function( a, b ) { - expect( arg1 ).toBe( a ); - expect( arg2 ).toBe( b ); + expect( a ).toBe( arg1 ); + expect( b ).toBe( arg2 ); } ); doAction( 'test.action', arg1, arg2 ); removeAllActions( 'test.action' ); - - expect( arg1 ).toBe( 10 ); - expect( arg2 ).toBe( 20 ); } ); test( 'fire action multiple times', function() { - var func; - expect.assertions(2); + expect.assertions( 2 ); - func = function() { + function func() { expect( true ).toBe( true ); }; From b1251e33baad0900552cf1aef34b20ac6c375fa9 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 19:31:29 +0200 Subject: [PATCH 29/91] Remove remaining per-test cleanup logic This is all handled in `beforeEach` now. --- packages/hooks/src/test/index.test.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 06c9ee4..c2f2d60 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -61,14 +61,12 @@ test( 'add and remove a filter', () => { test( 'add a filter and run it', () => { addFilter( 'test.filter', filter_a ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testa' ); - removeAllFilters( 'test.filter' ); } ); test( 'add 2 filters in a row and run them', () => { addFilter( 'test.filter', filter_a ); addFilter( 'test.filter', filter_b ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); - removeAllFilters( 'test.filter' ); } ); test( 'add 3 filters with different priorities and run them', () => { @@ -76,7 +74,6 @@ test( 'add 3 filters with different priorities and run them', () => { addFilter( 'test.filter', filter_b, 2 ); addFilter( 'test.filter', filter_c, 8 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testbca' ); - removeAllFilters( 'test.filter' ); } ); test( 'filters with the same and different priorities', () => { @@ -129,7 +126,6 @@ test( 'filters with the same and different priorities', () => { } ); test( 'add and remove an action', () => { - window.actionValue = ''; addAction( 'test.action', action_a ); removeAllActions( 'test.action' ); doAction( 'test.action' ); @@ -137,30 +133,24 @@ test( 'add and remove an action', () => { } ); test( 'add an action and run it', function() { - window.actionValue = ''; addAction( 'test.action', action_a ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'a' ); - removeAllActions( 'test.action' ); } ); test( 'add 2 actions in a row and then run them', function() { - window.actionValue = ''; addAction( 'test.action', action_a ); addAction( 'test.action', action_b ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'ab' ); - removeAllActions( 'test.action' ); } ); test( 'add 3 actions with different priorities and run them', function() { - window.actionValue = ''; addAction( 'test.action', action_a ); addAction( 'test.action', action_b, 2 ); addAction( 'test.action', action_c, 8 ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'bca' ); - removeAllActions( 'test.action' ); } ); test( 'pass in two arguments to an action', function() { @@ -172,7 +162,6 @@ test( 'pass in two arguments to an action', function() { expect( b ).toBe( arg2 ); } ); doAction( 'test.action', arg1, arg2 ); - removeAllActions( 'test.action' ); } ); test( 'fire action multiple times', function() { @@ -185,11 +174,9 @@ test( 'fire action multiple times', function() { addAction( 'test.action', func ); doAction( 'test.action' ); doAction( 'test.action' ); - removeAllActions( 'test.action' ); } ); test( 'remove specific action callback', function() { - window.actionValue = ''; addAction( 'test.action', action_a ); addAction( 'test.action', action_b, 2 ); addAction( 'test.action', action_c, 8 ); @@ -197,11 +184,9 @@ test( 'remove specific action callback', function() { removeAction( 'test.action', action_b ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'ca' ); - removeAllActions( 'test.action' ); } ); test( 'remove all action callbacks', function() { - window.actionValue = ''; addAction( 'test.action', action_a ); addAction( 'test.action', action_b, 2 ); addAction( 'test.action', action_c, 8 ); @@ -218,7 +203,6 @@ test( 'remove specific filter callback', function() { removeFilter( 'test.filter', filter_b ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); - removeAllFilters( 'test.filter' ); } ); test( 'remove all filter callbacks', function() { From 7eda5e29948388001d06eaa1ed8e3bf977c47656 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 20 Jul 2017 15:47:11 -0400 Subject: [PATCH 30/91] Add webpack and build wp-hooks for core --- package.json | 3 +- packages/hooks/src/wp-hooks.js | 41 +++ packages/hooks/wp-hooks.js | 482 +++++++++++++++++++++++++++++++++ webpack.config.js | 6 + 4 files changed, 531 insertions(+), 1 deletion(-) create mode 100644 packages/hooks/src/wp-hooks.js create mode 100644 packages/hooks/wp-hooks.js create mode 100644 webpack.config.js diff --git a/package.json b/package.json index ebc1c53..f044ec1 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "jest": "^20.0.4", "lerna": "^2.0.0-rc.5", "mkdirp": "^0.5.1", - "rimraf": "^2.6.1" + "rimraf": "^2.6.1", + "webpack": "^3.3.0" }, "scripts": { "build-clean": "rimraf ./packages/*/build ./packages/*/build-browser ./packages/*/build-module", diff --git a/packages/hooks/src/wp-hooks.js b/packages/hooks/src/wp-hooks.js new file mode 100644 index 0000000..3f0461d --- /dev/null +++ b/packages/hooks/src/wp-hooks.js @@ -0,0 +1,41 @@ +import HOOKS from './hooks'; +import { + addAction, + addFilter, + removeAction, + removeFilter, + removeAllActions, + removeAllFilters, + hasAction, + hasFilter, + doAction, + applyFilters, + currentAction, + currentFilter, + doingAction, + doingFilter, + didAction, + didFilter +} from './'; + +const hooks = { + addAction, + addFilter, + removeAction, + removeFilter, + removeAllActions, + removeAllFilters, + hasAction, + hasFilter, + doAction, + applyFilters, + currentAction, + currentFilter, + doingAction, + doingFilter, + didAction, + didFilter +} + +window.wp = window.wp || {}; +window.wp.hooks = hooks; diff --git a/packages/hooks/wp-hooks.js b/packages/hooks/wp-hooks.js new file mode 100644 index 0000000..3e196b0 --- /dev/null +++ b/packages/hooks/wp-hooks.js @@ -0,0 +1,482 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 1); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/** + * Contains the registered hooks, keyed by hook type. Each hook type is an + * array of objects with priority and callback of each registered hook. + */ +const HOOKS = { + actions: {}, + filters: {}, +}; + +/* harmony default export */ __webpack_exports__["a"] = (HOOKS); + + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__hooks__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1____ = __webpack_require__(2); + + + +const hooks = { + addAction: __WEBPACK_IMPORTED_MODULE_1____["a" /* addAction */], + addFilter: __WEBPACK_IMPORTED_MODULE_1____["b" /* addFilter */], + removeAction: __WEBPACK_IMPORTED_MODULE_1____["m" /* removeAction */], + removeFilter: __WEBPACK_IMPORTED_MODULE_1____["p" /* removeFilter */], + removeAllActions: __WEBPACK_IMPORTED_MODULE_1____["n" /* removeAllActions */], + removeAllFilters: __WEBPACK_IMPORTED_MODULE_1____["o" /* removeAllFilters */], + hasAction: __WEBPACK_IMPORTED_MODULE_1____["k" /* hasAction */], + hasFilter: __WEBPACK_IMPORTED_MODULE_1____["l" /* hasFilter */], + doAction: __WEBPACK_IMPORTED_MODULE_1____["h" /* doAction */], + applyFilters: __WEBPACK_IMPORTED_MODULE_1____["c" /* applyFilters */], + currentAction: __WEBPACK_IMPORTED_MODULE_1____["d" /* currentAction */], + currentFilter: __WEBPACK_IMPORTED_MODULE_1____["e" /* currentFilter */], + doingAction: __WEBPACK_IMPORTED_MODULE_1____["i" /* doingAction */], + doingFilter: __WEBPACK_IMPORTED_MODULE_1____["j" /* doingFilter */], + didAction: __WEBPACK_IMPORTED_MODULE_1____["f" /* didAction */], + didFilter: __WEBPACK_IMPORTED_MODULE_1____["g" /* didFilter */] +} + +window.wp = window.wp || {}; +window.wp.hooks = hooks; + + +/***/ }), +/* 2 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__hooks__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__createAddHook__ = __webpack_require__(3); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__createRemoveHook__ = __webpack_require__(4); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__createHasHook__ = __webpack_require__(5); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__createRunHook__ = __webpack_require__(6); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__createDoingHook__ = __webpack_require__(7); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__createDidHook__ = __webpack_require__(8); + + + + + + + + +// Add action/filter functions. +const addAction = Object(__WEBPACK_IMPORTED_MODULE_1__createAddHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); +/* harmony export (immutable) */ __webpack_exports__["a"] = addAction; + +const addFilter = Object(__WEBPACK_IMPORTED_MODULE_1__createAddHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters ); +/* harmony export (immutable) */ __webpack_exports__["b"] = addFilter; + + +// Remove action/filter functions. +const removeAction = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); +/* harmony export (immutable) */ __webpack_exports__["m"] = removeAction; + +const removeFilter = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters ); +/* harmony export (immutable) */ __webpack_exports__["p"] = removeFilter; + + +// Has action/filter functions. +const hasAction = Object(__WEBPACK_IMPORTED_MODULE_3__createHasHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); +/* harmony export (immutable) */ __webpack_exports__["k"] = hasAction; + +const hasFilter = Object(__WEBPACK_IMPORTED_MODULE_3__createHasHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters ); +/* harmony export (immutable) */ __webpack_exports__["l"] = hasFilter; + + +// Remove all actions/filters functions. +const removeAllActions = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions, true ); +/* harmony export (immutable) */ __webpack_exports__["n"] = removeAllActions; + +const removeAllFilters = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters, true ); +/* harmony export (immutable) */ __webpack_exports__["o"] = removeAllFilters; + + +// Do action/apply filters functions. +const doAction = Object(__WEBPACK_IMPORTED_MODULE_4__createRunHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); +/* harmony export (immutable) */ __webpack_exports__["h"] = doAction; + +const applyFilters = Object(__WEBPACK_IMPORTED_MODULE_4__createRunHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters, true ); +/* harmony export (immutable) */ __webpack_exports__["c"] = applyFilters; + + +// Current action/filter functions. +const currentAction = () => __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions.current || null; +/* harmony export (immutable) */ __webpack_exports__["d"] = currentAction; + +const currentFilter = () => __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters.current || null; +/* harmony export (immutable) */ __webpack_exports__["e"] = currentFilter; + + +// Doing action/filter: true while a hook is being run. +const doingAction = Object(__WEBPACK_IMPORTED_MODULE_5__createDoingHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); +/* harmony export (immutable) */ __webpack_exports__["i"] = doingAction; + +const doingFilter = Object(__WEBPACK_IMPORTED_MODULE_5__createDoingHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters ); +/* harmony export (immutable) */ __webpack_exports__["j"] = doingFilter; + + +// Did action/filter functions. +const didAction = Object(__WEBPACK_IMPORTED_MODULE_6__createDidHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); +/* harmony export (immutable) */ __webpack_exports__["f"] = didAction; + +const didFilter = Object(__WEBPACK_IMPORTED_MODULE_6__createDidHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters ); +/* harmony export (immutable) */ __webpack_exports__["g"] = didFilter; + + + +/***/ }), +/* 3 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/** + * Returns a function which, when invoked, will add a hook. + * + * @param {Object} hooks Stored hooks, keyed by hook name. + * + * @return {Function} Function that adds a new hook. + */ +function createAddHook( hooks ) { + /** + * Adds the hook to the appropriate hooks container. + * + * @param {string} hookName Name of hook to add + * @param {Function} callback Function to call when the hook is run + * @param {?number} priority Priority of this hook (default=10) + */ + return function addHook( hookName, callback, priority ) { + if ( typeof hookName !== 'string' ) { + console.error( 'The hook name must be a string.' ); + return; + } + + if ( typeof callback !== 'function' ) { + console.error( 'The hook callback must be a function.' ); + return; + } + + // Assign default priority + if ( 'undefined' === typeof priority ) { + priority = 10; + } else { + priority = parseInt( priority, 10 ); + } + + // Validate numeric priority + if ( isNaN( priority ) ) { + console.error( 'The hook priority must be omitted or a number.' ); + return; + } + + const handler = { callback, priority }; + let handlers; + + if ( hooks.hasOwnProperty( hookName ) ) { + // Find the correct insert index of the new hook. + handlers = hooks[ hookName ]; + let i = 0; + while ( i < handlers.length ) { + if ( handlers[ i ].priority > priority ) { + break; + } + i++; + } + // Insert (or append) the new hook. + handlers.splice( i, 0, handler ); + } else { + // This is the first hook of its type. + handlers = [ handler ]; + } + + hooks[ hookName ] = handlers; + }; +} + +/* harmony default export */ __webpack_exports__["a"] = (createAddHook); + + +/***/ }), +/* 4 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/** + * Returns a function which, when invoked, will remove a specified hook or all + * hooks by the given name. + * + * @param {Object} hooks Stored hooks, keyed by hook name. + * @param {bool} removeAll Whether to remove all hooked callbacks. + * + * @return {Function} Function that removes hooks. + */ +function createRemoveHook( hooks, removeAll ) { + /** + * Removes the specified callback (or all callbacks) from the hook with a + * given name. + * + * @param {string} hookName The name of the hook to modify. + * @param {?Function} callback The specific callback to be removed. If + * omitted (and `removeAll` is truthy), clears + * all callbacks. + */ + return function removeHook( hookName, callback ) { + // Bail if no hooks exist by this name + if ( ! hooks.hasOwnProperty( hookName ) ) { + return; + } + + if ( removeAll ) { + const runs = hooks[ hookName ].runs; + hooks[ hookName ] = []; + if ( runs ) { + hooks[ hookName ].runs = runs; + } + } else if ( callback ) { + // Try to find the specified callback to remove. + const handlers = hooks[ hookName ]; + for ( let i = handlers.length - 1; i >= 0; i-- ) { + if ( handlers[ i ].callback === callback ) { + handlers.splice( i, 1 ); + } + } + } + }; +} + +/* harmony default export */ __webpack_exports__["a"] = (createRemoveHook); + + +/***/ }), +/* 5 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/** + * Returns a function which, when invoked, will return whether any handlers are + * attached to a particular hook. + * + * @param {Object} hooks Stored hooks, keyed by hook name. + * + * @return {Function} Function that returns whether any handlers are + * attached to a particular hook. + */ +function createHasHook( hooks ) { + /** + * Returns how many handlers are attached for the given hook. + * + * @param {string} hookName The name of the hook to check for. + * + * @return {number} The number of handlers that are attached to + * the given hook. + */ + return function hasHook( hookName ) { + return hooks.hasOwnProperty( hookName ) + ? hooks[ hookName ].length + : 0; + }; +} + +/* harmony default export */ __webpack_exports__["a"] = (createHasHook); + + +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/** + * 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 {Object} hooks Stored hooks, keyed by hook name. + * @param {?bool} returnFirstArg Whether each hook callback is expected to + * return its first argument. + * + * @return {Function} Function that runs hook callbacks. + */ +function createRunHook( hooks, returnFirstArg ) { + /** + * Runs all callbacks for the specified hook. + * + * @param {string} hookName The name of the hook to run. + * @param {...*} args Arguments to pass to the hook callbacks. + * + * @return {*} Return value of runner, if applicable. + */ + return function runHooks( hookName, ...args ) { + const handlers = hooks[ hookName ]; + let maybeReturnValue = args[ 0 ]; + + if ( ! handlers ) { + return ( returnFirstArg ? maybeReturnValue : undefined ); + } + + hooks.current = hookName; + handlers.runs = ( handlers.runs || 0 ) + 1; + + handlers.forEach( handler => { + maybeReturnValue = handler.callback.apply( null, args ); + if ( returnFirstArg ) { + args[ 0 ] = maybeReturnValue; + } + } ); + + delete hooks.current; + + if ( returnFirstArg ) { + return maybeReturnValue; + } + }; +} + +/* harmony default export */ __webpack_exports__["a"] = (createRunHook); + + +/***/ }), +/* 7 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/** + * Returns a function which, when invoked, will return whether a hook is + * currently being executed. + * + * @param {Object} hooks Stored hooks, keyed by hook name. + * + * @return {Function} Function that returns whether a hook is currently + * being executed. + */ +function createDoingHook( hooks ) { + /** + * Returns whether a hook is currently being executed. + * + * @param {?string} hookName The name of the hook to check for. If + * omitted, will check for any hook being executed. + * + * @return {bool} Whether the hook is being executed. + */ + return function doingHook( hookName ) { + // If the hookName was not passed, check for any current hook. + if ( 'undefined' === typeof hookName ) { + return 'undefined' !== typeof hooks.current; + } + + // Return the current hook. + return hooks.current + ? hookName === hooks.current + : false; + }; +} + +/* harmony default export */ __webpack_exports__["a"] = (createDoingHook); + + +/***/ }), +/* 8 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/** + * Returns a function which, when invoked, will return the number of times a + * hook has been called. + * + * @param {Object} hooks Stored hooks, keyed by hook name. + * + * @return {Function} Function that returns a hook's call count. + */ +function createDidHook( hooks ) { + /** + * Returns the number of times an action has been fired. + * + * @param {string} hookName The hook name to check. + * + * @return {number} The number of times the hook has run. + */ + return function didHook( hookName ) { + return hooks.hasOwnProperty( hookName ) && hooks[ hookName ].runs + ? hooks[ hookName ].runs + : 0; + }; +} + +/* harmony default export */ __webpack_exports__["a"] = (createDidHook); + + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..0244e91 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,6 @@ +module.exports = { + entry: './packages/hooks/src/wp-hooks.js', + output: { + filename: './packages/hooks/wp-hooks.js' + } +} From 0e9986a2a863e8ba8692010f2d034f43e29299ec Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 20 Jul 2017 15:51:38 -0400 Subject: [PATCH 31/91] remove built file and adjust build path --- packages/hooks/wp-hooks.js | 482 ------------------------------------- webpack.config.js | 2 +- 2 files changed, 1 insertion(+), 483 deletions(-) delete mode 100644 packages/hooks/wp-hooks.js diff --git a/packages/hooks/wp-hooks.js b/packages/hooks/wp-hooks.js deleted file mode 100644 index 3e196b0..0000000 --- a/packages/hooks/wp-hooks.js +++ /dev/null @@ -1,482 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 1); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/** - * Contains the registered hooks, keyed by hook type. Each hook type is an - * array of objects with priority and callback of each registered hook. - */ -const HOOKS = { - actions: {}, - filters: {}, -}; - -/* harmony default export */ __webpack_exports__["a"] = (HOOKS); - - -/***/ }), -/* 1 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__hooks__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1____ = __webpack_require__(2); - - - -const hooks = { - addAction: __WEBPACK_IMPORTED_MODULE_1____["a" /* addAction */], - addFilter: __WEBPACK_IMPORTED_MODULE_1____["b" /* addFilter */], - removeAction: __WEBPACK_IMPORTED_MODULE_1____["m" /* removeAction */], - removeFilter: __WEBPACK_IMPORTED_MODULE_1____["p" /* removeFilter */], - removeAllActions: __WEBPACK_IMPORTED_MODULE_1____["n" /* removeAllActions */], - removeAllFilters: __WEBPACK_IMPORTED_MODULE_1____["o" /* removeAllFilters */], - hasAction: __WEBPACK_IMPORTED_MODULE_1____["k" /* hasAction */], - hasFilter: __WEBPACK_IMPORTED_MODULE_1____["l" /* hasFilter */], - doAction: __WEBPACK_IMPORTED_MODULE_1____["h" /* doAction */], - applyFilters: __WEBPACK_IMPORTED_MODULE_1____["c" /* applyFilters */], - currentAction: __WEBPACK_IMPORTED_MODULE_1____["d" /* currentAction */], - currentFilter: __WEBPACK_IMPORTED_MODULE_1____["e" /* currentFilter */], - doingAction: __WEBPACK_IMPORTED_MODULE_1____["i" /* doingAction */], - doingFilter: __WEBPACK_IMPORTED_MODULE_1____["j" /* doingFilter */], - didAction: __WEBPACK_IMPORTED_MODULE_1____["f" /* didAction */], - didFilter: __WEBPACK_IMPORTED_MODULE_1____["g" /* didFilter */] -} - -window.wp = window.wp || {}; -window.wp.hooks = hooks; - - -/***/ }), -/* 2 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__hooks__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__createAddHook__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__createRemoveHook__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__createHasHook__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__createRunHook__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__createDoingHook__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__createDidHook__ = __webpack_require__(8); - - - - - - - - -// Add action/filter functions. -const addAction = Object(__WEBPACK_IMPORTED_MODULE_1__createAddHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); -/* harmony export (immutable) */ __webpack_exports__["a"] = addAction; - -const addFilter = Object(__WEBPACK_IMPORTED_MODULE_1__createAddHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters ); -/* harmony export (immutable) */ __webpack_exports__["b"] = addFilter; - - -// Remove action/filter functions. -const removeAction = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); -/* harmony export (immutable) */ __webpack_exports__["m"] = removeAction; - -const removeFilter = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters ); -/* harmony export (immutable) */ __webpack_exports__["p"] = removeFilter; - - -// Has action/filter functions. -const hasAction = Object(__WEBPACK_IMPORTED_MODULE_3__createHasHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); -/* harmony export (immutable) */ __webpack_exports__["k"] = hasAction; - -const hasFilter = Object(__WEBPACK_IMPORTED_MODULE_3__createHasHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters ); -/* harmony export (immutable) */ __webpack_exports__["l"] = hasFilter; - - -// Remove all actions/filters functions. -const removeAllActions = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions, true ); -/* harmony export (immutable) */ __webpack_exports__["n"] = removeAllActions; - -const removeAllFilters = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters, true ); -/* harmony export (immutable) */ __webpack_exports__["o"] = removeAllFilters; - - -// Do action/apply filters functions. -const doAction = Object(__WEBPACK_IMPORTED_MODULE_4__createRunHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); -/* harmony export (immutable) */ __webpack_exports__["h"] = doAction; - -const applyFilters = Object(__WEBPACK_IMPORTED_MODULE_4__createRunHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters, true ); -/* harmony export (immutable) */ __webpack_exports__["c"] = applyFilters; - - -// Current action/filter functions. -const currentAction = () => __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions.current || null; -/* harmony export (immutable) */ __webpack_exports__["d"] = currentAction; - -const currentFilter = () => __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters.current || null; -/* harmony export (immutable) */ __webpack_exports__["e"] = currentFilter; - - -// Doing action/filter: true while a hook is being run. -const doingAction = Object(__WEBPACK_IMPORTED_MODULE_5__createDoingHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); -/* harmony export (immutable) */ __webpack_exports__["i"] = doingAction; - -const doingFilter = Object(__WEBPACK_IMPORTED_MODULE_5__createDoingHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters ); -/* harmony export (immutable) */ __webpack_exports__["j"] = doingFilter; - - -// Did action/filter functions. -const didAction = Object(__WEBPACK_IMPORTED_MODULE_6__createDidHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions ); -/* harmony export (immutable) */ __webpack_exports__["f"] = didAction; - -const didFilter = Object(__WEBPACK_IMPORTED_MODULE_6__createDidHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters ); -/* harmony export (immutable) */ __webpack_exports__["g"] = didFilter; - - - -/***/ }), -/* 3 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/** - * Returns a function which, when invoked, will add a hook. - * - * @param {Object} hooks Stored hooks, keyed by hook name. - * - * @return {Function} Function that adds a new hook. - */ -function createAddHook( hooks ) { - /** - * Adds the hook to the appropriate hooks container. - * - * @param {string} hookName Name of hook to add - * @param {Function} callback Function to call when the hook is run - * @param {?number} priority Priority of this hook (default=10) - */ - return function addHook( hookName, callback, priority ) { - if ( typeof hookName !== 'string' ) { - console.error( 'The hook name must be a string.' ); - return; - } - - if ( typeof callback !== 'function' ) { - console.error( 'The hook callback must be a function.' ); - return; - } - - // Assign default priority - if ( 'undefined' === typeof priority ) { - priority = 10; - } else { - priority = parseInt( priority, 10 ); - } - - // Validate numeric priority - if ( isNaN( priority ) ) { - console.error( 'The hook priority must be omitted or a number.' ); - return; - } - - const handler = { callback, priority }; - let handlers; - - if ( hooks.hasOwnProperty( hookName ) ) { - // Find the correct insert index of the new hook. - handlers = hooks[ hookName ]; - let i = 0; - while ( i < handlers.length ) { - if ( handlers[ i ].priority > priority ) { - break; - } - i++; - } - // Insert (or append) the new hook. - handlers.splice( i, 0, handler ); - } else { - // This is the first hook of its type. - handlers = [ handler ]; - } - - hooks[ hookName ] = handlers; - }; -} - -/* harmony default export */ __webpack_exports__["a"] = (createAddHook); - - -/***/ }), -/* 4 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/** - * Returns a function which, when invoked, will remove a specified hook or all - * hooks by the given name. - * - * @param {Object} hooks Stored hooks, keyed by hook name. - * @param {bool} removeAll Whether to remove all hooked callbacks. - * - * @return {Function} Function that removes hooks. - */ -function createRemoveHook( hooks, removeAll ) { - /** - * Removes the specified callback (or all callbacks) from the hook with a - * given name. - * - * @param {string} hookName The name of the hook to modify. - * @param {?Function} callback The specific callback to be removed. If - * omitted (and `removeAll` is truthy), clears - * all callbacks. - */ - return function removeHook( hookName, callback ) { - // Bail if no hooks exist by this name - if ( ! hooks.hasOwnProperty( hookName ) ) { - return; - } - - if ( removeAll ) { - const runs = hooks[ hookName ].runs; - hooks[ hookName ] = []; - if ( runs ) { - hooks[ hookName ].runs = runs; - } - } else if ( callback ) { - // Try to find the specified callback to remove. - const handlers = hooks[ hookName ]; - for ( let i = handlers.length - 1; i >= 0; i-- ) { - if ( handlers[ i ].callback === callback ) { - handlers.splice( i, 1 ); - } - } - } - }; -} - -/* harmony default export */ __webpack_exports__["a"] = (createRemoveHook); - - -/***/ }), -/* 5 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/** - * Returns a function which, when invoked, will return whether any handlers are - * attached to a particular hook. - * - * @param {Object} hooks Stored hooks, keyed by hook name. - * - * @return {Function} Function that returns whether any handlers are - * attached to a particular hook. - */ -function createHasHook( hooks ) { - /** - * Returns how many handlers are attached for the given hook. - * - * @param {string} hookName The name of the hook to check for. - * - * @return {number} The number of handlers that are attached to - * the given hook. - */ - return function hasHook( hookName ) { - return hooks.hasOwnProperty( hookName ) - ? hooks[ hookName ].length - : 0; - }; -} - -/* harmony default export */ __webpack_exports__["a"] = (createHasHook); - - -/***/ }), -/* 6 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/** - * 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 {Object} hooks Stored hooks, keyed by hook name. - * @param {?bool} returnFirstArg Whether each hook callback is expected to - * return its first argument. - * - * @return {Function} Function that runs hook callbacks. - */ -function createRunHook( hooks, returnFirstArg ) { - /** - * Runs all callbacks for the specified hook. - * - * @param {string} hookName The name of the hook to run. - * @param {...*} args Arguments to pass to the hook callbacks. - * - * @return {*} Return value of runner, if applicable. - */ - return function runHooks( hookName, ...args ) { - const handlers = hooks[ hookName ]; - let maybeReturnValue = args[ 0 ]; - - if ( ! handlers ) { - return ( returnFirstArg ? maybeReturnValue : undefined ); - } - - hooks.current = hookName; - handlers.runs = ( handlers.runs || 0 ) + 1; - - handlers.forEach( handler => { - maybeReturnValue = handler.callback.apply( null, args ); - if ( returnFirstArg ) { - args[ 0 ] = maybeReturnValue; - } - } ); - - delete hooks.current; - - if ( returnFirstArg ) { - return maybeReturnValue; - } - }; -} - -/* harmony default export */ __webpack_exports__["a"] = (createRunHook); - - -/***/ }), -/* 7 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/** - * Returns a function which, when invoked, will return whether a hook is - * currently being executed. - * - * @param {Object} hooks Stored hooks, keyed by hook name. - * - * @return {Function} Function that returns whether a hook is currently - * being executed. - */ -function createDoingHook( hooks ) { - /** - * Returns whether a hook is currently being executed. - * - * @param {?string} hookName The name of the hook to check for. If - * omitted, will check for any hook being executed. - * - * @return {bool} Whether the hook is being executed. - */ - return function doingHook( hookName ) { - // If the hookName was not passed, check for any current hook. - if ( 'undefined' === typeof hookName ) { - return 'undefined' !== typeof hooks.current; - } - - // Return the current hook. - return hooks.current - ? hookName === hooks.current - : false; - }; -} - -/* harmony default export */ __webpack_exports__["a"] = (createDoingHook); - - -/***/ }), -/* 8 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/** - * Returns a function which, when invoked, will return the number of times a - * hook has been called. - * - * @param {Object} hooks Stored hooks, keyed by hook name. - * - * @return {Function} Function that returns a hook's call count. - */ -function createDidHook( hooks ) { - /** - * Returns the number of times an action has been fired. - * - * @param {string} hookName The hook name to check. - * - * @return {number} The number of times the hook has run. - */ - return function didHook( hookName ) { - return hooks.hasOwnProperty( hookName ) && hooks[ hookName ].runs - ? hooks[ hookName ].runs - : 0; - }; -} - -/* harmony default export */ __webpack_exports__["a"] = (createDidHook); - - -/***/ }) -/******/ ]); \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 0244e91..036556a 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,6 @@ module.exports = { entry: './packages/hooks/src/wp-hooks.js', output: { - filename: './packages/hooks/wp-hooks.js' + filename: './packages/hooks/build/wp-core/wp-hooks.js' } } From c9890db6e925bc6144b37e446ef129332433e816 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 23:46:07 +0200 Subject: [PATCH 32/91] Remove unused dependencies --- packages/hooks/package.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 4724aff..94ec11a 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -10,9 +10,5 @@ "module": "build-module/index.js", "browser": "build-browser/index.js", "author": "WordPress", - "license": "GPL-2.0+", - "dependencies": { - "querystring": "^0.2.0", - "url": "^0.11.0" - } + "license": "GPL-2.0+" } From de6efd77cf0b1de0b58e2d9e03f52b0f672635cb Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 23:46:26 +0200 Subject: [PATCH 33/91] Use an ES6 default argument to set the default hook priority --- packages/hooks/src/createAddHook.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 71febb8..59b2139 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -13,7 +13,7 @@ function createAddHook( hooks ) { * @param {Function} callback Function to call when the hook is run * @param {?number} priority Priority of this hook (default=10) */ - return function addHook( hookName, callback, priority ) { + return function addHook( hookName, callback, priority = 10 ) { if ( typeof hookName !== 'string' ) { console.error( 'The hook name must be a string.' ); return; @@ -24,16 +24,9 @@ function createAddHook( hooks ) { return; } - // Assign default priority - if ( 'undefined' === typeof priority ) { - priority = 10; - } else { - priority = parseInt( priority, 10 ); - } - // Validate numeric priority - if ( isNaN( priority ) ) { - console.error( 'The hook priority must be omitted or a number.' ); + if ( typeof priority !== 'number' ) { + console.error( 'If specified, the hook priority must be a number.' ); return; } From ad479985757fd39ee32ff772f733db9f017ecba3 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Thu, 20 Jul 2017 23:52:20 +0200 Subject: [PATCH 34/91] Refactor handlers objects: don't assign extra properties on arrays --- packages/hooks/src/createAddHook.js | 10 +++++----- packages/hooks/src/createHasHook.js | 2 +- packages/hooks/src/createRemoveHook.js | 11 +++++------ packages/hooks/src/createRunHook.js | 19 ++++++++++++++----- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 59b2139..30ceda7 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -31,11 +31,10 @@ function createAddHook( hooks ) { } const handler = { callback, priority }; - let handlers; if ( hooks.hasOwnProperty( hookName ) ) { // Find the correct insert index of the new hook. - handlers = hooks[ hookName ]; + const handlers = hooks[ hookName ].handlers; let i = 0; while ( i < handlers.length ) { if ( handlers[ i ].priority > priority ) { @@ -47,10 +46,11 @@ function createAddHook( hooks ) { handlers.splice( i, 0, handler ); } else { // This is the first hook of its type. - handlers = [ handler ]; + hooks[ hookName ] = { + handlers: [ handler ], + runs: 0, + }; } - - hooks[ hookName ] = handlers; }; } diff --git a/packages/hooks/src/createHasHook.js b/packages/hooks/src/createHasHook.js index 6d9cd10..46cd61a 100644 --- a/packages/hooks/src/createHasHook.js +++ b/packages/hooks/src/createHasHook.js @@ -18,7 +18,7 @@ function createHasHook( hooks ) { */ return function hasHook( hookName ) { return hooks.hasOwnProperty( hookName ) - ? hooks[ hookName ].length + ? hooks[ hookName ].handlers.length : 0; }; } diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index 33d1bd5..a136ca2 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -24,14 +24,13 @@ function createRemoveHook( hooks, removeAll ) { } if ( removeAll ) { - const runs = hooks[ hookName ].runs; - hooks[ hookName ] = []; - if ( runs ) { - hooks[ hookName ].runs = runs; - } + hooks[ hookName ] = { + runs: hooks[ hookName ].runs, + handlers: [], + }; } else if ( callback ) { // Try to find the specified callback to remove. - const handlers = hooks[ hookName ]; + const handlers = hooks[ hookName ].handlers; for ( let i = handlers.length - 1; i >= 0; i-- ) { if ( handlers[ i ].callback === callback ) { handlers.splice( i, 1 ); diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index e9ab4eb..3d0da3b 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -19,16 +19,25 @@ function createRunHook( hooks, returnFirstArg ) { * @return {*} Return value of runner, if applicable. */ return function runHooks( hookName, ...args ) { - const handlers = hooks[ hookName ]; - let maybeReturnValue = args[ 0 ]; + if ( ! hooks.hasOwnProperty( hookName ) ) { + hooks[ hookName ] = { + runs: 0, + handlers: [], + }; + } - if ( ! handlers ) { - return ( returnFirstArg ? maybeReturnValue : undefined ); + const handlers = hooks[ hookName ].handlers; + + if ( ! handlers.length ) { + return returnFirstArg + ? args[ 0 ] + : undefined; } hooks.current = hookName; - handlers.runs = ( handlers.runs || 0 ) + 1; + hooks[ hookName ].runs++; + let maybeReturnValue = args[ 0 ]; handlers.forEach( handler => { maybeReturnValue = handler.callback.apply( null, args ); if ( returnFirstArg ) { From 562cf377ccfe55d2d0bc3e2886c8d508a4dc80a6 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 20 Jul 2017 18:23:36 -0400 Subject: [PATCH 35/91] Run core build JS thru babel --- package.json | 3 ++- webpack.config.js | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f044ec1..e62872f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "lerna": "^2.0.0-rc.5", "mkdirp": "^0.5.1", "rimraf": "^2.6.1", - "webpack": "^3.3.0" + "webpack": "^3.3.0", + "babel-loader": "^7.1.1" }, "scripts": { "build-clean": "rimraf ./packages/*/build ./packages/*/build-browser ./packages/*/build-module", diff --git a/webpack.config.js b/webpack.config.js index 036556a..ca6d3a0 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,5 +2,17 @@ module.exports = { entry: './packages/hooks/src/wp-hooks.js', output: { filename: './packages/hooks/build/wp-core/wp-hooks.js' + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /(node_modules)/, + use: { + loader: 'babel-loader' + } + } + ] } + } From f882313d9bf80a490c330d8d22ad02f90f7eafe6 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 21 Jul 2017 12:00:26 -0400 Subject: [PATCH 36/91] remove babel-loader for now --- package.json | 3 +-- webpack.config.js | 12 ------------ 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/package.json b/package.json index e62872f..f044ec1 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,7 @@ "lerna": "^2.0.0-rc.5", "mkdirp": "^0.5.1", "rimraf": "^2.6.1", - "webpack": "^3.3.0", - "babel-loader": "^7.1.1" + "webpack": "^3.3.0" }, "scripts": { "build-clean": "rimraf ./packages/*/build ./packages/*/build-browser ./packages/*/build-module", diff --git a/webpack.config.js b/webpack.config.js index ca6d3a0..036556a 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,17 +2,5 @@ module.exports = { entry: './packages/hooks/src/wp-hooks.js', output: { filename: './packages/hooks/build/wp-core/wp-hooks.js' - }, - module: { - rules: [ - { - test: /\.js$/, - exclude: /(node_modules)/, - use: { - loader: 'babel-loader' - } - } - ] } - } From 9eeb1987044a97a997e11a907449518e4c8e8860 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 21 Jul 2017 15:30:32 -0400 Subject: [PATCH 37/91] =?UTF-8?q?rename=20=E2=80=98current=E2=80=99=20=3D>?= =?UTF-8?q?=20=E2=80=98=5F=5Fcurrent=E2=80=99=20and=20make=20it=20a=20stac?= =?UTF-8?q?k?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/hooks/src/createDoingHook.js | 8 ++++---- packages/hooks/src/createRunHook.js | 7 +++++-- packages/hooks/src/index.js | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/hooks/src/createDoingHook.js b/packages/hooks/src/createDoingHook.js index ba7aa02..860b657 100644 --- a/packages/hooks/src/createDoingHook.js +++ b/packages/hooks/src/createDoingHook.js @@ -19,12 +19,12 @@ function createDoingHook( hooks ) { return function doingHook( hookName ) { // If the hookName was not passed, check for any current hook. if ( 'undefined' === typeof hookName ) { - return 'undefined' !== typeof hooks.current; + return 'undefined' !== typeof hooks.__current[0]; } - // Return the current hook. - return hooks.current - ? hookName === hooks.current + // Return the __current hook. + return hooks.__current[0] + ? hookName === hooks.__current[0] : false; }; } diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index 3d0da3b..911e2a0 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -34,7 +34,8 @@ function createRunHook( hooks, returnFirstArg ) { : undefined; } - hooks.current = hookName; + hooks.__current = hooks.__current || []; + hooks.__current.push( hookName ); hooks[ hookName ].runs++; let maybeReturnValue = args[ 0 ]; @@ -45,10 +46,12 @@ function createRunHook( hooks, returnFirstArg ) { } } ); - delete hooks.current; + hooks.__current.pop(); if ( returnFirstArg ) { return maybeReturnValue; + } else { + return false; } }; } diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index 992930e..732aa09 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -27,8 +27,8 @@ export const doAction = createRunHook( HOOKS.actions ); export const applyFilters = createRunHook( HOOKS.filters, true ); // Current action/filter functions. -export const currentAction = () => HOOKS.actions.current || null; -export const currentFilter = () => HOOKS.filters.current || null; +export const currentAction = () => HOOKS.actions.__current[0] || null; +export const currentFilter = () => HOOKS.filters.__current[0] || null; // Doing action/filter: true while a hook is being run. export const doingAction = createDoingHook( HOOKS.actions ); From fd0ccd3b884d27263ef06d5e4db638657dd10d93 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 21 Jul 2017 15:38:17 -0400 Subject: [PATCH 38/91] Add initial readme based on https://github.com/adamsilverstein/WP-JS-Hooks --- packages/hooks/README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 packages/hooks/README.md diff --git a/packages/hooks/README.md b/packages/hooks/README.md new file mode 100644 index 0000000..1174727 --- /dev/null +++ b/packages/hooks/README.md @@ -0,0 +1,34 @@ +# WP-JS-Hooks + +A lightweight & efficient EventManager for JavaScript in WordPress. + + +### API Usage +API functions can be called via the global `wp.hooks` like this `wp.hooks.addAction()`, etc. + +* `addAction( 'namespace.identifier', callback, priority )` +* `addFilter( 'namespace.identifier', callback, priority )` +* `removeAction( 'namespace.identifier', callback )` +* `removeFilter( 'namespace.identifier', callback )` +* `removeAllActions( 'namespace.identifier' )` +* `removeAllFilters( 'namespace.identifier' )` +* `doAction( 'namespace.identifier', arg1, arg2, moreArgs, finalArg )` +* `applyFilters( 'namespace.identifier', content )` +* `doingAction( 'namespace.identifier' )` +* `doingFilter( 'namespace.identifier' )` +* `didAction( 'namespace.identifier' )` +* `didFilter( 'namespace.identifier' )` +* `hasAction( 'namespace.identifier' )` +* `hasFilter( 'namespace.identifier' )` + + +### Background +See ticket [#21170](http://core.trac.wordpress.org/ticket/21170) for more information. + + +### Features + +* Fast and lightweight. +* Priorities system ensures hooks with lower integer priority are fired first. +* Uses native object hash lookup for finding hook callbacks. +* Utilizes insertion sort for keeping priorities correct. Best Case: O(n), worst case: O(n^2) From fc48fbfb2b29a545b0e5474a02729f38230d376c Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 21 Jul 2017 15:53:55 -0400 Subject: [PATCH 39/91] test remove a filter callback of lower priority when running hook --- packages/hooks/src/test/index.test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index c2f2d60..8e15d9d 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -205,6 +205,16 @@ test( 'remove specific filter callback', function() { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); } ); +test( 'remove a filter callback of lower priority when running hook', function() { + + addFilter( 'test.filter', filter_a, 1 ); + addFilter( 'test.filter', filter_b, 3 ); + addFilter( 'test.filter', filter_c, 4 ); + addFilter( 'test.filter', filter_a_removesb, 2 ); + + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); +} ); + test( 'remove all filter callbacks', function() { addFilter( 'test.filter', filter_a ); addFilter( 'test.filter', filter_b, 2 ); From 566af31749c47bac813269f1fc6497517c40a1fd Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 21 Jul 2017 15:54:11 -0400 Subject: [PATCH 40/91] test remove a filter callback of same priority when running hook --- packages/hooks/src/test/index.test.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 8e15d9d..a1c5515 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -39,6 +39,10 @@ function action_b() { function action_c() { window.actionValue += 'c'; } +function filter_a_removesb( str ) { + removeFilter( 'test.filter', filter_b ); + return str; +} beforeEach( () => { window.actionValue = ''; @@ -215,6 +219,16 @@ test( 'remove a filter callback of lower priority when running hook', function() expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); } ); +test( 'remove a filter callback of same priority when running hook', function() { + + addFilter( 'test.filter', filter_a, 1 ); + addFilter( 'test.filter', filter_a_removesb, 2 ); + addFilter( 'test.filter', filter_b, 2 ); + addFilter( 'test.filter', filter_c, 4 ); + + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); +} ); + test( 'remove all filter callbacks', function() { addFilter( 'test.filter', filter_a ); addFilter( 'test.filter', filter_b, 2 ); From 6ce626857615312e3f47f17193c1c9bc61aea583 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 21 Jul 2017 16:15:50 -0400 Subject: [PATCH 41/91] prevent and test for (dingle level) hook recursion --- packages/hooks/src/createRunHook.js | 14 +++++++++++--- packages/hooks/src/test/index.test.js | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index 911e2a0..d7af0eb 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -39,10 +39,18 @@ function createRunHook( hooks, returnFirstArg ) { hooks[ hookName ].runs++; let maybeReturnValue = args[ 0 ]; + handlers.forEach( handler => { - maybeReturnValue = handler.callback.apply( null, args ); - if ( returnFirstArg ) { - args[ 0 ] = maybeReturnValue; + if ( handler.callback !== hooks.currentCallback ) { + + // Prevent hook recursion. + hooks.currentCallback = handler.callback; + maybeReturnValue = handler.callback.apply( null, args ); + hooks.currentCallback = false; + + if ( returnFirstArg ) { + args[ 0 ] = maybeReturnValue; + } } } ); diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index a1c5515..8355722 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -24,26 +24,37 @@ import { function filter_a( str ) { return str + 'a'; } + function filter_b( str ) { return str + 'b'; } + function filter_c( str ) { return str + 'c'; } + function action_a() { window.actionValue += 'a'; } + function action_b() { window.actionValue += 'b'; } + function action_c() { window.actionValue += 'c'; } + function filter_a_removesb( str ) { removeFilter( 'test.filter', filter_b ); return str; } +function filter_that_applies_recursively( str ) { + applyFilters( 'test.filter', str ); + return str; +} + beforeEach( () => { window.actionValue = ''; // Reset state in between tests (clear all callbacks, `didAction` counts, @@ -321,3 +332,11 @@ test( 'Verify doingFilter, didFilter and hasFilter.', function() { expect( hasFilter( 'runtest.filter' ) ).toBe( 0 ); expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); } ); + +test( 'recursively calling a filter', function() { + + addFilter( 'test.filter', filter_that_applies_recursively, 10 ); + + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); +} ); + From 83dffa47ec0f121e066a88928fb467af0307dbca Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 21 Jul 2017 16:20:12 -0400 Subject: [PATCH 42/91] test remove a filter callback of higher priority when running hook --- packages/hooks/src/test/index.test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 8355722..9a1f1de 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -230,9 +230,20 @@ test( 'remove a filter callback of lower priority when running hook', function() expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); } ); +test( 'remove a filter callback of higher priority when running hook', function() { + + addFilter( 'test.filter', filter_a, 1 ); + addFilter( 'test.filter', filter_b, 3 ); + addFilter( 'test.filter', filter_c, 5 ); + addFilter( 'test.filter', filter_a_removesb, 6 ); + + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); +} ); + test( 'remove a filter callback of same priority when running hook', function() { addFilter( 'test.filter', filter_a, 1 ); + // Note: works if added first, adding after may need fixing. addFilter( 'test.filter', filter_a_removesb, 2 ); addFilter( 'test.filter', filter_b, 2 ); addFilter( 'test.filter', filter_c, 4 ); From 2a60b9f237ec34050535f326255da1624bceab65 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 21 Jul 2017 16:25:02 -0400 Subject: [PATCH 43/91] Failing recursive test: remove one hook in a callback before adding another --- packages/hooks/src/test/index.test.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 9a1f1de..acef761 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -239,6 +239,15 @@ test( 'remove a filter callback of higher priority when running hook', function( expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); +test( 'remove one hook in a callback before adding another', function() { + addFilter( 'test.filter', filter_a, 1 ); + addFilter( 'test.filter', filter_b, 3 ); + addFilter( 'test.filter', filter_c, 5 ); + addFilter( 'test.filter', filter_a_removesb, 4 ); + + // Fails!!! only a & b run, not c. + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); +} ); test( 'remove a filter callback of same priority when running hook', function() { From 79ef421b7debc0070aa352652089b713f12b482d Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 21 Jul 2017 17:04:04 -0400 Subject: [PATCH 44/91] Add babel-loader for core build --- package.json | 3 ++- webpack.config.js | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f044ec1..e62872f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "lerna": "^2.0.0-rc.5", "mkdirp": "^0.5.1", "rimraf": "^2.6.1", - "webpack": "^3.3.0" + "webpack": "^3.3.0", + "babel-loader": "^7.1.1" }, "scripts": { "build-clean": "rimraf ./packages/*/build ./packages/*/build-browser ./packages/*/build-module", diff --git a/webpack.config.js b/webpack.config.js index 036556a..5faefb9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,17 @@ module.exports = { entry: './packages/hooks/src/wp-hooks.js', output: { - filename: './packages/hooks/build/wp-core/wp-hooks.js' + filename: './packages/hooks/wp-core/wp-hooks.js' + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /(node_modules)/, + use: { + loader: 'babel-loader' + } + } + ] } } From bf69f8927de3569d88a6e1adeff753e69fa825f4 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 14:06:16 +0200 Subject: [PATCH 45/91] Clean up tests for removing a filter while filters are running --- packages/hooks/src/test/index.test.js | 63 ++++++++++++++++++--------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index acef761..0f29f78 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -33,6 +33,21 @@ function filter_c( str ) { return str + 'c'; } +function filter_b_removes_self( str ) { + removeFilter( 'test.filter', filter_b_removes_self ); + return str + 'b'; +} + +function filter_removes_b( str ) { + removeFilter( 'test.filter', filter_b ); + return str; +} + +function filter_removes_c( str ) { + removeFilter( 'test.filter', filter_c ); + return str; +} + function action_a() { window.actionValue += 'a'; } @@ -45,11 +60,6 @@ function action_c() { window.actionValue += 'c'; } -function filter_a_removesb( str ) { - removeFilter( 'test.filter', filter_b ); - return str; -} - function filter_that_applies_recursively( str ) { applyFilters( 'test.filter', str ); return str; @@ -220,40 +230,53 @@ test( 'remove specific filter callback', function() { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); } ); -test( 'remove a filter callback of lower priority when running hook', function() { - +test( 'filter removes a callback that has already executed', function() { addFilter( 'test.filter', filter_a, 1 ); addFilter( 'test.filter', filter_b, 3 ); - addFilter( 'test.filter', filter_c, 4 ); - addFilter( 'test.filter', filter_a_removesb, 2 ); + addFilter( 'test.filter', filter_c, 5 ); + addFilter( 'test.filter', filter_removes_b, 4 ); - expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); -test( 'remove a filter callback of higher priority when running hook', function() { +test( 'filter removes a callback that has already executed (same priority)', function() { + addFilter( 'test.filter', filter_a, 1 ); + addFilter( 'test.filter', filter_b, 2 ); + addFilter( 'test.filter', filter_removes_b, 2 ); + addFilter( 'test.filter', filter_c, 4 ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); +} ); + +test( 'filter removes the current callback', function() { addFilter( 'test.filter', filter_a, 1 ); - addFilter( 'test.filter', filter_b, 3 ); + addFilter( 'test.filter', filter_b_removes_self, 3 ); addFilter( 'test.filter', filter_c, 5 ); - addFilter( 'test.filter', filter_a_removesb, 6 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); -test( 'remove one hook in a callback before adding another', function() { + +test( 'filter removes a callback that has not yet executed (last)', function() { addFilter( 'test.filter', filter_a, 1 ); addFilter( 'test.filter', filter_b, 3 ); addFilter( 'test.filter', filter_c, 5 ); - addFilter( 'test.filter', filter_a_removesb, 4 ); + addFilter( 'test.filter', filter_removes_c, 4 ); - // Fails!!! only a & b run, not c. - expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); } ); -test( 'remove a filter callback of same priority when running hook', function() { +test( 'filter removes a callback that has not yet executed (middle)', function() { + addFilter( 'test.filter', filter_a, 1 ); + addFilter( 'test.filter', filter_b, 3 ); + addFilter( 'test.filter', filter_c, 4 ); + addFilter( 'test.filter', filter_removes_b, 2 ); + + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); +} ); +test( 'filter removes a callback that has not yet executed (same priority)', function() { addFilter( 'test.filter', filter_a, 1 ); - // Note: works if added first, adding after may need fixing. - addFilter( 'test.filter', filter_a_removesb, 2 ); + addFilter( 'test.filter', filter_removes_b, 2 ); addFilter( 'test.filter', filter_b, 2 ); addFilter( 'test.filter', filter_c, 4 ); From bd911d075eadff234b10b97f0bc44f6f587bbdc5 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 14:44:56 +0200 Subject: [PATCH 46/91] Add test demonstrating desired recursion behavior --- packages/hooks/src/test/index.test.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 0f29f78..f8e049f 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -60,11 +60,6 @@ function action_c() { window.actionValue += 'c'; } -function filter_that_applies_recursively( str ) { - applyFilters( 'test.filter', str ); - return str; -} - beforeEach( () => { window.actionValue = ''; // Reset state in between tests (clear all callbacks, `didAction` counts, @@ -377,9 +372,13 @@ test( 'Verify doingFilter, didFilter and hasFilter.', function() { } ); test( 'recursively calling a filter', function() { + addFilter( 'test.filter', value => { + if ( value.length === 7 ) { + return value; + } + return applyFilters( 'test.filter', value + 'X' ); + } ); - addFilter( 'test.filter', filter_that_applies_recursively, 10 ); - - expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); + expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testXXX' ); } ); From b802c1d954c371aa2f9c86021e672427e3623d9f Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 14:51:34 +0200 Subject: [PATCH 47/91] Convert most functions in tests to arrow functions (for consistency) --- packages/hooks/src/test/index.test.js | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index f8e049f..8adc2fe 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -152,20 +152,20 @@ test( 'add and remove an action', () => { expect( window.actionValue ).toBe( '' ); } ); -test( 'add an action and run it', function() { +test( 'add an action and run it', () => { addAction( 'test.action', action_a ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'a' ); } ); -test( 'add 2 actions in a row and then run them', function() { +test( 'add 2 actions in a row and then run them', () => { addAction( 'test.action', action_a ); addAction( 'test.action', action_b ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'ab' ); } ); -test( 'add 3 actions with different priorities and run them', function() { +test( 'add 3 actions with different priorities and run them', () => { addAction( 'test.action', action_a ); addAction( 'test.action', action_b, 2 ); addAction( 'test.action', action_c, 8 ); @@ -173,18 +173,18 @@ test( 'add 3 actions with different priorities and run them', function() { expect( window.actionValue ).toBe( 'bca' ); } ); -test( 'pass in two arguments to an action', function() { +test( 'pass in two arguments to an action', () => { const arg1 = { a: 10 }; const arg2 = { b: 20 }; - addAction( 'test.action', function( a, b ) { + addAction( 'test.action', ( a, b ) => { expect( a ).toBe( arg1 ); expect( b ).toBe( arg2 ); } ); doAction( 'test.action', arg1, arg2 ); } ); -test( 'fire action multiple times', function() { +test( 'fire action multiple times', () => { expect.assertions( 2 ); function func() { @@ -196,7 +196,7 @@ test( 'fire action multiple times', function() { doAction( 'test.action' ); } ); -test( 'remove specific action callback', function() { +test( 'remove specific action callback', () => { addAction( 'test.action', action_a ); addAction( 'test.action', action_b, 2 ); addAction( 'test.action', action_c, 8 ); @@ -206,7 +206,7 @@ test( 'remove specific action callback', function() { expect( window.actionValue ).toBe( 'ca' ); } ); -test( 'remove all action callbacks', function() { +test( 'remove all action callbacks', () => { addAction( 'test.action', action_a ); addAction( 'test.action', action_b, 2 ); addAction( 'test.action', action_c, 8 ); @@ -216,7 +216,7 @@ test( 'remove all action callbacks', function() { expect( window.actionValue ).toBe( '' ); } ); -test( 'remove specific filter callback', function() { +test( 'remove specific filter callback', () => { addFilter( 'test.filter', filter_a ); addFilter( 'test.filter', filter_b, 2 ); addFilter( 'test.filter', filter_c, 8 ); @@ -225,7 +225,7 @@ test( 'remove specific filter callback', function() { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); } ); -test( 'filter removes a callback that has already executed', function() { +test( 'filter removes a callback that has already executed', () => { addFilter( 'test.filter', filter_a, 1 ); addFilter( 'test.filter', filter_b, 3 ); addFilter( 'test.filter', filter_c, 5 ); @@ -234,7 +234,7 @@ test( 'filter removes a callback that has already executed', function() { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); -test( 'filter removes a callback that has already executed (same priority)', function() { +test( 'filter removes a callback that has already executed (same priority)', () => { addFilter( 'test.filter', filter_a, 1 ); addFilter( 'test.filter', filter_b, 2 ); addFilter( 'test.filter', filter_removes_b, 2 ); @@ -243,7 +243,7 @@ test( 'filter removes a callback that has already executed (same priority)', fun expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); -test( 'filter removes the current callback', function() { +test( 'filter removes the current callback', () => { addFilter( 'test.filter', filter_a, 1 ); addFilter( 'test.filter', filter_b_removes_self, 3 ); addFilter( 'test.filter', filter_c, 5 ); @@ -251,7 +251,7 @@ test( 'filter removes the current callback', function() { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); -test( 'filter removes a callback that has not yet executed (last)', function() { +test( 'filter removes a callback that has not yet executed (last)', () => { addFilter( 'test.filter', filter_a, 1 ); addFilter( 'test.filter', filter_b, 3 ); addFilter( 'test.filter', filter_c, 5 ); @@ -260,7 +260,7 @@ test( 'filter removes a callback that has not yet executed (last)', function() { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); } ); -test( 'filter removes a callback that has not yet executed (middle)', function() { +test( 'filter removes a callback that has not yet executed (middle)', () => { addFilter( 'test.filter', filter_a, 1 ); addFilter( 'test.filter', filter_b, 3 ); addFilter( 'test.filter', filter_c, 4 ); @@ -269,7 +269,7 @@ test( 'filter removes a callback that has not yet executed (middle)', function() expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); } ); -test( 'filter removes a callback that has not yet executed (same priority)', function() { +test( 'filter removes a callback that has not yet executed (same priority)', () => { addFilter( 'test.filter', filter_a, 1 ); addFilter( 'test.filter', filter_removes_b, 2 ); addFilter( 'test.filter', filter_b, 2 ); @@ -278,7 +278,7 @@ test( 'filter removes a callback that has not yet executed (same priority)', fun expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); } ); -test( 'remove all filter callbacks', function() { +test( 'remove all filter callbacks', () => { addFilter( 'test.filter', filter_a ); addFilter( 'test.filter', filter_b, 2 ); addFilter( 'test.filter', filter_c, 8 ); @@ -288,7 +288,7 @@ test( 'remove all filter callbacks', function() { } ); // Test doingAction, didAction, hasAction. -test( 'Test doingAction, didAction and hasAction.', function() { +test( 'Test doingAction, didAction and hasAction.', () => { let actionCalls = 0; addAction( 'another.action', () => {} ); @@ -342,7 +342,7 @@ test( 'Test doingAction, didAction and hasAction.', function() { expect( hasAction( 'notatest.action' ) ).toBe( 0 ); } ); -test( 'Verify doingFilter, didFilter and hasFilter.', function() { +test( 'Verify doingFilter, didFilter and hasFilter.', () => { let filterCalls = 0; addFilter( 'runtest.filter', arg => { @@ -371,7 +371,7 @@ test( 'Verify doingFilter, didFilter and hasFilter.', function() { expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); } ); -test( 'recursively calling a filter', function() { +test( 'recursively calling a filter', () => { addFilter( 'test.filter', value => { if ( value.length === 7 ) { return value; From 4e393d663db61cedcff4392f9d1e3a02f4798887 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 14:53:41 +0200 Subject: [PATCH 48/91] Add failing test for `currentFilter` with multiple filters running --- packages/hooks/src/test/index.test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 8adc2fe..6c6289b 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -382,3 +382,16 @@ test( 'recursively calling a filter', () => { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testXXX' ); } ); +test( 'current filter when multiple filters are running', () => { + addFilter( 'test.filter1', value => { + return applyFilters( 'test.filter2', value.concat( currentFilter() ) ); + } ); + + addFilter( 'test.filter2', value => { + return value.concat( currentFilter() ); + } ); + + expect( applyFilters( 'test.filter1', [ 'test' ] ) ).toBe( + [ 'test', 'test.filter1', 'test.filter2' ] + ); +} ); From 5d0513c7f2ea1b3f60b79959c91e537f50d12a1a Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 17:22:14 +0200 Subject: [PATCH 49/91] Fix `currentFilter` behavior --- packages/hooks/src/createCurrentHook.js | 27 +++++++++++++++++++++++++ packages/hooks/src/index.js | 5 +++-- packages/hooks/src/test/index.test.js | 2 +- 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 packages/hooks/src/createCurrentHook.js diff --git a/packages/hooks/src/createCurrentHook.js b/packages/hooks/src/createCurrentHook.js new file mode 100644 index 0000000..e5ff351 --- /dev/null +++ b/packages/hooks/src/createCurrentHook.js @@ -0,0 +1,27 @@ +/** + * Returns a function which, when invoked, will return the name of the + * currently running hook, or `null` if no hook of the given type is currently + * running. + * + * @param {Object} hooks Stored hooks, keyed by hook name. + * + * @return {Function} Function that returns the current hook. + */ +function createCurrentHook( hooks, returnFirstArg ) { + /** + * Returns the name of the currently running hook, or `null` if no hook of + * the given type is currently running. + * + * @return {?string} The name of the currently running hook, or + * `null` if no hook is currently running. + */ + return function currentHook() { + if ( ! hooks.__current || ! hooks.__current.length ) { + return null; + } + + return hooks.__current[ hooks.__current.length - 1 ]; + }; +} + +export default createCurrentHook; diff --git a/packages/hooks/src/index.js b/packages/hooks/src/index.js index 732aa09..93801c5 100644 --- a/packages/hooks/src/index.js +++ b/packages/hooks/src/index.js @@ -3,6 +3,7 @@ import createAddHook from './createAddHook'; import createRemoveHook from './createRemoveHook'; import createHasHook from './createHasHook'; import createRunHook from './createRunHook'; +import createCurrentHook from './createCurrentHook'; import createDoingHook from './createDoingHook'; import createDidHook from './createDidHook'; @@ -27,8 +28,8 @@ export const doAction = createRunHook( HOOKS.actions ); export const applyFilters = createRunHook( HOOKS.filters, true ); // Current action/filter functions. -export const currentAction = () => HOOKS.actions.__current[0] || null; -export const currentFilter = () => HOOKS.filters.__current[0] || null; +export const currentAction = createCurrentHook( HOOKS.actions ); +export const currentFilter = createCurrentHook( HOOKS.filters ); // Doing action/filter: true while a hook is being run. export const doingAction = createDoingHook( HOOKS.actions ); diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 6c6289b..e2ebcd2 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -391,7 +391,7 @@ test( 'current filter when multiple filters are running', () => { return value.concat( currentFilter() ); } ); - expect( applyFilters( 'test.filter1', [ 'test' ] ) ).toBe( + expect( applyFilters( 'test.filter1', [ 'test' ] ) ).toEqual( [ 'test', 'test.filter1', 'test.filter2' ] ); } ); From c11003c73d84a3b1c7fadafbd385ba997d5a16ba Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 17:23:06 +0200 Subject: [PATCH 50/91] Add more `currentFilter` test assertions --- packages/hooks/src/test/index.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index e2ebcd2..9d1da8c 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -391,7 +391,11 @@ test( 'current filter when multiple filters are running', () => { return value.concat( currentFilter() ); } ); + expect( currentFilter() ).toBe( null ); + expect( applyFilters( 'test.filter1', [ 'test' ] ) ).toEqual( [ 'test', 'test.filter1', 'test.filter2' ] ); + + expect( currentFilter() ).toBe( null ); } ); From ad098726b206f68ae08defd74c3b077276f15828 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 17:24:15 +0200 Subject: [PATCH 51/91] Remove `wp-hooks.js` entry point This logic needs to be generated by Webpack instead. Otherwise something like it will end up being duplicated and manually maintained for every module in this repo. --- packages/hooks/src/wp-hooks.js | 41 ---------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 packages/hooks/src/wp-hooks.js diff --git a/packages/hooks/src/wp-hooks.js b/packages/hooks/src/wp-hooks.js deleted file mode 100644 index 3f0461d..0000000 --- a/packages/hooks/src/wp-hooks.js +++ /dev/null @@ -1,41 +0,0 @@ -import HOOKS from './hooks'; -import { - addAction, - addFilter, - removeAction, - removeFilter, - removeAllActions, - removeAllFilters, - hasAction, - hasFilter, - doAction, - applyFilters, - currentAction, - currentFilter, - doingAction, - doingFilter, - didAction, - didFilter -} from './'; - -const hooks = { - addAction, - addFilter, - removeAction, - removeFilter, - removeAllActions, - removeAllFilters, - hasAction, - hasFilter, - doAction, - applyFilters, - currentAction, - currentFilter, - doingAction, - doingFilter, - didAction, - didFilter -} - -window.wp = window.wp || {}; -window.wp.hooks = hooks; From 0498ee8a0b2256c3fb9c87036f6555491579ce5b Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 17:42:29 +0200 Subject: [PATCH 52/91] Prevent hook names from starting with `__` This would break some of the library's internal functionality. --- packages/hooks/src/createAddHook.js | 5 +++++ packages/hooks/src/test/index.test.js | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 30ceda7..42bffca 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -19,6 +19,11 @@ function createAddHook( hooks ) { return; } + if ( /^__/.test( hookName ) ) { + console.error( 'The hook name cannot begin with `__`.' ); + return; + } + if ( typeof callback !== 'function' ) { console.error( 'The hook callback must be a function.' ); return; diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 9d1da8c..9c54c27 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -1,3 +1,5 @@ +/* eslint-disable no-console */ + /** * Internal dependencies */ @@ -60,6 +62,8 @@ function action_c() { window.actionValue += 'c'; } +const consoleErrorOriginal = console.error; + beforeEach( () => { window.actionValue = ''; // Reset state in between tests (clear all callbacks, `didAction` counts, @@ -70,6 +74,11 @@ beforeEach( () => { delete hooks[ k ]; } } ); + console.error = jest.fn(); +} ); + +afterEach( () => { + console.error = consoleErrorOriginal; } ); test( 'add and remove a filter', () => { @@ -89,6 +98,14 @@ test( 'add 2 filters in a row and run them', () => { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); } ); +test( 'cannot add filters named with __ prefix' , () => { + addFilter( '__test', () => null ); + expect( console.error ).toHaveBeenCalledWith( + 'The hook name cannot begin with `__`.' + ); + expect( applyFilters( '__test', 42 ) ).toBe( 42 ); +} ); + test( 'add 3 filters with different priorities and run them', () => { addFilter( 'test.filter', filter_a ); addFilter( 'test.filter', filter_b, 2 ); From 5b8c5f30fce4bf6d8ec0b2897d4ddd1b825b534d Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 17:45:10 +0200 Subject: [PATCH 53/91] Prevent running hooks with invalid names --- packages/hooks/src/createRunHook.js | 10 ++++++++++ packages/hooks/src/test/index.test.js | 10 ++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index d7af0eb..81f1ea6 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -19,6 +19,16 @@ function createRunHook( hooks, returnFirstArg ) { * @return {*} Return value of runner, if applicable. */ return function runHooks( hookName, ...args ) { + if ( typeof hookName !== 'string' ) { + console.error( 'The hook name must be a string.' ); + return; + } + + if ( /^__/.test( hookName ) ) { + console.error( 'The hook name cannot begin with `__`.' ); + return; + } + if ( ! hooks.hasOwnProperty( hookName ) ) { hooks[ hookName ] = { runs: 0, diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 9c54c27..d0a3097 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -98,12 +98,18 @@ test( 'add 2 filters in a row and run them', () => { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); } ); -test( 'cannot add filters named with __ prefix' , () => { +test( 'cannot add filters named with __ prefix', () => { addFilter( '__test', () => null ); expect( console.error ).toHaveBeenCalledWith( 'The hook name cannot begin with `__`.' ); - expect( applyFilters( '__test', 42 ) ).toBe( 42 ); +} ); + +test( 'cannot run filters named with __ prefix', () => { + expect( applyFilters( '__test', 42 ) ).toBe( undefined ); + expect( console.error ).toHaveBeenCalledWith( + 'The hook name cannot begin with `__`.' + ); } ); test( 'add 3 filters with different priorities and run them', () => { From 6327a542be626cad9d6e6ed97a2f0d15b8df7f5a Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 17:52:51 +0200 Subject: [PATCH 54/91] Add missing tests for error conditions --- packages/hooks/src/test/index.test.js | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index d0a3097..0c77bb1 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -98,6 +98,13 @@ test( 'add 2 filters in a row and run them', () => { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); } ); +test( 'cannot add filters with non-string names', () => { + addFilter( 42, () => null ); + expect( console.error ).toHaveBeenCalledWith( + 'The hook name must be a string.' + ); +} ); + test( 'cannot add filters named with __ prefix', () => { addFilter( '__test', () => null ); expect( console.error ).toHaveBeenCalledWith( @@ -105,6 +112,27 @@ test( 'cannot add filters named with __ prefix', () => { ); } ); +test( 'cannot add filters with non-function callbacks', () => { + addFilter( 'test', '42' ); + expect( console.error ).toHaveBeenCalledWith( + 'The hook callback must be a function.' + ); +} ); + +test( 'cannot add filters with non-numeric priorities', () => { + addFilter( 'test', () => null, '42' ); + expect( console.error ).toHaveBeenCalledWith( + 'If specified, the hook priority must be a number.' + ); +} ); + +test( 'cannot run filters with non-string names', () => { + expect( applyFilters( () => {}, 42 ) ).toBe( undefined ); + expect( console.error ).toHaveBeenCalledWith( + 'The hook name must be a string.' + ); +} ); + test( 'cannot run filters named with __ prefix', () => { expect( applyFilters( '__test', 42 ) ).toBe( undefined ); expect( console.error ).toHaveBeenCalledWith( From dd10eab04e9a66ba6289b9ce021f3625bfd346d8 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 18:02:18 +0200 Subject: [PATCH 55/91] Make hook removal functions return the number of hooks removed --- packages/hooks/src/createRemoveHook.js | 10 +++++++++- packages/hooks/src/test/index.test.js | 22 ++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index a136ca2..245e9e0 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -16,14 +16,19 @@ function createRemoveHook( hooks, removeAll ) { * @param {?Function} callback The specific callback to be removed. If * omitted (and `removeAll` is truthy), clears * all callbacks. + * + * @return {number} The number of callbacks removed. */ return function removeHook( hookName, callback ) { // Bail if no hooks exist by this name if ( ! hooks.hasOwnProperty( hookName ) ) { - return; + return 0; } + let handlersRemoved = 0; + if ( removeAll ) { + handlersRemoved = hooks[ hookName ].handlers.length; hooks[ hookName ] = { runs: hooks[ hookName ].runs, handlers: [], @@ -34,9 +39,12 @@ function createRemoveHook( hooks, removeAll ) { for ( let i = handlers.length - 1; i >= 0; i-- ) { if ( handlers[ i ].callback === callback ) { handlers.splice( i, 1 ); + handlersRemoved++; } } } + + return handlersRemoved; }; } diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 0c77bb1..3939eb0 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -83,8 +83,9 @@ afterEach( () => { test( 'add and remove a filter', () => { addFilter( 'test.filter', filter_a ); - removeAllFilters( 'test.filter' ); + expect( removeAllFilters( 'test.filter' ) ).toEqual( 1 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); + expect( removeAllFilters( 'test.filter' ) ).toEqual( 0 ); } ); test( 'add a filter and run it', () => { @@ -98,6 +99,11 @@ test( 'add 2 filters in a row and run them', () => { expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); } ); +test( 'remove a non-existent filter', () => { + expect( removeFilter( 'test.filter', filter_a ) ).toEqual( 0 ); + expect( removeAllFilters( 'test.filter' ) ).toEqual( 0 ); +} ); + test( 'cannot add filters with non-string names', () => { addFilter( 42, () => null ); expect( console.error ).toHaveBeenCalledWith( @@ -198,7 +204,7 @@ test( 'filters with the same and different priorities', () => { test( 'add and remove an action', () => { addAction( 'test.action', action_a ); - removeAllActions( 'test.action' ); + expect( removeAllActions( 'test.action' ) ).toEqual( 1 ); doAction( 'test.action' ); expect( window.actionValue ).toBe( '' ); } ); @@ -252,7 +258,7 @@ test( 'remove specific action callback', () => { addAction( 'test.action', action_b, 2 ); addAction( 'test.action', action_c, 8 ); - removeAction( 'test.action', action_b ); + expect( removeAction( 'test.action', action_b ) ).toEqual( 1 ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'ca' ); } ); @@ -262,7 +268,7 @@ test( 'remove all action callbacks', () => { addAction( 'test.action', action_b, 2 ); addAction( 'test.action', action_c, 8 ); - removeAllActions( 'test.action' ); + expect( removeAllActions( 'test.action' ) ).toEqual( 3 ); doAction( 'test.action' ); expect( window.actionValue ).toBe( '' ); } ); @@ -272,7 +278,7 @@ test( 'remove specific filter callback', () => { addFilter( 'test.filter', filter_b, 2 ); addFilter( 'test.filter', filter_c, 8 ); - removeFilter( 'test.filter', filter_b ); + expect( removeFilter( 'test.filter', filter_b ) ).toEqual( 1 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); } ); @@ -334,7 +340,7 @@ test( 'remove all filter callbacks', () => { addFilter( 'test.filter', filter_b, 2 ); addFilter( 'test.filter', filter_c, 8 ); - removeAllFilters( 'test.filter' ); + expect( removeAllFilters( 'test.filter' ) ).toEqual( 3 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); } ); @@ -379,7 +385,7 @@ test( 'Test doingAction, didAction and hasAction.', () => { expect( actionCalls ).toBe( 2 ); expect( didAction( 'test.action' ) ).toBe( 2 ); - removeAllActions( 'test.action' ); + expect( removeAllActions( 'test.action' ) ).toEqual( 1 ); // Verify state is reset appropriately. expect( doingAction( 'test.action' ) ).toBe( false ); @@ -416,7 +422,7 @@ test( 'Verify doingFilter, didFilter and hasFilter.', () => { expect( doingFilter( 'notatest.filter' ) ).toBe( false ); expect( currentFilter() ).toBe( null ); - removeAllFilters( 'runtest.filter' ); + expect( removeAllFilters( 'runtest.filter' ) ).toEqual( 1 ); expect( hasFilter( 'runtest.filter' ) ).toBe( 0 ); expect( didFilter( 'runtest.filter' ) ).toBe( 1 ); From 8be21e550b486e9d5650c972e9c3d9d8a27f28ab Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 18:05:15 +0200 Subject: [PATCH 56/91] Ensure that hook callbacks to remove are functions This will need to change later, but for now we should still make sure we validate our expected inputs strictly. --- packages/hooks/src/createRemoveHook.js | 7 ++++++- packages/hooks/src/test/index.test.js | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index 245e9e0..6e0a3cc 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -20,6 +20,11 @@ function createRemoveHook( hooks, removeAll ) { * @return {number} The number of callbacks removed. */ return function removeHook( hookName, callback ) { + if ( ! removeAll && typeof callback !== 'function' ) { + console.error( 'The hook callback to remove must be a function.' ); + return; + } + // Bail if no hooks exist by this name if ( ! hooks.hasOwnProperty( hookName ) ) { return 0; @@ -33,7 +38,7 @@ function createRemoveHook( hooks, removeAll ) { runs: hooks[ hookName ].runs, handlers: [], }; - } else if ( callback ) { + } else { // Try to find the specified callback to remove. const handlers = hooks[ hookName ].handlers; for ( let i = handlers.length - 1; i >= 0; i-- ) { diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 3939eb0..060f4f5 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -104,6 +104,13 @@ test( 'remove a non-existent filter', () => { expect( removeAllFilters( 'test.filter' ) ).toEqual( 0 ); } ); +test( 'remove an invalid callback from a filter', () => { + expect( removeFilter( 'test.filter', 42 ) ).toEqual( undefined ); + expect( console.error ).toHaveBeenCalledWith( + 'The hook callback to remove must be a function.' + ); +} ); + test( 'cannot add filters with non-string names', () => { addFilter( 42, () => null ); expect( console.error ).toHaveBeenCalledWith( From 70b3ebc3c417cddc6f718cbb6047e820ae4eabef Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 18:06:47 +0200 Subject: [PATCH 57/91] Test running a filter with no callbacks --- packages/hooks/src/test/index.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 060f4f5..5f4ef3c 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -81,6 +81,10 @@ afterEach( () => { console.error = consoleErrorOriginal; } ); +test( 'run a filter with no callbacks', () => { + expect( applyFilters( 'test.filter', 42 ) ).toEqual( 42 ); +} ); + test( 'add and remove a filter', () => { addFilter( 'test.filter', filter_a ); expect( removeAllFilters( 'test.filter' ) ).toEqual( 1 ); From a3b49019a14aa7849bc178ef60471239d072eab4 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 18:40:09 +0200 Subject: [PATCH 58/91] `doAction` should return `undefined` --- packages/hooks/src/createRunHook.js | 2 -- packages/hooks/src/test/index.test.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index 81f1ea6..74a12f7 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -68,8 +68,6 @@ function createRunHook( hooks, returnFirstArg ) { if ( returnFirstArg ) { return maybeReturnValue; - } else { - return false; } }; } diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 5f4ef3c..c56cf05 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -216,7 +216,7 @@ test( 'filters with the same and different priorities', () => { test( 'add and remove an action', () => { addAction( 'test.action', action_a ); expect( removeAllActions( 'test.action' ) ).toEqual( 1 ); - doAction( 'test.action' ); + expect( doAction( 'test.action' ) ).toBe( undefined ); expect( window.actionValue ).toBe( '' ); } ); From 6653227ec4ce9b4f8087e8b81d3c5283d9e46d3c Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 19:05:45 +0200 Subject: [PATCH 59/91] Add failing test for recursive filters --- packages/hooks/src/test/index.test.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index c56cf05..bd9c3e7 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -467,3 +467,19 @@ test( 'current filter when multiple filters are running', () => { expect( currentFilter() ).toBe( null ); } ); + +test( 'adding and removing filters with recursion', () => { + function removeRecurseAndAdd2( val ) { + expect( removeFilter( 'remove_and_add', removeRecurseAndAdd2 ) ).toEqual( 1 ); + val += '-' + applyFilters( 'remove_and_add', '' ) + '-'; + addFilter( 'remove_and_add', removeRecurseAndAdd2, 11 ); + return val + '2'; + } + + addFilter( 'remove_and_add', val => val + '1', 11 ); + addFilter( 'remove_and_add', removeRecurseAndAdd2, 11 ); + addFilter( 'remove_and_add', val => val + '3', 11 ); + addFilter( 'remove_and_add', val => val + '4', 12 ); + + expect( applyFilters( 'remove_and_add', '' ) ).toEqual( '1-134-234' ); +} ); From 2e9b96ea166fe4ee00704efa93d0951197b89437 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 19:56:55 +0200 Subject: [PATCH 60/91] First attempt at handling adding/removing callbacks during execution Also allows recursion. --- packages/hooks/src/createAddHook.js | 11 +++++++++++ packages/hooks/src/createCurrentHook.js | 2 +- packages/hooks/src/createDoingHook.js | 2 +- packages/hooks/src/createRemoveHook.js | 12 ++++++++++++ packages/hooks/src/createRunHook.js | 26 ++++++++++++------------- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 42bffca..c5aceaa 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -49,6 +49,17 @@ function createAddHook( hooks ) { } // Insert (or append) the new hook. handlers.splice( i, 0, handler ); + // We may also be currently executing this hook. If the callback + // we're adding would come after the current callback, there's no + // problem; otherwise we need to increase the execution index of + // any other runs by 1 to account for the added element. + ( hooks.__current || [] ) + .filter( hookInfo => hookInfo.name === hookName ) + .forEach( hookInfo => { + if ( hookInfo.currentIndex >= i ) { + hookInfo.currentIndex++; + } + } ); } else { // This is the first hook of its type. hooks[ hookName ] = { diff --git a/packages/hooks/src/createCurrentHook.js b/packages/hooks/src/createCurrentHook.js index e5ff351..2df265f 100644 --- a/packages/hooks/src/createCurrentHook.js +++ b/packages/hooks/src/createCurrentHook.js @@ -20,7 +20,7 @@ function createCurrentHook( hooks, returnFirstArg ) { return null; } - return hooks.__current[ hooks.__current.length - 1 ]; + return hooks.__current[ hooks.__current.length - 1 ].name; }; } diff --git a/packages/hooks/src/createDoingHook.js b/packages/hooks/src/createDoingHook.js index 860b657..d27f2fa 100644 --- a/packages/hooks/src/createDoingHook.js +++ b/packages/hooks/src/createDoingHook.js @@ -24,7 +24,7 @@ function createDoingHook( hooks ) { // Return the __current hook. return hooks.__current[0] - ? hookName === hooks.__current[0] + ? hookName === hooks.__current[0].name : false; }; } diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index 6e0a3cc..8e92b94 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -45,6 +45,18 @@ function createRemoveHook( hooks, removeAll ) { if ( handlers[ i ].callback === callback ) { handlers.splice( i, 1 ); handlersRemoved++; + // This callback may also be part of a hook that is + // currently executing. If the callback we're removing + // comes after the current callback, there's no problem; + // otherwise we need to decrease the execution index of any + // other runs by 1 to account for the removed element. + ( hooks.__current || [] ) + .filter( hookInfo => hookInfo.name === hookName ) + .forEach( hookInfo => { + if ( hookInfo.currentIndex >= i ) { + hookInfo.currentIndex--; + } + } ); } } } diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index 74a12f7..31dccd3 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -44,25 +44,25 @@ function createRunHook( hooks, returnFirstArg ) { : undefined; } + const hookInfo = { + name: hookName, + currentIndex: 0, + }; + hooks.__current = hooks.__current || []; - hooks.__current.push( hookName ); + hooks.__current.push( hookInfo ); hooks[ hookName ].runs++; let maybeReturnValue = args[ 0 ]; - handlers.forEach( handler => { - if ( handler.callback !== hooks.currentCallback ) { - - // Prevent hook recursion. - hooks.currentCallback = handler.callback; - maybeReturnValue = handler.callback.apply( null, args ); - hooks.currentCallback = false; - - if ( returnFirstArg ) { - args[ 0 ] = maybeReturnValue; - } + while ( hookInfo.currentIndex < handlers.length ) { + const handler = handlers[ hookInfo.currentIndex ]; + maybeReturnValue = handler.callback.apply( null, args ); + if ( returnFirstArg ) { + args[ 0 ] = maybeReturnValue; } - } ); + hookInfo.currentIndex++; + } hooks.__current.pop(); From 54f70c1e3787a675253a59ff554e93bb4fe276ac Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 19:57:35 +0200 Subject: [PATCH 61/91] Make the filter adding/removing/recursion test pass --- packages/hooks/src/test/index.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index bd9c3e7..e26d90d 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -472,14 +472,14 @@ test( 'adding and removing filters with recursion', () => { function removeRecurseAndAdd2( val ) { expect( removeFilter( 'remove_and_add', removeRecurseAndAdd2 ) ).toEqual( 1 ); val += '-' + applyFilters( 'remove_and_add', '' ) + '-'; - addFilter( 'remove_and_add', removeRecurseAndAdd2, 11 ); + addFilter( 'remove_and_add', removeRecurseAndAdd2, 10 ); return val + '2'; } addFilter( 'remove_and_add', val => val + '1', 11 ); - addFilter( 'remove_and_add', removeRecurseAndAdd2, 11 ); - addFilter( 'remove_and_add', val => val + '3', 11 ); - addFilter( 'remove_and_add', val => val + '4', 12 ); + addFilter( 'remove_and_add', removeRecurseAndAdd2, 12 ); + addFilter( 'remove_and_add', val => val + '3', 13 ); + addFilter( 'remove_and_add', val => val + '4', 14 ); expect( applyFilters( 'remove_and_add', '' ) ).toEqual( '1-134-234' ); } ); From afa92ea9a97876be19140b4e0c5515048d681830 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 20:36:08 +0200 Subject: [PATCH 62/91] Minor style and speed improvement --- packages/hooks/src/createAddHook.js | 12 +++++------- packages/hooks/src/createRemoveHook.js | 12 +++++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index c5aceaa..36ec8a6 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -53,13 +53,11 @@ function createAddHook( hooks ) { // we're adding would come after the current callback, there's no // problem; otherwise we need to increase the execution index of // any other runs by 1 to account for the added element. - ( hooks.__current || [] ) - .filter( hookInfo => hookInfo.name === hookName ) - .forEach( hookInfo => { - if ( hookInfo.currentIndex >= i ) { - hookInfo.currentIndex++; - } - } ); + ( hooks.__current || [] ).forEach( hookInfo => { + if ( hookInfo.name === hookName && hookInfo.currentIndex >= i ) { + hookInfo.currentIndex++; + } + } ); } else { // This is the first hook of its type. hooks[ hookName ] = { diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index 8e92b94..6cb8d47 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -50,13 +50,11 @@ function createRemoveHook( hooks, removeAll ) { // comes after the current callback, there's no problem; // otherwise we need to decrease the execution index of any // other runs by 1 to account for the removed element. - ( hooks.__current || [] ) - .filter( hookInfo => hookInfo.name === hookName ) - .forEach( hookInfo => { - if ( hookInfo.currentIndex >= i ) { - hookInfo.currentIndex--; - } - } ); + ( hooks.__current || [] ).forEach( hookInfo => { + if ( hookInfo.name === hookName && hookInfo.currentIndex >= i ) { + hookInfo.currentIndex--; + } + } ); } } } From 0919ab9eef6bdb7d8cdaf6f7d6c44b4c12e67960 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Mon, 24 Jul 2017 20:50:30 +0200 Subject: [PATCH 63/91] Add missing tests --- packages/hooks/src/test/index.test.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index e26d90d..7b3cafc 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -264,6 +264,33 @@ test( 'fire action multiple times', () => { doAction( 'test.action' ); } ); +test( 'add a filter before the one currently executing', () => { + addFilter( 'test.filter', val => { + addFilter( 'test.filter', val => val + 'a', 1 ); + return val + 'b'; + }, 2 ); + + expect( applyFilters( 'test.filter', 'test_' ) ).toEqual( 'test_b' ); +} ); + +test( 'add a filter after the one currently executing', () => { + addFilter( 'test.filter', val => { + addFilter( 'test.filter', val => val + 'b', 2 ); + return val + 'a'; + }, 1 ); + + expect( applyFilters( 'test.filter', 'test_' ) ).toEqual( 'test_ab' ); +} ); + +test( 'add a filter immediately after the one currently executing', () => { + addFilter( 'test.filter', val => { + addFilter( 'test.filter', val => val + 'b', 1 ); + return val + 'a'; + }, 1 ); + + expect( applyFilters( 'test.filter', 'test_' ) ).toEqual( 'test_ab' ); +} ); + test( 'remove specific action callback', () => { addAction( 'test.action', action_a ); addAction( 'test.action', action_b, 2 ); From 90942a7f67881100917728f0870530182d54f3a1 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Tue, 1 Aug 2017 09:18:53 -0400 Subject: [PATCH 64/91] Add a centralized webpack folder based build for packages --- webpack.config.js | 59 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/webpack.config.js b/webpack.config.js index 5faefb9..7b8e8c6 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,17 +1,46 @@ +const entryPointNames = [ + 'hooks', + 'url', +]; + +const externals = { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/server': 'ReactDOMServer', + tinymce: 'tinymce', + moment: 'moment', +}; + +entryPointNames.forEach( entryPointName => { + externals[ entryPointName ] = { + 'this': [ 'wp', entryPointName ], + }; +} ); + +const config = entryPointNames.reduce( ( memo, entryPointName ) => { + memo[ entryPointName ] = './packages/' + entryPointName + '/src/index.js'; + return memo; + }, {} ); + + module.exports = { - entry: './packages/hooks/src/wp-hooks.js', - output: { - filename: './packages/hooks/wp-core/wp-hooks.js' - }, - module: { - rules: [ - { - test: /\.js$/, - exclude: /(node_modules)/, - use: { - loader: 'babel-loader' - } - } - ] - } + entry: config, + externals, + output: { + filename: 'build/[name]/index.js', + path: __dirname, + library: [ 'wp', '[name]' ], + libraryTarget: 'this', + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /(node_modules)/, + use: { + loader: 'babel-loader' + } + } + ] + } } From e2547d9e7d16ee1a651654e9f446e6a4c537b0b0 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Tue, 8 Aug 2017 11:06:25 -0600 Subject: [PATCH 65/91] Add check: the hook name can only contain numbers, letters and underscores --- packages/hooks/src/createRunHook.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index 31dccd3..3282bd4 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -29,6 +29,11 @@ function createRunHook( hooks, returnFirstArg ) { return; } + if ( ! /^[a-z][a-z0-9_]*$/.test( hookName ) ) { + console.error( 'The hook name can only contain numbers, letters and underscores.' ); + return; + } + if ( ! hooks.hasOwnProperty( hookName ) ) { hooks[ hookName ] = { runs: 0, From cefc79a2611e6c4d1d5b4c0ee4862282d5490e56 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Tue, 8 Aug 2017 11:06:50 -0600 Subject: [PATCH 66/91] use yoda conditional as per wp coding standards --- packages/hooks/src/createRunHook.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index 3282bd4..754a73e 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -19,7 +19,7 @@ function createRunHook( hooks, returnFirstArg ) { * @return {*} Return value of runner, if applicable. */ return function runHooks( hookName, ...args ) { - if ( typeof hookName !== 'string' ) { + if ( 'string' !== typeof hookName ) { console.error( 'The hook name must be a string.' ); return; } From ca955004dc468aa2e2c9578616f5c4f0ad082329 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 08:53:54 -0400 Subject: [PATCH 67/91] removeHook - accept a namespace parameter and use it to identify item for removal --- packages/hooks/src/createRemoveHook.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index 6cb8d47..3eda8b1 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -12,18 +12,12 @@ function createRemoveHook( hooks, removeAll ) { * Removes the specified callback (or all callbacks) from the hook with a * given name. * - * @param {string} hookName The name of the hook to modify. - * @param {?Function} callback The specific callback to be removed. If - * omitted (and `removeAll` is truthy), clears - * all callbacks. + * @param {string} hookName The name of the hook to modify. + * @param {string} namespace The unique namespace identifying the callback in the form `my-plugin-slug/functionDescription`. * - * @return {number} The number of callbacks removed. + * @return {number} The number of callbacks removed. */ - return function removeHook( hookName, callback ) { - if ( ! removeAll && typeof callback !== 'function' ) { - console.error( 'The hook callback to remove must be a function.' ); - return; - } + return function removeHook( hookName, namespace ) { // Bail if no hooks exist by this name if ( ! hooks.hasOwnProperty( hookName ) ) { @@ -42,7 +36,9 @@ function createRemoveHook( hooks, removeAll ) { // Try to find the specified callback to remove. const handlers = hooks[ hookName ].handlers; for ( let i = handlers.length - 1; i >= 0; i-- ) { - if ( handlers[ i ].callback === callback ) { + if ( + handlers[ i ].namespace === namespace + ) { handlers.splice( i, 1 ); handlersRemoved++; // This callback may also be part of a hook that is From cc8b852078dbd5b9fbfbfcf0f086c861fb2e0f41 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 08:54:22 -0400 Subject: [PATCH 68/91] addHook - The hook name can only contain numbers, letters and underscores --- packages/hooks/src/createAddHook.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 36ec8a6..c466fdd 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -24,6 +24,11 @@ function createAddHook( hooks ) { return; } + if ( ! /^[a-z][a-z0-9_]*$/.test( hookName ) ) { + console.error( 'The hook name can only contain numbers, letters and underscores.' ); + return; + } + if ( typeof callback !== 'function' ) { console.error( 'The hook callback must be a function.' ); return; From 06ddd95a12f9663a0d0340479a9751f0158ee564 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 08:58:46 -0400 Subject: [PATCH 69/91] addHook - accept a namespace parameter and store in handler data --- packages/hooks/src/createAddHook.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index c466fdd..500c20b 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -9,12 +9,13 @@ function createAddHook( hooks ) { /** * Adds the hook to the appropriate hooks container. * - * @param {string} hookName Name of hook to add - * @param {Function} callback Function to call when the hook is run - * @param {?number} priority Priority of this hook (default=10) + * @param {string} hookName Name of hook to add + * @param {string} namespace The unique namespace identifying the callback in the form `my-plugin-slug/functionDescription`. + * @param {Function} callback Function to call when the hook is run + * @param {?number} priority Priority of this hook (default=10) */ - return function addHook( hookName, callback, priority = 10 ) { - if ( typeof hookName !== 'string' ) { + return function addHook( hookName, namespace, callback, priority = 10 ) { + if ( 'string' !== typeof hookName ) { console.error( 'The hook name must be a string.' ); return; } @@ -40,7 +41,7 @@ function createAddHook( hooks ) { return; } - const handler = { callback, priority }; + const handler = { callback, priority, namespace }; if ( hooks.hasOwnProperty( hookName ) ) { // Find the correct insert index of the new hook. From edd46d05071fe0a47fb198c6a29ef69f62e3dade Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 09:00:06 -0400 Subject: [PATCH 70/91] Use some Yoda conditionals --- packages/hooks/src/createAddHook.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 500c20b..442db78 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -30,13 +30,13 @@ function createAddHook( hooks ) { return; } - if ( typeof callback !== 'function' ) { + if ( 'function' !== typeof callback ) { console.error( 'The hook callback must be a function.' ); return; } // Validate numeric priority - if ( typeof priority !== 'number' ) { + if ( 'number' !== typeof priority ) { console.error( 'If specified, the hook priority must be a number.' ); return; } From 77be5ed65b4baaa75825c2f4c0dc5e41fbebc2d1 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 09:04:06 -0400 Subject: [PATCH 71/91] Ensure the passed namespace is a string of the form `my-plugin-slug/functionDescription --- packages/hooks/src/createAddHook.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 442db78..0b3aa49 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -30,6 +30,16 @@ function createAddHook( hooks ) { return; } + if ( 'string' !== typeof namespace ) { + console.error( 'The namespace must be a string.' ); + return; + } + + if ( ! /^.*\/.*$/.test( namespace ) ) { + console.error( 'The namespace must take the form `my-plugin-slug/functionDescription' ); + return; + } + if ( 'function' !== typeof callback ) { console.error( 'The hook callback must be a function.' ); return; From 2c62cdc060bb366b661eb406bd58f3a3604f4030 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 09:11:57 -0400 Subject: [PATCH 72/91] Add a build-modules command to run webpack --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 564f8a3..e7bef5d 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "scripts": { "build-clean": "rimraf ./packages/*/build ./packages/*/build-browser ./packages/*/build-module", "build": "node ./scripts/build.js", + "build-modules": "webpack --progress -p", "test": "jest", "test:coverage": "jest --coverage", "test:coverage-ci": "jest --coverage && coveralls < coverage/lcov.info", From 581e7154a71de7dace1a9032330bbcb4b3b55e31 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 10:32:42 -0400 Subject: [PATCH 73/91] Add a `validateNamespace` helper, centralizing namespace checks --- packages/hooks/src/validateNamespace.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 packages/hooks/src/validateNamespace.js diff --git a/packages/hooks/src/validateNamespace.js b/packages/hooks/src/validateNamespace.js new file mode 100644 index 0000000..f8d3e70 --- /dev/null +++ b/packages/hooks/src/validateNamespace.js @@ -0,0 +1,23 @@ +/** + * Validate a namespace. + * + * @param {string} namespace The namespace to validate. + * + * @return {bool} Whether the namespace is valid. + */ +function validateNamespace( namespace ) { + + if ( 'string' !== typeof namespace ) { + console.error( 'The namespace must be a string.' ); + return false; + } + + if ( ! /^.*\/.*$/.test( namespace ) ) { + console.error( 'The namespace must take the form `my-plugin-slug/functionDescription' ); + return false; + } + + return true; +} + +export default validateNamespace; From 4c7f252f998f9533217582fc065c25e73a22d0d8 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 10:33:03 -0400 Subject: [PATCH 74/91] Add a `validateHookName` helper, centralizing hookName validation --- packages/hooks/src/validateHookName.js | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 packages/hooks/src/validateHookName.js diff --git a/packages/hooks/src/validateHookName.js b/packages/hooks/src/validateHookName.js new file mode 100644 index 0000000..7af1a26 --- /dev/null +++ b/packages/hooks/src/validateHookName.js @@ -0,0 +1,28 @@ +/** + * Validate a hook name. + * + * @param {string} hookName The hook name to validate. + * + * @return {bool} Whether the hook name is valid. + */ +function validateHookName( hookName ) { + + if ( 'string' !== typeof hookName ) { + console.error( 'The hook name must be a string.' ); + return false; + } + + if ( /^__/.test( hookName ) ) { + console.error( 'The hook name cannot begin with `__`.' ); + return false; + } + + if ( ! /^[a-z][a-z0-9_.-]*$/.test( hookName ) ) { + console.error( 'The hook name can only contain numbers, letters, dashes, periods and underscores.' ); + return false; + } + + return true; +} + +export default validateHookName; From ef069586d081b86614cf15b495b00e33afedd292 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 10:34:25 -0400 Subject: [PATCH 75/91] Use new hookName and namespace validation helpers throughout generators for each hookName/namespace use --- packages/hooks/src/createAddHook.js | 23 +++++------------------ packages/hooks/src/createDidHook.js | 7 +++++++ packages/hooks/src/createRemoveHook.js | 15 +++++++++++++-- packages/hooks/src/createRunHook.js | 14 +++----------- 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 0b3aa49..6162d06 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -1,3 +1,6 @@ +import validateNamespace from './validateNamespace.js'; +import validateHookName from './validateHookName.js'; + /** * Returns a function which, when invoked, will add a hook. * @@ -15,28 +18,12 @@ function createAddHook( hooks ) { * @param {?number} priority Priority of this hook (default=10) */ return function addHook( hookName, namespace, callback, priority = 10 ) { - if ( 'string' !== typeof hookName ) { - console.error( 'The hook name must be a string.' ); - return; - } - - if ( /^__/.test( hookName ) ) { - console.error( 'The hook name cannot begin with `__`.' ); - return; - } - - if ( ! /^[a-z][a-z0-9_]*$/.test( hookName ) ) { - console.error( 'The hook name can only contain numbers, letters and underscores.' ); - return; - } - if ( 'string' !== typeof namespace ) { - console.error( 'The namespace must be a string.' ); + if ( ! validateHookName( hookName ) ) { return; } - if ( ! /^.*\/.*$/.test( namespace ) ) { - console.error( 'The namespace must take the form `my-plugin-slug/functionDescription' ); + if ( ! validateNamespace( namespace ) ) { return; } diff --git a/packages/hooks/src/createDidHook.js b/packages/hooks/src/createDidHook.js index cdbcee8..9871b10 100644 --- a/packages/hooks/src/createDidHook.js +++ b/packages/hooks/src/createDidHook.js @@ -1,3 +1,5 @@ +import validateHookName from './validateHookName.js'; + /** * Returns a function which, when invoked, will return the number of times a * hook has been called. @@ -15,6 +17,11 @@ function createDidHook( hooks ) { * @return {number} The number of times the hook has run. */ return function didHook( hookName ) { + + if ( ! validateHookName( hookName ) ) { + return; + } + return hooks.hasOwnProperty( hookName ) && hooks[ hookName ].runs ? hooks[ hookName ].runs : 0; diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index 3eda8b1..9383cc1 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -1,16 +1,19 @@ +import validateNamespace from './validateNamespace.js'; +import validateHookName from './validateHookName.js'; + /** * Returns a function which, when invoked, will remove a specified hook or all * hooks by the given name. * * @param {Object} hooks Stored hooks, keyed by hook name. - * @param {bool} removeAll Whether to remove all hooked callbacks. + * @param {bool} removeAll Whether to remove all callbacks for a hookName, without regard to namespace. Used to create `removeAll*` functions. * * @return {Function} Function that removes hooks. */ function createRemoveHook( hooks, removeAll ) { /** * Removes the specified callback (or all callbacks) from the hook with a - * given name. + * given hookName and namespace. * * @param {string} hookName The name of the hook to modify. * @param {string} namespace The unique namespace identifying the callback in the form `my-plugin-slug/functionDescription`. @@ -19,6 +22,14 @@ function createRemoveHook( hooks, removeAll ) { */ return function removeHook( hookName, namespace ) { + if ( ! validateHookName( hookName ) ) { + return; + } + + if ( ! removeAll && ! validateNamespace( namespace ) ) { + return; + } + // Bail if no hooks exist by this name if ( ! hooks.hasOwnProperty( hookName ) ) { return 0; diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js index 754a73e..ac04fe7 100644 --- a/packages/hooks/src/createRunHook.js +++ b/packages/hooks/src/createRunHook.js @@ -1,3 +1,5 @@ +import validateHookName from './validateHookName.js'; + /** * Returns a function which, when invoked, will execute all callbacks * registered to a hook of the specified type, optionally returning the final @@ -19,18 +21,8 @@ function createRunHook( hooks, returnFirstArg ) { * @return {*} Return value of runner, if applicable. */ return function runHooks( hookName, ...args ) { - if ( 'string' !== typeof hookName ) { - console.error( 'The hook name must be a string.' ); - return; - } - - if ( /^__/.test( hookName ) ) { - console.error( 'The hook name cannot begin with `__`.' ); - return; - } - if ( ! /^[a-z][a-z0-9_]*$/.test( hookName ) ) { - console.error( 'The hook name can only contain numbers, letters and underscores.' ); + if ( ! validateHookName( hookName ) ) { return; } From 319a023fe77cfefea88d69d595f777fe6053c743 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 10:59:41 -0400 Subject: [PATCH 76/91] Update tests to use namespaces --- packages/hooks/src/test/index.test.js | 198 +++++++++++++------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 7b3cafc..f08fe77 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -36,17 +36,17 @@ function filter_c( str ) { } function filter_b_removes_self( str ) { - removeFilter( 'test.filter', filter_b_removes_self ); + removeFilter( 'test.filter', 'my_plugin/my_callback_filter_b_removes_self' ); return str + 'b'; } function filter_removes_b( str ) { - removeFilter( 'test.filter', filter_b ); + removeFilter( 'test.filter', 'my_plugin/my_callback_filter_b' ); return str; } function filter_removes_c( str ) { - removeFilter( 'test.filter', filter_c ); + removeFilter( 'test.filter', 'my_plugin/my_callback_filter_c' ); return str; } @@ -86,58 +86,58 @@ test( 'run a filter with no callbacks', () => { } ); test( 'add and remove a filter', () => { - addFilter( 'test.filter', filter_a ); + addFilter( 'test.filter', 'my_plugin/my_callback', filter_a ); expect( removeAllFilters( 'test.filter' ) ).toEqual( 1 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); expect( removeAllFilters( 'test.filter' ) ).toEqual( 0 ); } ); test( 'add a filter and run it', () => { - addFilter( 'test.filter', filter_a ); + addFilter( 'test.filter', 'my_plugin/my_callback', filter_a ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testa' ); } ); test( 'add 2 filters in a row and run them', () => { - addFilter( 'test.filter', filter_a ); - addFilter( 'test.filter', filter_b ); + addFilter( 'test.filter', 'my_plugin/my_callback', filter_a ); + addFilter( 'test.filter', 'my_plugin/my_callback', filter_b ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); } ); test( 'remove a non-existent filter', () => { - expect( removeFilter( 'test.filter', filter_a ) ).toEqual( 0 ); + expect( removeFilter( 'test.filter', 'my_plugin/my_callback', filter_a ) ).toEqual( 0 ); expect( removeAllFilters( 'test.filter' ) ).toEqual( 0 ); } ); -test( 'remove an invalid callback from a filter', () => { +test( 'remove an invalid namespace from a filter', () => { expect( removeFilter( 'test.filter', 42 ) ).toEqual( undefined ); expect( console.error ).toHaveBeenCalledWith( - 'The hook callback to remove must be a function.' + 'The namespace must be a string.' ); } ); test( 'cannot add filters with non-string names', () => { - addFilter( 42, () => null ); + addFilter( 42, 'my_plugin/my_callback', () => null ); expect( console.error ).toHaveBeenCalledWith( 'The hook name must be a string.' ); } ); test( 'cannot add filters named with __ prefix', () => { - addFilter( '__test', () => null ); + addFilter( '__test', 'my_plugin/my_callback', () => null ); expect( console.error ).toHaveBeenCalledWith( 'The hook name cannot begin with `__`.' ); } ); test( 'cannot add filters with non-function callbacks', () => { - addFilter( 'test', '42' ); + addFilter( 'test', 'my_plugin/my_callback', '42' ); expect( console.error ).toHaveBeenCalledWith( 'The hook callback must be a function.' ); } ); test( 'cannot add filters with non-numeric priorities', () => { - addFilter( 'test', () => null, '42' ); + addFilter( 'test', 'my_plugin/my_callback', () => null, '42' ); expect( console.error ).toHaveBeenCalledWith( 'If specified, the hook priority must be a number.' ); @@ -158,9 +158,9 @@ test( 'cannot run filters named with __ prefix', () => { } ); test( 'add 3 filters with different priorities and run them', () => { - addFilter( 'test.filter', filter_a ); - addFilter( 'test.filter', filter_b, 2 ); - addFilter( 'test.filter', filter_c, 8 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 2 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 8 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testbca' ); } ); @@ -175,34 +175,34 @@ test( 'filters with the same and different priorities', () => { } ); } ); - addFilter( 'test_order', callbacks.fn_3a, 3 ); - addFilter( 'test_order', callbacks.fn_3b, 3 ); - addFilter( 'test_order', callbacks.fn_3c, 3 ); - addFilter( 'test_order', callbacks.fn_2a, 2 ); - addFilter( 'test_order', callbacks.fn_2b, 2 ); - addFilter( 'test_order', callbacks.fn_2c, 2 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_3a', callbacks.fn_3a, 3 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_3b', callbacks.fn_3b, 3 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_3c', callbacks.fn_3c, 3 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_2a', callbacks.fn_2a, 2 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_2b', callbacks.fn_2b, 2 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_2c', callbacks.fn_2c, 2 ); expect( applyFilters( 'test_order', [] ) ).toEqual( [ '2a', '2b', '2c', '3a', '3b', '3c' ] ); - removeFilter( 'test_order', callbacks.fn_2b ); - removeFilter( 'test_order', callbacks.fn_3a ); + removeFilter( 'test_order', 'my_plugin/my_callback_fn_2b', callbacks.fn_2b ); + removeFilter( 'test_order', 'my_plugin/my_callback_fn_3a', callbacks.fn_3a ); expect( applyFilters( 'test_order', [] ) ).toEqual( [ '2a', '2c', '3b', '3c' ] ); - addFilter( 'test_order', callbacks.fn_4a, 4 ); - addFilter( 'test_order', callbacks.fn_4b, 4 ); - addFilter( 'test_order', callbacks.fn_1a, 1 ); - addFilter( 'test_order', callbacks.fn_4c, 4 ); - addFilter( 'test_order', callbacks.fn_1b, 1 ); - addFilter( 'test_order', callbacks.fn_3d, 3 ); - addFilter( 'test_order', callbacks.fn_4d, 4 ); - addFilter( 'test_order', callbacks.fn_1c, 1 ); - addFilter( 'test_order', callbacks.fn_2d, 2 ); - addFilter( 'test_order', callbacks.fn_1d, 1 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_4a', callbacks.fn_4a, 4 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_4b', callbacks.fn_4b, 4 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_1a', callbacks.fn_1a, 1 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_4c', callbacks.fn_4c, 4 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_1b', callbacks.fn_1b, 1 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_3d', callbacks.fn_3d, 3 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_4d', callbacks.fn_4d, 4 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_1c', callbacks.fn_1c, 1 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_2d', callbacks.fn_2d, 2 ); + addFilter( 'test_order', 'my_plugin/my_callback_fn_1d', callbacks.fn_1d, 1 ); expect( applyFilters( 'test_order', [] ) ).toEqual( [ // all except 2b and 3a, which we removed earlier @@ -214,29 +214,29 @@ test( 'filters with the same and different priorities', () => { } ); test( 'add and remove an action', () => { - addAction( 'test.action', action_a ); + addAction( 'test.action', 'my_plugin/my_callback', action_a ); expect( removeAllActions( 'test.action' ) ).toEqual( 1 ); expect( doAction( 'test.action' ) ).toBe( undefined ); expect( window.actionValue ).toBe( '' ); } ); test( 'add an action and run it', () => { - addAction( 'test.action', action_a ); + addAction( 'test.action', 'my_plugin/my_callback', action_a ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'a' ); } ); test( 'add 2 actions in a row and then run them', () => { - addAction( 'test.action', action_a ); - addAction( 'test.action', action_b ); + addAction( 'test.action', 'my_plugin/my_callback', action_a ); + addAction( 'test.action', 'my_plugin/my_callback', action_b ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'ab' ); } ); test( 'add 3 actions with different priorities and run them', () => { - addAction( 'test.action', action_a ); - addAction( 'test.action', action_b, 2 ); - addAction( 'test.action', action_c, 8 ); + addAction( 'test.action', 'my_plugin/my_callback', action_a ); + addAction( 'test.action', 'my_plugin/my_callback', action_b, 2 ); + addAction( 'test.action', 'my_plugin/my_callback', action_c, 8 ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'bca' ); } ); @@ -245,7 +245,7 @@ test( 'pass in two arguments to an action', () => { const arg1 = { a: 10 }; const arg2 = { b: 20 }; - addAction( 'test.action', ( a, b ) => { + addAction( 'test.action', 'my_plugin/my_callback', ( a, b ) => { expect( a ).toBe( arg1 ); expect( b ).toBe( arg2 ); } ); @@ -259,14 +259,14 @@ test( 'fire action multiple times', () => { expect( true ).toBe( true ); }; - addAction( 'test.action', func ); + addAction( 'test.action', 'my_plugin/my_callback', func ); doAction( 'test.action' ); doAction( 'test.action' ); } ); test( 'add a filter before the one currently executing', () => { - addFilter( 'test.filter', val => { - addFilter( 'test.filter', val => val + 'a', 1 ); + addFilter( 'test.filter', 'my_plugin/my_callback', val => { + addFilter( 'test.filter', 'my_plugin/my_callback', val => val + 'a', 1 ); return val + 'b'; }, 2 ); @@ -274,8 +274,8 @@ test( 'add a filter before the one currently executing', () => { } ); test( 'add a filter after the one currently executing', () => { - addFilter( 'test.filter', val => { - addFilter( 'test.filter', val => val + 'b', 2 ); + addFilter( 'test.filter', 'my_plugin/my_callback', val => { + addFilter( 'test.filter', 'my_plugin/my_callback', val => val + 'b', 2 ); return val + 'a'; }, 1 ); @@ -283,8 +283,8 @@ test( 'add a filter after the one currently executing', () => { } ); test( 'add a filter immediately after the one currently executing', () => { - addFilter( 'test.filter', val => { - addFilter( 'test.filter', val => val + 'b', 1 ); + addFilter( 'test.filter', 'my_plugin/my_callback', val => { + addFilter( 'test.filter', 'my_plugin/my_callback', val => val + 'b', 1 ); return val + 'a'; }, 1 ); @@ -292,19 +292,19 @@ test( 'add a filter immediately after the one currently executing', () => { } ); test( 'remove specific action callback', () => { - addAction( 'test.action', action_a ); - addAction( 'test.action', action_b, 2 ); - addAction( 'test.action', action_c, 8 ); + addAction( 'test.action', 'my_plugin/my_callback_action_a', action_a ); + addAction( 'test.action', 'my_plugin/my_callback_action_b', action_b, 2 ); + addAction( 'test.action', 'my_plugin/my_callback_action_c', action_c, 8 ); - expect( removeAction( 'test.action', action_b ) ).toEqual( 1 ); + expect( removeAction( 'test.action', 'my_plugin/my_callback_action_b' ) ).toEqual( 1 ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'ca' ); } ); test( 'remove all action callbacks', () => { - addAction( 'test.action', action_a ); - addAction( 'test.action', action_b, 2 ); - addAction( 'test.action', action_c, 8 ); + addAction( 'test.action', 'my_plugin/my_callback_action_a', action_a ); + addAction( 'test.action', 'my_plugin/my_callback_action_b', action_b, 2 ); + addAction( 'test.action', 'my_plugin/my_callback_action_c', action_c, 8 ); expect( removeAllActions( 'test.action' ) ).toEqual( 3 ); doAction( 'test.action' ); @@ -312,71 +312,71 @@ test( 'remove all action callbacks', () => { } ); test( 'remove specific filter callback', () => { - addFilter( 'test.filter', filter_a ); - addFilter( 'test.filter', filter_b, 2 ); - addFilter( 'test.filter', filter_c, 8 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 2 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 8 ); - expect( removeFilter( 'test.filter', filter_b ) ).toEqual( 1 ); + expect( removeFilter( 'test.filter', 'my_plugin/my_callback_filter_b' ) ).toEqual( 1 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); } ); test( 'filter removes a callback that has already executed', () => { - addFilter( 'test.filter', filter_a, 1 ); - addFilter( 'test.filter', filter_b, 3 ); - addFilter( 'test.filter', filter_c, 5 ); - addFilter( 'test.filter', filter_removes_b, 4 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 3 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 5 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_removes_b', filter_removes_b, 4 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); test( 'filter removes a callback that has already executed (same priority)', () => { - addFilter( 'test.filter', filter_a, 1 ); - addFilter( 'test.filter', filter_b, 2 ); - addFilter( 'test.filter', filter_removes_b, 2 ); - addFilter( 'test.filter', filter_c, 4 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 2 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_removes_b', filter_removes_b, 2 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 4 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); test( 'filter removes the current callback', () => { - addFilter( 'test.filter', filter_a, 1 ); - addFilter( 'test.filter', filter_b_removes_self, 3 ); - addFilter( 'test.filter', filter_c, 5 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_b_removes_self', filter_b_removes_self, 3 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 5 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); test( 'filter removes a callback that has not yet executed (last)', () => { - addFilter( 'test.filter', filter_a, 1 ); - addFilter( 'test.filter', filter_b, 3 ); - addFilter( 'test.filter', filter_c, 5 ); - addFilter( 'test.filter', filter_removes_c, 4 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 3 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 5 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_removes_c', filter_removes_c, 4 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); } ); test( 'filter removes a callback that has not yet executed (middle)', () => { - addFilter( 'test.filter', filter_a, 1 ); - addFilter( 'test.filter', filter_b, 3 ); - addFilter( 'test.filter', filter_c, 4 ); - addFilter( 'test.filter', filter_removes_b, 2 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 3 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 4 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_removes_b', filter_removes_b, 2 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); } ); test( 'filter removes a callback that has not yet executed (same priority)', () => { - addFilter( 'test.filter', filter_a, 1 ); - addFilter( 'test.filter', filter_removes_b, 2 ); - addFilter( 'test.filter', filter_b, 2 ); - addFilter( 'test.filter', filter_c, 4 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_removes_b', filter_removes_b, 2 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 2 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 4 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); } ); test( 'remove all filter callbacks', () => { - addFilter( 'test.filter', filter_a ); - addFilter( 'test.filter', filter_b, 2 ); - addFilter( 'test.filter', filter_c, 8 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 2 ); + addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 8 ); expect( removeAllFilters( 'test.filter' ) ).toEqual( 3 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); @@ -386,7 +386,7 @@ test( 'remove all filter callbacks', () => { test( 'Test doingAction, didAction and hasAction.', () => { let actionCalls = 0; - addAction( 'another.action', () => {} ); + addAction( 'another.action', 'my_plugin/my_callback', () => {} ); doAction( 'another.action' ); // Verify no action is running yet. @@ -395,7 +395,7 @@ test( 'Test doingAction, didAction and hasAction.', () => { expect( didAction( 'test.action' ) ).toBe( 0 ); expect( hasAction( 'test.action' ) ).toBe( 0 ); - addAction( 'test.action', () => { + addAction( 'test.action', 'my_plugin/my_callback', () => { actionCalls++; expect( currentAction() ).toBe( 'test.action' ); expect( doingAction() ).toBe( true ); @@ -440,7 +440,7 @@ test( 'Test doingAction, didAction and hasAction.', () => { test( 'Verify doingFilter, didFilter and hasFilter.', () => { let filterCalls = 0; - addFilter( 'runtest.filter', arg => { + addFilter( 'runtest.filter', 'my_plugin/my_callback', arg => { filterCalls++; expect( currentFilter() ).toBe( 'runtest.filter' ); expect( doingFilter() ).toBe( true ); @@ -467,7 +467,7 @@ test( 'Verify doingFilter, didFilter and hasFilter.', () => { } ); test( 'recursively calling a filter', () => { - addFilter( 'test.filter', value => { + addFilter( 'test.filter', 'my_plugin/my_callback', value => { if ( value.length === 7 ) { return value; } @@ -478,11 +478,11 @@ test( 'recursively calling a filter', () => { } ); test( 'current filter when multiple filters are running', () => { - addFilter( 'test.filter1', value => { + addFilter( 'test.filter1', 'my_plugin/my_callback', value => { return applyFilters( 'test.filter2', value.concat( currentFilter() ) ); } ); - addFilter( 'test.filter2', value => { + addFilter( 'test.filter2', 'my_plugin/my_callback', value => { return value.concat( currentFilter() ); } ); @@ -497,16 +497,16 @@ test( 'current filter when multiple filters are running', () => { test( 'adding and removing filters with recursion', () => { function removeRecurseAndAdd2( val ) { - expect( removeFilter( 'remove_and_add', removeRecurseAndAdd2 ) ).toEqual( 1 ); + expect( removeFilter( 'remove_and_add', 'my_plugin/my_callback_recurse' ) ).toEqual( 1 ); val += '-' + applyFilters( 'remove_and_add', '' ) + '-'; - addFilter( 'remove_and_add', removeRecurseAndAdd2, 10 ); + addFilter( 'remove_and_add', 'my_plugin/my_callback_recurse', 10 ); return val + '2'; } - addFilter( 'remove_and_add', val => val + '1', 11 ); - addFilter( 'remove_and_add', removeRecurseAndAdd2, 12 ); - addFilter( 'remove_and_add', val => val + '3', 13 ); - addFilter( 'remove_and_add', val => val + '4', 14 ); + addFilter( 'remove_and_add', 'my_plugin/my_callback', val => val + '1', 11 ); + addFilter( 'remove_and_add', 'my_plugin/my_callback_recurse', removeRecurseAndAdd2, 12 ); + addFilter( 'remove_and_add', 'my_plugin/my_callback', val => val + '3', 13 ); + addFilter( 'remove_and_add', 'my_plugin/my_callback', val => val + '4', 14 ); expect( applyFilters( 'remove_and_add', '' ) ).toEqual( '1-134-234' ); } ); From 4ece207a8465dce14ca5f2cab9d3bcc9f0c5a06f Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 12:48:02 -0400 Subject: [PATCH 77/91] Update readme with new hook/namespace signature --- packages/hooks/README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/hooks/README.md b/packages/hooks/README.md index 1174727..68b2716 100644 --- a/packages/hooks/README.md +++ b/packages/hooks/README.md @@ -6,20 +6,20 @@ A lightweight & efficient EventManager for JavaScript in WordPress. ### API Usage API functions can be called via the global `wp.hooks` like this `wp.hooks.addAction()`, etc. -* `addAction( 'namespace.identifier', callback, priority )` -* `addFilter( 'namespace.identifier', callback, priority )` -* `removeAction( 'namespace.identifier', callback )` -* `removeFilter( 'namespace.identifier', callback )` -* `removeAllActions( 'namespace.identifier' )` -* `removeAllFilters( 'namespace.identifier' )` -* `doAction( 'namespace.identifier', arg1, arg2, moreArgs, finalArg )` -* `applyFilters( 'namespace.identifier', content )` -* `doingAction( 'namespace.identifier' )` -* `doingFilter( 'namespace.identifier' )` -* `didAction( 'namespace.identifier' )` -* `didFilter( 'namespace.identifier' )` -* `hasAction( 'namespace.identifier' )` -* `hasFilter( 'namespace.identifier' )` +* `addAction( 'hook_name', 'my_plugin/my_callback', callback, priority )` +* `addFilter( 'hook_name', 'my_plugin/my_callback', callback, priority )` +* `removeAction( 'hook_name', 'my_plugin/my_callback' )` +* `removeFilter( 'hook_name', 'my_plugin/my_callback' )` +* `removeAllActions( 'hook_name' )` +* `removeAllFilters( 'hook_name' )` +* `doAction( 'hook_name', arg1, arg2, moreArgs, finalArg )` +* `applyFilters( 'hook_name', content )` +* `doingAction( 'hook_name' )` +* `doingFilter( 'hook_name' )` +* `didAction( 'hook_name' )` +* `didFilter( 'hook_name' )` +* `hasAction( 'hook_name' )` +* `hasFilter( 'hook_name' )` ### Background From aa709ac97ceb3ecf52651c16a4fae686680abc39 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 22:09:58 -0400 Subject: [PATCH 78/91] Improve validateNamespace and validateHookName inline docs --- packages/hooks/src/validateHookName.js | 6 ++++-- packages/hooks/src/validateNamespace.js | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/hooks/src/validateHookName.js b/packages/hooks/src/validateHookName.js index 7af1a26..963f4c3 100644 --- a/packages/hooks/src/validateHookName.js +++ b/packages/hooks/src/validateHookName.js @@ -1,7 +1,9 @@ /** - * Validate a hook name. + * Validate a hookName string. * - * @param {string} hookName The hook name to validate. + * @param {string} hookName The hook name to validate. Should be a non empty string containing + * only numbers, letters, dashes, periods and underscores. Also, + * the hook name cannot begin with `__`. * * @return {bool} Whether the hook name is valid. */ diff --git a/packages/hooks/src/validateNamespace.js b/packages/hooks/src/validateNamespace.js index f8d3e70..4d8172a 100644 --- a/packages/hooks/src/validateNamespace.js +++ b/packages/hooks/src/validateNamespace.js @@ -1,7 +1,8 @@ /** - * Validate a namespace. + * Validate a namespace string. * - * @param {string} namespace The namespace to validate. + * @param {string} namespace The namespace to validate - should take the form + * `my-plugin-slug/functionDescription`. * * @return {bool} Whether the namespace is valid. */ From a8628a0601f69d3683a03f9d799cb782ea5f1ae6 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 22:10:31 -0400 Subject: [PATCH 79/91] require a non-empty string when validating namespace/hookName --- packages/hooks/src/validateHookName.js | 4 ++-- packages/hooks/src/validateNamespace.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/hooks/src/validateHookName.js b/packages/hooks/src/validateHookName.js index 963f4c3..62ffe5e 100644 --- a/packages/hooks/src/validateHookName.js +++ b/packages/hooks/src/validateHookName.js @@ -9,8 +9,8 @@ */ function validateHookName( hookName ) { - if ( 'string' !== typeof hookName ) { - console.error( 'The hook name must be a string.' ); + if ( 'string' !== typeof hookName || '' === hookName ) { + console.error( 'The hook name must be a non-empty string.' ); return false; } diff --git a/packages/hooks/src/validateNamespace.js b/packages/hooks/src/validateNamespace.js index 4d8172a..b0cfe39 100644 --- a/packages/hooks/src/validateNamespace.js +++ b/packages/hooks/src/validateNamespace.js @@ -8,8 +8,8 @@ */ function validateNamespace( namespace ) { - if ( 'string' !== typeof namespace ) { - console.error( 'The namespace must be a string.' ); + if ( 'string' !== typeof namespace || '' === namespace ) { + console.error( 'The namespace must be a non-empty string.' ); return false; } From 242f351a9e7d8132081028bdedb1532b3889acca Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 22:12:35 -0400 Subject: [PATCH 80/91] Adjust expected error language in tests. --- packages/hooks/src/test/index.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index f08fe77..419bdb3 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -111,14 +111,14 @@ test( 'remove a non-existent filter', () => { test( 'remove an invalid namespace from a filter', () => { expect( removeFilter( 'test.filter', 42 ) ).toEqual( undefined ); expect( console.error ).toHaveBeenCalledWith( - 'The namespace must be a string.' + 'The namespace must be a non-empty string.' ); } ); test( 'cannot add filters with non-string names', () => { addFilter( 42, 'my_plugin/my_callback', () => null ); expect( console.error ).toHaveBeenCalledWith( - 'The hook name must be a string.' + 'The hook name must be a non-empty string.' ); } ); @@ -146,7 +146,7 @@ test( 'cannot add filters with non-numeric priorities', () => { test( 'cannot run filters with non-string names', () => { expect( applyFilters( () => {}, 42 ) ).toBe( undefined ); expect( console.error ).toHaveBeenCalledWith( - 'The hook name must be a string.' + 'The hook name must be a non-empty string.' ); } ); From d8af28fc7f67f6348ef1d4f0e3512562d4cb965c Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 22:47:27 -0400 Subject: [PATCH 81/91] Improved regexes for hookName and namespace validation --- packages/hooks/src/validateHookName.js | 2 +- packages/hooks/src/validateNamespace.js | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/hooks/src/validateHookName.js b/packages/hooks/src/validateHookName.js index 62ffe5e..0059695 100644 --- a/packages/hooks/src/validateHookName.js +++ b/packages/hooks/src/validateHookName.js @@ -19,7 +19,7 @@ function validateHookName( hookName ) { return false; } - if ( ! /^[a-z][a-z0-9_.-]*$/.test( hookName ) ) { + if ( ! /^[a-zA-Z][a-zA-Z0-9_.-]*$/.test( hookName ) ) { console.error( 'The hook name can only contain numbers, letters, dashes, periods and underscores.' ); return false; } diff --git a/packages/hooks/src/validateNamespace.js b/packages/hooks/src/validateNamespace.js index b0cfe39..b126053 100644 --- a/packages/hooks/src/validateNamespace.js +++ b/packages/hooks/src/validateNamespace.js @@ -13,8 +13,13 @@ function validateNamespace( namespace ) { return false; } - if ( ! /^.*\/.*$/.test( namespace ) ) { - console.error( 'The namespace must take the form `my-plugin-slug/functionDescription' ); + if ( ! /^[a-zA-Z][a-zA-Z0-9_.-/]*$/.test( namespace ) ) { + console.error( 'The namespace can only contain numbers, letters, dashes, periods and underscores, plus the forward slash dividing slug and description in the namespace.' ); + return false; + } + + if ( ! /^[a-zA-Z][a-zA-Z0-9_.-]*\/[a-zA-Z][a-zA-Z0-9_.-]*$/.test( namespace ) ) { + console.error( 'The namespace must take the form `my-plugin-slug/functionDescription`.' ); return false; } From 650e9e23570d20f50d37556223585a32ce94d927 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 11 Aug 2017 22:47:47 -0400 Subject: [PATCH 82/91] Add more tests around hookName and namespace validation --- packages/hooks/src/test/index.test.js | 57 ++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 419bdb3..17e76f6 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -115,13 +115,68 @@ test( 'remove an invalid namespace from a filter', () => { ); } ); -test( 'cannot add filters with non-string names', () => { +test( 'cannot add filters with non-string hook names', () => { addFilter( 42, 'my_plugin/my_callback', () => null ); expect( console.error ).toHaveBeenCalledWith( 'The hook name must be a non-empty string.' ); } ); +test( 'cannot add filters with empty-string hook names', () => { + addFilter( '', 'my_plugin/my_callback', () => null ); + expect( console.error ).toHaveBeenCalledWith( + 'The hook name must be a non-empty string.' + ); +} ); + +test( 'cannot add filters with empty-string namespaces', () => { + addFilter( 'hook_name', '', () => null ); + expect( console.error ).toHaveBeenCalledWith( + 'The namespace must be a non-empty string.' + ); +} ); + +test( 'cannot add filters with invalid namespaces', () => { + addFilter( 'hook_name', 'invalid_name', () => null ); + expect( console.error ).toHaveBeenCalledWith( + 'The namespace must take the form `my-plugin-slug/functionDescription`.' + ); +} ); + +test( 'cannot add filters with namespaces missing a functionDescription', () => { + addFilter( 'hook_name', 'invalid_name/', () => null ); + expect( console.error ).toHaveBeenCalledWith( + 'The namespace must take the form `my-plugin-slug/functionDescription`.' + ); +} ); + +test( 'Can add filters with capitals in namespaces', () => { + addFilter( 'hook_name', 'OhNo/action', () => null ); + expect( console.error ).toHaveBeenCalledTimes( 0 ); +} ); + +test( 'Can add filters with capitals in hookName', () => { + addFilter( 'hookName', 'plugin/action', () => null ); + expect( console.error ).toHaveBeenCalledTimes( 0 ); +} ); + +test( 'Can add filters with periods in namespaces', () => { + addFilter( 'hook_name', 'plugin.name/ok.action', () => null ); + expect( console.error ).toHaveBeenCalledTimes( 0 ); +} ); + +test( 'Can add filters with periods in hookName', () => { + addFilter( 'hook.name', 'plugin/action', () => null ); + expect( console.error ).toHaveBeenCalledTimes( 0 ); +} ); + +test( 'cannot add filters with invalid namespaces', () => { + addFilter( 'hook_name', '/invalid_name', () => null ); + expect( console.error ).toHaveBeenCalledWith( + 'The namespace can only contain numbers, letters, dashes, periods and underscores, plus the forward slash dividing slug and description in the namespace.' + ); +} ); + test( 'cannot add filters named with __ prefix', () => { addFilter( '__test', 'my_plugin/my_callback', () => null ); expect( console.error ).toHaveBeenCalledWith( From a617214646c04019c6b21e8b36ff619d38bacb4c Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 16 Aug 2017 10:39:15 -0400 Subject: [PATCH 83/91] Validate namespace takes form `vendorName/pluginName/functionName` --- packages/hooks/src/validateNamespace.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hooks/src/validateNamespace.js b/packages/hooks/src/validateNamespace.js index b126053..0298275 100644 --- a/packages/hooks/src/validateNamespace.js +++ b/packages/hooks/src/validateNamespace.js @@ -18,8 +18,8 @@ function validateNamespace( namespace ) { return false; } - if ( ! /^[a-zA-Z][a-zA-Z0-9_.-]*\/[a-zA-Z][a-zA-Z0-9_.-]*$/.test( namespace ) ) { - console.error( 'The namespace must take the form `my-plugin-slug/functionDescription`.' ); + if ( ! /^[a-zA-Z][a-zA-Z0-9_.-]*\/[a-zA-Z][a-zA-Z0-9_.-]*\/[a-zA-Z][a-zA-Z0-9_.-]*$/.test( namespace ) ) { + console.error( 'The namespace must take the form `vendorName/pluginName/functionName`.' ); return false; } From 30e5e82c3758b138b4af40570b23d9f2e98ca56e Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 16 Aug 2017 10:39:46 -0400 Subject: [PATCH 84/91] Update tests with new namespace format --- packages/hooks/src/test/index.test.js | 208 +++++++++++++------------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 17e76f6..8824ea3 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -36,17 +36,17 @@ function filter_c( str ) { } function filter_b_removes_self( str ) { - removeFilter( 'test.filter', 'my_plugin/my_callback_filter_b_removes_self' ); + removeFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b_removes_self' ); return str + 'b'; } function filter_removes_b( str ) { - removeFilter( 'test.filter', 'my_plugin/my_callback_filter_b' ); + removeFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b' ); return str; } function filter_removes_c( str ) { - removeFilter( 'test.filter', 'my_plugin/my_callback_filter_c' ); + removeFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_c' ); return str; } @@ -86,25 +86,25 @@ test( 'run a filter with no callbacks', () => { } ); test( 'add and remove a filter', () => { - addFilter( 'test.filter', 'my_plugin/my_callback', filter_a ); + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', filter_a ); expect( removeAllFilters( 'test.filter' ) ).toEqual( 1 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); expect( removeAllFilters( 'test.filter' ) ).toEqual( 0 ); } ); test( 'add a filter and run it', () => { - addFilter( 'test.filter', 'my_plugin/my_callback', filter_a ); + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', filter_a ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testa' ); } ); test( 'add 2 filters in a row and run them', () => { - addFilter( 'test.filter', 'my_plugin/my_callback', filter_a ); - addFilter( 'test.filter', 'my_plugin/my_callback', filter_b ); + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', filter_a ); + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', filter_b ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); } ); test( 'remove a non-existent filter', () => { - expect( removeFilter( 'test.filter', 'my_plugin/my_callback', filter_a ) ).toEqual( 0 ); + expect( removeFilter( 'test.filter', 'my_name/my_plugin/my_callback', filter_a ) ).toEqual( 0 ); expect( removeAllFilters( 'test.filter' ) ).toEqual( 0 ); } ); @@ -116,14 +116,14 @@ test( 'remove an invalid namespace from a filter', () => { } ); test( 'cannot add filters with non-string hook names', () => { - addFilter( 42, 'my_plugin/my_callback', () => null ); + addFilter( 42, 'my_name/my_plugin/my_callback', () => null ); expect( console.error ).toHaveBeenCalledWith( 'The hook name must be a non-empty string.' ); } ); test( 'cannot add filters with empty-string hook names', () => { - addFilter( '', 'my_plugin/my_callback', () => null ); + addFilter( '', 'my_name/my_plugin/my_callback', () => null ); expect( console.error ).toHaveBeenCalledWith( 'The hook name must be a non-empty string.' ); @@ -139,34 +139,34 @@ test( 'cannot add filters with empty-string namespaces', () => { test( 'cannot add filters with invalid namespaces', () => { addFilter( 'hook_name', 'invalid_name', () => null ); expect( console.error ).toHaveBeenCalledWith( - 'The namespace must take the form `my-plugin-slug/functionDescription`.' + 'The namespace must take the form `vendorName/pluginName/functionName`.' ); } ); test( 'cannot add filters with namespaces missing a functionDescription', () => { addFilter( 'hook_name', 'invalid_name/', () => null ); expect( console.error ).toHaveBeenCalledWith( - 'The namespace must take the form `my-plugin-slug/functionDescription`.' + 'The namespace must take the form `vendorName/pluginName/functionName`.' ); } ); test( 'Can add filters with capitals in namespaces', () => { - addFilter( 'hook_name', 'OhNo/action', () => null ); + addFilter( 'hook_name', 'my_name/OhNo/action', () => null ); expect( console.error ).toHaveBeenCalledTimes( 0 ); } ); test( 'Can add filters with capitals in hookName', () => { - addFilter( 'hookName', 'plugin/action', () => null ); + addFilter( 'hookName', 'my_name/plugin/action', () => null ); expect( console.error ).toHaveBeenCalledTimes( 0 ); } ); test( 'Can add filters with periods in namespaces', () => { - addFilter( 'hook_name', 'plugin.name/ok.action', () => null ); + addFilter( 'hook_name', 'my_name/plugin.name/ok.action', () => null ); expect( console.error ).toHaveBeenCalledTimes( 0 ); } ); test( 'Can add filters with periods in hookName', () => { - addFilter( 'hook.name', 'plugin/action', () => null ); + addFilter( 'hook.name', 'my_name/plugin/action', () => null ); expect( console.error ).toHaveBeenCalledTimes( 0 ); } ); @@ -178,21 +178,21 @@ test( 'cannot add filters with invalid namespaces', () => { } ); test( 'cannot add filters named with __ prefix', () => { - addFilter( '__test', 'my_plugin/my_callback', () => null ); + addFilter( '__test', 'my_name/my_plugin/my_callback', () => null ); expect( console.error ).toHaveBeenCalledWith( 'The hook name cannot begin with `__`.' ); } ); test( 'cannot add filters with non-function callbacks', () => { - addFilter( 'test', 'my_plugin/my_callback', '42' ); + addFilter( 'test', 'my_name/my_plugin/my_callback', '42' ); expect( console.error ).toHaveBeenCalledWith( 'The hook callback must be a function.' ); } ); test( 'cannot add filters with non-numeric priorities', () => { - addFilter( 'test', 'my_plugin/my_callback', () => null, '42' ); + addFilter( 'test', 'my_name/my_plugin/my_callback', () => null, '42' ); expect( console.error ).toHaveBeenCalledWith( 'If specified, the hook priority must be a number.' ); @@ -213,9 +213,9 @@ test( 'cannot run filters named with __ prefix', () => { } ); test( 'add 3 filters with different priorities and run them', () => { - addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 2 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 8 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_a', filter_a ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b', filter_b, 2 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_c', filter_c, 8 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testbca' ); } ); @@ -230,34 +230,34 @@ test( 'filters with the same and different priorities', () => { } ); } ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_3a', callbacks.fn_3a, 3 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_3b', callbacks.fn_3b, 3 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_3c', callbacks.fn_3c, 3 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_2a', callbacks.fn_2a, 2 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_2b', callbacks.fn_2b, 2 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_2c', callbacks.fn_2c, 2 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_3a', callbacks.fn_3a, 3 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_3b', callbacks.fn_3b, 3 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_3c', callbacks.fn_3c, 3 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_2a', callbacks.fn_2a, 2 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_2b', callbacks.fn_2b, 2 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_2c', callbacks.fn_2c, 2 ); expect( applyFilters( 'test_order', [] ) ).toEqual( [ '2a', '2b', '2c', '3a', '3b', '3c' ] ); - removeFilter( 'test_order', 'my_plugin/my_callback_fn_2b', callbacks.fn_2b ); - removeFilter( 'test_order', 'my_plugin/my_callback_fn_3a', callbacks.fn_3a ); + removeFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_2b', callbacks.fn_2b ); + removeFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_3a', callbacks.fn_3a ); expect( applyFilters( 'test_order', [] ) ).toEqual( [ '2a', '2c', '3b', '3c' ] ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_4a', callbacks.fn_4a, 4 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_4b', callbacks.fn_4b, 4 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_1a', callbacks.fn_1a, 1 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_4c', callbacks.fn_4c, 4 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_1b', callbacks.fn_1b, 1 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_3d', callbacks.fn_3d, 3 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_4d', callbacks.fn_4d, 4 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_1c', callbacks.fn_1c, 1 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_2d', callbacks.fn_2d, 2 ); - addFilter( 'test_order', 'my_plugin/my_callback_fn_1d', callbacks.fn_1d, 1 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_4a', callbacks.fn_4a, 4 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_4b', callbacks.fn_4b, 4 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_1a', callbacks.fn_1a, 1 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_4c', callbacks.fn_4c, 4 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_1b', callbacks.fn_1b, 1 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_3d', callbacks.fn_3d, 3 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_4d', callbacks.fn_4d, 4 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_1c', callbacks.fn_1c, 1 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_2d', callbacks.fn_2d, 2 ); + addFilter( 'test_order', 'my_name/my_plugin/my_callback_fn_1d', callbacks.fn_1d, 1 ); expect( applyFilters( 'test_order', [] ) ).toEqual( [ // all except 2b and 3a, which we removed earlier @@ -269,29 +269,29 @@ test( 'filters with the same and different priorities', () => { } ); test( 'add and remove an action', () => { - addAction( 'test.action', 'my_plugin/my_callback', action_a ); + addAction( 'test.action', 'my_name/my_plugin/my_callback', action_a ); expect( removeAllActions( 'test.action' ) ).toEqual( 1 ); expect( doAction( 'test.action' ) ).toBe( undefined ); expect( window.actionValue ).toBe( '' ); } ); test( 'add an action and run it', () => { - addAction( 'test.action', 'my_plugin/my_callback', action_a ); + addAction( 'test.action', 'my_name/my_plugin/my_callback', action_a ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'a' ); } ); test( 'add 2 actions in a row and then run them', () => { - addAction( 'test.action', 'my_plugin/my_callback', action_a ); - addAction( 'test.action', 'my_plugin/my_callback', action_b ); + addAction( 'test.action', 'my_name/my_plugin/my_callback', action_a ); + addAction( 'test.action', 'my_name/my_plugin/my_callback', action_b ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'ab' ); } ); test( 'add 3 actions with different priorities and run them', () => { - addAction( 'test.action', 'my_plugin/my_callback', action_a ); - addAction( 'test.action', 'my_plugin/my_callback', action_b, 2 ); - addAction( 'test.action', 'my_plugin/my_callback', action_c, 8 ); + addAction( 'test.action', 'my_name/my_plugin/my_callback', action_a ); + addAction( 'test.action', 'my_name/my_plugin/my_callback', action_b, 2 ); + addAction( 'test.action', 'my_name/my_plugin/my_callback', action_c, 8 ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'bca' ); } ); @@ -300,7 +300,7 @@ test( 'pass in two arguments to an action', () => { const arg1 = { a: 10 }; const arg2 = { b: 20 }; - addAction( 'test.action', 'my_plugin/my_callback', ( a, b ) => { + addAction( 'test.action', 'my_name/my_plugin/my_callback', ( a, b ) => { expect( a ).toBe( arg1 ); expect( b ).toBe( arg2 ); } ); @@ -314,14 +314,14 @@ test( 'fire action multiple times', () => { expect( true ).toBe( true ); }; - addAction( 'test.action', 'my_plugin/my_callback', func ); + addAction( 'test.action', 'my_name/my_plugin/my_callback', func ); doAction( 'test.action' ); doAction( 'test.action' ); } ); test( 'add a filter before the one currently executing', () => { - addFilter( 'test.filter', 'my_plugin/my_callback', val => { - addFilter( 'test.filter', 'my_plugin/my_callback', val => val + 'a', 1 ); + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', val => { + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', val => val + 'a', 1 ); return val + 'b'; }, 2 ); @@ -329,8 +329,8 @@ test( 'add a filter before the one currently executing', () => { } ); test( 'add a filter after the one currently executing', () => { - addFilter( 'test.filter', 'my_plugin/my_callback', val => { - addFilter( 'test.filter', 'my_plugin/my_callback', val => val + 'b', 2 ); + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', val => { + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', val => val + 'b', 2 ); return val + 'a'; }, 1 ); @@ -338,8 +338,8 @@ test( 'add a filter after the one currently executing', () => { } ); test( 'add a filter immediately after the one currently executing', () => { - addFilter( 'test.filter', 'my_plugin/my_callback', val => { - addFilter( 'test.filter', 'my_plugin/my_callback', val => val + 'b', 1 ); + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', val => { + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', val => val + 'b', 1 ); return val + 'a'; }, 1 ); @@ -347,19 +347,19 @@ test( 'add a filter immediately after the one currently executing', () => { } ); test( 'remove specific action callback', () => { - addAction( 'test.action', 'my_plugin/my_callback_action_a', action_a ); - addAction( 'test.action', 'my_plugin/my_callback_action_b', action_b, 2 ); - addAction( 'test.action', 'my_plugin/my_callback_action_c', action_c, 8 ); + addAction( 'test.action', 'my_name/my_plugin/my_callback_action_a', action_a ); + addAction( 'test.action', 'my_name/my_plugin/my_callback_action_b', action_b, 2 ); + addAction( 'test.action', 'my_name/my_plugin/my_callback_action_c', action_c, 8 ); - expect( removeAction( 'test.action', 'my_plugin/my_callback_action_b' ) ).toEqual( 1 ); + expect( removeAction( 'test.action', 'my_name/my_plugin/my_callback_action_b' ) ).toEqual( 1 ); doAction( 'test.action' ); expect( window.actionValue ).toBe( 'ca' ); } ); test( 'remove all action callbacks', () => { - addAction( 'test.action', 'my_plugin/my_callback_action_a', action_a ); - addAction( 'test.action', 'my_plugin/my_callback_action_b', action_b, 2 ); - addAction( 'test.action', 'my_plugin/my_callback_action_c', action_c, 8 ); + addAction( 'test.action', 'my_name/my_plugin/my_callback_action_a', action_a ); + addAction( 'test.action', 'my_name/my_plugin/my_callback_action_b', action_b, 2 ); + addAction( 'test.action', 'my_name/my_plugin/my_callback_action_c', action_c, 8 ); expect( removeAllActions( 'test.action' ) ).toEqual( 3 ); doAction( 'test.action' ); @@ -367,71 +367,71 @@ test( 'remove all action callbacks', () => { } ); test( 'remove specific filter callback', () => { - addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 2 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 8 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_a', filter_a ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b', filter_b, 2 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_c', filter_c, 8 ); - expect( removeFilter( 'test.filter', 'my_plugin/my_callback_filter_b' ) ).toEqual( 1 ); + expect( removeFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b' ) ).toEqual( 1 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testca' ); } ); test( 'filter removes a callback that has already executed', () => { - addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 3 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 5 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_removes_b', filter_removes_b, 4 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b', filter_b, 3 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_c', filter_c, 5 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_removes_b', filter_removes_b, 4 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); test( 'filter removes a callback that has already executed (same priority)', () => { - addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 2 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_removes_b', filter_removes_b, 2 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 4 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b', filter_b, 2 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_removes_b', filter_removes_b, 2 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_c', filter_c, 4 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); test( 'filter removes the current callback', () => { - addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_b_removes_self', filter_b_removes_self, 3 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 5 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b_removes_self', filter_b_removes_self, 3 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_c', filter_c, 5 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testabc' ); } ); test( 'filter removes a callback that has not yet executed (last)', () => { - addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 3 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 5 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_removes_c', filter_removes_c, 4 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b', filter_b, 3 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_c', filter_c, 5 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_removes_c', filter_removes_c, 4 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' ); } ); test( 'filter removes a callback that has not yet executed (middle)', () => { - addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 3 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 4 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_removes_b', filter_removes_b, 2 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b', filter_b, 3 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_c', filter_c, 4 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_removes_b', filter_removes_b, 2 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); } ); test( 'filter removes a callback that has not yet executed (same priority)', () => { - addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a, 1 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_removes_b', filter_removes_b, 2 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 2 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 4 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_a', filter_a, 1 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_removes_b', filter_removes_b, 2 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b', filter_b, 2 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_c', filter_c, 4 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testac' ); } ); test( 'remove all filter callbacks', () => { - addFilter( 'test.filter', 'my_plugin/my_callback_filter_a', filter_a ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_b', filter_b, 2 ); - addFilter( 'test.filter', 'my_plugin/my_callback_filter_c', filter_c, 8 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_a', filter_a ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_b', filter_b, 2 ); + addFilter( 'test.filter', 'me_name/my_plugin/my_callback_filter_c', filter_c, 8 ); expect( removeAllFilters( 'test.filter' ) ).toEqual( 3 ); expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'test' ); @@ -441,7 +441,7 @@ test( 'remove all filter callbacks', () => { test( 'Test doingAction, didAction and hasAction.', () => { let actionCalls = 0; - addAction( 'another.action', 'my_plugin/my_callback', () => {} ); + addAction( 'another.action', 'my_name/my_plugin/my_callback', () => {} ); doAction( 'another.action' ); // Verify no action is running yet. @@ -450,7 +450,7 @@ test( 'Test doingAction, didAction and hasAction.', () => { expect( didAction( 'test.action' ) ).toBe( 0 ); expect( hasAction( 'test.action' ) ).toBe( 0 ); - addAction( 'test.action', 'my_plugin/my_callback', () => { + addAction( 'test.action', 'my_name/my_plugin/my_callback', () => { actionCalls++; expect( currentAction() ).toBe( 'test.action' ); expect( doingAction() ).toBe( true ); @@ -495,7 +495,7 @@ test( 'Test doingAction, didAction and hasAction.', () => { test( 'Verify doingFilter, didFilter and hasFilter.', () => { let filterCalls = 0; - addFilter( 'runtest.filter', 'my_plugin/my_callback', arg => { + addFilter( 'runtest.filter', 'my_name/my_plugin/my_callback', arg => { filterCalls++; expect( currentFilter() ).toBe( 'runtest.filter' ); expect( doingFilter() ).toBe( true ); @@ -522,7 +522,7 @@ test( 'Verify doingFilter, didFilter and hasFilter.', () => { } ); test( 'recursively calling a filter', () => { - addFilter( 'test.filter', 'my_plugin/my_callback', value => { + addFilter( 'test.filter', 'my_name/my_plugin/my_callback', value => { if ( value.length === 7 ) { return value; } @@ -533,11 +533,11 @@ test( 'recursively calling a filter', () => { } ); test( 'current filter when multiple filters are running', () => { - addFilter( 'test.filter1', 'my_plugin/my_callback', value => { + addFilter( 'test.filter1', 'my_name/my_plugin/my_callback', value => { return applyFilters( 'test.filter2', value.concat( currentFilter() ) ); } ); - addFilter( 'test.filter2', 'my_plugin/my_callback', value => { + addFilter( 'test.filter2', 'my_name/my_plugin/my_callback', value => { return value.concat( currentFilter() ); } ); @@ -552,16 +552,16 @@ test( 'current filter when multiple filters are running', () => { test( 'adding and removing filters with recursion', () => { function removeRecurseAndAdd2( val ) { - expect( removeFilter( 'remove_and_add', 'my_plugin/my_callback_recurse' ) ).toEqual( 1 ); + expect( removeFilter( 'remove_and_add', 'my_name/my_plugin/my_callback_recurse' ) ).toEqual( 1 ); val += '-' + applyFilters( 'remove_and_add', '' ) + '-'; - addFilter( 'remove_and_add', 'my_plugin/my_callback_recurse', 10 ); + addFilter( 'remove_and_add', 'my_name/my_plugin/my_callback_recurse', 10 ); return val + '2'; } - addFilter( 'remove_and_add', 'my_plugin/my_callback', val => val + '1', 11 ); - addFilter( 'remove_and_add', 'my_plugin/my_callback_recurse', removeRecurseAndAdd2, 12 ); - addFilter( 'remove_and_add', 'my_plugin/my_callback', val => val + '3', 13 ); - addFilter( 'remove_and_add', 'my_plugin/my_callback', val => val + '4', 14 ); + addFilter( 'remove_and_add', 'my_name/my_plugin/my_callback', val => val + '1', 11 ); + addFilter( 'remove_and_add', 'my_name/my_plugin/my_callback_recurse', removeRecurseAndAdd2, 12 ); + addFilter( 'remove_and_add', 'my_name/my_plugin/my_callback', val => val + '3', 13 ); + addFilter( 'remove_and_add', 'my_name/my_plugin/my_callback', val => val + '4', 14 ); expect( applyFilters( 'remove_and_add', '' ) ).toEqual( '1-134-234' ); } ); From 3a13768e7f4fd4d17e9764d5bcc9fa796e175ce4 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 16 Aug 2017 11:44:08 -0400 Subject: [PATCH 85/91] update readme with new namespace format --- packages/hooks/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/hooks/README.md b/packages/hooks/README.md index 68b2716..42afb85 100644 --- a/packages/hooks/README.md +++ b/packages/hooks/README.md @@ -6,10 +6,10 @@ A lightweight & efficient EventManager for JavaScript in WordPress. ### API Usage API functions can be called via the global `wp.hooks` like this `wp.hooks.addAction()`, etc. -* `addAction( 'hook_name', 'my_plugin/my_callback', callback, priority )` -* `addFilter( 'hook_name', 'my_plugin/my_callback', callback, priority )` -* `removeAction( 'hook_name', 'my_plugin/my_callback' )` -* `removeFilter( 'hook_name', 'my_plugin/my_callback' )` +* `addAction( 'hook_name', 'vendorName/pluginName/functionName', callback, priority )` +* `addFilter( 'hook_name', 'vendorName/pluginName/functionName', callback, priority )` +* `removeAction( 'hook_name', 'vendorName/pluginName/functionName' )` +* `removeFilter( 'hook_name', 'vendorName/pluginName/functionName' )` * `removeAllActions( 'hook_name' )` * `removeAllFilters( 'hook_name' )` * `doAction( 'hook_name', arg1, arg2, moreArgs, finalArg )` From 7c1fc297df08ea3d1876debfcb2cc1d6bf0c1ef8 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 17 Aug 2017 15:03:24 -0400 Subject: [PATCH 86/91] remove module build from branch --- package.json | 2 -- webpack.config.js | 46 ---------------------------------------------- 2 files changed, 48 deletions(-) delete mode 100644 webpack.config.js diff --git a/package.json b/package.json index e7bef5d..d5c5a2f 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "lerna": "^2.0.0", "mkdirp": "^0.5.1", "rimraf": "^2.6.1", - "webpack": "^3.3.0", "babel-loader": "^7.1.1" }, "jest": { @@ -26,7 +25,6 @@ "scripts": { "build-clean": "rimraf ./packages/*/build ./packages/*/build-browser ./packages/*/build-module", "build": "node ./scripts/build.js", - "build-modules": "webpack --progress -p", "test": "jest", "test:coverage": "jest --coverage", "test:coverage-ci": "jest --coverage && coveralls < coverage/lcov.info", diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index 7b8e8c6..0000000 --- a/webpack.config.js +++ /dev/null @@ -1,46 +0,0 @@ -const entryPointNames = [ - 'hooks', - 'url', -]; - -const externals = { - react: 'React', - 'react-dom': 'ReactDOM', - 'react-dom/server': 'ReactDOMServer', - tinymce: 'tinymce', - moment: 'moment', -}; - -entryPointNames.forEach( entryPointName => { - externals[ entryPointName ] = { - 'this': [ 'wp', entryPointName ], - }; -} ); - -const config = entryPointNames.reduce( ( memo, entryPointName ) => { - memo[ entryPointName ] = './packages/' + entryPointName + '/src/index.js'; - return memo; - }, {} ); - - -module.exports = { - entry: config, - externals, - output: { - filename: 'build/[name]/index.js', - path: __dirname, - library: [ 'wp', '[name]' ], - libraryTarget: 'this', - }, - module: { - rules: [ - { - test: /\.js$/, - exclude: /(node_modules)/, - use: { - loader: 'babel-loader' - } - } - ] - } -} From 45747e5ad147a6b35f2b7bb508eb139a475e2094 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Mon, 4 Sep 2017 09:39:41 -0400 Subject: [PATCH 87/91] Correct namespace strings in docblocks --- packages/hooks/src/createAddHook.js | 2 +- packages/hooks/src/createRemoveHook.js | 2 +- packages/hooks/src/validateNamespace.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index 6162d06..de97d16 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -13,7 +13,7 @@ function createAddHook( hooks ) { * Adds the hook to the appropriate hooks container. * * @param {string} hookName Name of hook to add - * @param {string} namespace The unique namespace identifying the callback in the form `my-plugin-slug/functionDescription`. + * @param {string} namespace The unique namespace identifying the callback in the form `vendorName/pluginName/functionName`. * @param {Function} callback Function to call when the hook is run * @param {?number} priority Priority of this hook (default=10) */ diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index 9383cc1..37dfc30 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -16,7 +16,7 @@ function createRemoveHook( hooks, removeAll ) { * given hookName and namespace. * * @param {string} hookName The name of the hook to modify. - * @param {string} namespace The unique namespace identifying the callback in the form `my-plugin-slug/functionDescription`. + * @param {string} namespace The unique namespace identifying the callback in the form `vendorName/pluginName/functionName`. * * @return {number} The number of callbacks removed. */ diff --git a/packages/hooks/src/validateNamespace.js b/packages/hooks/src/validateNamespace.js index 0298275..c246bc3 100644 --- a/packages/hooks/src/validateNamespace.js +++ b/packages/hooks/src/validateNamespace.js @@ -2,7 +2,7 @@ * Validate a namespace string. * * @param {string} namespace The namespace to validate - should take the form - * `my-plugin-slug/functionDescription`. + * `vendorName/pluginName/functionName`. * * @return {bool} Whether the namespace is valid. */ From a24847bc8117fff0adff7244fb5a6ba554a2a9cd Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 7 Sep 2017 10:06:21 -0400 Subject: [PATCH 88/91] Add args to applyFilters docs in readme --- packages/hooks/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hooks/README.md b/packages/hooks/README.md index 42afb85..12195b1 100644 --- a/packages/hooks/README.md +++ b/packages/hooks/README.md @@ -13,7 +13,7 @@ API functions can be called via the global `wp.hooks` like this `wp.hooks.addAct * `removeAllActions( 'hook_name' )` * `removeAllFilters( 'hook_name' )` * `doAction( 'hook_name', arg1, arg2, moreArgs, finalArg )` -* `applyFilters( 'hook_name', content )` +* `applyFilters( 'hook_name', content, arg1, arg2, moreArgs, finalArg )` * `doingAction( 'hook_name' )` * `doingFilter( 'hook_name' )` * `didAction( 'hook_name' )` From 9f4cefce276d02448051d28149a6523f7a6263c8 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 7 Sep 2017 10:07:22 -0400 Subject: [PATCH 89/91] camelCase for readme variable names --- packages/hooks/README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/hooks/README.md b/packages/hooks/README.md index 12195b1..30cc596 100644 --- a/packages/hooks/README.md +++ b/packages/hooks/README.md @@ -6,20 +6,20 @@ A lightweight & efficient EventManager for JavaScript in WordPress. ### API Usage API functions can be called via the global `wp.hooks` like this `wp.hooks.addAction()`, etc. -* `addAction( 'hook_name', 'vendorName/pluginName/functionName', callback, priority )` -* `addFilter( 'hook_name', 'vendorName/pluginName/functionName', callback, priority )` -* `removeAction( 'hook_name', 'vendorName/pluginName/functionName' )` -* `removeFilter( 'hook_name', 'vendorName/pluginName/functionName' )` -* `removeAllActions( 'hook_name' )` -* `removeAllFilters( 'hook_name' )` -* `doAction( 'hook_name', arg1, arg2, moreArgs, finalArg )` -* `applyFilters( 'hook_name', content, arg1, arg2, moreArgs, finalArg )` -* `doingAction( 'hook_name' )` -* `doingFilter( 'hook_name' )` -* `didAction( 'hook_name' )` -* `didFilter( 'hook_name' )` -* `hasAction( 'hook_name' )` -* `hasFilter( 'hook_name' )` +* `addAction( 'hookName', 'vendorName/pluginName/functionName', callback, priority )` +* `addFilter( 'hookName', 'vendorName/pluginName/functionName', callback, priority )` +* `removeAction( 'hookName', 'vendorName/pluginName/functionName' )` +* `removeFilter( 'hookName', 'vendorName/pluginName/functionName' )` +* `removeAllActions( 'hookName' )` +* `removeAllFilters( 'hookName' )` +* `doAction( 'hookName', arg1, arg2, moreArgs, finalArg )` +* `applyFilters( 'hookName', content, arg1, arg2, moreArgs, finalArg )` +* `doingAction( 'hookName' )` +* `doingFilter( 'hookName' )` +* `didAction( 'hookName' )` +* `didFilter( 'hookName' )` +* `hasAction( 'hookName' )` +* `hasFilter( 'hookName' )` ### Background From 73744fa903e428b36f4b0a3006bf737f5bd2f28f Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Tue, 12 Sep 2017 08:42:27 -0400 Subject: [PATCH 90/91] update hook and `vendor/plugin/function` wording, removing `Name` --- packages/hooks/README.md | 28 ++++++++++++------------- packages/hooks/src/validateNamespace.js | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/hooks/README.md b/packages/hooks/README.md index 30cc596..06cac12 100644 --- a/packages/hooks/README.md +++ b/packages/hooks/README.md @@ -6,20 +6,20 @@ A lightweight & efficient EventManager for JavaScript in WordPress. ### API Usage API functions can be called via the global `wp.hooks` like this `wp.hooks.addAction()`, etc. -* `addAction( 'hookName', 'vendorName/pluginName/functionName', callback, priority )` -* `addFilter( 'hookName', 'vendorName/pluginName/functionName', callback, priority )` -* `removeAction( 'hookName', 'vendorName/pluginName/functionName' )` -* `removeFilter( 'hookName', 'vendorName/pluginName/functionName' )` -* `removeAllActions( 'hookName' )` -* `removeAllFilters( 'hookName' )` -* `doAction( 'hookName', arg1, arg2, moreArgs, finalArg )` -* `applyFilters( 'hookName', content, arg1, arg2, moreArgs, finalArg )` -* `doingAction( 'hookName' )` -* `doingFilter( 'hookName' )` -* `didAction( 'hookName' )` -* `didFilter( 'hookName' )` -* `hasAction( 'hookName' )` -* `hasFilter( 'hookName' )` +* `addAction( 'hook', 'vendor/plugin/function', callback, priority )` +* `addFilter( 'hook', 'vendor/plugin/function', callback, priority )` +* `removeAction( 'hook', 'vendor/plugin/function' )` +* `removeFilter( 'hook', 'vendor/plugin/function' )` +* `removeAllActions( 'hook' )` +* `removeAllFilters( 'hook' )` +* `doAction( 'hook', arg1, arg2, moreArgs, finalArg )` +* `applyFilters( 'hook', content, arg1, arg2, moreArgs, finalArg )` +* `doingAction( 'hook' )` +* `doingFilter( 'hook' )` +* `didAction( 'hook' )` +* `didFilter( 'hook' )` +* `hasAction( 'hook' )` +* `hasFilter( 'hook' )` ### Background diff --git a/packages/hooks/src/validateNamespace.js b/packages/hooks/src/validateNamespace.js index c246bc3..e6ba236 100644 --- a/packages/hooks/src/validateNamespace.js +++ b/packages/hooks/src/validateNamespace.js @@ -19,7 +19,7 @@ function validateNamespace( namespace ) { } if ( ! /^[a-zA-Z][a-zA-Z0-9_.-]*\/[a-zA-Z][a-zA-Z0-9_.-]*\/[a-zA-Z][a-zA-Z0-9_.-]*$/.test( namespace ) ) { - console.error( 'The namespace must take the form `vendorName/pluginName/functionName`.' ); + console.error( 'The namespace must take the form `vendor/plugin/function`.' ); return false; } From 7465667e91c514b90364b191aa5f52fdfad56edf Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 13 Sep 2017 10:55:00 -0400 Subject: [PATCH 91/91] complte namespace shortening to `vendor/plugin/function` --- packages/hooks/src/createAddHook.js | 2 +- packages/hooks/src/createRemoveHook.js | 2 +- packages/hooks/src/test/index.test.js | 4 ++-- packages/hooks/src/validateNamespace.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/hooks/src/createAddHook.js b/packages/hooks/src/createAddHook.js index de97d16..9d4ac8d 100644 --- a/packages/hooks/src/createAddHook.js +++ b/packages/hooks/src/createAddHook.js @@ -13,7 +13,7 @@ function createAddHook( hooks ) { * Adds the hook to the appropriate hooks container. * * @param {string} hookName Name of hook to add - * @param {string} namespace The unique namespace identifying the callback in the form `vendorName/pluginName/functionName`. + * @param {string} namespace The unique namespace identifying the callback in the form `vendor/plugin/function`. * @param {Function} callback Function to call when the hook is run * @param {?number} priority Priority of this hook (default=10) */ diff --git a/packages/hooks/src/createRemoveHook.js b/packages/hooks/src/createRemoveHook.js index 37dfc30..42cbf9e 100644 --- a/packages/hooks/src/createRemoveHook.js +++ b/packages/hooks/src/createRemoveHook.js @@ -16,7 +16,7 @@ function createRemoveHook( hooks, removeAll ) { * given hookName and namespace. * * @param {string} hookName The name of the hook to modify. - * @param {string} namespace The unique namespace identifying the callback in the form `vendorName/pluginName/functionName`. + * @param {string} namespace The unique namespace identifying the callback in the form `vendor/plugin/function`. * * @return {number} The number of callbacks removed. */ diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index 8824ea3..cfc0aee 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -139,14 +139,14 @@ test( 'cannot add filters with empty-string namespaces', () => { test( 'cannot add filters with invalid namespaces', () => { addFilter( 'hook_name', 'invalid_name', () => null ); expect( console.error ).toHaveBeenCalledWith( - 'The namespace must take the form `vendorName/pluginName/functionName`.' + 'The namespace must take the form `vendor/plugin/function`.' ); } ); test( 'cannot add filters with namespaces missing a functionDescription', () => { addFilter( 'hook_name', 'invalid_name/', () => null ); expect( console.error ).toHaveBeenCalledWith( - 'The namespace must take the form `vendorName/pluginName/functionName`.' + 'The namespace must take the form `vendor/plugin/function`.' ); } ); diff --git a/packages/hooks/src/validateNamespace.js b/packages/hooks/src/validateNamespace.js index e6ba236..a559157 100644 --- a/packages/hooks/src/validateNamespace.js +++ b/packages/hooks/src/validateNamespace.js @@ -2,7 +2,7 @@ * Validate a namespace string. * * @param {string} namespace The namespace to validate - should take the form - * `vendorName/pluginName/functionName`. + * `vendor/plugin/function`. * * @return {bool} Whether the namespace is valid. */