Skip to content

Commit

Permalink
Hooks: Type package (#26430)
Browse files Browse the repository at this point in the history
* Simplify gutenberg env types

* eslint ignore build-types

* Type hooks package

Co-authored-by: Sara Marcondes <saram@fastmail.com>
  • Loading branch information
sirreal and sarayourfriend committed Nov 3, 2020
1 parent 90a70fd commit 26806cb
Show file tree
Hide file tree
Showing 17 changed files with 130 additions and 96 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.cache
build
build-module
build-types
node_modules
packages/block-serialization-spec-parser/parser.js
packages/e2e-tests/plugins
Expand Down
9 changes: 2 additions & 7 deletions packages/block-editor/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,9 @@
"rootDir": "src",
"declarationDir": "build-types"
},
"references": [
{ "path": "../element" }
],
"references": [ { "path": "../element" }, { "path": "../hooks" } ],
// NOTE: This package is being progressively typed. You are encouraged to
// expand this array with files which can be type-checked. At some point in
// the future, this can be simplified to an `includes` of `src/**/*`.
"files": [
"src/components/block-context/index.js",
"src/utils/dom.js"
]
"files": [ "src/components/block-context/index.js", "src/utils/dom.js" ]
}
2 changes: 1 addition & 1 deletion packages/components/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"rootDir": "src",
"declarationDir": "build-types"
},
"references": [ { "path": "../primitives" } ],
"references": [ { "path": "../hooks" }, { "path": "../primitives" } ],
"include": [
"src/base-control/**/*",
"src/dashicon/**/*",
Expand Down
4 changes: 4 additions & 0 deletions packages/hooks/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### New Feature

- Include TypeScript type declarations ([#26430](https://github.com/WordPress/gutenberg/pull/26430))

## 2.6.0 (2019-08-29)

### New Feature
Expand Down
1 change: 1 addition & 0 deletions packages/hooks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"main": "build/index.js",
"module": "build-module/index.js",
"react-native": "src/index",
"types": "build-types",
"dependencies": {
"@babel/runtime": "^7.11.2"
},
Expand Down
26 changes: 15 additions & 11 deletions packages/hooks/src/createAddHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@ import validateNamespace from './validateNamespace.js';
import validateHookName from './validateHookName.js';
import { doAction } from './';

/**
* @callback AddHook
*
* 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 `vendor/plugin/function`.
* @param {import('.').Callback} callback Function to call when the hook is run
* @param {number} [priority=10] Priority of this hook
*/

/**
* Returns a function which, when invoked, will add a hook.
*
* @param {Object} hooks Stored hooks, keyed by hook name.
* @param {import('.').Hooks} hooks Stored hooks, keyed by hook name.
*
* @return {Function} Function that adds a new hook.
* @return {AddHook} 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 {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)
*/
return function addHook( hookName, namespace, callback, priority = 10 ) {
if ( ! validateHookName( hookName ) ) {
return;
Expand Down Expand Up @@ -51,6 +54,7 @@ function createAddHook( hooks ) {
// Find the correct insert index of the new hook.
const handlers = hooks[ hookName ].handlers;

/** @type {number} */
let i;
for ( i = handlers.length; i > 0; i-- ) {
if ( priority >= handlers[ i - 1 ].priority ) {
Expand All @@ -70,7 +74,7 @@ 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 || [] ).forEach( ( hookInfo ) => {
hooks.__current.forEach( ( hookInfo ) => {
if (
hookInfo.name === hookName &&
hookInfo.currentIndex >= i
Expand Down
17 changes: 3 additions & 14 deletions packages/hooks/src/createCurrentHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,13 @@
* currently running hook, or `null` if no hook of the given type is currently
* running.
*
* @param {Object} hooks Stored hooks, keyed by hook name.
* @param {import('.').Hooks} hooks Stored hooks, keyed by hook name.
*
* @return {Function} Function that returns the current hook.
* @return {() => string | null} Function that returns the current hook name or null.
*/
function createCurrentHook( hooks ) {
/**
* 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 ].name;
return hooks.__current[ hooks.__current.length - 1 ]?.name ?? null;
};
}

Expand Down
21 changes: 12 additions & 9 deletions packages/hooks/src/createDidHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@
*/
import validateHookName from './validateHookName.js';

/**
* @callback DidHook
*
* Returns the number of times an action has been fired.
*
* @param {string} hookName The hook name to check.
*
* @return {number | undefined} The number of times the hook has run.
*/

/**
* 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.
* @param {import('.').Hooks} hooks Stored hooks, keyed by hook name.
*
* @return {Function} Function that returns a hook's call count.
* @return {DidHook} 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 ) {
if ( ! validateHookName( hookName ) ) {
return;
Expand Down
24 changes: 13 additions & 11 deletions packages/hooks/src/createDoingHook.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
/**
* @callback DoingHook
* 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 {boolean} Whether the hook is being executed.
*/

/**
* Returns a function which, when invoked, will return whether a hook is
* currently being executed.
*
* @param {Object} hooks Stored hooks, keyed by hook name.
* @param {import('.').Hooks} hooks Stored hooks, keyed by hook name.
*
* @return {Function} Function that returns whether a hook is currently
* being executed.
* @return {DoingHook} 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 {boolean} 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 ) {
Expand Down
26 changes: 14 additions & 12 deletions packages/hooks/src/createHasHook.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
/**
* @callback HasHook
*
* Returns whether any handlers are attached for the given hookName and optional namespace.
*
* @param {string} hookName The name of the hook to check for.
* @param {string} [namespace] Optional. The unique namespace identifying the callback
* in the form `vendor/plugin/function`.
*
* @return {boolean} Whether there are handlers that are attached to the given hook.
*/
/**
* 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.
* @param {import('.').Hooks} hooks Stored hooks, keyed by hook name.
*
* @return {Function} Function that returns whether any handlers are
* attached to a particular hook and optional namespace.
* @return {HasHook} Function that returns whether any handlers are
* attached to a particular hook and optional namespace.
*/
function createHasHook( hooks ) {
/**
* Returns whether any handlers are attached for the given hookName and optional namespace.
*
* @param {string} hookName The name of the hook to check for.
* @param {?string} namespace Optional. The unique namespace identifying the callback
* in the form `vendor/plugin/function`.
*
* @return {boolean} Whether there are handlers that are attached to the given hook.
*/
return function hasHook( hookName, namespace ) {
// Use the namespace if provided.
if ( 'undefined' !== typeof namespace ) {
Expand Down
4 changes: 2 additions & 2 deletions packages/hooks/src/createHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import createDidHook from './createDidHook';

/**
* Returns an instance of the hooks object.
*
* @return {Object} Object that contains all hooks.
*/
function createHooks() {
/** @type {import('.').Hooks} */
const actions = Object.create( null );
/** @type {import('.').Hooks} */
const filters = Object.create( null );
actions.__current = [];
filters.__current = [];
Expand Down
33 changes: 19 additions & 14 deletions packages/hooks/src/createRemoveHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,30 @@ import validateNamespace from './validateNamespace.js';
import validateHookName from './validateHookName.js';
import { doAction } from './';

/**
* @callback RemoveHook
* Removes the specified callback (or all callbacks) from the hook with a 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 `vendor/plugin/function`.
*
* @return {number | undefined} The number of callbacks removed.
*/

/**
* 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 {boolean} removeAll Whether to remove all callbacks for a hookName, without regard to namespace. Used to create `removeAll*` functions.
* @param {import('.').Hooks} hooks Stored hooks, keyed by hook name.
* @param {boolean} [removeAll=false] Whether to remove all callbacks for a hookName,
* without regard to namespace. Used to create
* `removeAll*` functions.
*
* @return {Function} Function that removes hooks.
* @return {RemoveHook} Function that removes hooks.
*/
function createRemoveHook( hooks, removeAll ) {
/**
* Removes the specified callback (or all callbacks) from the hook with a
* 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 `vendor/plugin/function`.
*
* @return {number} The number of callbacks removed.
*/
function createRemoveHook( hooks, removeAll = false ) {
return function removeHook( hookName, namespace ) {
if ( ! validateHookName( hookName ) ) {
return;
Expand Down Expand Up @@ -58,7 +63,7 @@ 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 || [] ).forEach( ( hookInfo ) => {
hooks.__current.forEach( ( hookInfo ) => {
if (
hookInfo.name === hookName &&
hookInfo.currentIndex >= i
Expand Down
18 changes: 5 additions & 13 deletions packages/hooks/src/createRunHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,13 @@
* 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 {?boolean} returnFirstArg Whether each hook callback is expected to
* return its first argument.
* @param {import('.').Hooks} hooks Stored hooks, keyed by hook name.
* @param {boolean} [returnFirstArg=false] Whether each hook callback is expected to
* return its first argument.
*
* @return {Function} Function that runs hook callbacks.
* @return {(hookName:string, ...args: unknown[]) => unknown} 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.
*/
function createRunHook( hooks, returnFirstArg = false ) {
return function runHooks( hookName, ...args ) {
if ( ! hooks[ hookName ] ) {
hooks[ hookName ] = {
Expand Down
26 changes: 26 additions & 0 deletions packages/hooks/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,32 @@
*/
import createHooks from './createHooks';

/** @typedef {(...args: any[])=>any} Callback */

/**
* @typedef Handler
* @property {Callback} callback The callback
* @property {string} namespace The namespace
* @property {number} priority The namespace
*/

/**
* @typedef Hook
* @property {Handler[]} handlers Array of handlers
* @property {number} runs Run counter
*
*/

/**
* @typedef Current
* @property {string} name Hook name
* @property {number} currentIndex The index
*/

/**
* @typedef {Record<string, Hook> & {__current: Current[]}} Hooks
*/

const {
addAction,
addFilter,
Expand Down
9 changes: 9 additions & 0 deletions packages/hooks/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"declarationDir": "build-types",
"types": [ "gutenberg-env" ]
},
"include": [ "src/**/*" ]
}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
{ "path": "packages/escape-html" },
{ "path": "packages/eslint-plugin" },
{ "path": "packages/html-entities" },
{ "path": "packages/hooks" },
{ "path": "packages/i18n" },
{ "path": "packages/icons" },
{ "path": "packages/is-shallow-equal" },
Expand Down
4 changes: 2 additions & 2 deletions typings/gutenberg-env/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
interface Environment {
NODE_ENV?: unknown;
NODE_ENV: unknown;
}
interface Process {
env?: Environment;
env: Environment;
}
declare var process: Process;

0 comments on commit 26806cb

Please sign in to comment.