@bluelibs/runner 1.0.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/LICENSE.md +7 -0
- package/README.md +797 -0
- package/dist/DependencyProcessor.d.ts +49 -0
- package/dist/DependencyProcessor.js +178 -0
- package/dist/DependencyProcessor.js.map +1 -0
- package/dist/EventManager.d.ts +13 -0
- package/dist/EventManager.js +58 -0
- package/dist/EventManager.js.map +1 -0
- package/dist/ResourceInitializer.d.ts +13 -0
- package/dist/ResourceInitializer.js +54 -0
- package/dist/ResourceInitializer.js.map +1 -0
- package/dist/Store.d.ts +62 -0
- package/dist/Store.js +186 -0
- package/dist/Store.js.map +1 -0
- package/dist/TaskRunner.d.ts +22 -0
- package/dist/TaskRunner.js +93 -0
- package/dist/TaskRunner.js.map +1 -0
- package/dist/define.d.ts +10 -0
- package/dist/define.js +111 -0
- package/dist/define.js.map +1 -0
- package/dist/defs.d.ts +127 -0
- package/dist/defs.js +12 -0
- package/dist/defs.js.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +12 -0
- package/dist/errors.js.map +1 -0
- package/dist/globalEvents.d.ts +36 -0
- package/dist/globalEvents.js +45 -0
- package/dist/globalEvents.js.map +1 -0
- package/dist/globalResources.d.ts +8 -0
- package/dist/globalResources.js +19 -0
- package/dist/globalResources.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/run.d.ts +32 -0
- package/dist/run.js +39 -0
- package/dist/run.js.map +1 -0
- package/dist/tools/findCircularDependencies.d.ts +16 -0
- package/dist/tools/findCircularDependencies.js +53 -0
- package/dist/tools/findCircularDependencies.js.map +1 -0
- package/package.json +50 -0
- package/src/DependencyProcessor.ts +243 -0
- package/src/EventManager.ts +84 -0
- package/src/ResourceInitializer.ts +69 -0
- package/src/Store.ts +250 -0
- package/src/TaskRunner.ts +135 -0
- package/src/__tests__/EventManager.test.ts +96 -0
- package/src/__tests__/ResourceInitializer.test.ts +109 -0
- package/src/__tests__/Store.test.ts +143 -0
- package/src/__tests__/TaskRunner.test.ts +135 -0
- package/src/__tests__/benchmark/benchmark.test.ts +146 -0
- package/src/__tests__/errors.test.ts +268 -0
- package/src/__tests__/globalEvents.test.ts +99 -0
- package/src/__tests__/index.ts +9 -0
- package/src/__tests__/run.hooks.test.ts +110 -0
- package/src/__tests__/run.test.ts +614 -0
- package/src/__tests__/tools/findCircularDependencies.test.ts +217 -0
- package/src/define.ts +142 -0
- package/src/defs.ts +221 -0
- package/src/errors.ts +22 -0
- package/src/globalEvents.ts +64 -0
- package/src/globalResources.ts +19 -0
- package/src/index.ts +28 -0
- package/src/run.ts +98 -0
- package/src/tools/findCircularDependencies.ts +69 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineTask,
|
|
3
|
+
defineResource,
|
|
4
|
+
defineEvent,
|
|
5
|
+
defineMiddleware,
|
|
6
|
+
} from "./define";
|
|
7
|
+
import { globalEvents } from "./globalEvents";
|
|
8
|
+
import { globalResources } from "./globalResources";
|
|
9
|
+
import { run } from "./run";
|
|
10
|
+
|
|
11
|
+
const globals = {
|
|
12
|
+
events: globalEvents,
|
|
13
|
+
resources: globalResources,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export { globals };
|
|
17
|
+
export {
|
|
18
|
+
defineTask as task,
|
|
19
|
+
defineResource as resource,
|
|
20
|
+
defineEvent as event,
|
|
21
|
+
defineMiddleware as middleware,
|
|
22
|
+
run,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export * as definitions from "./defs";
|
|
26
|
+
export { Store } from "./Store";
|
|
27
|
+
export { EventManager } from "./EventManager";
|
|
28
|
+
export { TaskRunner } from "./TaskRunner";
|
package/src/run.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { TaskRunner } from "./TaskRunner";
|
|
2
|
+
import {
|
|
3
|
+
DependencyMapType,
|
|
4
|
+
ITaskDefinition,
|
|
5
|
+
IResourceDefinintion,
|
|
6
|
+
IEventDefinition,
|
|
7
|
+
IMiddlewareDefinition,
|
|
8
|
+
DependencyValuesType,
|
|
9
|
+
IResource,
|
|
10
|
+
} from "./defs";
|
|
11
|
+
import { DependencyProcessor } from "./DependencyProcessor";
|
|
12
|
+
import { EventManager } from "./EventManager";
|
|
13
|
+
import { globalEvents } from "./globalEvents";
|
|
14
|
+
import { Store } from "./Store";
|
|
15
|
+
import { findCircularDependencies } from "./tools/findCircularDependencies";
|
|
16
|
+
import { Errors } from "./errors";
|
|
17
|
+
import { globalResources } from "./globalResources";
|
|
18
|
+
|
|
19
|
+
export type ResourcesStoreElementType<
|
|
20
|
+
C = any,
|
|
21
|
+
V = any,
|
|
22
|
+
D extends DependencyMapType = {}
|
|
23
|
+
> = {
|
|
24
|
+
resource: IResourceDefinintion<C, V, D>;
|
|
25
|
+
computedDependencies?: DependencyValuesType<D>;
|
|
26
|
+
config: C;
|
|
27
|
+
value: V;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type TasksStoreElementType<
|
|
31
|
+
Input = any,
|
|
32
|
+
Output extends Promise<any> = any,
|
|
33
|
+
D extends DependencyMapType = {}
|
|
34
|
+
> = {
|
|
35
|
+
task: ITaskDefinition<Input, Output, D>;
|
|
36
|
+
computedDependencies?: DependencyValuesType<D>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type MiddlewareStoreElementType = {
|
|
40
|
+
middleware: IMiddlewareDefinition;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type EventStoreElementType = {
|
|
44
|
+
event: IEventDefinition;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type RunnerState = {
|
|
48
|
+
tasks: Record<string, TasksStoreElementType>;
|
|
49
|
+
resources: Record<string, ResourcesStoreElementType>;
|
|
50
|
+
events: Record<string, EventStoreElementType>;
|
|
51
|
+
middleware: Record<string, MiddlewareStoreElementType>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type RunnerType = {
|
|
55
|
+
store: Store;
|
|
56
|
+
eventManager: EventManager;
|
|
57
|
+
taskRunner: TaskRunner;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export async function run<C, V>(
|
|
61
|
+
resource: IResource<C>,
|
|
62
|
+
config?: C
|
|
63
|
+
): Promise<V> {
|
|
64
|
+
const eventManager = new EventManager();
|
|
65
|
+
const store = new Store(eventManager);
|
|
66
|
+
const taskRunner = new TaskRunner(store, eventManager);
|
|
67
|
+
const processor = new DependencyProcessor(store, eventManager, taskRunner);
|
|
68
|
+
|
|
69
|
+
// In the registration phase we register deeply all the resources, tasks, middleware and events
|
|
70
|
+
store.initializeStore(resource, config);
|
|
71
|
+
store.storeGenericItem(globalResources.taskRunner.with(taskRunner));
|
|
72
|
+
store.computeRegisterOfResource(resource, config);
|
|
73
|
+
|
|
74
|
+
// We verify that there isn't any circular dependencies before we begin computing the dependencies
|
|
75
|
+
const dependentNodes = store.getDependentNodes();
|
|
76
|
+
const circularDependencies = findCircularDependencies(dependentNodes);
|
|
77
|
+
if (circularDependencies.cycles.length > 0) {
|
|
78
|
+
throw Errors.circularDependencies(circularDependencies.cycles);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await processor.processHooks();
|
|
82
|
+
|
|
83
|
+
// Now we can safely compute dependencies without being afraid of an infinite loop.
|
|
84
|
+
// The hooking part is done here.
|
|
85
|
+
await eventManager.emit(globalEvents.beforeInit);
|
|
86
|
+
|
|
87
|
+
await processor.computeAllDependencies();
|
|
88
|
+
|
|
89
|
+
// leftovers that were registered but not depended upon, except root
|
|
90
|
+
await processor.initializeUninitializedResources();
|
|
91
|
+
|
|
92
|
+
// Now we can initialise the root resource
|
|
93
|
+
await processor.initializeRoot();
|
|
94
|
+
|
|
95
|
+
await eventManager.emit(globalEvents.afterInit);
|
|
96
|
+
|
|
97
|
+
return store.root.value;
|
|
98
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A node that has dependencies.
|
|
3
|
+
*/
|
|
4
|
+
export interface IDependentNode {
|
|
5
|
+
id: string;
|
|
6
|
+
dependencies: Record<string, IDependentNode>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface FindCircularDependenciesResult {
|
|
10
|
+
cycles: string[];
|
|
11
|
+
missingDependencies: Array<{ nodeId: string; dependencyId: string }>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function findCircularDependencies(
|
|
15
|
+
nodes: IDependentNode[]
|
|
16
|
+
): FindCircularDependenciesResult {
|
|
17
|
+
const result: FindCircularDependenciesResult = {
|
|
18
|
+
cycles: [],
|
|
19
|
+
missingDependencies: [],
|
|
20
|
+
};
|
|
21
|
+
const visited: Set<string> = new Set();
|
|
22
|
+
const stack: Set<string> = new Set();
|
|
23
|
+
const path: string[] = [];
|
|
24
|
+
|
|
25
|
+
function dfs(node: IDependentNode): void {
|
|
26
|
+
if (stack.has(node.id)) {
|
|
27
|
+
const cycleStartIndex = path.indexOf(node.id);
|
|
28
|
+
const cycle = path.slice(cycleStartIndex).concat(node.id).join(" -> ");
|
|
29
|
+
result.cycles.push(cycle);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (visited.has(node.id)) return;
|
|
34
|
+
|
|
35
|
+
visited.add(node.id);
|
|
36
|
+
stack.add(node.id);
|
|
37
|
+
path.push(node.id);
|
|
38
|
+
|
|
39
|
+
if (node.dependencies && typeof node.dependencies === "object") {
|
|
40
|
+
for (const [depKey, dependentNode] of Object.entries(node.dependencies)) {
|
|
41
|
+
if (!dependentNode) {
|
|
42
|
+
result.missingDependencies.push({
|
|
43
|
+
nodeId: node.id,
|
|
44
|
+
dependencyId: depKey,
|
|
45
|
+
});
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
dfs(dependentNode);
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
result.missingDependencies.push({
|
|
52
|
+
nodeId: node.id,
|
|
53
|
+
dependencyId: "unknown",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
stack.delete(node.id);
|
|
58
|
+
path.pop();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
for (const node of nodes) {
|
|
62
|
+
if (!visited.has(node.id)) {
|
|
63
|
+
dfs(node);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
result.cycles = Array.from(new Set(result.cycles)); // Remove duplicate cycles
|
|
68
|
+
return result;
|
|
69
|
+
}
|