##// END OF EJS Templates
fluent configuration interfaces
cin -
r127:850cc60b6e2a ioc ts support
parent child
Show More
@@ -1,62 +1,25
1 import { primitive } from "../safe";
1 import { TypeRegistration } from "./Configuration";
2 import { TypeRegistration, DependencyRegistration, LazyDependencyRegistration, Registration, StrictTypeRegistration } from "./Configuration";
2 import { ExtractDependency } from "./fluent/interfaces";
3
4 export interface InjectOptions {
5 lazy?: boolean;
6 }
7
8 type Compatible<T1, T2> = T2 extends T1 ? any : never;
9
10 type ExtractService<K, S> = K extends keyof S ? S[K] : K;
11
3
12 type ExtractDependency<D, S> = D extends { $dependency: infer K } ?
4 export class AnnotaionBuilder<T, S extends object> {
13 D extends { lazy: true } ? () => ExtractService<K, S> : ExtractService<K, S> :
5 wire<P extends any[]>(...args: P) {
14 D extends { $type: new (...args: any[]) => infer I } ? I :
15 WalkDependencies<D, S>;
16
17 type WalkDependencies<D, S> = D extends primitive ? D :
18 { [K in keyof D]: ExtractDependency<D[K], S> };
19
20 export class Builder<T, S extends object> {
21 declare<P extends any[]>(...args: P) {
22 return <C extends new (...args: ExtractDependency<P, S>) => T>(constructor: C) => {
6 return <C extends new (...args: ExtractDependency<P, S>) => T>(constructor: C) => {
23
7
24 };
8 };
25 }
9 }
26
10
27 inject<P extends any[]>(...args: P) {
11 inject<P extends any[]>(...args: P) {
28 return <X extends { [m in M]: (...args: any) => any }, M extends keyof (T | X)>(
12 return <X extends { [m in M]: (...args: any) => any }, M extends keyof (T | X)>(
29 target: X,
13 target: X,
30 memberName: M,
14 memberName: M,
31 descriptor: TypedPropertyDescriptor<Compatible<(...args: ExtractDependency<P, S>) => any, T[M]>>
15 descriptor: TypedPropertyDescriptor< T[M] extends ((...args: ExtractDependency<P, S>) => any) ? any : never >
32 ) => {
16 ) => {
33
17
34 };
18 };
35 }
19 }
36
20
37 getDescriptor(): TypeRegistration<new () => T, S> {
21 getDescriptor(): TypeRegistration<new () => T, S> {
38 throw new Error();
22 throw new Error();
39 }
23 }
40
24
41 }
25 }
42
43 export interface DependencyOptions<T> {
44 optional?: boolean;
45 default?: T;
46 }
47
48 export interface LazyDependencyOptions<T> extends DependencyOptions<T> {
49 lazy: true;
50 }
51
52 interface Declaration<S extends object> {
53 define<T>(): Builder<T, S>;
54
55 dependency<K extends keyof S>(name: K, opts: LazyDependencyOptions<S[K]>): LazyDependencyRegistration<S, K>;
56 dependency<K extends keyof S>(name: K, opts?: DependencyOptions<S[K]>): DependencyRegistration<S, K>;
57
58 $type<T, P extends any[], C extends new (...args: ExtractDependency<P, S>) => T>(target: C, ...params: P): StrictTypeRegistration<C, S>;
59 }
60
61
62 export declare function declare<S extends object>(): Declaration<S>;
@@ -1,47 +1,68
1 import { primitive } from "../../safe";
1 import { primitive } from "../../safe";
2 import { ActivationType } from "../interfaces";
2 import { ActivationType } from "../interfaces";
3 import { Builder } from "../Annotations";
3 import { AnnotaionBuilder } from "../Annotations";
4 import { LazyDependencyRegistration, DependencyRegistration } from "../Configuration";
5 import { PromiseOrValue } from "../../interfaces";
4
6
5 type ExtractService<K, S> = K extends keyof S ? S[K] : K;
7 export interface DependencyOptions<T> {
8 optional?: boolean;
9 default?: T;
10 }
6
11
7 type ExtractDependency<D, S> = D extends { $dependency: infer K } ?
12 export interface LazyDependencyOptions<T> extends DependencyOptions<T> {
13 lazy: true;
14 }
15
16 export type ExtractService<K, S> = K extends keyof S ? S[K] : K;
17
18 export type ExtractDependency<D, S> = D extends { $dependency: infer K } ?
8 D extends { lazy: true } ? () => ExtractService<K, S> : ExtractService<K, S> :
19 D extends { lazy: true } ? () => ExtractService<K, S> : ExtractService<K, S> :
9 D extends { $type: new (...args: any[]) => infer I } ? I :
20 D extends { $type: new (...args: any[]) => infer I } ? I :
10 D extends { $factory: (...args: any[]) => infer R } ? R :
21 D extends { $factory: (...args: any[]) => infer R } ? R :
11 WalkDependencies<D, S>;
22 WalkDependencies<D, S>;
12
23
13 type WalkDependencies<D, S> = D extends primitive ? D :
24 export type WalkDependencies<D, S> = D extends primitive ? D :
14 { [K in keyof D]: ExtractDependency<D[K], S> };
25 { [K in keyof D]: ExtractDependency<D[K], S> };
15
26
16 type ServiceModule<T, S extends object, M extends keyof any = "service"> = {
27 export type ServiceModule<T, S extends object, M extends keyof any = "service"> = {
17 [m in M]: Builder<T, S>;
28 [m in M]: AnnotaionBuilder<T, S>;
18 };
29 };
19
30
20 type PromiseOrValue<T> = T | PromiseLike<T>;
31 export interface ServiceBuilder<T, S extends object> {
21
22 export interface TypeBuilder<T, S extends object> {
23 type<P extends any[], C extends new (...args: ExtractDependency<P, S>) => T>(
32 type<P extends any[], C extends new (...args: ExtractDependency<P, S>) => T>(
24 target: C, ...params: P): ConstructorBuilder<C, S>;
33 target: C, ...params: P): ConstructorBuilder<C, S>;
25 factory<P extends any[], F extends (...args: ExtractDependency<P, S>) => T>(
34 factory<P extends any[], F extends (...args: ExtractDependency<P, S>) => T>(
26 target: F, ...params: P): FactoryBuilder<F, S>;
35 target: F, ...params: P): FactoryBuilder<F, S>;
27 wire<M extends keyof any>(module: PromiseOrValue<ServiceModule<T, S, M>>, m: M): ServiceBuilder<T, S>;
36 wired<M extends keyof any>(module: PromiseOrValue<ServiceModule<T, S, M>>, m: M): RegistrationBuilder<T, S>;
28 wire(module: PromiseOrValue<ServiceModule<T, S>>): ServiceBuilder<T, S>;
37 wired(module: PromiseOrValue<ServiceModule<T, S>>): RegistrationBuilder<T, S>;
29 }
38 }
30
39
31 export interface ServiceBuilder<T, S extends object> {
40 export interface RegistrationBuilder<T, S extends object> {
32 override<K extends keyof S>(name: K, builder: S[K] | ((t: TypeBuilder<S[K], S>) => any)): this;
41 override<K extends keyof S>(name: K, builder: S[K] | ((t: ServiceBuilder<S[K], S>) => any)): this;
33 activate(activation: ActivationType): this;
42 activate(activation: ActivationType): this;
34 inject<M extends keyof T, P extends any[]>(member: T[M] extends (...params: ExtractDependency<P, S>) => any ? M : never, ...params: P): this;
43 inject<M extends keyof T, P extends any[]>(member: T[M] extends (...params: ExtractDependency<P, S>) => any ? M : never, ...params: P): this;
35 }
44 }
36
45
37 export interface ConstructorBuilder<C extends new (...args: any[]) => any, S extends object> extends ServiceBuilder<InstanceType<C>, S> {
46 export interface ConstructorBuilder<C extends new (...args: any[]) => any, S extends object> extends RegistrationBuilder<InstanceType<C>, S> {
38 $type: C;
47 $type: C;
39 }
48 }
40
49
41 export interface FactoryBuilder<F extends (...args: any[]) => any, S extends object> extends ServiceBuilder<ReturnType<F>, S> {
50 export interface FactoryBuilder<F extends (...args: any[]) => any, S extends object> extends RegistrationBuilder<ReturnType<F>, S> {
42 $factory: F;
51 $factory: F;
43 }
52 }
44
53
45 export interface ConfigBuilder<S extends object, Y extends keyof S = keyof S> {
54 export interface ConfigBuilder<S extends object, Y extends keyof S = keyof S> {
46 register<K extends Y>(name: K, builder: S[K] | ((t: TypeBuilder<S[K], S>) => any)): ConfigBuilder<S, Exclude<Y, K>>;
55 register<K extends Y>(name: K, builder: S[K] | ((t: ServiceBuilder<S[K], S>) => any)): ConfigBuilder<S, Exclude<Y, K>>;
47 }
56 }
57
58 interface ServicesDeclaration<S extends object> {
59 build<T>(this: void): ServiceBuilder<T, S>;
60 annotate<T>(this: void): AnnotaionBuilder<T, S>;
61
62 dependency<K extends keyof S>(this: void, name: K, opts: LazyDependencyOptions<S[K]>): LazyDependencyRegistration<S, K>;
63 dependency<K extends keyof S>(this: void, name: K, opts?: DependencyOptions<S[K]>): DependencyRegistration<S, K>;
64
65 configure(): ConfigBuilder<S>;
66 }
67
68 export declare function declare<S extends object>(): ServicesDeclaration<S>;
@@ -1,116 +1,118
1 export interface Constructor<T = {}> {
1 export interface Constructor<T = {}> {
2 new(...args: any[]): T;
2 new(...args: any[]): T;
3 prototype: T;
3 prototype: T;
4 }
4 }
5
5
6 export type PromiseOrValue<T> = T | PromiseLike<T>;
7
6 export type Factory<T = {}> = (...args: any[]) => T;
8 export type Factory<T = {}> = (...args: any[]) => T;
7
9
8 export type Predicate<T = any> = (x: T) => boolean;
10 export type Predicate<T = any> = (x: T) => boolean;
9
11
10 export interface MapOf<T> {
12 export interface MapOf<T> {
11 [key: string]: T;
13 [key: string]: T;
12 }
14 }
13
15
14 export interface IDestroyable {
16 export interface IDestroyable {
15 destroy(): void;
17 destroy(): void;
16 }
18 }
17
19
18 export interface IRemovable {
20 export interface IRemovable {
19 remove(): void;
21 remove(): void;
20 }
22 }
21
23
22 export interface ICancellation {
24 export interface ICancellation {
23 throwIfRequested(): void;
25 throwIfRequested(): void;
24 isRequested(): boolean;
26 isRequested(): boolean;
25 isSupported(): boolean;
27 isSupported(): boolean;
26 register(cb: (e: any) => void): IDestroyable;
28 register(cb: (e: any) => void): IDestroyable;
27 }
29 }
28
30
29 /**
31 /**
30 * Интерфейс поддерживающий асинхронную активацию
32 * Интерфейс поддерживающий асинхронную активацию
31 */
33 */
32 export interface IActivatable {
34 export interface IActivatable {
33 /**
35 /**
34 * @returns Boolean indicates the current state
36 * @returns Boolean indicates the current state
35 */
37 */
36 isActive(): boolean;
38 isActive(): boolean;
37
39
38 /**
40 /**
39 * Starts the component activation
41 * Starts the component activation
40 * @param ct cancellation token for this operation
42 * @param ct cancellation token for this operation
41 */
43 */
42 activate(ct?: ICancellation): Promise<void>;
44 activate(ct?: ICancellation): Promise<void>;
43
45
44 /**
46 /**
45 * Starts the component deactivation
47 * Starts the component deactivation
46 * @param ct cancellation token for this operation
48 * @param ct cancellation token for this operation
47 */
49 */
48 deactivate(ct?: ICancellation): Promise<void>;
50 deactivate(ct?: ICancellation): Promise<void>;
49
51
50 /**
52 /**
51 * Sets the activation controller for this component
53 * Sets the activation controller for this component
52 * @param controller The activation controller
54 * @param controller The activation controller
53 *
55 *
54 * Activation controller checks whether this component
56 * Activation controller checks whether this component
55 * can be activated and manages the active state of the
57 * can be activated and manages the active state of the
56 * component
58 * component
57 */
59 */
58 setActivationController(controller: IActivationController): void;
60 setActivationController(controller: IActivationController): void;
59
61
60 /** Indicates whether this component has an activation controller */
62 /** Indicates whether this component has an activation controller */
61 hasActivationController(): boolean;
63 hasActivationController(): boolean;
62
64
63 /**
65 /**
64 * Gets the current activation controller for this component
66 * Gets the current activation controller for this component
65 */
67 */
66 getActivationController(): IActivationController;
68 getActivationController(): IActivationController;
67 }
69 }
68
70
69 export interface IActivationController {
71 export interface IActivationController {
70 activating(component: IActivatable, ct?: ICancellation): Promise<void>;
72 activating(component: IActivatable, ct?: ICancellation): Promise<void>;
71
73
72 activated(component: IActivatable, ct?: ICancellation): Promise<void>;
74 activated(component: IActivatable, ct?: ICancellation): Promise<void>;
73
75
74 deactivating(component: IActivatable, ct?: ICancellation): Promise<void>;
76 deactivating(component: IActivatable, ct?: ICancellation): Promise<void>;
75
77
76 deactivated(component: IActivatable, ct?: ICancellation): Promise<void>;
78 deactivated(component: IActivatable, ct?: ICancellation): Promise<void>;
77
79
78 deactivate(ct?: ICancellation): Promise<void>;
80 deactivate(ct?: ICancellation): Promise<void>;
79
81
80 activate(component: IActivatable, ct?: ICancellation): Promise<void>;
82 activate(component: IActivatable, ct?: ICancellation): Promise<void>;
81
83
82 hasActive(): boolean;
84 hasActive(): boolean;
83
85
84 getActive(): IActivatable;
86 getActive(): IActivatable;
85 }
87 }
86
88
87 export interface IAsyncComponent {
89 export interface IAsyncComponent {
88 getCompletion(): Promise<void>;
90 getCompletion(): Promise<void>;
89 }
91 }
90
92
91 export interface ICancellable {
93 export interface ICancellable {
92 cancel(reason?: any): void;
94 cancel(reason?: any): void;
93 }
95 }
94
96
95 export interface IObservable<T> {
97 export interface IObservable<T> {
96 on(next: (x: T) => void, error?: (e: any) => void, complete?: () => void): IDestroyable;
98 on(next: (x: T) => void, error?: (e: any) => void, complete?: () => void): IDestroyable;
97 next(ct?: ICancellation): Promise<T>;
99 next(ct?: ICancellation): Promise<T>;
98 }
100 }
99
101
100 export interface IObserver<T> {
102 export interface IObserver<T> {
101 next(event: T): void;
103 next(event: T): void;
102
104
103 error(e: any): void;
105 error(e: any): void;
104
106
105 complete(): void;
107 complete(): void;
106 }
108 }
107
109
108 export interface TextWriter {
110 export interface TextWriter {
109 write(obj: any): void;
111 write(obj: any): void;
110 write(format: string, ...args: any[]): void;
112 write(format: string, ...args: any[]): void;
111
113
112 writeLine(obj?: any): void;
114 writeLine(obj?: any): void;
113 writeLine(format: string, ...args: any[]): void;
115 writeLine(format: string, ...args: any[]): void;
114
116
115 writeValue(value: any, spec?: string): void;
117 writeValue(value: any, spec?: string): void;
116 }
118 }
@@ -1,39 +1,39
1 import { Foo } from "./Foo";
1 import { Foo } from "./Foo";
2 import { define, dependency } from "./services";
2 import { annotate, dependency } from "./services";
3
3
4 export const service = define<Bar>();
4 export const service = annotate<Bar>();
5
5
6 @service.declare({
6 @service.wire({
7 foo: dependency("foo"),
7 foo: dependency("foo"),
8 nested: {
8 nested: {
9 lazy: dependency("foo", { lazy: true })
9 lazy: dependency("foo", { lazy: true })
10 },
10 },
11 host: dependency("host")
11 host: dependency("host")
12 }, "")
12 }, "")
13 export class Bar {
13 export class Bar {
14 barName = "bar";
14 barName = "Twister";
15
15
16 _v: Foo | undefined;
16 _v: Foo | undefined;
17
17
18 constructor(_opts: {
18 constructor(_opts: {
19 foo?: Foo;
19 foo?: Foo;
20 nested?: {
20 nested?: {
21 lazy: () => Foo
21 lazy: () => Foo
22 },
22 },
23 host: string
23 host: string
24 }, s: string) {
24 }, s: string) {
25
25
26 if (_opts && _opts.foo)
26 if (_opts && _opts.foo)
27 this._v = _opts.foo;
27 this._v = _opts.foo;
28 }
28 }
29
29
30 setName(name: string) {
30 setName(name: string) {
31
31
32 }
32 }
33
33
34 getFoo() {
34 getFoo() {
35 if (this._v === undefined)
35 if (this._v === undefined)
36 throw new Error("The foo isn't set");
36 throw new Error("The foo isn't set");
37 return this._v;
37 return this._v;
38 }
38 }
39 }
39 }
@@ -1,33 +1,29
1 import { Bar } from "./Bar";
1 import { Bar } from "./Bar";
2 import { define, dependency } from "./services";
2 import { annotate, dependency } from "./services";
3
3
4 // export service descriptor
4 // export service descriptor
5 // через service передается информация о типе зависимости
5 // через service передается информация о типе зависимости
6 // даже если это шаблон.
6 // даже если это шаблон.
7 export const service = define<Box<Bar>>();
7 export const service = annotate<Box<Bar>>();
8
8
9 @service.declare(dependency("bar"))
9 @service.wire()
10 export class Box<T> {
10 export class Box<T> {
11 private _value: T | undefined;
11 private _value: T | undefined;
12
12
13 constructor(value: T) {
13 constructor(value?: T) {
14 this._value = value;
14 this._value = value;
15 }
15 }
16
16
17 @service.inject(dependency("bar"))
17 @service.inject(dependency("bar"))
18 setValue(value: T) {
18 setValue(value: T) {
19 this._value = value;
19 this._value = value;
20 return value;
20 return value;
21 }
21 }
22
22
23 setObj(value: any) {
24
25 }
26
27 getValue() {
23 getValue() {
28 if (this._value === undefined)
24 if (this._value === undefined)
29 throw new Error("Trying to get a value from the empty box");
25 throw new Error("Trying to get a value from the empty box");
30
26
31 return this._value;
27 return this._value;
32 }
28 }
33 }
29 }
@@ -1,32 +1,28
1 import { configure, dependency, Services, $type } from "./services";
1 import { configure, dependency, build } from "./services";
2 import { Foo } from "./Foo";
2 import { Foo } from "./Foo";
3 import { Bar } from "./Bar";
3 import { Bar } from "./Bar";
4 import { Box } from "./Box";
4 import { Box } from "./Box";
5 import { ConfigBuilder, TypeBuilder } from "../di/fluent/interfaces";
6
5
7 export declare function build<T>(): TypeBuilder<T, Services>;
6 export const config = configure()
8
9 export declare const config: ConfigBuilder<Services>;
10 config
11 .register("bar", s => s
7 .register("bar", s => s
12 .wire(import("./Bar"), "service")
8 .wired(import("./Bar"), "service")
13 .inject("setName", "heell")
9 .inject("setName", "heell")
14 )
10 )
15 .register("box", s => s.wire(import("./Box")))
11 .register("box", s => s.wired(import("./Box")))
16 .register("host", "example.com")
12 .register("host", "example.com")
17 // .registerType("bar2", Bar, [{ foo: dependency("foo"), host: "" }]);
13 // .registerType("bar2", Bar, [{ foo: dependency("foo"), host: "" }]);
18 .register("bar2", s => s.type(Bar,
14 .register("bar2", s => s.type(Bar,
19 {
15 {
20 foo: build().type(Foo)
16 foo: build().type(Foo)
21 .activate("context"),
17 .activate("context"),
22 nested: { lazy: dependency("foo", {lazy: true}) },
18 nested: { lazy: dependency("foo", {lazy: true}) },
23 host: dependency("host")
19 host: dependency("host")
24 },
20 },
25 "")
21 "")
26 .inject("setName", dependency("host"))
22 .inject("setName", dependency("host"))
27 )
23 )
28 .register("box", s => s
24 .register("box", s => s
29 .type(Box, dependency("bar"))
25 .type(Box, dependency("bar"))
30 .activate("context")
26 .activate("context")
31 );
27 );
32
28
@@ -1,25 +1,25
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 { declare } from "../di/Annotations";
4 import { declare } from "../di/fluent/interfaces";
5
5
6 /**
6 /**
7 * Сервисы доступные внутри контейнера
7 * Сервисы доступные внутри контейнера
8 */
8 */
9 export interface Services {
9 export interface Services {
10 foo: Foo;
10 foo: Foo;
11
11
12 bar: Bar;
12 bar: Bar;
13
13
14 bar2: Bar;
14 bar2: Bar;
15
15
16 box: Box<Bar>;
16 box: Box<Bar>;
17
17
18 host: string;
18 host: string;
19
19
20 }
20 }
21
21
22 /**
22 /**
23 * Экспортируем вспомогательные функции для описания сервисов и кинфогурации
23 * Экспортируем вспомогательные функции для описания сервисов и кинфогурации
24 */
24 */
25 export const { define, dependency } = declare<Services>();
25 export const { dependency, build, annotate, configure } = declare<Services>();
General Comments 0
You need to be logged in to leave comments. Login now