-
-
Notifications
You must be signed in to change notification settings - Fork 7.7k
/
instance-links-host.ts
94 lines (82 loc) · 2.87 KB
/
instance-links-host.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
import { InjectionToken } from '@nestjs/common';
import { isFunction } from '@nestjs/common/utils/shared.utils';
import { UnknownElementException } from '../errors/exceptions/unknown-element.exception';
import { NestContainer } from './container';
import { InstanceWrapper } from './instance-wrapper';
import { Module } from './module';
type HostCollection = 'providers' | 'controllers' | 'injectables';
export interface InstanceLink<T = any> {
token: InjectionToken;
wrapperRef: InstanceWrapper<T>;
collection: Map<any, InstanceWrapper>;
moduleId: string;
}
export class InstanceLinksHost {
private readonly instanceLinks = new Map<InjectionToken, InstanceLink[]>();
constructor(private readonly container: NestContainer) {
this.initialize();
}
get<T = any>(token: InjectionToken): InstanceLink<T>;
get<T = any>(
token: InjectionToken,
options?: { moduleId?: string; each?: boolean },
): InstanceLink<T> | Array<InstanceLink<T>>;
get<T = any>(
token: InjectionToken,
options: { moduleId?: string; each?: boolean } = {},
): InstanceLink<T> | Array<InstanceLink<T>> {
const instanceLinksForGivenToken = this.instanceLinks.get(token);
if (!instanceLinksForGivenToken) {
throw new UnknownElementException(this.getInstanceNameByToken(token));
}
if (options.each) {
return instanceLinksForGivenToken;
}
const instanceLink = options.moduleId
? instanceLinksForGivenToken.find(
item => item.moduleId === options.moduleId,
)
: instanceLinksForGivenToken[instanceLinksForGivenToken.length - 1];
if (!instanceLink) {
throw new UnknownElementException(this.getInstanceNameByToken(token));
}
return instanceLink;
}
private initialize() {
const modules = this.container.getModules();
modules.forEach(moduleRef => {
const { providers, injectables, controllers } = moduleRef;
providers.forEach((wrapper, token) =>
this.addLink(wrapper, token, moduleRef, 'providers'),
);
injectables.forEach((wrapper, token) =>
this.addLink(wrapper, token, moduleRef, 'injectables'),
);
controllers.forEach((wrapper, token) =>
this.addLink(wrapper, token, moduleRef, 'controllers'),
);
});
}
private addLink(
wrapper: InstanceWrapper,
token: InjectionToken,
moduleRef: Module,
collectionName: HostCollection,
) {
const instanceLink: InstanceLink = {
moduleId: moduleRef.id,
wrapperRef: wrapper,
collection: moduleRef[collectionName],
token,
};
const existingLinks = this.instanceLinks.get(token);
if (!existingLinks) {
this.instanceLinks.set(token, [instanceLink]);
} else {
existingLinks.push(instanceLink);
}
}
private getInstanceNameByToken(token: InjectionToken): string {
return isFunction(token) ? (token as Function)?.name : (token as string);
}
}