##// END OF EJS Templates
working on typings
cin -
r8:80cb5668e4a7 default
parent child
Show More
@@ -3,7 +3,7 import { ConfigurableKeys, ContainerServ
3 3 import { ServiceContainer } from "./interfaces";
4 4 import { argumentNotNull, each, isKey } from "./traits";
5 5
6 export class FluentConfiguration<S extends object, Y extends ConfigurableKeys<S> = ConfigurableKeys<S>> {
6 export class FluentConfiguration<S, Y extends ConfigurableKeys<S> = ConfigurableKeys<S>> {
7 7
8 8 private _builders: Partial<RegistrationBuildersMap<S>> = {};
9 9
@@ -12,7 +12,7 export class FluentConfiguration<S exten
12 12 * @template D The map of the services
13 13 * @returns self
14 14 */
15 declare<D extends Partial<Pick<S, keyof D & keyof S>>>(): FluentConfiguration<S & D, Y | ConfigurableKeys<D>> {
15 declare<D extends 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
@@ -7,7 +7,7 export interface IDestroyable {
7 7 /**
8 8 * @template S Карта доступных зависимостей
9 9 */
10 export interface Resolver<S extends object> {
10 export interface Resolver<S> {
11 11 /**
12 12 * Функция для разрешения зависимостей, поддерживает создание фабричных методов,
13 13 * отложенную активацию и значение по-умолчанию для сервисов
@@ -27,13 +27,13 export interface Resolver<S extends obje
27 27 <K extends keyof S, O extends { lazy?: false; default?: unknown }>(name: K, opts?: O): (O extends { default: infer T } ? T : never) | NonNullable<S[K]>;
28 28 }
29 29
30 export type DepsMap<S extends object> = {
31 [k in key]: Refs<S>
30 export type DepsMap<S> = {
31 [k in key]: Refs<S> | keyof S;
32 32 };
33 33
34 export type Refs<S extends object> = {
34 export type Refs<S> = {
35 35 [k in keyof S]: Ref<k, boolean, S[k]>;
36 }[keyof S] | keyof S;
36 }[keyof S];
37 37
38 38 export type Ref<K extends key, L extends boolean, D> = { name: K, lazy?: L, default?: D | null };
39 39
@@ -41,21 +41,40 export type Lazy<T, L extends boolean> =
41 41
42 42 export type InferDefault<T> = T extends { default: infer D } ? D : never;
43 43
44 export type Resolve<S extends object, R> =
44 export type Resolve<S, R> =
45 45 R extends keyof S ? NonNullable<S[R]> :
46 R extends Ref<infer K, infer L, unknown> ?
47 K extends keyof S ? Lazy<NonNullable<S[K]> | InferDefault<R>, L> :
48 never:
46 R extends Ref<infer K, infer L, unknown> ?
47 K extends keyof S ? Lazy<NonNullable<S[K]> | InferDefault<R>, L> :
48 never :
49 49 never;
50 50
51 export interface IDescriptorBuilder<S extends object, T, R extends object, O extends keyof S> {
51 /**
52 * Интерфейс для конфигурирования сервиса в контейнере
53 */
54 export interface IDescriptorBuilder<S, T, R, O extends keyof S> {
52 55
53 /**
56 /** Указывает фабрика для создания экземпляра сервиса, фабрика передается
57 * в виде параметра. При вызове фабрике будет передан объект с зависимостями,
58 * которые были предварительно указаны вызовами метода `wants(...)`
54 59 *
55 * @param f
60 * Вызов данного метода завершает конфигурирование сервиса.
61 *
62 * @param f Фабрика для создания экземпляра сервиса
56 63 */
57 64 factory(f: (refs: R) => T): void;
58 65
66 /**
67 * Используется для указания зависимостей, которые потребуются фабричному
68 * методу при создании нового экземпляра сервиса. Данный метод может быть
69 * вызван несколько раз подряд, при этом вызовы этого метода имеют
70 * кумулятивный эффект.
71 *
72 * @template X Тип объекта с зависимостями, которые требуется получить при
73 * создании экземпляра фабрики при помощи фабричного метода.
74 * @param refs Объект с описанием зависимостей
75 * @returns Возвращает дескриптор сервиса, в котором указаны необходимые
76 * зависимости
77 */
59 78 wants<X extends DepsMap<S> & Record<keyof R & keyof X, never>>(refs: X):
60 79 IDescriptorBuilder<S, T, R & {
61 80 [k in keyof X]: Resolve<S, X[k]>;
@@ -67,50 +86,60 export interface IDescriptorBuilder<S ex
67 86 lifetime(lifetime: "singleton", typeId: string | number | object): this;
68 87 lifetime(lifetime: ILifetime<T> | Exclude<ActivationType, "singleton">): this;
69 88
89 /** Указывает функцию для освобождения экземпляра сервиса для случаев, когда
90 * время жизни привязано к контейнеру.
91 */
70 92 cleanup(cb: (item: T) => void): this;
71 93
94 /**
95 * Регистрирует в контейнере постоянное значение в качестве реализации сервиса.
96 *
97 * @param v Экземпляр реализации сервиса.
98 */
72 99 value(v: T): void;
73 100 }
74 101
75 export type RegistrationBuilder<S extends object, T> = (d: IDescriptorBuilder<S, T, object, ConfigurableKeys<S>>) => void;
102 export type RegistrationBuilder<S, T> = (d: IDescriptorBuilder<S, T, object, ConfigurableKeys<S>>) => void;
76 103
77 104 export type RegistrationBuildersMap<S extends Configurable<S>, K extends keyof S = keyof S> = {
78 105 [k in K]-?: RegistrationBuilder<ContainerServices<S>, NonNullable<S[k]>>
79 106 };
80 107
81 export interface Descriptor<S extends object, T> {
108 export interface Descriptor<S, T> {
82 109 activate(context: IActivationContext<S>): T;
83 110 }
84 111
85 export interface IActivationContext<S extends object> extends ServiceLocator<S> {
112 export interface IActivationContext<S> extends ServiceLocator<S> {
86 113 createLifetime<T>(): ILifetime<T>;
87 114
88 115 createContainerLifetime<T>(): ILifetime<T>;
89 116 }
90 117
91 export type RegistrationMap<S extends object, K extends keyof S = keyof S> = {
118 export type RegistrationMap<S, K extends keyof S = keyof S> = {
92 119 [k in K]-?: Descriptor<S, S[k]>;
93 120 };
94 121
95 export interface ContainerProvided<S extends Configurable<S>> {
122 export interface ContainerProvided<S> {
96 123 container: ServiceLocator<ContainerServices<S>>;
97 124
98 125 childContainer: IContainerBuilder<S>;
99 126 }
100 127
101 export type Configurable<S> = { [k in keyof S & (keyof ContainerProvided<never>)]: never; };
128 export type Configurable<S> = { [k in keyof S]: k extends ProvidedKeys ? never : S[k]; };
102 129
103 130 export type ProvidedKeys = keyof ContainerProvided<never>;
104 131
105 export type ContainerServices<S extends Configurable<S>> = S & ContainerProvided<S>;
132 export type ContainerServices<S> =
133 { [k in keyof S as k extends ProvidedKeys ? never: k]: S[k] } &
134 ContainerProvided<S>;
106 135
107 export type ConfigurableKeys<S extends object> = Exclude<keyof S, ProvidedKeys>;
136 export type ConfigurableKeys<S> = Exclude<keyof S, ProvidedKeys>;
108 137
109 export type ConfigurableServices<S extends object> = Pick<S, ConfigurableKeys<S>>;
138 export type ConfigurableServices<S> = Pick<S, ConfigurableKeys<S>>;
110 139
111 export type ContainerKeys<S extends Configurable<S>> = keyof S | keyof ContainerProvided<never>;
140 export type ContainerKeys<S> = keyof S | ProvidedKeys;
112 141
113 export interface ServiceLocator<S extends object> {
142 export interface ServiceLocator<S> {
114 143 resolve<K extends keyof S>(name: K): NonNullable<S[K]>;
115 144 resolve<K extends keyof S, T>(name: K, def: T): NonNullable<S[K]> | T;
116 145 }
@@ -119,14 +148,14 export interface LifetimeContainer {
119 148 createLifetime<T>(): ILifetime<T>;
120 149 }
121 150
122 export interface ServiceContainer<S extends Configurable<S>> extends
151 export interface ServiceContainer<S> extends
123 152 ServiceLocator<ContainerServices<S>>,
124 153 IDestroyable {
125 154
126 155 createChildContainer(): IContainerBuilder<S>;
127 156 }
128 157
129 export interface IContainerBuilder<S extends Configurable<S>> {
158 export interface IContainerBuilder<S> {
130 159 createServiceBuilder<K extends keyof S>(name: K): IDescriptorBuilder<S, NonNullable<S[K]>, object, keyof S>;
131 160
132 161 build(): ServiceContainer<S>;
@@ -1,7 +1,7
1 1 import { FluentConfiguration } from "./FluentConfiguration";
2 2 import { IDestroyable } from "./interfaces";
3 3
4 export function fluent<S extends object = object>() {
4 export function fluent<S = {}>() {
5 5 return new FluentConfiguration<S>();
6 6 }
7 7
@@ -1,7 +1,8
1 1 /* eslint max-classes-per-file: ["error", 20] */
2 2 import { describe, it } from "mocha";
3 3 import { Container } from "../Container";
4 import { ContainerServices, DepsMap, Refs, Resolver } from "../interfaces";
4 import { ContainerBuilder } from "../ContainerBuilder";
5 import { ConfigurableKeys, ContainerProvided, ContainerServices, DepsMap, Refs, Resolver } from "../interfaces";
5 6 import { fluent } from "../traits";
6 7
7 8 class Foo {
@@ -20,6 +21,8 interface Services {
20 21 bar?: Bar;
21 22
22 23 baz: Foo;
24
25 container: string;
23 26 }
24 27
25 28 interface ServicesB {
@@ -35,9 +38,18 declare const resolver: Resolver<Service
35 38
36 39 const foo = resolver("foo", {lazy: true});
37 40
38 const mmap = <X extends DepsMap<Services, string>>(m: X) => {};
41 const mmap = <X extends DepsMap<Services>>(m: X) => {};
42
43 declare const refs: Refs<Services>;
39 44
40 const refs: Refs<Services> = {name: "bar", default: undefined};
45 if (refs && refs.name === "foo") {
46 refs.default;
47 }
48
49 declare const x: ContainerServices<Services>;
50
51 x.container.resolve("container");
52
41 53
42 54 mmap({
43 55 fooz: {name: "foo", lazy: false, default: undefined },
@@ -56,6 +68,7 const config = fluent()
56 68 .declare<Services>()
57 69 .declare<ServicesB>()
58 70 .register({
71 zoo: it => {},
59 72 bar: it => it
60 73 .lifetime("context") // тип активации, время жизни
61 74 .wants({
@@ -77,11 +90,11 const config = fluent()
77 90 })
78 91 .done({});
79 92
80 declare const container: Container<object>;
93 declare const container: ContainerBuilder<{}>;
81 94 const c2 = config.configure(container);
82 95
83 96 c2.resolve("foo");
84 97
85 98 declare const m :ContainerServices<{foo: Foo}>["container"];
86 99
87 m.resolve("container").resolve("container"); No newline at end of file
100 m.resolve("container").resolve("container").resolve("foo"); No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now