fix(compiler): properly report unresolved dependencies

Fixes #9332

Closes #9341
This commit is contained in:
Pawel Kozlowski 2016-06-18 18:42:34 +02:00
parent 297f0fd2c3
commit fdf6bc18dd
2 changed files with 41 additions and 28 deletions

View File

@ -164,21 +164,23 @@ export class CompileMetadataResolver {
} }
} }
getTypeMetadata(type: Type, moduleUrl: string): cpl.CompileTypeMetadata { getTypeMetadata(type: Type, moduleUrl: string, dependencies: any[] = null):
cpl.CompileTypeMetadata {
return new cpl.CompileTypeMetadata({ return new cpl.CompileTypeMetadata({
name: this.sanitizeTokenName(type), name: this.sanitizeTokenName(type),
moduleUrl: moduleUrl, moduleUrl: moduleUrl,
runtime: type, runtime: type,
diDeps: this.getDependenciesMetadata(type, null) diDeps: this.getDependenciesMetadata(type, dependencies)
}); });
} }
getFactoryMetadata(factory: Function, moduleUrl: string): cpl.CompileFactoryMetadata { getFactoryMetadata(factory: Function, moduleUrl: string, dependencies: any[] = null):
cpl.CompileFactoryMetadata {
return new cpl.CompileFactoryMetadata({ return new cpl.CompileFactoryMetadata({
name: this.sanitizeTokenName(factory), name: this.sanitizeTokenName(factory),
moduleUrl: moduleUrl, moduleUrl: moduleUrl,
runtime: factory, runtime: factory,
diDeps: this.getDependenciesMetadata(factory, null) diDeps: this.getDependenciesMetadata(factory, dependencies)
}); });
} }
@ -229,9 +231,6 @@ export class CompileMetadataResolver {
params = []; params = [];
} }
let dependenciesMetadata: cpl.CompileDiDependencyMetadata[] = params.map((param) => { let dependenciesMetadata: cpl.CompileDiDependencyMetadata[] = params.map((param) => {
if (isBlank(param)) {
return null;
}
let isAttribute = false; let isAttribute = false;
let isHost = false; let isHost = false;
let isSelf = false; let isSelf = false;
@ -330,21 +329,25 @@ export class CompileMetadataResolver {
} }
getProviderMetadata(provider: Provider): cpl.CompileProviderMetadata { getProviderMetadata(provider: Provider): cpl.CompileProviderMetadata {
var compileDeps: any /** TODO #9100 */; var compileDeps: cpl.CompileDiDependencyMetadata[];
var compileTypeMetadata: cpl.CompileTypeMetadata = null;
var compileFactoryMetadata: cpl.CompileFactoryMetadata = null;
if (isPresent(provider.useClass)) { if (isPresent(provider.useClass)) {
compileDeps = this.getDependenciesMetadata(provider.useClass, provider.dependencies); compileTypeMetadata = this.getTypeMetadata(
provider.useClass, staticTypeModuleUrl(provider.useClass), provider.dependencies);
compileDeps = compileTypeMetadata.diDeps;
} else if (isPresent(provider.useFactory)) { } else if (isPresent(provider.useFactory)) {
compileDeps = this.getDependenciesMetadata(provider.useFactory, provider.dependencies); compileFactoryMetadata = this.getFactoryMetadata(
provider.useFactory, staticTypeModuleUrl(provider.useFactory), provider.dependencies);
compileDeps = compileFactoryMetadata.diDeps;
} }
return new cpl.CompileProviderMetadata({ return new cpl.CompileProviderMetadata({
token: this.getTokenMetadata(provider.token), token: this.getTokenMetadata(provider.token),
useClass: isPresent(provider.useClass) ? useClass: compileTypeMetadata,
this.getTypeMetadata(provider.useClass, staticTypeModuleUrl(provider.useClass)) :
null,
useValue: convertToCompileValue(provider.useValue), useValue: convertToCompileValue(provider.useValue),
useFactory: isPresent(provider.useFactory) ? useFactory: compileFactoryMetadata,
this.getFactoryMetadata(provider.useFactory, staticTypeModuleUrl(provider.useFactory)) :
null,
useExisting: isPresent(provider.useExisting) ? this.getTokenMetadata(provider.useExisting) : useExisting: isPresent(provider.useExisting) ? this.getTokenMetadata(provider.useExisting) :
null, null,
deps: compileDeps, deps: compileDeps,

View File

@ -1,14 +1,13 @@
import {CompilerConfig} from '@angular/compiler/src/config';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, Component, Directive, DoCheck, Injectable, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation} from '@angular/core';
import {LIFECYCLE_HOOKS_VALUES} from '@angular/core/src/metadata/lifecycle_hooks'; import {LIFECYCLE_HOOKS_VALUES} from '@angular/core/src/metadata/lifecycle_hooks';
import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal'; import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {IS_DART, stringify} from '../src/facade/lang'; import {IS_DART, stringify} from '../src/facade/lang';
import {CompileMetadataResolver} from '../src/metadata_resolver'; import {CompileMetadataResolver} from '../src/metadata_resolver';
import {Component, Directive, ViewEncapsulation, ChangeDetectionStrategy, OnChanges, OnInit, DoCheck, OnDestroy, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked, SimpleChanges,} from '@angular/core';
import {TEST_PROVIDERS} from './test_bindings';
import {CompilerConfig} from '@angular/compiler/src/config';
import {MalformedStylesComponent} from './metadata_resolver_fixture'; import {MalformedStylesComponent} from './metadata_resolver_fixture';
import {TEST_PROVIDERS} from './test_bindings';
export function main() { export function main() {
describe('CompileMetadataResolver', () => { describe('CompileMetadataResolver', () => {
@ -49,18 +48,20 @@ export function main() {
it('should throw when metadata is incorrectly typed', it('should throw when metadata is incorrectly typed',
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
if (!IS_DART) { expect(() => resolver.getDirectiveMetadata(MalformedStylesComponent))
expect(() => resolver.getDirectiveMetadata(MalformedStylesComponent)) .toThrowError(`Expected 'styles' to be an array of strings.`);
.toThrowError(`Expected 'styles' to be an array of strings.`);
}
})); }));
it('should throw with descriptive error message when provider token can not be resolved', it('should throw with descriptive error message when provider token can not be resolved',
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
if (!IS_DART) { expect(() => resolver.getDirectiveMetadata(MyBrokenComp1))
expect(() => resolver.getDirectiveMetadata(MyBrokenComp1)) .toThrowError(`Can't resolve all parameters for MyBrokenComp1: (?).`);
.toThrowError(`Can't resolve all parameters for MyBrokenComp1: (?).`); }));
}
it('should throw with descriptive error message when a param token of a dependency is undefined',
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
expect(() => resolver.getDirectiveMetadata(MyBrokenComp2))
.toThrowError(`Can't resolve all parameters for NonAnnotatedService: (?).`);
})); }));
it('should throw an error when the interpolation config has invalid symbols', it('should throw an error when the interpolation config has invalid symbols',
@ -152,6 +153,15 @@ class MyBrokenComp1 {
constructor(public dependency: any) {} constructor(public dependency: any) {}
} }
class NonAnnotatedService {
constructor(dep: any) {}
}
@Component({selector: 'my-broken-comp', template: '', providers: [NonAnnotatedService]})
class MyBrokenComp2 {
constructor(dependency: NonAnnotatedService) {}
}
@Component({selector: 'someSelector', template: '', interpolation: [' ', ' ']}) @Component({selector: 'someSelector', template: '', interpolation: [' ', ' ']})
class ComponentWithInvalidInterpolation1 { class ComponentWithInvalidInterpolation1 {
} }