@bluelibs/runner 1.5.4 → 2.1.0
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 +299 -156
- package/dist/define.d.ts +1 -1
- package/dist/define.js +6 -1
- package/dist/define.js.map +1 -1
- package/dist/defs.d.ts +14 -8
- package/dist/defs.js +3 -1
- package/dist/defs.js.map +1 -1
- package/dist/globalEvents.js +45 -0
- package/dist/globalEvents.js.map +1 -1
- package/dist/globalResources.js +19 -0
- package/dist/globalResources.js.map +1 -1
- package/dist/models/DependencyProcessor.d.ts +1 -7
- package/dist/models/DependencyProcessor.js +31 -54
- package/dist/models/DependencyProcessor.js.map +1 -1
- package/dist/models/EventManager.d.ts +4 -0
- package/dist/models/EventManager.js.map +1 -1
- package/dist/models/ResourceInitializer.js +4 -2
- package/dist/models/ResourceInitializer.js.map +1 -1
- package/dist/models/Store.d.ts +2 -2
- package/dist/models/Store.js.map +1 -1
- package/dist/models/TaskRunner.js +28 -16
- package/dist/models/TaskRunner.js.map +1 -1
- package/dist/run.js +1 -1
- package/dist/run.js.map +1 -1
- package/dist/tools/getCallerFile.d.ts +1 -0
- package/dist/tools/getCallerFile.js +30 -0
- package/dist/tools/getCallerFile.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/benchmark/benchmark.test.ts +9 -7
- package/src/__tests__/errors.test.ts +0 -13
- package/src/__tests__/globalEvents.test.ts +53 -28
- package/src/__tests__/index.ts +1 -1
- package/src/__tests__/models/EventManager.test.ts +1 -0
- package/src/__tests__/run.test.ts +140 -109
- package/src/__tests__/tools/getCallerFile.test.ts +51 -0
- package/src/__tests__/typesafety.test.ts +17 -16
- package/src/define.ts +10 -4
- package/src/defs.ts +38 -22
- package/src/globalEvents.ts +53 -0
- package/src/globalResources.ts +23 -0
- package/src/models/DependencyProcessor.ts +45 -80
- package/src/models/EventManager.ts +4 -0
- package/src/models/ResourceInitializer.ts +4 -2
- package/src/models/Store.ts +3 -2
- package/src/models/TaskRunner.ts +51 -28
- package/src/run.ts +1 -1
- package/src/tools/getCallerFile.ts +33 -0
- package/dist/DependencyProcessor.d.ts +0 -49
- package/dist/DependencyProcessor.js +0 -178
- package/dist/DependencyProcessor.js.map +0 -1
- package/dist/EventManager.d.ts +0 -17
- package/dist/EventManager.js +0 -73
- package/dist/EventManager.js.map +0 -1
- package/dist/ResourceInitializer.d.ts +0 -13
- package/dist/ResourceInitializer.js +0 -54
- package/dist/ResourceInitializer.js.map +0 -1
- package/dist/Store.d.ts +0 -90
- package/dist/Store.js +0 -291
- package/dist/Store.js.map +0 -1
- package/dist/TaskRunner.d.ts +0 -25
- package/dist/TaskRunner.js +0 -96
- package/dist/TaskRunner.js.map +0 -1
- package/src/__tests__/run.hooks.test.ts +0 -110
package/src/define.ts
CHANGED
|
@@ -16,17 +16,21 @@ import {
|
|
|
16
16
|
symbolEvent,
|
|
17
17
|
} from "./defs";
|
|
18
18
|
import { Errors } from "./errors";
|
|
19
|
+
import { getCallerFile } from "./tools/getCallerFile";
|
|
20
|
+
|
|
21
|
+
// Helper function to get the caller file
|
|
19
22
|
|
|
20
23
|
export function defineTask<
|
|
21
24
|
Input = undefined,
|
|
22
25
|
Output extends Promise<any> = any,
|
|
23
26
|
Deps extends DependencyMapType = any,
|
|
24
|
-
|
|
27
|
+
TOn extends "*" | IEventDefinition | undefined = undefined
|
|
25
28
|
>(
|
|
26
|
-
taskConfig: ITaskDefinition<Input, Output, Deps,
|
|
27
|
-
): ITask<Input, Output, Deps,
|
|
29
|
+
taskConfig: ITaskDefinition<Input, Output, Deps, TOn>
|
|
30
|
+
): ITask<Input, Output, Deps, TOn> {
|
|
28
31
|
return {
|
|
29
32
|
[symbols.task]: true,
|
|
33
|
+
[symbols.filePath]: getCallerFile(),
|
|
30
34
|
id: taskConfig.id,
|
|
31
35
|
dependencies: taskConfig.dependencies || ({} as Deps),
|
|
32
36
|
middleware: taskConfig.middleware || [],
|
|
@@ -58,9 +62,9 @@ export function defineResource<
|
|
|
58
62
|
): IResource<TConfig, TValue, TDeps> {
|
|
59
63
|
return {
|
|
60
64
|
[symbols.resource]: true,
|
|
65
|
+
[symbols.filePath]: getCallerFile(),
|
|
61
66
|
id: constConfig.id,
|
|
62
67
|
dependencies: constConfig.dependencies,
|
|
63
|
-
hooks: constConfig.hooks || [],
|
|
64
68
|
dispose: constConfig.dispose,
|
|
65
69
|
register: constConfig.register || [],
|
|
66
70
|
overrides: constConfig.overrides || [],
|
|
@@ -94,6 +98,7 @@ export function defineEvent<TPayload = any>(
|
|
|
94
98
|
config: IEventDefinitionConfig<TPayload>
|
|
95
99
|
): IEventDefinition<TPayload> {
|
|
96
100
|
return {
|
|
101
|
+
[symbols.filePath]: getCallerFile(),
|
|
97
102
|
[symbolEvent]: true,
|
|
98
103
|
...config,
|
|
99
104
|
};
|
|
@@ -103,6 +108,7 @@ export function defineMiddleware<TDeps extends DependencyMapType = {}>(
|
|
|
103
108
|
config: IMiddlewareDefinition<TDeps>
|
|
104
109
|
): IMiddleware<TDeps> {
|
|
105
110
|
const object = {
|
|
111
|
+
[symbols.filePath]: getCallerFile(),
|
|
106
112
|
[symbols.middleware]: true,
|
|
107
113
|
...config,
|
|
108
114
|
dependencies: config.dependencies || ({} as TDeps),
|
package/src/defs.ts
CHANGED
|
@@ -9,6 +9,8 @@ export const symbolMiddlewareGlobal: unique symbol = Symbol(
|
|
|
9
9
|
"runner.middlewareGlobal"
|
|
10
10
|
);
|
|
11
11
|
|
|
12
|
+
export const symbolFilePath: unique symbol = Symbol("runner.filePath");
|
|
13
|
+
|
|
12
14
|
export const symbols = {
|
|
13
15
|
task: symbolTask,
|
|
14
16
|
resource: symbolResource,
|
|
@@ -16,6 +18,7 @@ export const symbols = {
|
|
|
16
18
|
event: symbolEvent,
|
|
17
19
|
middleware: symbolMiddleware,
|
|
18
20
|
middlewareGlobal: symbolMiddlewareGlobal,
|
|
21
|
+
filePath: symbolFilePath,
|
|
19
22
|
};
|
|
20
23
|
|
|
21
24
|
export interface IMeta {
|
|
@@ -32,7 +35,7 @@ export interface IMiddlewareMeta extends IMeta {}
|
|
|
32
35
|
// DependencyMap types
|
|
33
36
|
export type DependencyMapType = Record<
|
|
34
37
|
string,
|
|
35
|
-
ITask<any, any, any> | IResource<any, any, any> | IEventDefinition<any>
|
|
38
|
+
ITask<any, any, any, any> | IResource<any, any, any> | IEventDefinition<any>
|
|
36
39
|
>;
|
|
37
40
|
|
|
38
41
|
// Helper Types for Extracting Generics
|
|
@@ -61,19 +64,39 @@ export type DependencyValuesType<T extends DependencyMapType> = {
|
|
|
61
64
|
[K in keyof T]: DependencyValueType<T[K]>;
|
|
62
65
|
};
|
|
63
66
|
|
|
67
|
+
type Optional<T> = {
|
|
68
|
+
[K in keyof T]?: T[K];
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Utility type to check if a type is void
|
|
72
|
+
type IsVoid<T> = [T] extends [void] ? true : false;
|
|
73
|
+
|
|
74
|
+
// Utility type to check if a type is optional (can be undefined)
|
|
75
|
+
type IsOptional<T> = undefined extends T ? true : false;
|
|
76
|
+
|
|
77
|
+
// IReso
|
|
78
|
+
|
|
79
|
+
// Conditional type to allow `void`, optional, or any type
|
|
80
|
+
type OptionalOrVoidOrAnything<T> = IsVoid<T> extends true
|
|
81
|
+
? void
|
|
82
|
+
: IsOptional<T> extends true
|
|
83
|
+
? Optional<T>
|
|
84
|
+
: T;
|
|
85
|
+
|
|
64
86
|
// RegisterableItems Type with Conditional Inclusion
|
|
65
|
-
export type RegisterableItems =
|
|
87
|
+
export type RegisterableItems<T = any> =
|
|
66
88
|
| IResourceWithConfig<any>
|
|
67
89
|
| IResource<void, any, any>
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
90
|
+
| IResource<OptionalOrVoidOrAnything<T>, any, any>
|
|
91
|
+
| ITaskDefinition<any, any, any, any>
|
|
92
|
+
| IMiddlewareDefinition<any>
|
|
93
|
+
| IEventDefinition<any>;
|
|
71
94
|
|
|
72
95
|
export interface ITaskDefinition<
|
|
73
96
|
TInput = any,
|
|
74
97
|
TOutput extends Promise<any> = any,
|
|
75
98
|
TDependencies extends DependencyMapType = {},
|
|
76
|
-
|
|
99
|
+
TOn extends "*" | IEventDefinition<any> | undefined = undefined // Adding a generic to track 'on' type
|
|
77
100
|
> {
|
|
78
101
|
id: string;
|
|
79
102
|
dependencies?: TDependencies | (() => TDependencies);
|
|
@@ -81,7 +104,7 @@ export interface ITaskDefinition<
|
|
|
81
104
|
/**
|
|
82
105
|
* Listen to events in a simple way
|
|
83
106
|
*/
|
|
84
|
-
on?:
|
|
107
|
+
on?: TOn;
|
|
85
108
|
/**
|
|
86
109
|
* This makes sense only when `on` is specified to provide the order of the execution.
|
|
87
110
|
* The event with the lowest order will be executed first.
|
|
@@ -89,7 +112,12 @@ export interface ITaskDefinition<
|
|
|
89
112
|
listenerOrder?: number;
|
|
90
113
|
meta?: ITaskMeta;
|
|
91
114
|
run: (
|
|
92
|
-
input:
|
|
115
|
+
input: TOn extends undefined ? TInput : IEvent<ExtractEventParams<TOn>>,
|
|
116
|
+
// input: TOn extends "*"
|
|
117
|
+
// ? IEvent<any>
|
|
118
|
+
// : TEventDefinitionInput extends null | void
|
|
119
|
+
// ? TInput
|
|
120
|
+
// : IEvent<TEventDefinitionInput>,
|
|
93
121
|
dependencies: DependencyValuesType<TDependencies>
|
|
94
122
|
) => TOutput;
|
|
95
123
|
}
|
|
@@ -127,13 +155,8 @@ export interface ITask<
|
|
|
127
155
|
TInput = any,
|
|
128
156
|
TOutput extends Promise<any> = any,
|
|
129
157
|
TDependencies extends DependencyMapType = {},
|
|
130
|
-
|
|
131
|
-
> extends ITaskDefinition<
|
|
132
|
-
TInput,
|
|
133
|
-
TOutput,
|
|
134
|
-
TDependencies,
|
|
135
|
-
TEventDefinitionInput
|
|
136
|
-
> {
|
|
158
|
+
TOn extends "*" | IEventDefinition<any> | undefined = undefined
|
|
159
|
+
> extends ITaskDefinition<TInput, TOutput, TDependencies, TOn> {
|
|
137
160
|
dependencies: TDependencies | (() => TDependencies);
|
|
138
161
|
computedDependencies?: DependencyValuesType<TDependencies>;
|
|
139
162
|
middleware: IMiddlewareDefinition[];
|
|
@@ -156,9 +179,6 @@ export interface IResourceDefinition<
|
|
|
156
179
|
> {
|
|
157
180
|
id: string;
|
|
158
181
|
dependencies?: TDependencies | ((config: TConfig) => TDependencies);
|
|
159
|
-
hooks?:
|
|
160
|
-
| IHookDefinition<TDependencies, THooks>[]
|
|
161
|
-
| ((config: TConfig) => IHookDefinition<TDependencies, THooks>[]);
|
|
162
182
|
register?:
|
|
163
183
|
| Array<RegisterableItems>
|
|
164
184
|
| ((config: TConfig) => Array<RegisterableItems>);
|
|
@@ -201,10 +221,6 @@ export interface IResource<
|
|
|
201
221
|
afterInit: IEventDefinition<AfterInitEventPayload<TConfig, TValue>>;
|
|
202
222
|
onError: IEventDefinition<OnErrorEventPayload>;
|
|
203
223
|
};
|
|
204
|
-
hooks:
|
|
205
|
-
| IHookDefinition<TDependencies>[]
|
|
206
|
-
| ((config: TConfig) => IHookDefinition<TDependencies>[]);
|
|
207
|
-
|
|
208
224
|
overrides: Array<IResource | ITask | IMiddleware | IResourceWithConfig>;
|
|
209
225
|
middleware: IMiddlewareDefinition[];
|
|
210
226
|
}
|
package/src/globalEvents.ts
CHANGED
|
@@ -5,12 +5,29 @@ import { ILog } from "./models/Logger";
|
|
|
5
5
|
export const globalEvents = {
|
|
6
6
|
beforeInit: defineEvent({
|
|
7
7
|
id: "global.beforeInit",
|
|
8
|
+
meta: {
|
|
9
|
+
title: "Before Initialization",
|
|
10
|
+
description:
|
|
11
|
+
"Triggered before any resource or system-wide initialization occurs.",
|
|
12
|
+
tags: ["system"],
|
|
13
|
+
},
|
|
8
14
|
}),
|
|
9
15
|
afterInit: defineEvent({
|
|
10
16
|
id: "global.afterInit",
|
|
17
|
+
meta: {
|
|
18
|
+
title: "After Initialization",
|
|
19
|
+
description:
|
|
20
|
+
"Fired after the system or resource initialization is completed.",
|
|
21
|
+
tags: ["system"],
|
|
22
|
+
},
|
|
11
23
|
}),
|
|
12
24
|
log: defineEvent<ILog>({
|
|
13
25
|
id: "global.log",
|
|
26
|
+
meta: {
|
|
27
|
+
title: "Log Event",
|
|
28
|
+
description: "Used to log events and messages across the system.",
|
|
29
|
+
tags: ["system"],
|
|
30
|
+
},
|
|
14
31
|
}),
|
|
15
32
|
tasks: {
|
|
16
33
|
beforeRun: defineEvent<{
|
|
@@ -18,6 +35,12 @@ export const globalEvents = {
|
|
|
18
35
|
input: any;
|
|
19
36
|
}>({
|
|
20
37
|
id: "global.tasks.beforeRun",
|
|
38
|
+
meta: {
|
|
39
|
+
title: "Before Task Execution",
|
|
40
|
+
description:
|
|
41
|
+
"Triggered before a task starts running, providing access to the input data.",
|
|
42
|
+
tags: ["system"],
|
|
43
|
+
},
|
|
21
44
|
}),
|
|
22
45
|
afterRun: defineEvent<{
|
|
23
46
|
task: ITask<any, any, any>;
|
|
@@ -25,6 +48,12 @@ export const globalEvents = {
|
|
|
25
48
|
output: any;
|
|
26
49
|
}>({
|
|
27
50
|
id: "global.tasks.afterRun",
|
|
51
|
+
meta: {
|
|
52
|
+
title: "After Task Execution",
|
|
53
|
+
description:
|
|
54
|
+
"Fired after a task has completed, providing both the input and output data.",
|
|
55
|
+
tags: ["system"],
|
|
56
|
+
},
|
|
28
57
|
}),
|
|
29
58
|
onError: defineEvent<{
|
|
30
59
|
error: any;
|
|
@@ -32,6 +61,12 @@ export const globalEvents = {
|
|
|
32
61
|
task: ITask<any, any, any>;
|
|
33
62
|
}>({
|
|
34
63
|
id: "global.tasks.onError",
|
|
64
|
+
meta: {
|
|
65
|
+
title: "Task Error",
|
|
66
|
+
description:
|
|
67
|
+
"Triggered when an error occurs during task execution. Allows error suppression.",
|
|
68
|
+
tags: ["system"],
|
|
69
|
+
},
|
|
35
70
|
}),
|
|
36
71
|
},
|
|
37
72
|
resources: {
|
|
@@ -40,6 +75,12 @@ export const globalEvents = {
|
|
|
40
75
|
config: any;
|
|
41
76
|
}>({
|
|
42
77
|
id: "global.resources.beforeInit",
|
|
78
|
+
meta: {
|
|
79
|
+
title: "Before Resource Initialization",
|
|
80
|
+
description:
|
|
81
|
+
"Fired before a resource is initialized, with access to the configuration.",
|
|
82
|
+
tags: ["system"],
|
|
83
|
+
},
|
|
43
84
|
}),
|
|
44
85
|
afterInit: defineEvent<{
|
|
45
86
|
resource: IResource<any, any, any>;
|
|
@@ -47,6 +88,12 @@ export const globalEvents = {
|
|
|
47
88
|
value: any;
|
|
48
89
|
}>({
|
|
49
90
|
id: "global.resources.afterInit",
|
|
91
|
+
meta: {
|
|
92
|
+
title: "After Resource Initialization",
|
|
93
|
+
description:
|
|
94
|
+
"Fired after a resource has been initialized, providing the final value.",
|
|
95
|
+
tags: ["system"],
|
|
96
|
+
},
|
|
50
97
|
}),
|
|
51
98
|
onError: defineEvent<{
|
|
52
99
|
error: Error;
|
|
@@ -54,6 +101,12 @@ export const globalEvents = {
|
|
|
54
101
|
resource: IResource<any, any, any>;
|
|
55
102
|
}>({
|
|
56
103
|
id: "global.resources.onError",
|
|
104
|
+
meta: {
|
|
105
|
+
title: "Resource Error",
|
|
106
|
+
description:
|
|
107
|
+
"Triggered when an error occurs during resource initialization. Allows error suppression.",
|
|
108
|
+
tags: ["system"],
|
|
109
|
+
},
|
|
57
110
|
}),
|
|
58
111
|
},
|
|
59
112
|
};
|
package/src/globalResources.ts
CHANGED
|
@@ -7,6 +7,12 @@ import { TaskRunner } from "./models/TaskRunner";
|
|
|
7
7
|
const store = defineResource({
|
|
8
8
|
id: "global.store",
|
|
9
9
|
init: async (store: Store) => store,
|
|
10
|
+
meta: {
|
|
11
|
+
title: "Store",
|
|
12
|
+
description:
|
|
13
|
+
"A global store that can be used to store and retrieve tasks, resources, events and middleware",
|
|
14
|
+
tags: ["internal"],
|
|
15
|
+
},
|
|
10
16
|
});
|
|
11
17
|
|
|
12
18
|
export const globalResources = {
|
|
@@ -14,13 +20,30 @@ export const globalResources = {
|
|
|
14
20
|
eventManager: defineResource({
|
|
15
21
|
id: "global.eventManager",
|
|
16
22
|
init: async (em: EventManager) => em,
|
|
23
|
+
meta: {
|
|
24
|
+
title: "Event Manager",
|
|
25
|
+
description:
|
|
26
|
+
"Manages all events and event listeners. This is meant to be used internally for most use-cases.",
|
|
27
|
+
tags: ["internal"],
|
|
28
|
+
},
|
|
17
29
|
}),
|
|
18
30
|
taskRunner: defineResource({
|
|
19
31
|
id: "global.taskRunner",
|
|
20
32
|
init: async (runner: TaskRunner) => runner,
|
|
33
|
+
meta: {
|
|
34
|
+
title: "Task Runner",
|
|
35
|
+
description:
|
|
36
|
+
"Manages the execution of tasks and task dependencies. This is meant to be used internally for most use-cases.",
|
|
37
|
+
tags: ["internal"],
|
|
38
|
+
},
|
|
21
39
|
}),
|
|
22
40
|
logger: defineResource({
|
|
23
41
|
id: "global.logger",
|
|
24
42
|
init: async (logger: Logger) => logger,
|
|
43
|
+
meta: {
|
|
44
|
+
title: "Logger",
|
|
45
|
+
description:
|
|
46
|
+
"Logs all events and errors. This is meant to be used internally for most use-cases. Emits a global.log event for each log.",
|
|
47
|
+
},
|
|
25
48
|
}),
|
|
26
49
|
};
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
IResource,
|
|
6
6
|
IHookDefinition,
|
|
7
7
|
IEventDefinition,
|
|
8
|
+
IEvent,
|
|
8
9
|
} from "../defs";
|
|
9
10
|
import { ResourceStoreElementType, Store, TaskStoreElementType } from "./Store";
|
|
10
11
|
import * as utils from "../define";
|
|
@@ -68,32 +69,6 @@ export class DependencyProcessor {
|
|
|
68
69
|
deps,
|
|
69
70
|
task.task.id
|
|
70
71
|
);
|
|
71
|
-
|
|
72
|
-
let eventDefinition = task.task.on;
|
|
73
|
-
if (eventDefinition) {
|
|
74
|
-
if (this.store.events.get(eventDefinition.id) === undefined) {
|
|
75
|
-
throw Errors.eventNotFound(eventDefinition.id);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
this.eventManager.addListener(
|
|
79
|
-
eventDefinition,
|
|
80
|
-
async (receivedEvent) => {
|
|
81
|
-
this.logger.debug({
|
|
82
|
-
message: `Task ${task.task.id} listened to event: ${eventDefinition.id}`,
|
|
83
|
-
event: receivedEvent,
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
return this.taskRunner.run(
|
|
87
|
-
task.task,
|
|
88
|
-
receivedEvent,
|
|
89
|
-
task.computedDependencies
|
|
90
|
-
);
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
order: task.task.listenerOrder || 0,
|
|
94
|
-
}
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
72
|
}
|
|
98
73
|
|
|
99
74
|
// Most likely these are resources that no-one has dependencies towards
|
|
@@ -145,62 +120,49 @@ export class DependencyProcessor {
|
|
|
145
120
|
/**
|
|
146
121
|
* Processes all hooks, should run before emission of any event.
|
|
147
122
|
*/
|
|
148
|
-
public
|
|
149
|
-
for (const
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
123
|
+
public attachListeners() {
|
|
124
|
+
for (const task of this.store.tasks.values()) {
|
|
125
|
+
if (task.task.on) {
|
|
126
|
+
let eventDefinition = task.task.on;
|
|
127
|
+
|
|
128
|
+
const handler = async (receivedEvent: IEvent<any>) => {
|
|
129
|
+
if (receivedEvent.source === task.task.id) {
|
|
130
|
+
// we don't want to trigger the same task that emitted the event
|
|
131
|
+
// process.exit(0);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
155
134
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
resourceStoreElement: ResourceStoreElementType<any, any, {}>
|
|
163
|
-
) {
|
|
164
|
-
let hooks = resourceStoreElement.resource.hooks;
|
|
165
|
-
if (typeof hooks === "function") {
|
|
166
|
-
hooks = hooks(resourceStoreElement.config);
|
|
167
|
-
}
|
|
135
|
+
this.logger.debug(
|
|
136
|
+
{
|
|
137
|
+
message:
|
|
138
|
+
eventDefinition === "*"
|
|
139
|
+
? `Task ${task.task.id} being triggered by all events`
|
|
140
|
+
: `Task ${task.task.id} being triggered by event: ${eventDefinition.id}`,
|
|
168
141
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
142
|
+
event: receivedEvent,
|
|
143
|
+
},
|
|
144
|
+
task.task.id
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
return this.taskRunner.run(
|
|
148
|
+
task.task,
|
|
149
|
+
receivedEvent,
|
|
150
|
+
task.computedDependencies
|
|
151
|
+
);
|
|
152
|
+
};
|
|
172
153
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
receivedEvent,
|
|
181
|
-
resourceStoreElement.computedDependencies as DependencyValuesType<{}>
|
|
182
|
-
);
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
order,
|
|
154
|
+
if (eventDefinition === "*") {
|
|
155
|
+
this.eventManager.addGlobalListener(handler, {
|
|
156
|
+
order: task.task.listenerOrder || 0,
|
|
157
|
+
});
|
|
158
|
+
} else {
|
|
159
|
+
if (this.store.events.get(eventDefinition.id) === undefined) {
|
|
160
|
+
throw Errors.eventNotFound(eventDefinition.id);
|
|
186
161
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
throw Errors.eventNotFound(event.id);
|
|
162
|
+
this.eventManager.addListener(eventDefinition, handler, {
|
|
163
|
+
order: task.task.listenerOrder || 0,
|
|
164
|
+
});
|
|
191
165
|
}
|
|
192
|
-
this.eventManager.addListener(
|
|
193
|
-
event,
|
|
194
|
-
async (receivedEvent) => {
|
|
195
|
-
return hook.run(
|
|
196
|
-
receivedEvent,
|
|
197
|
-
resourceStoreElement.computedDependencies as DependencyValuesType<{}>
|
|
198
|
-
);
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
order,
|
|
202
|
-
}
|
|
203
|
-
);
|
|
204
166
|
}
|
|
205
167
|
}
|
|
206
168
|
}
|
|
@@ -241,9 +203,12 @@ export class DependencyProcessor {
|
|
|
241
203
|
) {
|
|
242
204
|
return async (input) => {
|
|
243
205
|
// runs it in background.
|
|
244
|
-
this.logger.debug(
|
|
245
|
-
|
|
246
|
-
|
|
206
|
+
this.logger.debug(
|
|
207
|
+
{
|
|
208
|
+
message: `Event ${object.id} was emitted from ${source}`,
|
|
209
|
+
},
|
|
210
|
+
source
|
|
211
|
+
);
|
|
247
212
|
|
|
248
213
|
return this.eventManager.emit(object, input, source);
|
|
249
214
|
};
|
|
@@ -13,6 +13,10 @@ interface IListenerStorage {
|
|
|
13
13
|
export interface IEventHandlerOptions<T = any> {
|
|
14
14
|
order?: number;
|
|
15
15
|
filter?: (event: IEvent<T>) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Represents the listener ID. Use this to avoid a listener calling himself.
|
|
18
|
+
*/
|
|
19
|
+
id?: string;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
export class EventManager {
|
|
@@ -68,13 +68,15 @@ export class ResourceInitializer {
|
|
|
68
68
|
resource.id
|
|
69
69
|
);
|
|
70
70
|
|
|
71
|
-
this.logger.debug(`Resource ${resource.id} initialized
|
|
71
|
+
this.logger.debug(`Resource ${resource.id} initialized`, resource.id);
|
|
72
72
|
|
|
73
73
|
return value;
|
|
74
74
|
} catch (e) {
|
|
75
75
|
error = e;
|
|
76
76
|
let isSuppressed = false;
|
|
77
|
-
|
|
77
|
+
function suppress() {
|
|
78
|
+
isSuppressed = true;
|
|
79
|
+
}
|
|
78
80
|
|
|
79
81
|
// If you want to rewthrow the error, this should be done inside the onError event.
|
|
80
82
|
await this.eventManager.emit(
|
package/src/models/Store.ts
CHANGED
|
@@ -34,9 +34,10 @@ export type ResourceStoreElementType<
|
|
|
34
34
|
export type TaskStoreElementType<
|
|
35
35
|
Input = any,
|
|
36
36
|
Output extends Promise<any> = any,
|
|
37
|
-
D extends DependencyMapType = any
|
|
37
|
+
D extends DependencyMapType = any,
|
|
38
|
+
TOn extends "*" | IEventDefinition | undefined = any
|
|
38
39
|
> = {
|
|
39
|
-
task: ITask<Input, Output, D>;
|
|
40
|
+
task: ITask<Input, Output, D, TOn>;
|
|
40
41
|
computedDependencies: DependencyValuesType<D>;
|
|
41
42
|
isInitialized: boolean;
|
|
42
43
|
};
|
package/src/models/TaskRunner.ts
CHANGED
|
@@ -50,43 +50,63 @@ export class TaskRunner {
|
|
|
50
50
|
this.runnerStore.set(task.id, runner);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
// then ensure the hooks are called
|
|
55
|
-
// then ensure the middleware are called
|
|
56
|
-
await this.eventManager.emit(task.events.beforeRun, { input }, task.id);
|
|
57
|
-
await this.eventManager.emit(
|
|
58
|
-
globalEvents.tasks.beforeRun,
|
|
59
|
-
{
|
|
60
|
-
task,
|
|
61
|
-
input,
|
|
62
|
-
},
|
|
63
|
-
task.id
|
|
64
|
-
);
|
|
53
|
+
const isGlobalEventListener = task.on === "*";
|
|
65
54
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const output = await runner(input);
|
|
55
|
+
if (!isGlobalEventListener) {
|
|
56
|
+
await this.eventManager.emit(task.events.beforeRun, { input }, task.id);
|
|
57
|
+
}
|
|
70
58
|
|
|
59
|
+
if (
|
|
60
|
+
!isGlobalEventListener &&
|
|
61
|
+
task.on !== globalEvents.tasks.beforeRun &&
|
|
62
|
+
task.on !== globalEvents.tasks.afterRun
|
|
63
|
+
) {
|
|
71
64
|
await this.eventManager.emit(
|
|
72
|
-
|
|
73
|
-
{ input, output },
|
|
74
|
-
task.id
|
|
75
|
-
);
|
|
76
|
-
await this.eventManager.emit(
|
|
77
|
-
globalEvents.tasks.afterRun,
|
|
65
|
+
globalEvents.tasks.beforeRun,
|
|
78
66
|
{
|
|
79
67
|
task,
|
|
80
68
|
input,
|
|
81
|
-
output,
|
|
82
69
|
},
|
|
83
70
|
task.id
|
|
84
71
|
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let error;
|
|
75
|
+
try {
|
|
76
|
+
// craft the next function starting from the first next function
|
|
77
|
+
const output = await runner(input);
|
|
78
|
+
|
|
79
|
+
if (!isGlobalEventListener) {
|
|
80
|
+
await this.eventManager.emit(
|
|
81
|
+
task.events.afterRun,
|
|
82
|
+
{ input, output },
|
|
83
|
+
task.id
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
!isGlobalEventListener &&
|
|
89
|
+
task.on !== globalEvents.tasks.beforeRun &&
|
|
90
|
+
task.on !== globalEvents.tasks.afterRun
|
|
91
|
+
) {
|
|
92
|
+
await this.eventManager.emit(
|
|
93
|
+
globalEvents.tasks.afterRun,
|
|
94
|
+
{
|
|
95
|
+
task,
|
|
96
|
+
input,
|
|
97
|
+
output,
|
|
98
|
+
},
|
|
99
|
+
task.id
|
|
100
|
+
);
|
|
101
|
+
}
|
|
85
102
|
|
|
86
103
|
return output;
|
|
87
104
|
} catch (e) {
|
|
88
105
|
let isSuppressed = false;
|
|
89
|
-
|
|
106
|
+
function suppress() {
|
|
107
|
+
isSuppressed = true;
|
|
108
|
+
}
|
|
109
|
+
|
|
90
110
|
error = e;
|
|
91
111
|
|
|
92
112
|
// If you want to rewthrow the error, this should be done inside the onError event.
|
|
@@ -126,10 +146,13 @@ export class TaskRunner {
|
|
|
126
146
|
) {
|
|
127
147
|
// this is the final next()
|
|
128
148
|
let next = async (input) => {
|
|
129
|
-
this.logger.debug(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
149
|
+
this.logger.debug(
|
|
150
|
+
{
|
|
151
|
+
message: `Running task ${task.id}`,
|
|
152
|
+
input,
|
|
153
|
+
},
|
|
154
|
+
task.id
|
|
155
|
+
);
|
|
133
156
|
|
|
134
157
|
return task.run.call(null, input, taskDependencies as any);
|
|
135
158
|
};
|
package/src/run.ts
CHANGED
|
@@ -87,7 +87,7 @@ export async function run<C, V>(
|
|
|
87
87
|
|
|
88
88
|
// a form of hooking, we create the events for all tasks and store them so they can be referenced
|
|
89
89
|
await store.storeEventsForAllTasks();
|
|
90
|
-
await processor.
|
|
90
|
+
await processor.attachListeners();
|
|
91
91
|
await processor.computeAllDependencies();
|
|
92
92
|
|
|
93
93
|
// After this stage, logger print policy could have been set.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function getCallerFile(): string | undefined {
|
|
2
|
+
const originalFunc = Error.prepareStackTrace;
|
|
3
|
+
|
|
4
|
+
try {
|
|
5
|
+
const err = new Error();
|
|
6
|
+
let callerfile;
|
|
7
|
+
let currentfile;
|
|
8
|
+
|
|
9
|
+
// Safeguard prepareStackTrace
|
|
10
|
+
Error.prepareStackTrace = (err, stack) => stack;
|
|
11
|
+
|
|
12
|
+
const stack = err.stack as unknown as NodeJS.CallSite[];
|
|
13
|
+
|
|
14
|
+
// Don't know how to test this.
|
|
15
|
+
// if (stack.length < 3) {
|
|
16
|
+
// // We need at least 3 frames: current function, its caller, and one above
|
|
17
|
+
// return undefined;
|
|
18
|
+
// }
|
|
19
|
+
|
|
20
|
+
// Remove the first frame (getCallerFile itself)
|
|
21
|
+
stack.shift();
|
|
22
|
+
|
|
23
|
+
// Remove the second frame (the direct caller of getCallerFile)
|
|
24
|
+
currentfile = stack.shift()?.getFileName();
|
|
25
|
+
|
|
26
|
+
// The third frame (the caller above the immediate one)
|
|
27
|
+
callerfile = stack.shift()?.getFileName();
|
|
28
|
+
|
|
29
|
+
return callerfile; // Return the file name of the caller above
|
|
30
|
+
} finally {
|
|
31
|
+
Error.prepareStackTrace = originalFunc;
|
|
32
|
+
}
|
|
33
|
+
}
|