@@ -380,48 +380,27 @@ var Mustache;
380
380
var tree = [ ] ;
381
381
var collector = tree ;
382
382
var sections = [ ] ;
383
- var token , section ;
384
383
385
- for ( var i = 0 ; i < tokens . length ; ++ i ) {
384
+ var token ;
385
+ for ( var i = 0 , len = tokens . length ; i < len ; ++ i ) {
386
386
token = tokens [ i ] ;
387
-
388
387
switch ( token [ 0 ] ) {
389
- case "#" :
390
- case "^" :
391
- token [ 4 ] = [ ] ;
388
+ case '#' :
389
+ case '^' :
392
390
sections . push ( token ) ;
393
391
collector . push ( token ) ;
394
- collector = token [ 4 ] ;
392
+ collector = token [ 4 ] = [ ] ;
395
393
break ;
396
- case "/" :
397
- if ( sections . length === 0 ) {
398
- throw new Error ( "Unopened section: " + token [ 1 ] ) ;
399
- }
400
-
401
- section = sections . pop ( ) ;
402
-
403
- if ( section [ 1 ] !== token [ 1 ] ) {
404
- throw new Error ( "Unclosed section: " + section [ 1 ] ) ;
405
- }
406
-
407
- if ( sections . length > 0 ) {
408
- collector = sections [ sections . length - 1 ] [ 4 ] ;
409
- } else {
410
- collector = tree ;
411
- }
394
+ case '/' :
395
+ sections . pop ( ) ;
396
+ var length = sections . length ;
397
+ collector = length > 0 ? sections [ length - 1 ] [ 4 ] : tree ;
412
398
break ;
413
399
default :
414
400
collector . push ( token ) ;
415
401
}
416
402
}
417
403
418
- // Make sure there were no open sections when we're done.
419
- section = sections . pop ( ) ;
420
-
421
- if ( section ) {
422
- throw new Error ( "Unclosed section: " + section [ 1 ] ) ;
423
- }
424
-
425
404
return tree ;
426
405
}
427
406
@@ -435,7 +414,7 @@ var Mustache;
435
414
var token , lastToken ;
436
415
for ( var i = 0 , len = tokens . length ; i < len ; ++ i ) {
437
416
token = tokens [ i ] ;
438
- if ( lastToken && lastToken [ 0 ] === " text" && token [ 0 ] === " text" ) {
417
+ if ( token [ 0 ] === ' text' && lastToken && lastToken [ 0 ] === ' text' ) {
439
418
lastToken [ 1 ] += token [ 1 ] ;
440
419
lastToken [ 3 ] = token [ 3 ] ;
441
420
} else {
@@ -448,10 +427,6 @@ var Mustache;
448
427
}
449
428
450
429
function escapeTags ( tags ) {
451
- if ( tags . length !== 2 ) {
452
- throw new Error ( "Invalid tags: " + tags . join ( " " ) ) ;
453
- }
454
-
455
430
return [
456
431
new RegExp ( escapeRe ( tags [ 0 ] ) + "\\s*" ) ,
457
432
new RegExp ( "\\s*" + escapeRe ( tags [ 1 ] ) )
@@ -468,9 +443,15 @@ var Mustache;
468
443
template = template || '' ;
469
444
tags = tags || exports . tags ;
470
445
446
+ if ( typeof tags === 'string' ) tags = tags . split ( spaceRe ) ;
447
+ if ( tags . length !== 2 ) {
448
+ throw new Error ( 'Invalid tags: ' + tags . join ( ', ' ) ) ;
449
+ }
450
+
471
451
var tagRes = escapeTags ( tags ) ;
472
452
var scanner = new Scanner ( template ) ;
473
453
454
+ var sections = [ ] ; // Stack to hold section tokens
474
455
var tokens = [ ] ; // Buffer to hold the tokens
475
456
var spaces = [ ] ; // Indices of whitespace tokens on the current line
476
457
var hasTag = false ; // Is there a {{tag}} on the current line?
@@ -492,7 +473,6 @@ var Mustache;
492
473
}
493
474
494
475
var start , type , value , chr ;
495
-
496
476
while ( ! scanner . eos ( ) ) {
497
477
start = scanner . pos ;
498
478
value = scanner . scanUntil ( tagRes [ 0 ] ) ;
@@ -546,25 +526,48 @@ var Mustache;
546
526
547
527
// Match the closing tag.
548
528
if ( ! scanner . scan ( tagRes [ 1 ] ) ) {
549
- throw new Error ( " Unclosed tag at " + scanner . pos ) ;
529
+ throw new Error ( ' Unclosed tag at ' + scanner . pos ) ;
550
530
}
551
531
552
- tokens . push ( [ type , value , start , scanner . pos ] ) ;
532
+ // Check section nesting.
533
+ if ( type === '/' ) {
534
+ if ( sections . length === 0 ) {
535
+ throw new Error ( 'Unopened section "' + value + '" at ' + start ) ;
536
+ }
553
537
554
- if ( type === "name" || type === "{" || type === "&" ) {
555
- nonSpace = true ;
538
+ var section = sections . pop ( ) ;
539
+
540
+ if ( section [ 1 ] !== value ) {
541
+ throw new Error ( 'Unclosed section "' + section [ 1 ] + '" at ' + start ) ;
542
+ }
556
543
}
557
544
558
- // Set the tags for the next time around.
559
- if ( type === "=" ) {
545
+ var token = [ type , value , start , scanner . pos ] ;
546
+ tokens . push ( token ) ;
547
+
548
+ if ( type === '#' || type === '^' ) {
549
+ sections . push ( token ) ;
550
+ } else if ( type === "name" || type === "{" || type === "&" ) {
551
+ nonSpace = true ;
552
+ } else if ( type === "=" ) {
553
+ // Set the tags for the next time around.
560
554
tags = value . split ( spaceRe ) ;
555
+
556
+ if ( tags . length !== 2 ) {
557
+ throw new Error ( 'Invalid tags at ' + start + ': ' + tags . join ( ', ' ) ) ;
558
+ }
559
+
561
560
tagRes = escapeTags ( tags ) ;
562
561
}
563
562
}
564
563
565
- tokens = squashTokens ( tokens ) ;
564
+ // Make sure there are no open sections when we're done.
565
+ var section = sections . pop ( ) ;
566
+ if ( section ) {
567
+ throw new Error ( 'Unclosed section "' + section [ 1 ] + '" at ' + scanner . pos ) ;
568
+ }
566
569
567
- return nestTokens ( tokens ) ;
570
+ return nestTokens ( squashTokens ( tokens ) ) ;
568
571
} ;
569
572
570
573
// The high-level clearCache, compile, compilePartial, and render functions
0 commit comments