fix(compiler): disable non-components as an entry component (#14335)
PR Close #14335
This commit is contained in:
parent
56b3b3cbed
commit
44bb337acc
|
@ -930,7 +930,7 @@ export class CompileMetadataResolver {
|
||||||
|
|
||||||
extractIdentifiers(provider.useValue, collectedIdentifiers);
|
extractIdentifiers(provider.useValue, collectedIdentifiers);
|
||||||
collectedIdentifiers.forEach((identifier) => {
|
collectedIdentifiers.forEach((identifier) => {
|
||||||
const entry = this._getEntryComponentMetadata(identifier.reference);
|
const entry = this._getEntryComponentMetadata(identifier.reference, false);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
components.push(entry);
|
components.push(entry);
|
||||||
}
|
}
|
||||||
|
@ -938,17 +938,22 @@ export class CompileMetadataResolver {
|
||||||
return components;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getEntryComponentMetadata(dirType: any): cpl.CompileEntryComponentMetadata {
|
private _getEntryComponentMetadata(dirType: any, throwIfNotFound = true):
|
||||||
|
cpl.CompileEntryComponentMetadata {
|
||||||
const dirMeta = this.getNonNormalizedDirectiveMetadata(dirType);
|
const dirMeta = this.getNonNormalizedDirectiveMetadata(dirType);
|
||||||
if (dirMeta) {
|
if (dirMeta && dirMeta.metadata.isComponent) {
|
||||||
return {componentType: dirType, componentFactory: dirMeta.metadata.componentFactory};
|
return {componentType: dirType, componentFactory: dirMeta.metadata.componentFactory};
|
||||||
} else {
|
} else {
|
||||||
const dirSummary =
|
const dirSummary =
|
||||||
<cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive);
|
<cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive);
|
||||||
if (dirSummary) {
|
if (dirSummary && dirSummary.isComponent) {
|
||||||
return {componentType: dirType, componentFactory: dirSummary.componentFactory};
|
return {componentType: dirType, componentFactory: dirSummary.componentFactory};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (throwIfNotFound) {
|
||||||
|
throw syntaxError(`${dirType.name} cannot be used as an entry component.`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getProviderMetadata(provider: cpl.ProviderMeta): cpl.CompileProviderMetadata {
|
getProviderMetadata(provider: cpl.ProviderMeta): cpl.CompileProviderMetadata {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {TEST_COMPILER_PROVIDERS} from '@angular/compiler/testing/test_bindings';
|
import {TEST_COMPILER_PROVIDERS} from '@angular/compiler/testing/test_bindings';
|
||||||
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, Component, DoCheck, Injectable, NgModule, OnChanges, OnDestroy, OnInit, Pipe, SimpleChanges, ViewEncapsulation} from '@angular/core';
|
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, Component, Directive, DoCheck, Injectable, NgModule, OnChanges, OnDestroy, OnInit, Pipe, 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 {TestBed, async, inject} from '@angular/core/testing';
|
import {TestBed, async, inject} from '@angular/core/testing';
|
||||||
|
|
||||||
|
@ -312,6 +312,61 @@ export function main() {
|
||||||
expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(Module5, true))
|
expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(Module5, true))
|
||||||
.toThrowError(`['{', '}}'] contains unusable interpolation symbol.`);
|
.toThrowError(`['{', '}}'] contains unusable interpolation symbol.`);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it(`should throw an error when a Pipe is added to module's bootstrap list`,
|
||||||
|
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
|
||||||
|
|
||||||
|
@Pipe({name: 'pipe'})
|
||||||
|
class MyPipe {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({declarations: [MyPipe], bootstrap: [MyPipe]})
|
||||||
|
class ModuleWithPipeInBootstrap {
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(() => resolver.getNgModuleMetadata(ModuleWithPipeInBootstrap))
|
||||||
|
.toThrowError(`MyPipe cannot be used as an entry component.`);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it(`should throw an error when a Service is added to module's bootstrap list`,
|
||||||
|
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
|
||||||
|
|
||||||
|
@NgModule({declarations: [], bootstrap: [SimpleService]})
|
||||||
|
class ModuleWithServiceInBootstrap {
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(() => resolver.getNgModuleMetadata(ModuleWithServiceInBootstrap))
|
||||||
|
.toThrowError(`SimpleService cannot be used as an entry component.`);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it(`should throw an error when a Directive is added to module's bootstrap list`,
|
||||||
|
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
|
||||||
|
|
||||||
|
@Directive({selector: 'directive'})
|
||||||
|
class MyDirective {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({declarations: [], bootstrap: [MyDirective]})
|
||||||
|
class ModuleWithDirectiveInBootstrap {
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(() => resolver.getNgModuleMetadata(ModuleWithDirectiveInBootstrap))
|
||||||
|
.toThrowError(`MyDirective cannot be used as an entry component.`);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it(`should not throw an error when a Component is added to module's bootstrap list`,
|
||||||
|
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
|
||||||
|
|
||||||
|
@Component({template: ''})
|
||||||
|
class MyComp {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({declarations: [MyComp], bootstrap: [MyComp]})
|
||||||
|
class ModuleWithComponentInBootstrap {
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(() => resolver.getNgModuleMetadata(ModuleWithComponentInBootstrap)).not.toThrow();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should dedupe declarations in NgModule',
|
it('should dedupe declarations in NgModule',
|
||||||
|
|
|
@ -155,13 +155,11 @@ export function main() {
|
||||||
const logger = new MockConsole();
|
const logger = new MockConsole();
|
||||||
const errorHandler = new ErrorHandler(false);
|
const errorHandler = new ErrorHandler(false);
|
||||||
errorHandler._console = logger as any;
|
errorHandler._console = logger as any;
|
||||||
bootstrap(HelloRootDirectiveIsNotCmp, [
|
expect(
|
||||||
{provide: ErrorHandler, useValue: errorHandler}
|
() => bootstrap(
|
||||||
]).catch((e) => {
|
HelloRootDirectiveIsNotCmp, [{provide: ErrorHandler, useValue: errorHandler}]))
|
||||||
expect(e.message).toBe(
|
.toThrowError(`HelloRootDirectiveIsNotCmp cannot be used as an entry component.`);
|
||||||
`Could not compile '${stringify(HelloRootDirectiveIsNotCmp)}' because it is not a component.`);
|
|
||||||
done.done();
|
done.done();
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should throw if no element is found',
|
it('should throw if no element is found',
|
||||||
|
|
Loading…
Reference in New Issue