@@ -867,8 +867,7 @@ function patchESLint() {
867
867
var isVisualForce = visualForceExtensions . indexOf ( extension ) >= 0 ;
868
868
869
869
if ( typeof textOrSourceCode === 'string' && isVisualForce ) {
870
- var currentInfos = extract ( textOrSourceCode , pluginSettings . indent , false // isXML
871
- ) ;
870
+ var currentInfos = extract ( textOrSourceCode , pluginSettings . indent ) ;
872
871
// parsing the source code with the patched espree
873
872
var espreePath = Object . keys ( requireCache ) . find ( function ( key ) {
874
873
return key . endsWith ( path . join ( 'espree' , 'espree.js' ) ) ;
@@ -899,11 +898,12 @@ function patchESLint() {
899
898
comment : true ,
900
899
filePath : filename
901
900
} ) ;
901
+ //console.log('code: ', String(currentInfos.code));
902
902
903
903
var ast = espree . parse ( String ( currentInfos . code ) , parserOptions ) ;
904
904
var sourceCode = new SourceCode ( String ( currentInfos . code ) , ast ) ;
905
905
906
- messages = remapMessages ( localVerify ( sourceCode ) , currentInfos . code , pluginSettings . reportBadIndent , currentInfos . badIndentationLines ) ;
906
+ messages = remapMessages ( localVerify ( sourceCode ) , currentInfos . code , pluginSettings . reportBadIndent , currentInfos . badIndentationLines , currentInfos . apexRepeatTags ) ;
907
907
sourceCodeForMessages . set ( messages , textOrSourceCode ) ;
908
908
} else messages = localVerify ( textOrSourceCode ) ;
909
909
@@ -921,7 +921,7 @@ function patchESLint() {
921
921
} ;
922
922
}
923
923
924
- function remapMessages ( messages , code , reportBadIndent , badIndentationLines ) {
924
+ function remapMessages ( messages , code , reportBadIndent , badIndentationLines , apexRepeatTags ) {
925
925
var newMessages = [ ] ;
926
926
927
927
messages . forEach ( function ( message ) {
@@ -960,6 +960,16 @@ function remapMessages(messages, code, reportBadIndent, badIndentationLines) {
960
960
} ) ;
961
961
} ) ;
962
962
963
+ apexRepeatTags . forEach ( function ( location ) {
964
+ newMessages . push ( {
965
+ message : '<apex:repeat> tags are not allowed in Javascript' ,
966
+ line : location . line ,
967
+ column : location . column ,
968
+ ruleId : '(visualforce plugin)' ,
969
+ severity : 2
970
+ } ) ;
971
+ } ) ;
972
+
963
973
newMessages . sort ( function ( ma , mb ) {
964
974
return ma . line - mb . line || ma . column - mb . column ;
965
975
} ) ;
@@ -1165,10 +1175,9 @@ var _marked = [dedent].map(regeneratorRuntime.mark);
1165
1175
var htmlparser2 = __webpack_require__ ( 8 ) ;
1166
1176
var TransformableString = __webpack_require__ ( 2 ) ;
1167
1177
1168
- function iterateScripts ( code , options , onChunk ) {
1178
+ function iterateScripts ( code , onChunk ) {
1169
1179
if ( ! code ) return ;
1170
1180
1171
- var xmlMode = options . xmlMode ;
1172
1181
var index = 0 ;
1173
1182
var inScript = false ;
1174
1183
var nextType = null ;
@@ -1210,6 +1219,11 @@ function iterateScripts(code, options, onChunk) {
1210
1219
1211
1220
onopentag ( name ) {
1212
1221
// Test if current tag is a valid <script> tag.
1222
+ if ( name === 'apex:repeat' && inScript ) {
1223
+ emitChunk ( 'script' , parser . startIndex ) ;
1224
+ emitChunk ( 'apex:repeat' , parser . endIndex + 1 ) ;
1225
+ //console.log('open tag: ', code.slice(parser.startIndex, parser.endIndex+1));
1226
+ }
1213
1227
if ( name !== 'script' ) return ;
1214
1228
inScript = true ;
1215
1229
emitChunk ( 'html' , parser . endIndex + 1 ) ;
@@ -1224,6 +1238,12 @@ function iterateScripts(code, options, onChunk) {
1224
1238
} ,
1225
1239
1226
1240
onclosetag ( name ) {
1241
+ if ( name === 'apex:repeat' && inScript ) {
1242
+ emitChunk ( 'script' , parser . startIndex ) ;
1243
+ emitChunk ( 'apex:repeat' , parser . endIndex + 1 ) ;
1244
+ // console.log('close tag: ', code.slice(parser.startIndex, parser.endIndex+1));
1245
+ }
1246
+
1227
1247
if ( name !== 'script' || ! inScript ) return ;
1228
1248
1229
1249
inScript = false ;
@@ -1238,16 +1258,16 @@ function iterateScripts(code, options, onChunk) {
1238
1258
emitChunk ( 'script' , parser . endIndex + 1 ) ;
1239
1259
}
1240
1260
1241
- } , { xmlMode : xmlMode === true } ) ;
1261
+ } , { xmlMode : true } ) ;
1242
1262
1243
1263
parser . parseComplete ( code ) ;
1244
1264
1245
1265
emitChunk ( 'html' , parser . endIndex + 1 , true ) ;
1246
1266
}
1247
1267
1248
- function computeIndent ( descriptor , previousHTML , slice ) {
1268
+ function computeIndent ( descriptor , previousHTML , codeSlice ) {
1249
1269
if ( ! descriptor ) {
1250
- var indentMatch = / [ \n \r ] + ( [ \t ] * ) / . exec ( slice ) ;
1270
+ var indentMatch = / [ \n \r ] + ( [ \t ] * ) / . exec ( codeSlice ) ;
1251
1271
return indentMatch ? indentMatch [ 1 ] : '' ;
1252
1272
}
1253
1273
@@ -1256,7 +1276,7 @@ function computeIndent(descriptor, previousHTML, slice) {
1256
1276
return descriptor . spaces ;
1257
1277
}
1258
1278
1259
- function dedent ( indent , slice ) {
1279
+ function dedent ( indent , codeSlice ) {
1260
1280
var hadNonEmptyLine , re , match , newLine , lineIndent , lineText , isEmptyLine , isFirstNonEmptyLine , badIndentation ;
1261
1281
return regeneratorRuntime . wrap ( function dedent$ ( _context ) {
1262
1282
while ( 1 ) {
@@ -1266,7 +1286,7 @@ function dedent(indent, slice) {
1266
1286
re = / ( \r \n | \n | \r ) ( [ \t ] * ) ( .* ) / g;
1267
1287
1268
1288
case 2 :
1269
- match = re . exec ( slice ) ;
1289
+ match = re . exec ( codeSlice ) ;
1270
1290
1271
1291
if ( match ) {
1272
1292
_context . next = 5 ;
@@ -1334,58 +1354,74 @@ function dedent(indent, slice) {
1334
1354
} , _marked [ 0 ] , this ) ;
1335
1355
}
1336
1356
1337
- function extract ( code , indentDescriptor , xmlMode ) {
1357
+ function extract ( code , indentDescriptor ) {
1338
1358
var badIndentationLines = [ ] ;
1359
+ var apexRepeatTags = [ ] ;
1339
1360
var transformedCode = new TransformableString ( code ) ;
1340
1361
var lineNumber = 1 ;
1341
1362
var previousHTML = '' ;
1342
1363
1343
- iterateScripts ( code , { xmlMode } , function ( chunk ) {
1344
- var slice = code . slice ( chunk . start , chunk . end ) ;
1345
-
1346
- if ( chunk . type === 'html' || chunk . type === 'cdata start' || chunk . type === 'cdata end' ) {
1347
- var newLinesRe = / (?: \r \n | \n | \r ) ( [ ^ \r \n ] ) ? / g;
1348
- var lastEmptyLinesLength = 0 ;
1349
- for ( ; ; ) {
1350
- var match = newLinesRe . exec ( slice ) ;
1351
- if ( ! match ) break ;
1352
- lineNumber += 1 ;
1353
- lastEmptyLinesLength = ! match [ 1 ] ? lastEmptyLinesLength + match [ 0 ] . length : 0 ;
1354
- }
1355
- transformedCode . replace ( chunk . start , chunk . end - lastEmptyLinesLength , '/* HTML */' ) ;
1356
- if ( chunk . type === 'html' ) previousHTML = slice ;
1357
- } else if ( chunk . type === 'script' ) {
1358
- var _iteratorNormalCompletion = true ;
1359
- var _didIteratorError = false ;
1360
- var _iteratorError = undefined ;
1361
-
1362
- try {
1363
- for ( var _iterator = dedent ( computeIndent ( indentDescriptor , previousHTML , slice ) , slice ) [ Symbol . iterator ] ( ) , _step ; ! ( _iteratorNormalCompletion = ( _step = _iterator . next ( ) ) . done ) ; _iteratorNormalCompletion = true ) {
1364
- var action = _step . value ;
1365
-
1366
- lineNumber += 1 ;
1367
- if ( action . type === 'dedent' ) transformedCode . replace ( chunk . start + action . from , chunk . start + action . to , '' ) ; else if ( action . type === 'bad-indent' ) badIndentationLines . push ( lineNumber ) ;
1364
+ iterateScripts ( code , function ( chunk ) {
1365
+ var codeSlice = code . slice ( chunk . start , chunk . end ) ;
1366
+
1367
+ switch ( chunk . type ) {
1368
+ case 'html' :
1369
+ previousHTML = codeSlice ;
1370
+ // falls through
1371
+ case 'apex:repeat' :
1372
+ case 'cdata start' :
1373
+ case 'cdata end' :
1374
+ {
1375
+ var newLinesRe = / (?: \r \n | \n | \r ) ( [ ^ \r \n ] ) ? / g;
1376
+ var lastEmptyLinesLength = 0 ;
1377
+ for ( ; ; ) {
1378
+ var match = newLinesRe . exec ( codeSlice ) ;
1379
+ if ( ! match ) break ;
1380
+ lineNumber += 1 ;
1381
+ lastEmptyLinesLength = ! match [ 1 ] ? lastEmptyLinesLength + match [ 0 ] . length : 0 ;
1382
+ }
1383
+ transformedCode . replace ( chunk . start , chunk . end - lastEmptyLinesLength , '/* HTML */' ) ;
1384
+ break ;
1368
1385
}
1369
- } catch ( err ) {
1370
- _didIteratorError = true ;
1371
- _iteratorError = err ;
1372
- } finally {
1386
+ // case 'apex:repeat':
1387
+ // transformedCode.replace(chunk.start, chunk.end, `/* ${codeSlice} */`)
1388
+ // // TODO add message
1389
+ // break
1390
+ case 'script' :
1391
+ var _iteratorNormalCompletion = true ;
1392
+ var _didIteratorError = false ;
1393
+ var _iteratorError = undefined ;
1394
+
1373
1395
try {
1374
- if ( ! _iteratorNormalCompletion && _iterator . return ) {
1375
- _iterator . return ( ) ;
1396
+ for ( var _iterator = dedent ( computeIndent ( indentDescriptor , previousHTML , codeSlice ) , codeSlice ) [ Symbol . iterator ] ( ) , _step ; ! ( _iteratorNormalCompletion = ( _step = _iterator . next ( ) ) . done ) ; _iteratorNormalCompletion = true ) {
1397
+ var action = _step . value ;
1398
+
1399
+ lineNumber += 1 ;
1400
+ if ( action . type === 'dedent' ) transformedCode . replace ( chunk . start + action . from , chunk . start + action . to , '' ) ; else if ( action . type === 'bad-indent' ) badIndentationLines . push ( lineNumber ) ;
1376
1401
}
1402
+ } catch ( err ) {
1403
+ _didIteratorError = true ;
1404
+ _iteratorError = err ;
1377
1405
} finally {
1378
- if ( _didIteratorError ) {
1379
- throw _iteratorError ;
1406
+ try {
1407
+ if ( ! _iteratorNormalCompletion && _iterator . return ) {
1408
+ _iterator . return ( ) ;
1409
+ }
1410
+ } finally {
1411
+ if ( _didIteratorError ) {
1412
+ throw _iteratorError ;
1413
+ }
1380
1414
}
1381
1415
}
1382
- }
1416
+
1417
+ break ;
1383
1418
}
1384
- } ) ;
1419
+ } ) ; // iterateScripts
1385
1420
1386
1421
return {
1387
1422
code : transformedCode ,
1388
- badIndentationLines
1423
+ badIndentationLines,
1424
+ apexRepeatTags
1389
1425
} ;
1390
1426
}
1391
1427
@@ -1457,6 +1493,12 @@ var untaintingParents = {
1457
1493
MapEntry ( parentNode , node ) {
1458
1494
// keys are safe, values are not
1459
1495
return parentNode . key === node ;
1496
+ } ,
1497
+ VFELMemberExpression ( ) {
1498
+ // VFELMemberExpressions such as field[selector] are not untainting
1499
+ // However, JSENCODE should be applied to the expression itself,
1500
+ // and not the selectors, so we untaint the members of this expression
1501
+ return true ;
1460
1502
}
1461
1503
} ;
1462
1504
@@ -1489,17 +1531,17 @@ function isTainting(node) {
1489
1531
return true ;
1490
1532
}
1491
1533
1492
- var untainter = untaintingParents [ parent . type ] ;
1534
+ var untainter = parent && untaintingParents [ parent . type ] ;
1493
1535
1494
1536
// The parent expression untaints the whole subtree
1495
- if ( untainter && untainter ( parent , node ) ) {
1496
- return false ;
1497
- } else return isTainting ( parent ) ;
1537
+ if ( untainter && untainter ( parent , node ) ) return false ; else return isTainting ( parent ) ;
1498
1538
}
1499
1539
1500
- function checkIdentifier ( node , context ) {
1540
+ function checkNode ( node , context ) {
1541
+ //console.log(`identifier's `, node.name ,` parent is ${node.parent.type}`)
1542
+
1501
1543
// Not checking taint for system variables except the only user-controlled one
1502
- if ( isSafeSystemIdentifier ( node . name . toUpperCase ( ) ) ) return ;
1544
+ if ( node . name && isSafeSystemIdentifier ( node . name . toUpperCase ( ) ) ) return ;
1503
1545
1504
1546
if ( isTainting ( node ) ) context . report ( {
1505
1547
message : 'JSENCODE() must be applied to all rendered Apex variables' ,
@@ -1523,7 +1565,10 @@ module.exports = {
1523
1565
create ( context ) {
1524
1566
return {
1525
1567
VFELIdentifier : function VFELIdentifier ( node ) {
1526
- return checkIdentifier ( node , context ) ;
1568
+ return checkNode ( node , context ) ;
1569
+ } ,
1570
+ VFELMemberExpression : function VFELMemberExpression ( node ) {
1571
+ return checkNode ( node , context ) ;
1527
1572
}
1528
1573
} ;
1529
1574
}
0 commit comments