##// END OF EJS Templates
configuration interfaces moved to di/Configuration module...
cin -
r118:6738ac4c3072 ioc ts support
parent child
Show More
@@ -0,0 +1,7
1 import { isPrimitive } from "../safe";
2 import { Descriptor } from "./interfaces";
3
4 export function isDescriptor(x: any): x is Descriptor {
5 return (!isPrimitive(x)) &&
6 (x.activate instanceof Function);
7 }
@@ -1,19 +1,20
1 import { Descriptor, isDescriptor, Parse } from "./interfaces";
1 import { Descriptor } from "./interfaces";
2 import { ActivationContext } from "./ActivationContext";
2 import { ActivationContext } from "./ActivationContext";
3 import { isPrimitive } from "../safe";
3 import { isPrimitive } from "../safe";
4 import { isDescriptor } from "./traits";
4
5
5 export class AggregateDescriptor<T> implements Descriptor<Parse<T>> {
6 export class AggregateDescriptor<S, T> implements Descriptor<S, T> {
6 _value: T;
7 _value: any;
7
8
8 constructor(value: T) {
9 constructor(value: any) {
9 this._value = value;
10 this._value = value;
10 }
11 }
11
12
12 activate<S>(context: ActivationContext<S>) {
13 activate(context: ActivationContext<S>): T {
13 return this._parse(this._value, context, "$value");
14 return this._parse(this._value, context, "$value");
14 }
15 }
15
16
16 _parse<S, V>(value: V, context: ActivationContext<S>, path: string): Parse<V> {
17 _parse(value: any, context: ActivationContext<S>, path: string): any {
17 if (isPrimitive(value))
18 if (isPrimitive(value))
18 return value as any;
19 return value as any;
19
20
@@ -1,4 +1,5
1 import { Constructor } from "../interfaces";
1 import { Constructor } from "../interfaces";
2 import { primitive } from "../safe";
2
3
3 export interface InjectOptions {
4 export interface InjectOptions {
4 lazy?: boolean;
5 lazy?: boolean;
@@ -14,25 +15,28 interface Lazy<K extends keyof any> exte
14 lazy: true;
15 lazy: true;
15 }
16 }
16
17
17 type Setter<T = any> = (v: T) => void;
18
19 type Compatible<T1, T2> = T1 extends T2 ? any : never;
18 type Compatible<T1, T2> = T1 extends T2 ? any : never;
20
19
21 type ExtractService<K, S> = K extends keyof S ? S[K] : K;
20 type ExtractService<K, S> = K extends keyof S ? S[K] : K;
22
21
23 type ExtractDependency<D, S> = D extends { $dependency: infer K } ? D extends { lazy: true } ? () => ExtractService<K, S> : ExtractService<K, S> : VisitDependency<D, S>;
22 type ExtractDependency<D, S> = D extends { $dependency: infer K } ?
23 D extends { lazy: true } ? () => ExtractService<K, S> : ExtractService<K, S> :
24 WalkDependencies<D, S>;
24
25
25 type VisitDependency<D, S> = D extends {} ? { [K in keyof D]: ExtractDependency<D[K], S> } : D;
26 type WalkDependencies<D, S> = D extends primitive ? D :
27 { [K in keyof D]: ExtractDependency<D[K], S> };
26
28
27 interface Config<S> {
29 interface Services<S> {
28 dependency<K extends keyof S>(name: K): Dependency<K>;
30 get<K extends keyof S>(name: K): Dependency<K>;
29
31
30 lazy<K extends keyof S>(name: K): Lazy<K>;
32 lazy<K extends keyof S>(name: K): Lazy<K>;
31
33
32 build<T>(): Builder<T, S>;
34 build<T extends object>(): Builder<T, S>;
33 }
35 }
34
36
35 export declare function services<S extends object>(): Config<S>;
37 export declare function services<S extends object>(): Services<S>;
38
39 export declare function build<T = never, S = any>(): Builder<T, S>;
36
40
37 export class Builder<T, S> {
41 export class Builder<T, S> {
38 consume<P extends any[]>(...args: P) {
42 consume<P extends any[]>(...args: P) {
@@ -40,13 +44,17 export class Builder<T, S> {
40 };
44 };
41 }
45 }
42
46
43 inject<K extends keyof S>(dependency: K) {
47 inject<P extends any[]>(...args: P) {
44 // K = "bar"
48 // K = "bar"
45 // M = "setValue"
49 // M = "setValue"
46 // S[K] = Bar
50 // S[K] = Bar
47 // T[M] = (value: string) => void
51 // T[M] = (value: string) => void
48 // P[m] = (value: V) => void
52 // P[m] = (value: V) => void
49 return <P, M extends keyof (T | P)>(target: P, memberName: M, descriptor: TypedPropertyDescriptor<Compatible<T[M], Setter<S[K]>>>) => {
53 return <X extends { [m in M]: (...args: any) => any }, M extends keyof (T | X)>(
54 target: X,
55 memberName: M,
56 descriptor: TypedPropertyDescriptor<Compatible<(...args: ExtractDependency<P, S>) => any, T[M]>>
57 ) => {
50
58
51 };
59 };
52 }
60 }
@@ -55,4 +63,13 export class Builder<T, S> {
55 return this as Builder<T2, S>;
63 return this as Builder<T2, S>;
56 }
64 }
57
65
66 get<K extends keyof S>(name: K): Dependency<K> {
67 throw new Error();
58 }
68 }
69
70 lazy<K extends keyof S>(name: K): Lazy<K> {
71 throw new Error();
72 }
73
74
75 }
@@ -1,17 +1,6
1 import {
1 import {
2 ServiceRegistration,
2 PartialServiceMap,
3 TypeRegistration,
3 ActivationType
4 FactoryRegistration,
5 ServiceMap,
6 isDescriptor,
7 isDependencyRegistration,
8 DependencyRegistration,
9 ValueRegistration,
10 ActivationType,
11 isValueRegistration,
12 isTypeRegistration,
13 isFactoryRegistration,
14 PartialServiceMap
15 } from "./interfaces";
4 } from "./interfaces";
16
5
17 import { argumentNotEmptyString, isPrimitive, isPromise, delegate, argumentOfType, argumentNotNull, get } from "../safe";
6 import { argumentNotEmptyString, isPrimitive, isPromise, delegate, argumentOfType, argumentNotNull, get } from "../safe";
@@ -25,7 +14,81 import { TraceSource } from "../log/Trac
25 import { ConfigError } from "./ConfigError";
14 import { ConfigError } from "./ConfigError";
26 import { Cancellation } from "../Cancellation";
15 import { Cancellation } from "../Cancellation";
27 import { makeResolver } from "./ResolverHelper";
16 import { makeResolver } from "./ResolverHelper";
28 import { ICancellation } from "../interfaces";
17 import { ICancellation, Constructor, Factory } from "../interfaces";
18 import { isDescriptor } from "./traits";
19
20 export interface RegistrationScope<S> {
21
22 /** сервисы, которые регистрируются в контексте активации и таким образом
23 * могут переопределять ранее зарегистрированные сервисы. за это свойство
24 * нужно платить, кроме того порядок активации будет влиять на результат
25 * разрешения зависимостей.
26 */
27 services?: PartialServiceMap<S>;
28 }
29
30 /**
31 * Базовый интефейс конфигурации сервисов
32 */
33 export interface ServiceRegistration<T, P, S> extends RegistrationScope<S> {
34
35 activation?: ActivationType;
36
37 params?: P;
38
39 inject?: object | object[];
40
41 cleanup?: ((instance: T) => void) | string;
42 }
43
44 export interface TypeRegistration<T, P extends any[], S> extends ServiceRegistration<T, P, S> {
45 $type: string | (new (...params: P) => T);
46
47 }
48
49 export interface FactoryRegistration<T, P extends any[], S> extends ServiceRegistration<T, P, S> {
50 $factory: string | ( (...params: P) => T);
51 }
52
53 export interface ValueRegistration<T> {
54 $value: T;
55 parse?: boolean;
56 }
57
58 export interface DependencyRegistration<S, K extends keyof S> extends RegistrationScope<S> {
59 $dependency: K;
60 lazy?: boolean;
61 optional?: boolean;
62 default?: S[K];
63 }
64
65 const _activationTypes: { [k in ActivationType]: number; } = {
66 singleton: 1,
67 container: 2,
68 hierarchy: 3,
69 context: 4,
70 call: 5
71 };
72
73 export function isTypeRegistration(x: any): x is TypeRegistration<any, any, any> {
74 return (!isPrimitive(x)) && ("$type" in x);
75 }
76
77 export function isFactoryRegistration(x: any): x is FactoryRegistration<any, any, any> {
78 return (!isPrimitive(x)) && ("$factory" in x);
79 }
80
81 export function isValueRegistration(x: any): x is ValueRegistration<any> {
82 return (!isPrimitive(x)) && ("$value" in x);
83 }
84
85 export function isDependencyRegistration<S>(x: any): x is DependencyRegistration<S, keyof S> {
86 return (!isPrimitive(x)) && ("$dependency" in x);
87 }
88
89 export function isActivationType(x: string): x is ActivationType {
90 return typeof x === "string" && x in _activationTypes;
91 }
29
92
30 const trace = TraceSource.get("@implab/core/di/Configuration");
93 const trace = TraceSource.get("@implab/core/di/Configuration");
31 async function mapAll(data: any[], map?: (v: any, k: number) => any): Promise<any[]>;
94 async function mapAll(data: any[], map?: (v: any, k: number) => any): Promise<any[]>;
@@ -180,7 +243,7 export class Configuration<S> {
180 trace.debug("<{0}", name);
243 trace.debug("<{0}", name);
181 }
244 }
182
245
183 async _visit<T>(data: T, name: string): Promise<any> {
246 async _visit(data: any, name: string): Promise<any> {
184 if (isPrimitive(data) || isDescriptor(data))
247 if (isPrimitive(data) || isDescriptor(data))
185 return data;
248 return data;
186
249
@@ -196,10 +259,10 export class Configuration<S> {
196 return this._visitArray(data, name);
259 return this._visitArray(data, name);
197 }
260 }
198
261
199 return this._visitObject(data as T & object, name);
262 return this._visitObject(data, name);
200 }
263 }
201
264
202 async _visitObject<T extends object>(data: T, name: string) {
265 async _visitObject(data: any, name: string) {
203 if (data.constructor &&
266 if (data.constructor &&
204 data.constructor.prototype !== Object.prototype)
267 data.constructor.prototype !== Object.prototype)
205 return new ValueDescriptor(data);
268 return new ValueDescriptor(data);
@@ -259,30 +322,7 export class Configuration<S> {
259 this._visit(data.params, "params");
322 this._visit(data.params, "params");
260
323
261 if (data.activation) {
324 if (data.activation) {
262 if (typeof (data.activation) === "string") {
325 opts.activation = data.activation;
263 switch (data.activation.toLowerCase()) {
264 case "singleton":
265 opts.activation = ActivationType.Singleton;
266 break;
267 case "container":
268 opts.activation = ActivationType.Container;
269 break;
270 case "hierarchy":
271 opts.activation = ActivationType.Hierarchy;
272 break;
273 case "context":
274 opts.activation = ActivationType.Context;
275 break;
276 case "call":
277 opts.activation = ActivationType.Call;
278 break;
279 default:
280 throw new Error("Unknown activation type: " +
281 data.activation);
282 }
283 } else {
284 opts.activation = Number(data.activation);
285 }
286 }
326 }
287
327
288 if (data.cleanup)
328 if (data.cleanup)
@@ -312,7 +352,7 export class Configuration<S> {
312 return d;
352 return d;
313 }
353 }
314
354
315 async _visitTypeRegistration<T, P>(data: TypeRegistration<T, P, S>, name: string) {
355 async _visitTypeRegistration(data: TypeRegistration<any, any, S>, name: string) {
316 argumentNotNull(data.$type, "data.$type");
356 argumentNotNull(data.$type, "data.$type");
317 this._enter(name);
357 this._enter(name);
318
358
@@ -324,7 +364,7 export class Configuration<S> {
324 opts.type = this._resolveType(moduleName, typeName);
364 opts.type = this._resolveType(moduleName, typeName);
325 }
365 }
326
366
327 const d = new TypeServiceDescriptor(
367 const d = new TypeServiceDescriptor<S, any, any[]>(
328 await mapAll(opts)
368 await mapAll(opts)
329 );
369 );
330
370
@@ -333,14 +373,14 export class Configuration<S> {
333 return d;
373 return d;
334 }
374 }
335
375
336 async _visitFactoryRegistration<T, P>(data: FactoryRegistration<T, P, S>, name: string) {
376 async _visitFactoryRegistration(data: FactoryRegistration<any, any, S>, name: string) {
337 argumentOfType(data.$factory, Function, "data.$factory");
377 argumentOfType(data.$factory, Function, "data.$factory");
338 this._enter(name);
378 this._enter(name);
339
379
340 const opts = this._makeServiceParams(data);
380 const opts = this._makeServiceParams(data);
341 opts.factory = data.$factory;
381 opts.factory = data.$factory;
342
382
343 const d = new FactoryServiceDescriptor(
383 const d = new FactoryServiceDescriptor<S, any, any[]>(
344 await mapAll(opts)
384 await mapAll(opts)
345 );
385 );
346
386
@@ -1,16 +1,17
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 { isDescriptor, ServiceMap, Descriptor, PartialServiceMap, ContainerServices, Resolver } from "./interfaces";
4 import { ServiceMap, Descriptor, PartialServiceMap, ContainerServices, Resolver } from "./interfaces";
5 import { TraceSource } from "../log/TraceSource";
5 import { TraceSource } from "../log/TraceSource";
6 import { Configuration } from "./Configuration";
6 import { Configuration } from "./Configuration";
7 import { Cancellation } from "../Cancellation";
7 import { Cancellation } from "../Cancellation";
8 import { MapOf } from "../interfaces";
8 import { MapOf } from "../interfaces";
9 import { isDescriptor } from "./traits";
9
10
10 const trace = TraceSource.get("@implab/core/di/ActivationContext");
11 const trace = TraceSource.get("@implab/core/di/ActivationContext");
11
12
12 export class Container<S = any> implements Resolver<S> {
13 export class Container<S = any> implements Resolver<S> {
13 readonly _services: PartialServiceMap<S, ContainerServices<S>>;
14 readonly _services: PartialServiceMap<ContainerServices<S>>;
14
15
15 readonly _cache: MapOf<any>;
16 readonly _cache: MapOf<any>;
16
17
@@ -1,6 +1,5
1 import { ServiceDescriptor, ServiceDescriptorParams } from "./ServiceDescriptor";
1 import { ServiceDescriptor, ServiceDescriptorParams } from "./ServiceDescriptor";
2 import { argumentNotNull, oid } from "../safe";
2 import { argumentNotNull, oid } from "../safe";
3 import { ActivationType } from "./interfaces";
4
3
5 export interface FactoryServiceDescriptorParams<S, T, P extends any[]> extends ServiceDescriptorParams<S, T, P> {
4 export interface FactoryServiceDescriptorParams<S, T, P extends any[]> extends ServiceDescriptorParams<S, T, P> {
6 factory: (...args: P) => T;
5 factory: (...args: P) => T;
@@ -15,7 +14,7 export class FactoryServiceDescriptor<S,
15 // bind to null
14 // bind to null
16 this._factory = (...args) => opts.factory.apply(null, args as any);
15 this._factory = (...args) => opts.factory.apply(null, args as any);
17
16
18 if (opts.activation === ActivationType.Singleton) {
17 if (opts.activation === "singleton") {
19 this._cacheId = oid(opts.factory);
18 this._cacheId = oid(opts.factory);
20 }
19 }
21 }
20 }
@@ -26,7 +26,7 export class ReferenceDescriptor<S = any
26
26
27 _default: S[K] | undefined;
27 _default: S[K] | undefined;
28
28
29 _services: ServiceMap<S>;
29 _services: PartialServiceMap<S>;
30
30
31 constructor(opts: ReferenceDescriptorParams<S, K>) {
31 constructor(opts: ReferenceDescriptorParams<S, K>) {
32 argumentNotEmptyString(opts && opts.name, "opts.name");
32 argumentNotEmptyString(opts && opts.name, "opts.name");
@@ -53,7 +53,7 export class ReferenceDescriptor<S = any
53 const ct = saved.clone();
53 const ct = saved.clone();
54 try {
54 try {
55 if (cfg) {
55 if (cfg) {
56 each(cfg as ServiceMap<S>, (v, k) => ct.register(k, v));
56 each(cfg, (v, k) => ct.register(k, v));
57 }
57 }
58
58
59 return this._optional ? ct.resolve(this._name, this._default) : ct
59 return this._optional ? ct.resolve(this._name, this._default) : ct
@@ -1,8 +1,9
1 import { ActivationContext } from "./ActivationContext";
1 import { ActivationContext } from "./ActivationContext";
2 import { Descriptor, ActivationType, ServiceMap, isDescriptor, Parse, PartialServiceMap } from "./interfaces";
2 import { Descriptor, ServiceMap, PartialServiceMap, ActivationType } from "./interfaces";
3 import { Container } from "./Container";
3 import { Container } from "./Container";
4 import { argumentNotNull, isPrimitive, each, keys, isNull } from "../safe";
4 import { argumentNotNull, isPrimitive, keys, isNull } from "../safe";
5 import { TraceSource } from "../log/TraceSource";
5 import { TraceSource } from "../log/TraceSource";
6 import { isDescriptor } from "./traits";
6
7
7 let cacheId = 0;
8 let cacheId = 0;
8
9
@@ -33,7 +34,7 function makeClenupCallback(target: any,
33 }
34 }
34 }
35 }
35
36
36 function _parse<T, S>(value: T, context: ActivationContext<S>, path: string): Parse<T> {
37 function _parse(value: any, context: ActivationContext<any>, path: string): any {
37 if (isPrimitive(value))
38 if (isPrimitive(value))
38 return value as any;
39 return value as any;
39
40
@@ -77,7 +78,7 export class ServiceDescriptor<S, T, P e
77
78
78 _hasInstance = false;
79 _hasInstance = false;
79
80
80 _activationType = ActivationType.Call;
81 _activationType: ActivationType = "call";
81
82
82 _services: ServiceMap<S>;
83 _services: ServiceMap<S>;
83
84
@@ -125,7 +126,7 export class ServiceDescriptor<S, T, P e
125 this._cacheId = ++cacheId;
126 this._cacheId = ++cacheId;
126
127
127 switch (this._activationType) {
128 switch (this._activationType) {
128 case ActivationType.Singleton: // SINGLETON
129 case "singleton": // SINGLETON
129 // if the value is cached return it
130 // if the value is cached return it
130 if (this._hasInstance)
131 if (this._hasInstance)
131 return this._instance;
132 return this._instance;
@@ -146,7 +147,7 export class ServiceDescriptor<S, T, P e
146 this._hasInstance = true;
147 this._hasInstance = true;
147 return (this._instance = instance);
148 return (this._instance = instance);
148
149
149 case ActivationType.Container: // CONTAINER
150 case "container": // CONTAINER
150 // return a cached value
151 // return a cached value
151
152
152 if (this._hasInstance)
153 if (this._hasInstance)
@@ -163,17 +164,17 export class ServiceDescriptor<S, T, P e
163 // cache and return the instance
164 // cache and return the instance
164 this._hasInstance = true;
165 this._hasInstance = true;
165 return (this._instance = instance);
166 return (this._instance = instance);
166 case ActivationType.Context: // CONTEXT
167 case "context": // CONTEXT
167 // return a cached value if one exists
168 // return a cached value if one exists
168
169
169 if (context.has(this._cacheId))
170 if (context.has(this._cacheId))
170 return context.get(this._cacheId);
171 return context.get(this._cacheId);
171 // context context activated instances are controlled by callers
172 // context context activated instances are controlled by callers
172 return context.store(this._cacheId, this._create(context));
173 return context.store(this._cacheId, this._create(context));
173 case ActivationType.Call: // CALL
174 case "call": // CALL
174 // per-call created instances are controlled by callers
175 // per-call created instances are controlled by callers
175 return this._create(context);
176 return this._create(context);
176 case ActivationType.Hierarchy: // HIERARCHY
177 case "hierarchy": // HIERARCHY
177 // hierarchy activated instances are behave much like container activated
178 // hierarchy activated instances are behave much like container activated
178 // except they are created and bound to the child container
179 // except they are created and bound to the child container
179
180
@@ -209,7 +210,7 export class ServiceDescriptor<S, T, P e
209 _create(context: ActivationContext<S>) {
210 _create(context: ActivationContext<S>) {
210 trace.debug(`constructing ${context._name}`);
211 trace.debug(`constructing ${context._name}`);
211
212
212 if (this._activationType !== ActivationType.Call &&
213 if (this._activationType !== "call" &&
213 context.visit(this._cacheId) > 0)
214 context.visit(this._cacheId) > 0)
214 throw new Error("Recursion detected");
215 throw new Error("Recursion detected");
215
216
@@ -1,68 +1,16
1 import { isPrimitive, primitive } from "../safe";
2 import { ActivationContext } from "./ActivationContext";
1 import { ActivationContext } from "./ActivationContext";
3 import { Constructor, Factory } from "../interfaces";
4
2
5 export interface Descriptor<S = any, T = any> {
3 export interface Descriptor<S = any, T = any> {
6 activate(context: ActivationContext<S>): T;
4 activate(context: ActivationContext<S>): T;
7 }
5 }
8
6
9 export function isDescriptor(x: any): x is Descriptor {
7 export type ServiceMap<S> = {
10 return (!isPrimitive(x)) &&
8 [k in keyof S]: Descriptor<S, S[k]>;
11 (x.activate instanceof Function);
12 }
13
14 export type ServiceMap<S, S2 extends S = S> = {
15 [k in keyof S2]: Descriptor<S, S2[k]>;
16 };
9 };
17
10
18 export type PartialServiceMap<S, S2 extends S = S> = Partial<ServiceMap<S, S2>>;
11 export type PartialServiceMap<S> = {
19
12 [k in keyof S]?: Descriptor<S, S[k]>;
20 export enum ActivationType {
13 };
21 Singleton = 1,
22 Container,
23 Hierarchy,
24 Context,
25 Call
26 }
27
28 export interface RegistrationWithServices<S> {
29 services?: ServiceMap<S>;
30 }
31
32 export interface ServiceRegistration<T, P, S> extends RegistrationWithServices<S> {
33
34 activation?: "singleton" | "container" | "hierarchy" | "context" | "call";
35
36 params?: P;
37
38 inject?: object | object[];
39
40 cleanup?: ((instance: T) => void) | string;
41 }
42
43 export interface TypeRegistration<T, P, S> extends ServiceRegistration<T, P, S> {
44 $type: string | Constructor<T>;
45 }
46
47 export interface FactoryRegistration<T, P, S> extends ServiceRegistration<T, P, S> {
48 $factory: string | Factory<T>;
49 }
50
51 export interface ValueRegistration<T> {
52 $value: T;
53 parse?: boolean;
54 }
55
56 export interface DependencyRegistration<S, K extends keyof S> extends RegistrationWithServices<S> {
57 $dependency: K;
58 lazy?: boolean;
59 optional?: boolean;
60 default?: S[K];
61 }
62
63 export type Parse<T> = T extends primitive ? T:
64 T extends Descriptor<infer V> ? V :
65 { [K in keyof T]: Parse<T[K]> };
66
14
67 export interface Resolver<S> {
15 export interface Resolver<S> {
68 resolve<K extends keyof ContainerServices<S>, T extends ContainerServices<S>[K] = ContainerServices<S>[K]>(name: K, def?: T): T;
16 resolve<K extends keyof ContainerServices<S>, T extends ContainerServices<S>[K] = ContainerServices<S>[K]>(name: K, def?: T): T;
@@ -70,19 +18,4 export interface Resolver<S> {
70 export type ContainerServices<S> = S & {
18 export type ContainerServices<S> = S & {
71 container: Resolver<S>;
19 container: Resolver<S>;
72 };
20 };
73
21 export type ActivationType = "singleton" | "container" | "hierarchy" | "context" | "call";
74 export function isTypeRegistration(x: any): x is TypeRegistration<any, any, any> {
75 return (!isPrimitive(x)) && ("$type" in x);
76 }
77
78 export function isFactoryRegistration(x: any): x is FactoryRegistration<any, any, any> {
79 return (!isPrimitive(x)) && ("$factory" in x);
80 }
81
82 export function isValueRegistration(x: any): x is ValueRegistration<any> {
83 return (!isPrimitive(x)) && ("$value" in x);
84 }
85
86 export function isDependencyRegistration<S>(x: any): x is DependencyRegistration<S, keyof S> {
87 return (!isPrimitive(x)) && ("$dependency" in x);
88 }
@@ -1,22 +1,22
1 import { Foo } from "./Foo";
1 import { Foo } from "./Foo";
2 // import { config } from "./config";
2 import { build } from "./config";
3
3
4 // const service = config.build("bar");
4 const service = build<Bar>();
5
5
6 // @service.consume({
6 @service.consume({
7 // f: config.dependency("foo"),
7 foo: service.get("foo"),
8 // nested: {
8 nested: {
9 // lazy: config.lazy("foo")
9 lazy: service.lazy("foo")
10 // }
10 }
11 // })
11 })
12 export class Bar {
12 export class Bar {
13 barName = "bar";
13 barName = "bar";
14
14
15 _v: Foo | undefined;
15 _v: Foo | undefined;
16
16
17 constructor(_opts: {
17 constructor(_opts?: {
18 foo: Foo;
18 foo?: Foo;
19 nested: {
19 nested?: {
20 lazy: () => Foo
20 lazy: () => Foo
21 }
21 }
22 }) {
22 }) {
@@ -1,15 +1,17
1 import { services } from "../di/Annotations";
1 import { services } from "../di/Annotations";
2 import { Bar } from "./Bar";
2 import { Bar } from "./Bar";
3 import { Foo } from "./Foo";
3
4
4 // declare required dependencies
5 // declare required dependencies
5 const config = services<{
6 const config = services<{
6 bar: Bar;
7 bar: Bar;
8 foo: Foo;
7 }>();
9 }>();
8
10
9 // export service descriptor
11 // export service descriptor
10 export const service = config.build<Box<Bar>>();
12 export const service = config.build<Box<Bar>>();
11
13
12 @service.consume(config.dependency("bar"))
14 @service.consume(config.get("bar"))
13 export class Box<T> {
15 export class Box<T> {
14 private _value: T | undefined;
16 private _value: T | undefined;
15
17
@@ -17,9 +19,10 export class Box<T> {
17 this._value = value;
19 this._value = value;
18 }
20 }
19
21
20 // @service.inject("bar")
22 @service.inject( config.get("bar"))
21 setValue(value: T) {
23 setValue(value?: T) {
22 this._value = value;
24 this._value = value;
25 return value;
23 }
26 }
24
27
25 setObj(value: object) {
28 setObj(value: object) {
@@ -1,8 +1,7
1 import { Foo } from "./Foo";
1 import { Foo } from "./Foo";
2 import { Bar } from "./Bar";
2 import { Bar } from "./Bar";
3 import { Box } from "./Box";
3 import { Box } from "./Box";
4 import { primitive } from "../safe";
4 import { Builder } from "../di/Annotations";
5 import { Constructor } from "../interfaces";
6
5
7 interface Services {
6 interface Services {
8 foo: Foo;
7 foo: Foo;
@@ -15,24 +14,14 interface Services {
15
14
16 }
15 }
17
16
18 interface TypeDescriptor<T, C extends Constructor<T>> {
17 const services = {
19 $type: C;
18 build: <T>() => {
19 return new Builder<T, Services>();
20 }
21 };
20
22
21 params: Wrap<ConstructorParameters<C>>;
23 namespace services {
22 }
23
24
24 function typeRegistration<T, C extends Constructor<T>>(target: C, params: Wrap<ConstructorParameters<C>>): TypeDescriptor<T, C> {
25 throw new Error();
26 }
25 }
27
26
28 declare function register<T>(): { type<C extends Constructor<T>>(target: C, params: Wrap<ConstructorParameters<C>>): TypeDescriptor<T, C>};
27 export = services;
29
30 type Wrap<T> = T extends primitive ? T :
31 { [k in keyof T]: Wrap<T[k]> } | TypeDescriptor<T, Constructor<T>>;
32
33 const config: Wrap<Services> = {
34 foo: typeRegistration(Foo, []),
35 bar: typeRegistration(Bar, [{ foo: null as any, nested: null as any }]),
36 box: register<Box<Foo>>().type(Box, [{ $type: Bar, params: [] }]),
37 host: ""
38 };
@@ -91,4 +91,5 test("Load configuration from module", a
91
91
92 t.assert(!isNull(b1), "bar should not be null");
92 t.assert(!isNull(b1), "bar should not be null");
93 t.assert(!isNull(b1._v), "bar.foo should not be null");
93 t.assert(!isNull(b1._v), "bar.foo should not be null");
94
94 });
95 });
General Comments 0
You need to be logged in to leave comments. Login now