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

nestjs / nest / dc5be4d1-3bf5-4993-af5a-2ff5a301e315

27 Oct 2025 08:31AM UTC coverage: 88.888% (-0.04%) from 88.927%
dc5be4d1-3bf5-4993-af5a-2ff5a301e315

Pull #15820

circleci

web-flow
chore(deps): update mysql docker tag to v9.5.0
Pull Request #15820: chore(deps): update mysql docker tag to v9.5.0

2758 of 3490 branches covered (79.03%)

7319 of 8234 relevant lines covered (88.89%)

16.72 hits per line

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

79.66
/packages/core/injector/injector.ts
1
import {
1✔
2
  InjectionToken,
3
  Logger,
4
  LoggerService,
5
  OptionalFactoryDependency,
6
} from '@nestjs/common';
7
import {
1✔
8
  OPTIONAL_DEPS_METADATA,
9
  OPTIONAL_PROPERTY_DEPS_METADATA,
10
  PARAMTYPES_METADATA,
11
  PROPERTY_DEPS_METADATA,
12
  SELF_DECLARED_DEPS_METADATA,
13
} from '@nestjs/common/constants';
14
import {
15
  Controller,
16
  ForwardReference,
17
  Injectable,
18
  Type,
19
} from '@nestjs/common/interfaces';
20
import { clc } from '@nestjs/common/utils/cli-colors.util';
1✔
21
import {
1✔
22
  isFunction,
23
  isNil,
24
  isObject,
25
  isString,
26
  isSymbol,
27
  isUndefined,
28
} from '@nestjs/common/utils/shared.utils';
29
import { iterate } from 'iterare';
1✔
30
import { performance } from 'perf_hooks';
1✔
31
import { CircularDependencyException } from '../errors/exceptions';
1✔
32
import { RuntimeException } from '../errors/exceptions/runtime.exception';
1✔
33
import { UndefinedDependencyException } from '../errors/exceptions/undefined-dependency.exception';
1✔
34
import { UnknownDependenciesException } from '../errors/exceptions/unknown-dependencies.exception';
1✔
35
import { Barrier } from '../helpers/barrier';
1✔
36
import { STATIC_CONTEXT } from './constants';
1✔
37
import { INQUIRER } from './inquirer';
1✔
38
import {
1✔
39
  ContextId,
40
  InstancePerContext,
41
  InstanceWrapper,
42
  PropertyMetadata,
43
} from './instance-wrapper';
44
import { Module } from './module';
45
import { SettlementSignal } from './settlement-signal';
1✔
46

47
/**
48
 * The type of an injectable dependency
49
 */
50
export type InjectorDependency = InjectionToken;
51

52
/**
53
 * The property-based dependency
54
 */
55
export interface PropertyDependency {
56
  key: symbol | string;
57
  name: InjectorDependency;
58
  isOptional?: boolean;
59
  instance?: any;
60
}
61

62
/**
63
 * Context of a dependency which gets injected by
64
 * the injector
65
 */
66
export interface InjectorDependencyContext {
67
  /**
68
   * The name of the property key (property-based injection)
69
   */
70
  key?: string | symbol;
71
  /**
72
   * The function itself, the name of the function, or injection token.
73
   */
74
  name?: Function | string | symbol;
75
  /**
76
   * The index of the dependency which gets injected
77
   * from the dependencies array
78
   */
79
  index?: number;
80
  /**
81
   * The dependency array which gets injected
82
   */
83
  dependencies?: InjectorDependency[];
84
}
85

86
export class Injector {
1✔
87
  private logger: LoggerService = new Logger('InjectorLogger');
304✔
88
  private readonly instanceDecorator: (target: unknown) => unknown = (
304✔
89
    target: unknown,
90
  ) => target;
61✔
91

92
  constructor(
93
    private readonly options?: {
304✔
94
      /**
95
       * Whether to enable preview mode.
96
       */
97
      preview: boolean;
98
      /**
99
       * Function to decorate a freshly created instance.
100
       */
101
      instanceDecorator?: (target: unknown) => unknown;
102
    },
103
  ) {
104
    if (options?.instanceDecorator) {
304!
105
      this.instanceDecorator = options.instanceDecorator;
×
106
    }
107
  }
108

109
  public loadPrototype<T>(
110
    { token }: InstanceWrapper<T>,
111
    collection: Map<InjectionToken, InstanceWrapper<T>>,
112
    contextId = STATIC_CONTEXT,
124✔
113
  ) {
114
    if (!collection) {
124✔
115
      return;
1✔
116
    }
117
    const target = collection.get(token)!;
123✔
118
    const instance = target.createPrototype(contextId);
123✔
119
    if (instance) {
123✔
120
      const wrapper = new InstanceWrapper({
71✔
121
        ...target,
122
        instance,
123
      });
124
      collection.set(token, wrapper);
71✔
125
    }
126
  }
127

128
  public async loadInstance<T>(
129
    wrapper: InstanceWrapper<T>,
130
    collection: Map<InjectionToken, InstanceWrapper>,
131
    moduleRef: Module,
132
    contextId = STATIC_CONTEXT,
6✔
133
    inquirer?: InstanceWrapper,
134
  ) {
135
    const inquirerId = this.getInquirerId(inquirer);
143✔
136
    const instanceHost = wrapper.getInstanceByContextId(
143✔
137
      this.getContextId(contextId, wrapper),
138
      inquirerId,
139
    );
140

141
    if (instanceHost.isPending) {
142✔
142
      const settlementSignal = wrapper.settlementSignal;
11✔
143
      if (inquirer && settlementSignal?.isCycle(inquirer.id)) {
11!
144
        throw new CircularDependencyException(`"${wrapper.name}"`);
×
145
      }
146

147
      return instanceHost.donePromise!.then((err?: unknown) => {
11✔
148
        if (err) {
11✔
149
          throw err;
1✔
150
        }
151
      });
152
    }
153

154
    const settlementSignal = this.applySettlementSignal(instanceHost, wrapper);
131✔
155
    const token = wrapper.token || wrapper.name;
131✔
156

157
    const { inject } = wrapper;
131✔
158
    const targetWrapper = collection.get(token);
131✔
159
    if (isUndefined(targetWrapper)) {
131!
160
      throw new RuntimeException();
×
161
    }
162
    if (instanceHost.isResolved) {
131✔
163
      return settlementSignal.complete();
48✔
164
    }
165
    try {
83✔
166
      const t0 = this.getNowTimestamp();
83✔
167
      const callback = async (instances: unknown[]) => {
83✔
168
        const properties = await this.resolveProperties(
83✔
169
          wrapper,
170
          moduleRef,
171
          inject as InjectionToken[],
172
          contextId,
173
          wrapper,
174
          inquirer,
175
        );
176
        const instance = await this.instantiateClass(
83✔
177
          instances,
178
          wrapper,
179
          targetWrapper,
180
          contextId,
181
          inquirer,
182
        );
183
        this.applyProperties(instance, properties);
83✔
184
        wrapper.initTime = this.getNowTimestamp() - t0;
83✔
185
        settlementSignal.complete();
83✔
186
      };
187
      await this.resolveConstructorParams<T>(
83✔
188
        wrapper,
189
        moduleRef,
190
        inject as InjectionToken[],
191
        callback,
192
        contextId,
193
        wrapper,
194
        inquirer,
195
      );
196
    } catch (err) {
197
      wrapper.removeInstanceByContextId(
×
198
        this.getContextId(contextId, wrapper),
199
        inquirerId,
200
      );
201

202
      settlementSignal.error(err);
×
203
      throw err;
×
204
    }
205
  }
206

207
  public async loadMiddleware(
208
    wrapper: InstanceWrapper,
209
    collection: Map<InjectionToken, InstanceWrapper>,
210
    moduleRef: Module,
211
    contextId = STATIC_CONTEXT,
2✔
212
    inquirer?: InstanceWrapper,
213
  ) {
214
    const { metatype, token } = wrapper;
2✔
215
    const targetWrapper = collection.get(token)!;
2✔
216
    if (!isUndefined(targetWrapper.instance)) {
2✔
217
      return;
1✔
218
    }
219
    targetWrapper.instance = Object.create(metatype!.prototype);
1✔
220
    await this.loadInstance(
1✔
221
      wrapper,
222
      collection,
223
      moduleRef,
224
      contextId,
225
      inquirer || wrapper,
2✔
226
    );
227
  }
228

229
  public async loadController(
230
    wrapper: InstanceWrapper<Controller>,
231
    moduleRef: Module,
232
    contextId = STATIC_CONTEXT,
1✔
233
  ) {
234
    const controllers = moduleRef.controllers;
1✔
235
    await this.loadInstance<Controller>(
1✔
236
      wrapper,
237
      controllers,
238
      moduleRef,
239
      contextId,
240
      wrapper,
241
    );
242
    await this.loadEnhancersPerContext(wrapper, contextId, wrapper);
1✔
243
  }
244

245
  public async loadInjectable<T = any>(
246
    wrapper: InstanceWrapper<T>,
247
    moduleRef: Module,
248
    contextId = STATIC_CONTEXT,
21✔
249
    inquirer?: InstanceWrapper,
250
  ) {
251
    const injectables = moduleRef.injectables;
21✔
252
    await this.loadInstance<T>(
21✔
253
      wrapper,
254
      injectables,
255
      moduleRef,
256
      contextId,
257
      inquirer,
258
    );
259
  }
260

261
  public async loadProvider(
262
    wrapper: InstanceWrapper<Injectable>,
263
    moduleRef: Module,
264
    contextId = STATIC_CONTEXT,
94✔
265
    inquirer?: InstanceWrapper,
266
  ) {
267
    const providers = moduleRef.providers;
98✔
268
    await this.loadInstance<Injectable>(
98✔
269
      wrapper,
270
      providers,
271
      moduleRef,
272
      contextId,
273
      inquirer,
274
    );
275
    await this.loadEnhancersPerContext(wrapper, contextId, wrapper);
98✔
276
  }
277

278
  public applySettlementSignal<T>(
279
    instancePerContext: InstancePerContext<T>,
280
    host: InstanceWrapper<T>,
281
  ) {
282
    const settlementSignal = new SettlementSignal();
131✔
283
    instancePerContext.donePromise = settlementSignal.asPromise();
131✔
284
    instancePerContext.isPending = true;
131✔
285
    host.settlementSignal = settlementSignal;
131✔
286

287
    return settlementSignal;
131✔
288
  }
289

290
  public async resolveConstructorParams<T>(
291
    wrapper: InstanceWrapper<T>,
292
    moduleRef: Module,
293
    inject: InjectorDependency[] | undefined,
294
    callback: (args: unknown[]) => void | Promise<void>,
295
    contextId = STATIC_CONTEXT,
×
296
    inquirer?: InstanceWrapper,
297
    parentInquirer?: InstanceWrapper,
298
  ) {
299
    const inquirerId = this.getInquirerId(inquirer);
84✔
300
    const metadata = wrapper.getCtorMetadata();
84✔
301

302
    if (metadata && contextId !== STATIC_CONTEXT) {
84✔
303
      const deps = await this.loadCtorMetadata(
1✔
304
        metadata,
305
        contextId,
306
        inquirer,
307
        parentInquirer,
308
      );
309
      return callback(deps);
1✔
310
    }
311

312
    const isFactoryProvider = !isNil(inject);
83✔
313
    const [dependencies, optionalDependenciesIds] = isFactoryProvider
83✔
314
      ? this.getFactoryProviderDependencies(wrapper)
83!
315
      : this.getClassDependencies(wrapper);
316

317
    const paramBarrier = new Barrier(dependencies.length);
83✔
318
    let isResolved = true;
83✔
319
    const resolveParam = async (param: unknown, index: number) => {
83✔
320
      try {
4✔
321
        if (this.isInquirer(param, parentInquirer)) {
4!
322
          /*
323
           * Signal the barrier to make sure other dependencies do not get stuck waiting forever.
324
           */
325
          paramBarrier.signal();
×
326

327
          return parentInquirer && parentInquirer.instance;
×
328
        }
329
        if (inquirer?.isTransient && parentInquirer) {
4!
330
          // When `inquirer` is transient too, inherit the parent inquirer
331
          // This is required to ensure that transient providers are only resolved
332
          // when requested
333
          inquirer.attachRootInquirer(parentInquirer);
×
334
        }
335
        const paramWrapper = await this.resolveSingleParam<T>(
4✔
336
          wrapper,
337
          param as Type | string | symbol,
338
          { index, dependencies },
339
          moduleRef,
340
          contextId,
341
          inquirer,
342
          index,
343
        );
344

345
        /*
346
         * Ensure that all instance wrappers are resolved at this point before we continue.
347
         * Otherwise the staticity of `wrapper`'s dependency tree may be evaluated incorrectly
348
         * and result in undefined / null injection.
349
         */
350
        await paramBarrier.signalAndWait();
4✔
351

352
        const paramWrapperWithInstance = await this.resolveComponentHost(
4✔
353
          moduleRef,
354
          paramWrapper,
355
          contextId,
356
          inquirer,
357
        );
358
        const instanceHost = paramWrapperWithInstance.getInstanceByContextId(
4✔
359
          this.getContextId(contextId, paramWrapperWithInstance),
360
          inquirerId,
361
        );
362
        if (!instanceHost.isResolved && !paramWrapperWithInstance.forwardRef) {
4!
363
          isResolved = false;
×
364
        }
365
        return instanceHost?.instance;
4✔
366
      } catch (err) {
367
        /*
368
         * Signal the barrier to make sure other dependencies do not get stuck waiting forever. We
369
         * do not care if this occurs after `Barrier.signalAndWait()` is called in the `try` block
370
         * because the barrier will always have been resolved by then.
371
         */
372
        paramBarrier.signal();
×
373

374
        const isOptional = optionalDependenciesIds.includes(index);
×
375
        if (!isOptional) {
×
376
          throw err;
×
377
        }
378
        return undefined;
×
379
      }
380
    };
381
    const instances = await Promise.all(dependencies.map(resolveParam));
83✔
382
    isResolved && (await callback(instances));
83✔
383
  }
384

385
  public getClassDependencies<T>(
386
    wrapper: InstanceWrapper<T>,
387
  ): [InjectorDependency[], number[]] {
388
    const ctorRef = wrapper.metatype as Type<any>;
85✔
389
    return [
85✔
390
      this.reflectConstructorParams(ctorRef),
391
      this.reflectOptionalParams(ctorRef),
392
    ];
393
  }
394

395
  public getFactoryProviderDependencies<T>(
396
    wrapper: InstanceWrapper<T>,
397
  ): [InjectorDependency[], number[]] {
398
    const optionalDependenciesIds: number[] = [];
1✔
399

400
    /**
401
     * Same as the internal utility function `isOptionalFactoryDependency` from `@nestjs/common`.
402
     * We are duplicating it here because that one is not supposed to be exported.
403
     */
404
    function isOptionalFactoryDependency(
405
      value: InjectionToken | OptionalFactoryDependency,
406
    ): value is OptionalFactoryDependency {
407
      return (
3✔
408
        !isUndefined((value as OptionalFactoryDependency).token) &&
7✔
409
        !isUndefined((value as OptionalFactoryDependency).optional) &&
410
        !(value as any).prototype
411
      );
412
    }
413

414
    const mapFactoryProviderInjectArray = (
1✔
415
      item: InjectionToken | OptionalFactoryDependency,
416
      index: number,
417
    ): InjectionToken => {
418
      if (typeof item !== 'object') {
4✔
419
        return item;
1✔
420
      }
421
      if (isOptionalFactoryDependency(item)) {
3✔
422
        if (item.optional) {
2✔
423
          optionalDependenciesIds.push(index);
1✔
424
        }
425
        return item?.token;
2✔
426
      }
427
      return item;
1✔
428
    };
429
    return [
1✔
430
      wrapper.inject?.map?.(mapFactoryProviderInjectArray) as any[],
431
      optionalDependenciesIds,
432
    ];
433
  }
434

435
  public reflectConstructorParams<T>(type: Type<T>): any[] {
436
    const paramtypes = [
85✔
437
      ...(Reflect.getMetadata(PARAMTYPES_METADATA, type) || []),
166✔
438
    ];
439
    const selfParams = this.reflectSelfParams<T>(type);
85✔
440

441
    selfParams.forEach(({ index, param }) => (paramtypes[index] = param));
85✔
442
    return paramtypes;
85✔
443
  }
444

445
  public reflectOptionalParams<T>(type: Type<T>): any[] {
446
    return Reflect.getMetadata(OPTIONAL_DEPS_METADATA, type) || [];
85✔
447
  }
448

449
  public reflectSelfParams<T>(type: Type<T>): any[] {
450
    return Reflect.getMetadata(SELF_DECLARED_DEPS_METADATA, type) || [];
85✔
451
  }
452

453
  public async resolveSingleParam<T>(
454
    wrapper: InstanceWrapper<T>,
455
    param: Type<any> | string | symbol,
456
    dependencyContext: InjectorDependencyContext,
457
    moduleRef: Module,
458
    contextId = STATIC_CONTEXT,
1✔
459
    inquirer?: InstanceWrapper,
460
    keyOrIndex?: symbol | string | number,
461
  ) {
462
    if (isUndefined(param)) {
7✔
463
      this.logger.log(
1✔
464
        'Nest encountered an undefined dependency. This may be due to a circular import or a missing dependency declaration.',
465
      );
466
      throw new UndefinedDependencyException(
1✔
467
        wrapper.name,
468
        dependencyContext,
469
        moduleRef,
470
      );
471
    }
472
    const token = this.resolveParamToken(wrapper, param);
6✔
473
    return this.resolveComponentWrapper(
6✔
474
      moduleRef,
475
      token,
476
      dependencyContext,
477
      wrapper,
478
      contextId,
479
      inquirer,
480
      keyOrIndex,
481
    );
482
  }
483

484
  public resolveParamToken<T>(
485
    wrapper: InstanceWrapper<T>,
486
    param: Type<any> | string | symbol | ForwardReference,
487
  ) {
488
    if (typeof param === 'object' && 'forwardRef' in param) {
10✔
489
      wrapper.forwardRef = true;
2✔
490
      return param.forwardRef();
2✔
491
    }
492
    return param;
8✔
493
  }
494

495
  public async resolveComponentWrapper<T>(
496
    moduleRef: Module,
497
    token: InjectionToken,
498
    dependencyContext: InjectorDependencyContext,
499
    wrapper: InstanceWrapper<T>,
500
    contextId = STATIC_CONTEXT,
×
501
    inquirer?: InstanceWrapper,
502
    keyOrIndex?: symbol | string | number,
503
  ): Promise<InstanceWrapper> {
504
    this.printResolvingDependenciesLog(token, inquirer);
6✔
505
    this.printLookingForProviderLog(token, moduleRef);
6✔
506
    const providers = moduleRef.providers;
6✔
507
    return this.lookupComponent(
6✔
508
      providers,
509
      moduleRef,
510
      { ...dependencyContext, name: token },
511
      wrapper,
512
      contextId,
513
      inquirer,
514
      keyOrIndex,
515
    );
516
  }
517

518
  public async resolveComponentHost<T>(
519
    moduleRef: Module,
520
    instanceWrapper: InstanceWrapper<T | Promise<T>>,
521
    contextId = STATIC_CONTEXT,
4✔
522
    inquirer?: InstanceWrapper,
523
  ): Promise<InstanceWrapper> {
524
    const inquirerId = this.getInquirerId(inquirer);
10✔
525
    const instanceHost = instanceWrapper.getInstanceByContextId(
10✔
526
      this.getContextId(contextId, instanceWrapper),
527
      inquirerId,
528
    );
529
    if (!instanceHost.isResolved && !instanceWrapper.forwardRef) {
10✔
530
      inquirer?.settlementSignal?.insertRef(instanceWrapper.id);
5✔
531

532
      await this.loadProvider(
5✔
533
        instanceWrapper,
534
        instanceWrapper.host ?? moduleRef,
10✔
535
        contextId,
536
        inquirer,
537
      );
538
    } else if (
5!
539
      !instanceHost.isResolved &&
11✔
540
      instanceWrapper.forwardRef &&
541
      (contextId !== STATIC_CONTEXT || !!inquirerId)
542
    ) {
543
      /**
544
       * When circular dependency has been detected between
545
       * either request/transient providers, we have to asynchronously
546
       * resolve instance host for a specific contextId or inquirer, to ensure
547
       * that eventual lazily created instance will be merged with the prototype
548
       * instantiated beforehand.
549
       */
550
      instanceHost.donePromise &&
×
551
        void instanceHost.donePromise.then(() =>
552
          this.loadProvider(instanceWrapper, moduleRef, contextId, inquirer),
×
553
        );
554
    }
555
    if (instanceWrapper.async) {
10✔
556
      const host = instanceWrapper.getInstanceByContextId(
1✔
557
        this.getContextId(contextId, instanceWrapper),
558
        inquirerId,
559
      );
560
      host.instance = await host.instance;
1✔
561
      instanceWrapper.setInstanceByContextId(contextId, host, inquirerId);
1✔
562
    }
563
    return instanceWrapper;
10✔
564
  }
565

566
  public async lookupComponent<T = any>(
567
    providers: Map<Function | string | symbol, InstanceWrapper>,
568
    moduleRef: Module,
569
    dependencyContext: InjectorDependencyContext,
570
    wrapper: InstanceWrapper<T>,
571
    contextId = STATIC_CONTEXT,
5✔
572
    inquirer?: InstanceWrapper,
573
    keyOrIndex?: symbol | string | number,
574
  ): Promise<InstanceWrapper<T>> {
575
    const token = wrapper.token || wrapper.name;
11✔
576
    const { name } = dependencyContext;
11✔
577
    if (wrapper && token === name) {
11✔
578
      throw new UnknownDependenciesException(
1✔
579
        wrapper.name,
580
        dependencyContext,
581
        moduleRef,
582
        { id: wrapper.id },
583
      );
584
    }
585
    if (name && providers.has(name)) {
10✔
586
      const instanceWrapper = providers.get(name)!;
7✔
587
      this.printFoundInModuleLog(name, moduleRef);
7✔
588
      this.addDependencyMetadata(keyOrIndex!, wrapper, instanceWrapper);
7✔
589
      return instanceWrapper;
7✔
590
    }
591
    return this.lookupComponentInParentModules(
3✔
592
      dependencyContext,
593
      moduleRef,
594
      wrapper,
595
      contextId,
596
      inquirer,
597
      keyOrIndex,
598
    );
599
  }
600

601
  public async lookupComponentInParentModules<T = any>(
602
    dependencyContext: InjectorDependencyContext,
603
    moduleRef: Module,
604
    wrapper: InstanceWrapper<T>,
605
    contextId = STATIC_CONTEXT,
×
606
    inquirer?: InstanceWrapper,
607
    keyOrIndex?: symbol | string | number,
608
  ) {
609
    const instanceWrapper = await this.lookupComponentInImports(
3✔
610
      moduleRef,
611
      dependencyContext.name!,
612
      wrapper,
613
      [],
614
      contextId,
615
      inquirer,
616
      keyOrIndex,
617
    );
618
    if (isNil(instanceWrapper)) {
3✔
619
      throw new UnknownDependenciesException(
1✔
620
        wrapper.name,
621
        dependencyContext,
622
        moduleRef,
623
        { id: wrapper.id },
624
      );
625
    }
626
    return instanceWrapper;
2✔
627
  }
628

629
  public async lookupComponentInImports(
630
    moduleRef: Module,
631
    name: InjectionToken,
632
    wrapper: InstanceWrapper,
633
    moduleRegistry: any[] = [],
3✔
634
    contextId = STATIC_CONTEXT,
3✔
635
    inquirer?: InstanceWrapper,
636
    keyOrIndex?: symbol | string | number,
637
    isTraversing?: boolean,
638
  ): Promise<any> {
639
    let instanceWrapperRef: InstanceWrapper | null = null;
3✔
640
    const imports = moduleRef.imports || new Set<Module>();
3✔
641
    const identity = (item: any) => item;
3✔
642

643
    let children = [...imports.values()].filter(identity);
3✔
644
    if (isTraversing) {
3!
645
      const contextModuleExports = moduleRef.exports;
×
646
      children = children.filter(child =>
×
647
        contextModuleExports.has(child.metatype),
×
648
      );
649
    }
650
    for (const relatedModule of children) {
3✔
651
      if (moduleRegistry.includes(relatedModule.id)) {
×
652
        continue;
×
653
      }
654
      this.printLookingForProviderLog(name, relatedModule);
×
655
      moduleRegistry.push(relatedModule.id);
×
656

657
      const { providers, exports } = relatedModule;
×
658
      if (!exports.has(name) || !providers.has(name)) {
×
659
        const instanceRef = await this.lookupComponentInImports(
×
660
          relatedModule,
661
          name,
662
          wrapper,
663
          moduleRegistry,
664
          contextId,
665
          inquirer,
666
          keyOrIndex,
667
          true,
668
        );
669
        if (instanceRef) {
×
670
          this.addDependencyMetadata(keyOrIndex!, wrapper, instanceRef);
×
671
          return instanceRef;
×
672
        }
673
        continue;
×
674
      }
675
      this.printFoundInModuleLog(name, relatedModule);
×
676
      instanceWrapperRef = providers.get(name)!;
×
677
      this.addDependencyMetadata(keyOrIndex!, wrapper, instanceWrapperRef);
×
678

679
      const inquirerId = this.getInquirerId(inquirer);
×
680
      const instanceHost = instanceWrapperRef.getInstanceByContextId(
×
681
        this.getContextId(contextId, instanceWrapperRef),
682
        inquirerId,
683
      );
684
      if (!instanceHost.isResolved && !instanceWrapperRef.forwardRef) {
×
685
        /*
686
         * Provider will be loaded shortly in resolveComponentHost() once we pass the current
687
         * Barrier. We cannot load it here because doing so could incorrectly evaluate the
688
         * staticity of the dependency tree and lead to undefined / null injection.
689
         */
690
        break;
×
691
      }
692
    }
693
    return instanceWrapperRef;
3✔
694
  }
695

696
  public async resolveProperties<T>(
697
    wrapper: InstanceWrapper<T>,
698
    moduleRef: Module,
699
    inject?: InjectorDependency[],
700
    contextId = STATIC_CONTEXT,
×
701
    inquirer?: InstanceWrapper,
702
    parentInquirer?: InstanceWrapper,
703
  ): Promise<PropertyDependency[]> {
704
    if (!isNil(inject)) {
84!
705
      return [];
×
706
    }
707
    const metadata = wrapper.getPropertiesMetadata();
84✔
708
    if (metadata && contextId !== STATIC_CONTEXT) {
84✔
709
      return this.loadPropertiesMetadata(metadata, contextId, inquirer);
1✔
710
    }
711
    const properties = this.reflectProperties(wrapper.metatype as Type<any>);
83✔
712
    const propertyBarrier = new Barrier(properties.length);
83✔
713
    const instances = await Promise.all(
83✔
714
      properties.map(async (item: PropertyDependency) => {
715
        try {
2✔
716
          const dependencyContext = {
2✔
717
            key: item.key,
718
            name: item.name as Function | string | symbol,
719
          };
720
          if (this.isInquirer(item.name, parentInquirer)) {
2!
721
            /*
722
             * Signal the barrier to make sure other dependencies do not get stuck waiting forever.
723
             */
724
            propertyBarrier.signal();
×
725

726
            return parentInquirer && parentInquirer.instance;
×
727
          }
728
          const paramWrapper = await this.resolveSingleParam<T>(
2✔
729
            wrapper,
730
            item.name as string,
731
            dependencyContext,
732
            moduleRef,
733
            contextId,
734
            inquirer,
735
            item.key,
736
          );
737

738
          /*
739
           * Ensure that all instance wrappers are resolved at this point before we continue.
740
           * Otherwise the staticity of `wrapper`'s dependency tree may be evaluated incorrectly
741
           * and result in undefined / null injection.
742
           */
743
          await propertyBarrier.signalAndWait();
2✔
744

745
          const paramWrapperWithInstance = await this.resolveComponentHost(
2✔
746
            moduleRef,
747
            paramWrapper,
748
            contextId,
749
            inquirer,
750
          );
751
          if (!paramWrapperWithInstance) {
2!
752
            return undefined;
×
753
          }
754
          const inquirerId = this.getInquirerId(inquirer);
2✔
755
          const instanceHost = paramWrapperWithInstance.getInstanceByContextId(
2✔
756
            this.getContextId(contextId, paramWrapperWithInstance),
757
            inquirerId,
758
          );
759
          return instanceHost.instance;
2✔
760
        } catch (err) {
761
          /*
762
           * Signal the barrier to make sure other dependencies do not get stuck waiting forever. We
763
           * do not care if this occurs after `Barrier.signalAndWait()` is called in the `try` block
764
           * because the barrier will always have been resolved by then.
765
           */
766
          propertyBarrier.signal();
×
767

768
          if (!item.isOptional) {
×
769
            throw err;
×
770
          }
771
          return undefined;
×
772
        }
773
      }),
774
    );
775
    return properties.map((item: PropertyDependency, index: number) => ({
83✔
776
      ...item,
777
      instance: instances[index],
778
    }));
779
  }
780

781
  public reflectProperties<T>(type: Type<T>): PropertyDependency[] {
782
    const properties = Reflect.getMetadata(PROPERTY_DEPS_METADATA, type) || [];
83✔
783
    const optionalKeys: string[] =
784
      Reflect.getMetadata(OPTIONAL_PROPERTY_DEPS_METADATA, type) || [];
83✔
785

786
    return properties.map((item: any) => ({
83✔
787
      ...item,
788
      name: item.type,
789
      isOptional: optionalKeys.includes(item.key),
790
    }));
791
  }
792

793
  public applyProperties<T = any>(
794
    instance: T,
795
    properties: PropertyDependency[],
796
  ): void {
797
    if (!isObject(instance)) {
85✔
798
      return undefined;
1✔
799
    }
800
    iterate(properties)
84✔
801
      .filter(item => !isNil(item.instance))
5✔
802
      .forEach(item => (instance[item.key] = item.instance));
4✔
803
  }
804

805
  public async instantiateClass<T = any>(
806
    instances: any[],
807
    wrapper: InstanceWrapper,
808
    targetMetatype: InstanceWrapper,
809
    contextId = STATIC_CONTEXT,
×
810
    inquirer?: InstanceWrapper,
811
  ): Promise<T> {
812
    const { metatype, inject } = wrapper;
87✔
813
    const inquirerId = this.getInquirerId(inquirer);
87✔
814
    const instanceHost = targetMetatype.getInstanceByContextId(
87✔
815
      this.getContextId(contextId, targetMetatype),
816
      inquirerId,
817
    );
818
    const isInContext =
819
      wrapper.isStatic(contextId, inquirer) ||
87✔
820
      wrapper.isInRequestScope(contextId, inquirer) ||
821
      wrapper.isLazyTransient(contextId, inquirer) ||
822
      wrapper.isExplicitlyRequested(contextId, inquirer);
823

824
    if (this.options?.preview && !wrapper.host?.initOnPreview) {
87!
825
      instanceHost.isResolved = true;
×
826
      return instanceHost.instance;
×
827
    }
828

829
    if (isNil(inject) && isInContext) {
87✔
830
      instanceHost.instance = wrapper.forwardRef
60✔
831
        ? Object.assign(
60!
832
            instanceHost.instance,
833
            new (metatype as Type<any>)(...instances),
834
          )
835
        : new (metatype as Type<any>)(...instances);
836

837
      instanceHost.instance = this.instanceDecorator(instanceHost.instance);
60✔
838
      instanceHost.isConstructorCalled = true;
60✔
839
    } else if (isInContext) {
27✔
840
      const factoryReturnValue = (targetMetatype.metatype as any as Function)(
1✔
841
        ...instances,
842
      );
843
      instanceHost.instance = await factoryReturnValue;
1✔
844
      instanceHost.instance = this.instanceDecorator(instanceHost.instance);
1✔
845
      instanceHost.isConstructorCalled = true;
1✔
846
    }
847
    instanceHost.isResolved = true;
87✔
848
    return instanceHost.instance;
87✔
849
  }
850

851
  public async loadPerContext<T = any>(
852
    instance: T,
853
    moduleRef: Module,
854
    collection: Map<InjectionToken, InstanceWrapper>,
855
    ctx: ContextId,
856
    wrapper?: InstanceWrapper,
857
  ): Promise<T> {
858
    if (!wrapper) {
19✔
859
      const injectionToken = (instance as any).constructor!;
1✔
860
      wrapper = collection.get(injectionToken);
1✔
861
    }
862
    await this.loadInstance(wrapper!, collection, moduleRef, ctx, wrapper);
19✔
863
    await this.loadEnhancersPerContext(wrapper!, ctx, wrapper);
19✔
864

865
    const host = wrapper!.getInstanceByContextId(
19✔
866
      this.getContextId(ctx, wrapper!),
867
      wrapper!.id,
868
    );
869
    return host && (host.instance as T);
19✔
870
  }
871

872
  public async loadEnhancersPerContext(
873
    wrapper: InstanceWrapper,
874
    ctx: ContextId,
875
    inquirer?: InstanceWrapper,
876
  ) {
877
    const enhancers = wrapper.getEnhancersMetadata() || [];
119✔
878
    const loadEnhancer = (item: InstanceWrapper) => {
119✔
879
      const hostModule = item.host!;
2✔
880
      return this.loadInstance(
2✔
881
        item,
882
        hostModule.injectables,
883
        hostModule,
884
        ctx,
885
        inquirer,
886
      );
887
    };
888
    await Promise.all(enhancers.map(loadEnhancer));
119✔
889
  }
890

891
  public async loadCtorMetadata(
892
    metadata: InstanceWrapper<any>[],
893
    contextId: ContextId,
894
    inquirer?: InstanceWrapper,
895
    parentInquirer?: InstanceWrapper,
896
  ): Promise<any[]> {
897
    const hosts: Array<InstanceWrapper<any> | undefined> = await Promise.all(
2✔
898
      metadata.map(async item =>
899
        this.resolveScopedComponentHost(
2✔
900
          item,
901
          contextId,
902
          inquirer,
903
          parentInquirer,
904
        ),
905
      ),
906
    );
907
    const inquirerId = this.getInquirerId(inquirer);
2✔
908
    return hosts.map(
2✔
909
      item =>
910
        item?.getInstanceByContextId(
2✔
911
          this.getContextId(contextId, item),
912
          inquirerId,
913
        ).instance,
914
    );
915
  }
916

917
  public async loadPropertiesMetadata(
918
    metadata: PropertyMetadata[],
919
    contextId: ContextId,
920
    inquirer?: InstanceWrapper,
921
  ): Promise<PropertyDependency[]> {
922
    const dependenciesHosts = await Promise.all(
2✔
923
      metadata.map(async ({ wrapper: item, key }) => ({
2✔
924
        key,
925
        host: await this.resolveComponentHost(
926
          item.host!,
927
          item,
928
          contextId,
929
          inquirer,
930
        ),
931
      })),
932
    );
933
    const inquirerId = this.getInquirerId(inquirer);
2✔
934
    return dependenciesHosts.map(({ key, host }) => ({
2✔
935
      key,
936
      name: key,
937
      instance: host.getInstanceByContextId(
938
        this.getContextId(contextId, host),
939
        inquirerId,
940
      ).instance,
941
    }));
942
  }
943

944
  private getInquirerId(
945
    inquirer: InstanceWrapper | undefined,
946
  ): string | undefined {
947
    return inquirer ? inquirer.id : undefined;
330✔
948
  }
949

950
  private resolveScopedComponentHost(
951
    item: InstanceWrapper,
952
    contextId: ContextId,
953
    inquirer?: InstanceWrapper,
954
    parentInquirer?: InstanceWrapper,
955
  ) {
956
    return this.isInquirerRequest(item, parentInquirer)
2✔
957
      ? parentInquirer
2!
958
      : this.resolveComponentHost(item.host!, item, contextId, inquirer);
959
  }
960

961
  private isInquirerRequest(
962
    item: InstanceWrapper,
963
    parentInquirer: InstanceWrapper | undefined,
964
  ) {
965
    return item.isTransient && item.name === INQUIRER && parentInquirer;
2!
966
  }
967

968
  private isInquirer(
969
    param: unknown,
970
    parentInquirer: InstanceWrapper | undefined,
971
  ) {
972
    return param === INQUIRER && parentInquirer;
6!
973
  }
974

975
  protected addDependencyMetadata(
976
    keyOrIndex: symbol | string | number,
977
    hostWrapper: InstanceWrapper,
978
    instanceWrapper: InstanceWrapper,
979
  ) {
980
    if (isSymbol(keyOrIndex) || isString(keyOrIndex)) {
10✔
981
      hostWrapper.addPropertiesMetadata(keyOrIndex, instanceWrapper);
4✔
982
    } else {
983
      hostWrapper.addCtorMetadata(keyOrIndex, instanceWrapper);
6✔
984
    }
985
  }
986

987
  private getTokenName(token: InjectionToken): string {
988
    return isFunction(token) ? (token as Function).name : token.toString();
×
989
  }
990

991
  private printResolvingDependenciesLog(
992
    token: InjectionToken,
993
    inquirer?: InstanceWrapper,
994
  ): void {
995
    if (!this.isDebugMode()) {
6!
996
      return;
6✔
997
    }
998
    const tokenName = this.getTokenName(token);
×
999
    const dependentName =
1000
      (inquirer?.name && inquirer.name.toString?.()) ?? 'unknown';
×
1001
    const isAlias = dependentName === tokenName;
×
1002

1003
    const messageToPrint = `Resolving dependency ${clc.cyanBright(
×
1004
      tokenName,
1005
    )}${clc.green(' in the ')}${clc.yellow(dependentName)}${clc.green(
1006
      ` provider ${isAlias ? '(alias)' : ''}`,
×
1007
    )}`;
1008

1009
    this.logger.log(messageToPrint);
×
1010
  }
1011

1012
  private printLookingForProviderLog(
1013
    token: InjectionToken,
1014
    moduleRef: Module,
1015
  ): void {
1016
    if (!this.isDebugMode()) {
6!
1017
      return;
6✔
1018
    }
1019
    const tokenName = this.getTokenName(token);
×
1020
    const moduleRefName = moduleRef?.metatype?.name ?? 'unknown';
×
1021
    this.logger.log(
×
1022
      `Looking for ${clc.cyanBright(tokenName)}${clc.green(
1023
        ' in ',
1024
      )}${clc.magentaBright(moduleRefName)}`,
1025
    );
1026
  }
1027

1028
  private printFoundInModuleLog(
1029
    token: InjectionToken,
1030
    moduleRef: Module,
1031
  ): void {
1032
    if (!this.isDebugMode()) {
7!
1033
      return;
7✔
1034
    }
1035
    const tokenName = this.getTokenName(token);
×
1036
    const moduleRefName = moduleRef?.metatype?.name ?? 'unknown';
×
1037
    this.logger.log(
×
1038
      `Found ${clc.cyanBright(tokenName)}${clc.green(
1039
        ' in ',
1040
      )}${clc.magentaBright(moduleRefName)}`,
1041
    );
1042
  }
1043

1044
  private isDebugMode(): boolean {
1045
    return !!process.env.NEST_DEBUG;
19✔
1046
  }
1047

1048
  private getContextId(
1049
    contextId: ContextId,
1050
    instanceWrapper: InstanceWrapper,
1051
  ): ContextId {
1052
    return contextId.getParent
270✔
1053
      ? contextId.getParent({
270!
1054
          token: instanceWrapper.token,
1055
          isTreeDurable: instanceWrapper.isDependencyTreeDurable(),
1056
        })
1057
      : contextId;
1058
  }
1059

1060
  private getNowTimestamp() {
1061
    return performance.now();
166✔
1062
  }
1063
}
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