@garfish/hooks
Advanced tools
Comparing version 0.0.35-alpha.3 to 0.0.35
{ | ||
"name": "@garfish/hooks", | ||
"version": "0.0.35-alpha.3", | ||
"version": "0.0.35", | ||
"author": "zhoushaw", | ||
@@ -47,3 +47,3 @@ "description": "fork from tapable", | ||
}, | ||
"gitHead": "4772634da31463994a4f45466175bc28d70cc2dc" | ||
"gitHead": "f6b04041cc3efa2755b6dd560c98843f7b2b5419" | ||
} |
340
README.md
@@ -5,14 +5,14 @@ # Tapable | ||
``` javascript | ||
```javascript | ||
const { | ||
SyncHook, | ||
SyncBailHook, | ||
SyncWaterfallHook, | ||
SyncLoopHook, | ||
AsyncParallelHook, | ||
AsyncParallelBailHook, | ||
AsyncSeriesHook, | ||
AsyncSeriesBailHook, | ||
AsyncSeriesWaterfallHook | ||
} = require("tapable"); | ||
SyncHook, | ||
SyncBailHook, | ||
SyncWaterfallHook, | ||
SyncLoopHook, | ||
AsyncParallelHook, | ||
AsyncParallelBailHook, | ||
AsyncSeriesHook, | ||
AsyncSeriesBailHook, | ||
AsyncSeriesWaterfallHook, | ||
} = require('tapable'); | ||
``` | ||
@@ -22,3 +22,3 @@ | ||
``` shell | ||
```shell | ||
npm install --save tapable | ||
@@ -31,4 +31,4 @@ ``` | ||
``` js | ||
const hook = new SyncHook(["arg1", "arg2", "arg3"]); | ||
```js | ||
const hook = new SyncHook(['arg1', 'arg2', 'arg3']); | ||
``` | ||
@@ -38,13 +38,17 @@ | ||
``` js | ||
```js | ||
class Car { | ||
constructor() { | ||
this.hooks = { | ||
accelerate: new SyncHook(["newSpeed"]), | ||
brake: new SyncHook(), | ||
calculateRoutes: new AsyncParallelHook(["source", "target", "routesList"]) | ||
}; | ||
} | ||
constructor() { | ||
this.hooks = { | ||
accelerate: new SyncHook(['newSpeed']), | ||
brake: new SyncHook(), | ||
calculateRoutes: new AsyncParallelHook([ | ||
'source', | ||
'target', | ||
'routesList', | ||
]), | ||
}; | ||
} | ||
/* ... */ | ||
/* ... */ | ||
} | ||
@@ -55,7 +59,7 @@ ``` | ||
``` js | ||
```js | ||
const myCar = new Car(); | ||
// Use the tap method to add a consument | ||
myCar.hooks.brake.tap("WarningLampPlugin", () => warningLamp.on()); | ||
myCar.hooks.brake.tap('WarningLampPlugin', () => warningLamp.on()); | ||
``` | ||
@@ -67,4 +71,6 @@ | ||
``` js | ||
myCar.hooks.accelerate.tap("LoggerPlugin", newSpeed => console.log(`Accelerating to ${newSpeed}`)); | ||
```js | ||
myCar.hooks.accelerate.tap('LoggerPlugin', (newSpeed) => | ||
console.log(`Accelerating to ${newSpeed}`), | ||
); | ||
``` | ||
@@ -74,54 +80,65 @@ | ||
``` js | ||
myCar.hooks.calculateRoutes.tapPromise("GoogleMapsPlugin", (source, target, routesList) => { | ||
// return a promise | ||
return google.maps.findRoute(source, target).then(route => { | ||
routesList.add(route); | ||
}); | ||
}); | ||
myCar.hooks.calculateRoutes.tapAsync("BingMapsPlugin", (source, target, routesList, callback) => { | ||
bing.findRoute(source, target, (err, route) => { | ||
if(err) return callback(err); | ||
routesList.add(route); | ||
// call the callback | ||
callback(); | ||
}); | ||
}); | ||
```js | ||
myCar.hooks.calculateRoutes.tapPromise( | ||
'GoogleMapsPlugin', | ||
(source, target, routesList) => { | ||
// return a promise | ||
return google.maps.findRoute(source, target).then((route) => { | ||
routesList.add(route); | ||
}); | ||
}, | ||
); | ||
myCar.hooks.calculateRoutes.tapAsync( | ||
'BingMapsPlugin', | ||
(source, target, routesList, callback) => { | ||
bing.findRoute(source, target, (err, route) => { | ||
if (err) return callback(err); | ||
routesList.add(route); | ||
// call the callback | ||
callback(); | ||
}); | ||
}, | ||
); | ||
// You can still use sync plugins | ||
myCar.hooks.calculateRoutes.tap("CachedRoutesPlugin", (source, target, routesList) => { | ||
const cachedRoute = cache.get(source, target); | ||
if(cachedRoute) | ||
routesList.add(cachedRoute); | ||
}) | ||
myCar.hooks.calculateRoutes.tap( | ||
'CachedRoutesPlugin', | ||
(source, target, routesList) => { | ||
const cachedRoute = cache.get(source, target); | ||
if (cachedRoute) routesList.add(cachedRoute); | ||
}, | ||
); | ||
``` | ||
The class declaring these hooks need to call them: | ||
``` js | ||
```js | ||
class Car { | ||
/** | ||
* You won't get returned value from SyncHook or AsyncParallelHook, | ||
* to do that, use SyncWaterfallHook and AsyncSeriesWaterfallHook respectively | ||
**/ | ||
/** | ||
* You won't get returned value from SyncHook or AsyncParallelHook, | ||
* to do that, use SyncWaterfallHook and AsyncSeriesWaterfallHook respectively | ||
**/ | ||
setSpeed(newSpeed) { | ||
// following call returns undefined even when you returned values | ||
this.hooks.accelerate.call(newSpeed); | ||
} | ||
setSpeed(newSpeed) { | ||
// following call returns undefined even when you returned values | ||
this.hooks.accelerate.call(newSpeed); | ||
} | ||
useNavigationSystemPromise(source, target) { | ||
const routesList = new List(); | ||
return this.hooks.calculateRoutes.promise(source, target, routesList).then((res) => { | ||
// res is undefined for AsyncParallelHook | ||
return routesList.getRoutes(); | ||
}); | ||
} | ||
useNavigationSystemPromise(source, target) { | ||
const routesList = new List(); | ||
return this.hooks.calculateRoutes | ||
.call(source, target, routesList) | ||
.then((res) => { | ||
// res is undefined for AsyncParallelHook | ||
return routesList.getRoutes(); | ||
}); | ||
} | ||
useNavigationSystemAsync(source, target, callback) { | ||
const routesList = new List(); | ||
this.hooks.calculateRoutes.callAsync(source, target, routesList, err => { | ||
if(err) return callback(err); | ||
callback(null, routesList.getRoutes()); | ||
}); | ||
} | ||
useNavigationSystemAsync(source, target, callback) { | ||
const routesList = new List(); | ||
this.hooks.calculateRoutes.callAsync(source, target, routesList, (err) => { | ||
if (err) return callback(err); | ||
callback(null, routesList.getRoutes()); | ||
}); | ||
} | ||
} | ||
@@ -131,8 +148,9 @@ ``` | ||
The Hook will compile a method with the most efficient way of running your plugins. It generates code depending on: | ||
* The number of registered plugins (none, one, many) | ||
* The kind of registered plugins (sync, async, promise) | ||
* The used call method (sync, async, promise) | ||
* The number of arguments | ||
* Whether interception is used | ||
- The number of registered plugins (none, one, many) | ||
- The kind of registered plugins (sync, async, promise) | ||
- The used call method (sync, async, promise) | ||
- The number of arguments | ||
- Whether interception is used | ||
This ensures fastest possible execution. | ||
@@ -144,21 +162,20 @@ | ||
* Basic hook (without “Waterfall”, “Bail” or “Loop” in its name). This hook simply calls every function it tapped in a row. | ||
- Basic hook (without “Waterfall”, “Bail” or “Loop” in its name). This hook simply calls every function it tapped in a row. | ||
* __Waterfall__. A waterfall hook also calls each tapped function in a row. Unlike the basic hook, it passes a return value from each function to the next function. | ||
- **Waterfall**. A waterfall hook also calls each tapped function in a row. Unlike the basic hook, it passes a return value from each function to the next function. | ||
* __Bail__. A bail hook allows exiting early. When any of the tapped function returns anything, the bail hook will stop executing the remaining ones. | ||
- **Bail**. A bail hook allows exiting early. When any of the tapped function returns anything, the bail hook will stop executing the remaining ones. | ||
* __Loop__. When a plugin in a loop hook returns a non-undefined value the hook will restart from the first plugin. It will loop until all plugins return undefined. | ||
- **Loop**. When a plugin in a loop hook returns a non-undefined value the hook will restart from the first plugin. It will loop until all plugins return undefined. | ||
Additionally, hooks can be synchronous or asynchronous. To reflect this, there’re “Sync”, “AsyncSeries”, and “AsyncParallel” hook classes: | ||
* __Sync__. A sync hook can only be tapped with synchronous functions (using `myHook.tap()`). | ||
- **Sync**. A sync hook can only be tapped with synchronous functions (using `myHook.tap()`). | ||
* __AsyncSeries__. An async-series hook can be tapped with synchronous, callback-based and promise-based functions (using `myHook.tap()`, `myHook.tapAsync()` and `myHook.tapPromise()`). They call each async method in a row. | ||
- **AsyncSeries**. An async-series hook can be tapped with synchronous, callback-based and promise-based functions (using `myHook.tap()`, `myHook.tapAsync()` and `myHook.tapPromise()`). They call each async method in a row. | ||
* __AsyncParallel__. An async-parallel hook can also be tapped with synchronous, callback-based and promise-based functions (using `myHook.tap()`, `myHook.tapAsync()` and `myHook.tapPromise()`). However, they run each async method in parallel. | ||
- **AsyncParallel**. An async-parallel hook can also be tapped with synchronous, callback-based and promise-based functions (using `myHook.tap()`, `myHook.tapAsync()` and `myHook.tapPromise()`). However, they run each async method in parallel. | ||
The hook type is reflected in its class name. E.g., `AsyncSeriesWaterfallHook` allows asynchronous functions and runs them in series, passing each function’s return value into the next function. | ||
## Interception | ||
@@ -168,13 +185,13 @@ | ||
``` js | ||
```js | ||
myCar.hooks.calculateRoutes.intercept({ | ||
call: (source, target, routesList) => { | ||
console.log("Starting to calculate routes"); | ||
}, | ||
register: (tapInfo) => { | ||
// tapInfo = { type: "promise", name: "GoogleMapsPlugin", fn: ... } | ||
console.log(`${tapInfo.name} is doing its job`); | ||
return tapInfo; // may return a new tapInfo object | ||
} | ||
}) | ||
call: (source, target, routesList) => { | ||
console.log('Starting to calculate routes'); | ||
}, | ||
register: (tapInfo) => { | ||
// tapInfo = { type: "promise", name: "GoogleMapsPlugin", fn: ... } | ||
console.log(`${tapInfo.name} is doing its job`); | ||
return tapInfo; // may return a new tapInfo object | ||
}, | ||
}); | ||
``` | ||
@@ -194,28 +211,31 @@ | ||
``` js | ||
```js | ||
myCar.hooks.accelerate.intercept({ | ||
context: true, | ||
tap: (context, tapInfo) => { | ||
// tapInfo = { type: "sync", name: "NoisePlugin", fn: ... } | ||
console.log(`${tapInfo.name} is doing it's job`); | ||
context: true, | ||
tap: (context, tapInfo) => { | ||
// tapInfo = { type: "sync", name: "NoisePlugin", fn: ... } | ||
console.log(`${tapInfo.name} is doing it's job`); | ||
// `context` starts as an empty object if at least one plugin uses `context: true`. | ||
// If no plugins use `context: true`, then `context` is undefined. | ||
if (context) { | ||
// Arbitrary properties can be added to `context`, which plugins can then access. | ||
context.hasMuffler = true; | ||
} | ||
} | ||
// `context` starts as an empty object if at least one plugin uses `context: true`. | ||
// If no plugins use `context: true`, then `context` is undefined. | ||
if (context) { | ||
// Arbitrary properties can be added to `context`, which plugins can then access. | ||
context.hasMuffler = true; | ||
} | ||
}, | ||
}); | ||
myCar.hooks.accelerate.tap({ | ||
name: "NoisePlugin", | ||
context: true | ||
}, (context, newSpeed) => { | ||
if (context && context.hasMuffler) { | ||
console.log("Silence..."); | ||
} else { | ||
console.log("Vroom!"); | ||
} | ||
}); | ||
myCar.hooks.accelerate.tap( | ||
{ | ||
name: 'NoisePlugin', | ||
context: true, | ||
}, | ||
(context, newSpeed) => { | ||
if (context && context.hasMuffler) { | ||
console.log('Silence...'); | ||
} else { | ||
console.log('Vroom!'); | ||
} | ||
}, | ||
); | ||
``` | ||
@@ -227,16 +247,24 @@ | ||
``` js | ||
const keyedHook = new HookMap(key => new SyncHook(["arg"])) | ||
```js | ||
const keyedHook = new HookMap((key) => new SyncHook(['arg'])); | ||
``` | ||
``` js | ||
keyedHook.for("some-key").tap("MyPlugin", (arg) => { /* ... */ }); | ||
keyedHook.for("some-key").tapAsync("MyPlugin", (arg, callback) => { /* ... */ }); | ||
keyedHook.for("some-key").tapPromise("MyPlugin", (arg) => { /* ... */ }); | ||
```js | ||
keyedHook.for('some-key').tap('MyPlugin', (arg) => { | ||
/* ... */ | ||
}); | ||
keyedHook.for('some-key').tapAsync('MyPlugin', (arg, callback) => { | ||
/* ... */ | ||
}); | ||
keyedHook.for('some-key').tapPromise('MyPlugin', (arg) => { | ||
/* ... */ | ||
}); | ||
``` | ||
``` js | ||
const hook = keyedHook.get("some-key"); | ||
if(hook !== undefined) { | ||
hook.callAsync("arg", err => { /* ... */ }); | ||
```js | ||
const hook = keyedHook.get('some-key'); | ||
if (hook !== undefined) { | ||
hook.callAsync('arg', (err) => { | ||
/* ... */ | ||
}); | ||
} | ||
@@ -249,34 +277,40 @@ ``` | ||
``` ts | ||
```ts | ||
interface Hook { | ||
tap: (name: string | Tap, fn: (context?, ...args) => Result) => void, | ||
tapAsync: (name: string | Tap, fn: (context?, ...args, callback: (err, result: Result) => void) => void) => void, | ||
tapPromise: (name: string | Tap, fn: (context?, ...args) => Promise<Result>) => void, | ||
intercept: (interceptor: HookInterceptor) => void | ||
tap: (name: string | Tap, fn: (context?, ...args) => Result) => void; | ||
tapAsync: ( | ||
name: string | Tap, | ||
fn: (context?, ...args, callback: (err, result: Result) => void) => void, | ||
) => void; | ||
tapPromise: ( | ||
name: string | Tap, | ||
fn: (context?, ...args) => Promise<Result>, | ||
) => void; | ||
intercept: (interceptor: HookInterceptor) => void; | ||
} | ||
interface HookInterceptor { | ||
call: (context?, ...args) => void, | ||
loop: (context?, ...args) => void, | ||
tap: (context?, tap: Tap) => void, | ||
register: (tap: Tap) => Tap, | ||
context: boolean | ||
call: (context?, ...args) => void; | ||
loop: (context?, ...args) => void; | ||
tap: (context?, tap: Tap) => void; | ||
register: (tap: Tap) => Tap; | ||
context: boolean; | ||
} | ||
interface HookMap { | ||
for: (key: any) => Hook, | ||
intercept: (interceptor: HookMapInterceptor) => void | ||
for: (key: any) => Hook; | ||
intercept: (interceptor: HookMapInterceptor) => void; | ||
} | ||
interface HookMapInterceptor { | ||
factory: (key: any, hook: Hook) => Hook | ||
factory: (key: any, hook: Hook) => Hook; | ||
} | ||
interface Tap { | ||
name: string, | ||
type: string | ||
fn: Function, | ||
stage: number, | ||
context: boolean, | ||
before?: string | Array | ||
name: string; | ||
type: string; | ||
fn: Function; | ||
stage: number; | ||
context: boolean; | ||
before?: string | Array; | ||
} | ||
@@ -287,13 +321,13 @@ ``` | ||
``` ts | ||
```ts | ||
interface Hook { | ||
isUsed: () => boolean, | ||
call: (...args) => Result, | ||
promise: (...args) => Promise<Result>, | ||
callAsync: (...args, callback: (err, result: Result) => void) => void, | ||
isUsed: () => boolean; | ||
call: (...args) => Result; | ||
promise: (...args) => Promise<Result>; | ||
callAsync: (...args, callback: (err, result: Result) => void) => void; | ||
} | ||
interface HookMap { | ||
get: (key: any) => Hook | undefined, | ||
for: (key: any) => Hook | ||
get: (key: any) => Hook | undefined; | ||
for: (key: any) => Hook; | ||
} | ||
@@ -306,6 +340,6 @@ ``` | ||
``` js | ||
const { MultiHook } = require("tapable"); | ||
```js | ||
const { MultiHook } = require('tapable'); | ||
this.hooks.allHooks = new MultiHook([this.hooks.hookA, this.hooks.hookB]); | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
82126
331