##// END OF EJS Templates
WIP lifetime services
cin -
r12:94f233c23aa4 default
parent child
Show More
@@ -1,67 +1,66
1 import { Container } from "./Container";
1 import { Container } from "./Container";
2 import { DescriptorBuilder } from "./DescriptorBuilder";
2 import { DescriptorBuilder } from "./DescriptorBuilder";
3 import { Descriptor, IContainerBuilder, IDescriptorBuilder, DescriptorMap, ServiceLocator, ILifetime, IDestroyable } from "./interfaces";
3 import { Descriptor, IContainerBuilder, IDescriptorBuilder, DescriptorMap, ServiceLocator, ILifetime, IDestroyable } from "./interfaces";
4 import { emptyLifetime, LifetimeManager } from "./LifetimeManager";
4 import { emptyLifetime, LifetimeManager } from "./LifetimeManager";
5 import { isDestroyable, prototype } from "./traits";
5 import { isDestroyable, prototype } from "./traits";
6
6
7 /**
7 /**
8 * Container builder used to prepare service descriptors and create a IoC container
8 * Container builder used to prepare service descriptors and create a IoC container
9 */
9 */
10 export class ContainerBuilder<S, U extends keyof S> implements
10 export class ContainerBuilder<S, U extends keyof S> implements
11 IContainerBuilder<S, U> {
11 IContainerBuilder<S, U> {
12
12
13 private _pending = 1;
13 private _pending = 1;
14
14
15 private readonly _services: DescriptorMap<S>;
15 private readonly _services: DescriptorMap<S>;
16
16
17 private readonly _lifetimeManager = new LifetimeManager();
17 private readonly _lifetimeManager = new LifetimeManager();
18
18
19 private readonly _lifetime: ILifetime<IDestroyable>;
19 private readonly _lifetime: ILifetime<IDestroyable>;
20
20
21 constructor(parentServices: DescriptorMap<S> | null = null, lifetime?: ILifetime<IDestroyable>) {
21 constructor(parentServices: DescriptorMap<S> | null = null, lifetime?: ILifetime<IDestroyable>) {
22 this._services = prototype(parentServices);
22 this._services = prototype(parentServices);
23 this._lifetimeManager = new LifetimeManager();
23 this._lifetimeManager = new LifetimeManager();
24 this._lifetime = lifetime ?? emptyLifetime();
24 this._lifetime = lifetime ?? emptyLifetime();
25 }
25 }
26 createServiceBuilder<K extends U>(name: K):
26 createServiceBuilder<K extends U>(name: K):
27 IDescriptorBuilder<S, S[K], Record<never, never>, U> {
27 IDescriptorBuilder<S, S[K], Record<never, never>, U> {
28
28
29 return new DescriptorBuilder(this._lifetimeManager, this._register(name), this._fail);
29 return new DescriptorBuilder(this._lifetimeManager, this._register(name), this._fail);
30
30
31 }
31 }
32
32
33 build(): ServiceLocator<S> {
33 build(): ServiceLocator<S> {
34 this._assertBuilding();
34 this._assertBuilding();
35 if (!this._complete())
35 if (!this._complete())
36 throw new Error("The configuration didn't complete.");
36 throw new Error("The configuration didn't complete.");
37
37
38 const lifetime = this._lifetime;
38 const {remove, store} = this._lifetime(null);
39
39
40 const detach = isDestroyable(lifetime) ? () => lifetime.destroy() : () => void (0);
40 const container = new Container(this._services, this._lifetimeManager, remove);
41
41
42 const container = new Container(this._services, this._lifetimeManager, detach);
42 store(container);
43 lifetime.store(container);
44
43
45 return container;
44 return container;
46 }
45 }
47
46
48 private readonly _register = <K extends U>(name: K) =>
47 private readonly _register = <K extends U>(name: K) =>
49 (descriptor: Descriptor<S, S[K]>) => {
48 (descriptor: Descriptor<S, S[K]>) => {
50 this._complete();
49 this._complete();
51 this._services[name] = descriptor;
50 this._services[name] = descriptor;
52 };
51 };
53
52
54 private readonly _fail = (ex: unknown) => {
53 private readonly _fail = (ex: unknown) => {
55 throw ex;
54 throw ex;
56 };
55 };
57
56
58 private _assertBuilding() {
57 private _assertBuilding() {
59 if (!this._pending)
58 if (!this._pending)
60 throw new Error("The descriptor builder is finalized");
59 throw new Error("The descriptor builder is finalized");
61 }
60 }
62
61
63 private _complete() {
62 private _complete() {
64 return !(--this._pending);
63 return !(--this._pending);
65 }
64 }
66
65
67 } No newline at end of file
66 }
@@ -1,93 +1,97
1 import { ActivationError } from "./ActivationError";
2 import { Descriptor, ILifetime, DepsMap, IActivationContext, DescriptorMap } from "./interfaces";
1 import { Descriptor, ILifetime, DepsMap, IActivationContext, DescriptorMap } from "./interfaces";
3 import { each, key } from "./traits";
2 import { each, key } from "./traits";
4
3
5 export interface DescriptorImplArgs<S, T> {
4 export interface DescriptorImplArgs<S, T> {
6 lifetime: ILifetime<T>;
5 lifetime: ILifetime<T>;
7
6
8 factory: (refs: Record<key, unknown>) => NonNullable<T>;
7 factory: (refs: Record<key, unknown>) => NonNullable<T>;
9
8
10 cleanup?: (item: NonNullable<T>) => void;
9 cleanup?: (item: NonNullable<T>) => void;
11
10
12 overrides?: DescriptorMap<S>;
11 overrides?: DescriptorMap<S>;
13
12
14 dependencies?: DepsMap<S>;
13 dependencies?: DepsMap<S>;
15 }
14 }
16
15
17
16
18 export class DescriptorImpl<S, T> implements Descriptor<S, T> {
17 export class DescriptorImpl<S, T> implements Descriptor<S, T> {
19
18
20 private readonly _overrides?: DescriptorMap<S>;
19 private readonly _overrides?: DescriptorMap<S>;
21
20
22 private readonly _lifetime: ILifetime<T>;
21 private readonly _lifetime: ILifetime<T>;
23
22
24 private readonly _factory: (refs: Record<key, unknown>) => NonNullable<T>;
23 private readonly _factory: (refs: Record<key, unknown>) => NonNullable<T>;
25
24
26 private readonly _cleanup?: (item: NonNullable<T>) => void;
25 private readonly _cleanup?: (item: NonNullable<T>) => void;
27
26
28 private readonly _deps?: DepsMap<S>;
27 private readonly _deps?: DepsMap<S>;
29
28
30 readonly hasOverrides: boolean;
29 readonly hasOverrides: boolean;
31
30
32 constructor({ lifetime, factory, cleanup, overrides, dependencies }: DescriptorImplArgs<S, T>) {
31 constructor({ lifetime, factory, cleanup, overrides, dependencies }: DescriptorImplArgs<S, T>) {
33 this._lifetime = lifetime;
32 this._lifetime = lifetime;
34 this._factory = factory;
33 this._factory = factory;
35 if (cleanup)
34 if (cleanup)
36 this._cleanup = cleanup;
35 this._cleanup = cleanup;
37 if (overrides)
36 if (overrides)
38 this._overrides = overrides;
37 this._overrides = overrides;
39 if (dependencies)
38 if (dependencies)
40 this._deps = dependencies;
39 this._deps = dependencies;
41
40
42 this.hasOverrides = !!overrides;
41 this.hasOverrides = !!overrides;
43 }
42 }
44
43
45 activate(context: IActivationContext<S>): NonNullable<T> {
44 activate(context: IActivationContext<S>): NonNullable<T> {
46
45
47 if (this._lifetime.has())
46 const { has, get, initialize, store } = this._lifetime(context);
48 return this._lifetime.get();
49
47
50 this._lifetime.initialize(context);
48 if (has())
49 return get();
50
51 initialize();
51
52
52 if (this._overrides)
53 if (this._overrides)
53 each(this._overrides, (v, k) => context.register(k, v));
54 each(this._overrides, (v, k) => context.register(k, v));
54
55
55 const resolve = <K extends keyof S>({ name, lazy, ...opts }: { name: K; lazy?: boolean; default?: S[K] | null; }) => {
56 const resolve = <K extends keyof S>({ name, lazy, ...opts }: { name: K; lazy?: boolean; default?: S[K] | null; }) => {
56 if (lazy) {
57 if (lazy) {
57 return "default" in opts ?
58 return "default" in opts ?
58 () => context.resolve(name, opts.default) :
59 () => context.resolve(name, opts.default) :
59 () => context.resolve(name);
60 () => context.resolve(name);
60 } else {
61 } else {
61 return "default" in opts ?
62 return "default" in opts ?
62 context.resolve(name, opts.default) :
63 context.resolve(name, opts.default) :
63 context.resolve(name);
64 context.resolve(name);
64 }
65 }
65 };
66 };
66
67
67 const deps = this._deps;
68 const deps = this._deps;
68
69
69 const refs = deps ?
70 const refs = deps ?
70 Object.keys(deps)
71 Object.keys(deps)
71 .map(k => {
72 .map(k => {
72 const ref = deps[k];
73 const ref = deps[k];
73 return typeof ref !== "object" ?
74 return typeof ref !== "object" ?
74 { [k]: resolve({ name: ref }) } :
75 { [k]: resolve({ name: ref }) } :
75 { [k]: resolve(ref) };
76 { [k]: resolve(ref) };
76 })
77 })
77 .reduce((a, p) => ({ ...a, ...p }), {}) :
78 .reduce((a, p) => ({ ...a, ...p }), {}) :
78 {};
79 {};
79
80
80 try {
81 try {
82 // call the factory method
81 const instance = (0,this._factory)(refs);
83 const instance = (0,this._factory)(refs);
82 this._lifetime.store(instance, this._cleanup);
84
85 // store the instance
86 store(instance, this._cleanup);
83 return instance;
87 return instance;
84 } catch(err) {
88 } catch(err) {
85 context.fail(err);
89 context.fail(err);
86 }
90 }
87 }
91 }
88
92
89
93
90 toString() {
94 toString() {
91 return `[object DescriptorImpl, lifetime=${String(this._lifetime)}]`;
95 return `[object DescriptorImpl, lifetime=${String(this._lifetime)}]`;
92 }
96 }
93 }
97 }
@@ -1,252 +1,170
1 import { IActivationContext, ILifetime, ILifetimeContext, ILifetimeManager, ILifetimeSlot } from "./interfaces";
1 import { IDestroyable, ILifetimeContext, ILifetimeManager, ILifetimeSlot } from "./interfaces";
2 import { ActivationContext } from "./ActivationContext";
3 import { argumentNotNull, isDestroyable } from "./traits";
2 import { argumentNotNull, isDestroyable } from "./traits";
4
3
5 const safeCall = (item: () => void) => {
4 const safeCall = (item: () => void) => {
6 try {
5 try {
7 item();
6 item();
8 } catch {
7 } catch {
9 // silence!
8 // silence!
10 }
9 }
11 };
10 };
12
11
13 const noop = () => {};
12 const noop = () => { };
14
13
15 const fail = (message: string) => {
14 const fail = (message: string) => (): never => {
16 throw new Error(message);
15 throw new Error(message);
17 };
16 };
18
17
19 const _emptySlot = Object.freeze({
18 const _emptySlot = Object.freeze({
20 has: () => false,
19 has: () => false,
21
20
22 initialize: noop,
21 initialize: noop,
23
22
24 get: fail("The specified item isn't registered with a lifetime manager"),
23 get: fail("The specified item isn't registered with a lifetime manager"),
25
24
26 store: noop,
25 store: noop,
27
26
28 remove: noop
27 remove: noop,
29 });
30
31 const _unknonwSlot = Object.freeze({
32 has: () => false,
33
28
34 initialize: () => {
29 cleanup: noop,
35 throw new Error("Can't call initialize on the unknown lifetime object");
36 },
37 get: () => {
38 throw new Error("The lifetime object isn't initialized");
39 },
40 store: () => {
41 throw new Error("Can't store a value in the unknown lifetime object");
42 }
43 });
30 });
44
31
32 const _destroy = (item: IDestroyable) => item.destroy();
45
33
46 const pendingSlot = <T>(store: (item: T) => void) => ({
34 const _makeCleanup = <T>(value: T, cleanup?: (item: T) => void) =>
35 cleanup ? () => cleanup(value) :
36 isDestroyable(value) ? () => _destroy(value) :
37 noop;
38
39 const newSlot = <T>(put: (item: ILifetimeSlot<T>) => void, remove: () => void): ILifetimeSlot<T> => ({
47 has: () => false,
40 has: () => false,
48
41
49 get: () => {
42 initialize: () => put(pendingSlot(put, remove)),
50 throw new Error("The value in this slot doesn't exist");
43
51 },
44 get: fail("The slot doesn't hold a value"),
52
45
53 initialize: () => {
46 store: (value, cleanup) => put(valueSlot(value, cleanup, remove)),
54 throw new Error("Cyclic reference detected");
55 },
56
47
57 store
48 remove: noop,
49
50 cleanup: noop,
58 });
51 });
59
52
60 const valueSlot = <T>(value: T, cleanup: (item: T) => void) => ({
53 const pendingSlot = <T>(put: (item: ILifetimeSlot<T>) => void, remove: () => void): ILifetimeSlot<T> => ({
54 has: () => false,
55
56 get: fail("The value in this slot doesn't exist"),
57
58 initialize: fail("Cyclic reference detected"),
59
60 store: (value, cleanup) => put(valueSlot(value, cleanup, remove)),
61
62 remove,
63
64 cleanup: noop
65 });
66
67 const valueSlot = <T>(value: T, cleanup: ((item: T) => void) | undefined, remove: () => void) => ({
61 has: () => true,
68 has: () => true,
62
69
63 get: () => value,
70 get: () => value,
64
71
65 initialize: () => {
72 initialize: fail("The slot already has a value"),
66 throw new Error("The slot already has a value");
73
67 },
74 store: fail("The slot already has a value"),
68
75
69 store: () => {
76 cleanup: _makeCleanup(value, cleanup),
70 throw new Error("The slot already has a value");
77
71 }
78 remove: remove
72 });
79 });
73
80
74 const singletons: { [K: string]: unknown } = {};
75
76 export class LifetimeManager implements ILifetimeManager {
81 export class LifetimeManager implements ILifetimeManager {
77 private _destroyed = false;
82 private _destroyed = false;
78
83
79 private readonly _slots: Record<string, ILifetimeSlot<unknown>> = {};
84 private readonly _slots: Record<string, ILifetimeSlot<unknown>> = {};
80
85
81 slot<T>(cookie: string): ILifetimeSlot<T> {
86 slot<T>(cookie: string | number): ILifetimeSlot<T> {
82 if (cookie in this._slots)
87 if (cookie in this._slots)
83 return this._slots[cookie] as ILifetimeSlot<T>;
88 return this._slots[cookie] as ILifetimeSlot<T>;
84
89
85 const store = (item: T, cleanup?: (item: T) => void) => {
90 return newSlot<T>(this._put(cookie), this._remove(cookie));
86 this._assertNotDestroyed();
87 this._slots[cookie] = valueSlot(
88 item,
89 cleanup ?? isDestroyable(item) ? () => item.destroy() : noop
90 );
91 };
92
93 return {
94 has: () => false,
95 get: () => {
96 throw new Error("The value isn't stored in this slot");
97 },
98 store,
99 initialize: () => {
100 this._assertNotDestroyed();
101 this._slots[cookie] = pendingSlot(store);
102 }
103 };
104 }
91 }
105
92
106 remove(cookie: string) {
93 private readonly _put = (id: string | number) => <T>(slot: ILifetimeSlot<T>) => {
107 delete this._slots[cookie];
94 this._assertNotDestroyed();
108 }
95 this._slots[id] = slot as ILifetimeSlot<unknown>;
96 };
97
98 private readonly _remove = (id: string | number) => () => {
99 this._assertNotDestroyed();
100 delete this._slots[id];
101 };
109
102
110 private _assertNotDestroyed() {
103 private _assertNotDestroyed() {
111 if (this._destroyed)
104 if (this._destroyed)
112 throw new Error("The lifetime manager is destroyed");
105 throw new Error("The lifetime manager is destroyed");
113
106
114 }
107 }
115
108
116 destroy() {
109 destroy() {
117 if (!this._destroyed) {
110 if (!this._destroyed) {
118 this._destroyed = true;
111 this._destroyed = true;
119 Object.values(this._slots).forEach(({clean}) => )
112 Object.values(this._slots).forEach(({ cleanup }) => safeCall(cleanup));
120 }
113 }
121 }
114 }
122
115
123 }
116 }
124
117
125 export const emptyLifetime = <T>(): ILifetime<T> => {
118 export const emptyLifetime = <T>() => () => _emptySlot as ILifetimeSlot<T>;
126 return _emptyLifetime;
127 };
128
119
129 export const hierarchyLifetime = <T>(): ILifetime<T> => {
120 let nextId = 1;
130 // TODO: Π²ΠΎΡ‚ здСсь ошибка, ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΉ Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ сСрвиса Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ ΠΈ
131 // привязан lifetime ΠΈΠ· Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅Π³ΠΎ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°, ΠΏΡ€ΠΈ Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ Ρ‡Π΅Ρ€Π΅Π· Π²Ρ‚ΠΎΡ€ΠΎΠΉ
132 // Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° это ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Ρ‚ ΠΊ ошибкС, Ρ‚ΠΎΡ‡Π½Π΅Π΅ Π±ΡƒΠ΄Π΅Ρ‚ взят экзСмпляр
133 // ΠΈΠ· ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°.
134 let _lifetime: ILifetime<T> = _unknownLifetime;
135 return {
136 initialize(context: ILifetimeContext) {
137 if (_lifetime !== _unknownLifetime)
138 throw new Error("Cyclic reference activation detected");
139
121
140 _lifetime = context.createContainerLifetime<T>();
122 export const hierarchyLifetime = <T>() => {
141 },
123 const slotId = nextId++;
142 get() {
124 return (context: ILifetimeContext) =>
143 return _lifetime.get();
125 context.containerSlot<T>(slotId);
144 },
145 has() {
146 return _lifetime.has();
147 },
148 store(item: NonNullable<T>, cleanup?: (item: NonNullable<T>) => void) {
149 return _lifetime.store(item, cleanup);
150 },
151 toString() {
152 return `[object HierarchyLifetime, has=${String(this.has())}]`;
153 }
154 };
155 };
126 };
156
127
157 /**
128 /**
158 * Creates a lifetime instance bound to the current activation context. This
129 * Creates a lifetime instance bound to the current activation context. This
159 * lifetime will store the service instance per activation context. Every
130 * lifetime will store the service instance per activation context. Every
160 * top level service resolution will create a new activation context. This
131 * top level service resolution will create a new activation context. This
161 * context is propagated to subsequent service resolution thus all services
132 * context is propagated to subsequent service resolution thus all services
162 * with context lifetime will be shared among their consumers.
133 * with context lifetime will be shared among their consumers.
163 *
134 *
164 * @returns The instance of the lifetime.
135 * @returns The instance of the lifetime.
165 */
136 */
166 export const contextLifetime = <T>(): ILifetime<T> => {
137 export const contextLifetime = <T>() => {
167 let _lifetime: ILifetime<T> = _unknownLifetime;
138 const slotId = nextId++;
168 return {
139
169 initialize(context: ILifetimeContext) {
140 return (context: ILifetimeContext) =>
170 if (_lifetime !== _unknownLifetime)
141 context.contextSlot<T>(slotId);
171 throw new Error("Cyclic reference detected");
172 _lifetime = context.createLifetime();
173 },
174 get() {
175 return _lifetime.get();
176 },
177 has() {
178 return _lifetime.has();
179 },
180 store(item: NonNullable<T>) {
181 _lifetime.store(item);
182 },
183 toString() {
184 return `[object ContextLifetime, has=${String(this.has())}]`;
185 }
186 };
187 };
142 };
188
143
144 const singletons = new LifetimeManager();
145
189 /**
146 /**
190 * Creates the lifetime for the service which will allow existence only one
147 * Creates the lifetime for the service which will allow existence only one
191 * instance with the specified {@linkcode typeId}. If there will be created
148 * instance with the specified {@linkcode typeId}. If there will be created
192 * several lifetime instances with same `typeId` in the runtime, they will
149 * several lifetime instances with same `typeId` in the runtime, they will
193 * share the same service instance.
150 * share the same service instance.
194 *
151 *
195 * @param typeId The identified for the global instance, usually this is a
152 * @param typeId The identified for the global instance, usually this is a
196 * fully qualified class name
153 * fully qualified class name
197 * @returns The lifetime instance
154 * @returns The lifetime instance
198 */
155 */
199 export const singletonLifetime = <T>(typeId: string): ILifetime<T> => {
156 export const singletonLifetime = <T>(typeId: string) => {
200 argumentNotNull(typeId, "typeId");
157 argumentNotNull(typeId, "typeId");
201 let pending = false;
158
202 return {
159 return () => singletons.slot<T>(typeId);
203 has() {
204 return typeId in singletons;
205 },
206 get() {
207 if (!this.has())
208 throw new Error(`The instance ${typeId} doesn't exists`);
209 return singletons[typeId] as NonNullable<T>;
210 },
211 initialize() {
212 if (pending)
213 throw new Error("Cyclic reference detected");
214 pending = true;
215 },
216 store(item: NonNullable<T>) {
217 singletons[typeId] = item;
218 pending = false;
219 },
220 toString() {
221 return `[object SingletonLifetime, has=${String(this.has())}, typeId=${typeId}]`;
222 }
223 };
224 };
160 };
225
161
226 /** Creates a lifetime bound to the specified container. Using this lifetime
162 /** Creates a lifetime bound to the specified container. Using this lifetime
227 * will create a single service instance per the specified container.
163 * will create a single service instance per the specified container.
228 *
164 *
229 * @param container The container which will manage the lifetime for the service
165 * @param container The container which will manage the lifetime for the service
230 */
166 */
231 export const containerLifetime = <T>(container: { createLifetime<X>(): ILifetime<X> }) => {
167 export const containerLifetime = <T>(manager: ILifetimeManager) => {
232 let _lifetime: ILifetime<T> = _unknownLifetime;
168 const slotId = nextId++;
233 return {
169 return () => manager.slot<T>(slotId);
234 initialize() {
235 if (_lifetime !== _unknownLifetime)
236 throw new Error("Cyclic reference detected");
237 _lifetime = container.createLifetime();
238 },
239 get() {
240 return _lifetime.get();
241 },
242 has() {
243 return _lifetime.has();
244 },
245 store(item: NonNullable<T>, cleanup?: (item: NonNullable<T>) => void) {
246 _lifetime.store(item, cleanup);
247 },
248 toString() {
249 return `[object ContainerLifetime, has=${String(_lifetime.has())}]`;
250 }
251 };
252 };
170 };
@@ -1,272 +1,265
1 import { key } from "./traits";
1 import { key } from "./traits";
2
2
3 export interface IDestroyable {
3 export interface IDestroyable {
4 destroy(): void;
4 destroy(): void;
5 }
5 }
6
6
7 /**
7 /**
8 * @template S ΠšΠ°Ρ€Ρ‚Π° доступных зависимостСй
8 * @template S ΠšΠ°Ρ€Ρ‚Π° доступных зависимостСй
9 */
9 */
10 export interface Resolver<S> {
10 export interface Resolver<S> {
11 /**
11 /**
12 * Ѐункция для Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ зависимостСй, ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ созданиС Ρ„Π°Π±Ρ€ΠΈΡ‡Π½Ρ‹Ρ… ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ²,
12 * Ѐункция для Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ зависимостСй, ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ созданиС Ρ„Π°Π±Ρ€ΠΈΡ‡Π½Ρ‹Ρ… ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ²,
13 * ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΡƒΡŽ Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΡŽ ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ-ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ для сСрвисов
13 * ΠΎΡ‚Π»ΠΎΠΆΠ΅Π½Π½ΡƒΡŽ Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΡŽ ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ-ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ для сСрвисов
14 * @template K ΠšΠ»ΡŽΡ‡ сСрвиса ΠΈΠ· {@linkcode S}
14 * @template K ΠšΠ»ΡŽΡ‡ сСрвиса ΠΈΠ· {@linkcode S}
15 * @template O Π’ΠΈΠΏ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° {@linkcode opts} ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для вывСдСния Ρ‚ΠΈΠΏΠ°
15 * @template O Π’ΠΈΠΏ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° {@linkcode opts} ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для вывСдСния Ρ‚ΠΈΠΏΠ°
16 * Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ³ΠΎ значСния.
16 * Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ³ΠΎ значСния.
17 * @param name ΠšΠ»ΡŽΡ‡ сСрвиса, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½.
17 * @param name ΠšΠ»ΡŽΡ‡ сСрвиса, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½.
18 * @param {boolean=} opts.lazy ΠŸΡ€ΠΈΠ·Π½Π°ΠΊ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ трСбуСтся отлоТСнная активация,
18 * @param {boolean=} opts.lazy ΠŸΡ€ΠΈΠ·Π½Π°ΠΊ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ трСбуСтся отлоТСнная активация,
19 * Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½ Ρ„Π°Π±Ρ€ΠΈΡ‡Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ для получСния зависимости. Если Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½,
19 * Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½ Ρ„Π°Π±Ρ€ΠΈΡ‡Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ для получСния зависимости. Если Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½,
20 * Ρ‚ΠΎ считаСтся `false`.
20 * Ρ‚ΠΎ считаСтся `false`.
21 * @param {any=} opts.default Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, Ссли Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅ ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ
21 * @param {any=} opts.default Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, Ссли Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅ ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ
22 * сСрвис Π½Π΅ зарСгистрирован
22 * сСрвис Π½Π΅ зарСгистрирован
23 * @returns Π›ΠΈΠ±ΠΎ Ρ„Π°Π±Ρ€ΠΈΡ‡Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ для получСния зависимости, Π»ΠΈΠ±ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ зависимости
23 * @returns Π›ΠΈΠ±ΠΎ Ρ„Π°Π±Ρ€ΠΈΡ‡Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ для получСния зависимости, Π»ΠΈΠ±ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ зависимости
24 * @throws Error Если Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡ‚ΡŒ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Π° ΠΈ Π½Π΅ прСдоставлСно Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ-ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
24 * @throws Error Если Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡ‚ΡŒ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Π° ΠΈ Π½Π΅ прСдоставлСно Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ-ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
25 */
25 */
26 <K extends keyof S, O extends { lazy: true; }>(name: K, opts?: O): () => NonNullable<S[K]> | InferDefault<O>;
26 <K extends keyof S, O extends { lazy: true; }>(name: K, opts?: O): () => NonNullable<S[K]> | InferDefault<O>;
27 <K extends keyof S, O extends { lazy?: false; }>(name: K, opts?: O): NonNullable<S[K]> | InferDefault<O>;
27 <K extends keyof S, O extends { lazy?: false; }>(name: K, opts?: O): NonNullable<S[K]> | InferDefault<O>;
28 }
28 }
29
29
30 export type DepsMap<S> = {
30 export type DepsMap<S> = {
31 [k in key]: Refs<S> | keyof S;
31 [k in key]: Refs<S> | keyof S;
32 };
32 };
33
33
34 export type Refs<S> = {
34 export type Refs<S> = {
35 [k in keyof S]: Ref<k, S[k]>;
35 [k in keyof S]: Ref<k, S[k]>;
36 }[keyof S];
36 }[keyof S];
37
37
38 export type Ref<K extends key, D> = {
38 export type Ref<K extends key, D> = {
39 /** The name of the service */
39 /** The name of the service */
40 name: K;
40 name: K;
41
41
42 /** Make a lazy reference, the resolved dependency will be a function */
42 /** Make a lazy reference, the resolved dependency will be a function */
43 lazy?: boolean;
43 lazy?: boolean;
44
44
45 /** The default value for the case where the service isn't defined.
45 /** The default value for the case where the service isn't defined.
46 * When specified the dependency becomes optional, the default value can be
46 * When specified the dependency becomes optional, the default value can be
47 * `null` or `undefined`
47 * `null` or `undefined`
48 */
48 */
49 default?: D | null
49 default?: D | null
50 };
50 };
51
51
52 export type Lazy<T, L extends boolean> = L extends true ? () => T : T;
52 export type Lazy<T, L extends boolean> = L extends true ? () => T : T;
53
53
54 /** Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ‚ΠΈΠΏ свойства `default` Π² Ρ‚ΠΈΠΏΠ΅ {@link T} */
54 /** Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ‚ΠΈΠΏ свойства `default` Π² Ρ‚ΠΈΠΏΠ΅ {@link T} */
55 export type InferDefault<T> = T extends { default: infer D } ? D : never;
55 export type InferDefault<T> = T extends { default: infer D } ? D : never;
56
56
57 export type InferLazy<R> = R extends { lazy: infer L } ?
57 export type InferLazy<R> = R extends { lazy: infer L } ?
58 L extends true ? true : false :
58 L extends true ? true : false :
59 false;
59 false;
60 export type Resolve<S, R> =
60 export type Resolve<S, R> =
61 R extends keyof S ? NonNullable<S[R]> :
61 R extends keyof S ? NonNullable<S[R]> :
62 R extends Ref<infer K, unknown> ?
62 R extends Ref<infer K, unknown> ?
63 K extends keyof S ?
63 K extends keyof S ?
64 Lazy<NonNullable<S[K]> | InferDefault<R>, InferLazy<R>> :
64 Lazy<NonNullable<S[K]> | InferDefault<R>, InferLazy<R>> :
65 never :
65 never :
66 never;
66 never;
67
67
68 /**
68 /**
69 * Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ для конфигурирования сСрвиса Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅. ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ сСрвиса
69 * Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ для конфигурирования сСрвиса Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅. ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ сСрвиса
70 * состоит ΠΈΠ· настройки Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² Π²Ρ‹Π·ΠΎΠ²Π°ΠΌΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² {@linkcode wants},
70 * состоит ΠΈΠ· настройки Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² Π²Ρ‹Π·ΠΎΠ²Π°ΠΌΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² {@linkcode wants},
71 * {@linkcode lifetime}, {@linkcode override}, {@linkcode cleanup}. Π—Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ настройки
71 * {@linkcode lifetime}, {@linkcode override}, {@linkcode cleanup}. Π—Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ настройки
72 * сСрвиса осущСствляСтся Π²Ρ‹Π·ΠΎΠ²ΠΎΠΌ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΈΠ· ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² {@linkcode factory} Π»ΠΈΠ±ΠΎ
72 * сСрвиса осущСствляСтся Π²Ρ‹Π·ΠΎΠ²ΠΎΠΌ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΈΠ· ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² {@linkcode factory} Π»ΠΈΠ±ΠΎ
73 * {@linkcode value}.
73 * {@linkcode value}.
74 *
74 *
75 * @template S ΠšΠ°Ρ€Ρ‚Π° сСрвисов ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°, доступных ΠΏΡ€ΠΈ описании дСскриптора
75 * @template S ΠšΠ°Ρ€Ρ‚Π° сСрвисов ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°, доступных ΠΏΡ€ΠΈ описании дСскриптора
76 * @template T Π’ΠΈΠΏ сСрвиса
76 * @template T Π’ΠΈΠΏ сСрвиса
77 * @template R ΠšΠ°Ρ€Ρ‚Π° зависимостСй, которая пСрСдаСтся ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ Ρ„Π°Π±Ρ€ΠΈΠΊΠ΅
77 * @template R ΠšΠ°Ρ€Ρ‚Π° зависимостСй, которая пСрСдаСтся ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ Ρ„Π°Π±Ρ€ΠΈΠΊΠ΅
78 * @template U ИмСна ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… сСрвисов, доступных для пСрСопрСдСлСния
78 * @template U ИмСна ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… сСрвисов, доступных для пСрСопрСдСлСния
79 */
79 */
80 export interface IDescriptorBuilder<S, T, R, U extends keyof S> {
80 export interface IDescriptorBuilder<S, T, R, U extends keyof S> {
81
81
82 /** Π£ΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Ρ„Π°Π±Ρ€ΠΈΠΊΠ° для создания экзСмпляра сСрвиса, Ρ„Π°Π±Ρ€ΠΈΠΊΠ° пСрСдаСтся
82 /** Π£ΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Ρ„Π°Π±Ρ€ΠΈΠΊΠ° для создания экзСмпляра сСрвиса, Ρ„Π°Π±Ρ€ΠΈΠΊΠ° пСрСдаСтся
83 * Π² Π²ΠΈΠ΄Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°. ΠŸΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ Ρ„Π°Π±Ρ€ΠΈΠΊΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с зависимостями,
83 * Π² Π²ΠΈΠ΄Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°. ΠŸΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ Ρ„Π°Π±Ρ€ΠΈΠΊΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с зависимостями,
84 * ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±Ρ‹Π»ΠΈ ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Π½Ρ‹ Π²Ρ‹Π·ΠΎΠ²Π°ΠΌΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° `wants(...)`
84 * ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±Ρ‹Π»ΠΈ ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Π½Ρ‹ Π²Ρ‹Π·ΠΎΠ²Π°ΠΌΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° `wants(...)`
85 *
85 *
86 * Π’Ρ‹Π·ΠΎΠ² Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ сСрвиса.
86 * Π’Ρ‹Π·ΠΎΠ² Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ сСрвиса.
87 *
87 *
88 * @param f Π€Π°Π±Ρ€ΠΈΠΊΠ° для создания экзСмпляра сСрвиса.
88 * @param f Π€Π°Π±Ρ€ΠΈΠΊΠ° для создания экзСмпляра сСрвиса.
89 */
89 */
90 factory(f: (refs: R) => NonNullable<T>): void;
90 factory(f: (refs: R) => NonNullable<T>): void;
91
91
92 /**
92 /**
93 * Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для указания зависимостСй, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΡ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ΡΡ Ρ„Π°Π±Ρ€ΠΈΡ‡Π½ΠΎΠΌΡƒ
93 * Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для указания зависимостСй, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΡ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ΡΡ Ρ„Π°Π±Ρ€ΠΈΡ‡Π½ΠΎΠΌΡƒ
94 * ΠΌΠ΅Ρ‚ΠΎΠ΄Ρƒ ΠΏΡ€ΠΈ создании Π½ΠΎΠ²ΠΎΠ³ΠΎ экзСмпляра сСрвиса. Π”Π°Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ
94 * ΠΌΠ΅Ρ‚ΠΎΠ΄Ρƒ ΠΏΡ€ΠΈ создании Π½ΠΎΠ²ΠΎΠ³ΠΎ экзСмпляра сСрвиса. Π”Π°Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ
95 * Π²Ρ‹Π·Π²Π°Π½ нСсколько Ρ€Π°Π· подряд, ΠΏΡ€ΠΈ этом Π²Ρ‹Π·ΠΎΠ²Ρ‹ этого ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΠΈΠΌΠ΅ΡŽΡ‚
95 * Π²Ρ‹Π·Π²Π°Π½ нСсколько Ρ€Π°Π· подряд, ΠΏΡ€ΠΈ этом Π²Ρ‹Π·ΠΎΠ²Ρ‹ этого ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΠΈΠΌΠ΅ΡŽΡ‚
96 * кумулятивный эффСкт.
96 * кумулятивный эффСкт.
97 *
97 *
98 * @template X Π’ΠΈΠΏ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° с зависимостями, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ трСбуСтся ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈ
98 * @template X Π’ΠΈΠΏ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° с зависимостями, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ трСбуСтся ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈ
99 * создании экзСмпляра Ρ„Π°Π±Ρ€ΠΈΠΊΠΈ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ Ρ„Π°Π±Ρ€ΠΈΡ‡Π½ΠΎΠ³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°.
99 * создании экзСмпляра Ρ„Π°Π±Ρ€ΠΈΠΊΠΈ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ Ρ„Π°Π±Ρ€ΠΈΡ‡Π½ΠΎΠ³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°.
100 * @param refs ΠžΠ±ΡŠΠ΅ΠΊΡ‚ с описаниСм зависимостСй
100 * @param refs ΠžΠ±ΡŠΠ΅ΠΊΡ‚ с описаниСм зависимостСй
101 * @returns Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ дСскриптор сСрвиса, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΡƒΠΊΠ°Π·Π°Π½Ρ‹ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅
101 * @returns Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ дСскриптор сСрвиса, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΡƒΠΊΠ°Π·Π°Π½Ρ‹ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅
102 * зависимости
102 * зависимости
103 */
103 */
104 wants<X extends DepsMap<S> & Record<keyof R & keyof X, never>>(refs: X):
104 wants<X extends DepsMap<S> & Record<keyof R & keyof X, never>>(refs: X):
105 IDescriptorBuilder<S, T, R & {
105 IDescriptorBuilder<S, T, R & {
106 [k in keyof X]: Resolve<S, X[k]>;
106 [k in keyof X]: Resolve<S, X[k]>;
107 }, U>
107 }, U>
108
108
109 override<K extends U>(name: K, builder: BuildDescriptorFn<S, S[K], U>): this;
109 override<K extends U>(name: K, builder: BuildDescriptorFn<S, S[K], U>): this;
110 override<X extends ConfigurationMapConstraint<S, U, keyof X>>(services: X): this;
110 override<X extends ConfigurationMapConstraint<S, U, keyof X>>(services: X): this;
111
111
112 lifetime(lifetime: "singleton", typeId: string | number | object): this;
112 lifetime(lifetime: "singleton", typeId: string | number | object): this;
113 lifetime(lifetime: ILifetime<T> | Exclude<ActivationType, "singleton">): this;
113 lifetime(lifetime: ILifetime<T> | Exclude<ActivationType, "singleton">): this;
114
114
115 /** Π£ΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для освобоТдСния экзСмпляра сСрвиса для случаСв, ΠΊΠΎΠ³Π΄Π°
115 /** Π£ΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для освобоТдСния экзСмпляра сСрвиса для случаСв, ΠΊΠΎΠ³Π΄Π°
116 * врСмя ΠΆΠΈΠ·Π½ΠΈ привязано ΠΊ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρƒ.
116 * врСмя ΠΆΠΈΠ·Π½ΠΈ привязано ΠΊ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρƒ.
117 */
117 */
118 cleanup(cb: (item: T) => void): this;
118 cleanup(cb: (item: T) => void): this;
119
119
120 /**
120 /**
121 * РСгистрируСт Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅ постоянноС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² качСствС Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ сСрвиса.
121 * РСгистрируСт Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅ постоянноС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² качСствС Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ сСрвиса.
122 *
122 *
123 * @param v ЭкзСмпляр Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ сСрвиса.
123 * @param v ЭкзСмпляр Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ сСрвиса.
124 */
124 */
125 value(v: NonNullable<T>): void;
125 value(v: NonNullable<T>): void;
126 }
126 }
127
127
128 export type BuildDescriptorFn<S, T, U extends keyof S> = (d: IDescriptorBuilder<S, T, Record<never, never>, U>) => void;
128 export type BuildDescriptorFn<S, T, U extends keyof S> = (d: IDescriptorBuilder<S, T, Record<never, never>, U>) => void;
129
129
130 /**
130 /**
131 * ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°, состоит ΠΈΠ· Π½Π°Π±ΠΎΡ€Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ.
131 * ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°, состоит ΠΈΠ· Π½Π°Π±ΠΎΡ€Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ.
132 *
132 *
133 * ВсС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ ΡΠ²Π»ΡΡŽΡ‚ΡΡ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ, Ссли трСбуСтся ввСсти
133 * ВсС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ ΡΠ²Π»ΡΡŽΡ‚ΡΡ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ, Ссли трСбуСтся ввСсти
134 * Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹, Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ Ρ‚ΠΈΠΏΠ° {@linkcode K}
134 * Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹, Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ Ρ‚ΠΈΠΏΠ° {@linkcode K}
135 *
135 *
136 * @template S БСрвисы доступныС Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅
136 * @template S БСрвисы доступныС Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅
137 * @template K БСрвисы ΡƒΡ‡Π°ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
137 * @template K БСрвисы ΡƒΡ‡Π°ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
138 */
138 */
139 export type ConfigurationMap<S, K extends keyof S, U extends keyof S> = {
139 export type ConfigurationMap<S, K extends keyof S, U extends keyof S> = {
140 [k in K]-?: BuildDescriptorFn<S, S[k], U>
140 [k in K]-?: BuildDescriptorFn<S, S[k], U>
141 };
141 };
142
142
143 export type ConfigurationMapConstraint<S, U extends keyof S, X extends string | number | symbol> = {
143 export type ConfigurationMapConstraint<S, U extends keyof S, X extends string | number | symbol> = {
144 [k in X]-?: k extends U ? BuildDescriptorFn<S, S[k], U> : never;
144 [k in X]-?: k extends U ? BuildDescriptorFn<S, S[k], U> : never;
145 };
145 };
146
146
147 /**
147 /**
148 * The type constraint useful to restrict type parameters to prevent defining
148 * The type constraint useful to restrict type parameters to prevent defining
149 * the services with the {@link ContainerKeys} names.
149 * the services with the {@link ContainerKeys} names.
150 *
150 *
151 * The constraint doesn't exclude using this keys but declares them as `never`
151 * The constraint doesn't exclude using this keys but declares them as `never`
152 * which effectively will lead using this keys to the error.
152 * which effectively will lead using this keys to the error.
153 */
153 */
154 export type ContainerServicesConstraint<S> = {
154 export type ContainerServicesConstraint<S> = {
155 [k in keyof S]: k extends ContainerKeys ? never : S[k];
155 [k in keyof S]: k extends ContainerKeys ? never : S[k];
156 };
156 };
157
157
158 export interface Descriptor<S, T> {
158 export interface Descriptor<S, T> {
159
159
160 /** This flags indicates that this registration can be replaced or overridden. */
160 /** This flags indicates that this registration can be replaced or overridden. */
161 readonly configurable?: boolean;
161 readonly configurable?: boolean;
162
162
163 /** If specified signals the activation context that a new service scope
163 /** If specified signals the activation context that a new service scope
164 * should be created to isolate service overrides.
164 * should be created to isolate service overrides.
165 */
165 */
166 readonly hasOverrides?: boolean;
166 readonly hasOverrides?: boolean;
167
167
168 activate(context: IActivationContext<S>): NonNullable<T>;
168 activate(context: IActivationContext<S>): NonNullable<T>;
169 }
169 }
170
170
171 /** The context used to initialize lifetime instance {@linkcode ILifetime} */
171 /** The context used to initialize lifetime instance {@linkcode ILifetime} */
172 export interface ILifetimeContext {
172 export interface ILifetimeContext {
173 contextSlot<T>(slotId: string): ILifetimeSlot<T>;
173 contextSlot<T>(slotId: string | number): ILifetimeSlot<T>;
174
174
175 containerSlot<T>(slotId: string): ILifetimeSlot<T>;
175 containerSlot<T>(slotId: string | number): ILifetimeSlot<T>;
176
176
177 }
177 }
178
178
179 export interface IActivationContext<S> extends ILifetimeContext, ServiceLocator<S> {
179 export interface IActivationContext<S> extends ILifetimeContext, ServiceLocator<S> {
180
180
181 register<K extends keyof S>(name: K, service: DescriptorMap<S>[K]): void;
181 register<K extends keyof S>(name: K, service: DescriptorMap<S>[K]): void;
182
182
183 fail(error: unknown): never;
183 fail(error: unknown): never;
184 }
184 }
185
185
186 /**
186 /**
187 * Descriptors map for the specified services {@linkcode S}. All entries are
187 * Descriptors map for the specified services {@linkcode S}. All entries are
188 * optional regardless the required or optional services in the original map.
188 * optional regardless the required or optional services in the original map.
189 *
189 *
190 * @template S БСрвисы контСкста Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ
190 * @template S БСрвисы контСкста Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ
191 * @template U ΠšΠ°Ρ€Ρ‚Π° сСрвисов ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ дСскрипторами
191 * @template U ΠšΠ°Ρ€Ρ‚Π° сСрвисов ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ дСскрипторами
192 */
192 */
193 export type DescriptorMap<S> = {
193 export type DescriptorMap<S> = {
194 [k in keyof S]?: Descriptor<S, S[k]>;
194 [k in keyof S]?: Descriptor<S, S[k]>;
195 };
195 };
196
196
197 type ContainerKeys = keyof ContainerProvided<object>;
197 type ContainerKeys = keyof ContainerProvided<object>;
198
198
199 export type ContainerProvided<S extends ContainerServicesConstraint<S>> = {
199 export type ContainerProvided<S extends ContainerServicesConstraint<S>> = {
200 container: ServiceLocator<ContainerServices<S>>;
200 container: ServiceLocator<ContainerServices<S>>;
201
201
202 childContainer: IContainerBuilder<ContainerServices<S>, Exclude<keyof S, ContainerKeys>>;
202 childContainer: IContainerBuilder<ContainerServices<S>, Exclude<keyof S, ContainerKeys>>;
203 };
203 };
204
204
205
205
206 /**
206 /**
207 * Π’Π°Π±Π»ΠΈΡ†Π° сСрвисов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ прСдоставляСт ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€.
207 * Π’Π°Π±Π»ΠΈΡ†Π° сСрвисов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ прСдоставляСт ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€.
208 *
208 *
209 * БСрвисы, прСдоставляСмыС ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠΌ Π½Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ null ΠΈΠ»ΠΈ undefined.
209 * БСрвисы, прСдоставляСмыС ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠΌ Π½Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ null ΠΈΠ»ΠΈ undefined.
210 */
210 */
211 export type ContainerServices<S extends ContainerServicesConstraint<S>> = {
211 export type ContainerServices<S extends ContainerServicesConstraint<S>> = {
212 [k in keyof S | ContainerKeys]:
212 [k in keyof S | ContainerKeys]:
213 k extends ContainerKeys ? ContainerProvided<S>[k] :
213 k extends ContainerKeys ? ContainerProvided<S>[k] :
214 k extends keyof S ? S[k] : never
214 k extends keyof S ? S[k] : never
215 };
215 };
216
216
217
217
218 /**
218 /**
219 * Returns the service declared in the type map {@link S}.
219 * Returns the service declared in the type map {@link S}.
220 *
220 *
221 *
221 *
222 */
222 */
223 export interface ServiceLocator<S> {
223 export interface ServiceLocator<S> {
224 resolve<K extends keyof S>(name: K): NonNullable<S[K]>;
224 resolve<K extends keyof S>(name: K): NonNullable<S[K]>;
225 resolve<K extends keyof S, T>(name: K, def: T): NonNullable<S[K]> | T;
225 resolve<K extends keyof S, T>(name: K, def: T): NonNullable<S[K]> | T;
226 }
226 }
227
227
228
228
229 export interface IContainerBuilder<S, U extends keyof S> {
229 export interface IContainerBuilder<S, U extends keyof S> {
230 createServiceBuilder<K extends U>(name: K):
230 createServiceBuilder<K extends U>(name: K):
231 IDescriptorBuilder<S, S[K], Record<never, never>, U>;
231 IDescriptorBuilder<S, S[K], Record<never, never>, U>;
232
232
233 build(): ServiceLocator<S>;
233 build(): ServiceLocator<S>;
234 }
234 }
235
235
236
236
237 export type ActivationType = "singleton" | "container" | "hierarchy" | "context" | "call";
237 export type ActivationType = "singleton" | "container" | "hierarchy" | "context" | "call";
238
238
239 /**
239 /**
240 * Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ для управлСния Тизнью экзСмпляра ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. КаТдая рСгистрация ΠΈΠΌΠ΅Π΅Ρ‚
240 * Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ для управлСния Тизнью экзСмпляра ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. КаТдая рСгистрация ΠΈΠΌΠ΅Π΅Ρ‚
241 * свой собствСнный ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ `ILifetime`, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ создаСтся ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΉ Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ
241 * свой собствСнный ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ `ILifetime`, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ создаСтся ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΉ Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ
242 */
242 */
243 export interface ILifetime<T> {
243 export type ILifetime<T> = (context: ILifetimeContext) => ILifetimeSlot<NonNullable<T>>;
244 /** ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ ΡƒΠΆΠ΅ создан экзСмпляр ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° */
245 has(): boolean;
246
244
247 get(): NonNullable<T>;
245 export interface ILifetimeSlot<T> {
246 readonly has: () => boolean;
247
248 readonly get: () => T;
248
249
249 initialize(context: ILifetimeContext): void;
250 readonly initialize: () => void;
251
252 readonly store: (item: T, cleanup?: (item: T) => void) => void;
250
253
251 store(item: NonNullable<T>, cleanup?: (item: NonNullable<T>) => void): void;
254 readonly remove: () => void;
252
255
253 toString(): string;
256 readonly cleanup: () => void;
254 }
257 }
255
258
256 export interface ILifetimeSlot<T> {
257 has: () => boolean;
258
259 get: () => T;
260
261 initialize: () => void;
262
263 store(item: T, cleanup?: (item: T) => void): void;
264 }
265
266 export interface ILifetimeManager extends IDestroyable {
259 export interface ILifetimeManager extends IDestroyable {
267 create<T>(): ILifetime<T>;
260 slot<T>(id: string | number): ILifetimeSlot<T>;
268 }
261 }
269
262
270 export type ExtractRequired<T, K extends keyof T = keyof T> = { [p in K as (undefined extends T[p] ? never : p)]-?: T[p] };
263 export type ExtractRequired<T, K extends keyof T = keyof T> = { [p in K as (undefined extends T[p] ? never : p)]-?: T[p] };
271
264
272 export type ExtractRequiredKeys<T, K extends keyof T = keyof T> = { [p in K]-?: undefined extends T[p] ? never : p }[K]; No newline at end of file
265 export type ExtractRequiredKeys<T, K extends keyof T = keyof T> = { [p in K]-?: undefined extends T[p] ? never : p }[K];
General Comments 0
You need to be logged in to leave comments. Login now