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
This commit is contained in:
parent
77604b8b18
commit
4639f449cf
|
@ -216,6 +216,14 @@ export class _ParseAST {
|
||||||
return n.toString();
|
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 {
|
parseChain(): AST {
|
||||||
var exprs = [];
|
var exprs = [];
|
||||||
while (this.index < this.tokens.length) {
|
while (this.index < this.tokens.length) {
|
||||||
|
@ -237,14 +245,6 @@ export class _ParseAST {
|
||||||
return new Chain(exprs);
|
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 {
|
parsePipe(): AST {
|
||||||
var result = this.parseExpression();
|
var result = this.parseExpression();
|
||||||
if (this.optionalOperator("|")) {
|
if (this.optionalOperator("|")) {
|
||||||
|
@ -256,7 +256,7 @@ export class _ParseAST {
|
||||||
var name = this.expectIdentifierOrKeyword();
|
var name = this.expectIdentifierOrKeyword();
|
||||||
var args = [];
|
var args = [];
|
||||||
while (this.optionalCharacter($COLON)) {
|
while (this.optionalCharacter($COLON)) {
|
||||||
args.push(this.parsePipe());
|
args.push(this.parseExpression());
|
||||||
}
|
}
|
||||||
result = new BindingPipe(result, name, args);
|
result = new BindingPipe(result, name, args);
|
||||||
} while (this.optionalOperator("|"));
|
} while (this.optionalOperator("|"));
|
||||||
|
|
|
@ -408,6 +408,7 @@ var _availableDefinitions = [
|
||||||
'name | pipe',
|
'name | pipe',
|
||||||
'(name | pipe).length',
|
'(name | pipe).length',
|
||||||
"name | pipe:'one':address.city",
|
"name | pipe:'one':address.city",
|
||||||
|
"name | pipe:'a':'b' | pipe:0:1:2",
|
||||||
'value',
|
'value',
|
||||||
'a',
|
'a',
|
||||||
'address.city',
|
'address.city',
|
||||||
|
|
|
@ -354,6 +354,14 @@ export function main() {
|
||||||
expect(val.dispatcher.loggedValues).toEqual(['value one two default']);
|
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', () => {
|
it('should not reevaluate pure pipes unless its context or arg changes', () => {
|
||||||
var pipe = new CountingPipe();
|
var pipe = new CountingPipe();
|
||||||
var registry = new FakePipes('pipe', () => pipe, {pure: true});
|
var registry = new FakePipes('pipe', () => pipe, {pure: true});
|
||||||
|
|
|
@ -6,14 +6,6 @@ import {Unparser} from './unparser';
|
||||||
import {Lexer} from 'angular2/src/core/change_detection/parser/lexer';
|
import {Lexer} from 'angular2/src/core/change_detection/parser/lexer';
|
||||||
import {BindingPipe, LiteralPrimitive, AST} from 'angular2/src/core/change_detection/parser/ast';
|
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() {
|
export function main() {
|
||||||
function createParser() { return new Parser(new Lexer(), reflector); }
|
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('a?.b | c', '(a?.b | c)');
|
checkBinding('a?.b | c', '(a?.b | c)');
|
||||||
checkBinding('true | a', '(true | a)');
|
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', () => {
|
it('should only allow identifier or keyword as formatter names', () => {
|
||||||
|
|
Loading…
Reference in New Issue