From f25c97671a022ef0ef7fa633b97942d43a2ac48f Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Fri, 26 Aug 2016 19:29:53 +0200 Subject: [PATCH] fix(compiler): handle invalid host bindings and events (#11101) --- .../src/template_parser/template_parser.ts | 22 +++++++++++++---- .../template_parser/template_parser_spec.ts | 24 +++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/modules/@angular/compiler/src/template_parser/template_parser.ts b/modules/@angular/compiler/src/template_parser/template_parser.ts index 30e1cf06f7..fe518c87a3 100644 --- a/modules/@angular/compiler/src/template_parser/template_parser.ts +++ b/modules/@angular/compiler/src/template_parser/template_parser.ts @@ -13,7 +13,7 @@ import {CompileDirectiveMetadata, CompilePipeMetadata, CompileTokenMetadata, rem import {AST, ASTWithSource, BindingPipe, EmptyExpr, Interpolation, ParserError, RecursiveAstVisitor, TemplateBinding} from '../expression_parser/ast'; import {Parser} from '../expression_parser/parser'; import {ListWrapper, SetWrapper, StringMapWrapper} from '../facade/collection'; -import {isBlank, isPresent} from '../facade/lang'; +import {isBlank, isPresent, isString} from '../facade/lang'; import {HtmlParser} from '../i18n/html_parser'; import {Identifiers, identifierToken} from '../identifiers'; import * as html from '../ml_parser/ast'; @@ -746,9 +746,15 @@ class TemplateParseVisitor implements html.Visitor { targetPropertyAsts: BoundElementPropertyAst[]) { if (isPresent(hostProps)) { StringMapWrapper.forEach(hostProps, (expression: string, propName: string) => { - const exprAst = this._parseBinding(expression, sourceSpan); - targetPropertyAsts.push( - this._createElementPropertyAst(elementName, propName, exprAst, sourceSpan)); + if (isString(expression)) { + const exprAst = this._parseBinding(expression, sourceSpan); + targetPropertyAsts.push( + this._createElementPropertyAst(elementName, propName, exprAst, sourceSpan)); + } else { + this._reportError( + `Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, + sourceSpan); + } }); } } @@ -758,7 +764,13 @@ class TemplateParseVisitor implements html.Visitor { targetEventAsts: BoundEventAst[]) { if (isPresent(hostListeners)) { StringMapWrapper.forEach(hostListeners, (expression: string, propName: string) => { - this._parseEvent(propName, expression, sourceSpan, [], targetEventAsts); + if (isString(expression)) { + this._parseEvent(propName, expression, sourceSpan, [], targetEventAsts); + } else { + this._reportError( + `Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, + sourceSpan); + } }); } } diff --git a/modules/@angular/compiler/test/template_parser/template_parser_spec.ts b/modules/@angular/compiler/test/template_parser/template_parser_spec.ts index 604af8fe2c..ef0ebaec41 100644 --- a/modules/@angular/compiler/test/template_parser/template_parser_spec.ts +++ b/modules/@angular/compiler/test/template_parser/template_parser_spec.ts @@ -313,6 +313,30 @@ Can't bind to 'invalidProp' since it isn't a known property of 'my-component'. expect(console.warnings.length).toEqual(0); }); + it('should throw descriptive error when a host binding is not a string expression', () => { + var dirA = CompileDirectiveMetadata.create({ + selector: 'broken', + type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'}), + host: {'[class.foo]': null} + }); + + expect(() => { parse('', [dirA]); }) + .toThrowError( + `Template parse errors:\nValue of the host property binding "class.foo" needs to be a string representing an expression but got "null" (object) ("[ERROR ->]"): TestComp@0:0, Directive DirA`); + }); + + it('should throw descriptive error when a host event is not a string expression', () => { + var dirA = CompileDirectiveMetadata.create({ + selector: 'broken', + type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'}), + host: {'(click)': null} + }); + + expect(() => { parse('', [dirA]); }) + .toThrowError( + `Template parse errors:\nValue of the host listener "click" needs to be a string representing an expression but got "null" (object) ("[ERROR ->]"): TestComp@0:0, Directive DirA`); + }); + it('should not issue a warning when an animation property is bound without an expression', () => { humanizeTplAst(parse('
', []));