This commit is contained in:
21
node_modules/hookable/LICENSE.md
generated
vendored
Normal file
21
node_modules/hookable/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Pooya Parsa <pooya@pi0.io>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
271
node_modules/hookable/README.md
generated
vendored
Normal file
271
node_modules/hookable/README.md
generated
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
# Hookable
|
||||
|
||||
[![npm version][npm-version-src]][npm-version-href]
|
||||
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
||||
[![bundle][bundle-src]][bundle-href]
|
||||
[![Codecov][codecov-src]][codecov-href]
|
||||
[![License][license-src]][license-href]
|
||||
|
||||
Awaitable hooks system.
|
||||
|
||||
## Install
|
||||
|
||||
Using yarn:
|
||||
|
||||
```bash
|
||||
yarn add hookable
|
||||
```
|
||||
|
||||
Using npm:
|
||||
|
||||
```bash
|
||||
npm install hookable
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
**Method A: Create a hookable instance:**
|
||||
|
||||
```js
|
||||
import { createHooks } from 'hookable'
|
||||
|
||||
// Create a hookable instance
|
||||
const hooks = createHooks()
|
||||
|
||||
// Hook on 'hello'
|
||||
hooks.hook('hello', () => { console.log('Hello World' )})
|
||||
|
||||
// Call 'hello' hook
|
||||
hooks.callHook('hello')
|
||||
```
|
||||
|
||||
**Method B: Extend your base class from Hookable:**
|
||||
|
||||
```js
|
||||
import { Hookable } from 'hookable'
|
||||
|
||||
export default class FooLib extends Hookable {
|
||||
constructor() {
|
||||
// Call to parent to initialize
|
||||
super()
|
||||
// Initialize Hookable with custom logger
|
||||
// super(consola)
|
||||
}
|
||||
|
||||
async someFunction() {
|
||||
// Call and wait for `hook1` hooks (if any) sequential
|
||||
await this.callHook('hook1')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Inside plugins, register for any hook:**
|
||||
|
||||
```js
|
||||
const lib = new FooLib()
|
||||
|
||||
// Register a handler for `hook2`
|
||||
lib.hook('hook2', async () => { /* ... */ })
|
||||
|
||||
// Register multiply handlers at once
|
||||
lib.addHooks({
|
||||
hook1: async () => { /* ... */ },
|
||||
hook2: [ /* can be also an array */ ]
|
||||
})
|
||||
```
|
||||
|
||||
**Unregistering hooks:**
|
||||
|
||||
```js
|
||||
const lib = new FooLib()
|
||||
|
||||
const hook0 = async () => { /* ... */ }
|
||||
const hook1 = async () => { /* ... */ }
|
||||
const hook2 = async () => { /* ... */ }
|
||||
|
||||
// The hook() method returns an "unregister" function
|
||||
const unregisterHook0 = lib.hook('hook0', hook0)
|
||||
const unregisterHooks1and2 = lib.addHooks({ hook1, hook2 })
|
||||
|
||||
/* ... */
|
||||
|
||||
unregisterHook0()
|
||||
unregisterHooks1and2()
|
||||
|
||||
// or
|
||||
|
||||
lib.removeHooks({ hook0, hook1 })
|
||||
lib.removeHook('hook2', hook2)
|
||||
```
|
||||
|
||||
**Triggering a hook handler once:**
|
||||
|
||||
```js
|
||||
const lib = new FooLib()
|
||||
|
||||
const unregister = lib.hook('hook0', async () => {
|
||||
// Unregister as soon as the hook is executed
|
||||
unregister()
|
||||
|
||||
/* ... */
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
## Hookable class
|
||||
|
||||
### `constructor()`
|
||||
|
||||
### `hook (name, fn)`
|
||||
|
||||
Register a handler for a specific hook. `fn` must be a function.
|
||||
|
||||
Returns an `unregister` function that, when called, will remove the registered handler.
|
||||
|
||||
### `hookOnce (name, fn)`
|
||||
|
||||
Similar to `hook` but unregisters hook once called.
|
||||
|
||||
Returns an `unregister` function that, when called, will remove the registered handler before first call.
|
||||
|
||||
### `addHooks(configHooks)`
|
||||
|
||||
Flatten and register hooks object.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
hookable.addHooks({
|
||||
test: {
|
||||
before: () => {},
|
||||
after: () => {}
|
||||
}
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
This registers `test:before` and `test:after` hooks at bulk.
|
||||
|
||||
Returns an `unregister` function that, when called, will remove all the registered handlers.
|
||||
|
||||
### `async callHook (name, ...args)`
|
||||
|
||||
Used by class itself to **sequentially** call handlers of a specific hook.
|
||||
|
||||
### `callHookWith (name, callerFn)`
|
||||
|
||||
If you need custom control over how hooks are called, you can provide a custom function that will receive an array of handlers of a specific hook.
|
||||
|
||||
`callerFn` if a callback function that accepts two arguments, `hooks` and `args`:
|
||||
- `hooks`: Array of user hooks to be called
|
||||
- `args`: Array of arguments that should be passed each time calling a hook
|
||||
|
||||
### `deprecateHook (old, name)`
|
||||
|
||||
Deprecate hook called `old` in favor of `name` hook.
|
||||
|
||||
### `deprecateHooks (deprecatedHooks)`
|
||||
|
||||
Deprecate all hooks from an object (keys are old and values or newer ones).
|
||||
|
||||
### `removeHook (name, fn)`
|
||||
|
||||
Remove a particular hook handler, if the `fn` handler is present.
|
||||
|
||||
### `removeHooks (configHooks)`
|
||||
|
||||
Remove multiple hook handlers.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
const handler = async () => { /* ... */ }
|
||||
|
||||
hookable.hook('test:before', handler)
|
||||
hookable.addHooks({ test: { after: handler } })
|
||||
|
||||
// ...
|
||||
|
||||
hookable.removeHooks({
|
||||
test: {
|
||||
before: handler,
|
||||
after: handler
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### `removeAllHooks`
|
||||
|
||||
Remove all hook handlers.
|
||||
|
||||
### `beforeEach (syncCallback)`
|
||||
|
||||
Registers a (sync) callback to be called before each hook is being called.
|
||||
|
||||
```js
|
||||
hookable.beforeEach((event) => { console.log(`${event.name} hook is being called with ${event.args}`)}`)
|
||||
hookable.hook('test', () => { console.log('running test hook') })
|
||||
|
||||
// test hook is being called with []
|
||||
// running test hook
|
||||
await hookable.callHook('test')
|
||||
```
|
||||
|
||||
### `afterEach (syncCallback)`
|
||||
|
||||
Registers a (sync) callback to be called after each hook is being called.
|
||||
|
||||
```js
|
||||
hookable.afterEach((event) => { console.log(`${event.name} hook called with ${event.args}`)}`)
|
||||
hookable.hook('test', () => { console.log('running test hook') })
|
||||
|
||||
// running test hook
|
||||
// test hook called with []
|
||||
await hookable.callHook('test')
|
||||
```
|
||||
|
||||
### `createDebugger`
|
||||
|
||||
Automatically logs each hook that is called and how long it takes to run.
|
||||
|
||||
```js
|
||||
const debug = hookable.createDebugger(hooks, { tag: 'something' })
|
||||
|
||||
hooks.callHook('some-hook', 'some-arg')
|
||||
// [something] some-hook: 0.21ms
|
||||
|
||||
debug.close()
|
||||
```
|
||||
|
||||
## Migration
|
||||
|
||||
### From `4.x` to `5.x`
|
||||
|
||||
- Type checking improved. You can use `Hookable<T>` or `createHooks<T>()` to provide types interface **([c2e1e22](https://github.com/unjs/hookable/commit/c2e1e223d16e7bf87117cd8d72ad3ba211a333d8))**
|
||||
- We no longer provide an IE11 compatible umd build. Instead, you should use an ESM-aware bundler such as webpack or rollup to transpile if needed.
|
||||
- Logger param is dropped. We use `console.warn` by default for deprecated hooks.
|
||||
- Package now uses named exports. You should import `{ Hookable }` instead of `Hookable` or use new `createHooks` util
|
||||
- `mergeHooks` util is exported standalone. You should replace `Hookable.mergeHooks` and `this.mergeHooks` with new `{ mergeHooks }` export
|
||||
- In versions < 5.0.0 when using `callHook` if an error happened by one of the hook callbacks, we was handling errors globally and call global `error` hook + `console.error` instead and resolve `callHook` promise! This sometimes makes confusing behavior when we think code worked but it didn't. v5 introduced a breaking change that when a hook throws an error, `callHook` also rejects instead of a global `error` event. This means you should be careful to handle all errors when using `callHook` now.
|
||||
|
||||
## Credits
|
||||
|
||||
Extracted from [Nuxt](https://github.com/nuxt/nuxt.js) hooks system originally introduced by [Sébastien Chopin](https://github.com/Atinux)
|
||||
|
||||
Thanks to [Joe Paice](https://github.com/RGBboy) for donating [hookable](https://www.npmjs.com/package/hookable) package name.
|
||||
|
||||
## License
|
||||
|
||||
MIT - Made with 💖
|
||||
|
||||
<!-- Badges -->
|
||||
[npm-version-src]: https://img.shields.io/npm/v/hookable?style=flat&colorA=18181B&colorB=F0DB4F
|
||||
[npm-version-href]: https://npmjs.com/package/hookable
|
||||
[npm-downloads-src]: https://img.shields.io/npm/dm/hookable?style=flat&colorA=18181B&colorB=F0DB4F
|
||||
[npm-downloads-href]: https://npmjs.com/package/hookable
|
||||
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/hookable/main?style=flat&colorA=18181B&colorB=F0DB4F
|
||||
[codecov-href]: https://codecov.io/gh/unjs/h3
|
||||
[bundle-src]: https://img.shields.io/bundlephobia/minzip/hookable?style=flat&colorA=18181B&colorB=F0DB4F
|
||||
[bundle-href]: https://bundlephobia.com/result?p=hookable
|
||||
[license-src]: https://img.shields.io/github/license/unjs/hookable.svg?style=flat&colorA=18181B&colorB=F0DB4F
|
||||
[license-href]: https://github.com/unjs/hookable/blob/main/LICENSE
|
299
node_modules/hookable/dist/index.cjs
generated
vendored
Normal file
299
node_modules/hookable/dist/index.cjs
generated
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
'use strict';
|
||||
|
||||
function flatHooks(configHooks, hooks = {}, parentName) {
|
||||
for (const key in configHooks) {
|
||||
const subHook = configHooks[key];
|
||||
const name = parentName ? `${parentName}:${key}` : key;
|
||||
if (typeof subHook === "object" && subHook !== null) {
|
||||
flatHooks(subHook, hooks, name);
|
||||
} else if (typeof subHook === "function") {
|
||||
hooks[name] = subHook;
|
||||
}
|
||||
}
|
||||
return hooks;
|
||||
}
|
||||
function mergeHooks(...hooks) {
|
||||
const finalHooks = {};
|
||||
for (const hook of hooks) {
|
||||
const flatenHook = flatHooks(hook);
|
||||
for (const key in flatenHook) {
|
||||
if (finalHooks[key]) {
|
||||
finalHooks[key].push(flatenHook[key]);
|
||||
} else {
|
||||
finalHooks[key] = [flatenHook[key]];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const key in finalHooks) {
|
||||
if (finalHooks[key].length > 1) {
|
||||
const array = finalHooks[key];
|
||||
finalHooks[key] = (...arguments_) => serial(array, (function_) => function_(...arguments_));
|
||||
} else {
|
||||
finalHooks[key] = finalHooks[key][0];
|
||||
}
|
||||
}
|
||||
return finalHooks;
|
||||
}
|
||||
function serial(tasks, function_) {
|
||||
return tasks.reduce(
|
||||
(promise, task) => promise.then(() => function_(task)),
|
||||
Promise.resolve()
|
||||
);
|
||||
}
|
||||
const defaultTask = { run: (function_) => function_() };
|
||||
const _createTask = () => defaultTask;
|
||||
const createTask = typeof console.createTask !== "undefined" ? console.createTask : _createTask;
|
||||
function serialTaskCaller(hooks, args) {
|
||||
const name = args.shift();
|
||||
const task = createTask(name);
|
||||
return hooks.reduce(
|
||||
(promise, hookFunction) => promise.then(() => task.run(() => hookFunction(...args))),
|
||||
Promise.resolve()
|
||||
);
|
||||
}
|
||||
function parallelTaskCaller(hooks, args) {
|
||||
const name = args.shift();
|
||||
const task = createTask(name);
|
||||
return Promise.all(hooks.map((hook) => task.run(() => hook(...args))));
|
||||
}
|
||||
function serialCaller(hooks, arguments_) {
|
||||
return hooks.reduce(
|
||||
(promise, hookFunction) => promise.then(() => hookFunction(...arguments_ || [])),
|
||||
Promise.resolve()
|
||||
);
|
||||
}
|
||||
function parallelCaller(hooks, args) {
|
||||
return Promise.all(hooks.map((hook) => hook(...args || [])));
|
||||
}
|
||||
function callEachWith(callbacks, arg0) {
|
||||
for (const callback of [...callbacks]) {
|
||||
callback(arg0);
|
||||
}
|
||||
}
|
||||
|
||||
class Hookable {
|
||||
constructor() {
|
||||
this._hooks = {};
|
||||
this._before = void 0;
|
||||
this._after = void 0;
|
||||
this._deprecatedMessages = void 0;
|
||||
this._deprecatedHooks = {};
|
||||
this.hook = this.hook.bind(this);
|
||||
this.callHook = this.callHook.bind(this);
|
||||
this.callHookWith = this.callHookWith.bind(this);
|
||||
}
|
||||
hook(name, function_, options = {}) {
|
||||
if (!name || typeof function_ !== "function") {
|
||||
return () => {
|
||||
};
|
||||
}
|
||||
const originalName = name;
|
||||
let dep;
|
||||
while (this._deprecatedHooks[name]) {
|
||||
dep = this._deprecatedHooks[name];
|
||||
name = dep.to;
|
||||
}
|
||||
if (dep && !options.allowDeprecated) {
|
||||
let message = dep.message;
|
||||
if (!message) {
|
||||
message = `${originalName} hook has been deprecated` + (dep.to ? `, please use ${dep.to}` : "");
|
||||
}
|
||||
if (!this._deprecatedMessages) {
|
||||
this._deprecatedMessages = /* @__PURE__ */ new Set();
|
||||
}
|
||||
if (!this._deprecatedMessages.has(message)) {
|
||||
console.warn(message);
|
||||
this._deprecatedMessages.add(message);
|
||||
}
|
||||
}
|
||||
if (!function_.name) {
|
||||
try {
|
||||
Object.defineProperty(function_, "name", {
|
||||
get: () => "_" + name.replace(/\W+/g, "_") + "_hook_cb",
|
||||
configurable: true
|
||||
});
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
this._hooks[name] = this._hooks[name] || [];
|
||||
this._hooks[name].push(function_);
|
||||
return () => {
|
||||
if (function_) {
|
||||
this.removeHook(name, function_);
|
||||
function_ = void 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
hookOnce(name, function_) {
|
||||
let _unreg;
|
||||
let _function = (...arguments_) => {
|
||||
if (typeof _unreg === "function") {
|
||||
_unreg();
|
||||
}
|
||||
_unreg = void 0;
|
||||
_function = void 0;
|
||||
return function_(...arguments_);
|
||||
};
|
||||
_unreg = this.hook(name, _function);
|
||||
return _unreg;
|
||||
}
|
||||
removeHook(name, function_) {
|
||||
if (this._hooks[name]) {
|
||||
const index = this._hooks[name].indexOf(function_);
|
||||
if (index !== -1) {
|
||||
this._hooks[name].splice(index, 1);
|
||||
}
|
||||
if (this._hooks[name].length === 0) {
|
||||
delete this._hooks[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
deprecateHook(name, deprecated) {
|
||||
this._deprecatedHooks[name] = typeof deprecated === "string" ? { to: deprecated } : deprecated;
|
||||
const _hooks = this._hooks[name] || [];
|
||||
delete this._hooks[name];
|
||||
for (const hook of _hooks) {
|
||||
this.hook(name, hook);
|
||||
}
|
||||
}
|
||||
deprecateHooks(deprecatedHooks) {
|
||||
Object.assign(this._deprecatedHooks, deprecatedHooks);
|
||||
for (const name in deprecatedHooks) {
|
||||
this.deprecateHook(name, deprecatedHooks[name]);
|
||||
}
|
||||
}
|
||||
addHooks(configHooks) {
|
||||
const hooks = flatHooks(configHooks);
|
||||
const removeFns = Object.keys(hooks).map(
|
||||
(key) => this.hook(key, hooks[key])
|
||||
);
|
||||
return () => {
|
||||
for (const unreg of removeFns.splice(0, removeFns.length)) {
|
||||
unreg();
|
||||
}
|
||||
};
|
||||
}
|
||||
removeHooks(configHooks) {
|
||||
const hooks = flatHooks(configHooks);
|
||||
for (const key in hooks) {
|
||||
this.removeHook(key, hooks[key]);
|
||||
}
|
||||
}
|
||||
removeAllHooks() {
|
||||
for (const key in this._hooks) {
|
||||
delete this._hooks[key];
|
||||
}
|
||||
}
|
||||
callHook(name, ...arguments_) {
|
||||
arguments_.unshift(name);
|
||||
return this.callHookWith(serialTaskCaller, name, ...arguments_);
|
||||
}
|
||||
callHookParallel(name, ...arguments_) {
|
||||
arguments_.unshift(name);
|
||||
return this.callHookWith(parallelTaskCaller, name, ...arguments_);
|
||||
}
|
||||
callHookWith(caller, name, ...arguments_) {
|
||||
const event = this._before || this._after ? { name, args: arguments_, context: {} } : void 0;
|
||||
if (this._before) {
|
||||
callEachWith(this._before, event);
|
||||
}
|
||||
const result = caller(
|
||||
name in this._hooks ? [...this._hooks[name]] : [],
|
||||
arguments_
|
||||
);
|
||||
if (result instanceof Promise) {
|
||||
return result.finally(() => {
|
||||
if (this._after && event) {
|
||||
callEachWith(this._after, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this._after && event) {
|
||||
callEachWith(this._after, event);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
beforeEach(function_) {
|
||||
this._before = this._before || [];
|
||||
this._before.push(function_);
|
||||
return () => {
|
||||
if (this._before !== void 0) {
|
||||
const index = this._before.indexOf(function_);
|
||||
if (index !== -1) {
|
||||
this._before.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
afterEach(function_) {
|
||||
this._after = this._after || [];
|
||||
this._after.push(function_);
|
||||
return () => {
|
||||
if (this._after !== void 0) {
|
||||
const index = this._after.indexOf(function_);
|
||||
if (index !== -1) {
|
||||
this._after.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
function createHooks() {
|
||||
return new Hookable();
|
||||
}
|
||||
|
||||
const isBrowser = typeof window !== "undefined";
|
||||
function createDebugger(hooks, _options = {}) {
|
||||
const options = {
|
||||
inspect: isBrowser,
|
||||
group: isBrowser,
|
||||
filter: () => true,
|
||||
..._options
|
||||
};
|
||||
const _filter = options.filter;
|
||||
const filter = typeof _filter === "string" ? (name) => name.startsWith(_filter) : _filter;
|
||||
const _tag = options.tag ? `[${options.tag}] ` : "";
|
||||
const logPrefix = (event) => _tag + event.name + "".padEnd(event._id, "\0");
|
||||
const _idCtr = {};
|
||||
const unsubscribeBefore = hooks.beforeEach((event) => {
|
||||
if (filter !== void 0 && !filter(event.name)) {
|
||||
return;
|
||||
}
|
||||
_idCtr[event.name] = _idCtr[event.name] || 0;
|
||||
event._id = _idCtr[event.name]++;
|
||||
console.time(logPrefix(event));
|
||||
});
|
||||
const unsubscribeAfter = hooks.afterEach((event) => {
|
||||
if (filter !== void 0 && !filter(event.name)) {
|
||||
return;
|
||||
}
|
||||
if (options.group) {
|
||||
console.groupCollapsed(event.name);
|
||||
}
|
||||
if (options.inspect) {
|
||||
console.timeLog(logPrefix(event), event.args);
|
||||
} else {
|
||||
console.timeEnd(logPrefix(event));
|
||||
}
|
||||
if (options.group) {
|
||||
console.groupEnd();
|
||||
}
|
||||
_idCtr[event.name]--;
|
||||
});
|
||||
return {
|
||||
/** Stop debugging and remove listeners */
|
||||
close: () => {
|
||||
unsubscribeBefore();
|
||||
unsubscribeAfter();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.Hookable = Hookable;
|
||||
exports.createDebugger = createDebugger;
|
||||
exports.createHooks = createHooks;
|
||||
exports.flatHooks = flatHooks;
|
||||
exports.mergeHooks = mergeHooks;
|
||||
exports.parallelCaller = parallelCaller;
|
||||
exports.serial = serial;
|
||||
exports.serialCaller = serialCaller;
|
103
node_modules/hookable/dist/index.d.ts
generated
vendored
Normal file
103
node_modules/hookable/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
type HookCallback = (...arguments_: any) => Promise<void> | void;
|
||||
interface Hooks {
|
||||
[key: string]: HookCallback;
|
||||
}
|
||||
type HookKeys<T> = keyof T & string;
|
||||
type DeprecatedHook<T> = {
|
||||
message?: string;
|
||||
to: HookKeys<T>;
|
||||
};
|
||||
type DeprecatedHooks<T> = {
|
||||
[name in HookKeys<T>]: DeprecatedHook<T>;
|
||||
};
|
||||
type ValueOf<C> = C extends Record<any, any> ? C[keyof C] : never;
|
||||
type Strings<T> = Exclude<keyof T, number | symbol>;
|
||||
type KnownKeys<T> = keyof {
|
||||
[K in keyof T as string extends K ? never : number extends K ? never : K]: never;
|
||||
};
|
||||
type StripGeneric<T> = Pick<T, KnownKeys<T> extends keyof T ? KnownKeys<T> : never>;
|
||||
type OnlyGeneric<T> = Omit<T, KnownKeys<T> extends keyof T ? KnownKeys<T> : never>;
|
||||
type Namespaces<T> = ValueOf<{
|
||||
[key in Strings<T>]: key extends `${infer Namespace}:${string}` ? Namespace : never;
|
||||
}>;
|
||||
type BareHooks<T> = ValueOf<{
|
||||
[key in Strings<T>]: key extends `${string}:${string}` ? never : key;
|
||||
}>;
|
||||
type HooksInNamespace<T, Namespace extends string> = ValueOf<{
|
||||
[key in Strings<T>]: key extends `${Namespace}:${infer HookName}` ? HookName : never;
|
||||
}>;
|
||||
type WithoutNamespace<T, Namespace extends string> = {
|
||||
[key in HooksInNamespace<T, Namespace>]: `${Namespace}:${key}` extends keyof T ? T[`${Namespace}:${key}`] : never;
|
||||
};
|
||||
type NestedHooks<T> = (Partial<StripGeneric<T>> | Partial<OnlyGeneric<T>>) & Partial<{
|
||||
[key in Namespaces<StripGeneric<T>>]: NestedHooks<WithoutNamespace<T, key>>;
|
||||
}> & Partial<{
|
||||
[key in BareHooks<StripGeneric<T>>]: T[key];
|
||||
}>;
|
||||
|
||||
type InferCallback<HT, HN extends keyof HT> = HT[HN] extends HookCallback ? HT[HN] : never;
|
||||
type InferSpyEvent<HT extends Record<string, any>> = {
|
||||
[key in keyof HT]: {
|
||||
name: key;
|
||||
args: Parameters<HT[key]>;
|
||||
context: Record<string, any>;
|
||||
};
|
||||
}[keyof HT];
|
||||
declare class Hookable<HooksT extends Record<string, any> = Record<string, HookCallback>, HookNameT extends HookKeys<HooksT> = HookKeys<HooksT>> {
|
||||
private _hooks;
|
||||
private _before?;
|
||||
private _after?;
|
||||
private _deprecatedHooks;
|
||||
private _deprecatedMessages?;
|
||||
constructor();
|
||||
hook<NameT extends HookNameT>(name: NameT, function_: InferCallback<HooksT, NameT>, options?: {
|
||||
allowDeprecated?: boolean;
|
||||
}): () => void;
|
||||
hookOnce<NameT extends HookNameT>(name: NameT, function_: InferCallback<HooksT, NameT>): () => void;
|
||||
removeHook<NameT extends HookNameT>(name: NameT, function_: InferCallback<HooksT, NameT>): void;
|
||||
deprecateHook<NameT extends HookNameT>(name: NameT, deprecated: HookKeys<HooksT> | DeprecatedHook<HooksT>): void;
|
||||
deprecateHooks(deprecatedHooks: Partial<Record<HookNameT, DeprecatedHook<HooksT>>>): void;
|
||||
addHooks(configHooks: NestedHooks<HooksT>): () => void;
|
||||
removeHooks(configHooks: NestedHooks<HooksT>): void;
|
||||
removeAllHooks(): void;
|
||||
callHook<NameT extends HookNameT>(name: NameT, ...arguments_: Parameters<InferCallback<HooksT, NameT>>): Promise<any>;
|
||||
callHookParallel<NameT extends HookNameT>(name: NameT, ...arguments_: Parameters<InferCallback<HooksT, NameT>>): Promise<any[]>;
|
||||
callHookWith<NameT extends HookNameT, CallFunction extends (hooks: HookCallback[], arguments_: Parameters<InferCallback<HooksT, NameT>>) => any>(caller: CallFunction, name: NameT, ...arguments_: Parameters<InferCallback<HooksT, NameT>>): ReturnType<CallFunction>;
|
||||
beforeEach(function_: (event: InferSpyEvent<HooksT>) => void): () => void;
|
||||
afterEach(function_: (event: InferSpyEvent<HooksT>) => void): () => void;
|
||||
}
|
||||
declare function createHooks<T extends Record<string, any>>(): Hookable<T>;
|
||||
|
||||
declare function flatHooks<T>(configHooks: NestedHooks<T>, hooks?: T, parentName?: string): T;
|
||||
declare function mergeHooks<T>(...hooks: NestedHooks<T>[]): T;
|
||||
declare function serial<T>(tasks: T[], function_: (task: T) => Promise<any> | any): Promise<any>;
|
||||
/** @deprecated */
|
||||
declare function serialCaller(hooks: HookCallback[], arguments_?: any[]): Promise<void>;
|
||||
/** @deprecated */
|
||||
declare function parallelCaller(hooks: HookCallback[], args?: any[]): Promise<void[]>;
|
||||
|
||||
interface CreateDebuggerOptions {
|
||||
/** An optional tag to prefix console logs with */
|
||||
tag?: string;
|
||||
/**
|
||||
* Show hook params to the console output
|
||||
*
|
||||
* Enabled for browsers by default
|
||||
*/
|
||||
inspect?: boolean;
|
||||
/**
|
||||
* Use group/groupEnd wrapper around logs happening during a specific hook
|
||||
*
|
||||
* Enabled for browsers by default
|
||||
*/
|
||||
group?: boolean;
|
||||
/** Filter which hooks to enable debugger for. Can be a string prefix or fn. */
|
||||
filter?: string | ((event: string) => boolean);
|
||||
}
|
||||
/** Start debugging hook names and timing in console */
|
||||
declare function createDebugger(hooks: Hookable<any>, _options?: CreateDebuggerOptions): {
|
||||
/** Stop debugging and remove listeners */
|
||||
close: () => void;
|
||||
};
|
||||
|
||||
export { CreateDebuggerOptions, DeprecatedHook, DeprecatedHooks, HookCallback, HookKeys, Hookable, Hooks, NestedHooks, createDebugger, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };
|
290
node_modules/hookable/dist/index.mjs
generated
vendored
Normal file
290
node_modules/hookable/dist/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
function flatHooks(configHooks, hooks = {}, parentName) {
|
||||
for (const key in configHooks) {
|
||||
const subHook = configHooks[key];
|
||||
const name = parentName ? `${parentName}:${key}` : key;
|
||||
if (typeof subHook === "object" && subHook !== null) {
|
||||
flatHooks(subHook, hooks, name);
|
||||
} else if (typeof subHook === "function") {
|
||||
hooks[name] = subHook;
|
||||
}
|
||||
}
|
||||
return hooks;
|
||||
}
|
||||
function mergeHooks(...hooks) {
|
||||
const finalHooks = {};
|
||||
for (const hook of hooks) {
|
||||
const flatenHook = flatHooks(hook);
|
||||
for (const key in flatenHook) {
|
||||
if (finalHooks[key]) {
|
||||
finalHooks[key].push(flatenHook[key]);
|
||||
} else {
|
||||
finalHooks[key] = [flatenHook[key]];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const key in finalHooks) {
|
||||
if (finalHooks[key].length > 1) {
|
||||
const array = finalHooks[key];
|
||||
finalHooks[key] = (...arguments_) => serial(array, (function_) => function_(...arguments_));
|
||||
} else {
|
||||
finalHooks[key] = finalHooks[key][0];
|
||||
}
|
||||
}
|
||||
return finalHooks;
|
||||
}
|
||||
function serial(tasks, function_) {
|
||||
return tasks.reduce(
|
||||
(promise, task) => promise.then(() => function_(task)),
|
||||
Promise.resolve()
|
||||
);
|
||||
}
|
||||
const defaultTask = { run: (function_) => function_() };
|
||||
const _createTask = () => defaultTask;
|
||||
const createTask = typeof console.createTask !== "undefined" ? console.createTask : _createTask;
|
||||
function serialTaskCaller(hooks, args) {
|
||||
const name = args.shift();
|
||||
const task = createTask(name);
|
||||
return hooks.reduce(
|
||||
(promise, hookFunction) => promise.then(() => task.run(() => hookFunction(...args))),
|
||||
Promise.resolve()
|
||||
);
|
||||
}
|
||||
function parallelTaskCaller(hooks, args) {
|
||||
const name = args.shift();
|
||||
const task = createTask(name);
|
||||
return Promise.all(hooks.map((hook) => task.run(() => hook(...args))));
|
||||
}
|
||||
function serialCaller(hooks, arguments_) {
|
||||
return hooks.reduce(
|
||||
(promise, hookFunction) => promise.then(() => hookFunction(...arguments_ || [])),
|
||||
Promise.resolve()
|
||||
);
|
||||
}
|
||||
function parallelCaller(hooks, args) {
|
||||
return Promise.all(hooks.map((hook) => hook(...args || [])));
|
||||
}
|
||||
function callEachWith(callbacks, arg0) {
|
||||
for (const callback of [...callbacks]) {
|
||||
callback(arg0);
|
||||
}
|
||||
}
|
||||
|
||||
class Hookable {
|
||||
constructor() {
|
||||
this._hooks = {};
|
||||
this._before = void 0;
|
||||
this._after = void 0;
|
||||
this._deprecatedMessages = void 0;
|
||||
this._deprecatedHooks = {};
|
||||
this.hook = this.hook.bind(this);
|
||||
this.callHook = this.callHook.bind(this);
|
||||
this.callHookWith = this.callHookWith.bind(this);
|
||||
}
|
||||
hook(name, function_, options = {}) {
|
||||
if (!name || typeof function_ !== "function") {
|
||||
return () => {
|
||||
};
|
||||
}
|
||||
const originalName = name;
|
||||
let dep;
|
||||
while (this._deprecatedHooks[name]) {
|
||||
dep = this._deprecatedHooks[name];
|
||||
name = dep.to;
|
||||
}
|
||||
if (dep && !options.allowDeprecated) {
|
||||
let message = dep.message;
|
||||
if (!message) {
|
||||
message = `${originalName} hook has been deprecated` + (dep.to ? `, please use ${dep.to}` : "");
|
||||
}
|
||||
if (!this._deprecatedMessages) {
|
||||
this._deprecatedMessages = /* @__PURE__ */ new Set();
|
||||
}
|
||||
if (!this._deprecatedMessages.has(message)) {
|
||||
console.warn(message);
|
||||
this._deprecatedMessages.add(message);
|
||||
}
|
||||
}
|
||||
if (!function_.name) {
|
||||
try {
|
||||
Object.defineProperty(function_, "name", {
|
||||
get: () => "_" + name.replace(/\W+/g, "_") + "_hook_cb",
|
||||
configurable: true
|
||||
});
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
this._hooks[name] = this._hooks[name] || [];
|
||||
this._hooks[name].push(function_);
|
||||
return () => {
|
||||
if (function_) {
|
||||
this.removeHook(name, function_);
|
||||
function_ = void 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
hookOnce(name, function_) {
|
||||
let _unreg;
|
||||
let _function = (...arguments_) => {
|
||||
if (typeof _unreg === "function") {
|
||||
_unreg();
|
||||
}
|
||||
_unreg = void 0;
|
||||
_function = void 0;
|
||||
return function_(...arguments_);
|
||||
};
|
||||
_unreg = this.hook(name, _function);
|
||||
return _unreg;
|
||||
}
|
||||
removeHook(name, function_) {
|
||||
if (this._hooks[name]) {
|
||||
const index = this._hooks[name].indexOf(function_);
|
||||
if (index !== -1) {
|
||||
this._hooks[name].splice(index, 1);
|
||||
}
|
||||
if (this._hooks[name].length === 0) {
|
||||
delete this._hooks[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
deprecateHook(name, deprecated) {
|
||||
this._deprecatedHooks[name] = typeof deprecated === "string" ? { to: deprecated } : deprecated;
|
||||
const _hooks = this._hooks[name] || [];
|
||||
delete this._hooks[name];
|
||||
for (const hook of _hooks) {
|
||||
this.hook(name, hook);
|
||||
}
|
||||
}
|
||||
deprecateHooks(deprecatedHooks) {
|
||||
Object.assign(this._deprecatedHooks, deprecatedHooks);
|
||||
for (const name in deprecatedHooks) {
|
||||
this.deprecateHook(name, deprecatedHooks[name]);
|
||||
}
|
||||
}
|
||||
addHooks(configHooks) {
|
||||
const hooks = flatHooks(configHooks);
|
||||
const removeFns = Object.keys(hooks).map(
|
||||
(key) => this.hook(key, hooks[key])
|
||||
);
|
||||
return () => {
|
||||
for (const unreg of removeFns.splice(0, removeFns.length)) {
|
||||
unreg();
|
||||
}
|
||||
};
|
||||
}
|
||||
removeHooks(configHooks) {
|
||||
const hooks = flatHooks(configHooks);
|
||||
for (const key in hooks) {
|
||||
this.removeHook(key, hooks[key]);
|
||||
}
|
||||
}
|
||||
removeAllHooks() {
|
||||
for (const key in this._hooks) {
|
||||
delete this._hooks[key];
|
||||
}
|
||||
}
|
||||
callHook(name, ...arguments_) {
|
||||
arguments_.unshift(name);
|
||||
return this.callHookWith(serialTaskCaller, name, ...arguments_);
|
||||
}
|
||||
callHookParallel(name, ...arguments_) {
|
||||
arguments_.unshift(name);
|
||||
return this.callHookWith(parallelTaskCaller, name, ...arguments_);
|
||||
}
|
||||
callHookWith(caller, name, ...arguments_) {
|
||||
const event = this._before || this._after ? { name, args: arguments_, context: {} } : void 0;
|
||||
if (this._before) {
|
||||
callEachWith(this._before, event);
|
||||
}
|
||||
const result = caller(
|
||||
name in this._hooks ? [...this._hooks[name]] : [],
|
||||
arguments_
|
||||
);
|
||||
if (result instanceof Promise) {
|
||||
return result.finally(() => {
|
||||
if (this._after && event) {
|
||||
callEachWith(this._after, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this._after && event) {
|
||||
callEachWith(this._after, event);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
beforeEach(function_) {
|
||||
this._before = this._before || [];
|
||||
this._before.push(function_);
|
||||
return () => {
|
||||
if (this._before !== void 0) {
|
||||
const index = this._before.indexOf(function_);
|
||||
if (index !== -1) {
|
||||
this._before.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
afterEach(function_) {
|
||||
this._after = this._after || [];
|
||||
this._after.push(function_);
|
||||
return () => {
|
||||
if (this._after !== void 0) {
|
||||
const index = this._after.indexOf(function_);
|
||||
if (index !== -1) {
|
||||
this._after.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
function createHooks() {
|
||||
return new Hookable();
|
||||
}
|
||||
|
||||
const isBrowser = typeof window !== "undefined";
|
||||
function createDebugger(hooks, _options = {}) {
|
||||
const options = {
|
||||
inspect: isBrowser,
|
||||
group: isBrowser,
|
||||
filter: () => true,
|
||||
..._options
|
||||
};
|
||||
const _filter = options.filter;
|
||||
const filter = typeof _filter === "string" ? (name) => name.startsWith(_filter) : _filter;
|
||||
const _tag = options.tag ? `[${options.tag}] ` : "";
|
||||
const logPrefix = (event) => _tag + event.name + "".padEnd(event._id, "\0");
|
||||
const _idCtr = {};
|
||||
const unsubscribeBefore = hooks.beforeEach((event) => {
|
||||
if (filter !== void 0 && !filter(event.name)) {
|
||||
return;
|
||||
}
|
||||
_idCtr[event.name] = _idCtr[event.name] || 0;
|
||||
event._id = _idCtr[event.name]++;
|
||||
console.time(logPrefix(event));
|
||||
});
|
||||
const unsubscribeAfter = hooks.afterEach((event) => {
|
||||
if (filter !== void 0 && !filter(event.name)) {
|
||||
return;
|
||||
}
|
||||
if (options.group) {
|
||||
console.groupCollapsed(event.name);
|
||||
}
|
||||
if (options.inspect) {
|
||||
console.timeLog(logPrefix(event), event.args);
|
||||
} else {
|
||||
console.timeEnd(logPrefix(event));
|
||||
}
|
||||
if (options.group) {
|
||||
console.groupEnd();
|
||||
}
|
||||
_idCtr[event.name]--;
|
||||
});
|
||||
return {
|
||||
/** Stop debugging and remove listeners */
|
||||
close: () => {
|
||||
unsubscribeBefore();
|
||||
unsubscribeAfter();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export { Hookable, createDebugger, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };
|
49
node_modules/hookable/package.json
generated
vendored
Normal file
49
node_modules/hookable/package.json
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "hookable",
|
||||
"version": "5.5.3",
|
||||
"description": "Awaitable hook system",
|
||||
"keywords": [
|
||||
"hook",
|
||||
"hookable",
|
||||
"plugin",
|
||||
"tapable",
|
||||
"tappable"
|
||||
],
|
||||
"repository": "unjs/hookable",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
"import": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"require": "./dist/index.cjs"
|
||||
},
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.15.11",
|
||||
"@vitest/coverage-c8": "^0.29.8",
|
||||
"changelogen": "^0.5.2",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-config-unjs": "^0.1.0",
|
||||
"expect-type": "^0.15.0",
|
||||
"prettier": "^2.8.7",
|
||||
"typescript": "^5.0.2",
|
||||
"unbuild": "^1.1.2",
|
||||
"vite": "^4.2.1",
|
||||
"vitest": "^0.29.8"
|
||||
},
|
||||
"packageManager": "pnpm@8.0.0",
|
||||
"scripts": {
|
||||
"build": "unbuild",
|
||||
"dev": "vitest",
|
||||
"lint": "eslint --cache --ext .ts,.js,.mjs,.cjs . && prettier -c src test",
|
||||
"lint:fix": "eslint --cache --ext .ts,.js,.mjs,.cjs . --fix && prettier -c src test -w",
|
||||
"prepublish": "pnpm build",
|
||||
"release": "pnpm test && pnpm build && changelogen --release --push && pnpm publish",
|
||||
"test": "pnpm lint && vitest run --coverage",
|
||||
"test:types": "tsc --noEmit"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user