@bluelibs/runner 1.0.0 → 1.2.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.
Files changed (76) hide show
  1. package/README.md +231 -12
  2. package/dist/DependencyProcessor.d.ts +2 -2
  3. package/dist/DependencyProcessor.js +3 -3
  4. package/dist/DependencyProcessor.js.map +1 -1
  5. package/dist/EventManager.d.ts +4 -0
  6. package/dist/EventManager.js +15 -0
  7. package/dist/EventManager.js.map +1 -1
  8. package/dist/Store.d.ts +30 -2
  9. package/dist/Store.js +134 -29
  10. package/dist/Store.js.map +1 -1
  11. package/dist/TaskRunner.d.ts +3 -0
  12. package/dist/TaskRunner.js +3 -0
  13. package/dist/TaskRunner.js.map +1 -1
  14. package/dist/define.js +2 -7
  15. package/dist/define.js.map +1 -1
  16. package/dist/defs.d.ts +15 -4
  17. package/dist/errors.d.ts +2 -0
  18. package/dist/errors.js +2 -0
  19. package/dist/errors.js.map +1 -1
  20. package/dist/globalEvents.d.ts +2 -0
  21. package/dist/globalEvents.js +3 -0
  22. package/dist/globalEvents.js.map +1 -1
  23. package/dist/globalResources.d.ts +8 -6
  24. package/dist/globalResources.js +9 -4
  25. package/dist/globalResources.js.map +1 -1
  26. package/dist/index.d.ts +8 -6
  27. package/dist/index.js +3 -3
  28. package/dist/index.js.map +1 -1
  29. package/dist/models/DependencyProcessor.d.ts +49 -0
  30. package/dist/models/DependencyProcessor.js +178 -0
  31. package/dist/models/DependencyProcessor.js.map +1 -0
  32. package/dist/models/EventManager.d.ts +17 -0
  33. package/dist/models/EventManager.js +73 -0
  34. package/dist/models/EventManager.js.map +1 -0
  35. package/dist/models/Logger.d.ts +33 -0
  36. package/dist/models/Logger.js +76 -0
  37. package/dist/models/Logger.js.map +1 -0
  38. package/dist/models/ResourceInitializer.d.ts +13 -0
  39. package/dist/models/ResourceInitializer.js +54 -0
  40. package/dist/models/ResourceInitializer.js.map +1 -0
  41. package/dist/models/Store.d.ts +90 -0
  42. package/dist/models/Store.js +302 -0
  43. package/dist/models/Store.js.map +1 -0
  44. package/dist/models/TaskRunner.d.ts +25 -0
  45. package/dist/models/TaskRunner.js +96 -0
  46. package/dist/models/TaskRunner.js.map +1 -0
  47. package/dist/models/index.d.ts +5 -0
  48. package/dist/models/index.js +22 -0
  49. package/dist/models/index.js.map +1 -0
  50. package/dist/run.d.ts +4 -4
  51. package/dist/run.js +14 -7
  52. package/dist/run.js.map +1 -1
  53. package/package.json +1 -2
  54. package/src/__tests__/index.ts +8 -4
  55. package/src/__tests__/{EventManager.test.ts → models/EventManager.test.ts} +20 -2
  56. package/src/__tests__/models/Logger.test.ts +140 -0
  57. package/src/__tests__/{ResourceInitializer.test.ts → models/ResourceInitializer.test.ts} +4 -4
  58. package/src/__tests__/models/Store.test.ts +128 -0
  59. package/src/__tests__/{TaskRunner.test.ts → models/TaskRunner.test.ts} +5 -5
  60. package/src/__tests__/run.overrides.test.ts +392 -0
  61. package/src/__tests__/run.test.ts +28 -1
  62. package/src/define.ts +4 -8
  63. package/src/defs.ts +20 -4
  64. package/src/errors.ts +6 -0
  65. package/src/globalEvents.ts +4 -0
  66. package/src/globalResources.ts +18 -11
  67. package/src/index.ts +3 -3
  68. package/src/{DependencyProcessor.ts → models/DependencyProcessor.ts} +6 -6
  69. package/src/{EventManager.ts → models/EventManager.ts} +21 -1
  70. package/src/models/Logger.ts +100 -0
  71. package/src/{ResourceInitializer.ts → models/ResourceInitializer.ts} +2 -2
  72. package/src/{Store.ts → models/Store.ts} +181 -41
  73. package/src/{TaskRunner.ts → models/TaskRunner.ts} +6 -3
  74. package/src/models/index.ts +5 -0
  75. package/src/run.ts +17 -9
  76. package/src/__tests__/Store.test.ts +0 -143
@@ -5,6 +5,7 @@ import {
5
5
  defineMiddleware,
6
6
  } from "../define";
7
7
  import { run } from "../run";
8
+ import { globalResources } from "../globalResources";
8
9
 
9
10
  describe("run", () => {
10
11
  // Tasks
@@ -603,7 +604,6 @@ describe("run", () => {
603
604
  dependencies: () => ({ middle }),
604
605
  register: () => [middle, testTask],
605
606
  async init(_, { middle }) {
606
- console.log(middle.toString());
607
607
  expect(await middle()).toBe("middle");
608
608
  },
609
609
  });
@@ -611,4 +611,31 @@ describe("run", () => {
611
611
  await run(app);
612
612
  expect(mockFn).toHaveBeenCalled();
613
613
  });
614
+
615
+ describe("disposal", () => {
616
+ it("should be able to dispose of a resource", async () => {
617
+ const disposeFn = jest.fn();
618
+ const testResource = defineResource({
619
+ id: "test.resource",
620
+ dispose: disposeFn,
621
+ init: async () => "Resource Value",
622
+ });
623
+
624
+ const app = defineResource({
625
+ id: "app",
626
+ register: [testResource],
627
+ dependencies: { testResource, store: globalResources.store },
628
+ async init(_, { testResource, store }) {
629
+ expect(testResource).toBe("Resource Value");
630
+
631
+ return {
632
+ dispose: () => store.dispose(),
633
+ };
634
+ },
635
+ });
636
+
637
+ const result = await run(app);
638
+ await result.dispose();
639
+ });
640
+ });
614
641
  });
package/src/define.ts CHANGED
@@ -10,6 +10,8 @@ import {
10
10
  DependencyMapType,
11
11
  DependencyValuesType,
12
12
  IMiddleware,
13
+ IHookDefinition,
14
+ IEvent,
13
15
  } from "./defs";
14
16
  import { Errors } from "./errors";
15
17
 
@@ -21,14 +23,6 @@ export function defineTask<
21
23
  >(
22
24
  config: ITaskDefinition<Input, Output, Deps, Test>
23
25
  ): ITask<Input, Output, Deps, Test> {
24
- const autorun: any = {};
25
- // if (config.autorun) {
26
- // if (config.autorun.on) {
27
- // autorun.on = Array.isArray(config.autorun.on);
28
- // autorun.schedule = config.autorun.schedule;
29
- // }
30
- // }
31
-
32
26
  return {
33
27
  [symbols.task]: true,
34
28
  id: config.id,
@@ -63,7 +57,9 @@ export function defineResource<
63
57
  id: constConfig.id,
64
58
  dependencies: constConfig.dependencies,
65
59
  hooks: constConfig.hooks || [],
60
+ dispose: constConfig.dispose,
66
61
  register: constConfig.register || [],
62
+ overrides: constConfig.overrides || [],
67
63
  init: constConfig.init,
68
64
  with: function (config: TConfig) {
69
65
  return {
package/src/defs.ts CHANGED
@@ -21,7 +21,7 @@ export interface IMiddlewareMeta extends IMeta {}
21
21
  // DependencyMap types
22
22
  export type DependencyMapType = Record<
23
23
  string,
24
- ITask | IResource | IEventDefinition
24
+ ITask | IResource | IEventDefinition | IResourceWithConfig<any, any>
25
25
  >;
26
26
 
27
27
  export type DependencyValueType<T> = T extends ITask<
@@ -132,7 +132,21 @@ export interface IResourceDefinintion<
132
132
  config: TConfig,
133
133
  dependencies: DependencyValuesType<TDependencies>
134
134
  ) => Promise<TValue>;
135
+ /**
136
+ * Clean-up function for the resource. This is called when the resource is no longer needed.
137
+ *
138
+ * @param value The value of the resource
139
+ * @param config The configuration it received
140
+ * @param dependencies The dependencies it needed
141
+ * @returns
142
+ */
143
+ dispose?: (
144
+ value: TValue,
145
+ config: TConfig,
146
+ dependencies: DependencyValuesType<TDependencies>
147
+ ) => Promise<TValue>;
135
148
  meta?: IResourceMeta;
149
+ overrides?: Array<IResource | ITask | IMiddleware | IResourceWithConfig>;
136
150
  }
137
151
 
138
152
  export interface IResource<
@@ -155,6 +169,8 @@ export interface IResource<
155
169
  hooks:
156
170
  | IHookDefinition<TDependencies>[]
157
171
  | ((config: TConfig) => IHookDefinition<TDependencies>[]);
172
+
173
+ overrides: Array<IResource | ITask | IMiddleware | IResourceWithConfig>;
158
174
  }
159
175
 
160
176
  export interface IResourceWithConfig<
@@ -212,10 +228,10 @@ export interface IMiddlewareExecutionInput {
212
228
  next: (input?: any) => Promise<any>;
213
229
  }
214
230
 
215
- export interface IHookDefinition<D extends DependencyMapType = {}> {
216
- event: IEventDefinition;
231
+ export interface IHookDefinition<D extends DependencyMapType = {}, T = any> {
232
+ event: IEventDefinition<T>;
217
233
  run: (
218
- event: IEvent,
234
+ event: IEvent<T>,
219
235
  dependencies: DependencyValuesType<D>
220
236
  ) => Promise<void> | void;
221
237
  }
package/src/errors.ts CHANGED
@@ -19,4 +19,10 @@ export const Errors = {
19
19
 
20
20
  middlewareAlreadyGlobal: (id: string) =>
21
21
  new Error("Cannot call global on a global middleware: " + id),
22
+
23
+ locked: (what: string) =>
24
+ new Error(`Cannot modify the ${what} when it is locked.`),
25
+
26
+ storeAlreadyInitialized: () =>
27
+ new Error("Store already initialized. Cannot reinitialize."),
22
28
  };
@@ -1,5 +1,6 @@
1
1
  import { defineEvent } from "./define";
2
2
  import { ITask, IResource } from "./defs";
3
+ import { ILog } from "./models/Logger";
3
4
 
4
5
  export const globalEvents = {
5
6
  beforeInit: defineEvent({
@@ -8,6 +9,9 @@ export const globalEvents = {
8
9
  afterInit: defineEvent({
9
10
  id: "global.afterInit",
10
11
  }),
12
+ log: defineEvent<ILog>({
13
+ id: "global.log",
14
+ }),
11
15
  tasks: {
12
16
  beforeRun: defineEvent<{
13
17
  task: ITask<any, any, any>;
@@ -1,19 +1,26 @@
1
1
  import { defineResource } from "./define";
2
- import { EventManager } from "./EventManager";
3
- import { Store } from "./Store";
4
- import { TaskRunner } from "./TaskRunner";
2
+ import { EventManager } from "./models/EventManager";
3
+ import { Logger } from "./models/Logger";
4
+ import { Store } from "./models/Store";
5
+ import { TaskRunner } from "./models/TaskRunner";
6
+
7
+ const store = defineResource({
8
+ id: "global.store",
9
+ init: async (store: Store) => store,
10
+ });
5
11
 
6
12
  export const globalResources = {
7
- store: defineResource<Store>({
8
- id: "global.store",
9
- init: async (store) => store,
10
- }),
11
- eventManager: defineResource<EventManager>({
13
+ store,
14
+ eventManager: defineResource({
12
15
  id: "global.eventManager",
13
- init: async (em) => em,
16
+ init: async (em: EventManager) => em,
14
17
  }),
15
- taskRunner: defineResource<TaskRunner>({
18
+ taskRunner: defineResource({
16
19
  id: "global.taskRunner",
17
- init: async (runner) => runner,
20
+ init: async (runner: TaskRunner) => runner,
21
+ }),
22
+ logger: defineResource({
23
+ id: "global.logger",
24
+ init: async (logger: Logger) => logger,
18
25
  }),
19
26
  };
package/src/index.ts CHANGED
@@ -23,6 +23,6 @@ export {
23
23
  };
24
24
 
25
25
  export * as definitions from "./defs";
26
- export { Store } from "./Store";
27
- export { EventManager } from "./EventManager";
28
- export { TaskRunner } from "./TaskRunner";
26
+ export { Store } from "./models/Store";
27
+ export { EventManager } from "./models/EventManager";
28
+ export { TaskRunner } from "./models/TaskRunner";
@@ -5,13 +5,13 @@ import {
5
5
  IResource,
6
6
  IHookDefinition,
7
7
  IEventDefinition,
8
- } from "./defs";
8
+ } from "../defs";
9
9
  import { ResourceStoreElementType, Store } from "./Store";
10
- import * as utils from "./define";
10
+ import * as utils from "../define";
11
11
  import { EventManager } from "./EventManager";
12
12
  import { ResourceInitializer } from "./ResourceInitializer";
13
13
  import { TaskRunner } from "./TaskRunner";
14
- import { Errors } from "./errors";
14
+ import { Errors } from "../errors";
15
15
 
16
16
  /**
17
17
  * This class is responsible of setting up dependencies with their respective computedValues.
@@ -113,11 +113,11 @@ export class DependencyProcessor {
113
113
  * Processes all hooks, should run before emission of any event.
114
114
  * @returns
115
115
  */
116
- public processHooks() {
116
+ public attachHooks() {
117
117
  // iterate through resources and send them to processHooks
118
118
  for (const resource of this.store.resources.values()) {
119
119
  if (resource.resource.hooks) {
120
- this.processHooksForResource(resource);
120
+ this.attachHooksToResource(resource);
121
121
  }
122
122
  }
123
123
  }
@@ -127,7 +127,7 @@ export class DependencyProcessor {
127
127
  * @param hooks
128
128
  * @param deps
129
129
  */
130
- public processHooksForResource(
130
+ public attachHooksToResource(
131
131
  resourceStoreElement: ResourceStoreElementType<any, any, {}>
132
132
  ) {
133
133
  let hooks = resourceStoreElement.resource.hooks;
@@ -1,4 +1,5 @@
1
- import { EventHandlerType, IEvent, IEventDefinition } from "./defs";
1
+ import { EventHandlerType, IEvent, IEventDefinition } from "../defs";
2
+ import { Errors } from "../errors";
2
3
 
3
4
  const HandlerOptionsDefaults = { order: 0 };
4
5
 
@@ -16,6 +17,21 @@ export interface IEventHandlerOptions<T = any> {
16
17
  export class EventManager {
17
18
  private listeners: Map<string, IListenerStorage[]> = new Map();
18
19
  private globalListeners: IListenerStorage[] = [];
20
+ #isLocked = false;
21
+
22
+ get isLocked() {
23
+ return this.#isLocked;
24
+ }
25
+
26
+ lock() {
27
+ this.#isLocked = true;
28
+ }
29
+
30
+ checkLock() {
31
+ if (this.#isLocked) {
32
+ throw Errors.locked("EventManager");
33
+ }
34
+ }
19
35
 
20
36
  async emit<TInput>(
21
37
  eventDefinition: IEventDefinition<TInput>,
@@ -46,6 +62,8 @@ export class EventManager {
46
62
  handler: EventHandlerType<T>,
47
63
  options: IEventHandlerOptions<T> = HandlerOptionsDefaults
48
64
  ): void {
65
+ this.checkLock();
66
+
49
67
  if (Array.isArray(event)) {
50
68
  event.forEach((id) => this.addListener(id, handler, options));
51
69
  } else {
@@ -66,6 +84,8 @@ export class EventManager {
66
84
  handler: EventHandlerType,
67
85
  options: IEventHandlerOptions = HandlerOptionsDefaults
68
86
  ): void {
87
+ this.checkLock();
88
+
69
89
  const newListener: IListenerStorage = {
70
90
  handler,
71
91
  order: options.order || 0,
@@ -0,0 +1,100 @@
1
+ import { globalEvents } from "../globalEvents";
2
+ import { EventManager } from "./EventManager";
3
+
4
+ export type LogLevels =
5
+ | "trace"
6
+ | "debug"
7
+ | "info"
8
+ | "warn"
9
+ | "error"
10
+ | "critical";
11
+
12
+ export interface ILog {
13
+ level: string;
14
+ context?: string;
15
+ data: any;
16
+ timestamp: Date;
17
+ }
18
+
19
+ export class Logger {
20
+ public static defaultContext = "app";
21
+
22
+ public severity = {
23
+ trace: 0,
24
+ debug: 1,
25
+ info: 2,
26
+ warn: 3,
27
+ error: 4,
28
+ critical: 5,
29
+ };
30
+
31
+ constructor(private eventManager: EventManager) {}
32
+
33
+ /**
34
+ * @param level
35
+ * @param message
36
+ */
37
+ public async log(level: LogLevels, data: any): Promise<void> {
38
+ const log: ILog = {
39
+ level,
40
+ data,
41
+ timestamp: new Date(),
42
+ };
43
+
44
+ await this.eventManager.emit(globalEvents.log, log);
45
+ }
46
+
47
+ public async print(log: ILog) {
48
+ // Extract the relevant information from the log
49
+ const { level, context, data, timestamp } = log;
50
+
51
+ // Format the timestamp to a more readable format
52
+ const formattedTimestamp = timestamp.toISOString();
53
+
54
+ // Format the log level for better visibility
55
+ const levelStr = `[${level.toUpperCase()}]`;
56
+
57
+ // Format the context, if provided
58
+ const contextStr = context ? `(${context})` : "";
59
+
60
+ // Handle different data types, especially if it's an error
61
+ let dataStr: string;
62
+ if (data instanceof Error) {
63
+ dataStr = `Error: ${data.name} - ${data.message}\nStack Trace:\n${data.stack}`;
64
+ } else if (typeof data === "object") {
65
+ dataStr = JSON.stringify(data, null, 2); // Pretty-print JSON objects
66
+ } else {
67
+ dataStr = String(data); // Convert any other type to string
68
+ }
69
+
70
+ // Construct the final log message
71
+ const logMessage = `${formattedTimestamp} ${levelStr} ${contextStr} - ${dataStr}`;
72
+
73
+ // Print the log message
74
+ console.log(logMessage);
75
+ }
76
+
77
+ public async info(data: any) {
78
+ await this.log("info", data);
79
+ }
80
+
81
+ public async error(data: any) {
82
+ await this.log("error", data);
83
+ }
84
+
85
+ public async warn(data: any) {
86
+ await this.log("warn", data);
87
+ }
88
+
89
+ public async debug(data: any) {
90
+ await this.log("debug", data);
91
+ }
92
+
93
+ public async trace(data: any) {
94
+ await this.log("trace", data);
95
+ }
96
+
97
+ public async critical(data: any) {
98
+ await this.log("critical", data);
99
+ }
100
+ }
@@ -3,9 +3,9 @@ import {
3
3
  DependencyValuesType,
4
4
  ITask,
5
5
  IResource,
6
- } from "./defs";
6
+ } from "../defs";
7
7
  import { EventManager } from "./EventManager";
8
- import { globalEvents } from "./globalEvents";
8
+ import { globalEvents } from "../globalEvents";
9
9
  import { Store } from "./Store";
10
10
 
11
11
  export class ResourceInitializer {