https://github.com/timobechtel/krog
Add a hooks based plugin system to your library.
https://github.com/timobechtel/krog
extension hook hooks library plugin
Last synced: 8 months ago
JSON representation
Add a hooks based plugin system to your library.
- Host: GitHub
- URL: https://github.com/timobechtel/krog
- Owner: TimoBechtel
- License: mit
- Created: 2022-02-23T21:03:43.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2023-11-13T15:39:20.000Z (over 2 years ago)
- Last Synced: 2024-10-30T03:30:40.334Z (over 1 year ago)
- Topics: extension, hook, hooks, library, plugin
- Language: TypeScript
- Homepage:
- Size: 493 KB
- Stars: 4
- Watchers: 4
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
🪝
krog
Add a hooks-based plugin system to your library.
/krɔːɡ/, danish: "hook"
·
Report Bug / Request Feature
·
## Table of Contents
- [About](#about)
- [Features](#Features)
- [Installation](#install)
- [Usage](#usage)
- [As a library author](#As-a-library-author)
- [As a plugin author](#As-a-plugin-author)
- [Used by](#used-by)
- [Development / Contributing](#Development-Contributing)
## About
_krog_ adds typescript aware hooks to your library to allow for more flexible and powerful plugins.
### Features ✨
- supports async hooks
- typescript support
- data can be manipulated through hooks
- full control over how plugins are configured / loaded
Example:
```typescript
const { data } = await hooks.call('before:write', {
args: { data: 'Hello World' },
});
```
## Install
```sh
pnpm add krog
```
or
```sh
npm install krog
```
## Usage
### As library author
#### 1. Create hooks instance
```js
import { createHooks } from 'krog';
const hooks = createHooks();
```
With typescript, you can add types:
```ts
import { createHooks, Hook } from 'krog';
export type AvailableHooks = {
// first type is the arguments type, second is the context type; both are optional
'before:write': Hook<{ data: string }, { config: any }>;
};
const hooks = createHooks();
```
#### 2. Register hooks
Now anywhere in your code, register hooks, using `hooks.register(hookName, myFunction);` These may come from a plugin.
Note: When multiple functions are registered to the same hook, they are called in the order they were registered.
Examples:
```js
// register a single hook
hooks.register('before:write', myHookFunction);
```
```js
// register all hooks from a list of plugins
plugins.forEach((plugin) => {
hooks.registerMany(plugin.hooks);
});
```
```js
// manually register each hook
plugins.forEach((plugin) => {
hooks.register('before:write', plugin.beforeWrite);
});
```
#### 3. Call hooks
##### a) Wrap functions
The easiest way is to wrap existing functions using `hooks.wrap`.
This will then pass all arguments to the hook before running the initial function.
```js
// wrap your function (note the parenthesis at the end)
const wrappedPrinter = hooks.wrap('before:write', printer)();
// call the wrapped function like normal
wrappedPrinter('Hello World');
```
You can also pass a context to your wrapped function:
(that is the reason for the parenthesis at the end)
```js
// create a function factory
const createInstance = hooks.wrap('before:write', myFunction);
// create an instance of the function with a context
const myWrappedFunction = createInstance(myContext);
// call the wrapped function like normal
myWrappedFunction(myArguments);
```
##### b) Call hooks directly
You can also call a hook anywhere in your code using `hooks.call`.
You can pass arguments to the hook, and get the result back.
You can also pass a context object, which will be available in the hook function.
```js
const { data } = await hooks.call('before:write', {
args: { data: dataBeforeHook },
context: myContext,
});
```
#### 4. Unregister hooks
You can unregister hooks by:
##### a) Calling the returned unregister function
```js
const unregister = hooks.register('before:write', myHookFunction);
unregister();
// for registerMany
const unregisterMany = hooks.registerMany({
'before:write': myHookFunction,
});
unregisterMany();
```
##### b) Calling `hooks.unregister`
```js
hooks.register('before:write', myHookFunction);
// unregister a specific callback for the 'before:write' hook
hooks.unregister('before:write', myHookFunction);
// unregister all callbacks for the 'before:write' hook
hooks.unregister('before:write');
```
### As plugin author
#### Create a plugin
The syntax depends on how the library handles plugins. If the library allows you to pass hooks directly, you may configure them similar like this:
```js
const upperCasePlugin = {
hooks: {
'before:write': (args, context) => {
if (context.config.uppercase) {
// if you want to modify the data, you can return a new args object (context cannot be modified)
return {
data: args.data.toUpperCase(),
};
}
// if you don't return anything, the data will be unchanged
},
},
};
```
### FAQs
#### Differences between arguments and context
- The **context** is an object that is passed to all hooks. It can be used to pass data or functions that can be used in hooks but should not be modified by a hook.
- **arguments** on the other hand, are passed to the hook and can be modified by returning a modified version.
## Used by
- [socketdb](https://github.com/TimoBechtel/socketdb)
- [stapigen](https://github.com/TimoBechtel/stapigen)
(feel free to add your library by submitting a pull request)
## Development / Contributing
### Run tests
```sh
pnpm run test
```
### Commit messages
This project uses semantic-release for automated release versions. So commits in this project follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.2/) guidelines. I recommend using [commitizen](https://github.com/commitizen/cz-cli) for automated commit messages.
---
_This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_