diff --git a/modules/angular2/src/change_detection/parser/parser.ts b/modules/angular2/src/change_detection/parser/parser.ts index 7b1519df3b..debce8186c 100644 --- a/modules/angular2/src/change_detection/parser/parser.ts +++ b/modules/angular2/src/change_detection/parser/parser.ts @@ -65,18 +65,21 @@ export class Parser { } parseAction(input: string, location: any): ASTWithSource { + this._checkNoInterpolation(input, location); var tokens = this._lexer.tokenize(input); var ast = new _ParseAST(input, location, tokens, this._reflector, true).parseChain(); return new ASTWithSource(ast, input, location); } parseBinding(input: string, location: any): ASTWithSource { + this._checkNoInterpolation(input, location); var tokens = this._lexer.tokenize(input); var ast = new _ParseAST(input, location, tokens, this._reflector, false).parseChain(); return new ASTWithSource(ast, input, location); } parseSimpleBinding(input: string, location: string): ASTWithSource { + this._checkNoInterpolation(input, location); var tokens = this._lexer.tokenize(input); var ast = new _ParseAST(input, location, tokens, this._reflector, false).parseSimpleBinding(); return new ASTWithSource(ast, input, location); @@ -105,12 +108,9 @@ export class Parser { var ast = new _ParseAST(input, location, tokens, this._reflector, false).parseChain(); expressions.push(ast); } else { - var errLocation = ''; - for (var j = 0; j < i; j++) { - errLocation += j % 2 === 0 ? parts[j] : `{{${parts[j]}}}`; - } throw new ParseException('Blank expressions are not allowed in interpolated strings', input, - `at column ${errLocation.length} in`, location); + `at column ${this._findInterpolationErrorColumn(parts, i)} in`, + location); } } return new ASTWithSource(new Interpolation(strings, expressions), input, location); @@ -119,6 +119,24 @@ export class Parser { wrapLiteralPrimitive(input: string, location: any): ASTWithSource { return new ASTWithSource(new LiteralPrimitive(input), input, location); } + + private _checkNoInterpolation(input: string, location: any): void { + var parts = StringWrapper.split(input, INTERPOLATION_REGEXP); + if (parts.length > 1) { + throw new ParseException('Got interpolation ({{}}) where expression was expected', input, + `at column ${this._findInterpolationErrorColumn(parts, 1)} in`, + location); + } + } + + private _findInterpolationErrorColumn(parts: string[], partInErrIdx: number): number { + var errLocation = ''; + for (var j = 0; j < partInErrIdx; j++) { + errLocation += j % 2 === 0 ? parts[j] : `{{${parts[j]}}}`; + } + + return errLocation.length; + } } export class _ParseAST { diff --git a/modules/angular2/test/change_detection/parser/parser_spec.ts b/modules/angular2/test/change_detection/parser/parser_spec.ts index 4c21cde143..cf11b55bb5 100644 --- a/modules/angular2/test/change_detection/parser/parser_spec.ts +++ b/modules/angular2/test/change_detection/parser/parser_spec.ts @@ -204,6 +204,11 @@ export function main() { it('should store the passed-in location', () => { expect(parseAction('someExpr', 'location').location).toBe('location'); }); + + it("should throw when encountering interpolation", () => { + expectActionError("{{a()}}") + .toThrowErrorWith('Got interpolation ({{}}) where expression was expected'); + }); }); describe("general error handling", () => { @@ -256,6 +261,11 @@ export function main() { it('should throw on assignment', () => { expect(() => parseBinding("a=2")).toThrowError(new RegExp("contain assignments")); }); + + it('should throw when encountering interpolation', () => { + expectBindingError("{{a.b}}") + .toThrowErrorWith('Got interpolation ({{}}) where expression was expected'); + }); }); describe('parseTemplateBindings', () => { @@ -398,12 +408,12 @@ export function main() { it("should throw on empty interpolation expressions", () => { expect(() => parseInterpolation("{{}}")) - .toThrowError(new RegExp( - "Parser Error: Blank expressions are not allowed in interpolated strings")); + .toThrowErrorWith( + "Parser Error: Blank expressions are not allowed in interpolated strings"); expect(() => parseInterpolation("foo {{ }}")) - .toThrowError(new RegExp( - "Parser Error: Blank expressions are not allowed in interpolated strings")); + .toThrowErrorWith( + "Parser Error: Blank expressions are not allowed in interpolated strings"); }); }); @@ -420,8 +430,13 @@ export function main() { it("should throw when the given expression is not just a field name", () => { expect(() => parseSimpleBinding("name + 1")) - .toThrowError(new RegExp( - 'Simple binding expression can only contain field access and constants')); + .toThrowErrorWith( + 'Simple binding expression can only contain field access and constants'); + }); + + it('should throw when encountering interpolation', () => { + expect(() => parseSimpleBinding('{{exp}}')) + .toThrowErrorWith('Got interpolation ({{}}) where expression was expected'); }); }); diff --git a/modules/angular2/test/render/dom/compiler/property_binding_parser_spec.ts b/modules/angular2/test/render/dom/compiler/property_binding_parser_spec.ts index 03b38d29e2..6f6b6c8272 100644 --- a/modules/angular2/test/render/dom/compiler/property_binding_parser_spec.ts +++ b/modules/angular2/test/render/dom/compiler/property_binding_parser_spec.ts @@ -49,6 +49,12 @@ export function main() { expect(process(el('
'))[0]).toBe(null); }); + it('should throw when [] binding contains interpolation', () => { + expect(() => process(el('
'))[0]) + .toThrowErrorWith( + 'Got interpolation ({{}}) where expression was expected at column 4 in [a + {{b()}}] in someComponent'); + }); + it('should detect bind- syntax', () => { var results = process(el('
')); expect(results[0].propertyBindings.get('a').source).toEqual('b'); @@ -157,6 +163,12 @@ export function main() { expect(eventBinding.fullName).toEqual('click'); }); + it('should throw when () action contains interpolation', () => { + expect(() => process(el('
'))[0]) + .toThrowErrorWith( + 'Got interpolation ({{}}) where expression was expected at column 0 in [{{b()}}] in someComponent'); + }); + it('should detect on- syntax', () => { var results = process(el('
')); var eventBinding = results[0].eventBindings[0];