Skip to content

Commit f9f500c

Browse files
committed
improve expression parser
- allow more use of globals such as parseInt, encodeURI... - better warning when expression contains reserved keywords
1 parent 3eabe22 commit f9f500c

File tree

3 files changed

+55
-20
lines changed

3 files changed

+55
-20
lines changed

src/parsers/expression.js

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,29 @@ var Path = require('./path')
33
var Cache = require('../cache')
44
var expressionCache = new Cache(1000)
55

6-
var keywords =
7-
'Math,Date,break,case,catch,continue,debugger,default,' +
8-
'delete,do,else,false,finally,for,function,if,in,' +
9-
'instanceof,new,null,return,switch,this,throw,true,try,' +
10-
'typeof,var,void,while,with,undefined,abstract,boolean,' +
11-
'byte,char,class,const,double,enum,export,extends,' +
12-
'final,float,goto,implements,import,int,interface,long,' +
13-
'native,package,private,protected,public,short,static,' +
14-
'super,synchronized,throws,transient,volatile,' +
15-
'arguments,let,yield'
6+
var allowedKeywords =
7+
'Math,Date,this,true,false,null,undefined,Infinity,NaN,' +
8+
'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' +
9+
'encodeURIComponent,parseInt,parseFloat'
10+
var allowedKeywordsRE =
11+
new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)')
12+
13+
// keywords that don't make sense inside expressions
14+
var imporperKeywords =
15+
'break,case,class,catch,const,continue,debugger,default,' +
16+
'delete,do,else,export,extends,finally,for,function,if,' +
17+
'import,in,instanceof,let,return,super,switch,throw,try,' +
18+
'var,while,with,yield,enum,await,implements,package,' +
19+
'proctected,static,interface,private,public'
20+
var imporoperKeywordsRE =
21+
new RegExp('^(' + imporperKeywords.replace(/,/g, '\\b|') + '\\b)')
1622

1723
var wsRE = /\s/g
1824
var newlineRE = /\n/g
19-
var saveRE = /[\{,]\s*[\w\$_]+\s*:|('[^']*'|"[^"]*")|new /g
25+
var saveRE = /[\{,]\s*[\w\$_]+\s*:|('[^']*'|"[^"]*")|new |typeof |void /g
2026
var restoreRE = /"(\d+)"/g
2127
var pathTestRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\])*$/
2228
var pathReplaceRE = /[^\w$\.]([A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\])*)/g
23-
var keywordsRE = new RegExp('^(' + keywords.replace(/,/g, '\\b|') + '\\b)')
2429
var booleanLiteralRE = /^(true|false)$/
2530

2631
/**
@@ -68,7 +73,7 @@ function save (str, isString) {
6873
function rewrite (raw) {
6974
var c = raw.charAt(0)
7075
var path = raw.slice(1)
71-
if (keywordsRE.test(path)) {
76+
if (allowedKeywordsRE.test(path)) {
7277
return raw
7378
} else {
7479
path = path.indexOf('"') > -1
@@ -100,6 +105,12 @@ function restore (str, i) {
100105
*/
101106

102107
function compileExpFns (exp, needSet) {
108+
if (imporoperKeywordsRE.test(exp)) {
109+
_.warn(
110+
'Avoid using reserved keywords in expression: '
111+
+ exp
112+
)
113+
}
103114
// reset state
104115
saved.length = 0
105116
// save strings and object literal keys
@@ -230,7 +241,9 @@ exports.parse = function (exp, needSet) {
230241
// global "Math"
231242
var res =
232243
pathTestRE.test(exp) &&
244+
// don't treat true/false as paths
233245
!booleanLiteralRE.test(exp) &&
246+
// Math constants e.g. Math.PI, Math.E etc.
234247
exp.slice(0, 5) !== 'Math.'
235248
? compilePathFns(exp)
236249
: compileExpFns(exp, needSet)

src/util/debug.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,8 @@ function enableDebug () {
3030
* @param {String} msg
3131
*/
3232

33-
var warned = false
3433
exports.warn = function (msg) {
3534
if (hasConsole && (!config.silent || config.debug)) {
36-
if (!config.debug && !warned) {
37-
warned = true
38-
console.log(
39-
'Set `Vue.config.debug = true` to enable debug mode.'
40-
)
41-
}
4235
console.warn('[Vue warn]: ' + msg)
4336
/* istanbul ignore if */
4437
if (config.debug) {

test/unit/specs/parsers/expression_spec.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,27 @@ var testCases = [
204204
scope: {},
205205
expected: true,
206206
paths: []
207+
},
208+
// typeof operator
209+
{
210+
exp: 'typeof test === "string"',
211+
scope: { test: "123" },
212+
expected: true,
213+
paths: ['test']
214+
},
215+
// isNaN
216+
{
217+
exp: 'isNaN(a)',
218+
scope: { a: 2 },
219+
expected: false,
220+
paths: ['a']
221+
},
222+
// parseFloat & parseInt
223+
{
224+
exp: 'parseInt(a, 10) + parseFloat(b)',
225+
scope: { a: 2.33, b: '3.45' },
226+
expected: 5.45,
227+
paths: ['a', 'b']
207228
}
208229
]
209230

@@ -253,16 +274,24 @@ describe('Expression Parser', function () {
253274
})
254275

255276
it('should warn on invalid expression', function () {
277+
expect(_.warn).not.toHaveBeenCalled()
256278
var res = expParser.parse('a--b"ffff')
257279
expect(_.warn).toHaveBeenCalled()
258280
})
259281

260282
if (leftHandThrows()) {
261283
it('should warn on invalid left hand expression for setter', function () {
284+
expect(_.warn).not.toHaveBeenCalled()
262285
var res = expParser.parse('a+b', true)
263286
expect(_.warn).toHaveBeenCalled()
264287
})
265288
}
289+
290+
it('should warn if expression contains improper reserved keywords', function () {
291+
expect(_.warn).not.toHaveBeenCalled()
292+
var res = expParser.parse('break + 1')
293+
expect(_.warn).toHaveBeenCalled()
294+
})
266295
})
267296
})
268297

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy