hookified 1.12.0 → 1.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +233 -24
- package/dist/browser/index.global.js +570 -1
- package/dist/browser/index.global.js.map +1 -1
- package/dist/browser/index.js +571 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +595 -1
- package/dist/node/index.d.cts +64 -0
- package/dist/node/index.d.ts +64 -0
- package/dist/node/index.js +567 -1
- package/package.json +11 -12
package/README.md
CHANGED
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
- Browser Support and Delivered via CDN
|
|
17
17
|
- Ability to throw errors in hooks
|
|
18
18
|
- Ability to pass in a logger (such as Pino) for errors
|
|
19
|
+
- Enforce consistent hook naming conventions with `enforceBeforeAfter`
|
|
20
|
+
- Deprecation warnings for hooks with `deprecatedHooks`
|
|
21
|
+
- Control deprecated hook execution with `allowDeprecated`
|
|
19
22
|
- No package dependencies and only 100KB in size
|
|
20
23
|
- Fast and Efficient with [Benchmarks](#benchmarks)
|
|
21
24
|
- Maintained on a regular basis!
|
|
@@ -27,6 +30,9 @@
|
|
|
27
30
|
- [API - Hooks](#api---hooks)
|
|
28
31
|
- [.throwHookErrors](#throwhookerrors)
|
|
29
32
|
- [.logger](#logger)
|
|
33
|
+
- [.enforceBeforeAfter](#enforcebeforeafter)
|
|
34
|
+
- [.deprecatedHooks](#deprecatedhooks)
|
|
35
|
+
- [.allowDeprecated](#allowdeprecated)
|
|
30
36
|
- [.onHook(eventName, handler)](#onhookeventname-handler)
|
|
31
37
|
- [.onHookEntry(hookEntry)](#onhookentryhookentry)
|
|
32
38
|
- [.addHook(eventName, handler)](#addhookeventname-handler)
|
|
@@ -57,9 +63,9 @@
|
|
|
57
63
|
- [.eventNames()](#eventnames)
|
|
58
64
|
- [.listenerCount(eventName?)](#listenercounteventname)
|
|
59
65
|
- [.rawListeners(eventName?)](#rawlistenerseventname)
|
|
60
|
-
- [Development and Contribution](#development-and-contribution)
|
|
61
66
|
- [Benchmarks](#benchmarks)
|
|
62
|
-
- [
|
|
67
|
+
- [How to Contribute](#how-to-contribute)
|
|
68
|
+
- [License and Copyright](#license-and-copyright)
|
|
63
69
|
|
|
64
70
|
# Installation
|
|
65
71
|
```bash
|
|
@@ -231,6 +237,197 @@ myClass.onHook('before:myMethod2', async () => {
|
|
|
231
237
|
await myClass.hook('before:myMethod2');
|
|
232
238
|
```
|
|
233
239
|
|
|
240
|
+
## .enforceBeforeAfter
|
|
241
|
+
|
|
242
|
+
If set to true, enforces that all hook names must start with 'before' or 'after'. This is useful for maintaining consistent hook naming conventions in your application. Default is false.
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
import { Hookified } from 'hookified';
|
|
246
|
+
|
|
247
|
+
class MyClass extends Hookified {
|
|
248
|
+
constructor() {
|
|
249
|
+
super({ enforceBeforeAfter: true });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const myClass = new MyClass();
|
|
254
|
+
|
|
255
|
+
console.log(myClass.enforceBeforeAfter); // true
|
|
256
|
+
|
|
257
|
+
// These will work fine
|
|
258
|
+
myClass.onHook('beforeSave', async () => {
|
|
259
|
+
console.log('Before save hook');
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
myClass.onHook('afterSave', async () => {
|
|
263
|
+
console.log('After save hook');
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
myClass.onHook('before:validation', async () => {
|
|
267
|
+
console.log('Before validation hook');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// This will throw an error
|
|
271
|
+
try {
|
|
272
|
+
myClass.onHook('customEvent', async () => {
|
|
273
|
+
console.log('This will not work');
|
|
274
|
+
});
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.log(error.message); // Hook event "customEvent" must start with "before" or "after" when enforceBeforeAfter is enabled
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// You can also change it dynamically
|
|
280
|
+
myClass.enforceBeforeAfter = false;
|
|
281
|
+
myClass.onHook('customEvent', async () => {
|
|
282
|
+
console.log('This will work now');
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
The validation applies to all hook-related methods:
|
|
287
|
+
- `onHook()`, `addHook()`, `onHookEntry()`, `onHooks()`
|
|
288
|
+
- `prependHook()`, `onceHook()`, `prependOnceHook()`
|
|
289
|
+
- `hook()`, `callHook()`
|
|
290
|
+
- `getHooks()`, `removeHook()`, `removeHooks()`
|
|
291
|
+
|
|
292
|
+
Note: The `beforeHook()` and `afterHook()` helper methods automatically generate proper hook names and work regardless of the `enforceBeforeAfter` setting.
|
|
293
|
+
|
|
294
|
+
## .deprecatedHooks
|
|
295
|
+
|
|
296
|
+
A Map of deprecated hook names to deprecation messages. When a deprecated hook is used, a warning will be emitted via the 'warn' event and logged to the logger (if available). Default is an empty Map.
|
|
297
|
+
|
|
298
|
+
```javascript
|
|
299
|
+
import { Hookified } from 'hookified';
|
|
300
|
+
|
|
301
|
+
// Define deprecated hooks with custom messages
|
|
302
|
+
const deprecatedHooks = new Map([
|
|
303
|
+
['oldHook', 'Use newHook instead'],
|
|
304
|
+
['legacyMethod', 'This hook will be removed in v2.0'],
|
|
305
|
+
['deprecatedFeature', ''] // Empty message - will just say "deprecated"
|
|
306
|
+
]);
|
|
307
|
+
|
|
308
|
+
class MyClass extends Hookified {
|
|
309
|
+
constructor() {
|
|
310
|
+
super({ deprecatedHooks });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const myClass = new MyClass();
|
|
315
|
+
|
|
316
|
+
console.log(myClass.deprecatedHooks); // Map with deprecated hooks
|
|
317
|
+
|
|
318
|
+
// Listen for deprecation warnings
|
|
319
|
+
myClass.on('warn', (event) => {
|
|
320
|
+
console.log(`Deprecation warning: ${event.message}`);
|
|
321
|
+
// event.hook contains the hook name
|
|
322
|
+
// event.message contains the full warning message
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Using a deprecated hook will emit warnings
|
|
326
|
+
myClass.onHook('oldHook', () => {
|
|
327
|
+
console.log('This hook is deprecated');
|
|
328
|
+
});
|
|
329
|
+
// Output: Hook "oldHook" is deprecated: Use newHook instead
|
|
330
|
+
|
|
331
|
+
// Using a deprecated hook with empty message
|
|
332
|
+
myClass.onHook('deprecatedFeature', () => {
|
|
333
|
+
console.log('This hook is deprecated');
|
|
334
|
+
});
|
|
335
|
+
// Output: Hook "deprecatedFeature" is deprecated
|
|
336
|
+
|
|
337
|
+
// You can also set deprecated hooks dynamically
|
|
338
|
+
myClass.deprecatedHooks.set('anotherOldHook', 'Please migrate to the new API');
|
|
339
|
+
|
|
340
|
+
// Works with logger if provided
|
|
341
|
+
import pino from 'pino';
|
|
342
|
+
const logger = pino();
|
|
343
|
+
|
|
344
|
+
const myClassWithLogger = new Hookified({
|
|
345
|
+
deprecatedHooks,
|
|
346
|
+
logger
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// Deprecation warnings will be logged to logger.warn
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
The deprecation warning system applies to all hook-related methods:
|
|
353
|
+
- Registration: `onHook()`, `addHook()`, `onHookEntry()`, `onHooks()`, `prependHook()`, `onceHook()`, `prependOnceHook()`
|
|
354
|
+
- Execution: `hook()`, `callHook()`
|
|
355
|
+
- Management: `getHooks()`, `removeHook()`, `removeHooks()`
|
|
356
|
+
|
|
357
|
+
Deprecation warnings are emitted in two ways:
|
|
358
|
+
1. **Event**: A 'warn' event is emitted with `{ hook: string, message: string }`
|
|
359
|
+
2. **Logger**: Logged to `logger.warn()` if a logger is configured and has a `warn` method
|
|
360
|
+
|
|
361
|
+
## .allowDeprecated
|
|
362
|
+
|
|
363
|
+
Controls whether deprecated hooks are allowed to be registered and executed. Default is true. When set to false, deprecated hooks will still emit warnings but will be prevented from registration and execution.
|
|
364
|
+
|
|
365
|
+
```javascript
|
|
366
|
+
import { Hookified } from 'hookified';
|
|
367
|
+
|
|
368
|
+
const deprecatedHooks = new Map([
|
|
369
|
+
['oldHook', 'Use newHook instead']
|
|
370
|
+
]);
|
|
371
|
+
|
|
372
|
+
class MyClass extends Hookified {
|
|
373
|
+
constructor() {
|
|
374
|
+
super({ deprecatedHooks, allowDeprecated: false });
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const myClass = new MyClass();
|
|
379
|
+
|
|
380
|
+
console.log(myClass.allowDeprecated); // false
|
|
381
|
+
|
|
382
|
+
// Listen for deprecation warnings (still emitted even when blocked)
|
|
383
|
+
myClass.on('warn', (event) => {
|
|
384
|
+
console.log(`Warning: ${event.message}`);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Try to register a deprecated hook - will emit warning but not register
|
|
388
|
+
myClass.onHook('oldHook', () => {
|
|
389
|
+
console.log('This will never execute');
|
|
390
|
+
});
|
|
391
|
+
// Output: Warning: Hook "oldHook" is deprecated: Use newHook instead
|
|
392
|
+
|
|
393
|
+
// Verify hook was not registered
|
|
394
|
+
console.log(myClass.getHooks('oldHook')); // undefined
|
|
395
|
+
|
|
396
|
+
// Try to execute a deprecated hook - will emit warning but not execute
|
|
397
|
+
await myClass.hook('oldHook');
|
|
398
|
+
// Output: Warning: Hook "oldHook" is deprecated: Use newHook instead
|
|
399
|
+
// (but no handlers execute)
|
|
400
|
+
|
|
401
|
+
// Non-deprecated hooks work normally
|
|
402
|
+
myClass.onHook('validHook', () => {
|
|
403
|
+
console.log('This works fine');
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
console.log(myClass.getHooks('validHook')); // [handler function]
|
|
407
|
+
|
|
408
|
+
// You can dynamically change the setting
|
|
409
|
+
myClass.allowDeprecated = true;
|
|
410
|
+
|
|
411
|
+
// Now deprecated hooks can be registered and executed
|
|
412
|
+
myClass.onHook('oldHook', () => {
|
|
413
|
+
console.log('Now this works');
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
console.log(myClass.getHooks('oldHook')); // [handler function]
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Behavior when `allowDeprecated` is false:**
|
|
420
|
+
- **Registration**: All hook registration methods (`onHook`, `addHook`, `prependHook`, etc.) will emit warnings but skip registration
|
|
421
|
+
- **Execution**: Hook execution methods (`hook`, `callHook`) will emit warnings but skip execution
|
|
422
|
+
- **Management**: Hook management methods (`getHooks`, `removeHook`) will emit warnings and return undefined/skip operations
|
|
423
|
+
- **Warnings**: Deprecation warnings are always emitted regardless of `allowDeprecated` setting
|
|
424
|
+
|
|
425
|
+
**Use cases:**
|
|
426
|
+
- **Development**: Keep `allowDeprecated: true` to maintain functionality while seeing warnings
|
|
427
|
+
- **Testing**: Set `allowDeprecated: false` to ensure no deprecated hooks are accidentally used
|
|
428
|
+
- **Migration**: Gradually disable deprecated hooks during API transitions
|
|
429
|
+
- **Production**: Disable deprecated hooks to prevent legacy code execution
|
|
430
|
+
|
|
234
431
|
## .onHook(eventName, handler)
|
|
235
432
|
|
|
236
433
|
Subscribe to a hook event.
|
|
@@ -999,7 +1196,31 @@ myClass.on('message', (message) => {
|
|
|
999
1196
|
console.log(myClass.rawListeners('message'));
|
|
1000
1197
|
```
|
|
1001
1198
|
|
|
1002
|
-
#
|
|
1199
|
+
# Benchmarks
|
|
1200
|
+
|
|
1201
|
+
We are doing very simple benchmarking to see how this compares to other libraries using `tinybench`. This is not a full benchmark but just a simple way to see how it performs. Our goal is to be as close or better than the other libraries including native (EventEmitter).
|
|
1202
|
+
|
|
1203
|
+
## Hooks
|
|
1204
|
+
|
|
1205
|
+
| name | summary | ops/sec | time/op | margin | samples |
|
|
1206
|
+
|-----------------------|:---------:|----------:|----------:|:--------:|----------:|
|
|
1207
|
+
| Hookified (v1.12.1) | 🥇 | 5M | 243ns | ±0.89% | 4M |
|
|
1208
|
+
| Hookable (v5.5.3) | -69% | 1M | 835ns | ±2.23% | 1M |
|
|
1209
|
+
|
|
1210
|
+
## Emits
|
|
1211
|
+
|
|
1212
|
+
This shows how on par `hookified` is to the native `EventEmitter` and popular `eventemitter3`. These are simple emitting benchmarks to see how it performs.
|
|
1213
|
+
|
|
1214
|
+
| name | summary | ops/sec | time/op | margin | samples |
|
|
1215
|
+
|---------------------------|:---------:|----------:|----------:|:--------:|----------:|
|
|
1216
|
+
| Hookified (v1.12.1) | 🥇 | 12M | 89ns | ±2.56% | 11M |
|
|
1217
|
+
| EventEmitter3 (v5.0.1) | -1.7% | 12M | 91ns | ±3.31% | 11M |
|
|
1218
|
+
| EventEmitter (v20.17.0) | -4% | 11M | 92ns | ±0.38% | 11M |
|
|
1219
|
+
| Emittery (v1.2.0) | -91% | 1M | 1µs | ±1.59% | 993K |
|
|
1220
|
+
|
|
1221
|
+
_Note: the `EventEmitter` version is Nodejs versioning._
|
|
1222
|
+
|
|
1223
|
+
# How to Contribute
|
|
1003
1224
|
|
|
1004
1225
|
Hookified is written in TypeScript and tests are written in `vitest`. To run the tests, use the following command:
|
|
1005
1226
|
|
|
@@ -1017,31 +1238,19 @@ npm install -g pnpm
|
|
|
1017
1238
|
|
|
1018
1239
|
To contribute follow the [Contributing Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
1019
1240
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
## Hooks
|
|
1025
|
-
|
|
1026
|
-
| name | summary | ops/sec | time/op | margin | samples |
|
|
1027
|
-
|-------------------|:---------:|----------:|----------:|:--------:|----------:|
|
|
1028
|
-
| Hookified 1.8.0 | 🥇 | 4M | 299ns | ±2.42% | 3M |
|
|
1029
|
-
| Hookable 5.5.3 | -73% | 982K | 1µs | ±2.92% | 812K |
|
|
1030
|
-
|
|
1031
|
-
## Emits
|
|
1241
|
+
```bash
|
|
1242
|
+
pnpm i && pnpm test
|
|
1243
|
+
```
|
|
1032
1244
|
|
|
1033
|
-
|
|
1245
|
+
Note that we are using `pnpm` as our package manager. If you don't have it installed, you can install it globally with:
|
|
1034
1246
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
| EventEmitter3 5.0.1 | -1.3% | 10M | 114ns | ±1.84% | 9M |
|
|
1039
|
-
| EventEmitter v22.12.0 | -1.5% | 9M | 114ns | ±1.18% | 9M |
|
|
1040
|
-
| Emittery 1.1.0 | -92% | 785K | 1µs | ±0.45% | 761K |
|
|
1247
|
+
```bash
|
|
1248
|
+
npm install -g pnpm
|
|
1249
|
+
```
|
|
1041
1250
|
|
|
1042
|
-
|
|
1251
|
+
To contribute follow the [Contributing Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
1043
1252
|
|
|
1044
|
-
# License
|
|
1253
|
+
# License and Copyright
|
|
1045
1254
|
|
|
1046
1255
|
[MIT & © Jared Wray](LICENSE)
|
|
1047
1256
|
|