fix(Compiler): add an error when a directive is null or undefined
fixes #1908
This commit is contained in:
parent
666336be1a
commit
25cd6e4321
|
@ -92,7 +92,7 @@ export class Compiler {
|
||||||
// Used for bootstrapping.
|
// Used for bootstrapping.
|
||||||
compileInHost(componentTypeOrBinding:any):Promise<ProtoViewRef> {
|
compileInHost(componentTypeOrBinding:any):Promise<ProtoViewRef> {
|
||||||
var componentBinding = this._bindDirective(componentTypeOrBinding);
|
var componentBinding = this._bindDirective(componentTypeOrBinding);
|
||||||
this._assertTypeIsComponent(componentBinding);
|
Compiler._assertTypeIsComponent(componentBinding);
|
||||||
|
|
||||||
var directiveMetadata = componentBinding.metadata;
|
var directiveMetadata = componentBinding.metadata;
|
||||||
return this._render.compileHost(directiveMetadata).then( (hostRenderPv) => {
|
return this._render.compileHost(directiveMetadata).then( (hostRenderPv) => {
|
||||||
|
@ -104,7 +104,7 @@ export class Compiler {
|
||||||
|
|
||||||
compile(component: Type):Promise<ProtoViewRef> {
|
compile(component: Type):Promise<ProtoViewRef> {
|
||||||
var componentBinding = this._bindDirective(component);
|
var componentBinding = this._bindDirective(component);
|
||||||
this._assertTypeIsComponent(componentBinding);
|
Compiler._assertTypeIsComponent(componentBinding);
|
||||||
var protoView = this._compile(componentBinding);
|
var protoView = this._compile(componentBinding);
|
||||||
var pvPromise = PromiseWrapper.isPromise(protoView) ? protoView : PromiseWrapper.resolve(protoView);
|
var pvPromise = PromiseWrapper.isPromise(protoView) ? protoView : PromiseWrapper.resolve(protoView);
|
||||||
return pvPromise.then( (appProtoView) => {
|
return pvPromise.then( (appProtoView) => {
|
||||||
|
@ -134,13 +134,21 @@ export class Compiler {
|
||||||
if (isBlank(template)) {
|
if (isBlank(template)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var directives = ListWrapper.map(
|
|
||||||
this._flattenDirectives(template),
|
var directives = this._flattenDirectives(template);
|
||||||
(directive) => this._bindDirective(directive)
|
|
||||||
);
|
for (var i = 0; i < directives.length; i++) {
|
||||||
var renderTemplate = this._buildRenderTemplate(component, template, directives);
|
if (!Compiler._isValidDirective(directives[i])) {
|
||||||
|
throw new BaseException(
|
||||||
|
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var boundDirectives = ListWrapper.map(directives, (directive) => this._bindDirective(directive));
|
||||||
|
|
||||||
|
var renderTemplate = this._buildRenderTemplate(component, template, boundDirectives);
|
||||||
pvPromise = this._render.compile(renderTemplate).then( (renderPv) => {
|
pvPromise = this._render.compile(renderTemplate).then( (renderPv) => {
|
||||||
return this._compileNestedProtoViews(componentBinding, renderPv, directives);
|
return this._compileNestedProtoViews(componentBinding, renderPv, boundDirectives);
|
||||||
});
|
});
|
||||||
|
|
||||||
MapWrapper.set(this._compiling, component, pvPromise);
|
MapWrapper.set(this._compiling, component, pvPromise);
|
||||||
|
@ -227,7 +235,7 @@ export class Compiler {
|
||||||
return directives;
|
return directives;
|
||||||
}
|
}
|
||||||
|
|
||||||
_flattenList(tree:List<any>, out:List<Type>):void {
|
_flattenList(tree:List<any>, out:List<any> /*<Type|Binding>*/):void {
|
||||||
for (var i = 0; i < tree.length; i++) {
|
for (var i = 0; i < tree.length; i++) {
|
||||||
var item = tree[i];
|
var item = tree[i];
|
||||||
if (ListWrapper.isList(item)) {
|
if (ListWrapper.isList(item)) {
|
||||||
|
@ -238,7 +246,11 @@ export class Compiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_assertTypeIsComponent(directiveBinding:DirectiveBinding):void {
|
static _isValidDirective(value: any): boolean {
|
||||||
|
return isPresent(value) && (value instanceof Type || value instanceof Binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _assertTypeIsComponent(directiveBinding:DirectiveBinding):void {
|
||||||
if (directiveBinding.metadata.type !== renderApi.DirectiveMetadata.COMPONENT_TYPE) {
|
if (directiveBinding.metadata.type !== renderApi.DirectiveMetadata.COMPONENT_TYPE) {
|
||||||
throw new BaseException(`Could not load '${stringify(directiveBinding.key.token)}' because it is not a component.`);
|
throw new BaseException(`Could not load '${stringify(directiveBinding.key.token)}' because it is not a component.`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
expect,
|
expect,
|
||||||
iit,
|
iit,
|
||||||
inject,
|
inject,
|
||||||
|
IS_DARTIUM,
|
||||||
beforeEachBindings,
|
beforeEachBindings,
|
||||||
it,
|
it,
|
||||||
xit
|
xit
|
||||||
|
@ -823,6 +824,57 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("error handling", () => {
|
describe("error handling", () => {
|
||||||
|
it('should report a meaningful error when a directive is missing annotation',
|
||||||
|
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||||
|
|
||||||
|
tb.overrideView(MyComp, new View({
|
||||||
|
directives: [SomeDirectiveMissingAnnotation]
|
||||||
|
}));
|
||||||
|
|
||||||
|
PromiseWrapper.catchError(
|
||||||
|
tb.createView(MyComp, {context: ctx}),
|
||||||
|
(e) => {
|
||||||
|
expect(e.message).toEqual('No Directive annotation found on SomeDirectiveMissingAnnotation');
|
||||||
|
async.done();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should report a meaningful error when a directive is null',
|
||||||
|
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||||
|
|
||||||
|
tb.overrideView(MyComp, new View({
|
||||||
|
directives: [[null]]
|
||||||
|
}));
|
||||||
|
|
||||||
|
PromiseWrapper.catchError(
|
||||||
|
tb.createView(MyComp, {context: ctx}),
|
||||||
|
(e) => {
|
||||||
|
expect(e.message).toEqual("Unexpected directive value 'null' on the View of component 'MyComp'");
|
||||||
|
async.done();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (!IS_DARTIUM) {
|
||||||
|
it('should report a meaningful error when a directive is undefined',
|
||||||
|
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||||
|
|
||||||
|
var undefinedValue;
|
||||||
|
|
||||||
|
tb.overrideView(MyComp, new View({
|
||||||
|
directives: [undefinedValue]
|
||||||
|
}));
|
||||||
|
|
||||||
|
PromiseWrapper.catchError(
|
||||||
|
tb.createView(MyComp, {context: ctx}),
|
||||||
|
(e) => {
|
||||||
|
expect(e.message).toEqual("Unexpected directive value 'undefined' on the View of component 'MyComp'");
|
||||||
|
async.done();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
it('should specify a location of an error that happened during change detection (text)',
|
it('should specify a location of an error that happened during change detection (text)',
|
||||||
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||||
|
@ -1110,7 +1162,6 @@ class MyComp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'component-with-pipes',
|
selector: 'component-with-pipes',
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -1159,6 +1210,8 @@ class ChildCompUsingService {
|
||||||
})
|
})
|
||||||
class SomeDirective { }
|
class SomeDirective { }
|
||||||
|
|
||||||
|
class SomeDirectiveMissingAnnotation { }
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cmp-with-parent'
|
selector: 'cmp-with-parent'
|
||||||
})
|
})
|
||||||
|
|
|
@ -121,6 +121,11 @@ export function main() {
|
||||||
reflector.registerType(TestObj, {"annotations" : [1,2]});
|
reflector.registerType(TestObj, {"annotations" : [1,2]});
|
||||||
expect(reflector.annotations(TestObj)).toEqual([1,2]);
|
expect(reflector.annotations(TestObj)).toEqual([1,2]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should work for a clas without annotations", () => {
|
||||||
|
var p = reflector.annotations(ClassWithoutAnnotations);
|
||||||
|
expect(p).toEqual([]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("getter", () => {
|
describe("getter", () => {
|
||||||
|
|
Loading…
Reference in New Issue