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

nestjs / nest / de00f050-29aa-4a07-94cd-4a5c3beeb9b5

05 Dec 2023 08:46AM UTC coverage: 92.992% (+0.7%) from 92.258%
de00f050-29aa-4a07-94cd-4a5c3beeb9b5

Pull #12880

circleci

이정현B
feat(core): add option to bind global
Pull Request #12880: fix(core): always bind global modules when scan for modules

2798 of 3460 branches covered (0.0%)

7 of 8 new or added lines in 1 file covered. (87.5%)

199 existing lines in 30 files now uncovered.

6555 of 7049 relevant lines covered (92.99%)

17.99 hits per line

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

92.35
/packages/core/scanner.ts
1
import { DynamicModule, ForwardReference, Provider } from '@nestjs/common';
2
import {
1✔
3
  CATCH_WATERMARK,
4
  CONTROLLER_WATERMARK,
5
  EnhancerSubtype,
6
  ENHANCER_KEY_TO_SUBTYPE_MAP,
7
  EXCEPTION_FILTERS_METADATA,
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 { GraphInspector } from './inspector/graph-inspector';
54
import { UuidFactory } from './inspector/uuid-factory';
1✔
55
import { MetadataScanner } from './metadata-scanner';
56

57
interface ApplicationProviderWrapper {
58
  moduleKey: string;
59
  providerKey: string;
60
  type: InjectionToken;
61
  scope?: Scope;
62
}
63

64
export class DependenciesScanner {
1✔
65
  private readonly applicationProvidersApplyMap: ApplicationProviderWrapper[] =
41✔
66
    [];
67

68
  constructor(
69
    private readonly container: NestContainer,
41✔
70
    private readonly metadataScanner: MetadataScanner,
41✔
71
    private readonly graphInspector: GraphInspector,
41✔
72
    private readonly applicationConfig = new ApplicationConfig(),
41✔
73
  ) {}
74

75
  public async scan(module: Type<any>) {
76
    await this.registerCoreModule();
7✔
77
    await this.scanForModules(module);
7✔
78
    await this.scanModulesForDependencies();
7✔
79
    this.calculateModulesDistance();
7✔
80

81
    this.addScopedEnhancersMetadata();
7✔
82
    this.container.bindGlobalScope();
7✔
83
  }
84

85
  public async scanForModules(
86
    moduleDef:
87
      | ForwardReference
88
      | Type<unknown>
89
      | DynamicModule
90
      | Promise<DynamicModule>,
91
    scope: Type<unknown>[] = [],
10✔
92
    ctxRegistry: (ForwardReference | DynamicModule | Type<unknown>)[] = [],
12✔
93
    bindGlobal = false,
12✔
94
  ): Promise<Module[]> {
95
    const moduleInstance = await this.insertModule(moduleDef, scope);
21✔
96

97
    if (bindGlobal) {
21✔
98
      this.container.bindGlobalsToImports(moduleInstance);
5✔
99
    }
100

101
    ctxRegistry.push(await moduleDef);
21✔
102

103
    if (this.isForwardReference(await moduleDef)) {
21!
NEW
104
      moduleDef = (moduleDef as ForwardReference).forwardRef();
×
105
    }
106

107
    const modules = !this.isDynamicModule(
21✔
108
      moduleDef as Type<any> | DynamicModule,
109
    )
110
      ? this.reflectMetadata(MODULE_METADATA.IMPORTS, moduleDef as Type<any>)
21✔
111
      : [
112
          ...this.reflectMetadata(
113
            MODULE_METADATA.IMPORTS,
114
            (moduleDef as DynamicModule).module,
115
          ),
116
          ...((moduleDef as DynamicModule).imports || []),
6✔
117
        ];
118

119
    let registeredModuleRefs = [];
21✔
120
    for (const [index, innerModule] of modules.entries()) {
21✔
121
      // In case of a circular dependency (ES module system), JavaScript will resolve the type to `undefined`.
122
      if (innerModule === undefined) {
7✔
123
        throw new UndefinedModuleException(moduleDef, index, scope);
1✔
124
      }
125
      if (!innerModule) {
6✔
126
        throw new InvalidModuleException(moduleDef, index, scope);
1✔
127
      }
128
      if (ctxRegistry.includes(innerModule)) {
5!
UNCOV
129
        continue;
×
130
      }
131
      const moduleRefs = await this.scanForModules(
5✔
132
        innerModule,
133
        [].concat(scope, moduleDef),
134
        ctxRegistry,
135
        bindGlobal,
136
      );
137
      registeredModuleRefs = registeredModuleRefs.concat(moduleRefs);
5✔
138
    }
139
    if (!moduleInstance) {
19✔
140
      return registeredModuleRefs;
2✔
141
    }
142
    return [moduleInstance].concat(registeredModuleRefs);
17✔
143
  }
144

145
  public async insertModule(
146
    moduleDefinition: any,
147
    scope: Type<unknown>[],
148
  ): Promise<Module | undefined> {
149
    const moduleToAdd = this.isForwardReference(moduleDefinition)
25✔
150
      ? moduleDefinition.forwardRef()
25✔
151
      : moduleDefinition;
152

153
    if (
25✔
154
      this.isInjectable(moduleToAdd) ||
70✔
155
      this.isController(moduleToAdd) ||
156
      this.isExceptionFilter(moduleToAdd)
157
    ) {
158
      throw new InvalidClassModuleException(moduleDefinition, scope);
3✔
159
    }
160

161
    return this.container.addModule(moduleToAdd, scope);
21✔
162
  }
163

164
  public async scanModulesForDependencies(
165
    modules: Map<string, Module> = this.container.getModules(),
7✔
166
  ) {
167
    for (const [token, { metatype }] of modules) {
11✔
168
      await this.reflectImports(metatype, token, metatype.name);
17✔
169
      this.reflectProviders(metatype, token);
17✔
170
      this.reflectControllers(metatype, token);
17✔
171
      this.reflectExports(metatype, token);
17✔
172
    }
173
  }
174

175
  public async reflectImports(
176
    module: Type<unknown>,
177
    token: string,
178
    context: string,
179
  ) {
180
    const modules = [
17✔
181
      ...this.reflectMetadata(MODULE_METADATA.IMPORTS, module),
182
      ...this.container.getDynamicMetadataByToken(
183
        token,
184
        MODULE_METADATA.IMPORTS as 'imports',
185
      ),
186
    ];
187
    for (const related of modules) {
17✔
188
      await this.insertImport(related, token, context);
4✔
189
    }
190
  }
191

192
  public reflectProviders(module: Type<any>, token: string) {
193
    const providers = [
17✔
194
      ...this.reflectMetadata(MODULE_METADATA.PROVIDERS, module),
195
      ...this.container.getDynamicMetadataByToken(
196
        token,
197
        MODULE_METADATA.PROVIDERS as 'providers',
198
      ),
199
    ];
200
    providers.forEach(provider => {
17✔
201
      this.insertProvider(provider, token);
41✔
202
      this.reflectDynamicMetadata(provider, token);
41✔
203
    });
204
  }
205

206
  public reflectControllers(module: Type<any>, token: string) {
207
    const controllers = [
17✔
208
      ...this.reflectMetadata(MODULE_METADATA.CONTROLLERS, module),
209
      ...this.container.getDynamicMetadataByToken(
210
        token,
211
        MODULE_METADATA.CONTROLLERS as 'controllers',
212
      ),
213
    ];
214
    controllers.forEach(item => {
17✔
215
      this.insertController(item, token);
6✔
216
      this.reflectDynamicMetadata(item, token);
6✔
217
    });
218
  }
219

220
  public reflectDynamicMetadata(cls: Type<Injectable>, token: string) {
221
    if (!cls || !cls.prototype) {
49✔
222
      return;
33✔
223
    }
224
    this.reflectInjectables(cls, token, GUARDS_METADATA);
16✔
225
    this.reflectInjectables(cls, token, INTERCEPTORS_METADATA);
16✔
226
    this.reflectInjectables(cls, token, EXCEPTION_FILTERS_METADATA);
16✔
227
    this.reflectInjectables(cls, token, PIPES_METADATA);
16✔
228
    this.reflectParamInjectables(cls, token, ROUTE_ARGS_METADATA);
16✔
229
  }
230

231
  public reflectExports(module: Type<unknown>, token: string) {
232
    const exports = [
17✔
233
      ...this.reflectMetadata(MODULE_METADATA.EXPORTS, module),
234
      ...this.container.getDynamicMetadataByToken(
235
        token,
236
        MODULE_METADATA.EXPORTS as 'exports',
237
      ),
238
    ];
239
    exports.forEach(exportedProvider =>
17✔
240
      this.insertExportedProvider(exportedProvider, token),
38✔
241
    );
242
  }
243

244
  public reflectInjectables(
245
    component: Type<Injectable>,
246
    token: string,
247
    metadataKey: string,
248
  ) {
249
    const controllerInjectables = this.reflectMetadata<Type<Injectable>>(
60✔
250
      metadataKey,
251
      component,
252
    );
253
    const methodInjectables = this.metadataScanner
60✔
254
      .getAllMethodNames(component.prototype)
255
      .reduce((acc, method) => {
256
        const methodInjectable = this.reflectKeyMetadata(
48✔
257
          component,
258
          metadataKey,
259
          method,
260
        );
261

262
        if (methodInjectable) {
48!
UNCOV
263
          acc.push(methodInjectable);
×
264
        }
265

266
        return acc;
48✔
267
      }, []);
268

269
    controllerInjectables.forEach(injectable =>
60✔
UNCOV
270
      this.insertInjectable(
×
271
        injectable,
272
        token,
273
        component,
274
        ENHANCER_KEY_TO_SUBTYPE_MAP[metadataKey],
275
      ),
276
    );
277
    methodInjectables.forEach(methodInjectable => {
60✔
UNCOV
278
      methodInjectable.metadata.forEach(injectable =>
×
UNCOV
279
        this.insertInjectable(
×
280
          injectable,
281
          token,
282
          component,
283
          ENHANCER_KEY_TO_SUBTYPE_MAP[metadataKey],
284
          methodInjectable.methodKey,
285
        ),
286
      );
287
    });
288
  }
289

290
  public reflectParamInjectables(
291
    component: Type<Injectable>,
292
    token: string,
293
    metadataKey: string,
294
  ) {
295
    const paramsMethods = this.metadataScanner.getAllMethodNames(
15✔
296
      component.prototype,
297
    );
298

299
    paramsMethods.forEach(methodKey => {
15✔
300
      const metadata: Record<
301
        string,
302
        {
303
          index: number;
304
          data: unknown;
305
          pipes: Array<Type<PipeTransform> | PipeTransform>;
306
        }
307
      > = Reflect.getMetadata(metadataKey, component, methodKey);
12✔
308

309
      if (!metadata) {
12!
310
        return;
12✔
311
      }
312

313
      const params = Object.values(metadata);
×
UNCOV
314
      params
×
UNCOV
315
        .map(item => item.pipes)
×
316
        .flat(1)
317
        .forEach(injectable =>
UNCOV
318
          this.insertInjectable(
×
319
            injectable,
320
            token,
321
            component,
322
            'pipe',
323
            methodKey,
324
          ),
325
        );
326
    });
327
  }
328

329
  public reflectKeyMetadata(
330
    component: Type<Injectable>,
331
    key: string,
332
    methodKey: string,
333
  ): { methodKey: string; metadata: any } | undefined {
334
    let prototype = component.prototype;
51✔
335
    do {
51✔
336
      const descriptor = Reflect.getOwnPropertyDescriptor(prototype, methodKey);
51✔
337
      if (!descriptor) {
51✔
338
        continue;
1✔
339
      }
340
      const metadata = Reflect.getMetadata(key, descriptor.value);
50✔
341
      if (!metadata) {
50✔
342
        return;
48✔
343
      }
344
      return { methodKey, metadata };
2✔
345
    } while (
346
      (prototype = Reflect.getPrototypeOf(prototype)) &&
2!
347
      prototype !== Object.prototype &&
348
      prototype
349
    );
350
    return undefined;
1✔
351
  }
352

353
  public calculateModulesDistance() {
354
    const modulesGenerator = this.container.getModules().values();
7✔
355

356
    // Skip "InternalCoreModule" from calculating distance
357
    modulesGenerator.next();
7✔
358

359
    const modulesStack = [];
7✔
360
    const calculateDistance = (moduleRef: Module, distance = 1) => {
7✔
361
      if (!moduleRef || modulesStack.includes(moduleRef)) {
7✔
362
        return;
1✔
363
      }
364
      modulesStack.push(moduleRef);
6✔
365

366
      const moduleImports = moduleRef.imports;
6✔
367
      moduleImports.forEach(importedModuleRef => {
6✔
UNCOV
368
        if (importedModuleRef) {
×
UNCOV
369
          if (distance > importedModuleRef.distance) {
×
UNCOV
370
            importedModuleRef.distance = distance;
×
371
          }
UNCOV
372
          calculateDistance(importedModuleRef, distance + 1);
×
373
        }
374
      });
375
    };
376

377
    const rootModule = modulesGenerator.next().value as Module;
7✔
378
    calculateDistance(rootModule);
7✔
379
  }
380

381
  public async insertImport(related: any, token: string, context: string) {
382
    if (isUndefined(related)) {
6✔
383
      throw new CircularDependencyException(context);
1✔
384
    }
385
    if (this.isForwardReference(related)) {
5✔
386
      return this.container.addImport(related.forwardRef(), token);
1✔
387
    }
388
    await this.container.addImport(related, token);
4✔
389
  }
390

391
  public isCustomProvider(
392
    provider: Provider,
393
  ): provider is
394
    | ClassProvider
395
    | ValueProvider
396
    | FactoryProvider
397
    | ExistingProvider {
398
    return provider && !isNil((provider as any).provide);
47✔
399
  }
400

401
  public insertProvider(provider: Provider, token: string) {
402
    const isCustomProvider = this.isCustomProvider(provider);
47✔
403
    if (!isCustomProvider) {
47✔
404
      return this.container.addProvider(provider as Type<any>, token);
10✔
405
    }
406
    const applyProvidersMap = this.getApplyProvidersMap();
37✔
407
    const providersKeys = Object.keys(applyProvidersMap);
37✔
408
    const type = (
409
      provider as
37✔
410
        | ClassProvider
411
        | ValueProvider
412
        | FactoryProvider
413
        | ExistingProvider
414
    ).provide;
415

416
    if (!providersKeys.includes(type as string)) {
37✔
417
      return this.container.addProvider(provider as any, token);
34✔
418
    }
419
    const uuid = UuidFactory.get(type.toString());
3✔
420
    const providerToken = `${type as string} (UUID: ${uuid})`;
3✔
421

422
    let scope = (provider as ClassProvider | FactoryProvider).scope;
3✔
423
    if (isNil(scope) && (provider as ClassProvider).useClass) {
3!
UNCOV
424
      scope = getClassScope((provider as ClassProvider).useClass);
×
425
    }
426
    this.applicationProvidersApplyMap.push({
3✔
427
      type,
428
      moduleKey: token,
429
      providerKey: providerToken,
430
      scope,
431
    });
432

433
    const newProvider = {
3✔
434
      ...provider,
435
      provide: providerToken,
436
      scope,
437
    } as Provider;
438

439
    const enhancerSubtype =
440
      ENHANCER_TOKEN_TO_SUBTYPE_MAP[
3✔
441
        type as
442
          | typeof APP_GUARD
443
          | typeof APP_PIPE
444
          | typeof APP_FILTER
445
          | typeof APP_INTERCEPTOR
446
      ];
447
    const factoryOrClassProvider = newProvider as
3✔
448
      | FactoryProvider
449
      | ClassProvider;
450
    if (this.isRequestOrTransient(factoryOrClassProvider.scope)) {
3✔
451
      return this.container.addInjectable(newProvider, token, enhancerSubtype);
1✔
452
    }
453
    this.container.addProvider(newProvider, token, enhancerSubtype);
2✔
454
  }
455

456
  public insertInjectable(
457
    injectable: Type<Injectable> | object,
458
    token: string,
459
    host: Type<Injectable>,
460
    subtype: EnhancerSubtype,
461
    methodKey?: string,
462
  ) {
463
    if (isFunction(injectable)) {
4✔
464
      const instanceWrapper = this.container.addInjectable(
2✔
465
        injectable as Type,
466
        token,
467
        subtype,
468
        host,
469
      ) as InstanceWrapper;
470

471
      this.graphInspector.insertEnhancerMetadataCache({
2✔
472
        moduleToken: token,
473
        classRef: host,
474
        enhancerInstanceWrapper: instanceWrapper,
475
        targetNodeId: instanceWrapper.id,
476
        subtype,
477
        methodKey,
478
      });
479
      return instanceWrapper;
2✔
480
    } else {
481
      this.graphInspector.insertEnhancerMetadataCache({
2✔
482
        moduleToken: token,
483
        classRef: host,
484
        enhancerRef: injectable,
485
        methodKey,
486
        subtype,
487
      });
488
    }
489
  }
490

491
  public insertExportedProvider(
492
    exportedProvider: Type<Injectable>,
493
    token: string,
494
  ) {
495
    this.container.addExportedProvider(exportedProvider, token);
37✔
496
  }
497

498
  public insertController(controller: Type<Controller>, token: string) {
499
    this.container.addController(controller, token);
6✔
500
  }
501

502
  public reflectMetadata<T = any>(
503
    metadataKey: string,
504
    metatype: Type<any>,
505
  ): T[] {
506
    return Reflect.getMetadata(metadataKey, metatype) || [];
149✔
507
  }
508

509
  public async registerCoreModule() {
510
    const moduleDefinition = InternalCoreModuleFactory.create(
3✔
511
      this.container,
512
      this,
513
      this.container.getModuleCompiler(),
514
      this.container.getHttpAdapterHostRef(),
515
      this.graphInspector,
516
    );
517
    const [instance] = await this.scanForModules(moduleDefinition);
3✔
518
    this.container.registerCoreModuleRef(instance);
3✔
519
  }
520

521
  /**
522
   * Add either request or transient globally scoped enhancers
523
   * to all controllers metadata storage
524
   */
525
  public addScopedEnhancersMetadata() {
526
    iterate(this.applicationProvidersApplyMap)
8✔
527
      .filter(wrapper => this.isRequestOrTransient(wrapper.scope))
1✔
528
      .forEach(({ moduleKey, providerKey }) => {
529
        const modulesContainer = this.container.getModules();
1✔
530
        const { injectables } = modulesContainer.get(moduleKey);
1✔
531
        const instanceWrapper = injectables.get(providerKey);
1✔
532

533
        const iterableIterator = modulesContainer.values();
1✔
534
        iterate(iterableIterator)
1✔
535
          .map(moduleRef =>
536
            Array.from<InstanceWrapper>(moduleRef.controllers.values()).concat(
1✔
537
              moduleRef.entryProviders,
538
            ),
539
          )
540
          .flatten()
541
          .forEach(controllerOrEntryProvider =>
542
            controllerOrEntryProvider.addEnhancerMetadata(instanceWrapper),
2✔
543
          );
544
      });
545
  }
546

547
  public applyApplicationProviders() {
548
    const applyProvidersMap = this.getApplyProvidersMap();
2✔
549
    const applyRequestProvidersMap = this.getApplyRequestProvidersMap();
2✔
550

551
    const getInstanceWrapper = (
2✔
552
      moduleKey: string,
553
      providerKey: string,
554
      collectionKey: 'providers' | 'injectables',
555
    ) => {
556
      const modules = this.container.getModules();
2✔
557
      const collection = modules.get(moduleKey)[collectionKey];
2✔
558
      return collection.get(providerKey);
2✔
559
    };
560

561
    // Add global enhancers to the application config
562
    this.applicationProvidersApplyMap.forEach(
2✔
563
      ({ moduleKey, providerKey, type, scope }) => {
564
        let instanceWrapper: InstanceWrapper;
565
        if (this.isRequestOrTransient(scope)) {
2✔
566
          instanceWrapper = getInstanceWrapper(
1✔
567
            moduleKey,
568
            providerKey,
569
            'injectables',
570
          );
571

572
          this.graphInspector.insertAttachedEnhancer(instanceWrapper);
1✔
573
          return applyRequestProvidersMap[type as string](instanceWrapper);
1✔
574
        }
575
        instanceWrapper = getInstanceWrapper(
1✔
576
          moduleKey,
577
          providerKey,
578
          'providers',
579
        );
580
        this.graphInspector.insertAttachedEnhancer(instanceWrapper);
1✔
581
        applyProvidersMap[type as string](instanceWrapper.instance);
1✔
582
      },
583
    );
584
  }
585

586
  public getApplyProvidersMap(): { [type: string]: Function } {
587
    return {
42✔
588
      [APP_INTERCEPTOR]: (interceptor: NestInterceptor) =>
589
        this.applicationConfig.addGlobalInterceptor(interceptor),
1✔
590
      [APP_PIPE]: (pipe: PipeTransform) =>
591
        this.applicationConfig.addGlobalPipe(pipe),
1✔
592
      [APP_GUARD]: (guard: CanActivate) =>
593
        this.applicationConfig.addGlobalGuard(guard),
1✔
594
      [APP_FILTER]: (filter: ExceptionFilter) =>
595
        this.applicationConfig.addGlobalFilter(filter),
1✔
596
    };
597
  }
598

599
  public getApplyRequestProvidersMap(): { [type: string]: Function } {
600
    return {
5✔
601
      [APP_INTERCEPTOR]: (interceptor: InstanceWrapper<NestInterceptor>) =>
602
        this.applicationConfig.addGlobalRequestInterceptor(interceptor),
1✔
603
      [APP_PIPE]: (pipe: InstanceWrapper<PipeTransform>) =>
604
        this.applicationConfig.addGlobalRequestPipe(pipe),
1✔
605
      [APP_GUARD]: (guard: InstanceWrapper<CanActivate>) =>
606
        this.applicationConfig.addGlobalRequestGuard(guard),
1✔
607
      [APP_FILTER]: (filter: InstanceWrapper<ExceptionFilter>) =>
608
        this.applicationConfig.addGlobalRequestFilter(filter),
1✔
609
    };
610
  }
611

612
  public isDynamicModule(
613
    module: Type<any> | DynamicModule,
614
  ): module is DynamicModule {
615
    return module && !!(module as DynamicModule).module;
21✔
616
  }
617

618
  /**
619
   * @param metatype
620
   * @returns `true` if `metatype` is annotated with the `@Injectable()` decorator.
621
   */
622
  private isInjectable(metatype: Type<any>): boolean {
623
    return !!Reflect.getMetadata(INJECTABLE_WATERMARK, metatype);
25✔
624
  }
625

626
  /**
627
   * @param metatype
628
   * @returns `true` if `metatype` is annotated with the `@Controller()` decorator.
629
   */
630
  private isController(metatype: Type<any>): boolean {
631
    return !!Reflect.getMetadata(CONTROLLER_WATERMARK, metatype);
23✔
632
  }
633

634
  /**
635
   * @param metatype
636
   * @returns `true` if `metatype` is annotated with the `@Catch()` decorator.
637
   */
638
  private isExceptionFilter(metatype: Type<any>): boolean {
639
    return !!Reflect.getMetadata(CATCH_WATERMARK, metatype);
22✔
640
  }
641

642
  private isForwardReference(
643
    module: Type<any> | DynamicModule | ForwardReference,
644
  ): module is ForwardReference {
645
    return module && !!(module as ForwardReference).forwardRef;
51✔
646
  }
647

648
  private isRequestOrTransient(scope: Scope): boolean {
649
    return scope === Scope.REQUEST || scope === Scope.TRANSIENT;
6✔
650
  }
651
}
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

© 2025 Coveralls, Inc