@shuvi/hook 1.0.22 → 1.0.24

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.
@@ -1,54 +1,7 @@
1
- import { SyncHook, SyncBailHook, SyncWaterfallHook, AsyncParallelHook, AsyncSeriesWaterfallHook, SyncHookHandler, SyncBailHookHandler, SyncWaterfallHookHandler, AsyncParallelHookHandler, AsyncSeriesWaterfallHookHandler, AsyncSeriesHook, AsyncSeriesBailHook, AsyncSeriesHookHandler, AsyncSeriesBailHookHandler } from './hooks';
2
- export declare type PatchPluginParameter<T, C> = RemoveManagerVoidParameter<AddContextParameter<T, C>>;
3
- export declare type AddContextParameter<T, C> = T extends (initalValue: infer I, extraArg: infer E) => infer R ? (initalValue: I, extraArg: E, context: C) => R : T;
4
- export declare type AnyHook = SyncHook<any, any, any> | SyncBailHook<any, any, any> | SyncWaterfallHook<any, any> | AsyncParallelHook<any, any, any> | AsyncSeriesHook<any, any, any> | AsyncSeriesBailHook<any, any, any> | AsyncSeriesWaterfallHook<any, any>;
5
- export interface HookMap {
6
- [x: string]: AnyHook;
7
- }
8
- export declare type Setup<HM extends HookMap = {}> = (utils: {
9
- addHooks: (hook: Partial<HM>) => void;
10
- }) => void;
11
- export declare type CreatePlugin<HM extends HookMap, C> = (pluginHandlers: IPluginHandlers<HM, C> & {
12
- setup?: Setup;
13
- }, options?: PluginOptions) => IPluginInstance<HM, C>;
14
- export declare type HookManager<HM extends HookMap, C> = {
15
- createPlugin: CreatePlugin<HM, C>;
16
- usePlugin: (...plugins: IPluginInstance<HM, C>[]) => void;
17
- runner: RunnerType<HM>;
18
- setContext: (context: C) => void;
19
- clear: () => void;
20
- addHooks: <EHM extends HookMap>(hook: Partial<EHM>) => void;
21
- hooks: HM;
22
- getPlugins: () => IPluginInstance<HM, C>[];
23
- };
24
- export declare type RunnerType<HM> = {
25
- [K in keyof HM]: HookRunnerType<HM[K]>;
26
- } & {
27
- setup: Setup;
28
- };
29
- export declare type HookRunnerType<H> = H extends SyncHook<infer T, infer E, infer R> ? SyncHook<T, E, R>['run'] : H extends SyncBailHook<infer T, infer E, infer R> ? SyncBailHook<T, E, R>['run'] : H extends SyncWaterfallHook<infer T, infer E> ? SyncWaterfallHook<T, E>['run'] : H extends AsyncParallelHook<infer T, infer E, infer R> ? AsyncParallelHook<T, E, R>['run'] : H extends AsyncSeriesHook<infer T, infer E, infer R> ? AsyncSeriesHook<T, E, R>['run'] : H extends AsyncSeriesBailHook<infer T, infer E, infer R> ? AsyncSeriesBailHook<T, E, R>['run'] : H extends AsyncSeriesWaterfallHook<infer T, infer E> ? AsyncSeriesWaterfallHook<T, E>['run'] : never;
30
- export declare type IPluginInstance<HM, C> = {
31
- handlers: IPluginHandlers<HM, C>;
32
- PLUGIN_SYMBOL: 'PLUGIN_SYMBOL';
33
- } & Required<PluginOptions>;
34
- export declare type IPluginHandlers<HM, C> = Partial<IPluginHandlersFullMap<HM, C>>;
35
- export declare type IPluginHandlersFullMap<HM, C> = {
36
- [K in keyof HM]: HM[K] extends SyncHook<infer T, infer E, infer R> ? PatchPluginParameter<SyncHookHandler<T, E, R>, C> : HM[K] extends SyncBailHook<infer T, infer E, infer R> ? PatchPluginParameter<SyncBailHookHandler<T, E, R>, C> : HM[K] extends SyncWaterfallHook<infer T, infer E> ? PatchPluginParameter<SyncWaterfallHookHandler<T, E>, C> : HM[K] extends AsyncParallelHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncParallelHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncSeriesHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesBailHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncSeriesBailHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesWaterfallHook<infer T, infer E> ? PatchPluginParameter<AsyncSeriesWaterfallHookHandler<T, E>, C> : never;
37
- };
38
- export declare type PluginOptions = {
39
- name?: string;
40
- pre?: string[];
41
- post?: string[];
42
- rivals?: string[];
43
- required?: string[];
44
- order?: number;
45
- group?: number;
46
- [x: string]: any;
47
- };
1
+ import { IPluginHandlers, IPluginInstance, HookManager, HookMap, PluginOptions } from './types';
48
2
  export declare const isPluginInstance: <T extends IPluginInstance<any, any> = IPluginInstance<any, any>>(plugin: any) => plugin is T;
49
3
  export declare type ArrayElements<T extends {}> = {
50
4
  [K in keyof T]: T[K][];
51
5
  };
52
6
  export declare function createPlugin<HM extends HookMap, C = void>(pluginHandlers: IPluginHandlers<HM, C>, options?: PluginOptions): IPluginInstance<HM, C>;
53
7
  export declare const createHookManager: <HM extends HookMap, C = void>(hookMap: HM, hasContext?: boolean) => HookManager<HM, C>;
54
- export declare type RemoveManagerVoidParameter<T> = T extends (initalValue: infer I, extraArg: infer E, context: infer C) => infer R ? null extends I ? null extends E ? null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends E ? null extends C ? (initialValue: I, context: C) => R : void extends C ? (initialValue: I) => R : (initialValue: I, context: C) => R : null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends I ? null extends E ? null extends C ? (extraArg: E, context: C) => R : void extends C ? (extraArg: E) => R : (extraArg: E, context: C) => R : void extends E ? null extends C ? (context: C) => R : void extends C ? () => R : (context: C) => R : null extends C ? (extraArg: E, context: C) => R : void extends C ? (extraArg: E) => R : (extraArg: E, context: C) => R : null extends E ? null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends E ? null extends C ? (initialValue: I, context: C) => R : void extends C ? (initialValue: I) => R : (initialValue: I, context: C) => R : null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : T;
package/esm/hookGroup.js CHANGED
@@ -1,81 +1,17 @@
1
1
  import { createSyncHook, createSyncBailHook, createSyncWaterfallHook, createAsyncParallelHook, createAsyncSeriesWaterfallHook, createAsyncSeriesBailHook, createAsyncSeriesHook } from './hooks';
2
+ import { verifyPlugins, sortPlugins } from './utils';
2
3
  const DEFAULT_OPTIONS = {
3
4
  name: 'untitled',
4
- pre: [],
5
- post: [],
6
- rivals: [],
5
+ before: [],
6
+ after: [],
7
+ conflict: [],
7
8
  required: [],
8
- order: 0,
9
9
  group: 0
10
10
  };
11
11
  const PLUGIN_SYMBOL = 'PLUGIN_SYMBOL';
12
12
  export const isPluginInstance = (plugin) => plugin &&
13
13
  plugin.hasOwnProperty(PLUGIN_SYMBOL) &&
14
14
  plugin.PLUGIN_SYMBOL === PLUGIN_SYMBOL;
15
- const sortPlugins = (input) => {
16
- let plugins = input.slice();
17
- plugins.sort((a, b) => {
18
- // sort by group first
19
- if (a.group === b.group) {
20
- return a.order - b.order;
21
- }
22
- else {
23
- return a.group - b.group;
24
- }
25
- });
26
- for (let i = 0; i < plugins.length; i++) {
27
- let plugin = plugins[i];
28
- if (plugin.pre) {
29
- for (const pre of plugin.pre) {
30
- for (let j = i + 1; j < plugins.length; j++) {
31
- if (plugins[j].name === pre) {
32
- plugins = [
33
- ...plugins.slice(0, i),
34
- plugins[j],
35
- ...plugins.slice(i, j),
36
- ...plugins.slice(j + 1, plugins.length)
37
- ];
38
- }
39
- }
40
- }
41
- }
42
- if (plugin.post) {
43
- for (const post of plugin.post) {
44
- for (let j = 0; j < i; j++) {
45
- if (plugins[j].name === post) {
46
- plugins = [
47
- ...plugins.slice(0, j),
48
- ...plugins.slice(j + 1, i + 1),
49
- plugins[j],
50
- ...plugins.slice(i + 1, plugins.length)
51
- ];
52
- }
53
- }
54
- }
55
- }
56
- }
57
- return plugins;
58
- };
59
- const checkPlugins = (plugins) => {
60
- for (const origin of plugins) {
61
- if (origin.rivals) {
62
- for (const rival of origin.rivals) {
63
- for (const plugin of plugins) {
64
- if (rival === plugin.name) {
65
- throw new Error(`${origin.name} has rival ${plugin.name}`);
66
- }
67
- }
68
- }
69
- }
70
- if (origin.required) {
71
- for (const required of origin.required) {
72
- if (!plugins.some(plugin => plugin.name === required)) {
73
- throw new Error(`The plugin: ${required} is required when plugin: ${origin.name} is exist.`);
74
- }
75
- }
76
- }
77
- }
78
- };
79
15
  function uuid() {
80
16
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
81
17
  var r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8;
@@ -136,10 +72,9 @@ export const createHookManager = (hookMap, hasContext = true) => {
136
72
  _plugins.push(...plugins);
137
73
  };
138
74
  const load = () => {
139
- let plugins = _plugins;
140
- plugins = sortPlugins(plugins);
141
- checkPlugins(plugins);
142
- plugins.forEach(plugin => {
75
+ verifyPlugins(_plugins);
76
+ _plugins = sortPlugins(_plugins);
77
+ _plugins.forEach(plugin => {
143
78
  const handlers = plugin.handlers;
144
79
  let hookName;
145
80
  for (hookName in handlers) {
package/esm/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './hooks';
2
2
  export * from './hookGroup';
3
+ export * from './types';
package/esm/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './hooks';
2
2
  export * from './hookGroup';
3
+ export * from './types';
package/esm/types.d.ts ADDED
@@ -0,0 +1,59 @@
1
+ import { SyncHook, SyncBailHook, SyncWaterfallHook, AsyncParallelHook, AsyncSeriesWaterfallHook, SyncHookHandler, SyncBailHookHandler, SyncWaterfallHookHandler, AsyncParallelHookHandler, AsyncSeriesWaterfallHookHandler, AsyncSeriesHook, AsyncSeriesBailHook, AsyncSeriesHookHandler, AsyncSeriesBailHookHandler } from './hooks';
2
+ export declare type PatchPluginParameter<T, C> = RemoveManagerVoidParameter<AddContextParameter<T, C>>;
3
+ export declare type AddContextParameter<T, C> = T extends (initalValue: infer I, extraArg: infer E) => infer R ? (initalValue: I, extraArg: E, context: C) => R : T;
4
+ export declare type AnyHook = SyncHook<any, any, any> | SyncBailHook<any, any, any> | SyncWaterfallHook<any, any> | AsyncParallelHook<any, any, any> | AsyncSeriesHook<any, any, any> | AsyncSeriesBailHook<any, any, any> | AsyncSeriesWaterfallHook<any, any>;
5
+ export interface HookMap {
6
+ [x: string]: AnyHook;
7
+ }
8
+ export declare type Setup<HM extends HookMap = {}> = (utils: {
9
+ addHooks: (hook: Partial<HM>) => void;
10
+ }) => void;
11
+ export declare type CreatePlugin<HM extends HookMap, C> = (pluginHandlers: IPluginHandlers<HM, C> & {
12
+ setup?: Setup;
13
+ }, options?: PluginOptions) => IPluginInstance<HM, C>;
14
+ export declare type HookManager<HM extends HookMap, C> = {
15
+ createPlugin: CreatePlugin<HM, C>;
16
+ usePlugin: (...plugins: IPluginInstance<HM, C>[]) => void;
17
+ runner: RunnerType<HM>;
18
+ setContext: (context: C) => void;
19
+ clear: () => void;
20
+ addHooks: <EHM extends HookMap>(hook: Partial<EHM>) => void;
21
+ hooks: HM;
22
+ getPlugins: () => IPluginInstance<HM, C>[];
23
+ };
24
+ export declare type RunnerType<HM> = {
25
+ [K in keyof HM]: HookRunnerType<HM[K]>;
26
+ } & {
27
+ setup: Setup;
28
+ };
29
+ export declare type HookRunnerType<H> = H extends SyncHook<infer T, infer E, infer R> ? SyncHook<T, E, R>['run'] : H extends SyncBailHook<infer T, infer E, infer R> ? SyncBailHook<T, E, R>['run'] : H extends SyncWaterfallHook<infer T, infer E> ? SyncWaterfallHook<T, E>['run'] : H extends AsyncParallelHook<infer T, infer E, infer R> ? AsyncParallelHook<T, E, R>['run'] : H extends AsyncSeriesHook<infer T, infer E, infer R> ? AsyncSeriesHook<T, E, R>['run'] : H extends AsyncSeriesBailHook<infer T, infer E, infer R> ? AsyncSeriesBailHook<T, E, R>['run'] : H extends AsyncSeriesWaterfallHook<infer T, infer E> ? AsyncSeriesWaterfallHook<T, E>['run'] : never;
30
+ export declare type IPluginInstance<HM, C> = {
31
+ handlers: IPluginHandlers<HM, C>;
32
+ PLUGIN_SYMBOL: 'PLUGIN_SYMBOL';
33
+ } & Required<PluginOptions>;
34
+ export declare type IPluginHandlers<HM, C> = Partial<IPluginHandlersFullMap<HM, C>>;
35
+ export declare type IPluginHandlersFullMap<HM, C> = {
36
+ [K in keyof HM]: HM[K] extends SyncHook<infer T, infer E, infer R> ? PatchPluginParameter<SyncHookHandler<T, E, R>, C> : HM[K] extends SyncBailHook<infer T, infer E, infer R> ? PatchPluginParameter<SyncBailHookHandler<T, E, R>, C> : HM[K] extends SyncWaterfallHook<infer T, infer E> ? PatchPluginParameter<SyncWaterfallHookHandler<T, E>, C> : HM[K] extends AsyncParallelHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncParallelHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncSeriesHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesBailHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncSeriesBailHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesWaterfallHook<infer T, infer E> ? PatchPluginParameter<AsyncSeriesWaterfallHookHandler<T, E>, C> : never;
37
+ };
38
+ export declare type PluginOptions = {
39
+ name?: string;
40
+ /** current plugin should before these configured plugins.
41
+ * only works for same group
42
+ */
43
+ before?: string[];
44
+ /** current plugin should after these configured plugins.
45
+ * only works for same group.
46
+ */
47
+ after?: string[];
48
+ /** current plugin should not be used with these configured plugins */
49
+ conflict?: string[];
50
+ /** current plugin should be used with these configured plugins */
51
+ required?: string[];
52
+ /** current plugin group.
53
+ * smaller group will be executed first
54
+ * 0: default
55
+ */
56
+ group?: number;
57
+ [x: string]: any;
58
+ };
59
+ export declare type RemoveManagerVoidParameter<T> = T extends (initalValue: infer I, extraArg: infer E, context: infer C) => infer R ? null extends I ? null extends E ? null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends E ? null extends C ? (initialValue: I, context: C) => R : void extends C ? (initialValue: I) => R : (initialValue: I, context: C) => R : null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends I ? null extends E ? null extends C ? (extraArg: E, context: C) => R : void extends C ? (extraArg: E) => R : (extraArg: E, context: C) => R : void extends E ? null extends C ? (context: C) => R : void extends C ? () => R : (context: C) => R : null extends C ? (extraArg: E, context: C) => R : void extends C ? (extraArg: E) => R : (extraArg: E, context: C) => R : null extends E ? null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends E ? null extends C ? (initialValue: I, context: C) => R : void extends C ? (initialValue: I) => R : (initialValue: I, context: C) => R : null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : T;
package/esm/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/esm/utils.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { IPluginInstance } from './types';
2
+ export declare const sortPluginsByRelationShip: <T extends IPluginInstance<any, any>[]>(input: T) => T;
3
+ export declare const sortPlugins: <T extends IPluginInstance<any, any>[]>(input: T) => T;
4
+ export declare const verifyPlugins: (plugins: IPluginInstance<any, any>[]) => void;
package/esm/utils.js ADDED
@@ -0,0 +1,104 @@
1
+ export const sortPluginsByRelationShip = (input) => {
2
+ const plugins = new Map();
3
+ /**
4
+ * the key is the end point of the edge
5
+ * In this way, we can easily find the plugin with zero in-degree
6
+ */
7
+ const edges = new Map();
8
+ const addEdge = (start, end) => {
9
+ if (!edges.has(end)) {
10
+ edges.set(end, new Set());
11
+ }
12
+ edges.get(end).add(start);
13
+ };
14
+ // Firstly, set plugins into map
15
+ input.forEach(plugin => {
16
+ plugins.set(plugin.name, plugin);
17
+ });
18
+ input.forEach(plugin => {
19
+ if (!edges.has(plugin.name)) {
20
+ edges.set(plugin.name, new Set());
21
+ }
22
+ if (plugin.before) {
23
+ plugin.before.forEach(name => {
24
+ // If the plugin is not in the input, we will ignore it
25
+ if (plugins.has(name)) {
26
+ addEdge(plugin.name, name);
27
+ }
28
+ });
29
+ }
30
+ if (plugin.after) {
31
+ plugin.after.forEach(name => {
32
+ // If the plugin is not in the input, we will ignore it
33
+ if (plugins.has(name)) {
34
+ addEdge(name, plugin.name);
35
+ }
36
+ });
37
+ }
38
+ });
39
+ const sorted = [];
40
+ while (edges.size > 0) {
41
+ let hasZeroInDegree = false;
42
+ edges.forEach((value, key) => {
43
+ if (value.size === 0) {
44
+ hasZeroInDegree = true;
45
+ sorted.push(plugins.get(key));
46
+ edges.delete(key);
47
+ edges.forEach(v => {
48
+ v.delete(key);
49
+ });
50
+ }
51
+ });
52
+ if (!hasZeroInDegree) {
53
+ throw new Error(`Plugin circular dependency detected: ${Array.from(edges.keys()).join(', ')}. Please ensure the plugins have correct 'before' and 'after' property.`);
54
+ }
55
+ }
56
+ return sorted;
57
+ };
58
+ export const sortPlugins = (input) => {
59
+ const groupMap = new Map();
60
+ input.forEach(plugin => {
61
+ if (!groupMap.has(plugin.group)) {
62
+ groupMap.set(plugin.group, []);
63
+ }
64
+ groupMap.get(plugin.group).push(plugin);
65
+ });
66
+ const groupNumbers = Array.from(groupMap.keys());
67
+ const sortedGroupNumbers = groupNumbers.sort((a, b) => a - b);
68
+ const sorted = [];
69
+ sortedGroupNumbers.forEach(groupNumber => {
70
+ sorted.push(...sortPluginsByRelationShip(groupMap.get(groupNumber)));
71
+ });
72
+ return sorted;
73
+ };
74
+ export const verifyPlugins = (plugins) => {
75
+ const names = new Set();
76
+ for (const current of plugins) {
77
+ if (typeof current.name !== 'string') {
78
+ throw new Error(`Plugin name must be string type.`);
79
+ }
80
+ if (!current.name) {
81
+ throw new Error(`Plugin name must be non-empty string.`);
82
+ }
83
+ if (names.has(current.name)) {
84
+ throw new Error(`Plugin name duplication detected: ${current.name}.`);
85
+ }
86
+ names.add(current.name);
87
+ if (current.conflict) {
88
+ for (const conflict of current.conflict) {
89
+ for (const plugin of plugins) {
90
+ if (conflict === plugin.name) {
91
+ throw new Error(`Plugin conflict detected: ${current.name} has conflict with ${plugin.name}.`);
92
+ }
93
+ }
94
+ }
95
+ }
96
+ if (current.required) {
97
+ for (const required of current.required) {
98
+ if (!plugins.some(plugin => plugin.name === required)) {
99
+ throw new Error(`Plugin missing detected: ${required} is required by ${current.name}.`);
100
+ }
101
+ }
102
+ }
103
+ }
104
+ };
@@ -1,54 +1,7 @@
1
- import { SyncHook, SyncBailHook, SyncWaterfallHook, AsyncParallelHook, AsyncSeriesWaterfallHook, SyncHookHandler, SyncBailHookHandler, SyncWaterfallHookHandler, AsyncParallelHookHandler, AsyncSeriesWaterfallHookHandler, AsyncSeriesHook, AsyncSeriesBailHook, AsyncSeriesHookHandler, AsyncSeriesBailHookHandler } from './hooks';
2
- export declare type PatchPluginParameter<T, C> = RemoveManagerVoidParameter<AddContextParameter<T, C>>;
3
- export declare type AddContextParameter<T, C> = T extends (initalValue: infer I, extraArg: infer E) => infer R ? (initalValue: I, extraArg: E, context: C) => R : T;
4
- export declare type AnyHook = SyncHook<any, any, any> | SyncBailHook<any, any, any> | SyncWaterfallHook<any, any> | AsyncParallelHook<any, any, any> | AsyncSeriesHook<any, any, any> | AsyncSeriesBailHook<any, any, any> | AsyncSeriesWaterfallHook<any, any>;
5
- export interface HookMap {
6
- [x: string]: AnyHook;
7
- }
8
- export declare type Setup<HM extends HookMap = {}> = (utils: {
9
- addHooks: (hook: Partial<HM>) => void;
10
- }) => void;
11
- export declare type CreatePlugin<HM extends HookMap, C> = (pluginHandlers: IPluginHandlers<HM, C> & {
12
- setup?: Setup;
13
- }, options?: PluginOptions) => IPluginInstance<HM, C>;
14
- export declare type HookManager<HM extends HookMap, C> = {
15
- createPlugin: CreatePlugin<HM, C>;
16
- usePlugin: (...plugins: IPluginInstance<HM, C>[]) => void;
17
- runner: RunnerType<HM>;
18
- setContext: (context: C) => void;
19
- clear: () => void;
20
- addHooks: <EHM extends HookMap>(hook: Partial<EHM>) => void;
21
- hooks: HM;
22
- getPlugins: () => IPluginInstance<HM, C>[];
23
- };
24
- export declare type RunnerType<HM> = {
25
- [K in keyof HM]: HookRunnerType<HM[K]>;
26
- } & {
27
- setup: Setup;
28
- };
29
- export declare type HookRunnerType<H> = H extends SyncHook<infer T, infer E, infer R> ? SyncHook<T, E, R>['run'] : H extends SyncBailHook<infer T, infer E, infer R> ? SyncBailHook<T, E, R>['run'] : H extends SyncWaterfallHook<infer T, infer E> ? SyncWaterfallHook<T, E>['run'] : H extends AsyncParallelHook<infer T, infer E, infer R> ? AsyncParallelHook<T, E, R>['run'] : H extends AsyncSeriesHook<infer T, infer E, infer R> ? AsyncSeriesHook<T, E, R>['run'] : H extends AsyncSeriesBailHook<infer T, infer E, infer R> ? AsyncSeriesBailHook<T, E, R>['run'] : H extends AsyncSeriesWaterfallHook<infer T, infer E> ? AsyncSeriesWaterfallHook<T, E>['run'] : never;
30
- export declare type IPluginInstance<HM, C> = {
31
- handlers: IPluginHandlers<HM, C>;
32
- PLUGIN_SYMBOL: 'PLUGIN_SYMBOL';
33
- } & Required<PluginOptions>;
34
- export declare type IPluginHandlers<HM, C> = Partial<IPluginHandlersFullMap<HM, C>>;
35
- export declare type IPluginHandlersFullMap<HM, C> = {
36
- [K in keyof HM]: HM[K] extends SyncHook<infer T, infer E, infer R> ? PatchPluginParameter<SyncHookHandler<T, E, R>, C> : HM[K] extends SyncBailHook<infer T, infer E, infer R> ? PatchPluginParameter<SyncBailHookHandler<T, E, R>, C> : HM[K] extends SyncWaterfallHook<infer T, infer E> ? PatchPluginParameter<SyncWaterfallHookHandler<T, E>, C> : HM[K] extends AsyncParallelHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncParallelHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncSeriesHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesBailHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncSeriesBailHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesWaterfallHook<infer T, infer E> ? PatchPluginParameter<AsyncSeriesWaterfallHookHandler<T, E>, C> : never;
37
- };
38
- export declare type PluginOptions = {
39
- name?: string;
40
- pre?: string[];
41
- post?: string[];
42
- rivals?: string[];
43
- required?: string[];
44
- order?: number;
45
- group?: number;
46
- [x: string]: any;
47
- };
1
+ import { IPluginHandlers, IPluginInstance, HookManager, HookMap, PluginOptions } from './types';
48
2
  export declare const isPluginInstance: <T extends IPluginInstance<any, any> = IPluginInstance<any, any>>(plugin: any) => plugin is T;
49
3
  export declare type ArrayElements<T extends {}> = {
50
4
  [K in keyof T]: T[K][];
51
5
  };
52
6
  export declare function createPlugin<HM extends HookMap, C = void>(pluginHandlers: IPluginHandlers<HM, C>, options?: PluginOptions): IPluginInstance<HM, C>;
53
7
  export declare const createHookManager: <HM extends HookMap, C = void>(hookMap: HM, hasContext?: boolean) => HookManager<HM, C>;
54
- export declare type RemoveManagerVoidParameter<T> = T extends (initalValue: infer I, extraArg: infer E, context: infer C) => infer R ? null extends I ? null extends E ? null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends E ? null extends C ? (initialValue: I, context: C) => R : void extends C ? (initialValue: I) => R : (initialValue: I, context: C) => R : null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends I ? null extends E ? null extends C ? (extraArg: E, context: C) => R : void extends C ? (extraArg: E) => R : (extraArg: E, context: C) => R : void extends E ? null extends C ? (context: C) => R : void extends C ? () => R : (context: C) => R : null extends C ? (extraArg: E, context: C) => R : void extends C ? (extraArg: E) => R : (extraArg: E, context: C) => R : null extends E ? null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends E ? null extends C ? (initialValue: I, context: C) => R : void extends C ? (initialValue: I) => R : (initialValue: I, context: C) => R : null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : T;
package/lib/hookGroup.js CHANGED
@@ -2,13 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createHookManager = exports.createPlugin = exports.isPluginInstance = void 0;
4
4
  const hooks_1 = require("./hooks");
5
+ const utils_1 = require("./utils");
5
6
  const DEFAULT_OPTIONS = {
6
7
  name: 'untitled',
7
- pre: [],
8
- post: [],
9
- rivals: [],
8
+ before: [],
9
+ after: [],
10
+ conflict: [],
10
11
  required: [],
11
- order: 0,
12
12
  group: 0
13
13
  };
14
14
  const PLUGIN_SYMBOL = 'PLUGIN_SYMBOL';
@@ -16,70 +16,6 @@ const isPluginInstance = (plugin) => plugin &&
16
16
  plugin.hasOwnProperty(PLUGIN_SYMBOL) &&
17
17
  plugin.PLUGIN_SYMBOL === PLUGIN_SYMBOL;
18
18
  exports.isPluginInstance = isPluginInstance;
19
- const sortPlugins = (input) => {
20
- let plugins = input.slice();
21
- plugins.sort((a, b) => {
22
- // sort by group first
23
- if (a.group === b.group) {
24
- return a.order - b.order;
25
- }
26
- else {
27
- return a.group - b.group;
28
- }
29
- });
30
- for (let i = 0; i < plugins.length; i++) {
31
- let plugin = plugins[i];
32
- if (plugin.pre) {
33
- for (const pre of plugin.pre) {
34
- for (let j = i + 1; j < plugins.length; j++) {
35
- if (plugins[j].name === pre) {
36
- plugins = [
37
- ...plugins.slice(0, i),
38
- plugins[j],
39
- ...plugins.slice(i, j),
40
- ...plugins.slice(j + 1, plugins.length)
41
- ];
42
- }
43
- }
44
- }
45
- }
46
- if (plugin.post) {
47
- for (const post of plugin.post) {
48
- for (let j = 0; j < i; j++) {
49
- if (plugins[j].name === post) {
50
- plugins = [
51
- ...plugins.slice(0, j),
52
- ...plugins.slice(j + 1, i + 1),
53
- plugins[j],
54
- ...plugins.slice(i + 1, plugins.length)
55
- ];
56
- }
57
- }
58
- }
59
- }
60
- }
61
- return plugins;
62
- };
63
- const checkPlugins = (plugins) => {
64
- for (const origin of plugins) {
65
- if (origin.rivals) {
66
- for (const rival of origin.rivals) {
67
- for (const plugin of plugins) {
68
- if (rival === plugin.name) {
69
- throw new Error(`${origin.name} has rival ${plugin.name}`);
70
- }
71
- }
72
- }
73
- }
74
- if (origin.required) {
75
- for (const required of origin.required) {
76
- if (!plugins.some(plugin => plugin.name === required)) {
77
- throw new Error(`The plugin: ${required} is required when plugin: ${origin.name} is exist.`);
78
- }
79
- }
80
- }
81
- }
82
- };
83
19
  function uuid() {
84
20
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
85
21
  var r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8;
@@ -141,10 +77,9 @@ const createHookManager = (hookMap, hasContext = true) => {
141
77
  _plugins.push(...plugins);
142
78
  };
143
79
  const load = () => {
144
- let plugins = _plugins;
145
- plugins = sortPlugins(plugins);
146
- checkPlugins(plugins);
147
- plugins.forEach(plugin => {
80
+ (0, utils_1.verifyPlugins)(_plugins);
81
+ _plugins = (0, utils_1.sortPlugins)(_plugins);
82
+ _plugins.forEach(plugin => {
148
83
  const handlers = plugin.handlers;
149
84
  let hookName;
150
85
  for (hookName in handlers) {
package/lib/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './hooks';
2
2
  export * from './hookGroup';
3
+ export * from './types';
package/lib/index.js CHANGED
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./hooks"), exports);
18
18
  __exportStar(require("./hookGroup"), exports);
19
+ __exportStar(require("./types"), exports);
package/lib/types.d.ts ADDED
@@ -0,0 +1,59 @@
1
+ import { SyncHook, SyncBailHook, SyncWaterfallHook, AsyncParallelHook, AsyncSeriesWaterfallHook, SyncHookHandler, SyncBailHookHandler, SyncWaterfallHookHandler, AsyncParallelHookHandler, AsyncSeriesWaterfallHookHandler, AsyncSeriesHook, AsyncSeriesBailHook, AsyncSeriesHookHandler, AsyncSeriesBailHookHandler } from './hooks';
2
+ export declare type PatchPluginParameter<T, C> = RemoveManagerVoidParameter<AddContextParameter<T, C>>;
3
+ export declare type AddContextParameter<T, C> = T extends (initalValue: infer I, extraArg: infer E) => infer R ? (initalValue: I, extraArg: E, context: C) => R : T;
4
+ export declare type AnyHook = SyncHook<any, any, any> | SyncBailHook<any, any, any> | SyncWaterfallHook<any, any> | AsyncParallelHook<any, any, any> | AsyncSeriesHook<any, any, any> | AsyncSeriesBailHook<any, any, any> | AsyncSeriesWaterfallHook<any, any>;
5
+ export interface HookMap {
6
+ [x: string]: AnyHook;
7
+ }
8
+ export declare type Setup<HM extends HookMap = {}> = (utils: {
9
+ addHooks: (hook: Partial<HM>) => void;
10
+ }) => void;
11
+ export declare type CreatePlugin<HM extends HookMap, C> = (pluginHandlers: IPluginHandlers<HM, C> & {
12
+ setup?: Setup;
13
+ }, options?: PluginOptions) => IPluginInstance<HM, C>;
14
+ export declare type HookManager<HM extends HookMap, C> = {
15
+ createPlugin: CreatePlugin<HM, C>;
16
+ usePlugin: (...plugins: IPluginInstance<HM, C>[]) => void;
17
+ runner: RunnerType<HM>;
18
+ setContext: (context: C) => void;
19
+ clear: () => void;
20
+ addHooks: <EHM extends HookMap>(hook: Partial<EHM>) => void;
21
+ hooks: HM;
22
+ getPlugins: () => IPluginInstance<HM, C>[];
23
+ };
24
+ export declare type RunnerType<HM> = {
25
+ [K in keyof HM]: HookRunnerType<HM[K]>;
26
+ } & {
27
+ setup: Setup;
28
+ };
29
+ export declare type HookRunnerType<H> = H extends SyncHook<infer T, infer E, infer R> ? SyncHook<T, E, R>['run'] : H extends SyncBailHook<infer T, infer E, infer R> ? SyncBailHook<T, E, R>['run'] : H extends SyncWaterfallHook<infer T, infer E> ? SyncWaterfallHook<T, E>['run'] : H extends AsyncParallelHook<infer T, infer E, infer R> ? AsyncParallelHook<T, E, R>['run'] : H extends AsyncSeriesHook<infer T, infer E, infer R> ? AsyncSeriesHook<T, E, R>['run'] : H extends AsyncSeriesBailHook<infer T, infer E, infer R> ? AsyncSeriesBailHook<T, E, R>['run'] : H extends AsyncSeriesWaterfallHook<infer T, infer E> ? AsyncSeriesWaterfallHook<T, E>['run'] : never;
30
+ export declare type IPluginInstance<HM, C> = {
31
+ handlers: IPluginHandlers<HM, C>;
32
+ PLUGIN_SYMBOL: 'PLUGIN_SYMBOL';
33
+ } & Required<PluginOptions>;
34
+ export declare type IPluginHandlers<HM, C> = Partial<IPluginHandlersFullMap<HM, C>>;
35
+ export declare type IPluginHandlersFullMap<HM, C> = {
36
+ [K in keyof HM]: HM[K] extends SyncHook<infer T, infer E, infer R> ? PatchPluginParameter<SyncHookHandler<T, E, R>, C> : HM[K] extends SyncBailHook<infer T, infer E, infer R> ? PatchPluginParameter<SyncBailHookHandler<T, E, R>, C> : HM[K] extends SyncWaterfallHook<infer T, infer E> ? PatchPluginParameter<SyncWaterfallHookHandler<T, E>, C> : HM[K] extends AsyncParallelHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncParallelHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncSeriesHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesBailHook<infer T, infer E, infer R> ? PatchPluginParameter<AsyncSeriesBailHookHandler<T, E, R>, C> : HM[K] extends AsyncSeriesWaterfallHook<infer T, infer E> ? PatchPluginParameter<AsyncSeriesWaterfallHookHandler<T, E>, C> : never;
37
+ };
38
+ export declare type PluginOptions = {
39
+ name?: string;
40
+ /** current plugin should before these configured plugins.
41
+ * only works for same group
42
+ */
43
+ before?: string[];
44
+ /** current plugin should after these configured plugins.
45
+ * only works for same group.
46
+ */
47
+ after?: string[];
48
+ /** current plugin should not be used with these configured plugins */
49
+ conflict?: string[];
50
+ /** current plugin should be used with these configured plugins */
51
+ required?: string[];
52
+ /** current plugin group.
53
+ * smaller group will be executed first
54
+ * 0: default
55
+ */
56
+ group?: number;
57
+ [x: string]: any;
58
+ };
59
+ export declare type RemoveManagerVoidParameter<T> = T extends (initalValue: infer I, extraArg: infer E, context: infer C) => infer R ? null extends I ? null extends E ? null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends E ? null extends C ? (initialValue: I, context: C) => R : void extends C ? (initialValue: I) => R : (initialValue: I, context: C) => R : null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends I ? null extends E ? null extends C ? (extraArg: E, context: C) => R : void extends C ? (extraArg: E) => R : (extraArg: E, context: C) => R : void extends E ? null extends C ? (context: C) => R : void extends C ? () => R : (context: C) => R : null extends C ? (extraArg: E, context: C) => R : void extends C ? (extraArg: E) => R : (extraArg: E, context: C) => R : null extends E ? null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : void extends E ? null extends C ? (initialValue: I, context: C) => R : void extends C ? (initialValue: I) => R : (initialValue: I, context: C) => R : null extends C ? (initialValue: I, extraArg: E, context: C) => R : void extends C ? (initialValue: I, extraArg: E) => R : (initialValue: I, extraArg: E, context: C) => R : T;
package/lib/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/lib/utils.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { IPluginInstance } from './types';
2
+ export declare const sortPluginsByRelationShip: <T extends IPluginInstance<any, any>[]>(input: T) => T;
3
+ export declare const sortPlugins: <T extends IPluginInstance<any, any>[]>(input: T) => T;
4
+ export declare const verifyPlugins: (plugins: IPluginInstance<any, any>[]) => void;
package/lib/utils.js ADDED
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.verifyPlugins = exports.sortPlugins = exports.sortPluginsByRelationShip = void 0;
4
+ const sortPluginsByRelationShip = (input) => {
5
+ const plugins = new Map();
6
+ /**
7
+ * the key is the end point of the edge
8
+ * In this way, we can easily find the plugin with zero in-degree
9
+ */
10
+ const edges = new Map();
11
+ const addEdge = (start, end) => {
12
+ if (!edges.has(end)) {
13
+ edges.set(end, new Set());
14
+ }
15
+ edges.get(end).add(start);
16
+ };
17
+ // Firstly, set plugins into map
18
+ input.forEach(plugin => {
19
+ plugins.set(plugin.name, plugin);
20
+ });
21
+ input.forEach(plugin => {
22
+ if (!edges.has(plugin.name)) {
23
+ edges.set(plugin.name, new Set());
24
+ }
25
+ if (plugin.before) {
26
+ plugin.before.forEach(name => {
27
+ // If the plugin is not in the input, we will ignore it
28
+ if (plugins.has(name)) {
29
+ addEdge(plugin.name, name);
30
+ }
31
+ });
32
+ }
33
+ if (plugin.after) {
34
+ plugin.after.forEach(name => {
35
+ // If the plugin is not in the input, we will ignore it
36
+ if (plugins.has(name)) {
37
+ addEdge(name, plugin.name);
38
+ }
39
+ });
40
+ }
41
+ });
42
+ const sorted = [];
43
+ while (edges.size > 0) {
44
+ let hasZeroInDegree = false;
45
+ edges.forEach((value, key) => {
46
+ if (value.size === 0) {
47
+ hasZeroInDegree = true;
48
+ sorted.push(plugins.get(key));
49
+ edges.delete(key);
50
+ edges.forEach(v => {
51
+ v.delete(key);
52
+ });
53
+ }
54
+ });
55
+ if (!hasZeroInDegree) {
56
+ throw new Error(`Plugin circular dependency detected: ${Array.from(edges.keys()).join(', ')}. Please ensure the plugins have correct 'before' and 'after' property.`);
57
+ }
58
+ }
59
+ return sorted;
60
+ };
61
+ exports.sortPluginsByRelationShip = sortPluginsByRelationShip;
62
+ const sortPlugins = (input) => {
63
+ const groupMap = new Map();
64
+ input.forEach(plugin => {
65
+ if (!groupMap.has(plugin.group)) {
66
+ groupMap.set(plugin.group, []);
67
+ }
68
+ groupMap.get(plugin.group).push(plugin);
69
+ });
70
+ const groupNumbers = Array.from(groupMap.keys());
71
+ const sortedGroupNumbers = groupNumbers.sort((a, b) => a - b);
72
+ const sorted = [];
73
+ sortedGroupNumbers.forEach(groupNumber => {
74
+ sorted.push(...(0, exports.sortPluginsByRelationShip)(groupMap.get(groupNumber)));
75
+ });
76
+ return sorted;
77
+ };
78
+ exports.sortPlugins = sortPlugins;
79
+ const verifyPlugins = (plugins) => {
80
+ const names = new Set();
81
+ for (const current of plugins) {
82
+ if (typeof current.name !== 'string') {
83
+ throw new Error(`Plugin name must be string type.`);
84
+ }
85
+ if (!current.name) {
86
+ throw new Error(`Plugin name must be non-empty string.`);
87
+ }
88
+ if (names.has(current.name)) {
89
+ throw new Error(`Plugin name duplication detected: ${current.name}.`);
90
+ }
91
+ names.add(current.name);
92
+ if (current.conflict) {
93
+ for (const conflict of current.conflict) {
94
+ for (const plugin of plugins) {
95
+ if (conflict === plugin.name) {
96
+ throw new Error(`Plugin conflict detected: ${current.name} has conflict with ${plugin.name}.`);
97
+ }
98
+ }
99
+ }
100
+ }
101
+ if (current.required) {
102
+ for (const required of current.required) {
103
+ if (!plugins.some(plugin => plugin.name === required)) {
104
+ throw new Error(`Plugin missing detected: ${required} is required by ${current.name}.`);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ };
110
+ exports.verifyPlugins = verifyPlugins;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shuvi/hook",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "license": "MIT",
5
5
  "main": "lib/index.js",
6
6
  "module": "esm/index.js",