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