Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hooks: Type package #26430

Merged
merged 8 commits into from
Nov 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 ) => {
sirreal marked this conversation as resolved.
Show resolved Hide resolved
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 ) => {
sirreal marked this conversation as resolved.
Show resolved Hide resolved
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;