Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/nestjs/nest
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilmysliwiec committed May 12, 2020
2 parents 7775081 + dcf3ca0 commit 64df4a9
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 155 deletions.
5 changes: 2 additions & 3 deletions packages/core/errors/exceptions/invalid-module.exception.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { INVALID_MODULE_MESSAGE } from '../messages';
import { RuntimeException } from './runtime.exception';

export class InvalidModuleException extends RuntimeException {
constructor(trace: any[]) {
const scope = (trace || []).map(module => module.name).join(' -> ');
super(INVALID_MODULE_MESSAGE`${scope}`);
constructor(parentModule: any, index: number, scope: any[]) {
super(INVALID_MODULE_MESSAGE(parentModule, index, scope));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { UNDEFINED_FORWARDREF_MESSAGE } from '../messages';
import { RuntimeException } from './runtime.exception';
import { Type } from '@nestjs/common';

export class UndefinedForwardRefException extends RuntimeException {
constructor(scope: Type<any>[]) {
super(UNDEFINED_FORWARDREF_MESSAGE(scope));
}
}
8 changes: 8 additions & 0 deletions packages/core/errors/exceptions/undefined-module.exception.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { RuntimeException } from './runtime.exception';
import { UNDEFINED_MODULE_MESSAGE } from '../messages';

export class UndefinedModuleException extends RuntimeException {
constructor(parentModule: any, index: number, scope: any[]) {
super(UNDEFINED_MODULE_MESSAGE(parentModule, index, scope));
}
}
45 changes: 38 additions & 7 deletions packages/core/errors/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ const getDependencyName = (dependency: InjectorDependency): string =>
const getModuleName = (module: Module) =>
(module && getInstanceName(module.metatype)) || 'current';

const stringifyScope = (scope: any[]): string =>
(scope || []).map(getInstanceName).join(' -> ');

export const UNKNOWN_DEPENDENCIES_MESSAGE = (
type: string | symbol,
unknownDependencyContext: InjectorDependencyContext,
Expand Down Expand Up @@ -84,15 +87,43 @@ export const INVALID_MIDDLEWARE_MESSAGE = (
name: string,
) => `The middleware doesn't provide the 'use' method (${name})`;

export const INVALID_MODULE_MESSAGE = (
text: TemplateStringsArray,
scope: string,
) =>
`Nest cannot create the module instance. Often, this is because of a circular dependency between modules. Use forwardRef() to avoid it.
export const UNDEFINED_FORWARDREF_MESSAGE = (
scope: Type<any>[],
) => `Nest cannot create the module instance. Often, this is because of a circular dependency between modules. Use forwardRef() to avoid it.
(Read more: https://docs.nestjs.com/fundamentals/circular-dependency)
Scope [${scope}]
`;
Scope [${stringifyScope(scope)}]
`;

export const INVALID_MODULE_MESSAGE = (
parentModule: any,
index: number,
scope: any[],
) => {
const parentModuleName = parentModule?.name || 'module';

return `Nest cannot create the ${parentModuleName} instance.
Received an unexpected value at index [${index}] of the ${parentModuleName} "imports" array.
Scope [${stringifyScope(scope)}]`;
};

export const UNDEFINED_MODULE_MESSAGE = (
parentModule: any,
index: number,
scope: any[],
) => {
const parentModuleName = parentModule?.name || 'module';

return `Nest cannot create the ${parentModuleName} instance.
The module at index [${index}] of the ${parentModuleName} "imports" array is undefined.
Potential causes:
- A circular dependency between modules. Use forwardRef() to avoid it. Read more: https://docs.nestjs.com/fundamentals/circular-dependency
- The module at index [${index}] is of type "undefined". Check your import statements and the type of the module.
Scope [${stringifyScope(scope)}]`;
};

export const UNKNOWN_EXPORT_MESSAGE = (token = 'item', module: string) => {
return `Nest cannot export a provider/module that is not a part of the currently processed module (${module}). Please verify whether the exported ${token} is available in this particular context.
Expand Down
6 changes: 4 additions & 2 deletions packages/core/injector/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Injectable } from '@nestjs/common/interfaces/injectable.interface';
import { Type } from '@nestjs/common/interfaces/type.interface';
import { ApplicationConfig } from '../application-config';
import { CircularDependencyException } from '../errors/exceptions/circular-dependency.exception';
import { InvalidModuleException } from '../errors/exceptions/invalid-module.exception';
import { UnknownModuleException } from '../errors/exceptions/unknown-module.exception';
import { ExternalContextCreator } from '../helpers/external-context-creator';
import { HttpAdapterHost } from '../helpers/http-adapter-host';
Expand All @@ -16,6 +15,7 @@ import { InternalProvidersStorage } from './internal-providers-storage';
import { Module } from './module';
import { ModuleTokenFactory } from './module-token-factory';
import { ModulesContainer } from './modules-container';
import { UndefinedForwardRefException } from '../errors/exceptions/undefined-forwardref.exception';

export class NestContainer {
private readonly globalModules = new Set<Module>();
Expand Down Expand Up @@ -55,8 +55,10 @@ export class NestContainer {
metatype: Type<any> | DynamicModule | Promise<DynamicModule>,
scope: Type<any>[],
): Promise<Module> {
// In DependenciesScanner#scanForModules we already check for undefined or invalid modules
// We sill need to catch the edge-case of `forwardRef(() => undefined)`
if (!metatype) {
throw new InvalidModuleException(scope);
throw new UndefinedForwardRefException(scope);
}
const { type, dynamicMetadata, token } = await this.moduleCompiler.compile(
metatype,
Expand Down
11 changes: 10 additions & 1 deletion packages/core/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import { NestContainer } from './injector/container';
import { InstanceWrapper } from './injector/instance-wrapper';
import { Module } from './injector/module';
import { MetadataScanner } from './metadata-scanner';
import { InvalidModuleException } from './errors/exceptions/invalid-module.exception';
import { UndefinedModuleException } from './errors/exceptions/undefined-module.exception';

interface ApplicationProviderWrapper {
moduleKey: string;
Expand Down Expand Up @@ -90,7 +92,14 @@ export class DependenciesScanner {
...((module as DynamicModule).imports || []),
];

for (const innerModule of modules) {
for (const [index, innerModule] of modules.entries()) {
// In case of a circular dependency (ES module system), JavaScript will resolve the type to `undefined`.
if (innerModule === undefined) {
throw new UndefinedModuleException(module, index, scope);
}
if (!innerModule) {
throw new InvalidModuleException(module, index, scope);
}
if (ctxRegistry.includes(innerModule)) {
continue;
}
Expand Down
Loading

0 comments on commit 64df4a9

Please sign in to comment.