composed-di 0.0.6-alpha → 0.2.6

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.
@@ -0,0 +1,6 @@
1
+ export declare class ServiceScope {
2
+ readonly name: string;
3
+ readonly symbol: symbol;
4
+ constructor(name: string);
5
+ }
6
+ //# sourceMappingURL=ServiceScope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceScope.d.ts","sourceRoot":"","sources":["../src/ServiceScope.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAY;IAGX,QAAQ,CAAC,IAAI,EAAE,MAAM;IAFjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEH,IAAI,EAAE,MAAM;CAGlC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceScope = void 0;
4
+ class ServiceScope {
5
+ constructor(name) {
6
+ this.name = name;
7
+ this.symbol = Symbol(name);
8
+ }
9
+ }
10
+ exports.ServiceScope = ServiceScope;
11
+ //# sourceMappingURL=ServiceScope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceScope.js","sourceRoot":"","sources":["../src/ServiceScope.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAY;IAGvB,YAAqB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;CACF;AAND,oCAMC"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './ServiceKey';
2
2
  export * from './ServiceModule';
3
3
  export * from './ServiceFactory';
4
+ export * from './ServiceScope';
4
5
  export * from './utils';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,SAAS,CAAA"}
package/dist/index.js CHANGED
@@ -17,5 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./ServiceKey"), exports);
18
18
  __exportStar(require("./ServiceModule"), exports);
19
19
  __exportStar(require("./ServiceFactory"), exports);
20
+ __exportStar(require("./ServiceScope"), exports);
20
21
  __exportStar(require("./utils"), exports);
21
22
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,kDAAgC;AAChC,mDAAiC;AACjC,0CAAuB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,kDAAgC;AAChC,mDAAiC;AACjC,iDAA8B;AAC9B,0CAAuB"}
@@ -1,4 +1,5 @@
1
1
  import { ServiceKey } from './ServiceKey';
2
+ import { ServiceScope } from './ServiceScope';
2
3
  type ServiceType<T> = T extends ServiceKey<infer U> ? U : never;
3
4
  type DependencyTypes<T extends readonly ServiceKey<unknown>[]> = {
4
5
  [K in keyof T]: ServiceType<T[K]>;
@@ -6,13 +7,15 @@ type DependencyTypes<T extends readonly ServiceKey<unknown>[]> = {
6
7
  export declare abstract class ServiceFactory<const T, const D extends readonly ServiceKey<unknown>[] = []> {
7
8
  abstract provides: ServiceKey<T>;
8
9
  abstract dependsOn: D;
9
- abstract initialize(...dependencies: DependencyTypes<D>): T | Promise<T>;
10
- abstract dispose(instance: T): void;
10
+ abstract scope?: ServiceScope;
11
+ abstract initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>;
12
+ abstract dispose?: () => void;
11
13
  /**
12
14
  * Creates a singleton service factory that ensures a single instance of the provided service is initialized
13
- * and used throughout its lifecycle.
15
+ * and used throughout the scope lifecycle.
14
16
  */
15
- static singleton<const T, const D extends readonly ServiceKey<unknown>[] = []>({ provides, dependsOn, initialize, dispose, }: {
17
+ static singleton<const T, const D extends readonly ServiceKey<unknown>[] = []>({ scope, provides, dependsOn, initialize, dispose, }: {
18
+ scope?: ServiceScope;
16
19
  provides: ServiceKey<T>;
17
20
  dependsOn?: D;
18
21
  initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>;
@@ -22,11 +25,10 @@ export declare abstract class ServiceFactory<const T, const D extends readonly S
22
25
  * Creates a one-shot service factory that initializes a new instance of the provided service
23
26
  * every time it is requested.
24
27
  */
25
- static oneShot<const T, const D extends readonly ServiceKey<unknown>[] = []>({ provides, dependsOn, initialize, dispose, }: {
28
+ static oneShot<const T, const D extends readonly ServiceKey<unknown>[] = []>({ provides, dependsOn, initialize, }: {
26
29
  provides: ServiceKey<T>;
27
30
  dependsOn: D;
28
31
  initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>;
29
- dispose?: (instance: T) => void;
30
32
  }): ServiceFactory<T, D>;
31
33
  }
32
34
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceFactory.d.ts","sourceRoot":"","sources":["../src/ServiceFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,KAAK,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAGhE,KAAK,eAAe,CAAC,CAAC,SAAS,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI;KAC9D,CAAC,IAAI,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAClC,CAAC;AAEF,8BAAsB,cAAc,CAClC,KAAK,CAAC,CAAC,EACP,KAAK,CAAC,CAAC,SAAS,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE;IAEnD,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IAEtB,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAExE,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI;IAEnC;;;OAGG;IACH,MAAM,CAAC,SAAS,CACd,KAAK,CAAC,CAAC,EACP,KAAK,CAAC,CAAC,SAAS,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,EACnD,EACA,QAAQ,EACR,SAA8B,EAC9B,UAAU,EACV,OAAkB,GACnB,EAAE;QACD,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;QACxB,SAAS,CAAC,EAAE,CAAC,CAAC;QACd,UAAU,EAAE,CAAC,GAAG,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACpE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC;KACjC,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;IAsBxB;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,SAAS,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAC3E,QAAQ,EACR,SAAS,EACT,UAAU,EACV,OAAkB,GACnB,EAAE;QACD,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;QACxB,SAAS,EAAE,CAAC,CAAC;QACb,UAAU,EAAE,CAAC,GAAG,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACpE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC;KACjC,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;CAQzB"}
1
+ {"version":3,"file":"ServiceFactory.d.ts","sourceRoot":"","sources":["../src/ServiceFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,KAAK,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAGhE,KAAK,eAAe,CAAC,CAAC,SAAS,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI;KAC9D,CAAC,IAAI,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAClC,CAAC;AAEF,8BAAsB,cAAc,CAClC,KAAK,CAAC,CAAC,EACP,KAAK,CAAC,CAAC,SAAS,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE;IAEnD,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,CAAC,GAAG,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAE9B;;;OAGG;IACH,MAAM,CAAC,SAAS,CACd,KAAK,CAAC,CAAC,EACP,KAAK,CAAC,CAAC,SAAS,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,EACnD,EACA,KAAK,EACL,QAAQ,EACR,SAA8B,EAC9B,UAAU,EACV,OAAkB,GACnB,EAAE;QACD,KAAK,CAAC,EAAE,YAAY,CAAC;QACrB,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;QACxB,SAAS,CAAC,EAAE,CAAC,CAAC;QACd,UAAU,EAAE,CAAC,GAAG,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACpE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC;KACjC,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;IAuBxB;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,SAAS,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAC3E,QAAQ,EACR,SAAS,EACT,UAAU,GACX,EAAE;QACD,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;QACxB,SAAS,EAAE,CAAC,CAAC;QACb,UAAU,EAAE,CAAC,GAAG,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACrE,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;CAOzB"}
@@ -13,25 +13,25 @@ exports.ServiceFactory = void 0;
13
13
  class ServiceFactory {
14
14
  /**
15
15
  * Creates a singleton service factory that ensures a single instance of the provided service is initialized
16
- * and used throughout its lifecycle.
16
+ * and used throughout the scope lifecycle.
17
17
  */
18
- static singleton({ provides, dependsOn = [], initialize, dispose = () => { }, }) {
18
+ static singleton({ scope, provides, dependsOn = [], initialize, dispose = () => { }, }) {
19
19
  let instance;
20
20
  return {
21
+ scope,
21
22
  provides,
22
23
  dependsOn,
23
24
  initialize(...dependencies) {
24
25
  return __awaiter(this, void 0, void 0, function* () {
25
- if (instance) {
26
- return instance;
26
+ if (instance === undefined) {
27
+ instance = yield initialize(...dependencies);
27
28
  }
28
- instance = yield initialize(...dependencies);
29
29
  return instance;
30
30
  });
31
31
  },
32
- dispose(serviceInstance) {
33
- if (instance === serviceInstance) {
34
- dispose(serviceInstance);
32
+ dispose() {
33
+ if (instance !== undefined) {
34
+ dispose(instance);
35
35
  instance = undefined;
36
36
  }
37
37
  },
@@ -41,12 +41,11 @@ class ServiceFactory {
41
41
  * Creates a one-shot service factory that initializes a new instance of the provided service
42
42
  * every time it is requested.
43
43
  */
44
- static oneShot({ provides, dependsOn, initialize, dispose = () => { }, }) {
44
+ static oneShot({ provides, dependsOn, initialize, }) {
45
45
  return {
46
46
  provides,
47
47
  dependsOn,
48
48
  initialize,
49
- dispose,
50
49
  };
51
50
  }
52
51
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceFactory.js","sourceRoot":"","sources":["../src/ServiceFactory.ts"],"names":[],"mappings":";;;;;;;;;;;;AAUA,MAAsB,cAAc;IAWlC;;;OAGG;IACH,MAAM,CAAC,SAAS,CAGd,EACA,QAAQ,EACR,SAAS,GAAG,EAAkB,EAC9B,UAAU,EACV,OAAO,GAAG,GAAG,EAAE,GAAE,CAAC,GAMnB;QACC,IAAI,QAAuB,CAAC;QAE5B,OAAO;YACL,QAAQ;YACR,SAAS;YACH,UAAU,CAAC,GAAG,YAAgC;;oBAClD,IAAI,QAAQ,EAAE,CAAC;wBACb,OAAO,QAAQ,CAAC;oBAClB,CAAC;oBACD,QAAQ,GAAG,MAAM,UAAU,CAAC,GAAG,YAAY,CAAC,CAAC;oBAC7C,OAAO,QAAQ,CAAC;gBAClB,CAAC;aAAA;YACD,OAAO,CAAC,eAAkB;gBACxB,IAAI,QAAQ,KAAK,eAAe,EAAE,CAAC;oBACjC,OAAO,CAAC,eAAe,CAAC,CAAC;oBACzB,QAAQ,GAAG,SAAS,CAAC;gBACvB,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAAO,CAA+D,EAC3E,QAAQ,EACR,SAAS,EACT,UAAU,EACV,OAAO,GAAG,GAAG,EAAE,GAAE,CAAC,GAMnB;QACC,OAAO;YACL,QAAQ;YACR,SAAS;YACT,UAAU;YACV,OAAO;SACR,CAAC;IACJ,CAAC;CACF;AAxED,wCAwEC"}
1
+ {"version":3,"file":"ServiceFactory.js","sourceRoot":"","sources":["../src/ServiceFactory.ts"],"names":[],"mappings":";;;;;;;;;;;;AAWA,MAAsB,cAAc;IAUlC;;;OAGG;IACH,MAAM,CAAC,SAAS,CAGd,EACA,KAAK,EACL,QAAQ,EACR,SAAS,GAAG,EAAkB,EAC9B,UAAU,EACV,OAAO,GAAG,GAAG,EAAE,GAAE,CAAC,GAOnB;QACC,IAAI,QAAuB,CAAC;QAE5B,OAAO;YACL,KAAK;YACL,QAAQ;YACR,SAAS;YACH,UAAU,CAAC,GAAG,YAAgC;;oBAClD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;wBAC3B,QAAQ,GAAG,MAAM,UAAU,CAAC,GAAG,YAAY,CAAC,CAAC;oBAC/C,CAAC;oBAED,OAAO,QAAQ,CAAC;gBAClB,CAAC;aAAA;YACD,OAAO;gBACL,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;oBAC3B,OAAO,CAAC,QAAQ,CAAC,CAAC;oBAClB,QAAQ,GAAG,SAAS,CAAC;gBACvB,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAAO,CAA+D,EAC3E,QAAQ,EACR,SAAS,EACT,UAAU,GAKX;QACC,OAAO;YACL,QAAQ;YACR,SAAS;YACT,UAAU;SACX,CAAC;IACJ,CAAC;CACF;AAvED,wCAuEC"}
@@ -1,6 +1,6 @@
1
1
  export declare class ServiceKey<T> {
2
2
  readonly name: string;
3
- private readonly symbol;
3
+ readonly symbol: symbol;
4
4
  constructor(name: string);
5
5
  }
6
6
  //# sourceMappingURL=ServiceKey.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceKey.d.ts","sourceRoot":"","sources":["../src/ServiceKey.ts"],"names":[],"mappings":"AACA,qBAAa,UAAU,CAAC,CAAC;aAGK,IAAI,EAAE,MAAM;IAFxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEJ,IAAI,EAAE,MAAM;CAGzC"}
1
+ {"version":3,"file":"ServiceKey.d.ts","sourceRoot":"","sources":["../src/ServiceKey.ts"],"names":[],"mappings":"AACA,qBAAa,UAAU,CAAC,CAAC;aAGK,IAAI,EAAE,MAAM;IAFxC,SAAgB,MAAM,EAAE,MAAM,CAAC;gBAEH,IAAI,EAAE,MAAM;CAGzC"}
@@ -1,9 +1,33 @@
1
1
  import { ServiceKey } from './ServiceKey';
2
2
  import { ServiceFactory } from './ServiceFactory';
3
+ import { ServiceScope } from './ServiceScope';
4
+ type GenericFactory = ServiceFactory<unknown, readonly ServiceKey<unknown>[]>;
3
5
  export declare class ServiceModule {
4
- readonly factories: ServiceFactory<any, any>[];
5
- constructor(factories: Set<ServiceFactory<unknown, readonly ServiceKey<unknown>[]>>);
6
+ readonly factories: GenericFactory[];
7
+ private constructor();
6
8
  get<T>(key: ServiceKey<T>): Promise<T>;
7
- static from(entries: (ServiceModule | ServiceFactory<unknown, readonly ServiceKey<unknown>[]>)[]): ServiceModule;
9
+ /**
10
+ * Disposes of service factories within the specified scope or all factories if no scope is provided.
11
+ *
12
+ * This method is useful for cleaning up resources and instances held by service factories,
13
+ * such as singleton factories, as they may hold database connections or other resources that need to be released.
14
+ *
15
+ * @param {ServiceScope} [scope] The scope to filter the factories to be disposed.
16
+ * If not provided, all factories are disposed of.
17
+ * @return {void} No return value.
18
+ */
19
+ dispose(scope?: ServiceScope): void;
20
+ /**
21
+ * Creates a new ServiceModule instance by aggregating and deduplicating a list of
22
+ * ServiceModule or GenericFactory instances.
23
+ * If multiple factories provide the same
24
+ * ServiceKey, the last one in the list takes precedence.
25
+ *
26
+ * @param {Array<ServiceModule | GenericFactory>} entries - An array of ServiceModule or GenericFactory
27
+ * instances to be processed into a single ServiceModule.
28
+ * @return {ServiceModule} A new ServiceModule containing the deduplicated factories.
29
+ */
30
+ static from(entries: (ServiceModule | GenericFactory)[]): ServiceModule;
8
31
  }
32
+ export {};
9
33
  //# sourceMappingURL=ServiceModule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceModule.d.ts","sourceRoot":"","sources":["../src/ServiceModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,qBAAa,aAAa;IACxB,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAM;gBAGlD,SAAS,EAAE,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAS5D,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAqBnD,MAAM,CAAC,IAAI,CACT,OAAO,EAAE,CAAC,aAAa,GAAG,cAAc,CAAC,OAAO,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,GACnF,aAAa;CAajB"}
1
+ {"version":3,"file":"ServiceModule.d.ts","sourceRoot":"","sources":["../src/ServiceModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,KAAK,cAAc,GAAG,cAAc,CAAC,OAAO,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAG9E,qBAAa,aAAa;IACJ,QAAQ,CAAC,SAAS,EAAE,cAAc,EAAE;IAAxD,OAAO;IAOM,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAqBnD;;;;;;;;;OASG;IACI,OAAO,CAAC,KAAK,CAAC,EAAE,YAAY;IAQnC;;;;;;;;;OASG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,aAAa,GAAG,cAAc,CAAC,EAAE,GAAG,aAAa;CAcxE"}
@@ -12,9 +12,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.ServiceModule = void 0;
13
13
  class ServiceModule {
14
14
  constructor(factories) {
15
- this.factories = [];
16
- this.factories = Array.from(factories);
17
- this.factories.forEach((factory) => {
15
+ this.factories = factories;
16
+ factories.forEach((factory) => {
18
17
  checkRecursiveDependencies(factory);
19
18
  checkMissingDependencies(factory, this.factories);
20
19
  });
@@ -36,15 +35,41 @@ class ServiceModule {
36
35
  return factory.initialize(...dependencies);
37
36
  });
38
37
  }
38
+ /**
39
+ * Disposes of service factories within the specified scope or all factories if no scope is provided.
40
+ *
41
+ * This method is useful for cleaning up resources and instances held by service factories,
42
+ * such as singleton factories, as they may hold database connections or other resources that need to be released.
43
+ *
44
+ * @param {ServiceScope} [scope] The scope to filter the factories to be disposed.
45
+ * If not provided, all factories are disposed of.
46
+ * @return {void} No return value.
47
+ */
48
+ dispose(scope) {
49
+ const factories = scope
50
+ ? this.factories.filter((f) => f.scope === scope)
51
+ : this.factories;
52
+ factories.forEach((factory) => { var _a; return (_a = factory.dispose) === null || _a === void 0 ? void 0 : _a.call(factory); });
53
+ }
54
+ /**
55
+ * Creates a new ServiceModule instance by aggregating and deduplicating a list of
56
+ * ServiceModule or GenericFactory instances.
57
+ * If multiple factories provide the same
58
+ * ServiceKey, the last one in the list takes precedence.
59
+ *
60
+ * @param {Array<ServiceModule | GenericFactory>} entries - An array of ServiceModule or GenericFactory
61
+ * instances to be processed into a single ServiceModule.
62
+ * @return {ServiceModule} A new ServiceModule containing the deduplicated factories.
63
+ */
39
64
  static from(entries) {
40
- return new ServiceModule(new Set(entries.flatMap((e) => {
41
- if (e instanceof ServiceModule) {
42
- return e.factories;
43
- }
44
- else {
45
- return [e];
46
- }
47
- })));
65
+ // Flatten entries and keep only the last factory for each ServiceKey
66
+ const flattened = entries.flatMap((e) => e instanceof ServiceModule ? e.factories : [e]);
67
+ const byKey = new Map();
68
+ // Later factories overwrite earlier ones (last-wins)
69
+ for (const f of flattened) {
70
+ byKey.set(f.provides.symbol, f);
71
+ }
72
+ return new ServiceModule(Array.from(byKey.values()));
48
73
  }
49
74
  }
50
75
  exports.ServiceModule = ServiceModule;
@@ -69,9 +94,10 @@ function checkMissingDependencies(factory, factories) {
69
94
  throw new Error(`${factory.provides.name} will fail because it depends on:\n ${dependencyList}`);
70
95
  }
71
96
  function isRegistered(key, factories) {
72
- return factories.some((factory) => factory.provides === key);
97
+ return factories.some((factory) => { var _a; return ((_a = factory.provides) === null || _a === void 0 ? void 0 : _a.symbol) === (key === null || key === void 0 ? void 0 : key.symbol); });
73
98
  }
74
99
  function isSuitable(key, factory) {
75
- return (factory === null || factory === void 0 ? void 0 : factory.provides) === key;
100
+ var _a;
101
+ return ((_a = factory === null || factory === void 0 ? void 0 : factory.provides) === null || _a === void 0 ? void 0 : _a.symbol) === (key === null || key === void 0 ? void 0 : key.symbol);
76
102
  }
77
103
  //# sourceMappingURL=ServiceModule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceModule.js","sourceRoot":"","sources":["../src/ServiceModule.ts"],"names":[],"mappings":";;;;;;;;;;;;AAGA,MAAa,aAAa;IAGxB,YACE,SAAuE;QAHhE,cAAS,GAA+B,EAAE,CAAC;QAKlD,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACjC,0BAA0B,CAAC,OAAO,CAAC,CAAC;YACpC,wBAAwB,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC;IAEY,GAAG,CAAI,GAAkB;;YACpC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC9C,OAAO,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;YAEH,+DAA+D;YAC/D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CAAC,yCAAyC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACvE,CAAC;YAED,iCAAiC;YACjC,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,GAAG,CACpC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,aAAkC,EAAE,EAAE;gBAC3D,OAAO,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACjC,CAAC,CAAC,CACH,CAAC;YAEF,8CAA8C;YAC9C,OAAO,OAAO,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC,CAAC;QAC7C,CAAC;KAAA;IAED,MAAM,CAAC,IAAI,CACT,OAAoF;QAEpF,OAAO,IAAI,aAAa,CACtB,IAAI,GAAG,CACL,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YACpB,IAAI,CAAC,YAAY,aAAa,EAAE,CAAC;gBAC/B,OAAO,CAAC,CAAC,SAAS,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,CAAC,CAAC,CAAC;YACb,CAAC;QACH,CAAC,CAAC,CACH,CACF,CAAC;IACJ,CAAC;CACF;AAjDD,sCAiDC;AAED,SAAS,0BAA0B,CACjC,OAAgE;IAEhE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,EAAE;QACzD,OAAO,aAAa,KAAK,OAAO,CAAC,QAAQ,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,oCAAoC,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAC7D,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAC/B,OAAgE,EAChE,SAAoC;IAEpC,MAAM,mBAAmB,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAClD,CAAC,aAA8B,EAAE,EAAE;QACjC,OAAO,CAAC,YAAY,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACjD,CAAC,CACF,CAAC;IACF,IAAI,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,OAAO;IACT,CAAC;IAED,MAAM,cAAc,GAAG,mBAAmB;SACvC,GAAG,CAAC,CAAC,aAAa,EAAE,EAAE,CAAC,OAAO,aAAa,CAAC,IAAI,EAAE,CAAC;SACnD,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,IAAI,KAAK,CACb,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,uCAAuC,cAAc,EAAE,CAChF,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,GAAwB,EACxB,SAAoC;IAEpC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,UAAU,CACjB,GAAkB,EAClB,OAAmC;IAEnC,OAAO,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,MAAK,GAAG,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"ServiceModule.js","sourceRoot":"","sources":["../src/ServiceModule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=test-from.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-from.d.ts","sourceRoot":"","sources":["../src/test-from.ts"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const ServiceKey_1 = require("./ServiceKey");
13
+ const ServiceFactory_1 = require("./ServiceFactory");
14
+ const ServiceModule_1 = require("./ServiceModule");
15
+ function testLastWinsFlat() {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const Key = new ServiceKey_1.ServiceKey('Value');
18
+ const first = ServiceFactory_1.ServiceFactory.oneShot({
19
+ provides: Key,
20
+ dependsOn: [],
21
+ initialize: () => 1,
22
+ });
23
+ const second = ServiceFactory_1.ServiceFactory.oneShot({
24
+ provides: Key,
25
+ dependsOn: [],
26
+ initialize: () => 2,
27
+ });
28
+ const mod = ServiceModule_1.ServiceModule.from([first, second]);
29
+ const value = yield mod.get(Key);
30
+ if (value !== 2) {
31
+ throw new Error(`Flat last-wins failed: expected 2, got ${value}`);
32
+ }
33
+ });
34
+ }
35
+ function testLastWinsNested() {
36
+ return __awaiter(this, void 0, void 0, function* () {
37
+ const Key = new ServiceKey_1.ServiceKey('Value');
38
+ const first = ServiceFactory_1.ServiceFactory.oneShot({
39
+ provides: Key,
40
+ dependsOn: [],
41
+ initialize: () => 10,
42
+ });
43
+ const second = ServiceFactory_1.ServiceFactory.oneShot({
44
+ provides: Key,
45
+ dependsOn: [],
46
+ initialize: () => 20,
47
+ });
48
+ const a = ServiceModule_1.ServiceModule.from([first]);
49
+ const b = ServiceModule_1.ServiceModule.from([second]);
50
+ const root = ServiceModule_1.ServiceModule.from([a, b]);
51
+ const value = yield root.get(Key);
52
+ if (value !== 20) {
53
+ throw new Error(`Nested last-wins failed: expected 20, got ${value}`);
54
+ }
55
+ });
56
+ }
57
+ function run() {
58
+ return __awaiter(this, void 0, void 0, function* () {
59
+ yield testLastWinsFlat();
60
+ yield testLastWinsNested();
61
+ console.log('All tests passed for ServiceModule.from last-wins behavior.');
62
+ });
63
+ }
64
+ run().catch((err) => {
65
+ console.error(err);
66
+ process.exit(1);
67
+ });
68
+ //# sourceMappingURL=test-from.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-from.js","sourceRoot":"","sources":["../src/test-from.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,6CAA0C;AAC1C,qDAAkD;AAClD,mDAAgD;AAEhD,SAAe,gBAAgB;;QAC7B,MAAM,GAAG,GAAG,IAAI,uBAAU,CAAS,OAAO,CAAC,CAAC;QAE5C,MAAM,KAAK,GAAG,+BAAc,CAAC,OAAO,CAAC;YACnC,QAAQ,EAAE,GAAG;YACb,SAAS,EAAE,EAAE;YACb,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;SACpB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,+BAAc,CAAC,OAAO,CAAC;YACpC,QAAQ,EAAE,GAAG;YACb,SAAS,EAAE,EAAE;YACb,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;SACpB,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,6BAAa,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,0CAA0C,KAAK,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;CAAA;AAED,SAAe,kBAAkB;;QAC/B,MAAM,GAAG,GAAG,IAAI,uBAAU,CAAS,OAAO,CAAC,CAAC;QAE5C,MAAM,KAAK,GAAG,+BAAc,CAAC,OAAO,CAAC;YACnC,QAAQ,EAAE,GAAG;YACb,SAAS,EAAE,EAAE;YACb,UAAU,EAAE,GAAG,EAAE,CAAC,EAAE;SACrB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,+BAAc,CAAC,OAAO,CAAC;YACpC,QAAQ,EAAE,GAAG;YACb,SAAS,EAAE,EAAE;YACb,UAAU,EAAE,GAAG,EAAE,CAAC,EAAE;SACrB,CAAC,CAAC;QAEH,MAAM,CAAC,GAAG,6BAAa,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,6BAAa,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAEvC,MAAM,IAAI,GAAG,6BAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,6CAA6C,KAAK,EAAE,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;CAAA;AAED,SAAe,GAAG;;QAChB,MAAM,gBAAgB,EAAE,CAAC;QACzB,MAAM,kBAAkB,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;IAC7E,CAAC;CAAA;AAED,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAClB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/utils.d.ts CHANGED
@@ -17,10 +17,18 @@ export interface DotGraphOptions {
17
17
  *
18
18
  * Arrows point from dependencies to dependents (from what is needed to what needs it).
19
19
  *
20
- * @param module - The ServiceModule to convert to DOT notation
21
- * @param options - Optional configuration for the graph appearance
22
- * @returns A string containing the DOT notation graph
20
+ * @param {ServiceModule} module - The ServiceModule to convert to DOT notation
21
+ * @param {DotGraphOptions} options - Optional configuration for the graph appearance
22
+ * @returns {string} A string containing the DOT notation graph
23
23
  */
24
24
  export declare function createDotGraph(module: ServiceModule, { direction, title, highlightLeaves, highlightRoots }?: DotGraphOptions): string;
25
- export declare function printDotGraph(module: ServiceModule): void;
25
+ /**
26
+ * Prints a DOT representation of a service module graph to the console.
27
+ * The output can be used to visualize the graph using online graph visualization tools.
28
+ *
29
+ * @param {ServiceModule} module - The service module representing the graph to be converted into DOT format.
30
+ * @param {DotGraphOptions} [options] - Optional configurations to customize the output of the DOT graph.
31
+ * @return {void} - This function does not return a value.
32
+ */
33
+ export declare function printDotGraph(module: ServiceModule, options?: DotGraphOptions): void;
26
34
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,MAAM,WAAW,eAAe;IAC9B,kGAAkG;IAClG,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,0BAA0B;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,yDAAyD;IACzD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AASD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,GAAE,eAKtD,GACA,MAAM,CA6FR;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,QAIlD"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,MAAM,WAAW,eAAe;IAC9B,kGAAkG;IAClG,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,0BAA0B;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,yDAAyD;IACzD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AASD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,GAAE,eAKtD,GACA,MAAM,CA6FR;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,eAAe,GACxB,IAAI,CAIN"}
package/dist/utils.js CHANGED
@@ -16,9 +16,9 @@ function escapeDotString(str) {
16
16
  *
17
17
  * Arrows point from dependencies to dependents (from what is needed to what needs it).
18
18
  *
19
- * @param module - The ServiceModule to convert to DOT notation
20
- * @param options - Optional configuration for the graph appearance
21
- * @returns A string containing the DOT notation graph
19
+ * @param {ServiceModule} module - The ServiceModule to convert to DOT notation
20
+ * @param {DotGraphOptions} options - Optional configuration for the graph appearance
21
+ * @returns {string} A string containing the DOT notation graph
22
22
  */
23
23
  function createDotGraph(module, { direction, title, highlightLeaves, highlightRoots } = {
24
24
  direction: 'TB',
@@ -99,8 +99,16 @@ function createDotGraph(module, { direction, title, highlightLeaves, highlightRo
99
99
  lines.push('}');
100
100
  return lines.join('\n');
101
101
  }
102
- function printDotGraph(module) {
103
- console.log(createDotGraph(module));
102
+ /**
103
+ * Prints a DOT representation of a service module graph to the console.
104
+ * The output can be used to visualize the graph using online graph visualization tools.
105
+ *
106
+ * @param {ServiceModule} module - The service module representing the graph to be converted into DOT format.
107
+ * @param {DotGraphOptions} [options] - Optional configurations to customize the output of the DOT graph.
108
+ * @return {void} - This function does not return a value.
109
+ */
110
+ function printDotGraph(module, options) {
111
+ console.log(createDotGraph(module, options));
104
112
  console.log('\n\nCopy the DOT output above and paste it into:');
105
113
  console.log('https://dreampuf.github.io/GraphvizOnline/');
106
114
  }
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "composed-di",
3
3
  "private": false,
4
- "version": "0.0.6-alpha",
4
+ "version": "0.2.6",
5
5
  "author": "Juan Herrera juanhr454@gmail.com",
6
6
  "type": "commonjs",
7
7
  "main": "./dist/index.js",
@@ -1,4 +1,5 @@
1
1
  import { ServiceKey } from './ServiceKey';
2
+ import { ServiceScope } from './ServiceScope';
2
3
 
3
4
  // Helper types to extract the type from ServiceKey
4
5
  type ServiceType<T> = T extends ServiceKey<infer U> ? U : never;
@@ -14,24 +15,25 @@ export abstract class ServiceFactory<
14
15
  > {
15
16
  abstract provides: ServiceKey<T>;
16
17
  abstract dependsOn: D;
17
-
18
- abstract initialize(...dependencies: DependencyTypes<D>): T | Promise<T>;
19
-
20
- abstract dispose(instance: T): void;
18
+ abstract scope?: ServiceScope;
19
+ abstract initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>;
20
+ abstract dispose?: () => void;
21
21
 
22
22
  /**
23
23
  * Creates a singleton service factory that ensures a single instance of the provided service is initialized
24
- * and used throughout its lifecycle.
24
+ * and used throughout the scope lifecycle.
25
25
  */
26
26
  static singleton<
27
27
  const T,
28
28
  const D extends readonly ServiceKey<unknown>[] = [],
29
29
  >({
30
+ scope,
30
31
  provides,
31
32
  dependsOn = [] as unknown as D,
32
33
  initialize,
33
34
  dispose = () => {},
34
35
  }: {
36
+ scope?: ServiceScope;
35
37
  provides: ServiceKey<T>;
36
38
  dependsOn?: D;
37
39
  initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>;
@@ -40,18 +42,19 @@ export abstract class ServiceFactory<
40
42
  let instance: T | undefined;
41
43
 
42
44
  return {
45
+ scope,
43
46
  provides,
44
47
  dependsOn,
45
48
  async initialize(...dependencies: DependencyTypes<D>): Promise<T> {
46
- if (instance) {
47
- return instance;
49
+ if (instance === undefined) {
50
+ instance = await initialize(...dependencies);
48
51
  }
49
- instance = await initialize(...dependencies);
52
+
50
53
  return instance;
51
54
  },
52
- dispose(serviceInstance: T): void {
53
- if (instance === serviceInstance) {
54
- dispose(serviceInstance);
55
+ dispose(): void {
56
+ if (instance !== undefined) {
57
+ dispose(instance);
55
58
  instance = undefined;
56
59
  }
57
60
  },
@@ -66,18 +69,15 @@ export abstract class ServiceFactory<
66
69
  provides,
67
70
  dependsOn,
68
71
  initialize,
69
- dispose = () => {},
70
72
  }: {
71
73
  provides: ServiceKey<T>;
72
74
  dependsOn: D;
73
75
  initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>;
74
- dispose?: (instance: T) => void;
75
76
  }): ServiceFactory<T, D> {
76
77
  return {
77
78
  provides,
78
79
  dependsOn,
79
80
  initialize,
80
- dispose,
81
81
  };
82
82
  }
83
83
  }
package/src/ServiceKey.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // @ts-ignore
2
2
  export class ServiceKey<T> {
3
- private readonly symbol: symbol;
3
+ public readonly symbol: symbol;
4
4
 
5
5
  constructor(public readonly name: string) {
6
6
  this.symbol = Symbol(name);
@@ -1,102 +1,123 @@
1
- import { ServiceKey } from './ServiceKey';
2
- import { ServiceFactory } from './ServiceFactory';
3
-
4
- export class ServiceModule {
5
- readonly factories: ServiceFactory<any, any>[] = [];
6
-
7
- constructor(
8
- factories: Set<ServiceFactory<unknown, readonly ServiceKey<unknown>[]>>,
9
- ) {
10
- this.factories = Array.from(factories);
11
- this.factories.forEach((factory) => {
12
- checkRecursiveDependencies(factory);
13
- checkMissingDependencies(factory, this.factories);
14
- });
15
- }
16
-
17
- public async get<T>(key: ServiceKey<T>): Promise<T> {
18
- const factory = this.factories.find((factory) => {
19
- return isSuitable(key, factory);
20
- });
21
-
22
- // Check if a factory to supply the requested key was not found
23
- if (!factory) {
24
- throw new Error(`Could not find a suitable factory for ${key.name}`);
25
- }
26
-
27
- // Resolve all dependencies first
28
- const dependencies = await Promise.all(
29
- factory.dependsOn.map((dependencyKey: ServiceKey<unknown>) => {
30
- return this.get(dependencyKey);
31
- }),
32
- );
33
-
34
- // Call the factory to retrieve the dependency
35
- return factory.initialize(...dependencies);
36
- }
37
-
38
- static from(
39
- entries: (ServiceModule | ServiceFactory<unknown, readonly ServiceKey<unknown>[]>)[],
40
- ): ServiceModule {
41
- return new ServiceModule(
42
- new Set(
43
- entries.flatMap((e) => {
44
- if (e instanceof ServiceModule) {
45
- return e.factories;
46
- } else {
47
- return [e];
48
- }
49
- }),
50
- ),
51
- );
52
- }
53
- }
54
-
55
- function checkRecursiveDependencies(
56
- factory: ServiceFactory<unknown, readonly ServiceKey<unknown>[]>,
57
- ) {
58
- const recursive = factory.dependsOn.some((dependencyKey) => {
59
- return dependencyKey === factory.provides;
60
- });
61
-
62
- if (recursive) {
63
- throw new Error(
64
- 'Recursive dependency detected on: ' + factory.provides.name,
65
- );
66
- }
67
- }
68
-
69
- function checkMissingDependencies(
70
- factory: ServiceFactory<unknown, readonly ServiceKey<unknown>[]>,
71
- factories: ServiceFactory<unknown>[],
72
- ) {
73
- const missingDependencies = factory.dependsOn.filter(
74
- (dependencyKey: ServiceKey<any>) => {
75
- return !isRegistered(dependencyKey, factories);
76
- },
77
- );
78
- if (missingDependencies.length === 0) {
79
- return;
80
- }
81
-
82
- const dependencyList = missingDependencies
83
- .map((dependencyKey) => ` -> ${dependencyKey.name}`)
84
- .join('\n');
85
- throw new Error(
86
- `${factory.provides.name} will fail because it depends on:\n ${dependencyList}`,
87
- );
88
- }
89
-
90
- function isRegistered(
91
- key: ServiceKey<unknown>,
92
- factories: ServiceFactory<unknown>[],
93
- ) {
94
- return factories.some((factory) => factory.provides === key);
95
- }
96
-
97
- function isSuitable<T, D extends readonly ServiceKey<unknown>[]>(
98
- key: ServiceKey<T>,
99
- factory: ServiceFactory<unknown, D>,
100
- ): factory is ServiceFactory<T, D> {
101
- return factory?.provides === key;
102
- }
1
+ import { ServiceKey } from './ServiceKey';
2
+ import { ServiceFactory } from './ServiceFactory';
3
+ import { ServiceScope } from './ServiceScope';
4
+
5
+ type GenericFactory = ServiceFactory<unknown, readonly ServiceKey<unknown>[]>;
6
+ type GenericKey = ServiceKey<unknown>;
7
+
8
+ export class ServiceModule {
9
+ private constructor(readonly factories: GenericFactory[]) {
10
+ factories.forEach((factory) => {
11
+ checkRecursiveDependencies(factory);
12
+ checkMissingDependencies(factory, this.factories);
13
+ });
14
+ }
15
+
16
+ public async get<T>(key: ServiceKey<T>): Promise<T> {
17
+ const factory = this.factories.find((factory: GenericFactory) => {
18
+ return isSuitable(key, factory);
19
+ });
20
+
21
+ // Check if a factory to supply the requested key was not found
22
+ if (!factory) {
23
+ throw new Error(`Could not find a suitable factory for ${key.name}`);
24
+ }
25
+
26
+ // Resolve all dependencies first
27
+ const dependencies = await Promise.all(
28
+ factory.dependsOn.map((dependencyKey: ServiceKey<unknown>) => {
29
+ return this.get(dependencyKey);
30
+ }),
31
+ );
32
+
33
+ // Call the factory to retrieve the dependency
34
+ return factory.initialize(...dependencies);
35
+ }
36
+
37
+ /**
38
+ * Disposes of service factories within the specified scope or all factories if no scope is provided.
39
+ *
40
+ * This method is useful for cleaning up resources and instances held by service factories,
41
+ * such as singleton factories, as they may hold database connections or other resources that need to be released.
42
+ *
43
+ * @param {ServiceScope} [scope] The scope to filter the factories to be disposed.
44
+ * If not provided, all factories are disposed of.
45
+ * @return {void} No return value.
46
+ */
47
+ public dispose(scope?: ServiceScope) {
48
+ const factories = scope
49
+ ? this.factories.filter((f) => f.scope === scope)
50
+ : this.factories;
51
+
52
+ factories.forEach((factory) => factory.dispose?.());
53
+ }
54
+
55
+ /**
56
+ * Creates a new ServiceModule instance by aggregating and deduplicating a list of
57
+ * ServiceModule or GenericFactory instances.
58
+ * If multiple factories provide the same
59
+ * ServiceKey, the last one in the list takes precedence.
60
+ *
61
+ * @param {Array<ServiceModule | GenericFactory>} entries - An array of ServiceModule or GenericFactory
62
+ * instances to be processed into a single ServiceModule.
63
+ * @return {ServiceModule} A new ServiceModule containing the deduplicated factories.
64
+ */
65
+ static from(entries: (ServiceModule | GenericFactory)[]): ServiceModule {
66
+ // Flatten entries and keep only the last factory for each ServiceKey
67
+ const flattened = entries.flatMap((e) =>
68
+ e instanceof ServiceModule ? e.factories : [e],
69
+ );
70
+
71
+ const byKey = new Map<symbol, GenericFactory>();
72
+ // Later factories overwrite earlier ones (last-wins)
73
+ for (const f of flattened) {
74
+ byKey.set(f.provides.symbol, f);
75
+ }
76
+
77
+ return new ServiceModule(Array.from(byKey.values()));
78
+ }
79
+ }
80
+
81
+ function checkRecursiveDependencies(factory: GenericFactory) {
82
+ const recursive = factory.dependsOn.some((dependencyKey) => {
83
+ return dependencyKey === factory.provides;
84
+ });
85
+
86
+ if (recursive) {
87
+ throw new Error(
88
+ 'Recursive dependency detected on: ' + factory.provides.name,
89
+ );
90
+ }
91
+ }
92
+
93
+ function checkMissingDependencies(
94
+ factory: GenericFactory,
95
+ factories: GenericFactory[],
96
+ ) {
97
+ const missingDependencies = factory.dependsOn.filter(
98
+ (dependencyKey: GenericKey) => {
99
+ return !isRegistered(dependencyKey, factories);
100
+ },
101
+ );
102
+ if (missingDependencies.length === 0) {
103
+ return;
104
+ }
105
+
106
+ const dependencyList = missingDependencies
107
+ .map((dependencyKey) => ` -> ${dependencyKey.name}`)
108
+ .join('\n');
109
+ throw new Error(
110
+ `${factory.provides.name} will fail because it depends on:\n ${dependencyList}`,
111
+ );
112
+ }
113
+
114
+ function isRegistered(key: GenericKey, factories: GenericFactory[]) {
115
+ return factories.some((factory) => factory.provides?.symbol === key?.symbol);
116
+ }
117
+
118
+ function isSuitable<T, D extends readonly ServiceKey<any>[]>(
119
+ key: ServiceKey<T>,
120
+ factory: ServiceFactory<any, D>,
121
+ ): factory is ServiceFactory<T, D> {
122
+ return factory?.provides?.symbol === key?.symbol;
123
+ }
@@ -0,0 +1,7 @@
1
+ export class ServiceScope {
2
+ readonly symbol: symbol;
3
+
4
+ constructor(readonly name: string) {
5
+ this.symbol = Symbol(name);
6
+ }
7
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './ServiceKey';
2
2
  export * from './ServiceModule';
3
3
  export * from './ServiceFactory';
4
+ export * from './ServiceScope'
4
5
  export * from './utils'
package/src/utils.ts CHANGED
@@ -27,9 +27,9 @@ function escapeDotString(str: string): string {
27
27
  *
28
28
  * Arrows point from dependencies to dependents (from what is needed to what needs it).
29
29
  *
30
- * @param module - The ServiceModule to convert to DOT notation
31
- * @param options - Optional configuration for the graph appearance
32
- * @returns A string containing the DOT notation graph
30
+ * @param {ServiceModule} module - The ServiceModule to convert to DOT notation
31
+ * @param {DotGraphOptions} options - Optional configuration for the graph appearance
32
+ * @returns {string} A string containing the DOT notation graph
33
33
  */
34
34
  export function createDotGraph(
35
35
  module: ServiceModule,
@@ -134,8 +134,19 @@ export function createDotGraph(
134
134
  return lines.join('\n');
135
135
  }
136
136
 
137
- export function printDotGraph(module: ServiceModule) {
138
- console.log(createDotGraph(module));
137
+ /**
138
+ * Prints a DOT representation of a service module graph to the console.
139
+ * The output can be used to visualize the graph using online graph visualization tools.
140
+ *
141
+ * @param {ServiceModule} module - The service module representing the graph to be converted into DOT format.
142
+ * @param {DotGraphOptions} [options] - Optional configurations to customize the output of the DOT graph.
143
+ * @return {void} - This function does not return a value.
144
+ */
145
+ export function printDotGraph(
146
+ module: ServiceModule,
147
+ options?: DotGraphOptions,
148
+ ): void {
149
+ console.log(createDotGraph(module, options));
139
150
  console.log('\n\nCopy the DOT output above and paste it into:');
140
151
  console.log('https://dreampuf.github.io/GraphvizOnline/');
141
152
  }