##// END OF EJS Templates
Fixed container interfaces, separated ServiceContainer
cin -
r144:f97a113c3209 v1.4.0-rc4 default
parent child
Show More
@@ -1,7 +1,6
1 1 import { TraceSource } from "../log/TraceSource";
2 2 import { argumentNotEmptyString } from "../safe";
3 import { Descriptor, ContainerServiceMap, ContainerKeys, TypeOfService, ILifetime } from "./interfaces";
4 import { Container } from "./Container";
3 import { Descriptor, ContainerServiceMap, ContainerKeys, TypeOfService, ILifetime, ServiceContainer } from "./interfaces";
5 4 import { MapOf } from "../interfaces";
6 5
7 6 const trace = TraceSource.get("@implab/core/di/ActivationContext");
@@ -30,7 +29,7 export class ActivationContext<S extends
30 29
31 30 _service: Descriptor<S, any>;
32 31
33 _container: Container<S>;
32 _container: ServiceContainer<S>;
34 33
35 34 _parent: ActivationContext<S> | undefined;
36 35
@@ -42,7 +41,7 export class ActivationContext<S extends
42 41 * @param service the service to activate, this parameter is used for the
43 42 * debug purpose.
44 43 */
45 constructor(container: Container<S>, services: ContainerServiceMap<S>, name: string, service: Descriptor<S, any>) {
44 constructor(container: ServiceContainer<S>, services: ContainerServiceMap<S>, name: string, service: Descriptor<S, any>) {
46 45 this._name = name;
47 46 this._service = service;
48 47 this._visited = {};
@@ -3,13 +3,12 import {
3 3 ActivationType,
4 4 ContainerKeys,
5 5 TypeOfService,
6 ILifetime
6 ILifetime, ServiceContainer
7 7 } from "./interfaces";
8 8
9 9 import { argumentNotEmptyString, isPrimitive, isPromise, delegate, argumentOfType, argumentNotNull, get, primitive } from "../safe";
10 10 import { AggregateDescriptor } from "./AggregateDescriptor";
11 11 import { ValueDescriptor } from "./ValueDescriptor";
12 import { Container } from "./Container";
13 12 import { ReferenceDescriptor } from "./ReferenceDescriptor";
14 13 import { TypeServiceDescriptor } from "./TypeServiceDescriptor";
15 14 import { FactoryServiceDescriptor } from "./FactoryServiceDescriptor";
@@ -149,7 +148,7 export class Configuration<S extends obj
149 148
150 149 _hasInnerDescriptors = false;
151 150
152 readonly _container: Container<S>;
151 readonly _container: ServiceContainer<S>;
153 152
154 153 _path: Array<string>;
155 154
@@ -157,7 +156,7 export class Configuration<S extends obj
157 156
158 157 _require: ModuleResolver | undefined;
159 158
160 constructor(container: Container<S>) {
159 constructor(container: ServiceContainer<S>) {
161 160 argumentNotNull(container, "container");
162 161 this._container = container;
163 162 this._path = [];
@@ -1,11 +1,11
1 1 import { ActivationContext } from "./ActivationContext";
2 2 import { ValueDescriptor } from "./ValueDescriptor";
3 3 import { ActivationError } from "./ActivationError";
4 import { ServiceMap, Descriptor, PartialServiceMap, ServiceLocator, ContainerServiceMap, ContainerKeys, TypeOfService } from "./interfaces";
4 import { ServiceMap, Descriptor, PartialServiceMap, ContainerServiceMap, ContainerKeys, TypeOfService, ServiceContainer } from "./interfaces";
5 5 import { TraceSource } from "../log/TraceSource";
6 6 import { Configuration, RegistrationMap } from "./Configuration";
7 7 import { Cancellation } from "../Cancellation";
8 import { IDestroyable, PromiseOrValue, ICancellation } from "../interfaces";
8 import { IDestroyable, ICancellation } from "../interfaces";
9 9 import { isDescriptor } from "./traits";
10 10 import { LifetimeManager } from "./LifetimeManager";
11 11 import { each, isString } from "../safe";
@@ -14,7 +14,7 import { FluentConfiguration } from "./f
14 14
15 15 const trace = TraceSource.get("@implab/core/di/ActivationContext");
16 16
17 export class Container<S extends object = any> implements ServiceLocator<S>, IDestroyable {
17 export class Container<S extends object = any> implements ServiceContainer<S>, IDestroyable {
18 18 readonly _services: ContainerServiceMap<S>;
19 19
20 20 readonly _lifetimeManager: LifetimeManager;
@@ -91,6 +91,7 export class Container<S extends object
91 91 return this;
92 92 }
93 93
94 /** @deprecated use getLifetimeManager() */
94 95 onDispose(callback: () => void) {
95 96 if (!(callback instanceof Function))
96 97 throw new Error("The callback must be a function");
@@ -134,13 +135,13 export class Container<S extends object
134 135 }
135 136 }
136 137
137 applyConfig<S2 extends object>(config: Promise<{ default: ContainerConfiguration<S2>; }>, ct?: ICancellation): Promise<Container<S & S2>>;
138 applyConfig<S2 extends object, P extends string>(config: Promise<{ [p in P]: ContainerConfiguration<S2>; }>, prop: P, ct?: ICancellation): Promise<Container<S & S2>>;
138 applyConfig<S2 extends object>(config: Promise<{ default: ContainerConfiguration<S2>; }>, ct?: ICancellation): Promise<ServiceContainer<S & S2>>;
139 applyConfig<S2 extends object, P extends string>(config: Promise<{ [p in P]: ContainerConfiguration<S2>; }>, prop: P, ct?: ICancellation): Promise<ServiceContainer<S & S2>>;
139 140 async applyConfig<S2 extends object, P extends string>(
140 141 config: Promise<{ [p in P | "default"]: ContainerConfiguration<S2>; }>,
141 142 propOrCt?: P | ICancellation,
142 143 ct?: ICancellation
143 ): Promise<Container<S & S2>> {
144 ): Promise<ServiceContainer<S & S2>> {
144 145 const mod = await config;
145 146
146 147 let _ct: ICancellation;
@@ -1,8 +1,7
1 1 import { IDestroyable, MapOf } from "../interfaces";
2 import { argumentNotNull, isDestroyable, primitive, isNull, argumentNotEmptyString } from "../safe";
3 import { ILifetime } from "./interfaces";
2 import { argumentNotNull, isDestroyable, argumentNotEmptyString } from "../safe";
3 import { ILifetime, ServiceContainer } from "./interfaces";
4 4 import { ActivationContext } from "./ActivationContext";
5 import { Container } from "./Container";
6 5
7 6 function safeCall(item: () => void) {
8 7 try {
@@ -48,7 +47,7 const unknownLifetime: ILifetime = Objec
48 47
49 48 let nextId = 0;
50 49
51 const singletons: { [k in keyof any]: any; } = {};
50 const singletons: any = {};
52 51
53 52 export class LifetimeManager implements IDestroyable {
54 53 private _cleanup: (() => void)[] = [];
@@ -176,7 +175,7 export class LifetimeManager implements
176 175 };
177 176 }
178 177
179 static containerLifetime(container: Container<any>) {
178 static containerLifetime(container: ServiceContainer<any>) {
180 179 let _lifetime = unknownLifetime;
181 180 return {
182 181 initialize(context: ActivationContext<any>) {
@@ -1,12 +1,11
1 1 import { Resolver, RegistrationBuilder } from "./interfaces";
2 import { Container } from "../Container";
3 import { Descriptor, ILifetime, ActivationType, PartialServiceMap } from "../interfaces";
2 import { Descriptor, ILifetime, ActivationType, PartialServiceMap, ServiceContainer } from "../interfaces";
4 3 import { DescriptorImpl } from "./DescriptorImpl";
5 4 import { LifetimeManager } from "../LifetimeManager";
6 5 import { isString, each, isPrimitive, isPromise, oid } from "../../safe";
7 6
8 7 export class DescriptorBuilder<S extends object, T> {
9 private readonly _container: Container<S>;
8 private readonly _container: ServiceContainer<S>;
10 9 private readonly _cb: (d: Descriptor<S, T>) => void;
11 10
12 11 private readonly _eb: (err: any) => void;
@@ -23,7 +22,7 export class DescriptorBuilder<S extends
23 22
24 23 private _failed = false;
25 24
26 constructor(container: Container<S>, cb: (d: Descriptor<S, T>) => void, eb: (err: any) => void) {
25 constructor(container: ServiceContainer<S>, cb: (d: Descriptor<S, T>) => void, eb: (err: any) => void) {
27 26 this._container = container;
28 27 this._cb = cb;
29 28 this._eb = eb;
@@ -1,8 +1,8
1 import { Container } from "../Container";
2 1 import { argumentNotNull, each, isPrimitive, isPromise } from "../../safe";
3 2 import { DescriptorBuilder } from "./DescriptorBuilder";
4 3 import { RegistrationBuilder, FluentRegistrations, ContainerConfiguration } from "./interfaces";
5 4 import { Cancellation } from "../../Cancellation";
5 import { ServiceContainer } from "../interfaces";
6 6
7 7 export class FluentConfiguration<S extends object, Y extends keyof S = keyof S> {
8 8
@@ -29,13 +29,13 export class FluentConfiguration<S exten
29 29 return this.register(config);
30 30 }
31 31
32 apply<SC extends object>(target: Container<SC>, ct = Cancellation.none) {
32 apply<S2 extends object>(target: ServiceContainer<S2>, ct = Cancellation.none) {
33 33
34 34 let pending = 1;
35 35
36 const _t2 = target as unknown as Container<SC & S>;
36 const _t2 = target as unknown as ServiceContainer<S2 & S>;
37 37
38 return new Promise<Container<SC & S>>((resolve, reject) => {
38 return new Promise<ServiceContainer<S2 & S>>((resolve, reject) => {
39 39 function guard(v: void | Promise<void>) {
40 40 if (isPromise(v))
41 41 v.catch(reject);
@@ -47,7 +47,7 export class FluentConfiguration<S exten
47 47 }
48 48 each(this._builders, (v, k) => {
49 49 pending++;
50 const d = new DescriptorBuilder<SC & S, any>(_t2,
50 const d = new DescriptorBuilder<S2 & S, any>(_t2,
51 51 result => {
52 52 _t2.register(k, result);
53 53 complete();
@@ -1,7 +1,6
1 1 import { primitive } from "../../safe";
2 import { TypeOfService, ContainerKeys, ActivationType, ILifetime } from "../interfaces";
2 import { TypeOfService, ContainerKeys, ActivationType, ILifetime, ServiceContainer } from "../interfaces";
3 3 import { ICancellation } from "../../interfaces";
4 import { Container } from "../Container";
5 4
6 5 export interface DependencyOptions {
7 6 optional?: boolean;
@@ -49,7 +48,7 export interface DescriptorBuilder<S ext
49 48 }
50 49
51 50 export interface ContainerConfiguration<S extends object> {
52 apply<S2 extends object>(target: Container<S2>, ct: ICancellation): Promise<Container<S2 & S>>;
51 apply<S2 extends object>(target: ServiceContainer<S2>, ct?: ICancellation): Promise<ServiceContainer<S2 & S>>;
53 52 }
54 53
55 54 export type RegistrationBuilder<S extends object, T> = (d: DescriptorBuilder<S, T>, ct?: ICancellation) => void | Promise<void>;
@@ -1,4 +1,5
1 1 import { ActivationContext } from "./ActivationContext";
2 import { LifetimeManager } from "./LifetimeManager";
2 3
3 4 export interface Descriptor<S extends object = any, T = any> {
4 5 activate(context: ActivationContext<S>): T;
@@ -26,6 +27,14 export interface ServiceLocator<S extend
26 27 resolve<K extends ContainerKeys<S>>(name: K, def?: TypeOfService<S, K>): TypeOfService<S, K>;
27 28 }
28 29
30 export interface ServiceContainer<S extends object> extends ServiceLocator<S> {
31 getLifetimeManager(): LifetimeManager;
32 register<K extends keyof S>(name: K, service: Descriptor<S, S[K]>): this;
33 register(services: PartialServiceMap<S>): this;
34
35 createChildContainer(): ServiceContainer<S>;
36 }
37
29 38 export interface ContainerProvided<S extends object> {
30 39 container: ServiceLocator<S>;
31 40 }
@@ -20,3 +20,7 export interface ChildServices extends S
20 20
21 21 bar: Bar;
22 22 }
23
24 export interface FooServices {
25 foo: Foo;
26 }
@@ -5,7 +5,8 import { Container } from "../di/Contain
5 5 import { Foo } from "../mock/Foo";
6 6 import { Box } from "../mock/Box";
7 7 import { delay } from "../safe";
8 import { Services } from "../mock/services";
8 import { FooServices, Services } from "../mock/services";
9 import { ContainerConfiguration } from "../di/fluent/interfaces";
9 10
10 11 test("Simple fluent config", async t => {
11 12 const config = fluent<{ host: string; bar: Bar; foo: Foo }>()
@@ -67,3 +68,13 test("Container applyConfig", async t =>
67 68
68 69 t.assert(container.resolve("host"), "Should resolve simple value");
69 70 });
71
72 test("Child container config", async t => {
73 const container = await new Container<{}>().applyConfig(import("../mock/config"));
74
75 const fooServices: ContainerConfiguration<FooServices> = (await import("../mock/config2")).default;
76
77 const child = await fooServices.apply(container.createChildContainer());
78
79 t.assert(child.resolve("foo"), "foo should be resolved");
80 });
General Comments 0
You need to be logged in to leave comments. Login now