Skip to content

Commit 81150ac

Browse files
committed
feat($parse): Allow user-defined literals
Allow user-defined literals. Close: angular#9504 Close: angular#9492 Close: angular#14194
1 parent 7ecfa5d commit 81150ac

File tree

2 files changed

+45
-15
lines changed

2 files changed

+45
-15
lines changed

src/ng/parse.js

+31-14
Original file line numberDiff line numberDiff line change
@@ -463,8 +463,10 @@ AST.prototype = {
463463
primary = this.arrayDeclaration();
464464
} else if (this.expect('{')) {
465465
primary = this.object();
466-
} else if (this.constants.hasOwnProperty(this.peek().text)) {
467-
primary = copy(this.constants[this.consume().text]);
466+
} else if (this.selfReferential.hasOwnProperty(this.peek().text)) {
467+
primary = copy(this.selfReferential[this.consume().text]);
468+
} else if (this.options.literals.hasOwnProperty(this.peek().text)) {
469+
primary = { type: AST.Literal, value: this.options.literals[this.consume().text]};
468470
} else if (this.peek().identifier) {
469471
primary = this.identifier();
470472
} else if (this.peek().constant) {
@@ -616,15 +618,7 @@ AST.prototype = {
616618
return false;
617619
},
618620

619-
620-
/* `undefined` is not a constant, it is an identifier,
621-
* but using it as an identifier is not supported
622-
*/
623-
constants: {
624-
'true': { type: AST.Literal, value: true },
625-
'false': { type: AST.Literal, value: false },
626-
'null': { type: AST.Literal, value: null },
627-
'undefined': {type: AST.Literal, value: undefined },
621+
selfReferential: {
628622
'this': {type: AST.ThisExpression },
629623
'$locals': {type: AST.LocalsExpression }
630624
}
@@ -1669,7 +1663,7 @@ var Parser = function(lexer, $filter, options) {
16691663
this.lexer = lexer;
16701664
this.$filter = $filter;
16711665
this.options = options;
1672-
this.ast = new AST(this.lexer);
1666+
this.ast = new AST(lexer, options);
16731667
this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
16741668
new ASTCompiler(this.ast, $filter);
16751669
};
@@ -1746,16 +1740,39 @@ function getValueOf(value) {
17461740
function $ParseProvider() {
17471741
var cacheDefault = createMap();
17481742
var cacheExpensive = createMap();
1743+
var literals = {
1744+
'true': true,
1745+
'false': false,
1746+
'null': null,
1747+
'undefined': undefined
1748+
};
1749+
1750+
/**
1751+
* @ngdoc method
1752+
* @name $parseProvider#addLiteral
1753+
* @description
1754+
*
1755+
* Configure $parse service to add literal values that will be present as literal at expressions.
1756+
*
1757+
* @param {string} literalName Token for the literal value. The literal name value must be a valid literal name.
1758+
* @param {*} literalValue Value for this literal. All literal values must be primitives or `undefined`.
1759+
*
1760+
**/
1761+
this.addLiteral = function(literalName, literalValue) {
1762+
literals[literalName] = literalValue;
1763+
};
17491764

17501765
this.$get = ['$filter', function($filter) {
17511766
var noUnsafeEval = csp().noUnsafeEval;
17521767
var $parseOptions = {
17531768
csp: noUnsafeEval,
1754-
expensiveChecks: false
1769+
expensiveChecks: false,
1770+
literals: copy(literals)
17551771
},
17561772
$parseOptionsExpensive = {
17571773
csp: noUnsafeEval,
1758-
expensiveChecks: true
1774+
expensiveChecks: true,
1775+
literals: copy(literals)
17591776
};
17601777
var runningChecksEnabled = false;
17611778

test/ng/parseSpec.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ describe('parser', function() {
223223
/* global AST: false */
224224
createAst = function() {
225225
var lexer = new Lexer({csp: false});
226-
var ast = new AST(lexer, {csp: false});
226+
var ast = new AST(lexer, {csp: false, literals: {'true': true, 'false': false, 'undefined': undefined, 'null': null}});
227227
return ast.ast.apply(ast, arguments);
228228
};
229229
});
@@ -1681,6 +1681,19 @@ describe('parser', function() {
16811681
$filterProvider = filterProvider;
16821682
}]));
16831683

1684+
forEach([true, false], function(cspEnabled) {
1685+
beforeEach(module(['$parseProvider', function(parseProvider) {
1686+
parseProvider.addLiteral('Infinity', Infinity);
1687+
}]));
1688+
1689+
it('should allow extending literals with csp ' + cspEnabled, inject(function($rootScope) {
1690+
expect($rootScope.$eval("Infinity")).toEqual(Infinity);
1691+
expect($rootScope.$eval("-Infinity")).toEqual(-Infinity);
1692+
expect(function() {$rootScope.$eval("Infinity = 1");}).toThrow();
1693+
expect($rootScope.$eval("Infinity")).toEqual(Infinity);
1694+
}));
1695+
});
1696+
16841697
forEach([true, false], function(cspEnabled) {
16851698
describe('csp: ' + cspEnabled, function() {
16861699

0 commit comments

Comments
 (0)