From 4639f449cf8957aea53d399e5261d1b228e6b724 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Tue, 13 Oct 2015 18:55:46 -0700 Subject: [PATCH] feat(Parser): associate pipes right to left closes #4605 BREAKING CHANGE: Before: `1 + 1 | pipe:a | pipe:b` was parsed as `(1 + 1) | pipe:(a | pipe:b)` After: `1 + 1 | pipe:a | pipe:b` is parsed as `((1 + 1) | pipe:a) | pipe:b` Closes #4716 --- .../src/core/change_detection/parser/parser.ts | 18 +++++++++--------- .../change_detection/change_detector_config.ts | 1 + .../change_detection/change_detector_spec.ts | 8 ++++++++ .../change_detection/parser/parser_spec.ts | 12 ++---------- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/modules/angular2/src/core/change_detection/parser/parser.ts b/modules/angular2/src/core/change_detection/parser/parser.ts index 3503cfff04..fe7550e168 100644 --- a/modules/angular2/src/core/change_detection/parser/parser.ts +++ b/modules/angular2/src/core/change_detection/parser/parser.ts @@ -216,6 +216,14 @@ export class _ParseAST { return n.toString(); } + parseSimpleBinding(): AST { + var ast = this.parseChain(); + if (!SimpleExpressionChecker.check(ast)) { + this.error(`Simple binding expression can only contain field access and constants'`); + } + return ast; + } + parseChain(): AST { var exprs = []; while (this.index < this.tokens.length) { @@ -237,14 +245,6 @@ export class _ParseAST { return new Chain(exprs); } - parseSimpleBinding(): AST { - var ast = this.parseChain(); - if (!SimpleExpressionChecker.check(ast)) { - this.error(`Simple binding expression can only contain field access and constants'`); - } - return ast; - } - parsePipe(): AST { var result = this.parseExpression(); if (this.optionalOperator("|")) { @@ -256,7 +256,7 @@ export class _ParseAST { var name = this.expectIdentifierOrKeyword(); var args = []; while (this.optionalCharacter($COLON)) { - args.push(this.parsePipe()); + args.push(this.parseExpression()); } result = new BindingPipe(result, name, args); } while (this.optionalOperator("|")); diff --git a/modules/angular2/test/core/change_detection/change_detector_config.ts b/modules/angular2/test/core/change_detection/change_detector_config.ts index a69c69dd42..271ace03f7 100644 --- a/modules/angular2/test/core/change_detection/change_detector_config.ts +++ b/modules/angular2/test/core/change_detection/change_detector_config.ts @@ -408,6 +408,7 @@ var _availableDefinitions = [ 'name | pipe', '(name | pipe).length', "name | pipe:'one':address.city", + "name | pipe:'a':'b' | pipe:0:1:2", 'value', 'a', 'address.city', diff --git a/modules/angular2/test/core/change_detection/change_detector_spec.ts b/modules/angular2/test/core/change_detection/change_detector_spec.ts index e594fe84dd..a63c4fd889 100644 --- a/modules/angular2/test/core/change_detection/change_detector_spec.ts +++ b/modules/angular2/test/core/change_detection/change_detector_spec.ts @@ -354,6 +354,14 @@ export function main() { expect(val.dispatcher.loggedValues).toEqual(['value one two default']); }); + it('should associate pipes right-to-left', () => { + var registry = new FakePipes('pipe', () => new MultiArgPipe()); + var person = new Person('value'); + var val = _createChangeDetector("name | pipe:'a':'b' | pipe:0:1:2", person, registry); + val.changeDetector.detectChanges(); + expect(val.dispatcher.loggedValues).toEqual(['value a b default 0 1 2']); + }); + it('should not reevaluate pure pipes unless its context or arg changes', () => { var pipe = new CountingPipe(); var registry = new FakePipes('pipe', () => pipe, {pure: true}); diff --git a/modules/angular2/test/core/change_detection/parser/parser_spec.ts b/modules/angular2/test/core/change_detection/parser/parser_spec.ts index c3ed640874..dd4577aa59 100644 --- a/modules/angular2/test/core/change_detection/parser/parser_spec.ts +++ b/modules/angular2/test/core/change_detection/parser/parser_spec.ts @@ -6,14 +6,6 @@ import {Unparser} from './unparser'; import {Lexer} from 'angular2/src/core/change_detection/parser/lexer'; import {BindingPipe, LiteralPrimitive, AST} from 'angular2/src/core/change_detection/parser/ast'; -class TestData { - constructor(public a?: any, public b?: any, public fnReturnValue?: any) {} - - fn() { return this.fnReturnValue; } - - add(a, b) { return a + b; } -} - export function main() { function createParser() { return new Parser(new Lexer(), reflector); } @@ -229,8 +221,8 @@ export function main() { checkBinding('a[b] | c', '(a[b] | c)'); checkBinding('a?.b | c', '(a?.b | c)'); checkBinding('true | a', '(true | a)'); - checkBinding('a | b:c | d', '(a | b:(c | d))'); - checkBinding('(a | b:c) | d', '((a | b:c) | d)'); + checkBinding('a | b:c | d', '((a | b:c) | d)'); + checkBinding('a | b:(c | d)', '(a | b:(c | d))'); }); it('should only allow identifier or keyword as formatter names', () => {