@bluelibs/runner 1.1.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 (67) hide show
  1. package/README.md +191 -13
  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/Store.d.ts +24 -1
  6. package/dist/Store.js +108 -34
  7. package/dist/Store.js.map +1 -1
  8. package/dist/TaskRunner.d.ts +3 -0
  9. package/dist/TaskRunner.js +3 -0
  10. package/dist/TaskRunner.js.map +1 -1
  11. package/dist/define.js +1 -0
  12. package/dist/define.js.map +1 -1
  13. package/dist/defs.d.ts +6 -4
  14. package/dist/globalEvents.d.ts +2 -0
  15. package/dist/globalEvents.js +3 -0
  16. package/dist/globalEvents.js.map +1 -1
  17. package/dist/globalResources.d.ts +5 -3
  18. package/dist/globalResources.js +4 -0
  19. package/dist/globalResources.js.map +1 -1
  20. package/dist/index.d.ts +8 -6
  21. package/dist/index.js +3 -3
  22. package/dist/index.js.map +1 -1
  23. package/dist/models/DependencyProcessor.d.ts +49 -0
  24. package/dist/models/DependencyProcessor.js +178 -0
  25. package/dist/models/DependencyProcessor.js.map +1 -0
  26. package/dist/models/EventManager.d.ts +17 -0
  27. package/dist/models/EventManager.js +73 -0
  28. package/dist/models/EventManager.js.map +1 -0
  29. package/dist/models/Logger.d.ts +33 -0
  30. package/dist/models/Logger.js +76 -0
  31. package/dist/models/Logger.js.map +1 -0
  32. package/dist/models/ResourceInitializer.d.ts +13 -0
  33. package/dist/models/ResourceInitializer.js +54 -0
  34. package/dist/models/ResourceInitializer.js.map +1 -0
  35. package/dist/models/Store.d.ts +90 -0
  36. package/dist/models/Store.js +302 -0
  37. package/dist/models/Store.js.map +1 -0
  38. package/dist/models/TaskRunner.d.ts +25 -0
  39. package/dist/models/TaskRunner.js +96 -0
  40. package/dist/models/TaskRunner.js.map +1 -0
  41. package/dist/models/index.d.ts +5 -0
  42. package/dist/models/index.js +22 -0
  43. package/dist/models/index.js.map +1 -0
  44. package/dist/run.d.ts +3 -3
  45. package/dist/run.js +12 -6
  46. package/dist/run.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/__tests__/index.ts +8 -4
  49. package/src/__tests__/{EventManager.test.ts → models/EventManager.test.ts} +3 -3
  50. package/src/__tests__/models/Logger.test.ts +140 -0
  51. package/src/__tests__/{ResourceInitializer.test.ts → models/ResourceInitializer.test.ts} +4 -4
  52. package/src/__tests__/{Store.test.ts → models/Store.test.ts} +4 -4
  53. package/src/__tests__/{TaskRunner.test.ts → models/TaskRunner.test.ts} +5 -5
  54. package/src/__tests__/run.overrides.test.ts +392 -0
  55. package/src/define.ts +3 -0
  56. package/src/defs.ts +7 -4
  57. package/src/globalEvents.ts +4 -0
  58. package/src/globalResources.ts +8 -3
  59. package/src/index.ts +3 -3
  60. package/src/{DependencyProcessor.ts → models/DependencyProcessor.ts} +6 -6
  61. package/src/{EventManager.ts → models/EventManager.ts} +2 -2
  62. package/src/models/Logger.ts +100 -0
  63. package/src/{ResourceInitializer.ts → models/ResourceInitializer.ts} +2 -2
  64. package/src/{Store.ts → models/Store.ts} +145 -47
  65. package/src/{TaskRunner.ts → models/TaskRunner.ts} +6 -3
  66. package/src/models/index.ts +5 -0
  67. package/src/run.ts +13 -7
package/dist/run.js CHANGED
@@ -1,21 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.run = run;
4
- const TaskRunner_1 = require("./TaskRunner");
5
- const DependencyProcessor_1 = require("./DependencyProcessor");
6
- const EventManager_1 = require("./EventManager");
4
+ const TaskRunner_1 = require("./models/TaskRunner");
5
+ const DependencyProcessor_1 = require("./models/DependencyProcessor");
6
+ const EventManager_1 = require("./models/EventManager");
7
7
  const globalEvents_1 = require("./globalEvents");
8
- const Store_1 = require("./Store");
8
+ const Store_1 = require("./models/Store");
9
9
  const findCircularDependencies_1 = require("./tools/findCircularDependencies");
10
10
  const errors_1 = require("./errors");
11
11
  const globalResources_1 = require("./globalResources");
12
+ const Logger_1 = require("./models/Logger");
12
13
  async function run(resource, config) {
13
14
  const eventManager = new EventManager_1.EventManager();
14
15
  const store = new Store_1.Store(eventManager);
15
16
  const taskRunner = new TaskRunner_1.TaskRunner(store, eventManager);
16
17
  const processor = new DependencyProcessor_1.DependencyProcessor(store, eventManager, taskRunner);
18
+ const logger = new Logger_1.Logger(eventManager);
17
19
  // In the registration phase we register deeply all the resources, tasks, middleware and events
18
20
  store.initializeStore(resource, config);
21
+ store.storeGenericItem(globalResources_1.globalResources.logger.with(logger));
19
22
  store.storeGenericItem(globalResources_1.globalResources.taskRunner.with(taskRunner));
20
23
  // We verify that there isn't any circular dependencies before we begin computing the dependencies
21
24
  const dependentNodes = store.getDependentNodes();
@@ -23,11 +26,14 @@ async function run(resource, config) {
23
26
  if (circularDependencies.cycles.length > 0) {
24
27
  throw errors_1.Errors.circularDependencies(circularDependencies.cycles);
25
28
  }
26
- await processor.processHooks();
29
+ await store.processOverrides();
30
+ // a form of hooking, we store the events for all tasks
31
+ await store.storeEventsForAllTasks();
32
+ await processor.attachHooks();
33
+ await processor.computeAllDependencies();
27
34
  // Now we can safely compute dependencies without being afraid of an infinite loop.
28
35
  // The hooking part is done here.
29
36
  await eventManager.emit(globalEvents_1.globalEvents.beforeInit);
30
- await processor.computeAllDependencies();
31
37
  // leftovers that were registered but not depended upon, except root
32
38
  await processor.initializeUninitializedResources();
33
39
  // Now we can initialise the root resource
package/dist/run.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":";;AA2DA,kBAwCC;AAnGD,6CAA0C;AAU1C,+DAA4D;AAC5D,iDAA8C;AAC9C,iDAA8C;AAC9C,mCAAgC;AAChC,+EAA4E;AAC5E,qCAAkC;AAClC,uDAAoD;AA2C7C,KAAK,UAAU,GAAG,CACvB,QAAyB,EACzB,MAAU;IAEV,MAAM,YAAY,GAAG,IAAI,2BAAY,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,aAAK,CAAC,YAAY,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,IAAI,uBAAU,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,IAAI,yCAAmB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;IAE3E,+FAA+F;IAC/F,KAAK,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,KAAK,CAAC,gBAAgB,CAAC,iCAAe,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAEpE,kGAAkG;IAClG,MAAM,cAAc,GAAG,KAAK,CAAC,iBAAiB,EAAE,CAAC;IACjD,MAAM,oBAAoB,GAAG,IAAA,mDAAwB,EAAC,cAAc,CAAC,CAAC;IACtE,IAAI,oBAAoB,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,eAAM,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,SAAS,CAAC,YAAY,EAAE,CAAC;IAE/B,mFAAmF;IACnF,iCAAiC;IACjC,MAAM,YAAY,CAAC,IAAI,CAAC,2BAAY,CAAC,UAAU,CAAC,CAAC;IAEjD,MAAM,SAAS,CAAC,sBAAsB,EAAE,CAAC;IAEzC,oEAAoE;IACpE,MAAM,SAAS,CAAC,gCAAgC,EAAE,CAAC;IAEnD,0CAA0C;IAC1C,MAAM,SAAS,CAAC,cAAc,EAAE,CAAC;IAEjC,MAAM,YAAY,CAAC,IAAI,CAAC,2BAAY,CAAC,SAAS,CAAC,CAAC;IAEhD,0CAA0C;IAC1C,KAAK,CAAC,IAAI,EAAE,CAAC;IAEb,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":";;AA4DA,kBA6CC;AAzGD,oDAAiD;AAUjD,sEAAmE;AACnE,wDAAqD;AACrD,iDAA8C;AAC9C,0CAAuC;AACvC,+EAA4E;AAC5E,qCAAkC;AAClC,uDAAoD;AACpD,4CAAyC;AA2ClC,KAAK,UAAU,GAAG,CACvB,QAAyB,EACzB,MAAU;IAEV,MAAM,YAAY,GAAG,IAAI,2BAAY,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,aAAK,CAAC,YAAY,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,IAAI,uBAAU,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,IAAI,yCAAmB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,YAAY,CAAC,CAAC;IAExC,+FAA+F;IAC/F,KAAK,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,KAAK,CAAC,gBAAgB,CAAC,iCAAe,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,KAAK,CAAC,gBAAgB,CAAC,iCAAe,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAEpE,kGAAkG;IAClG,MAAM,cAAc,GAAG,KAAK,CAAC,iBAAiB,EAAE,CAAC;IACjD,MAAM,oBAAoB,GAAG,IAAA,mDAAwB,EAAC,cAAc,CAAC,CAAC;IACtE,IAAI,oBAAoB,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,eAAM,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,KAAK,CAAC,gBAAgB,EAAE,CAAC;IAE/B,uDAAuD;IACvD,MAAM,KAAK,CAAC,sBAAsB,EAAE,CAAC;IACrC,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC;IAC9B,MAAM,SAAS,CAAC,sBAAsB,EAAE,CAAC;IAEzC,mFAAmF;IACnF,iCAAiC;IACjC,MAAM,YAAY,CAAC,IAAI,CAAC,2BAAY,CAAC,UAAU,CAAC,CAAC;IAEjD,oEAAoE;IACpE,MAAM,SAAS,CAAC,gCAAgC,EAAE,CAAC;IAEnD,0CAA0C;IAC1C,MAAM,SAAS,CAAC,cAAc,EAAE,CAAC;IAEjC,MAAM,YAAY,CAAC,IAAI,CAAC,2BAAY,CAAC,SAAS,CAAC,CAAC;IAEhD,0CAA0C;IAC1C,KAAK,CAAC,IAAI,EAAE,CAAC;IAEb,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AAC1B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluelibs/runner",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "BlueLibs Runner",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
@@ -1,9 +1,13 @@
1
- import "./EventManager.test";
1
+ import "./models/EventManager.test";
2
+ import "./models/ResourceInitializer.test";
3
+ import "./models/TaskRunner.test";
4
+ import "./models/Store.test";
5
+ import "./models/Logger.test";
6
+
2
7
  import "./tools/findCircularDependencies.test";
3
- import "./ResourceInitializer.test";
8
+
4
9
  import "./run.test";
5
10
  import "./run.hooks.test";
6
- import "./TaskRunner.test";
11
+ import "./run.overrides.test";
7
12
  import "./globalEvents.test";
8
- import "./Store.test";
9
13
  import "./errors.test";
@@ -1,6 +1,6 @@
1
- import { IEvent, IEventDefinition } from "../defs";
2
- import { Errors } from "../errors";
3
- import { EventManager } from "../EventManager";
1
+ import { IEvent, IEventDefinition } from "../../defs";
2
+ import { Errors } from "../../errors";
3
+ import { EventManager } from "../../models/EventManager";
4
4
 
5
5
  describe("EventManager", () => {
6
6
  let eventManager: EventManager;
@@ -0,0 +1,140 @@
1
+ import { Logger, ILog, LogLevels } from "../../models/Logger";
2
+ import { EventManager } from "../../models/EventManager";
3
+ import { globalEvents } from "../../globalEvents";
4
+ import { mock } from "node:test";
5
+
6
+ describe("Logger", () => {
7
+ let logger: Logger;
8
+ let mockEventManager: jest.Mocked<EventManager>;
9
+
10
+ beforeEach(() => {
11
+ mockEventManager = new EventManager() as jest.Mocked<EventManager>;
12
+ logger = new Logger(mockEventManager);
13
+ });
14
+
15
+ describe("log method", () => {
16
+ it("should emit a log event with correct data", async () => {
17
+ const testData = "Test log message";
18
+ const testLevel = "info";
19
+ mockEventManager.emit = jest.fn();
20
+
21
+ await logger.log(testLevel, testData);
22
+
23
+ expect(mockEventManager.emit).toHaveBeenCalledWith(
24
+ globalEvents.log,
25
+ expect.objectContaining({
26
+ level: testLevel,
27
+ data: testData,
28
+ timestamp: expect.any(Date),
29
+ })
30
+ );
31
+ });
32
+
33
+ it("should handle different log levels", async () => {
34
+ const levels: Array<LogLevels> = [
35
+ "trace",
36
+ "debug",
37
+ "info",
38
+ "warn",
39
+ "error",
40
+ "critical",
41
+ ];
42
+
43
+ mockEventManager.emit = jest.fn();
44
+
45
+ for (const level of levels) {
46
+ await logger.log(level, `Test ${level} message`);
47
+
48
+ expect(mockEventManager.emit).toHaveBeenCalledWith(
49
+ globalEvents.log,
50
+ expect.objectContaining({
51
+ level,
52
+ data: `Test ${level} message`,
53
+ timestamp: expect.any(Date),
54
+ })
55
+ );
56
+ }
57
+ });
58
+ });
59
+
60
+ describe("print method", () => {
61
+ let consoleLogSpy: jest.SpyInstance;
62
+
63
+ beforeEach(() => {
64
+ consoleLogSpy = jest.spyOn(console, "log").mockImplementation();
65
+ });
66
+
67
+ afterEach(() => {
68
+ consoleLogSpy.mockRestore();
69
+ });
70
+
71
+ it("should print log messages correctly", async () => {
72
+ const testLog: ILog = {
73
+ level: "info",
74
+ context: "test",
75
+ data: "Test log message",
76
+ timestamp: new Date("2023-01-01T00:00:00Z"),
77
+ };
78
+
79
+ await logger.print(testLog);
80
+
81
+ expect(consoleLogSpy).toHaveBeenCalledWith(
82
+ expect.stringContaining("[INFO] (test) - Test log message")
83
+ );
84
+ });
85
+
86
+ it("should handle Error objects in log data", async () => {
87
+ const testError = new Error("Test error");
88
+ const testLog: ILog = {
89
+ level: "error",
90
+ data: testError,
91
+ timestamp: new Date("2023-01-01T00:00:00Z"),
92
+ };
93
+
94
+ await logger.print(testLog);
95
+
96
+ expect(consoleLogSpy).toHaveBeenCalledWith(
97
+ expect.stringContaining("Error: Error - Test error")
98
+ );
99
+ expect(consoleLogSpy).toHaveBeenCalledWith(
100
+ expect.stringContaining("Stack Trace:")
101
+ );
102
+ });
103
+
104
+ it("should pretty-print JSON objects in log data", async () => {
105
+ const testObject = { key: "value", nested: { foo: "bar" } };
106
+ const testLog: ILog = {
107
+ level: "debug",
108
+ data: testObject,
109
+ timestamp: new Date("2023-01-01T00:00:00Z"),
110
+ };
111
+
112
+ await logger.print(testLog);
113
+
114
+ expect(consoleLogSpy).toHaveBeenCalledWith(
115
+ expect.stringContaining(JSON.stringify(testObject, null, 2))
116
+ );
117
+ });
118
+ });
119
+
120
+ describe("log level methods", () => {
121
+ const testLevels: Array<LogLevels> = [
122
+ "trace",
123
+ "debug",
124
+ "info",
125
+ "warn",
126
+ "error",
127
+ "critical",
128
+ ];
129
+
130
+ for (const level of testLevels) {
131
+ it(`should call log method with ${level} level`, async () => {
132
+ const logSpy = jest.spyOn(logger, "log").mockImplementation();
133
+
134
+ await logger[level]("Test log message");
135
+
136
+ expect(logSpy).toHaveBeenCalledWith(level, "Test log message");
137
+ });
138
+ }
139
+ });
140
+ });
@@ -1,7 +1,7 @@
1
- import { ResourceInitializer } from "../ResourceInitializer";
2
- import { Store } from "../Store";
3
- import { EventManager } from "../EventManager";
4
- import { defineResource } from "../define";
1
+ import { ResourceInitializer } from "../../models/ResourceInitializer";
2
+ import { Store } from "../../models/Store";
3
+ import { EventManager } from "../../models/EventManager";
4
+ import { defineResource } from "../../define";
5
5
 
6
6
  describe("ResourceInitializer", () => {
7
7
  let store: Store;
@@ -1,12 +1,12 @@
1
- import { Store } from "../Store";
2
- import { EventManager } from "../EventManager";
1
+ import { Store } from "../../models/Store";
2
+ import { EventManager } from "../../models/EventManager";
3
3
  import {
4
4
  defineResource,
5
5
  defineTask,
6
6
  defineMiddleware,
7
7
  defineEvent,
8
- } from "../define";
9
- import { globalResources } from "../globalResources";
8
+ } from "../../define";
9
+ import { globalResources } from "../../globalResources";
10
10
 
11
11
  describe("Store", () => {
12
12
  let eventManager: EventManager;
@@ -1,8 +1,8 @@
1
- import { TaskRunner } from "../TaskRunner";
2
- import { Store } from "../Store";
3
- import { EventManager } from "../EventManager";
4
- import { defineTask, defineResource, defineMiddleware } from "../define";
5
- import { ITask } from "../defs";
1
+ import { TaskRunner } from "../../models/TaskRunner";
2
+ import { Store } from "../../models/Store";
3
+ import { EventManager } from "../../models/EventManager";
4
+ import { defineTask, defineResource, defineMiddleware } from "../../define";
5
+ import { ITask } from "../../defs";
6
6
 
7
7
  describe("TaskRunner", () => {
8
8
  let store: Store;
@@ -0,0 +1,392 @@
1
+ import { definitions } from "..";
2
+ import {
3
+ defineTask,
4
+ defineResource,
5
+ defineEvent,
6
+ defineMiddleware,
7
+ } from "../define";
8
+ import { Errors } from "../errors";
9
+ import { run } from "../run";
10
+
11
+ describe("run.overrides", () => {
12
+ // Tasks
13
+ it("Should work with a simple override", async () => {
14
+ const task = defineTask({
15
+ id: "task",
16
+ run: async () => "Task executed",
17
+ });
18
+
19
+ const override = defineTask({
20
+ id: "task",
21
+ run: async () => "Task overridden",
22
+ });
23
+
24
+ const app = defineResource({
25
+ id: "app",
26
+ register: [task],
27
+ dependencies: {
28
+ task,
29
+ },
30
+ overrides: [override],
31
+ async init(_, deps) {
32
+ return await deps.task();
33
+ },
34
+ });
35
+
36
+ const result = await run(app);
37
+ expect(result).toBe("Task overridden");
38
+ });
39
+
40
+ it("Should work with a deep override", async () => {
41
+ const task = defineTask({
42
+ id: "task",
43
+ run: async () => "Task executed",
44
+ });
45
+
46
+ const override = defineTask({
47
+ id: "task",
48
+ run: async () => "Task overridden",
49
+ });
50
+
51
+ const middle = defineResource({
52
+ id: "app",
53
+ register: [task],
54
+ overrides: [override],
55
+ });
56
+
57
+ const root = defineResource({
58
+ id: "root",
59
+ register: [middle],
60
+ dependencies: { task },
61
+ async init(_, deps) {
62
+ return await deps.task();
63
+ },
64
+ });
65
+
66
+ const result = await run(root);
67
+ expect(result).toBe("Task overridden");
68
+ });
69
+
70
+ it("Should work with a deep override with config", async () => {
71
+ const task = defineTask({
72
+ id: "task",
73
+ run: async () => "Task executed",
74
+ });
75
+
76
+ const override = defineTask({
77
+ id: "task",
78
+ run: async () => "Task overridden",
79
+ });
80
+
81
+ const middle = defineResource<{ test: string }>({
82
+ id: "app",
83
+ register: [task],
84
+ overrides: [override],
85
+ });
86
+
87
+ const root = defineResource({
88
+ id: "root",
89
+ register: [middle.with({ test: "ok" })],
90
+ dependencies: { task },
91
+ async init(_, deps) {
92
+ return await deps.task();
93
+ },
94
+ });
95
+
96
+ const result = await run(root);
97
+ expect(result).toBe("Task overridden");
98
+ });
99
+
100
+ it("Should work with a override that has an override", async () => {
101
+ const task = defineTask({
102
+ id: "task",
103
+ run: async () => "Task executed",
104
+ });
105
+
106
+ const override = defineTask({
107
+ id: "task",
108
+ run: async () => "Task overridden",
109
+ });
110
+
111
+ const resource = defineResource({
112
+ id: "resource",
113
+ });
114
+
115
+ const resourceOverride = {
116
+ ...resource,
117
+ overrides: [override],
118
+ };
119
+
120
+ const middle = defineResource({
121
+ id: "app",
122
+ register: [task],
123
+ overrides: [resourceOverride],
124
+ });
125
+
126
+ const root = defineResource({
127
+ id: "root",
128
+ register: [middle, resource],
129
+ dependencies: { task },
130
+ async init(_, deps) {
131
+ return await deps.task();
132
+ },
133
+ });
134
+
135
+ const result = await run(root);
136
+ expect(result).toBe("Task overridden");
137
+ });
138
+
139
+ it("Should work with a override that has an override with config", async () => {
140
+ const task = defineTask({
141
+ id: "task",
142
+ run: async () => "Task executed",
143
+ });
144
+
145
+ const override = defineTask({
146
+ id: "task",
147
+ run: async () => "Task overridden",
148
+ });
149
+
150
+ const resource = defineResource({
151
+ id: "resource",
152
+ });
153
+
154
+ const resourceOverride: definitions.IResource<any> = {
155
+ ...resource,
156
+ overrides: [override],
157
+ async init(config: { test: string }) {
158
+ return "Resource init";
159
+ },
160
+ };
161
+
162
+ const middle = defineResource({
163
+ id: "app",
164
+ register: [task],
165
+ overrides: [resourceOverride.with({ test: "ok" })],
166
+ });
167
+
168
+ const root = defineResource({
169
+ id: "root",
170
+ register: [middle, resource],
171
+ dependencies: { task },
172
+ async init(_, deps) {
173
+ return await deps.task();
174
+ },
175
+ });
176
+
177
+ const result = await run(root);
178
+ expect(result).toBe("Task overridden");
179
+ });
180
+
181
+ it("should work overriding a middleware", async () => {
182
+ const middleware = defineMiddleware({
183
+ id: "middleware",
184
+ run: async ({ next }) => {
185
+ return `Middleware: ${await next()}`;
186
+ },
187
+ });
188
+
189
+ const override = defineMiddleware({
190
+ id: "middleware",
191
+ run: async ({ next }) => {
192
+ return `Override: ${await next()}`;
193
+ },
194
+ });
195
+
196
+ const task = defineTask({
197
+ id: "task",
198
+ middleware: [middleware],
199
+ run: async () => "Task executed",
200
+ });
201
+
202
+ const resource = defineResource({
203
+ id: "resource",
204
+ register: [middleware, task],
205
+ dependencies: { task },
206
+ overrides: [override],
207
+ async init(_, deps) {
208
+ return deps.task();
209
+ },
210
+ });
211
+
212
+ const result = await run(resource);
213
+ expect(result).toBe("Override: Task executed");
214
+ });
215
+
216
+ it("should throw, when you try to override something unregistered", async () => {
217
+ const task = defineTask({
218
+ id: "task",
219
+ run: async () => "Task executed",
220
+ });
221
+
222
+ const override = defineTask({
223
+ id: "task2",
224
+ run: async () => "Task overridden",
225
+ });
226
+
227
+ const app = defineResource({
228
+ id: "app",
229
+ dependencies: {
230
+ task,
231
+ },
232
+ overrides: [override],
233
+ async init(_, deps) {
234
+ return await deps.task();
235
+ },
236
+ });
237
+
238
+ await expect(run(app)).rejects.toThrowError(
239
+ Errors.dependencyNotFound("task2").message
240
+ );
241
+ });
242
+
243
+ it("should throw, when you try to override something unregistered but with resources with config", async () => {
244
+ const r1 = defineResource({
245
+ id: "override",
246
+ init: async () => "Task executed",
247
+ });
248
+ const r2 = defineResource({
249
+ id: "override2",
250
+ init: async () => "Task executed",
251
+ });
252
+
253
+ const app = defineResource({
254
+ id: "app",
255
+ dependencies: {
256
+ r1,
257
+ },
258
+ overrides: [r2.with()],
259
+ async init(_, r1) {
260
+ return r1;
261
+ },
262
+ });
263
+
264
+ await expect(run(app)).rejects.toThrowError(
265
+ Errors.dependencyNotFound("override2").message
266
+ );
267
+ });
268
+
269
+ it("should have an override priority, the deeper you are, the less priority you have in the override", async () => {
270
+ const task = defineTask({
271
+ id: "task",
272
+ run: async () => "Task executed",
273
+ });
274
+
275
+ const override = defineTask({
276
+ id: "task2",
277
+ run: async () => "Task overridden",
278
+ });
279
+
280
+ const override2 = defineTask({
281
+ id: "task",
282
+ run: async () => "Task super-overridden",
283
+ });
284
+
285
+ const middle = defineResource({
286
+ id: "app",
287
+ register: [task],
288
+ overrides: [override],
289
+ });
290
+
291
+ const app = defineResource({
292
+ id: "app",
293
+ dependencies: {
294
+ task,
295
+ },
296
+ register: [middle],
297
+ overrides: [override2],
298
+ async init(_, deps) {
299
+ return await deps.task();
300
+ },
301
+ });
302
+
303
+ const result = await run(app);
304
+ expect(result).toBe("Task super-overridden");
305
+ });
306
+
307
+ it("should override if I have a previously registered normal resource with a resource with config", async () => {
308
+ const r1 = defineResource({
309
+ id: "override",
310
+ init: async () => "Task executed",
311
+ });
312
+ const r2 = defineResource({
313
+ id: "override",
314
+ init: async () => "Task overriden.",
315
+ });
316
+
317
+ const app = defineResource({
318
+ id: "app",
319
+ dependencies: {
320
+ r1,
321
+ },
322
+ register: [r1],
323
+ overrides: [r2.with()],
324
+ async init(_, deps) {
325
+ return deps.r1;
326
+ },
327
+ });
328
+
329
+ await expect(run(app)).resolves.toBe("Task overriden.");
330
+ });
331
+
332
+ it("should override if I have a previously registered normal resource with a resource with config", async () => {
333
+ const r1 = defineResource({
334
+ id: "override",
335
+ init: async () => "Task executed",
336
+ });
337
+ const r2 = defineResource({
338
+ id: "override",
339
+ init: async () => "Task overriden.",
340
+ });
341
+
342
+ const app = defineResource({
343
+ id: "app",
344
+ dependencies: {
345
+ r1,
346
+ },
347
+ register: [r1.with()],
348
+ overrides: [r2.with()],
349
+ async init(_, deps) {
350
+ return deps.r1;
351
+ },
352
+ });
353
+
354
+ await expect(run(app)).resolves.toBe("Task overriden.");
355
+ });
356
+
357
+ it("should override something deeply registered, with a with config", async () => {
358
+ const r1 = defineResource({
359
+ id: "override",
360
+ init: async () => "Task executed",
361
+ });
362
+
363
+ const middle = defineResource({
364
+ id: "app.m1",
365
+ register: [r1],
366
+ });
367
+
368
+ const middle2 = defineResource({
369
+ id: "app.m2",
370
+ register: [middle],
371
+ });
372
+
373
+ const r2 = defineResource({
374
+ id: "override",
375
+ init: async () => "Task overriden.",
376
+ });
377
+
378
+ const app = defineResource({
379
+ id: "app",
380
+ dependencies: {
381
+ r1,
382
+ },
383
+ register: [middle2],
384
+ overrides: [r2.with()],
385
+ async init(_, deps) {
386
+ return deps.r1;
387
+ },
388
+ });
389
+
390
+ await expect(run(app)).resolves.toBe("Task overriden.");
391
+ });
392
+ });
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
 
@@ -57,6 +59,7 @@ export function defineResource<
57
59
  hooks: constConfig.hooks || [],
58
60
  dispose: constConfig.dispose,
59
61
  register: constConfig.register || [],
62
+ overrides: constConfig.overrides || [],
60
63
  init: constConfig.init,
61
64
  with: function (config: TConfig) {
62
65
  return {