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

nestjs / nest / a4d5f079-e4c7-473a-a3b3-a406892e6719

16 Jul 2025 07:48AM UTC coverage: 88.934% (+0.02%) from 88.913%
a4d5f079-e4c7-473a-a3b3-a406892e6719

Pull #15413

circleci

y-nk
feat(common): add generic for argument metadata
Pull Request #15413: feat(common): add generic for argument metadata

2730 of 3449 branches covered (79.15%)

7265 of 8169 relevant lines covered (88.93%)

16.62 hits per line

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

84.27
/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 { STATIC_CONTEXT } from './constants';
1✔
36
import { INQUIRER } from './inquirer';
1✔
37
import {
1✔
38
  ContextId,
39
  InstancePerContext,
40
  InstanceWrapper,
41
  PropertyMetadata,
42
} from './instance-wrapper';
43
import { Module } from './module';
44
import { SettlementSignal } from './settlement-signal';
1✔
45

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

286
    return settlementSignal;
131✔
287
  }
288

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

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

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

316
    let isResolved = true;
83✔
317
    const resolveParam = async (param: unknown, index: number) => {
83✔
318
      try {
4✔
319
        if (this.isInquirer(param, parentInquirer)) {
4!
320
          return parentInquirer && parentInquirer.instance;
×
321
        }
322
        if (inquirer?.isTransient && parentInquirer) {
4!
323
          inquirer = parentInquirer;
×
324
          inquirerId = this.getInquirerId(parentInquirer);
×
325
        }
326
        const paramWrapper = await this.resolveSingleParam<T>(
4✔
327
          wrapper,
328
          param as Type | string | symbol,
329
          { index, dependencies },
330
          moduleRef,
331
          contextId,
332
          inquirer,
333
          index,
334
        );
335
        const instanceHost = paramWrapper.getInstanceByContextId(
4✔
336
          this.getContextId(contextId, paramWrapper),
337
          inquirerId,
338
        );
339
        if (!instanceHost.isResolved && !paramWrapper.forwardRef) {
4!
340
          isResolved = false;
×
341
        }
342
        return instanceHost?.instance;
4✔
343
      } catch (err) {
344
        const isOptional = optionalDependenciesIds.includes(index);
×
345
        if (!isOptional) {
×
346
          throw err;
×
347
        }
348
        return undefined;
×
349
      }
350
    };
351
    const instances = await Promise.all(dependencies.map(resolveParam));
83✔
352
    isResolved && (await callback(instances));
83✔
353
  }
354

355
  public getClassDependencies<T>(
356
    wrapper: InstanceWrapper<T>,
357
  ): [InjectorDependency[], number[]] {
358
    const ctorRef = wrapper.metatype as Type<any>;
85✔
359
    return [
85✔
360
      this.reflectConstructorParams(ctorRef),
361
      this.reflectOptionalParams(ctorRef),
362
    ];
363
  }
364

365
  public getFactoryProviderDependencies<T>(
366
    wrapper: InstanceWrapper<T>,
367
  ): [InjectorDependency[], number[]] {
368
    const optionalDependenciesIds: number[] = [];
1✔
369

370
    /**
371
     * Same as the internal utility function `isOptionalFactoryDependency` from `@nestjs/common`.
372
     * We are duplicating it here because that one is not supposed to be exported.
373
     */
374
    function isOptionalFactoryDependency(
375
      value: InjectionToken | OptionalFactoryDependency,
376
    ): value is OptionalFactoryDependency {
377
      return (
3✔
378
        !isUndefined((value as OptionalFactoryDependency).token) &&
7✔
379
        !isUndefined((value as OptionalFactoryDependency).optional) &&
380
        !(value as any).prototype
381
      );
382
    }
383

384
    const mapFactoryProviderInjectArray = (
1✔
385
      item: InjectionToken | OptionalFactoryDependency,
386
      index: number,
387
    ): InjectionToken => {
388
      if (typeof item !== 'object') {
4✔
389
        return item;
1✔
390
      }
391
      if (isOptionalFactoryDependency(item)) {
3✔
392
        if (item.optional) {
2✔
393
          optionalDependenciesIds.push(index);
1✔
394
        }
395
        return item?.token;
2✔
396
      }
397
      return item;
1✔
398
    };
399
    return [
1✔
400
      wrapper.inject?.map?.(mapFactoryProviderInjectArray) as any[],
401
      optionalDependenciesIds,
402
    ];
403
  }
404

405
  public reflectConstructorParams<T>(type: Type<T>): any[] {
406
    const paramtypes = [
85✔
407
      ...(Reflect.getMetadata(PARAMTYPES_METADATA, type) || []),
166✔
408
    ];
409
    const selfParams = this.reflectSelfParams<T>(type);
85✔
410

411
    selfParams.forEach(({ index, param }) => (paramtypes[index] = param));
85✔
412
    return paramtypes;
85✔
413
  }
414

415
  public reflectOptionalParams<T>(type: Type<T>): any[] {
416
    return Reflect.getMetadata(OPTIONAL_DEPS_METADATA, type) || [];
85✔
417
  }
418

419
  public reflectSelfParams<T>(type: Type<T>): any[] {
420
    return Reflect.getMetadata(SELF_DECLARED_DEPS_METADATA, type) || [];
85✔
421
  }
422

423
  public async resolveSingleParam<T>(
424
    wrapper: InstanceWrapper<T>,
425
    param: Type<any> | string | symbol,
426
    dependencyContext: InjectorDependencyContext,
427
    moduleRef: Module,
428
    contextId = STATIC_CONTEXT,
1✔
429
    inquirer?: InstanceWrapper,
430
    keyOrIndex?: symbol | string | number,
431
  ) {
432
    if (isUndefined(param)) {
7✔
433
      this.logger.log(
1✔
434
        'Nest encountered an undefined dependency. This may be due to a circular import or a missing dependency declaration.',
435
      );
436
      throw new UndefinedDependencyException(
1✔
437
        wrapper.name,
438
        dependencyContext,
439
        moduleRef,
440
      );
441
    }
442
    const token = this.resolveParamToken(wrapper, param);
6✔
443
    return this.resolveComponentInstance<T>(
6✔
444
      moduleRef,
445
      token,
446
      dependencyContext,
447
      wrapper,
448
      contextId,
449
      inquirer,
450
      keyOrIndex,
451
    );
452
  }
453

454
  public resolveParamToken<T>(
455
    wrapper: InstanceWrapper<T>,
456
    param: Type<any> | string | symbol | ForwardReference,
457
  ) {
458
    if (typeof param === 'object' && 'forwardRef' in param) {
10✔
459
      wrapper.forwardRef = true;
2✔
460
      return param.forwardRef();
2✔
461
    }
462
    return param;
8✔
463
  }
464

465
  public async resolveComponentInstance<T>(
466
    moduleRef: Module,
467
    token: InjectionToken,
468
    dependencyContext: InjectorDependencyContext,
469
    wrapper: InstanceWrapper<T>,
470
    contextId = STATIC_CONTEXT,
4✔
471
    inquirer?: InstanceWrapper,
472
    keyOrIndex?: symbol | string | number,
473
  ): Promise<InstanceWrapper> {
474
    this.printResolvingDependenciesLog(token, inquirer);
10✔
475
    this.printLookingForProviderLog(token, moduleRef);
10✔
476
    const providers = moduleRef.providers;
10✔
477
    const instanceWrapper = await this.lookupComponent(
10✔
478
      providers,
479
      moduleRef,
480
      { ...dependencyContext, name: token },
481
      wrapper,
482
      contextId,
483
      inquirer,
484
      keyOrIndex,
485
    );
486

487
    return this.resolveComponentHost(
10✔
488
      moduleRef,
489
      instanceWrapper,
490
      contextId,
491
      inquirer,
492
    );
493
  }
494

495
  public async resolveComponentHost<T>(
496
    moduleRef: Module,
497
    instanceWrapper: InstanceWrapper<T | Promise<T>>,
498
    contextId = STATIC_CONTEXT,
×
499
    inquirer?: InstanceWrapper,
500
  ): Promise<InstanceWrapper> {
501
    const inquirerId = this.getInquirerId(inquirer);
10✔
502
    const instanceHost = instanceWrapper.getInstanceByContextId(
10✔
503
      this.getContextId(contextId, instanceWrapper),
504
      inquirerId,
505
    );
506
    if (!instanceHost.isResolved && !instanceWrapper.forwardRef) {
10✔
507
      inquirer?.settlementSignal?.insertRef(instanceWrapper.id);
5✔
508

509
      await this.loadProvider(
5✔
510
        instanceWrapper,
511
        instanceWrapper.host ?? moduleRef,
10✔
512
        contextId,
513
        inquirer,
514
      );
515
    } else if (
5!
516
      !instanceHost.isResolved &&
11✔
517
      instanceWrapper.forwardRef &&
518
      (contextId !== STATIC_CONTEXT || !!inquirerId)
519
    ) {
520
      /**
521
       * When circular dependency has been detected between
522
       * either request/transient providers, we have to asynchronously
523
       * resolve instance host for a specific contextId or inquirer, to ensure
524
       * that eventual lazily created instance will be merged with the prototype
525
       * instantiated beforehand.
526
       */
527
      instanceHost.donePromise &&
×
528
        void instanceHost.donePromise.then(() =>
529
          this.loadProvider(instanceWrapper, moduleRef, contextId, inquirer),
×
530
        );
531
    }
532
    if (instanceWrapper.async) {
10✔
533
      const host = instanceWrapper.getInstanceByContextId(
1✔
534
        this.getContextId(contextId, instanceWrapper),
535
        inquirerId,
536
      );
537
      host.instance = await host.instance;
1✔
538
      instanceWrapper.setInstanceByContextId(contextId, host, inquirerId);
1✔
539
    }
540
    return instanceWrapper;
10✔
541
  }
542

543
  public async lookupComponent<T = any>(
544
    providers: Map<Function | string | symbol, InstanceWrapper>,
545
    moduleRef: Module,
546
    dependencyContext: InjectorDependencyContext,
547
    wrapper: InstanceWrapper<T>,
548
    contextId = STATIC_CONTEXT,
5✔
549
    inquirer?: InstanceWrapper,
550
    keyOrIndex?: symbol | string | number,
551
  ): Promise<InstanceWrapper<T>> {
552
    const token = wrapper.token || wrapper.name;
11✔
553
    const { name } = dependencyContext;
11✔
554
    if (wrapper && token === name) {
11✔
555
      throw new UnknownDependenciesException(
1✔
556
        wrapper.name,
557
        dependencyContext,
558
        moduleRef,
559
        { id: wrapper.id },
560
      );
561
    }
562
    if (name && providers.has(name)) {
10✔
563
      const instanceWrapper = providers.get(name)!;
7✔
564
      this.printFoundInModuleLog(name, moduleRef);
7✔
565
      this.addDependencyMetadata(keyOrIndex!, wrapper, instanceWrapper);
7✔
566
      return instanceWrapper;
7✔
567
    }
568
    return this.lookupComponentInParentModules(
3✔
569
      dependencyContext,
570
      moduleRef,
571
      wrapper,
572
      contextId,
573
      inquirer,
574
      keyOrIndex,
575
    );
576
  }
577

578
  public async lookupComponentInParentModules<T = any>(
579
    dependencyContext: InjectorDependencyContext,
580
    moduleRef: Module,
581
    wrapper: InstanceWrapper<T>,
582
    contextId = STATIC_CONTEXT,
×
583
    inquirer?: InstanceWrapper,
584
    keyOrIndex?: symbol | string | number,
585
  ) {
586
    const instanceWrapper = await this.lookupComponentInImports(
3✔
587
      moduleRef,
588
      dependencyContext.name!,
589
      wrapper,
590
      [],
591
      contextId,
592
      inquirer,
593
      keyOrIndex,
594
    );
595
    if (isNil(instanceWrapper)) {
3✔
596
      throw new UnknownDependenciesException(
1✔
597
        wrapper.name,
598
        dependencyContext,
599
        moduleRef,
600
        { id: wrapper.id },
601
      );
602
    }
603
    return instanceWrapper;
2✔
604
  }
605

606
  public async lookupComponentInImports(
607
    moduleRef: Module,
608
    name: InjectionToken,
609
    wrapper: InstanceWrapper,
610
    moduleRegistry: any[] = [],
5✔
611
    contextId = STATIC_CONTEXT,
5✔
612
    inquirer?: InstanceWrapper,
613
    keyOrIndex?: symbol | string | number,
614
    isTraversing?: boolean,
615
  ): Promise<any> {
616
    let instanceWrapperRef: InstanceWrapper | null = null;
5✔
617
    const imports = moduleRef.imports || new Set<Module>();
5✔
618
    const identity = (item: any) => item;
5✔
619

620
    let children = [...imports.values()].filter(identity);
5✔
621
    if (isTraversing) {
5!
622
      const contextModuleExports = moduleRef.exports;
×
623
      children = children.filter(child =>
×
624
        contextModuleExports.has(child.metatype),
×
625
      );
626
    }
627
    for (const relatedModule of children) {
5✔
628
      if (moduleRegistry.includes(relatedModule.id)) {
1!
629
        continue;
×
630
      }
631
      this.printLookingForProviderLog(name, relatedModule);
1✔
632
      moduleRegistry.push(relatedModule.id);
1✔
633

634
      const { providers, exports } = relatedModule;
1✔
635
      if (!exports.has(name) || !providers.has(name)) {
1!
636
        const instanceRef = await this.lookupComponentInImports(
×
637
          relatedModule,
638
          name,
639
          wrapper,
640
          moduleRegistry,
641
          contextId,
642
          inquirer,
643
          keyOrIndex,
644
          true,
645
        );
646
        if (instanceRef) {
×
647
          this.addDependencyMetadata(keyOrIndex!, wrapper, instanceRef);
×
648
          return instanceRef;
×
649
        }
650
        continue;
×
651
      }
652
      this.printFoundInModuleLog(name, relatedModule);
1✔
653
      instanceWrapperRef = providers.get(name)!;
1✔
654
      this.addDependencyMetadata(keyOrIndex!, wrapper, instanceWrapperRef);
1✔
655

656
      const inquirerId = this.getInquirerId(inquirer);
1✔
657
      const instanceHost = instanceWrapperRef.getInstanceByContextId(
1✔
658
        this.getContextId(contextId, instanceWrapperRef),
659
        inquirerId,
660
      );
661
      if (!instanceHost.isResolved && !instanceWrapperRef.forwardRef) {
1!
662
        wrapper.settlementSignal?.insertRef(instanceWrapperRef.id);
1✔
663

664
        await this.loadProvider(
1✔
665
          instanceWrapperRef,
666
          relatedModule,
667
          contextId,
668
          wrapper,
669
        );
670
        break;
1✔
671
      }
672
    }
673
    return instanceWrapperRef;
5✔
674
  }
675

676
  public async resolveProperties<T>(
677
    wrapper: InstanceWrapper<T>,
678
    moduleRef: Module,
679
    inject?: InjectorDependency[],
680
    contextId = STATIC_CONTEXT,
×
681
    inquirer?: InstanceWrapper,
682
    parentInquirer?: InstanceWrapper,
683
  ): Promise<PropertyDependency[]> {
684
    if (!isNil(inject)) {
84!
685
      return [];
×
686
    }
687
    const metadata = wrapper.getPropertiesMetadata();
84✔
688
    if (metadata && contextId !== STATIC_CONTEXT) {
84✔
689
      return this.loadPropertiesMetadata(metadata, contextId, inquirer);
1✔
690
    }
691
    const properties = this.reflectProperties(wrapper.metatype as Type<any>);
83✔
692
    const instances = await Promise.all(
83✔
693
      properties.map(async (item: PropertyDependency) => {
694
        try {
2✔
695
          const dependencyContext = {
2✔
696
            key: item.key,
697
            name: item.name as Function | string | symbol,
698
          };
699
          if (this.isInquirer(item.name, parentInquirer)) {
2!
700
            return parentInquirer && parentInquirer.instance;
×
701
          }
702
          const paramWrapper = await this.resolveSingleParam<T>(
2✔
703
            wrapper,
704
            item.name as string,
705
            dependencyContext,
706
            moduleRef,
707
            contextId,
708
            inquirer,
709
            item.key,
710
          );
711
          if (!paramWrapper) {
2!
712
            return undefined;
×
713
          }
714
          const inquirerId = this.getInquirerId(inquirer);
2✔
715
          const instanceHost = paramWrapper.getInstanceByContextId(
2✔
716
            this.getContextId(contextId, paramWrapper),
717
            inquirerId,
718
          );
719
          return instanceHost.instance;
2✔
720
        } catch (err) {
721
          if (!item.isOptional) {
×
722
            throw err;
×
723
          }
724
          return undefined;
×
725
        }
726
      }),
727
    );
728
    return properties.map((item: PropertyDependency, index: number) => ({
83✔
729
      ...item,
730
      instance: instances[index],
731
    }));
732
  }
733

734
  public reflectProperties<T>(type: Type<T>): PropertyDependency[] {
735
    const properties = Reflect.getMetadata(PROPERTY_DEPS_METADATA, type) || [];
83✔
736
    const optionalKeys: string[] =
737
      Reflect.getMetadata(OPTIONAL_PROPERTY_DEPS_METADATA, type) || [];
83✔
738

739
    return properties.map((item: any) => ({
83✔
740
      ...item,
741
      name: item.type,
742
      isOptional: optionalKeys.includes(item.key),
743
    }));
744
  }
745

746
  public applyProperties<T = any>(
747
    instance: T,
748
    properties: PropertyDependency[],
749
  ): void {
750
    if (!isObject(instance)) {
85✔
751
      return undefined;
1✔
752
    }
753
    iterate(properties)
84✔
754
      .filter(item => !isNil(item.instance))
5✔
755
      .forEach(item => (instance[item.key] = item.instance));
4✔
756
  }
757

758
  public async instantiateClass<T = any>(
759
    instances: any[],
760
    wrapper: InstanceWrapper,
761
    targetMetatype: InstanceWrapper,
762
    contextId = STATIC_CONTEXT,
×
763
    inquirer?: InstanceWrapper,
764
  ): Promise<T> {
765
    const { metatype, inject } = wrapper;
87✔
766
    const inquirerId = this.getInquirerId(inquirer);
87✔
767
    const instanceHost = targetMetatype.getInstanceByContextId(
87✔
768
      this.getContextId(contextId, targetMetatype),
769
      inquirerId,
770
    );
771
    const isInContext =
772
      wrapper.isStatic(contextId, inquirer) ||
87✔
773
      wrapper.isInRequestScope(contextId, inquirer) ||
774
      wrapper.isLazyTransient(contextId, inquirer) ||
775
      wrapper.isExplicitlyRequested(contextId, inquirer);
776

777
    if (this.options?.preview && !wrapper.host?.initOnPreview) {
87!
778
      instanceHost.isResolved = true;
×
779
      return instanceHost.instance;
×
780
    }
781

782
    if (isNil(inject) && isInContext) {
87✔
783
      instanceHost.instance = wrapper.forwardRef
60✔
784
        ? Object.assign(
60!
785
            instanceHost.instance,
786
            new (metatype as Type<any>)(...instances),
787
          )
788
        : new (metatype as Type<any>)(...instances);
789

790
      instanceHost.instance = this.instanceDecorator(instanceHost.instance);
60✔
791
    } else if (isInContext) {
27✔
792
      const factoryReturnValue = (targetMetatype.metatype as any as Function)(
1✔
793
        ...instances,
794
      );
795
      instanceHost.instance = await factoryReturnValue;
1✔
796
      instanceHost.instance = this.instanceDecorator(instanceHost.instance);
1✔
797
    }
798
    instanceHost.isResolved = true;
87✔
799
    return instanceHost.instance;
87✔
800
  }
801

802
  public async loadPerContext<T = any>(
803
    instance: T,
804
    moduleRef: Module,
805
    collection: Map<InjectionToken, InstanceWrapper>,
806
    ctx: ContextId,
807
    wrapper?: InstanceWrapper,
808
  ): Promise<T> {
809
    if (!wrapper) {
19✔
810
      const injectionToken = (instance as any).constructor!;
1✔
811
      wrapper = collection.get(injectionToken);
1✔
812
    }
813
    await this.loadInstance(wrapper!, collection, moduleRef, ctx, wrapper);
19✔
814
    await this.loadEnhancersPerContext(wrapper!, ctx, wrapper);
19✔
815

816
    const host = wrapper!.getInstanceByContextId(
19✔
817
      this.getContextId(ctx, wrapper!),
818
      wrapper!.id,
819
    );
820
    return host && (host.instance as T);
19✔
821
  }
822

823
  public async loadEnhancersPerContext(
824
    wrapper: InstanceWrapper,
825
    ctx: ContextId,
826
    inquirer?: InstanceWrapper,
827
  ) {
828
    const enhancers = wrapper.getEnhancersMetadata() || [];
119✔
829
    const loadEnhancer = (item: InstanceWrapper) => {
119✔
830
      const hostModule = item.host!;
2✔
831
      return this.loadInstance(
2✔
832
        item,
833
        hostModule.injectables,
834
        hostModule,
835
        ctx,
836
        inquirer,
837
      );
838
    };
839
    await Promise.all(enhancers.map(loadEnhancer));
119✔
840
  }
841

842
  public async loadCtorMetadata(
843
    metadata: InstanceWrapper<any>[],
844
    contextId: ContextId,
845
    inquirer?: InstanceWrapper,
846
    parentInquirer?: InstanceWrapper,
847
  ): Promise<any[]> {
848
    const hosts: Array<InstanceWrapper<any> | undefined> = await Promise.all(
2✔
849
      metadata.map(async item =>
850
        this.resolveScopedComponentHost(
2✔
851
          item,
852
          contextId,
853
          inquirer,
854
          parentInquirer,
855
        ),
856
      ),
857
    );
858
    const inquirerId = this.getInquirerId(inquirer);
2✔
859
    return hosts.map(
2✔
860
      item =>
861
        item?.getInstanceByContextId(
2✔
862
          this.getContextId(contextId, item),
863
          inquirerId,
864
        ).instance,
865
    );
866
  }
867

868
  public async loadPropertiesMetadata(
869
    metadata: PropertyMetadata[],
870
    contextId: ContextId,
871
    inquirer?: InstanceWrapper,
872
  ): Promise<PropertyDependency[]> {
873
    const dependenciesHosts = await Promise.all(
2✔
874
      metadata.map(async ({ wrapper: item, key }) => ({
2✔
875
        key,
876
        host: await this.resolveComponentHost(
877
          item.host!,
878
          item,
879
          contextId,
880
          inquirer,
881
        ),
882
      })),
883
    );
884
    const inquirerId = this.getInquirerId(inquirer);
2✔
885
    return dependenciesHosts.map(({ key, host }) => ({
2✔
886
      key,
887
      name: key,
888
      instance: host.getInstanceByContextId(
889
        this.getContextId(contextId, host),
890
        inquirerId,
891
      ).instance,
892
    }));
893
  }
894

895
  private getInquirerId(
896
    inquirer: InstanceWrapper | undefined,
897
  ): string | undefined {
898
    return inquirer ? inquirer.id : undefined;
331✔
899
  }
900

901
  private resolveScopedComponentHost(
902
    item: InstanceWrapper,
903
    contextId: ContextId,
904
    inquirer?: InstanceWrapper,
905
    parentInquirer?: InstanceWrapper,
906
  ) {
907
    return this.isInquirerRequest(item, parentInquirer)
2✔
908
      ? parentInquirer
2!
909
      : this.resolveComponentHost(item.host!, item, contextId, inquirer);
910
  }
911

912
  private isInquirerRequest(
913
    item: InstanceWrapper,
914
    parentInquirer: InstanceWrapper | undefined,
915
  ) {
916
    return item.isTransient && item.name === INQUIRER && parentInquirer;
2!
917
  }
918

919
  private isInquirer(
920
    param: unknown,
921
    parentInquirer: InstanceWrapper | undefined,
922
  ) {
923
    return param === INQUIRER && parentInquirer;
6!
924
  }
925

926
  protected addDependencyMetadata(
927
    keyOrIndex: symbol | string | number,
928
    hostWrapper: InstanceWrapper,
929
    instanceWrapper: InstanceWrapper,
930
  ) {
931
    if (isSymbol(keyOrIndex) || isString(keyOrIndex)) {
11✔
932
      hostWrapper.addPropertiesMetadata(keyOrIndex, instanceWrapper);
4✔
933
    } else {
934
      hostWrapper.addCtorMetadata(keyOrIndex, instanceWrapper);
7✔
935
    }
936
  }
937

938
  private getTokenName(token: InjectionToken): string {
939
    return isFunction(token) ? (token as Function).name : token.toString();
×
940
  }
941

942
  private printResolvingDependenciesLog(
943
    token: InjectionToken,
944
    inquirer?: InstanceWrapper,
945
  ): void {
946
    if (!this.isDebugMode()) {
10!
947
      return;
10✔
948
    }
949
    const tokenName = this.getTokenName(token);
×
950
    const dependentName =
951
      (inquirer?.name && inquirer.name.toString?.()) ?? 'unknown';
×
952
    const isAlias = dependentName === tokenName;
×
953

954
    const messageToPrint = `Resolving dependency ${clc.cyanBright(
×
955
      tokenName,
956
    )}${clc.green(' in the ')}${clc.yellow(dependentName)}${clc.green(
957
      ` provider ${isAlias ? '(alias)' : ''}`,
×
958
    )}`;
959

960
    this.logger.log(messageToPrint);
×
961
  }
962

963
  private printLookingForProviderLog(
964
    token: InjectionToken,
965
    moduleRef: Module,
966
  ): void {
967
    if (!this.isDebugMode()) {
11!
968
      return;
11✔
969
    }
970
    const tokenName = this.getTokenName(token);
×
971
    const moduleRefName = moduleRef?.metatype?.name ?? 'unknown';
×
972
    this.logger.log(
×
973
      `Looking for ${clc.cyanBright(tokenName)}${clc.green(
974
        ' in ',
975
      )}${clc.magentaBright(moduleRefName)}`,
976
    );
977
  }
978

979
  private printFoundInModuleLog(
980
    token: InjectionToken,
981
    moduleRef: Module,
982
  ): void {
983
    if (!this.isDebugMode()) {
8!
984
      return;
8✔
985
    }
986
    const tokenName = this.getTokenName(token);
×
987
    const moduleRefName = moduleRef?.metatype?.name ?? 'unknown';
×
988
    this.logger.log(
×
989
      `Found ${clc.cyanBright(tokenName)}${clc.green(
990
        ' in ',
991
      )}${clc.magentaBright(moduleRefName)}`,
992
    );
993
  }
994

995
  private isDebugMode(): boolean {
996
    return !!process.env.NEST_DEBUG;
29✔
997
  }
998

999
  private getContextId(
1000
    contextId: ContextId,
1001
    instanceWrapper: InstanceWrapper,
1002
  ): ContextId {
1003
    return contextId.getParent
271✔
1004
      ? contextId.getParent({
271!
1005
          token: instanceWrapper.token,
1006
          isTreeDurable: instanceWrapper.isDependencyTreeDurable(),
1007
        })
1008
      : contextId;
1009
  }
1010

1011
  private getNowTimestamp() {
1012
    return performance.now();
166✔
1013
  }
1014
}
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