fix(core): only warn and auto declare undeclared `entryComponents`.

This is needed to support existing applications.
After final these warnings will become errors.

Closes #10316
This commit is contained in:
Tobias Bosch 2016-07-27 01:45:20 -07:00
parent 69e72c0786
commit e44e8668ea
3 changed files with 51 additions and 22 deletions

View File

@ -351,17 +351,23 @@ export class CompileMetadataResolver {
}
});
moduleMeta.declaredDirectives.forEach((dirMeta) => {
dirMeta.entryComponents.forEach((entryComponent) => {
if (!moduleMeta.transitiveModule.directivesSet.has(entryComponent.runtime)) {
throw new BaseException(
`Component ${stringify(dirMeta.type.runtime)} in NgModule ${stringify(moduleMeta.type.runtime)} uses ${stringify(entryComponent.runtime)} via "entryComponents" but it was neither declared nor imported into the module!`);
dirMeta.entryComponents.forEach((entryComponentType) => {
if (!moduleMeta.transitiveModule.directivesSet.has(entryComponentType.runtime)) {
this._addDirectiveToModule(
this.getDirectiveMetadata(entryComponentType.runtime), moduleMeta.type.runtime,
moduleMeta.transitiveModule, moduleMeta.declaredDirectives);
this._console.warn(
`Component ${stringify(dirMeta.type.runtime)} in NgModule ${stringify(moduleMeta.type.runtime)} uses ${stringify(entryComponentType.runtime)} via "entryComponents" but it was neither declared nor imported into the module! This warning will become an error after final.`);
}
});
});
moduleMeta.entryComponents.forEach((entryComponentType) => {
if (!moduleMeta.transitiveModule.directivesSet.has(entryComponentType.runtime)) {
throw new BaseException(
`NgModule ${stringify(moduleMeta.type.runtime)} uses ${stringify(entryComponentType.runtime)} via "entryComponents" but it was neither declared nor imported!`);
this._addDirectiveToModule(
this.getDirectiveMetadata(entryComponentType.runtime), moduleMeta.type.runtime,
moduleMeta.transitiveModule, moduleMeta.declaredDirectives);
this._console.warn(
`NgModule ${stringify(moduleMeta.type.runtime)} uses ${stringify(entryComponentType.runtime)} via "entryComponents" but it was neither declared nor imported! This warning will become an error after final.`);
}
});
}

View File

@ -7,20 +7,33 @@
*/
import {AsyncTestCompleter, beforeEach, ddescribe, xdescribe, describe, expect, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder, configureModule} from '@angular/core/testing';
import {TestComponentBuilder, configureModule, configureCompiler} from '@angular/core/testing';
import {Component, ComponentFactoryResolver, NoComponentFactoryError, forwardRef, ANALYZE_FOR_ENTRY_COMPONENTS, ViewMetadata} from '@angular/core';
import {stringify} from '../../src/facade/lang';
import {Console} from '../../src/console';
export function main() {
describe('jit', () => { declareTests({useJit: true}); });
describe('no jit', () => { declareTests({useJit: false}); });
}
class DummyConsole implements Console {
public warnings: string[] = [];
log(message: string) {}
warn(message: string) { this.warnings.push(message); }
}
function declareTests({useJit}: {useJit: boolean}) {
describe('@Component.entryComponents', function() {
beforeEach(() => { configureModule({declarations: [MainComp, ChildComp, NestedChildComp]}); });
var console: DummyConsole;
beforeEach(() => {
console = new DummyConsole();
configureCompiler({useJit: useJit, providers: [{provide: Console, useValue: console}]});
configureModule({declarations: [MainComp, ChildComp, NestedChildComp]});
});
it('should error if the component was not declared nor imported by the module',
it('should warn and auto declare if the component was not declared nor imported by the module',
inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
@Component({selector: 'child', template: ''})
@ -31,9 +44,14 @@ function declareTests({useJit}: {useJit: boolean}) {
class SomeComp {
}
expect(() => tcb.createSync(SomeComp))
.toThrowError(
`Component ${stringify(SomeComp)} in NgModule DynamicTestModule uses ${stringify(ChildComp)} via "entryComponents" but it was neither declared nor imported into the module!`);
const compFixture = tcb.createSync(SomeComp);
const cf = compFixture.componentRef.injector.get(ComponentFactoryResolver)
.resolveComponentFactory(ChildComp);
expect(cf.componentType).toBe(ChildComp);
expect(console.warnings).toEqual([
`Component ${stringify(SomeComp)} in NgModule DynamicTestModule uses ${stringify(ChildComp)} via "entryComponents" but it was neither declared nor imported into the module! This warning will become an error after final.`
]);
}));

View File

@ -164,16 +164,6 @@ function declareTests({useJit}: {useJit: boolean}) {
`Can't export pipe ${stringify(SomePipe)} from ${stringify(SomeModule)} as it was neither declared nor imported!`);
});
it('should error when using an entryComponent that was neither declared nor imported', () => {
@NgModule({entryComponents: [SomeComp]})
class SomeModule {
}
expect(() => createModule(SomeModule))
.toThrowError(
`NgModule ${stringify(SomeModule)} uses ${stringify(SomeComp)} via "entryComponents" but it was neither declared nor imported!`);
});
it('should error if a directive is declared in more than 1 module', () => {
@NgModule({declarations: [SomeDirective]})
class Module1 {
@ -281,6 +271,21 @@ function declareTests({useJit}: {useJit: boolean}) {
.toBe(SomeComp);
});
it('should warn and auto declare when using an entryComponent that was neither declared nor imported',
() => {
@NgModule({entryComponents: [SomeComp]})
class SomeModule {
}
const ngModule = createModule(SomeModule);
expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp).componentType)
.toBe(SomeComp);
expect(console.warnings).toEqual([
`NgModule ${stringify(SomeModule)} uses ${stringify(SomeComp)} via "entryComponents" but it was neither declared nor imported! This warning will become an error after final.`
]);
});
it('should entryComponents ComponentFactories via ANALYZE_FOR_ENTRY_COMPONENTS', () => {
@NgModule({
declarations: [SomeComp],