diff --git a/LICENSE b/LICENSE index 528d47b..be87f15 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,4 @@ -MIT License - -Copyright (c) Jared Wray +MIT License & © Jared Wray Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 03fddc9..fd24dfc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Hookified -# Event and Middleware Hooks for Your Libraries +# Async Event and Middleware Hooks [![tests](https://github.com/jaredwray/hookified/actions/workflows/tests.yaml/badge.svg)](https://github.com/jaredwray/hookified/actions/workflows/tests.yaml) [![GitHub license](https://img.shields.io/github/license/jaredwray/hookified)](https://github.com/jaredwray/hookified/blob/master/LICENSE) @@ -10,10 +10,12 @@ ## Features - Emit Events via [Emittery](https://npmjs.com/package/emittery) -- Middleware Hooks with data passing +- Async Middleware Hooks for Your Methods - ESM and Nodejs 20+ - Maintained on a regular basis! +Special thanks to [@sindresorhus](https://github.com/sindresorhus) for the [Emittery](https://npmjs.com/package/emittery) library. 🍻 + ## Installation ```bash npm install hookified --save @@ -31,7 +33,7 @@ class MyClass extends Hookified { } async myMethodEmittingEvent() { - await this.emit('message', 'Hello World'); + await this.emit('message', 'Hello World'); //using Emittery } //with hooks you can pass data in and if they are subscribed via onHook they can modify the data @@ -43,5 +45,71 @@ class MyClass extends Hookified { return data; } } +``` + +You can even pass in multiple arguments to the hooks: + +```javascript +import { Hookified } from 'hookified'; + +class MyClass extends Hookified { + constructor() { + super(); + } + + async myMethodWithHooks() Promise { + let data = { some: 'data' }; + let data2 = { some: 'data2' }; + // do something + await this.hook('before:myMethod2', data, data2); + + return data; + } +} +``` + +## API + +Please see the [Emittery](https://npmjs.com/package/emittery) documentation for more information on the event emitter. + +### .onHook(eventName, handler) + +Subscribe to a hook event. + +### .removeHook(eventName) + +Unsubscribe from a hook event. + +### .hook(eventName, ...args) + +Run a hook event. + +### .hooks + +Get all hooks. + +### .getHooks(eventName) + +Get all hooks for an event. + +### .clearHooks(eventName) + +## Development and Testing + +Hookified is written in TypeScript and tests are written in `vitest`. To run the tests, use the following command: + +To setup the environment and run the tests: + +```bash +npm i && npm test +``` + +To contribute follow the [Contributing Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md). + +## License + +[MIT & © Jared Wray](LICENSE) + + diff --git a/package.json b/package.json index ea9c176..e1b64ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hookified", - "version": "0.6.0", + "version": "0.7.0", "description": "Event and Middleware Hooks", "type": "module", "main": "./dist/index.js", diff --git a/src/index.ts b/src/index.ts index 5788283..fc030ab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,7 @@ export class Hookified extends Emittery { } // Adds a handler function for a specific event - async onHook(event: string, handler: Hook) { + onHook(event: string, handler: Hook) { const eventHandlers = this._hooks.get(event); if (eventHandlers) { eventHandlers.push(handler); @@ -21,7 +21,7 @@ export class Hookified extends Emittery { } // Removes a specific handler function for a specific event - async removeHook(event: string, handler: Hook) { + removeHook(event: string, handler: Hook) { const eventHandlers = this._hooks.get(event); if (eventHandlers) { const index = eventHandlers.indexOf(handler); @@ -52,4 +52,12 @@ export class Hookified extends Emittery { // Creating a new map to prevent external modifications to the original map return this._hooks; } + + getHooks(event: string) { + return this._hooks.get(event); + } + + clearHooks() { + this._hooks.clear(); + } } diff --git a/test/index.test.ts b/test/index.test.ts index 2c10869..c99c4cd 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -13,21 +13,35 @@ describe('Hookified', () => { const handler = () => {}; // eslint-disable-next-line @typescript-eslint/no-empty-function const handler2 = () => {}; - await hookified.onHook('event', handler); - await hookified.onHook('event2', handler2); - expect(hookified.hooks.get('event')).toEqual([handler]); - expect(hookified.hooks.get('event2')).toEqual([handler2]); + hookified.onHook('event', handler); + hookified.onHook('event2', handler2); + expect(hookified.getHooks('event')).toEqual([handler]); + expect(hookified.getHooks('event2')).toEqual([handler2]); expect(hookified.hooks.size).toBe(2); }); + test('onHook with Clear', async () => { + const hookified = new Hookified(); + // eslint-disable-next-line @typescript-eslint/no-empty-function + const handler = () => {}; + // eslint-disable-next-line @typescript-eslint/no-empty-function + const handler2 = () => {}; + hookified.onHook('event', handler); + hookified.onHook('event2', handler2); + expect(hookified.getHooks('event')).toEqual([handler]); + expect(hookified.getHooks('event2')).toEqual([handler2]); + hookified.clearHooks(); + expect(hookified.hooks.size).toBe(0); + }); + test('onHook multiple handlers', async () => { const hookified = new Hookified(); // eslint-disable-next-line @typescript-eslint/no-empty-function const handler = () => {}; // eslint-disable-next-line @typescript-eslint/no-empty-function const handler2 = () => {}; - await hookified.onHook('event', handler); - await hookified.onHook('event', handler2); + hookified.onHook('event', handler); + hookified.onHook('event', handler2); expect(hookified.hooks.get('event')).toEqual([handler, handler2]); expect(hookified.hooks.size).toBe(1); }); @@ -38,10 +52,10 @@ describe('Hookified', () => { const handler = () => {}; // eslint-disable-next-line @typescript-eslint/no-empty-function const handler2 = () => {}; - await hookified.onHook('event', handler); - await hookified.onHook('event', handler2); - await hookified.removeHook('event', handler); - expect(hookified.hooks.get('event')).toEqual([handler2]); + hookified.onHook('event', handler); + hookified.onHook('event', handler2); + hookified.removeHook('event', handler); + expect(hookified.getHooks('event')).toEqual([handler2]); expect(hookified.hooks.size).toBe(1); }); @@ -56,7 +70,7 @@ describe('Hookified', () => { handlerData = data; }; - await hookified.onHook('event', handler); + hookified.onHook('event', handler); await hookified.hook('event', data); expect(handlerData.key).toBe('modified'); }); @@ -78,7 +92,7 @@ describe('Hookified', () => { console.log(handlerData); }; - await hookified.onHook('event', handler); + hookified.onHook('event', handler); await hookified.hook('event', data, data2, data3); expect(handlerData[0].key).toBe('modified'); expect(handlerData[1].key).toBe('foo'); @@ -94,13 +108,12 @@ describe('Hookified', () => { }); const data = {key: 'value'}; - let handlerData; - const handler = (data: any) => { + const handler = () => { throw new Error('error'); }; - await hookified.onHook('event', handler); + hookified.onHook('event', handler); await hookified.hook('event', data); expect(errorMessage).toBe('Error in hook handler for event "event": error'); });