-
Notifications
You must be signed in to change notification settings - Fork 0
/
container-impl.ts
155 lines (136 loc) · 4.44 KB
/
container-impl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import {
Container,
ResolveFactoryFunction,
FactoryRegistry,
DependencyInjectionError,
Token,
Constructor,
Constructor1,
Constructor2,
Constructor3,
Constructor4,
Constructor5,
Constructor6,
Constructor7,
ClassProvider1,
ClassProvider2,
ClassProvider3,
ClassProvider4,
ClassProvider5,
ClassProvider6,
ClassProvider7,
ResolveProvider,
ValueProvider,
ClassBaseProvider,
} from '../interfaces';
import { memoize } from './utils';
export class ContainerImpl extends Container {
public useValue<T, TResult extends T>(provider: ValueProvider<T, TResult>): Container {
this.register(provider.for, () => provider.use);
return this;
}
public useFactory<T, TResult extends T>(provider: ResolveProvider<T, TResult>): Container {
this.register(provider.for, provider.use, provider.singleton);
return this;
}
public useClass<T, TCtor extends Constructor1<T, TCtorArg1>, TCtorArg1>(
provider: ClassProvider1<T, TCtor, TCtorArg1>
): Container;
public useClass<T, TCtor extends Constructor2<T, TCtorArg1, TCtorArg2>, TCtorArg1, TCtorArg2>(
provider: ClassProvider2<T, TCtor, TCtorArg1, TCtorArg2>
): Container;
public useClass<T, TCtor extends Constructor3<T, TCtorArg1, TCtorArg2, TCtorArg3>, TCtorArg1, TCtorArg2, TCtorArg3>(
provider: ClassProvider3<T, TCtor, TCtorArg1, TCtorArg2, TCtorArg3>
): Container;
public useClass<
T,
TCtor extends Constructor4<T, TCtorArg1, TCtorArg2, TCtorArg3, TCtorArg4>,
TCtorArg1,
TCtorArg2,
TCtorArg3,
TCtorArg4
>(provider: ClassProvider4<T, TCtor, TCtorArg1, TCtorArg2, TCtorArg3, TCtorArg4>): Container;
public useClass<
T,
TCtor extends Constructor5<T, TCtorArg1, TCtorArg2, TCtorArg3, TCtorArg4, TCtorArg5>,
TCtorArg1,
TCtorArg2,
TCtorArg3,
TCtorArg4,
TCtorArg5
>(provider: ClassProvider5<T, TCtor, TCtorArg1, TCtorArg2, TCtorArg3, TCtorArg4, TCtorArg5>): Container;
public useClass<
T,
TCtor extends Constructor6<T, TCtorArg1, TCtorArg2, TCtorArg3, TCtorArg4, TCtorArg5, TCtorArg6>,
TCtorArg1,
TCtorArg2,
TCtorArg3,
TCtorArg4,
TCtorArg5,
TCtorArg6
>(provider: ClassProvider6<T, TCtor, TCtorArg1, TCtorArg2, TCtorArg3, TCtorArg4, TCtorArg5, TCtorArg6>): Container;
public useClass<
T,
TCtor extends Constructor7<T, TCtorArg1, TCtorArg2, TCtorArg3, TCtorArg4, TCtorArg5, TCtorArg6, TCtorArg7>,
TCtorArg1,
TCtorArg2,
TCtorArg3,
TCtorArg4,
TCtorArg5,
TCtorArg6,
TCtorArg7
>(
provider: ClassProvider7<T, TCtor, TCtorArg1, TCtorArg2, TCtorArg3, TCtorArg4, TCtorArg5, TCtorArg6, TCtorArg7>
): Container;
public useClass(provider: ClassBaseProvider<unknown, Constructor<unknown>>): Container {
this.register(
provider.for,
() => {
const Ctor = provider.use;
const depTokens = provider.inject ?? [];
const deps = depTokens.map((token) => this.resolve(token));
return new Ctor(...deps);
},
provider.singleton
);
return this;
}
public constructor(private readonly factoryRegistry: FactoryRegistry) {
super();
}
private register<T>(token: Token<T>, factory: ResolveFactoryFunction<T>, singleton?: boolean): this {
if (this.factoryRegistry.hasFactory(token)) {
const displayToken = this.getTokenDisplayName(token);
throw new DependencyInjectionError(`Factory is already registered for '${displayToken}'`);
}
const finalFactory = singleton ? memoize(factory) : factory;
this.factoryRegistry.setFactory(token, finalFactory);
return this;
}
public resolve<T>(token: Token<T>): T {
const factory = this.factoryRegistry.getFactory(token);
if (factory == null) {
const displayToken = this.getTokenDisplayName(token);
throw new DependencyInjectionError(`Unable to resolve '${displayToken}'`);
}
try {
return factory(this) as T;
} catch (err) {
const innerError = err instanceof Error ? err : undefined;
const displayToken = this.getTokenDisplayName(token);
throw new DependencyInjectionError(`Error resolving '${displayToken}'`, innerError);
}
}
public tryVerifyAll(): boolean {
return true;
}
public verifyAll(): void {
this.factoryRegistry.forEach((factory, token) => {
console.log(token, factory);
});
}
private getTokenDisplayName<T>(token: Token<T>): string {
const displayToken = token instanceof Function ? token.name : token.toString();
return displayToken;
}
}