• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nestjs / nest / 6e9bba89-0b66-4e3f-896c-1b3d2826bdc8

10 Feb 2025 03:11PM UTC coverage: 89.294% (-0.4%) from 89.692%
6e9bba89-0b66-4e3f-896c-1b3d2826bdc8

push

circleci

web-flow
Merge pull request #14597 from nestjs/perf/use-topology-tree-for-distance

perf(core): use topology tree for calculating distance (depth)

2664 of 3348 branches covered (79.57%)

23 of 63 new or added lines in 3 files covered. (36.51%)

1 existing line in 1 file now uncovered.

7123 of 7977 relevant lines covered (89.29%)

16.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.76
/packages/core/scanner.ts
1
import { DynamicModule, ForwardReference, Provider } from '@nestjs/common';
2
import {
1✔
3
  CATCH_WATERMARK,
4
  CONTROLLER_WATERMARK,
5
  ENHANCER_KEY_TO_SUBTYPE_MAP,
6
  EXCEPTION_FILTERS_METADATA,
7
  EnhancerSubtype,
8
  GUARDS_METADATA,
9
  INJECTABLE_WATERMARK,
10
  INTERCEPTORS_METADATA,
11
  MODULE_METADATA,
12
  PIPES_METADATA,
13
  ROUTE_ARGS_METADATA,
14
} from '@nestjs/common/constants';
15
import {
1✔
16
  CanActivate,
17
  ClassProvider,
18
  Controller,
19
  ExceptionFilter,
20
  ExistingProvider,
21
  FactoryProvider,
22
  Injectable,
23
  InjectionToken,
24
  NestInterceptor,
25
  PipeTransform,
26
  Scope,
27
  Type,
28
  ValueProvider,
29
} from '@nestjs/common/interfaces';
30
import {
1✔
31
  isFunction,
32
  isNil,
33
  isUndefined,
34
} from '@nestjs/common/utils/shared.utils';
35
import { iterate } from 'iterare';
1✔
36
import { ApplicationConfig } from './application-config';
1✔
37
import {
1✔
38
  APP_FILTER,
39
  APP_GUARD,
40
  APP_INTERCEPTOR,
41
  APP_PIPE,
42
  ENHANCER_TOKEN_TO_SUBTYPE_MAP,
43
} from './constants';
44
import { CircularDependencyException } from './errors/exceptions/circular-dependency.exception';
1✔
45
import { InvalidClassModuleException } from './errors/exceptions/invalid-class-module.exception';
1✔
46
import { InvalidModuleException } from './errors/exceptions/invalid-module.exception';
1✔
47
import { UndefinedModuleException } from './errors/exceptions/undefined-module.exception';
1✔
48
import { getClassScope } from './helpers/get-class-scope';
1✔
49
import { NestContainer } from './injector/container';
50
import { InstanceWrapper } from './injector/instance-wrapper';
51
import { InternalCoreModuleFactory } from './injector/internal-core-module/internal-core-module-factory';
1✔
52
import { Module } from './injector/module';
53
import { TopologyTree } from './injector/topology-tree/topology-tree';
1✔
54
import { GraphInspector } from './inspector/graph-inspector';
55
import { UuidFactory } from './inspector/uuid-factory';
1✔
56
import { ModuleDefinition } from './interfaces/module-definition.interface';
57
import { ModuleOverride } from './interfaces/module-override.interface';
58
import { MetadataScanner } from './metadata-scanner';
59

60
interface ApplicationProviderWrapper {
61
  moduleKey: string;
62
  providerKey: string;
63
  type: InjectionToken;
64
  scope?: Scope;
65
}
66

67
interface ModulesScanParameters {
68
  moduleDefinition: ModuleDefinition;
69
  scope?: Type<unknown>[];
70
  ctxRegistry?: (ForwardReference | DynamicModule | Type<unknown>)[];
71
  overrides?: ModuleOverride[];
72
  lazy?: boolean;
73
}
74

75
export class DependenciesScanner {
1✔
76
  private readonly applicationProvidersApplyMap: ApplicationProviderWrapper[] =
44✔
77
    [];
78

79
  constructor(
80
    private readonly container: NestContainer,
44✔
81
    private readonly metadataScanner: MetadataScanner,
44✔
82
    private readonly graphInspector: GraphInspector,
44✔
83
    private readonly applicationConfig = new ApplicationConfig(),
44✔
84
  ) {}
85

86
  public async scan(
87
    module: Type<any>,
88
    options?: { overrides?: ModuleOverride[] },
89
  ) {
90
    await this.registerCoreModule(options?.overrides);
8✔
91
    await this.scanForModules({
8✔
92
      moduleDefinition: module,
93
      overrides: options?.overrides,
94
    });
95
    await this.scanModulesForDependencies();
8✔
96
    this.addScopedEnhancersMetadata();
8✔
97

98
    // Modules distance calculation should be done after all modules are scanned
99
    // but before global modules are registered (linked to all modules).
100
    // Global modules have their distance set to MAX anyway.
101
    this.calculateModulesDistance();
8✔
102

103
    this.container.bindGlobalScope();
8✔
104
  }
105

106
  public async scanForModules({
107
    moduleDefinition,
108
    lazy,
109
    scope = [],
11✔
110
    ctxRegistry = [],
13✔
111
    overrides = [],
11✔
112
  }: ModulesScanParameters): Promise<Module[]> {
113
    const { moduleRef: moduleInstance, inserted: moduleInserted } =
114
      (await this.insertOrOverrideModule(moduleDefinition, overrides, scope)) ??
25✔
115
      {};
116

117
    moduleDefinition =
25✔
118
      this.getOverrideModuleByModule(moduleDefinition, overrides)?.newModule ??
47✔
119
      moduleDefinition;
120

121
    moduleDefinition =
25✔
122
      moduleDefinition instanceof Promise
123
        ? await moduleDefinition
25!
124
        : moduleDefinition;
125

126
    ctxRegistry.push(moduleDefinition);
25✔
127

128
    if (this.isForwardReference(moduleDefinition)) {
25✔
129
      moduleDefinition = (moduleDefinition as ForwardReference).forwardRef();
1✔
130
    }
131
    const modules = !this.isDynamicModule(
25✔
132
      moduleDefinition as Type<any> | DynamicModule,
133
    )
134
      ? this.reflectMetadata(
25!
135
          MODULE_METADATA.IMPORTS,
136
          moduleDefinition as Type<any>,
137
        )
138
      : [
139
          ...this.reflectMetadata(
140
            MODULE_METADATA.IMPORTS,
141
            (moduleDefinition as DynamicModule).module,
142
          ),
143
          ...((moduleDefinition as DynamicModule).imports || []),
×
144
        ];
145

146
    let registeredModuleRefs: Module[] = [];
25✔
147
    for (const [index, innerModule] of modules.entries()) {
25✔
148
      // In case of a circular dependency (ES module system), JavaScript will resolve the type to `undefined`.
149
      if (innerModule === undefined) {
14✔
150
        throw new UndefinedModuleException(moduleDefinition, index, scope);
1✔
151
      }
152
      if (!innerModule) {
13✔
153
        throw new InvalidModuleException(moduleDefinition, index, scope);
1✔
154
      }
155
      if (ctxRegistry.includes(innerModule)) {
12!
156
        continue;
×
157
      }
158
      const moduleRefs = await this.scanForModules({
12✔
159
        moduleDefinition: innerModule,
160
        scope: ([] as Array<Type>).concat(scope, moduleDefinition as Type),
161
        ctxRegistry,
162
        overrides,
163
        lazy,
164
      });
165
      registeredModuleRefs = registeredModuleRefs.concat(moduleRefs);
12✔
166
    }
167
    if (!moduleInstance) {
23✔
168
      return registeredModuleRefs;
5✔
169
    }
170

171
    if (lazy && moduleInserted) {
18✔
172
      this.container.bindGlobalsToImports(moduleInstance);
4✔
173
    }
174
    return [moduleInstance].concat(registeredModuleRefs);
18✔
175
  }
176

177
  public async insertModule(
178
    moduleDefinition: any,
179
    scope: Type<unknown>[],
180
  ): Promise<
181
    | {
182
        moduleRef: Module;
183
        inserted: boolean;
184
      }
185
    | undefined
186
  > {
187
    const moduleToAdd = this.isForwardReference(moduleDefinition)
26✔
188
      ? moduleDefinition.forwardRef()
26✔
189
      : moduleDefinition;
190

191
    if (
26✔
192
      this.isInjectable(moduleToAdd) ||
75✔
193
      this.isController(moduleToAdd) ||
194
      this.isExceptionFilter(moduleToAdd)
195
    ) {
196
      throw new InvalidClassModuleException(moduleDefinition, scope);
3✔
197
    }
198

199
    return this.container.addModule(moduleToAdd, scope);
23✔
200
  }
201

202
  public async scanModulesForDependencies(
203
    modules: Map<string, Module> = this.container.getModules(),
8✔
204
  ) {
205
    for (const [token, { metatype }] of modules) {
11✔
206
      await this.reflectImports(metatype, token, metatype.name);
18✔
207
      this.reflectProviders(metatype, token);
18✔
208
      this.reflectControllers(metatype, token);
18✔
209
      this.reflectExports(metatype, token);
18✔
210
    }
211
  }
212

213
  public async reflectImports(
214
    module: Type<unknown>,
215
    token: string,
216
    context: string,
217
  ) {
218
    const modules = [
18✔
219
      ...this.reflectMetadata(MODULE_METADATA.IMPORTS, module),
220
      ...this.container.getDynamicMetadataByToken(
221
        token,
222
        MODULE_METADATA.IMPORTS as 'imports',
223
      )!,
224
    ];
225
    for (const related of modules) {
18✔
226
      await this.insertImport(related, token, context);
9✔
227
    }
228
  }
229

230
  public reflectProviders(module: Type<any>, token: string) {
231
    const providers = [
18✔
232
      ...this.reflectMetadata(MODULE_METADATA.PROVIDERS, module),
233
      ...this.container.getDynamicMetadataByToken(
234
        token,
235
        MODULE_METADATA.PROVIDERS as 'providers',
236
      )!,
237
    ];
238
    providers.forEach(provider => {
18✔
239
      this.insertProvider(provider, token);
9✔
240
      this.reflectDynamicMetadata(provider, token);
9✔
241
    });
242
  }
243

244
  public reflectControllers(module: Type<any>, token: string) {
245
    const controllers = [
18✔
246
      ...this.reflectMetadata(MODULE_METADATA.CONTROLLERS, module),
247
      ...this.container.getDynamicMetadataByToken(
248
        token,
249
        MODULE_METADATA.CONTROLLERS as 'controllers',
250
      )!,
251
    ];
252
    controllers.forEach(item => {
18✔
253
      this.insertController(item, token);
10✔
254
      this.reflectDynamicMetadata(item, token);
10✔
255
    });
256
  }
257

258
  public reflectDynamicMetadata(cls: Type<Injectable>, token: string) {
259
    if (!cls || !cls.prototype) {
21✔
260
      return;
2✔
261
    }
262
    this.reflectInjectables(cls, token, GUARDS_METADATA);
19✔
263
    this.reflectInjectables(cls, token, INTERCEPTORS_METADATA);
19✔
264
    this.reflectInjectables(cls, token, EXCEPTION_FILTERS_METADATA);
19✔
265
    this.reflectInjectables(cls, token, PIPES_METADATA);
19✔
266
    this.reflectParamInjectables(cls, token, ROUTE_ARGS_METADATA);
19✔
267
  }
268

269
  public reflectExports(module: Type<unknown>, token: string) {
270
    const exports = [
18✔
271
      ...this.reflectMetadata(MODULE_METADATA.EXPORTS, module),
272
      ...this.container.getDynamicMetadataByToken(
273
        token,
274
        MODULE_METADATA.EXPORTS as 'exports',
275
      )!,
276
    ];
277
    exports.forEach(exportedProvider =>
18✔
278
      this.insertExportedProviderOrModule(exportedProvider, token),
4✔
279
    );
280
  }
281

282
  public reflectInjectables(
283
    component: Type<Injectable>,
284
    token: string,
285
    metadataKey: string,
286
  ) {
287
    const controllerInjectables = this.reflectMetadata<Type<Injectable>>(
72✔
288
      metadataKey,
289
      component,
290
    );
291
    const methodInjectables = this.metadataScanner
72✔
292
      .getAllMethodNames(component.prototype)
293
      .reduce(
294
        (acc, method) => {
295
          const methodInjectable = this.reflectKeyMetadata(
×
296
            component,
297
            metadataKey,
298
            method,
299
          );
300

301
          if (methodInjectable) {
×
302
            acc.push(methodInjectable);
×
303
          }
304

305
          return acc;
×
306
        },
307
        [] as Array<{
308
          methodKey: string;
309
          metadata: Type<Injectable>[];
310
        }>,
311
      );
312

313
    controllerInjectables.forEach(injectable =>
72✔
314
      this.insertInjectable(
×
315
        injectable,
316
        token,
317
        component,
318
        ENHANCER_KEY_TO_SUBTYPE_MAP[metadataKey],
319
      ),
320
    );
321
    methodInjectables.forEach(methodInjectable => {
72✔
322
      methodInjectable.metadata.forEach(injectable =>
×
323
        this.insertInjectable(
×
324
          injectable,
325
          token,
326
          component,
327
          ENHANCER_KEY_TO_SUBTYPE_MAP[metadataKey],
328
          methodInjectable.methodKey,
329
        ),
330
      );
331
    });
332
  }
333

334
  public reflectParamInjectables(
335
    component: Type<Injectable>,
336
    token: string,
337
    metadataKey: string,
338
  ) {
339
    const paramsMethods = this.metadataScanner.getAllMethodNames(
18✔
340
      component.prototype,
341
    );
342

343
    paramsMethods.forEach(methodKey => {
18✔
344
      const metadata: Record<
345
        string,
346
        {
347
          index: number;
348
          data: unknown;
349
          pipes: Array<Type<PipeTransform> | PipeTransform>;
350
        }
351
      > = Reflect.getMetadata(metadataKey, component, methodKey);
×
352

353
      if (!metadata) {
×
354
        return;
×
355
      }
356

357
      const params = Object.values(metadata);
×
358
      params
×
359
        .map(item => item.pipes)
×
360
        .flat(1)
361
        .forEach(injectable =>
362
          this.insertInjectable(
×
363
            injectable,
364
            token,
365
            component,
366
            'pipe',
367
            methodKey,
368
          ),
369
        );
370
    });
371
  }
372

373
  public reflectKeyMetadata(
374
    component: Type<Injectable>,
375
    key: string,
376
    methodKey: string,
377
  ): { methodKey: string; metadata: any } | undefined {
378
    let prototype = component.prototype;
3✔
379
    do {
3✔
380
      const descriptor = Reflect.getOwnPropertyDescriptor(prototype, methodKey);
3✔
381
      if (!descriptor) {
3✔
382
        continue;
1✔
383
      }
384
      const metadata = Reflect.getMetadata(key, descriptor.value);
2✔
385
      if (!metadata) {
2!
386
        return;
×
387
      }
388
      return { methodKey, metadata };
2✔
389
    } while (
390
      (prototype = Reflect.getPrototypeOf(prototype)) &&
2!
391
      prototype !== Object.prototype &&
392
      prototype
393
    );
394
    return undefined;
1✔
395
  }
396

397
  public calculateModulesDistance() {
398
    const modulesGenerator = this.container.getModules().values();
8✔
399
    // Skip "InternalCoreModule"
400
    // The second element is the actual root module
401
    modulesGenerator.next();
8✔
402

403
    const rootModule = modulesGenerator.next().value!;
8✔
404
    if (!rootModule) {
8✔
405
      return;
2✔
406
    }
407

408
    // Convert modules to an acyclic connected graph
409
    const tree = new TopologyTree(rootModule);
6✔
410
    tree.walk((moduleRef, depth) => {
6✔
411
      if (moduleRef.isGlobal) {
6!
UNCOV
412
        return;
×
413
      }
414
      moduleRef.distance = depth;
6✔
415
    });
416
  }
417

418
  public async insertImport(related: any, token: string, context: string) {
419
    if (isUndefined(related)) {
11✔
420
      throw new CircularDependencyException(context);
1✔
421
    }
422
    if (this.isForwardReference(related)) {
10✔
423
      return this.container.addImport(related.forwardRef(), token);
2✔
424
    }
425
    await this.container.addImport(related, token);
8✔
426
  }
427

428
  public isCustomProvider(
429
    provider: Provider,
430
  ): provider is
431
    | ClassProvider
432
    | ValueProvider
433
    | FactoryProvider
434
    | ExistingProvider {
435
    return provider && !isNil((provider as any).provide);
15✔
436
  }
437

438
  public insertProvider(provider: Provider, token: string) {
439
    const isCustomProvider = this.isCustomProvider(provider);
15✔
440
    if (!isCustomProvider) {
15✔
441
      return this.container.addProvider(provider, token);
9✔
442
    }
443
    const applyProvidersMap = this.getApplyProvidersMap();
6✔
444
    const providersKeys = Object.keys(applyProvidersMap);
6✔
445
    const type = provider.provide;
6✔
446

447
    if (!providersKeys.includes(type as string)) {
6✔
448
      return this.container.addProvider(provider as any, token);
3✔
449
    }
450
    const uuid = UuidFactory.get(type.toString());
3✔
451
    const providerToken = `${type as string} (UUID: ${uuid})`;
3✔
452

453
    let scope = (provider as ClassProvider | FactoryProvider).scope;
3✔
454
    if (isNil(scope) && (provider as ClassProvider).useClass) {
3!
455
      scope = getClassScope((provider as ClassProvider).useClass);
×
456
    }
457
    this.applicationProvidersApplyMap.push({
3✔
458
      type,
459
      moduleKey: token,
460
      providerKey: providerToken,
461
      scope,
462
    });
463

464
    const newProvider = {
3✔
465
      ...provider,
466
      provide: providerToken,
467
      scope,
468
    } as Provider;
469

470
    const enhancerSubtype =
471
      ENHANCER_TOKEN_TO_SUBTYPE_MAP[
3✔
472
        type as
473
          | typeof APP_GUARD
474
          | typeof APP_PIPE
475
          | typeof APP_FILTER
476
          | typeof APP_INTERCEPTOR
477
      ];
478
    const factoryOrClassProvider = newProvider as
3✔
479
      | FactoryProvider
480
      | ClassProvider;
481
    if (this.isRequestOrTransient(factoryOrClassProvider.scope!)) {
3✔
482
      return this.container.addInjectable(newProvider, token, enhancerSubtype);
1✔
483
    }
484
    this.container.addProvider(newProvider, token, enhancerSubtype);
2✔
485
  }
486

487
  public insertInjectable(
488
    injectable: Type<Injectable> | object,
489
    token: string,
490
    host: Type<Injectable>,
491
    subtype: EnhancerSubtype,
492
    methodKey?: string,
493
  ) {
494
    if (isFunction(injectable)) {
4✔
495
      const instanceWrapper = this.container.addInjectable(
2✔
496
        injectable as Type,
497
        token,
498
        subtype,
499
        host,
500
      ) as InstanceWrapper;
501

502
      this.graphInspector.insertEnhancerMetadataCache({
2✔
503
        moduleToken: token,
504
        classRef: host,
505
        enhancerInstanceWrapper: instanceWrapper,
506
        targetNodeId: instanceWrapper.id,
507
        subtype,
508
        methodKey,
509
      });
510
      return instanceWrapper;
2✔
511
    } else {
512
      this.graphInspector.insertEnhancerMetadataCache({
2✔
513
        moduleToken: token,
514
        classRef: host,
515
        enhancerRef: injectable,
516
        methodKey,
517
        subtype,
518
      });
519
    }
520
  }
521

522
  public insertExportedProviderOrModule(
523
    toExport: ForwardReference | DynamicModule | Type<unknown>,
524
    token: string,
525
  ) {
526
    const fulfilledProvider = this.isForwardReference(toExport)
3✔
527
      ? toExport.forwardRef()
3!
528
      : toExport;
529
    this.container.addExportedProviderOrModule(fulfilledProvider, token);
3✔
530
  }
531

532
  public insertController(controller: Type<Controller>, token: string) {
533
    this.container.addController(controller, token);
10✔
534
  }
535

536
  private insertOrOverrideModule(
537
    moduleDefinition: ModuleDefinition,
538
    overrides: ModuleOverride[],
539
    scope: Type<unknown>[],
540
  ): Promise<
541
    | {
542
        moduleRef: Module;
543
        inserted: boolean;
544
      }
545
    | undefined
546
  > {
547
    const overrideModule = this.getOverrideModuleByModule(
25✔
548
      moduleDefinition,
549
      overrides,
550
    );
551
    if (overrideModule !== undefined) {
25✔
552
      return this.overrideModule(
3✔
553
        moduleDefinition,
554
        overrideModule.newModule,
555
        scope,
556
      );
557
    }
558

559
    return this.insertModule(moduleDefinition, scope);
22✔
560
  }
561

562
  private getOverrideModuleByModule(
563
    module: ModuleDefinition,
564
    overrides: ModuleOverride[],
565
  ): ModuleOverride | undefined {
566
    if (this.isForwardReference(module)) {
50✔
567
      return overrides.find(moduleToOverride => {
2✔
568
        return (
2✔
569
          moduleToOverride.moduleToReplace === module.forwardRef() ||
4✔
570
          (
571
            moduleToOverride.moduleToReplace as ForwardReference
572
          ).forwardRef?.() === module.forwardRef()
573
        );
574
      });
575
    }
576

577
    return overrides.find(
48✔
578
      moduleToOverride => moduleToOverride.moduleToReplace === module,
12✔
579
    );
580
  }
581

582
  private async overrideModule(
583
    moduleToOverride: ModuleDefinition,
584
    newModule: ModuleDefinition,
585
    scope: Type<unknown>[],
586
  ): Promise<
587
    | {
588
        moduleRef: Module;
589
        inserted: boolean;
590
      }
591
    | undefined
592
  > {
593
    return this.container.replaceModule(
3✔
594
      this.isForwardReference(moduleToOverride)
595
        ? moduleToOverride.forwardRef()
3✔
596
        : moduleToOverride,
597
      this.isForwardReference(newModule) ? newModule.forwardRef() : newModule,
3✔
598
      scope,
599
    );
600
  }
601

602
  public reflectMetadata<T = any>(
603
    metadataKey: string,
604
    metatype: Type<any>,
605
  ): T[] {
606
    return Reflect.getMetadata(metadataKey, metatype) || [];
169✔
607
  }
608

609
  public async registerCoreModule(overrides?: ModuleOverride[]) {
610
    const moduleDefinition = InternalCoreModuleFactory.create(
×
611
      this.container,
612
      this,
613
      this.container.getModuleCompiler(),
614
      this.container.getHttpAdapterHostRef(),
615
      this.graphInspector,
616
      overrides,
617
    );
618
    const [instance] = await this.scanForModules({
×
619
      moduleDefinition,
620
      overrides,
621
    });
622
    this.container.registerCoreModuleRef(instance);
×
623
  }
624

625
  /**
626
   * Add either request or transient globally scoped enhancers
627
   * to all controllers metadata storage
628
   */
629
  public addScopedEnhancersMetadata() {
630
    iterate(this.applicationProvidersApplyMap)
9✔
631
      .filter(wrapper => this.isRequestOrTransient(wrapper.scope!))
1✔
632
      .forEach(({ moduleKey, providerKey }) => {
633
        const modulesContainer = this.container.getModules();
1✔
634
        const { injectables } = modulesContainer.get(moduleKey)!;
1✔
635
        const instanceWrapper = injectables.get(providerKey);
1✔
636

637
        const iterableIterator = modulesContainer.values();
1✔
638
        iterate(iterableIterator)
1✔
639
          .map(moduleRef =>
640
            Array.from<InstanceWrapper>(moduleRef.controllers.values()).concat(
1✔
641
              moduleRef.entryProviders,
642
            ),
643
          )
644
          .flatten()
645
          .forEach(controllerOrEntryProvider =>
646
            controllerOrEntryProvider.addEnhancerMetadata(instanceWrapper!),
2✔
647
          );
648
      });
649
  }
650

651
  public applyApplicationProviders() {
652
    const applyProvidersMap = this.getApplyProvidersMap();
2✔
653
    const applyRequestProvidersMap = this.getApplyRequestProvidersMap();
2✔
654

655
    const getInstanceWrapper = (
2✔
656
      moduleKey: string,
657
      providerKey: string,
658
      collectionKey: 'providers' | 'injectables',
659
    ) => {
660
      const modules = this.container.getModules();
2✔
661
      const collection = modules.get(moduleKey)![collectionKey];
2✔
662
      return collection.get(providerKey);
2✔
663
    };
664

665
    // Add global enhancers to the application config
666
    this.applicationProvidersApplyMap.forEach(
2✔
667
      ({ moduleKey, providerKey, type, scope }) => {
668
        let instanceWrapper: InstanceWrapper;
669
        if (this.isRequestOrTransient(scope!)) {
2✔
670
          instanceWrapper = getInstanceWrapper(
1✔
671
            moduleKey,
672
            providerKey,
673
            'injectables',
674
          )!;
675

676
          this.graphInspector.insertAttachedEnhancer(instanceWrapper);
1✔
677
          return applyRequestProvidersMap[type as string](instanceWrapper);
1✔
678
        }
679
        instanceWrapper = getInstanceWrapper(
1✔
680
          moduleKey,
681
          providerKey,
682
          'providers',
683
        )!;
684
        this.graphInspector.insertAttachedEnhancer(instanceWrapper);
1✔
685
        applyProvidersMap[type as string](instanceWrapper.instance);
1✔
686
      },
687
    );
688
  }
689

690
  public getApplyProvidersMap(): { [type: string]: Function } {
691
    return {
11✔
692
      [APP_INTERCEPTOR]: (interceptor: NestInterceptor) =>
693
        this.applicationConfig.addGlobalInterceptor(interceptor),
1✔
694
      [APP_PIPE]: (pipe: PipeTransform) =>
695
        this.applicationConfig.addGlobalPipe(pipe),
1✔
696
      [APP_GUARD]: (guard: CanActivate) =>
697
        this.applicationConfig.addGlobalGuard(guard),
1✔
698
      [APP_FILTER]: (filter: ExceptionFilter) =>
699
        this.applicationConfig.addGlobalFilter(filter),
1✔
700
    };
701
  }
702

703
  public getApplyRequestProvidersMap(): { [type: string]: Function } {
704
    return {
5✔
705
      [APP_INTERCEPTOR]: (interceptor: InstanceWrapper<NestInterceptor>) =>
706
        this.applicationConfig.addGlobalRequestInterceptor(interceptor),
1✔
707
      [APP_PIPE]: (pipe: InstanceWrapper<PipeTransform>) =>
708
        this.applicationConfig.addGlobalRequestPipe(pipe),
1✔
709
      [APP_GUARD]: (guard: InstanceWrapper<CanActivate>) =>
710
        this.applicationConfig.addGlobalRequestGuard(guard),
1✔
711
      [APP_FILTER]: (filter: InstanceWrapper<ExceptionFilter>) =>
712
        this.applicationConfig.addGlobalRequestFilter(filter),
1✔
713
    };
714
  }
715

716
  public isDynamicModule(
717
    module: Type<any> | DynamicModule,
718
  ): module is DynamicModule {
719
    return module && !!(module as DynamicModule).module;
25✔
720
  }
721

722
  /**
723
   * @param metatype
724
   * @returns `true` if `metatype` is annotated with the `@Injectable()` decorator.
725
   */
726
  private isInjectable(metatype: Type<any>): boolean {
727
    return !!Reflect.getMetadata(INJECTABLE_WATERMARK, metatype);
26✔
728
  }
729

730
  /**
731
   * @param metatype
732
   * @returns `true` if `metatype` is annotated with the `@Controller()` decorator.
733
   */
734
  private isController(metatype: Type<any>): boolean {
735
    return !!Reflect.getMetadata(CONTROLLER_WATERMARK, metatype);
25✔
736
  }
737

738
  /**
739
   * @param metatype
740
   * @returns `true` if `metatype` is annotated with the `@Catch()` decorator.
741
   */
742
  private isExceptionFilter(metatype: Type<any>): boolean {
743
    return !!Reflect.getMetadata(CATCH_WATERMARK, metatype);
24✔
744
  }
745

746
  private isForwardReference(
747
    module: ModuleDefinition,
748
  ): module is ForwardReference {
749
    return module && !!(module as ForwardReference).forwardRef;
120✔
750
  }
751

752
  private isRequestOrTransient(scope: Scope): boolean {
753
    return scope === Scope.REQUEST || scope === Scope.TRANSIENT;
6✔
754
  }
755
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc