mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-23 08:56:17 -04:00
hooks: Rewrite callAll
and aCallAll
for consistency
Rewrite the `callAll` and `aCallAll` functions to support all reasonable hook behaviors and to report errors for unreasonable behaviors (e.g., calling the callback twice). Now a hook function like the following works as expected when invoked by `aCallAll`: ``` exports.myHookFn = (hookName, context, cb) => { cb('some value'); return; }; ```
This commit is contained in:
parent
79119baf58
commit
36aceb3aba
6 changed files with 1400 additions and 74 deletions
|
@ -4,48 +4,114 @@ A hook function is registered with a hook via the plugin's `ep.json` file. See
|
|||
the Plugins section for details. A hook may have many registered functions from
|
||||
different plugins.
|
||||
|
||||
When a hook is invoked, its registered functions are called with three
|
||||
arguments:
|
||||
Some hooks call their registered functions one at a time until one of them
|
||||
returns a value. Others always call all of their registered functions and
|
||||
combine the results (if applicable).
|
||||
|
||||
1. hookName - The name of the hook being invoked.
|
||||
2. context - An object with some relevant information about the context of the
|
||||
## Registered hook functions
|
||||
|
||||
Note: The documentation in this section applies to every hook unless the
|
||||
hook-specific documentation says otherwise.
|
||||
|
||||
### Arguments
|
||||
|
||||
Hook functions are called with three arguments:
|
||||
|
||||
1. `hookName` - The name of the hook being invoked.
|
||||
2. `context` - An object with some relevant information about the context of the
|
||||
call. See the hook-specific documentation for details.
|
||||
3. callback - Function to call when done. This callback takes a single argument,
|
||||
the meaning of which depends on the hook. See the "Return values" section for
|
||||
general information that applies to most hooks. The value returned by this
|
||||
callback must be returned by the hook function unless otherwise specified.
|
||||
3. `cb` - For asynchronous operations this callback can be called to signal
|
||||
completion and optionally provide a return value. The callback takes a single
|
||||
argument, the meaning of which depends on the hook (see the "Return values"
|
||||
section for general information that applies to most hooks). This callback
|
||||
always returns `undefined`.
|
||||
|
||||
## Return values
|
||||
### Expected behavior
|
||||
|
||||
Note: This section applies to every hook unless the hook-specific documentation
|
||||
says otherwise.
|
||||
The presence of a callback parameter suggests that every hook function can run
|
||||
asynchronously. While that is the eventual goal, there are some legacy hooks
|
||||
that expect their hook functions to provide a value synchronously. For such
|
||||
hooks, the hook functions must do one of the following:
|
||||
|
||||
Hook functions return zero or more values to Etherpad by passing an array to the
|
||||
provided callback. Hook functions typically provide a single value (array of
|
||||
length one). If the function does not want to or need to provide a value, it may
|
||||
pass an empty array or `undefined` (which is treated the same as an empty
|
||||
array). Hook functions may also provide more than one value (array of length two
|
||||
or more).
|
||||
* Call the callback with a non-Promise value (`undefined` is acceptable) and
|
||||
return `undefined`, in that order.
|
||||
* Return a non-Promise value other than `undefined` (`null` is acceptable) and
|
||||
never call the callback. Note that `async` functions *always* return a
|
||||
Promise, so they must never be used for synchronous hooks.
|
||||
* Only have two parameters (`hookName` and `context`) and return any non-Promise
|
||||
value (`undefined` is acceptable).
|
||||
|
||||
Some hooks concatenate the arrays provided by its registered functions. For
|
||||
example, if a hook's registered functions pass `[1, 2]`, `undefined`, `[3, 4]`,
|
||||
`[]`, and `[5]` to the provided callback, then the hook's return value is `[1,
|
||||
2, 3, 4, 5]`.
|
||||
For hooks that permit asynchronous behavior, the hook functions must do one or
|
||||
more of the following:
|
||||
|
||||
Other hooks only use the first non-empty array provided by a registered
|
||||
function. In this case, each of the hook's registered functions is called one at
|
||||
a time until one provides a non-empty array. The remaining functions are
|
||||
skipped. If none of the functions provide a non-empty array, or there are no
|
||||
registered functions, the hook's return value is `[]`.
|
||||
* Return `undefined` and call the callback, in either order.
|
||||
* Return something other than `undefined` (`null` is acceptable) and never call
|
||||
the callback. Note that `async` functions *always* return a Promise, so they
|
||||
must never call the callback.
|
||||
* Only have two parameters (`hookName` and `context`).
|
||||
|
||||
Example:
|
||||
Note that the acceptable behaviors for asynchronous hook functions is a superset
|
||||
of the acceptable behaviors for synchronous hook functions.
|
||||
|
||||
```
|
||||
exports.abstractHook = (hookName, context, callback) => {
|
||||
if (notApplicableToThisPlugin(context)) {
|
||||
return callback();
|
||||
}
|
||||
const value = doSomeProcessing(context);
|
||||
return callback([value]);
|
||||
WARNING: The number of parameters is determined by examining
|
||||
[Function.length](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length),
|
||||
which does not count [default
|
||||
parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters)
|
||||
or ["rest"
|
||||
parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters).
|
||||
To avoid problems, do not use default or rest parameters when defining hook
|
||||
functions.
|
||||
|
||||
### Return values
|
||||
|
||||
A hook function can provide a value to Etherpad in one of the following ways:
|
||||
|
||||
* Pass the desired value as the first argument to the callback.
|
||||
* Return the desired value directly. The value must not be `undefined` unless
|
||||
the hook function only has two parameters. (Hook functions with three
|
||||
parameters that want to provide `undefined` should instead use the callback.)
|
||||
* For hooks that permit asynchronous behavior, return a Promise that resolves to
|
||||
the desired value.
|
||||
* For hooks that permit asynchronous behavior, pass a Promise that resolves to
|
||||
the desired value as the first argument to the callback.
|
||||
|
||||
Examples:
|
||||
|
||||
```javascript
|
||||
exports.exampleOne = (hookName, context, callback) => {
|
||||
return 'valueOne';
|
||||
};
|
||||
|
||||
exports.exampleTwo = (hookName, context, callback) => {
|
||||
callback('valueTwo');
|
||||
return;
|
||||
};
|
||||
|
||||
// ONLY FOR HOOKS THAT PERMIT ASYNCHRONOUS BEHAVIOR
|
||||
exports.exampleThree = (hookName, context, callback) => {
|
||||
return new Promise('valueThree');
|
||||
};
|
||||
|
||||
// ONLY FOR HOOKS THAT PERMIT ASYNCHRONOUS BEHAVIOR
|
||||
exports.exampleFour = (hookName, context, callback) => {
|
||||
callback(new Promise('valueFour'));
|
||||
return;
|
||||
};
|
||||
|
||||
// ONLY FOR HOOKS THAT PERMIT ASYNCHRONOUS BEHAVIOR
|
||||
exports.exampleFive = async (hookName, context) => {
|
||||
// Note that this function is async, so it actually returns a Promise that
|
||||
// is resolved to 'valueFive'.
|
||||
return 'valueFive';
|
||||
};
|
||||
```
|
||||
|
||||
Etherpad collects the values provided by the hook functions into an array,
|
||||
filters out all `undefined` values, then flattens the array one level.
|
||||
Flattening one level makes it possible for a hook function to behave as if it
|
||||
were multiple separate hook functions.
|
||||
|
||||
For example: Suppose a hook has eight registered functions that return the
|
||||
following values: `1`, `[2]`, `['3a', '3b']` `[[4]]`, `undefined`,
|
||||
`[undefined]`, `[]`, and `null`. The value returned to the caller of the hook is
|
||||
`[1, 2, '3a', '3b', [4], undefined, null]`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue