UNPKG

15.5 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.Module = void 0;
4const constants_1 = require("@nestjs/common/constants");
5const random_string_generator_util_1 = require("@nestjs/common/utils/random-string-generator.util");
6const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
7const iterare_1 = require("iterare");
8const application_config_1 = require("../application-config");
9const exceptions_1 = require("../errors/exceptions");
10const context_id_factory_1 = require("../helpers/context-id-factory");
11const get_class_scope_1 = require("../helpers/get-class-scope");
12const is_durable_1 = require("../helpers/is-durable");
13const uuid_factory_1 = require("../inspector/uuid-factory");
14const constants_2 = require("./constants");
15const instance_wrapper_1 = require("./instance-wrapper");
16const module_ref_1 = require("./module-ref");
17class Module {
18 constructor(_metatype, container) {
19 this._metatype = _metatype;
20 this.container = container;
21 this._imports = new Set();
22 this._providers = new Map();
23 this._injectables = new Map();
24 this._middlewares = new Map();
25 this._controllers = new Map();
26 this._entryProviderKeys = new Set();
27 this._exports = new Set();
28 this._distance = 0;
29 this._initOnPreview = false;
30 this._isGlobal = false;
31 this.addCoreProviders();
32 this._id = this.generateUuid();
33 }
34 get id() {
35 return this._id;
36 }
37 get token() {
38 return this._token;
39 }
40 set token(token) {
41 this._token = token;
42 }
43 get name() {
44 return this.metatype.name;
45 }
46 get isGlobal() {
47 return this._isGlobal;
48 }
49 set isGlobal(global) {
50 this._isGlobal = global;
51 }
52 get initOnPreview() {
53 return this._initOnPreview;
54 }
55 set initOnPreview(initOnPreview) {
56 this._initOnPreview = initOnPreview;
57 }
58 get providers() {
59 return this._providers;
60 }
61 get middlewares() {
62 return this._middlewares;
63 }
64 get imports() {
65 return this._imports;
66 }
67 get injectables() {
68 return this._injectables;
69 }
70 get controllers() {
71 return this._controllers;
72 }
73 get entryProviders() {
74 return Array.from(this._entryProviderKeys).map(token => this.providers.get(token));
75 }
76 get exports() {
77 return this._exports;
78 }
79 get instance() {
80 if (!this._providers.has(this._metatype)) {
81 throw new exceptions_1.RuntimeException();
82 }
83 const module = this._providers.get(this._metatype);
84 return module.instance;
85 }
86 get metatype() {
87 return this._metatype;
88 }
89 get distance() {
90 return this._distance;
91 }
92 set distance(value) {
93 this._distance = value;
94 }
95 addCoreProviders() {
96 this.addModuleAsProvider();
97 this.addModuleRef();
98 this.addApplicationConfig();
99 }
100 addModuleRef() {
101 const moduleRef = this.createModuleReferenceType();
102 this._providers.set(module_ref_1.ModuleRef, new instance_wrapper_1.InstanceWrapper({
103 token: module_ref_1.ModuleRef,
104 name: module_ref_1.ModuleRef.name,
105 metatype: module_ref_1.ModuleRef,
106 isResolved: true,
107 instance: new moduleRef(),
108 host: this,
109 }));
110 }
111 addModuleAsProvider() {
112 this._providers.set(this._metatype, new instance_wrapper_1.InstanceWrapper({
113 token: this._metatype,
114 name: this._metatype.name,
115 metatype: this._metatype,
116 isResolved: false,
117 instance: null,
118 host: this,
119 }));
120 }
121 addApplicationConfig() {
122 this._providers.set(application_config_1.ApplicationConfig, new instance_wrapper_1.InstanceWrapper({
123 token: application_config_1.ApplicationConfig,
124 name: application_config_1.ApplicationConfig.name,
125 isResolved: true,
126 instance: this.container.applicationConfig,
127 host: this,
128 }));
129 }
130 addInjectable(injectable, enhancerSubtype, host) {
131 if (this.isCustomProvider(injectable)) {
132 return this.addCustomProvider(injectable, this._injectables, enhancerSubtype);
133 }
134 let instanceWrapper = this.injectables.get(injectable);
135 if (!instanceWrapper) {
136 instanceWrapper = new instance_wrapper_1.InstanceWrapper({
137 token: injectable,
138 name: injectable.name,
139 metatype: injectable,
140 instance: null,
141 isResolved: false,
142 scope: (0, get_class_scope_1.getClassScope)(injectable),
143 durable: (0, is_durable_1.isDurable)(injectable),
144 subtype: enhancerSubtype,
145 host: this,
146 });
147 this._injectables.set(injectable, instanceWrapper);
148 }
149 if (host) {
150 const hostWrapper = this._controllers.get(host) || this._providers.get(host);
151 hostWrapper && hostWrapper.addEnhancerMetadata(instanceWrapper);
152 }
153 return instanceWrapper;
154 }
155 addProvider(provider, enhancerSubtype) {
156 if (this.isCustomProvider(provider)) {
157 if (this.isEntryProvider(provider.provide)) {
158 this._entryProviderKeys.add(provider.provide);
159 }
160 return this.addCustomProvider(provider, this._providers, enhancerSubtype);
161 }
162 this._providers.set(provider, new instance_wrapper_1.InstanceWrapper({
163 token: provider,
164 name: provider.name,
165 metatype: provider,
166 instance: null,
167 isResolved: false,
168 scope: (0, get_class_scope_1.getClassScope)(provider),
169 durable: (0, is_durable_1.isDurable)(provider),
170 host: this,
171 }));
172 if (this.isEntryProvider(provider)) {
173 this._entryProviderKeys.add(provider);
174 }
175 return provider;
176 }
177 isCustomProvider(provider) {
178 return !(0, shared_utils_1.isNil)(provider.provide);
179 }
180 addCustomProvider(provider, collection, enhancerSubtype) {
181 if (this.isCustomClass(provider)) {
182 this.addCustomClass(provider, collection, enhancerSubtype);
183 }
184 else if (this.isCustomValue(provider)) {
185 this.addCustomValue(provider, collection, enhancerSubtype);
186 }
187 else if (this.isCustomFactory(provider)) {
188 this.addCustomFactory(provider, collection, enhancerSubtype);
189 }
190 else if (this.isCustomUseExisting(provider)) {
191 this.addCustomUseExisting(provider, collection, enhancerSubtype);
192 }
193 return provider.provide;
194 }
195 isCustomClass(provider) {
196 return !(0, shared_utils_1.isUndefined)(provider.useClass);
197 }
198 isCustomValue(provider) {
199 return ((0, shared_utils_1.isObject)(provider) &&
200 Object.prototype.hasOwnProperty.call(provider, 'useValue'));
201 }
202 isCustomFactory(provider) {
203 return !(0, shared_utils_1.isUndefined)(provider.useFactory);
204 }
205 isCustomUseExisting(provider) {
206 return !(0, shared_utils_1.isUndefined)(provider.useExisting);
207 }
208 isDynamicModule(exported) {
209 return exported && exported.module;
210 }
211 addCustomClass(provider, collection, enhancerSubtype) {
212 let { scope, durable } = provider;
213 const { useClass } = provider;
214 if ((0, shared_utils_1.isUndefined)(scope)) {
215 scope = (0, get_class_scope_1.getClassScope)(useClass);
216 }
217 if ((0, shared_utils_1.isUndefined)(durable)) {
218 durable = (0, is_durable_1.isDurable)(useClass);
219 }
220 const token = provider.provide;
221 collection.set(token, new instance_wrapper_1.InstanceWrapper({
222 token,
223 name: useClass?.name || useClass,
224 metatype: useClass,
225 instance: null,
226 isResolved: false,
227 scope,
228 durable,
229 host: this,
230 subtype: enhancerSubtype,
231 }));
232 }
233 addCustomValue(provider, collection, enhancerSubtype) {
234 const { useValue: value, provide: providerToken } = provider;
235 collection.set(providerToken, new instance_wrapper_1.InstanceWrapper({
236 token: providerToken,
237 name: providerToken?.name || providerToken,
238 metatype: null,
239 instance: value,
240 isResolved: true,
241 async: value instanceof Promise,
242 host: this,
243 subtype: enhancerSubtype,
244 }));
245 }
246 addCustomFactory(provider, collection, enhancerSubtype) {
247 const { useFactory: factory, inject, scope, durable, provide: providerToken, } = provider;
248 collection.set(providerToken, new instance_wrapper_1.InstanceWrapper({
249 token: providerToken,
250 name: providerToken?.name || providerToken,
251 metatype: factory,
252 instance: null,
253 isResolved: false,
254 inject: inject || [],
255 scope,
256 durable,
257 host: this,
258 subtype: enhancerSubtype,
259 }));
260 }
261 addCustomUseExisting(provider, collection, enhancerSubtype) {
262 const { useExisting, provide: providerToken } = provider;
263 collection.set(providerToken, new instance_wrapper_1.InstanceWrapper({
264 token: providerToken,
265 name: providerToken?.name || providerToken,
266 metatype: (instance => instance),
267 instance: null,
268 isResolved: false,
269 inject: [useExisting],
270 host: this,
271 isAlias: true,
272 subtype: enhancerSubtype,
273 }));
274 }
275 addExportedProvider(provider) {
276 const addExportedUnit = (token) => this._exports.add(this.validateExportedProvider(token));
277 if (this.isCustomProvider(provider)) {
278 return this.addCustomExportedProvider(provider);
279 }
280 else if ((0, shared_utils_1.isString)(provider) || (0, shared_utils_1.isSymbol)(provider)) {
281 return addExportedUnit(provider);
282 }
283 else if (this.isDynamicModule(provider)) {
284 const { module: moduleClassRef } = provider;
285 return addExportedUnit(moduleClassRef);
286 }
287 addExportedUnit(provider);
288 }
289 addCustomExportedProvider(provider) {
290 const provide = provider.provide;
291 if ((0, shared_utils_1.isString)(provide) || (0, shared_utils_1.isSymbol)(provide)) {
292 return this._exports.add(this.validateExportedProvider(provide));
293 }
294 this._exports.add(this.validateExportedProvider(provide));
295 }
296 validateExportedProvider(token) {
297 if (this._providers.has(token)) {
298 return token;
299 }
300 const imports = (0, iterare_1.iterate)(this._imports.values())
301 .filter(item => !!item)
302 .map(({ metatype }) => metatype)
303 .filter(metatype => !!metatype)
304 .toArray();
305 if (!imports.includes(token)) {
306 const { name } = this.metatype;
307 const providerName = (0, shared_utils_1.isFunction)(token) ? token.name : token;
308 throw new exceptions_1.UnknownExportException(providerName, name);
309 }
310 return token;
311 }
312 addController(controller) {
313 this._controllers.set(controller, new instance_wrapper_1.InstanceWrapper({
314 token: controller,
315 name: controller.name,
316 metatype: controller,
317 instance: null,
318 isResolved: false,
319 scope: (0, get_class_scope_1.getClassScope)(controller),
320 durable: (0, is_durable_1.isDurable)(controller),
321 host: this,
322 }));
323 this.assignControllerUniqueId(controller);
324 }
325 assignControllerUniqueId(controller) {
326 Object.defineProperty(controller, constants_2.CONTROLLER_ID_KEY, {
327 enumerable: false,
328 writable: false,
329 configurable: true,
330 value: (0, random_string_generator_util_1.randomStringGenerator)(),
331 });
332 }
333 addImport(moduleRef) {
334 this._imports.add(moduleRef);
335 }
336 /**
337 * @deprecated
338 */
339 addRelatedModule(module) {
340 this._imports.add(module);
341 }
342 replace(toReplace, options) {
343 if (options.isProvider && this.hasProvider(toReplace)) {
344 const originalProvider = this._providers.get(toReplace);
345 return originalProvider.mergeWith({ provide: toReplace, ...options });
346 }
347 else if (!options.isProvider && this.hasInjectable(toReplace)) {
348 const originalInjectable = this._injectables.get(toReplace);
349 return originalInjectable.mergeWith({
350 provide: toReplace,
351 ...options,
352 });
353 }
354 }
355 hasProvider(token) {
356 return this._providers.has(token);
357 }
358 hasInjectable(token) {
359 return this._injectables.has(token);
360 }
361 getProviderByKey(name) {
362 return this._providers.get(name);
363 }
364 getProviderById(id) {
365 return Array.from(this._providers.values()).find(item => item.id === id);
366 }
367 getControllerById(id) {
368 return Array.from(this._controllers.values()).find(item => item.id === id);
369 }
370 getInjectableById(id) {
371 return Array.from(this._injectables.values()).find(item => item.id === id);
372 }
373 getMiddlewareById(id) {
374 return Array.from(this._middlewares.values()).find(item => item.id === id);
375 }
376 getNonAliasProviders() {
377 return [...this._providers].filter(([_, wrapper]) => !wrapper.isAlias);
378 }
379 createModuleReferenceType() {
380 // eslint-disable-next-line @typescript-eslint/no-this-alias
381 const self = this;
382 return class extends module_ref_1.ModuleRef {
383 constructor() {
384 super(self.container);
385 }
386 get(typeOrToken, options = {}) {
387 options.strict ??= true;
388 options.each ??= false;
389 return this.find(typeOrToken, options.strict
390 ? {
391 moduleId: self.id,
392 each: options.each,
393 }
394 : options);
395 }
396 resolve(typeOrToken, contextId = (0, context_id_factory_1.createContextId)(), options = {}) {
397 options.strict ??= true;
398 options.each ??= false;
399 return this.resolvePerContext(typeOrToken, self, contextId, options);
400 }
401 async create(type, contextId) {
402 if (!(type && (0, shared_utils_1.isFunction)(type) && type.prototype)) {
403 throw new exceptions_1.InvalidClassException(type);
404 }
405 return this.instantiateClass(type, self, contextId);
406 }
407 };
408 }
409 isEntryProvider(metatype) {
410 return typeof metatype === 'function'
411 ? !!Reflect.getMetadata(constants_1.ENTRY_PROVIDER_WATERMARK, metatype)
412 : false;
413 }
414 generateUuid() {
415 const prefix = 'M_';
416 const key = this.name?.toString() ?? this.token?.toString();
417 return key ? uuid_factory_1.UuidFactory.get(`${prefix}_${key}`) : (0, random_string_generator_util_1.randomStringGenerator)();
418 }
419}
420exports.Module = Module;