diff --git a/src/ng/parse.js b/src/ng/parse.js index 1cb87cc8f6b0..e49736ba2ce4 100644 --- a/src/ng/parse.js +++ b/src/ng/parse.js @@ -1644,11 +1644,26 @@ Parser.prototype = { constructor: Parser, parse: function(text) { - var ast = this.ast.ast(text); - var fn = this.astCompiler.compile(ast); - fn.literal = isLiteral(ast); - fn.constant = isConstant(ast); + var ast = this.getAst(text); + var fn = this.astCompiler.compile(ast.ast); + fn.literal = isLiteral(ast.ast); + fn.constant = isConstant(ast.ast); + fn.oneTime = ast.oneTime; return fn; + }, + + getAst: function(exp) { + var oneTime = false; + exp = exp.trim(); + + if (exp.charAt(0) === ':' && exp.charAt(1) === ':') { + oneTime = true; + exp = exp.substring(2); + } + return { + ast: this.ast.ast(exp), + oneTime: oneTime + }; } }; @@ -1771,10 +1786,11 @@ function $ParseProvider() { isIdentifierStart: isFunction(identStart) && identStart, isIdentifierContinue: isFunction(identContinue) && identContinue }; + $parse.$$getAst = $$getAst; return $parse; function $parse(exp, interceptorFn) { - var parsedExpression, oneTime, cacheKey; + var parsedExpression, cacheKey; switch (typeof exp) { case 'string': @@ -1784,16 +1800,12 @@ function $ParseProvider() { parsedExpression = cache[cacheKey]; if (!parsedExpression) { - if (exp.charAt(0) === ':' && exp.charAt(1) === ':') { - oneTime = true; - exp = exp.substring(2); - } var lexer = new Lexer($parseOptions); var parser = new Parser(lexer, $filter, $parseOptions); parsedExpression = parser.parse(exp); if (parsedExpression.constant) { parsedExpression.$$watchDelegate = constantWatchDelegate; - } else if (oneTime) { + } else if (parsedExpression.oneTime) { parsedExpression.$$watchDelegate = parsedExpression.literal ? oneTimeLiteralWatchDelegate : oneTimeWatchDelegate; } else if (parsedExpression.inputs) { @@ -1811,6 +1823,12 @@ function $ParseProvider() { } } + function $$getAst(exp) { + var lexer = new Lexer($parseOptions); + var parser = new Parser(lexer, $filter, $parseOptions); + return parser.getAst(exp).ast; + } + function expressionInputDirtyCheck(newValue, oldValueOfValue, compareObjectIdentity) { if (newValue == null || oldValueOfValue == null) { // null/undefined diff --git a/test/ng/parseSpec.js b/test/ng/parseSpec.js index b57be4b69172..e08b881e0cfe 100644 --- a/test/ng/parseSpec.js +++ b/test/ng/parseSpec.js @@ -3994,4 +3994,48 @@ describe('parser', function() { }); }); }); + + describe('hidden/unsupported features', function() { + describe('$$getAst()', function() { + it('should be a method exposed on the `$parse` service', inject(function($parse) { + expect(isFunction($parse.$$getAst)).toBeTruthy(); + })); + + it('should accept a string expression argument and return the corresponding AST', inject(function($parse) { + var ast = $parse.$$getAst('foo.bar'); + expect(ast).toEqual({ + type: 'Program', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'MemberExpression', + object: { type: 'Identifier', name: 'foo' }, + property: { type: 'Identifier', name: 'bar' }, + computed: false + } + } + ] + }); + })); + + it('should parse one time binding expressions', inject(function($parse) { + var ast = $parse.$$getAst('::foo.bar'); + expect(ast).toEqual({ + type: 'Program', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'MemberExpression', + object: { type: 'Identifier', name: 'foo' }, + property: { type: 'Identifier', name: 'bar' }, + computed: false + } + } + ] + }); + })); + }); + }); });