hookable 5.5.2 → 6.0.0-rc.1
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 +76 -57
- package/dist/index.d.mts +107 -0
- package/dist/index.mjs +243 -263
- package/package.json +30 -27
- package/dist/index.cjs +0 -296
- package/dist/index.d.ts +0 -103
package/dist/index.cjs
DELETED
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
function flatHooks(configHooks, hooks = {}, parentName) {
|
|
4
|
-
for (const key in configHooks) {
|
|
5
|
-
const subHook = configHooks[key];
|
|
6
|
-
const name = parentName ? `${parentName}:${key}` : key;
|
|
7
|
-
if (typeof subHook === "object" && subHook !== null) {
|
|
8
|
-
flatHooks(subHook, hooks, name);
|
|
9
|
-
} else if (typeof subHook === "function") {
|
|
10
|
-
hooks[name] = subHook;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return hooks;
|
|
14
|
-
}
|
|
15
|
-
function mergeHooks(...hooks) {
|
|
16
|
-
const finalHooks = {};
|
|
17
|
-
for (const hook of hooks) {
|
|
18
|
-
const flatenHook = flatHooks(hook);
|
|
19
|
-
for (const key in flatenHook) {
|
|
20
|
-
if (finalHooks[key]) {
|
|
21
|
-
finalHooks[key].push(flatenHook[key]);
|
|
22
|
-
} else {
|
|
23
|
-
finalHooks[key] = [flatenHook[key]];
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
for (const key in finalHooks) {
|
|
28
|
-
if (finalHooks[key].length > 1) {
|
|
29
|
-
const array = finalHooks[key];
|
|
30
|
-
finalHooks[key] = (...arguments_) => serial(array, (function_) => function_(...arguments_));
|
|
31
|
-
} else {
|
|
32
|
-
finalHooks[key] = finalHooks[key][0];
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return finalHooks;
|
|
36
|
-
}
|
|
37
|
-
function serial(tasks, function_) {
|
|
38
|
-
return tasks.reduce(
|
|
39
|
-
(promise, task) => promise.then(() => function_(task)),
|
|
40
|
-
Promise.resolve()
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
const defaultTask = { run: (function_) => function_() };
|
|
44
|
-
const _createTask = () => defaultTask;
|
|
45
|
-
const createTask = typeof console.createTask !== "undefined" ? console.createTask : _createTask;
|
|
46
|
-
function serialTaskCaller(hooks, args) {
|
|
47
|
-
const name = args.shift();
|
|
48
|
-
const task = createTask(name);
|
|
49
|
-
return hooks.reduce(
|
|
50
|
-
(promise, hookFunction) => promise.then(() => task.run(() => hookFunction(...args))),
|
|
51
|
-
Promise.resolve()
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
function parallelTaskCaller(hooks, args) {
|
|
55
|
-
const name = args.shift();
|
|
56
|
-
const task = createTask(name);
|
|
57
|
-
return Promise.all(hooks.map((hook) => task.run(() => hook(...args))));
|
|
58
|
-
}
|
|
59
|
-
function serialCaller(hooks, arguments_) {
|
|
60
|
-
return hooks.reduce(
|
|
61
|
-
(promise, hookFunction) => promise.then(() => hookFunction(...arguments_ || [])),
|
|
62
|
-
Promise.resolve()
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
function parallelCaller(hooks, args) {
|
|
66
|
-
return Promise.all(hooks.map((hook) => hook(...args || [])));
|
|
67
|
-
}
|
|
68
|
-
function callEachWith(callbacks, arg0) {
|
|
69
|
-
for (const callback of callbacks) {
|
|
70
|
-
callback(arg0);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
class Hookable {
|
|
75
|
-
constructor() {
|
|
76
|
-
this._hooks = {};
|
|
77
|
-
this._before = void 0;
|
|
78
|
-
this._after = void 0;
|
|
79
|
-
this._deprecatedMessages = void 0;
|
|
80
|
-
this._deprecatedHooks = {};
|
|
81
|
-
this.hook = this.hook.bind(this);
|
|
82
|
-
this.callHook = this.callHook.bind(this);
|
|
83
|
-
this.callHookWith = this.callHookWith.bind(this);
|
|
84
|
-
}
|
|
85
|
-
hook(name, function_, options = {}) {
|
|
86
|
-
if (!name || typeof function_ !== "function") {
|
|
87
|
-
return () => {
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
const originalName = name;
|
|
91
|
-
let dep;
|
|
92
|
-
while (this._deprecatedHooks[name]) {
|
|
93
|
-
dep = this._deprecatedHooks[name];
|
|
94
|
-
name = dep.to;
|
|
95
|
-
}
|
|
96
|
-
if (dep && !options.allowDeprecated) {
|
|
97
|
-
let message = dep.message;
|
|
98
|
-
if (!message) {
|
|
99
|
-
message = `${originalName} hook has been deprecated` + (dep.to ? `, please use ${dep.to}` : "");
|
|
100
|
-
}
|
|
101
|
-
if (!this._deprecatedMessages) {
|
|
102
|
-
this._deprecatedMessages = /* @__PURE__ */ new Set();
|
|
103
|
-
}
|
|
104
|
-
if (!this._deprecatedMessages.has(message)) {
|
|
105
|
-
console.warn(message);
|
|
106
|
-
this._deprecatedMessages.add(message);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (!function_.name) {
|
|
110
|
-
try {
|
|
111
|
-
Object.defineProperty(function_, "name", {
|
|
112
|
-
get: () => "_" + name.replace(/\W+/g, "_") + "_hook_cb",
|
|
113
|
-
configurable: true
|
|
114
|
-
});
|
|
115
|
-
} catch {
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
this._hooks[name] = this._hooks[name] || [];
|
|
119
|
-
this._hooks[name].push(function_);
|
|
120
|
-
return () => {
|
|
121
|
-
if (function_) {
|
|
122
|
-
this.removeHook(name, function_);
|
|
123
|
-
function_ = void 0;
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
hookOnce(name, function_) {
|
|
128
|
-
let _unreg;
|
|
129
|
-
let _function = (...arguments_) => {
|
|
130
|
-
if (typeof _unreg === "function") {
|
|
131
|
-
_unreg();
|
|
132
|
-
}
|
|
133
|
-
_unreg = void 0;
|
|
134
|
-
_function = void 0;
|
|
135
|
-
return function_(...arguments_);
|
|
136
|
-
};
|
|
137
|
-
_unreg = this.hook(name, _function);
|
|
138
|
-
return _unreg;
|
|
139
|
-
}
|
|
140
|
-
removeHook(name, function_) {
|
|
141
|
-
if (this._hooks[name]) {
|
|
142
|
-
const index = this._hooks[name].indexOf(function_);
|
|
143
|
-
if (index !== -1) {
|
|
144
|
-
this._hooks[name].splice(index, 1);
|
|
145
|
-
}
|
|
146
|
-
if (this._hooks[name].length === 0) {
|
|
147
|
-
delete this._hooks[name];
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
deprecateHook(name, deprecated) {
|
|
152
|
-
this._deprecatedHooks[name] = typeof deprecated === "string" ? { to: deprecated } : deprecated;
|
|
153
|
-
const _hooks = this._hooks[name] || [];
|
|
154
|
-
delete this._hooks[name];
|
|
155
|
-
for (const hook of _hooks) {
|
|
156
|
-
this.hook(name, hook);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
deprecateHooks(deprecatedHooks) {
|
|
160
|
-
Object.assign(this._deprecatedHooks, deprecatedHooks);
|
|
161
|
-
for (const name in deprecatedHooks) {
|
|
162
|
-
this.deprecateHook(name, deprecatedHooks[name]);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
addHooks(configHooks) {
|
|
166
|
-
const hooks = flatHooks(configHooks);
|
|
167
|
-
const removeFns = Object.keys(hooks).map(
|
|
168
|
-
(key) => this.hook(key, hooks[key])
|
|
169
|
-
);
|
|
170
|
-
return () => {
|
|
171
|
-
for (const unreg of removeFns.splice(0, removeFns.length)) {
|
|
172
|
-
unreg();
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
removeHooks(configHooks) {
|
|
177
|
-
const hooks = flatHooks(configHooks);
|
|
178
|
-
for (const key in hooks) {
|
|
179
|
-
this.removeHook(key, hooks[key]);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
removeAllHooks() {
|
|
183
|
-
for (const key in this._hooks) {
|
|
184
|
-
delete this._hooks[key];
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
callHook(name, ...arguments_) {
|
|
188
|
-
arguments_.unshift(name);
|
|
189
|
-
return this.callHookWith(serialTaskCaller, name, ...arguments_);
|
|
190
|
-
}
|
|
191
|
-
callHookParallel(name, ...arguments_) {
|
|
192
|
-
arguments_.unshift(name);
|
|
193
|
-
return this.callHookWith(parallelTaskCaller, name, ...arguments_);
|
|
194
|
-
}
|
|
195
|
-
callHookWith(caller, name, ...arguments_) {
|
|
196
|
-
const event = this._before || this._after ? { name, args: arguments_, context: {} } : void 0;
|
|
197
|
-
if (this._before) {
|
|
198
|
-
callEachWith(this._before, event);
|
|
199
|
-
}
|
|
200
|
-
const result = caller(this._hooks[name] || [], arguments_);
|
|
201
|
-
if (result instanceof Promise) {
|
|
202
|
-
return result.finally(() => {
|
|
203
|
-
if (this._after && event) {
|
|
204
|
-
callEachWith(this._after, event);
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
if (this._after && event) {
|
|
209
|
-
callEachWith(this._after, event);
|
|
210
|
-
}
|
|
211
|
-
return result;
|
|
212
|
-
}
|
|
213
|
-
beforeEach(function_) {
|
|
214
|
-
this._before = this._before || [];
|
|
215
|
-
this._before.push(function_);
|
|
216
|
-
return () => {
|
|
217
|
-
if (this._before !== void 0) {
|
|
218
|
-
const index = this._before.indexOf(function_);
|
|
219
|
-
if (index !== -1) {
|
|
220
|
-
this._before.splice(index, 1);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
afterEach(function_) {
|
|
226
|
-
this._after = this._after || [];
|
|
227
|
-
this._after.push(function_);
|
|
228
|
-
return () => {
|
|
229
|
-
if (this._after !== void 0) {
|
|
230
|
-
const index = this._after.indexOf(function_);
|
|
231
|
-
if (index !== -1) {
|
|
232
|
-
this._after.splice(index, 1);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
function createHooks() {
|
|
239
|
-
return new Hookable();
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const isBrowser = typeof window !== "undefined";
|
|
243
|
-
function createDebugger(hooks, _options = {}) {
|
|
244
|
-
const options = {
|
|
245
|
-
inspect: isBrowser,
|
|
246
|
-
group: isBrowser,
|
|
247
|
-
filter: () => true,
|
|
248
|
-
..._options
|
|
249
|
-
};
|
|
250
|
-
const _filter = options.filter;
|
|
251
|
-
const filter = typeof _filter === "string" ? (name) => name.startsWith(_filter) : _filter;
|
|
252
|
-
const _tag = options.tag ? `[${options.tag}] ` : "";
|
|
253
|
-
const logPrefix = (event) => _tag + event.name + "".padEnd(event._id, "\0");
|
|
254
|
-
const _idCtr = {};
|
|
255
|
-
const unsubscribeBefore = hooks.beforeEach((event) => {
|
|
256
|
-
if (filter !== void 0 && !filter(event.name)) {
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
_idCtr[event.name] = _idCtr[event.name] || 0;
|
|
260
|
-
event._id = _idCtr[event.name]++;
|
|
261
|
-
console.time(logPrefix(event));
|
|
262
|
-
});
|
|
263
|
-
const unsubscribeAfter = hooks.afterEach((event) => {
|
|
264
|
-
if (filter !== void 0 && !filter(event.name)) {
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
if (options.group) {
|
|
268
|
-
console.groupCollapsed(event.name);
|
|
269
|
-
}
|
|
270
|
-
if (options.inspect) {
|
|
271
|
-
console.timeLog(logPrefix(event), event.args);
|
|
272
|
-
} else {
|
|
273
|
-
console.timeEnd(logPrefix(event));
|
|
274
|
-
}
|
|
275
|
-
if (options.group) {
|
|
276
|
-
console.groupEnd();
|
|
277
|
-
}
|
|
278
|
-
_idCtr[event.name]--;
|
|
279
|
-
});
|
|
280
|
-
return {
|
|
281
|
-
/** Stop debugging and remove listeners */
|
|
282
|
-
close: () => {
|
|
283
|
-
unsubscribeBefore();
|
|
284
|
-
unsubscribeAfter();
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
exports.Hookable = Hookable;
|
|
290
|
-
exports.createDebugger = createDebugger;
|
|
291
|
-
exports.createHooks = createHooks;
|
|
292
|
-
exports.flatHooks = flatHooks;
|
|
293
|
-
exports.mergeHooks = mergeHooks;
|
|
294
|
-
exports.parallelCaller = parallelCaller;
|
|
295
|
-
exports.serial = serial;
|
|
296
|
-
exports.serialCaller = serialCaller;
|
package/dist/index.d.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
type HookCallback = (...arguments_: any) => Promise<void> | void;
|
|
2
|
-
interface Hooks {
|
|
3
|
-
[key: string]: HookCallback;
|
|
4
|
-
}
|
|
5
|
-
type HookKeys<T> = keyof T & string;
|
|
6
|
-
type DeprecatedHook<T> = {
|
|
7
|
-
message?: string;
|
|
8
|
-
to: HookKeys<T>;
|
|
9
|
-
};
|
|
10
|
-
type DeprecatedHooks<T> = {
|
|
11
|
-
[name in HookKeys<T>]: DeprecatedHook<T>;
|
|
12
|
-
};
|
|
13
|
-
type ValueOf<C> = C extends Record<any, any> ? C[keyof C] : never;
|
|
14
|
-
type Strings<T> = Exclude<keyof T, number | symbol>;
|
|
15
|
-
type KnownKeys<T> = keyof {
|
|
16
|
-
[K in keyof T as string extends K ? never : number extends K ? never : K]: never;
|
|
17
|
-
};
|
|
18
|
-
type StripGeneric<T> = Pick<T, KnownKeys<T> extends keyof T ? KnownKeys<T> : never>;
|
|
19
|
-
type OnlyGeneric<T> = Omit<T, KnownKeys<T> extends keyof T ? KnownKeys<T> : never>;
|
|
20
|
-
type Namespaces<T> = ValueOf<{
|
|
21
|
-
[key in Strings<T>]: key extends `${infer Namespace}:${string}` ? Namespace : never;
|
|
22
|
-
}>;
|
|
23
|
-
type BareHooks<T> = ValueOf<{
|
|
24
|
-
[key in Strings<T>]: key extends `${string}:${string}` ? never : key;
|
|
25
|
-
}>;
|
|
26
|
-
type HooksInNamespace<T, Namespace extends string> = ValueOf<{
|
|
27
|
-
[key in Strings<T>]: key extends `${Namespace}:${infer HookName}` ? HookName : never;
|
|
28
|
-
}>;
|
|
29
|
-
type WithoutNamespace<T, Namespace extends string> = {
|
|
30
|
-
[key in HooksInNamespace<T, Namespace>]: `${Namespace}:${key}` extends keyof T ? T[`${Namespace}:${key}`] : never;
|
|
31
|
-
};
|
|
32
|
-
type NestedHooks<T> = (Partial<StripGeneric<T>> | Partial<OnlyGeneric<T>>) & Partial<{
|
|
33
|
-
[key in Namespaces<StripGeneric<T>>]: NestedHooks<WithoutNamespace<T, key>>;
|
|
34
|
-
}> & Partial<{
|
|
35
|
-
[key in BareHooks<StripGeneric<T>>]: T[key];
|
|
36
|
-
}>;
|
|
37
|
-
|
|
38
|
-
type InferCallback<HT, HN extends keyof HT> = HT[HN] extends HookCallback ? HT[HN] : never;
|
|
39
|
-
type InferSpyEvent<HT extends Record<string, any>> = {
|
|
40
|
-
[key in keyof HT]: {
|
|
41
|
-
name: key;
|
|
42
|
-
args: Parameters<HT[key]>;
|
|
43
|
-
context: Record<string, any>;
|
|
44
|
-
};
|
|
45
|
-
}[keyof HT];
|
|
46
|
-
declare class Hookable<HooksT extends Record<string, any> = Record<string, HookCallback>, HookNameT extends HookKeys<HooksT> = HookKeys<HooksT>> {
|
|
47
|
-
private _hooks;
|
|
48
|
-
private _before?;
|
|
49
|
-
private _after?;
|
|
50
|
-
private _deprecatedHooks;
|
|
51
|
-
private _deprecatedMessages?;
|
|
52
|
-
constructor();
|
|
53
|
-
hook<NameT extends HookNameT>(name: NameT, function_: InferCallback<HooksT, NameT>, options?: {
|
|
54
|
-
allowDeprecated?: boolean;
|
|
55
|
-
}): () => void;
|
|
56
|
-
hookOnce<NameT extends HookNameT>(name: NameT, function_: InferCallback<HooksT, NameT>): () => void;
|
|
57
|
-
removeHook<NameT extends HookNameT>(name: NameT, function_: InferCallback<HooksT, NameT>): void;
|
|
58
|
-
deprecateHook<NameT extends HookNameT>(name: NameT, deprecated: HookKeys<HooksT> | DeprecatedHook<HooksT>): void;
|
|
59
|
-
deprecateHooks(deprecatedHooks: Partial<Record<HookNameT, DeprecatedHook<HooksT>>>): void;
|
|
60
|
-
addHooks(configHooks: NestedHooks<HooksT>): () => void;
|
|
61
|
-
removeHooks(configHooks: NestedHooks<HooksT>): void;
|
|
62
|
-
removeAllHooks(): void;
|
|
63
|
-
callHook<NameT extends HookNameT>(name: NameT, ...arguments_: Parameters<InferCallback<HooksT, NameT>>): Promise<any>;
|
|
64
|
-
callHookParallel<NameT extends HookNameT>(name: NameT, ...arguments_: Parameters<InferCallback<HooksT, NameT>>): Promise<any[]>;
|
|
65
|
-
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>;
|
|
66
|
-
beforeEach(function_: (event: InferSpyEvent<HooksT>) => void): () => void;
|
|
67
|
-
afterEach(function_: (event: InferSpyEvent<HooksT>) => void): () => void;
|
|
68
|
-
}
|
|
69
|
-
declare function createHooks<T extends Record<string, any>>(): Hookable<T>;
|
|
70
|
-
|
|
71
|
-
declare function flatHooks<T>(configHooks: NestedHooks<T>, hooks?: T, parentName?: string): T;
|
|
72
|
-
declare function mergeHooks<T>(...hooks: NestedHooks<T>[]): T;
|
|
73
|
-
declare function serial<T>(tasks: T[], function_: (task: T) => Promise<any> | any): Promise<any>;
|
|
74
|
-
/** @deprecated */
|
|
75
|
-
declare function serialCaller(hooks: HookCallback[], arguments_?: any[]): Promise<void>;
|
|
76
|
-
/** @deprecated */
|
|
77
|
-
declare function parallelCaller(hooks: HookCallback[], args?: any[]): Promise<void[]>;
|
|
78
|
-
|
|
79
|
-
interface CreateDebuggerOptions {
|
|
80
|
-
/** An optional tag to prefix console logs with */
|
|
81
|
-
tag?: string;
|
|
82
|
-
/**
|
|
83
|
-
* Show hook params to the console output
|
|
84
|
-
*
|
|
85
|
-
* Enabled for browsers by default
|
|
86
|
-
*/
|
|
87
|
-
inspect?: boolean;
|
|
88
|
-
/**
|
|
89
|
-
* Use group/groupEnd wrapper around logs happening during a specific hook
|
|
90
|
-
*
|
|
91
|
-
* Enabled for browsers by default
|
|
92
|
-
*/
|
|
93
|
-
group?: boolean;
|
|
94
|
-
/** Filter which hooks to enable debugger for. Can be a string prefix or fn. */
|
|
95
|
-
filter?: string | ((event: string) => boolean);
|
|
96
|
-
}
|
|
97
|
-
/** Start debugging hook names and timing in console */
|
|
98
|
-
declare function createDebugger(hooks: Hookable<any>, _options?: CreateDebuggerOptions): {
|
|
99
|
-
/** Stop debugging and remove listeners */
|
|
100
|
-
close: () => void;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
export { CreateDebuggerOptions, DeprecatedHook, DeprecatedHooks, HookCallback, HookKeys, Hookable, Hooks, NestedHooks, createDebugger, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };
|