Skip to content

Commit

Permalink
fix(compiler): throw an error for invalid provider
Browse files Browse the repository at this point in the history
  • Loading branch information
Dzmitry Shylovich authored and Dzmitry Shylovich committed Dec 17, 2016
1 parent 0e3981a commit 3a1649e
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
19 changes: 17 additions & 2 deletions modules/@angular/compiler/src/metadata_resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {DirectiveNormalizer} from './directive_normalizer';
import {DirectiveResolver} from './directive_resolver';
import {ListWrapper, StringMapWrapper} from './facade/collection';
import {isBlank, isPresent, stringify} from './facade/lang';
import {Identifiers, createIdentifierToken, resolveIdentifier} from './identifiers';
import {Identifiers, resolveIdentifier} from './identifiers';
import {CompilerInjectable} from './injectable';
import {hasLifecycleHook} from './lifecycle_reflector';
import {NgModuleResolver} from './ng_module_resolver';
Expand All @@ -24,7 +24,7 @@ import {ComponentStillLoadingError, LIFECYCLE_HOOKS_VALUES, ReflectorReader, ref
import {ElementSchemaRegistry} from './schema/element_schema_registry';
import {SummaryResolver} from './summary_resolver';
import {getUrlScheme} from './url_resolver';
import {MODULE_SUFFIX, SyncAsyncResult, SyntaxError, ValueTransformer, visitValue} from './util';
import {MODULE_SUFFIX, SyntaxError, ValueTransformer, visitValue} from './util';

export type ErrorCollector = (error: any, type?: any) => void;
export const ERROR_COLLECTOR_TOKEN = new OpaqueToken('ErrorCollector');
Expand Down Expand Up @@ -779,6 +779,7 @@ export class CompileMetadataResolver {
provider = resolveForwardRef(provider);
let providerMeta: cpl.ProviderMeta;
if (provider && typeof provider == 'object' && provider.hasOwnProperty('provide')) {
this._validate(provider);
providerMeta = new cpl.ProviderMeta(provider.provide, provider);
} else if (isValidType(provider)) {
providerMeta = new cpl.ProviderMeta(provider, {useClass: provider});
Expand Down Expand Up @@ -812,6 +813,20 @@ export class CompileMetadataResolver {
return compileProviders;
}

private _validate(provider: any): void {
if (provider.hasOwnProperty('useClass') && provider.useClass == null) {
throw new Error(`
Invalid provider for ${stringifyType(provider.token)}. useClass cannot be null or undefined, got: ${provider.useClass}.
Usually it happens when:
1. Missing import statement.
2. There's a circular dependency (might be caused by using index.ts files).
3. Class was declared after it was used:
const provider = {provide: SomeClass, useClass: SomeClass};
class SomeClass {}`);
}
}

private _getEntryComponentsFromProvider(provider: cpl.ProviderMeta, type?: any):
cpl.CompileIdentifierMetadata[] {
const components: cpl.CompileIdentifierMetadata[] = [];
Expand Down
10 changes: 10 additions & 0 deletions modules/@angular/compiler/test/metadata_resolver_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,16 @@ export function main() {
SyntaxError, `Can't resolve all parameters for NonAnnotatedService: (?).`);
}));

it('should throw with descriptive error message when encounter invalid provider',
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
@NgModule({providers: [{provide: SimpleService, useClass: undefined}]})
class SomeModule {
}

expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, true))
.toThrowError(/Invalid provider for SimpleService. useClass cannot be null or undefined, got: undefined.`/);
}));

it('should throw with descriptive error message when one of providers is not present',
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
@NgModule({declarations: [MyBrokenComp3]})
Expand Down

0 comments on commit 3a1649e

Please sign in to comment.