##// END OF EJS Templates
Removed ContextResolver, added DescriptoBuilder.wants(...), dependencies are declared statically
cin -
r4:d9e74143f779 default
parent child
Show More
@@ -1,41 +1,41
1 1 export interface ActivationItem {
2 2 name: string;
3 3 service: string;
4 4 }
5 5
6 6 export class ActivationError {
7 activationStack: ActivationItem[];
7 readonly activationStack: ActivationItem[];
8 8
9 service: string;
9 readonly service: string;
10 10
11 innerException: unknown;
11 readonly innerException: unknown;
12 12
13 message: string;
13 readonly message: string;
14 14
15 15 constructor(service: string, activationStack: ActivationItem[], innerException: unknown) {
16 16 this.message = "Failed to activate the service";
17 17 this.activationStack = activationStack;
18 18 this.service = service;
19 19 this.innerException = innerException;
20 20 }
21 21
22 22 toString() {
23 23 const parts = [this.message];
24 24 if (this.service)
25 25 parts.push(`when activating: ${String(this.service)}`);
26 26
27 27 if (this.innerException)
28 28 parts.push(`caused by: ${String(this.innerException)}`);
29 29
30 30 if (this.activationStack) {
31 31 parts.push("at");
32 32 parts.push.apply(null,
33 33 this.activationStack
34 34 .map(({ name, service }) => ` ${name} ${service}`)
35 35 );
36 36
37 37 }
38 38
39 39 return parts.join("\n");
40 40 }
41 41 }
@@ -1,169 +1,196
1 import { Resolver, RegistrationBuilder, LifetimeContainer, ConfigurableKeys } from "./interfaces";
1 import { RegistrationBuilder, LifetimeContainer, ConfigurableKeys, IDescriptorBuilder, Ref, Resolved, DepsMap } from "./interfaces";
2 2 import { Descriptor, ILifetime, ActivationType } from "./interfaces";
3 3 import { DescriptorImpl, RegistrationOverridesMap } from "./DescriptorImpl";
4 4 import { LifetimeManager } from "./LifetimeManager";
5 import { each, isKey, isPromise, isString, oid } from "./traits";
5 import { each, isKey, isPromise, isString, key, oid } from "./traits";
6 6
7 7 /**
8 8 * @template {S} Карта доступных зависимостей, как правило `ContainerServices`
9 9 * @template {T} Тип сервиса
10 10 */
11 export class DescriptorBuilder<S extends object, T> {
11 export class DescriptorBuilder<S extends object, T, R extends object = object> implements IDescriptorBuilder<S, T, R> {
12 12 private readonly _lifetimeContainer: LifetimeContainer;
13 13 private readonly _cb: (d: Descriptor<S, T>) => void;
14 14
15 15 private readonly _eb: (err: unknown) => void;
16 16
17 private readonly _refs: DepsMap<key, keyof S>;
18
17 19 private _lifetime = LifetimeManager.empty<T>();
18 20
19 21 private _overrides: RegistrationOverridesMap<S>;
20 22
21 23 private _cleanup?: (item: T) => void;
22 24
23 private _factory?: (resolve: Resolver<S>) => T;
25 private _factory?: (refs: R) => T;
24 26
25 27 private _pending = 1;
26 28
27 29 private _failed = false;
28 30
29 31 private _finalized = false;
30 32
31 33 /**
32 34 * Creates new DescriptorBuilder. Accepts a lifetime container for resolving "container"
33 35 * lifetime.
34 36 *
35 37 * @param container The lifetime container is the container where the service is to be registered.
36 38 * @param cb The callback to receive the built service descriptor
37 39 * @param eb The callback to receive the error due
38 40 */
39 41 constructor(container: LifetimeContainer, cb: (d: Descriptor<S, T>) => void, eb: (err: unknown) => void) {
40 42 this._lifetimeContainer = container;
41 43 this._cb = cb;
42 44 this._eb = eb;
43 45 this._overrides = {};
46 this._refs = {};
44 47 }
48 wants<X extends { [k in Exclude<key, keyof R>]: keyof S | Ref<keyof S, boolean, unknown>; }>(refs: X):
49 IDescriptorBuilder<S, T, R & {
50 [k in keyof X]:
51 X[k] extends keyof S ? NonNullable<S[X[k]]> :
52 X[k] extends Ref<infer K, infer L, infer D> ? Resolved<S, K & keyof S, L, D> :
53 never;
54 }> {
55
56 each(refs, (v, k) => this._refs[k] = v);
57
58 return this as IDescriptorBuilder<S, T, R & {
59 [k in keyof X]:
60 X[k] extends keyof S ? NonNullable<S[X[k]]> :
61 X[k] extends Ref<infer K, infer L, infer D> ? Resolved<S, K & keyof S, L, D> :
62 never;
63 }>;
64 }
65 factory(f: (refs: R) => T): void {
66 this._assertBuilding();
67 this._factory = f;
68 this._finalize();
69 this._complete();
70 }
71
45 72
46 73 private _assertBuilding() {
47 74 if (this._finalized)
48 75 throw new Error("The descriptor builder is finalized");
49 76 }
50 77
51 78 private _finalize() {
52 79 this._finalized = true;
53 80 }
54 81
55 82 override<K extends ConfigurableKeys<S>>(name: K, builder: RegistrationBuilder<S, NonNullable<S[K]>>): this;
56 83 override<K extends ConfigurableKeys<S>>(services: { [k in K]: RegistrationBuilder<S, NonNullable<S[k]>> }): this;
57 84 override<K extends ConfigurableKeys<S>>(nameOrServices: K | { [name in K]: RegistrationBuilder<S, NonNullable<S[K]>> }, builder?: RegistrationBuilder<S, NonNullable<S[K]>>): this {
58 85 this._assertBuilding();
59 86 const guard = (v: void | Promise<void>) => {
60 87 if (isPromise(v))
61 88 v.catch(err => this._fail(err));
62 89 };
63 90
64 91 if (isKey(nameOrServices)) {
65 92 if (builder) {
66 93 this._defer();
67 94 const d = new DescriptorBuilder<S, NonNullable<S[K]>>(
68 95 this._lifetimeContainer,
69 96 result => {
70 97 this._overrides[nameOrServices] = result;
71 98 this._complete();
72 99 },
73 100 err => this._fail(err)
74 101 );
75 102
76 103 try {
77 104 guard(builder(d));
78 105 } catch (err) {
79 106 this._fail(err);
80 107 }
81 108 }
82 109 } else {
83 110 each(nameOrServices, (v, k) => this.override(k, v));
84 111 }
85 112 return this;
86 113 }
87 114
88 115 lifetime(lifetime: "singleton", typeId: string): this;
89 116 lifetime(lifetime: ILifetime<T> | Exclude<ActivationType, "singleton">): this;
90 117 lifetime(lifetime: ILifetime<T> | ActivationType, typeId?: string): this {
91 118 this._assertBuilding();
92 119 if (isString(lifetime)) {
93 120 this._lifetime = this._resolveLifetime(lifetime, typeId);
94 121 } else {
95 122 this._lifetime = lifetime;
96 123 }
97 124 return this;
98 125 }
99 126
100 127 cleanup(cb: (item: T) => void): this {
101 128 this._assertBuilding();
102 129 this._cleanup = cb;
103 130 return this;
104 131 }
105 132
106 factory(f: (resolve: Resolver<S>) => T): void {
133 /*factory(f: (resolve: Resolver<S>) => T): void {
107 134 this._assertBuilding();
108 135 this._factory = f;
109 136 this._finalize();
110 137 this._complete();
111 }
138 }*/
112 139
113 140 value(v: T): void {
114 141 this._assertBuilding();
115 142 this._cb({
116 143 activate() {
117 144 return v;
118 145 }
119 146 });
120 147 this._finalize();
121 148 }
122 149
123 150 _resolveLifetime<T>(activation: ActivationType, typeId?: string | object): ILifetime<T> {
124 151 switch (activation) {
125 152 case "container":
126 153 return LifetimeManager.containerLifetime(this._lifetimeContainer);
127 154 case "hierarchy":
128 155 return LifetimeManager.hierarchyLifetime();
129 156 case "context":
130 157 return LifetimeManager.contextLifetime();
131 158 case "singleton": {
132 159 if (!typeId)
133 160 throw Error("The singleton activation requires a typeId");
134 161
135 162 const _oid = isString(typeId) ? typeId : oid(typeId);
136 163
137 164 return LifetimeManager.singletonLifetime(_oid);
138 165 }
139 166 default:
140 167 return LifetimeManager.empty();
141 168 }
142 169 }
143 170
144 171 _defer() {
145 172 this._pending++;
146 173 }
147 174
148 175 _complete() {
149 176 if (--this._pending === 0) {
150 177 if (!this._factory)
151 178 throw new Error("The factory must be specified");
152 179
153 180 this._cb(new DescriptorImpl<S, T>({
154 181 lifetime: this._lifetime,
155 182 factory: this._factory,
156 183 overrides: this._overrides,
157 184 cleanup: this._cleanup
158 185 }));
159 186 }
160 187 }
161 188
162 189 _fail(err: unknown) {
163 190 if (!this._failed) {
164 191 this._failed = true;
165 192 this._eb.call(undefined, err);
166 193 }
167 194 }
168 195
169 196 }
@@ -1,63 +1,83
1 import { Descriptor, ILifetime, ConfigurableKeys, Resolver } from "./interfaces";
1 import { Descriptor, ILifetime, ConfigurableKeys, DepsMap, Ref } from "./interfaces";
2 2 import { ActivationContext } from "./ActivationContext";
3 import { ContextResolver } from "./ContextResolver";
4 import { each } from "./traits";
3 import { each, isKey, key } from "./traits";
5 4
6 5 export type RegistrationOverridesMap<S extends object> = { [k in ConfigurableKeys<S>]?: Descriptor<S, NonNullable<S[k]>> };
7 6
8 7 export interface DescriptorImplArgs<S extends object, T> {
9 8 lifetime: ILifetime<T>;
10 9
11 factory: (resolve: Resolver<S>) => T;
10 factory: (refs: Record<key, never>) => T;
12 11
13 12 cleanup?: (item: T) => void;
14 13
15 14 overrides?: RegistrationOverridesMap<S>;
15
16 dependencies?: DepsMap<key, keyof S>;
16 17 }
17 18
18 19
19 20 export class DescriptorImpl<S extends object, T> implements Descriptor<S, T> {
20 21
21 22 private readonly _overrides?: RegistrationOverridesMap<S>;
22 23
23 24 private readonly _lifetime: ILifetime<T>;
24 25
25 private readonly _factory: (resolve: Resolver<S>) => T;
26 private readonly _factory: (refs: Record<key, never>) => T;
26 27
27 28 private readonly _cleanup?: (item: T) => void;
28 29
29 constructor(args: DescriptorImplArgs<S, T>) {
30 this._lifetime = args.lifetime;
31 this._factory = args.factory;
32 if (args.cleanup)
33 this._cleanup = args.cleanup;
34 if (args.overrides)
35 this._overrides = args.overrides;
30 private readonly _deps?: DepsMap<key, keyof S>;
31
32 constructor({ lifetime, factory, cleanup, overrides, dependencies }: DescriptorImplArgs<S, T>) {
33 this._lifetime = lifetime;
34 this._factory = factory;
35 if (cleanup)
36 this._cleanup = cleanup;
37 if (overrides)
38 this._overrides = overrides;
39 if (dependencies)
40 this._deps = dependencies;
36 41 }
37 42
38 43 activate(context: ActivationContext<S>): T {
39 44
40 45 if (this._lifetime.has())
41 46 return this._lifetime.get();
42 47
43 48 this._lifetime.initialize(context);
44 49
45 50 if (this._overrides)
46 51 each(this._overrides, (v, k) => context.register(k, v));
47 52
48
49 const resolver = new ContextResolver(context);
53 const resolve = <K extends keyof S, L extends boolean, D = never>({ name, lazy, ...opts }: Ref<K, L, D>) => {
54 if (lazy) {
55 return () => "default" in opts ? context.resolve(name, opts.default) : context.resolve(name);
56 } else {
57 return "default" in opts ? context.resolve(name, opts.default) : context.resolve(name);
58 }
59 };
50 60
61 const makeRefs = (deps?: DepsMap<key, keyof S>) => deps ?
62 Object.keys(deps)
63 .map(k => {
64 const ref = deps[k];
65 return isKey(ref) ?
66 { [k]: resolve({ name: ref }) } :
67 { [k]: resolve(ref) };
68 })
69 .reduce((a, p) => ({ ...a, ...p }), {} ) as Record<key, never>:
70 {} as Record<key, never>;
51 71
52 const instance = this._factory.call(undefined, resolver.resolve.bind(resolver));
72 const instance = this._factory.call(undefined, makeRefs(this._deps));
53 73
54 74 this._lifetime.store(instance, this._cleanup);
55 75
56 76 return instance;
57 77 }
58 78
59 79
60 80 toString() {
61 81 return `[object DescriptorImpl, lifetime=${String(this._lifetime)}]`;
62 82 }
63 83 }
@@ -1,94 +1,93
1 1 import { DescriptorBuilder } from "./DescriptorBuilder";
2 2 import { ConfigurableKeys, ContainerServices, ConfigurableServices, RegistrationBuildersMap, ExtractRequired } from "./interfaces";
3 3 import { ServiceContainer } from "./interfaces";
4 4 import { argumentNotNull, each, isKey } from "./traits";
5 5
6 6 export class FluentConfiguration<S extends object, Y extends ConfigurableKeys<S> = ConfigurableKeys<S>> {
7 7
8 8 private _builders: Partial<RegistrationBuildersMap<S>> = {};
9 9
10 10 /** Adds a declaration of the services to the current config.
11 11 *
12 12 * @template D The map of the services
13 13 * @returns self
14 14 */
15 15 declare<D extends Partial<Pick<S, keyof D & keyof S>>>(): FluentConfiguration<S & D, Y | ConfigurableKeys<D>> {
16 16 return this as FluentConfiguration<S & D, Y | ConfigurableKeys<D>>;
17 17 }
18 18
19 19 /** Adds compile-time information about the already provided services
20 20 *
21 21 * @template P The map of the provided services
22 22 * @returns self
23 23 */
24 24 provided<P extends Pick<S, keyof P & keyof S>>(): FluentConfiguration<S & P, Exclude<Y, keyof P>> {
25 25 return this as FluentConfiguration<S & P, Exclude<Y, keyof P>>;
26 26 }
27 27
28 28 /** Register the service.
29 29 *
30 30 * @param name The name of the service
31 31 * @param builder The service builder
32 32 * @returns self
33 33 */
34 34 register<K extends Y>(name: K, builder: RegistrationBuildersMap<S>[K]): FluentConfiguration<S, Exclude<Y, K>>;
35 35 /** Registers the collection of services
36 36 * @param config The collection of services to register.
37 37 * @returns self
38 38 */
39 39 register<K extends Y>(config: RegistrationBuildersMap<S, K>): FluentConfiguration<S, Exclude<Y, K>>;
40 40 register<K extends Y>(nameOrConfig: K | RegistrationBuildersMap<S, K>, builder?: RegistrationBuildersMap<S>[K]) {
41 41 if (isKey(nameOrConfig)) {
42 42 argumentNotNull(builder, "builder");
43 43 this._builders[nameOrConfig] = builder;
44 44 } else {
45 45 each(nameOrConfig, (v, k) => this.register(k, v));
46 46 }
47 47
48 48 return this as FluentConfiguration<S, Exclude<Y, K>>;
49 49 }
50 50
51 51 /**
52 52 * This method is used to enable a compile time check of the configuration.
53 53 * If there are not configured services in the configuration the compiler
54 54 * will trigger the error.
55 55 *
56 56 * @param missing Empty object literal should always be specified.
57 57 * @returns self
58 58 */
59 59 // eslint-disable-next-line @typescript-eslint/no-unused-vars
60 60 done<M extends ExtractRequired<S,Y>>(missing: M) {
61 61 return this;
62 62 }
63 63
64 64
65 apply<A extends Partial<S>>(target: ServiceContainer<A>) {
65 apply<T extends ServiceContainer<S>>(target: T) {
66 66
67 67 let pending = 1;
68 68
69 const _t2 = target as ServiceContainer<S>;
70
71 69 const reject = (ex: unknown) => { throw ex; };
72 70
73 71 const complete = () => !--pending;
74 72
75 73 each(this._builders, (v, k) => {
76 74 pending++;
77 const d = new DescriptorBuilder<ContainerServices<S>, NonNullable<ConfigurableServices<S>[typeof k]>>(_t2,
75 const d = new DescriptorBuilder<ContainerServices<S>, NonNullable<ConfigurableServices<S>[typeof k]>>(
76 target,
78 77 result => {
79 _t2.register(k, result);
78 target.register(k, result);
80 79 complete();
81 80 },
82 81 reject
83 82 );
84 83
85 84
86 85 v(d);
87 86 });
88 87 if (!complete())
89 88 throw new Error("The configuration didn't complete.");
90 89
91 return _t2 as ServiceContainer<A & S>;
90 return target as T & ServiceContainer<S>;
92 91 }
93 92
94 93 }
@@ -1,121 +1,137
1 1 import { ActivationContext } from "./ActivationContext";
2 import { key } from "./traits";
2 3
3 4 export type primitive = number | string | null | undefined | symbol;
4 5
5 6 export interface IDestroyable {
6 7 destroy(): void;
7 8 }
8 9
9 10 /**
10 11 * @template S Карта доступных зависимостей
11 12 */
12 13 export interface Resolver<S extends object> {
13 14 /**
14 15 * Функция для разрешения зависимостей, поддерживает создание фабричных методов,
15 16 * отложенную активацию и значение по-умолчанию для сервисов
16 17 * @template K Ключ сервиса из {@link S}
17 18 * @template O Тип параметра {@link opts} используется для выведения типа
18 19 * возвращаемого значения.
19 20 * @param name Ключ сервиса, который будет разрешен.
20 21 * @param {boolean=} opts.lazy Признак того, что требуется отложенная активация,
21 22 * будет возвращен фабричный метод для получения зависимости. Если не указан,
22 23 * то считается `false`.
23 24 * @param {any=} opts.default Значение по умолчанию, если в контейнере указанный
24 25 * сервис не зарегистрирован
25 26 * @returns Либо фабричный метод для получения зависимости, либо значение зависимости
26 27 * @throws Error Если зависимость не найдена и не предоставлено значение по-умолчанию
27 28 */
28 29 <K extends keyof S, O extends { lazy: true; default?: unknown }>(name: K, opts?: O): () => (O extends { default: infer T } ? T : never) | NonNullable<S[K]>;
29 30 <K extends keyof S, O extends { lazy?: false; default?: unknown }>(name: K, opts?: O): (O extends { default: infer T } ? T : never) | NonNullable<S[K]>;
30 31 }
31 32
32 export interface DescriptorBuilder<S extends object, T> {
33 export type DepsMap<K extends key, SK extends key> = { [k in K]: SK | Ref<SK, boolean, unknown> };
34
35 export type Ref<K extends key, L extends boolean, D> = { name: K, lazy?: L} | { name: K, lazy?: L, default: D };
36
37 export type Resolved<S, K extends keyof S, L, D> =
38 L extends true ? () => NonNullable<S[K]> | (unknown extends D ? never : D) : NonNullable<S[K]> | (unknown extends D ? never : D);
39
40 export interface IDescriptorBuilder<S extends object, T, R extends object = object> {
33 41
34 42 /**
35 43 *
36 44 * @param f
37 45 */
38 factory(f: (resolve: Resolver<S>) => T): void;
46 factory(f: (refs: R) => T): void;
47
48 wants<X extends DepsMap<Exclude<key, keyof R>, keyof S>>(refs: X):
49 IDescriptorBuilder<S, T, R & {
50 [k in keyof X]:
51 X[k] extends keyof S ? NonNullable<S[X[k]]> :
52 X[k] extends Ref<infer K, infer L, infer D> ? Resolved<S,K & keyof S,L,D>:
53 never
54 }>
39 55
40 56 override<K extends ConfigurableKeys<S>>(name: K, builder: RegistrationBuilder<S, NonNullable<S[K]>>): this;
41 57 override<K extends ConfigurableKeys<S>>(services: { [name in K]: RegistrationBuilder<S, NonNullable<S[K]>> }): this;
42 58
43 59 lifetime(lifetime: "singleton", typeId: string | number | object): this;
44 60 lifetime(lifetime: ILifetime<T> | Exclude<ActivationType, "singleton">): this;
45 61
46 62 cleanup(cb: (item: T) => void): this;
47 63
48 64 value(v: T): void;
49 65 }
50 66
51 export type RegistrationBuilder<S extends object, T> = (d: DescriptorBuilder<S, T>) => void;
67 export type RegistrationBuilder<S extends object, T> = (d: IDescriptorBuilder<S, T>) => void;
52 68
53 69 export type RegistrationBuildersMap<S extends object, K extends ConfigurableKeys<S> = ConfigurableKeys<S>> = {
54 70 [k in K]-?: RegistrationBuilder<ContainerServices<S>, NonNullable<ConfigurableServices<S>[k]>>
55 71 };
56 72
57 73 export interface Descriptor<S extends object, T> {
58 74 activate(context: ActivationContext<S>): T;
59 75 }
60 76
61 77 export type ConfigurableDescriptor<S extends object, K extends ConfigurableKeys<S>> = Descriptor<ContainerServices<S>, ConfigurableServices<S>[K]>;
62 78
63 79 export type RegistrationMap<S extends object, K extends keyof S = keyof S> = {
64 80 [k in K]-?: Descriptor<S, S[k]>;
65 81 };
66 82
67 83 export interface ProvidedServices<S extends object> {
68 84 container: ServiceLocator<ContainerServices<S>>;
69 85
70 86 childContainer: ServiceContainer<S>;
71 87 }
72 88
73 89 export type ProvidedKeys = keyof ProvidedServices<object>;
74 90
75 91 export type ContainerKeys<S extends object> = keyof ContainerServices<S>;
76 92
77 93 export type Mix<S, X> = { [k in keyof (S & X)]: k extends keyof X ? X[k] : S[k & keyof S] };
78 94
79 95 export type ContainerServices<S extends object> = Mix<S, ProvidedServices<S>>;
80 96
81 97 export type ConfigurableKeys<S extends object> = Exclude<keyof S, ProvidedKeys>;
82 98
83 99 export type ConfigurableServices<S extends object> = Pick<S, ConfigurableKeys<S>>;
84 100
85 101 export interface ServiceLocator<S extends object> {
86 102 resolve<K extends keyof S>(name: K): NonNullable<S[K]>;
87 103 resolve<K extends keyof S, T>(name: K, def: T): NonNullable<S[K]> | T;
88 104 }
89 105
90 106 export interface LifetimeContainer {
91 107 createLifetime<T>(): ILifetime<T>;
92 108 }
93 109
94 110 export interface ServiceContainer<S extends object> extends ServiceLocator<ContainerServices<S>>, LifetimeContainer, IDestroyable {
95 111
96 112 register<K extends ConfigurableKeys<S>>(name: K, service: ConfigurableDescriptor<S, K>): void;
97 113 register<K extends ConfigurableKeys<S>>(services: { [k in K]: ConfigurableDescriptor<S, K> }): void;
98 114
99 115 createChildContainer(): ServiceContainer<S>;
100 116 }
101 117
102 118
103 119 export type ActivationType = "singleton" | "container" | "hierarchy" | "context" | "call";
104 120
105 121 /**
106 122 * Интерфейс для управления жизнью экземпляра объекта. Каждая регистрация имеет
107 123 * свой собственный объект `ILifetime`, который создается при первой активации
108 124 */
109 125 export interface ILifetime<T> {
110 126 /** Проверяет, что уже создан экземпляр объекта */
111 127 has(): boolean;
112 128
113 129 get(): T;
114 130
115 131 initialize(context: ActivationContext<object>): void;
116 132
117 133 store(item: T, cleanup?: (item: T) => void): void;
118 134 }
119 135
120 136 export type ExtractRequired<T, K extends keyof T = keyof T> = { [p in K as (undefined extends T[p] ? never : p)]-?: T[p] };
121 137
@@ -1,58 +1,65
1 1 /* eslint max-classes-per-file: ["error", 20] */
2 2 import { describe, it } from "mocha";
3 import {LifetimeManager} from "../LifetimeManager";
4 3 import {Container} from "../Container";
5 4 import { fluent } from "../traits";
6 5
7 6 class Foo {
8 7 foo = "foo";
9 8 }
10 9
11 10 class Bar {
12 11 bar = "bar";
13 12
14 13 constructor(foo?: () => Foo) {}
15 14 }
16 15
17 16 interface Services {
18 17 foo: Foo;
19 18
20 19 bar?: Bar;
21 20
22 21 baz: Foo;
23 22 }
24 23
25 24 interface ServicesB {
26 25 // will give errors
27 26 // baz: Bar;
28 27
29 28 baz: Foo;
30 29
31 30 zoo?: Foo;
32 31 }
33 32
34 33 interface SharedServices {
35 34 foo: Foo;
36 35
37 36 bar?: Bar;
38 37
39 38 baz: Bar;
40 39 }
41 40
42 41 const config = fluent()
43 42 .declare<Services>()
44 43 .declare<ServicesB>()
45 44 .register({
46 45 bar: it => it
47 .lifetime("context")
48 .factory($ => new Bar($("zoo", {lazy: true, default: new Foo()}))),
49 foo: it => it.factory($ => new Foo()),
46 .lifetime("context") // тип активации, время жизни
47 .wants({
48 zoo: "zoo", // зависимость
49
50 zoo$: { name: "zoo", lazy: true } // отложенная активация,
51 //фабричный метод
52 })
53 .factory(({ zoo$ }) => // фабрика получает объект с именованными зависимостями
54 // удобно для деструктурирования
55 new Bar(zoo$) // создается экземпляр сервиса
56 ),
57 foo: it => it.factory(() => new Foo()),
50 58 baz: it => it.value(new Foo())
51 59 })
52 60 .done({});
53 61
54 declare const container: Container<SharedServices>;
55
62 declare const container: Container<Record<string, never>>;
56 63 const c2 = config.apply(container);
57 64
58 c2.resolve("baz"); No newline at end of file
65 c2.resolve("foo"); No newline at end of file
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now