| @@ -0,0 +1,23 | |||
|
|
1 | import { Foo } from "./Foo"; | |
|
|
2 | import { Bar } from "./Bar"; | |
|
|
3 | import { Box } from "./Box"; | |
|
|
4 | import { declare } from "../di/Annotations"; | |
|
|
5 | ||
|
|
6 | /** | |
|
|
7 | * Сервисы доступные внутри контейнера | |
|
|
8 | */ | |
|
|
9 | export interface Services { | |
|
|
10 | foo: Foo; | |
|
|
11 | ||
|
|
12 | bar: Bar; | |
|
|
13 | ||
|
|
14 | box: Box<Bar>; | |
|
|
15 | ||
|
|
16 | host: string; | |
|
|
17 | ||
|
|
18 | } | |
|
|
19 | ||
|
|
20 | /** | |
|
|
21 | * Экспортируем вспомогательные функции для описания сервисов и кинфогурации | |
|
|
22 | */ | |
|
|
23 | export const { define, dependency, config } = declare<Services>(); | |
| @@ -1,75 +1,75 | |||
|
|
1 | import { Constructor } from "../interfaces"; | |
|
|
2 | 1 |
|
|
|
2 | import { TypeRegistration } from "./Configuration"; | |
|
|
3 | 3 | |
|
|
4 | 4 | export interface InjectOptions { |
|
|
5 | 5 | lazy?: boolean; |
|
|
6 | 6 | } |
|
|
7 | 7 | |
|
|
8 | interface Dependency<K extends keyof any> { | |
|
|
8 | export interface Dependency<K extends keyof any> { | |
|
|
9 | 9 | $dependency: K; |
|
|
10 | 10 | |
|
|
11 | 11 | lazy?: boolean; |
|
|
12 | 12 | } |
|
|
13 | 13 | |
|
|
14 | interface Lazy<K extends keyof any> extends Dependency<K> { | |
|
|
14 | export interface Lazy<K extends keyof any> extends Dependency<K> { | |
|
|
15 | 15 | lazy: true; |
|
|
16 | 16 | } |
|
|
17 | 17 | |
|
|
18 |
type Compatible<T1, T2> = T |
|
|
|
18 | type Compatible<T1, T2> = T2 extends T1 ? any : never; | |
|
|
19 | 19 | |
|
|
20 | 20 | type ExtractService<K, S> = K extends keyof S ? S[K] : K; |
|
|
21 | 21 | |
|
|
22 | 22 | type ExtractDependency<D, S> = D extends { $dependency: infer K } ? |
|
|
23 | 23 | D extends { lazy: true } ? () => ExtractService<K, S> : ExtractService<K, S> : |
|
|
24 | 24 | WalkDependencies<D, S>; |
|
|
25 | 25 | |
|
|
26 | 26 | type WalkDependencies<D, S> = D extends primitive ? D : |
|
|
27 | 27 | { [K in keyof D]: ExtractDependency<D[K], S> }; |
|
|
28 | 28 | |
|
|
29 | interface Services<S> { | |
|
|
30 | get<K extends keyof S>(name: K): Dependency<K>; | |
|
|
31 | ||
|
|
32 | lazy<K extends keyof S>(name: K): Lazy<K>; | |
|
|
33 | ||
|
|
34 | build<T extends object>(): Builder<T, S>; | |
|
|
35 | } | |
|
|
36 | ||
|
|
37 | export declare function services<S extends object>(): Services<S>; | |
|
|
38 | ||
|
|
39 | export declare function build<T = never, S = any>(): Builder<T, S>; | |
|
|
40 | ||
|
|
41 | 29 | export class Builder<T, S> { |
|
|
42 |
|
|
|
|
30 | declare<P extends any[]>(...args: P) { | |
|
|
43 | 31 | return <C extends new (...args: ExtractDependency<P, S>) => T>(constructor: C) => { |
|
|
32 | return constructor as C & { service: Builder<T, S> }; | |
|
|
44 | 33 | }; |
|
|
45 | 34 | } |
|
|
46 | 35 | |
|
|
47 | 36 | inject<P extends any[]>(...args: P) { |
|
|
48 | 37 | // K = "bar" |
|
|
49 | 38 | // M = "setValue" |
|
|
50 | 39 | // S[K] = Bar |
|
|
51 | 40 | // T[M] = (value: string) => void |
|
|
52 | 41 | // P[m] = (value: V) => void |
|
|
53 | 42 | return <X extends { [m in M]: (...args: any) => any }, M extends keyof (T | X)>( |
|
|
54 | 43 | target: X, |
|
|
55 | 44 | memberName: M, |
|
|
56 | 45 | descriptor: TypedPropertyDescriptor<Compatible<(...args: ExtractDependency<P, S>) => any, T[M]>> |
|
|
57 | 46 | ) => { |
|
|
58 | 47 | |
|
|
59 | 48 | }; |
|
|
60 | 49 | } |
|
|
61 | 50 | |
|
|
62 | cast<T2 extends T>(): Builder<T2, S> { | |
|
|
63 | return this as Builder<T2, S>; | |
|
|
64 | } | |
|
|
65 | ||
|
|
66 | get<K extends keyof S>(name: K): Dependency<K> { | |
|
|
51 | getDescriptor(): TypeRegistration<T, any, S> { | |
|
|
67 | 52 | throw new Error(); |
|
|
68 | 53 | } |
|
|
69 | 54 | |
|
|
70 | lazy<K extends keyof S>(name: K): Lazy<K> { | |
|
|
71 | throw new Error(); | |
|
|
72 | } | |
|
|
55 | } | |
|
|
56 | ||
|
|
57 | interface Declaration<S> { | |
|
|
58 | define<T>(): Builder<T, S>; | |
|
|
59 | ||
|
|
60 | dependency<K extends keyof S>(name: K, opts: { lazy: true }): Lazy<K>; | |
|
|
61 | dependency<K extends keyof S>(name: K, opts?: any): Dependency<K>; | |
|
|
62 | ||
|
|
63 | config(): Config<S>; | |
|
|
64 | } | |
|
|
73 | 65 | |
|
|
66 | interface ServiceModule<T, S> { | |
|
|
67 | service: Builder<T, S>; | |
|
|
68 | } | |
|
|
74 | 69 | |
|
|
70 | interface Config<S> { | |
|
|
71 | register<K extends keyof S>(name: K, builder: Builder<S[K], S>): Config<Omit<S, K>>; | |
|
|
72 | register<K extends keyof S>(name: K, m: Promise<ServiceModule<S[K], S>>): Config<Omit<S, K>>; | |
|
|
75 | 73 | } |
|
|
74 | ||
|
|
75 | export declare function declare<S extends object>(): Declaration<S>; | |
| @@ -1,33 +1,33 | |||
|
|
1 | 1 | import { Foo } from "./Foo"; |
|
|
2 |
import { |
|
|
|
2 | import { define, dependency } from "./services"; | |
|
|
3 | 3 | |
|
|
4 |
const service = |
|
|
|
4 | export const service = define<Bar>(); | |
|
|
5 | 5 | |
|
|
6 |
@service. |
|
|
|
7 |
foo: |
|
|
|
6 | @service.declare({ | |
|
|
7 | foo: dependency("foo"), | |
|
|
8 | 8 | nested: { |
|
|
9 |
lazy: |
|
|
|
9 | lazy: dependency("foo", {lazy: true}) | |
|
|
10 | 10 | } |
|
|
11 | 11 | }) |
|
|
12 | 12 | export class Bar { |
|
|
13 | 13 | barName = "bar"; |
|
|
14 | 14 | |
|
|
15 | 15 | _v: Foo | undefined; |
|
|
16 | 16 | |
|
|
17 | 17 | constructor(_opts?: { |
|
|
18 | 18 | foo?: Foo; |
|
|
19 | 19 | nested?: { |
|
|
20 | 20 | lazy: () => Foo |
|
|
21 | 21 | } |
|
|
22 | 22 | }) { |
|
|
23 | 23 | |
|
|
24 | 24 | if (_opts && _opts.foo) |
|
|
25 | 25 | this._v = _opts.foo; |
|
|
26 | 26 | } |
|
|
27 | 27 | |
|
|
28 | 28 | getFoo() { |
|
|
29 | 29 | if (this._v === undefined) |
|
|
30 | 30 | throw new Error("The foo isn't set"); |
|
|
31 | 31 | return this._v; |
|
|
32 | 32 | } |
|
|
33 | 33 | } |
| @@ -1,38 +1,33 | |||
|
|
1 | import { services } from "../di/Annotations"; | |
|
|
2 | 1 |
|
|
|
3 | import { Foo } from "./Foo"; | |
|
|
4 | ||
|
|
5 | // declare required dependencies | |
|
|
6 | const config = services<{ | |
|
|
7 | bar: Bar; | |
|
|
8 | foo: Foo; | |
|
|
9 | }>(); | |
|
|
2 | import { define, dependency } from "./services"; | |
|
|
10 | 3 | |
|
|
11 | 4 | // export service descriptor |
|
|
12 | export const service = config.build<Box<Bar>>(); | |
|
|
5 | // через service передается информация о типе зависимости | |
|
|
6 | // даже если это шаблон. | |
|
|
7 | export const service = define<Box<Bar>>(); | |
|
|
13 | 8 | |
|
|
14 |
@service. |
|
|
|
9 | @service.declare(dependency("bar")) | |
|
|
15 | 10 | export class Box<T> { |
|
|
16 | 11 | private _value: T | undefined; |
|
|
17 | 12 | |
|
|
18 | 13 | constructor(value: T) { |
|
|
19 | 14 | this._value = value; |
|
|
20 | 15 | } |
|
|
21 | 16 | |
|
|
22 |
@service.inject( |
|
|
|
23 |
setValue(value |
|
|
|
17 | @service.inject(dependency("bar")) | |
|
|
18 | setValue(value: T) { | |
|
|
24 | 19 | this._value = value; |
|
|
25 | 20 | return value; |
|
|
26 | 21 | } |
|
|
27 | 22 | |
|
|
28 |
setObj(value: |
|
|
|
23 | setObj(value: any) { | |
|
|
29 | 24 | |
|
|
30 | 25 | } |
|
|
31 | 26 | |
|
|
32 | 27 | getValue() { |
|
|
33 | 28 | if (this._value === undefined) |
|
|
34 | 29 | throw new Error("Trying to get a value from the empty box"); |
|
|
35 | 30 | |
|
|
36 | 31 | return this._value; |
|
|
37 | 32 | } |
|
|
38 | 33 | } |
| @@ -1,27 +1,6 | |||
|
|
1 |
import { |
|
|
|
2 | import { Bar } from "./Bar"; | |
|
|
3 | import { Box } from "./Box"; | |
|
|
4 | import { Builder } from "../di/Annotations"; | |
|
|
5 | ||
|
|
6 | interface Services { | |
|
|
7 | foo: Foo; | |
|
|
8 | ||
|
|
9 | bar: Bar; | |
|
|
10 | ||
|
|
11 | box: Box<Foo>; | |
|
|
12 | ||
|
|
13 | host: string; | |
|
|
1 | import { config } from "./services"; | |
|
|
14 | 2 | |
|
|
15 | } | |
|
|
16 | ||
|
|
17 | const services = { | |
|
|
18 | build: <T>() => { | |
|
|
19 | return new Builder<T, Services>(); | |
|
|
20 | } | |
|
|
21 | }; | |
|
|
22 | ||
|
|
23 | namespace services { | |
|
|
24 | ||
|
|
25 | } | |
|
|
26 | ||
|
|
27 | export = services; | |
|
|
3 | config() | |
|
|
4 | .register("bar", import("./Bar")) | |
|
|
5 | .register("box", import("./Box")) | |
|
|
6 | .register("foo", import("./Foo"), "Foo"); | |
General Comments 0
You need to be logged in to leave comments.
Login now
