@@ -375,6 +375,34 @@ var (
375
375
})
376
376
)
377
377
378
+ // Void element closer.
379
+ var voidElementCloser voidElementCloserParser
380
+
381
+ type voidElementCloserParser struct {}
382
+
383
+ var voidElementCloseTags = []string {"</area>" , "</base>" , "</br>" , "</col>" , "</command>" , "</embed>" , "</hr>" , "</img>" , "</input>" , "</keygen>" , "</link>" , "</meta>" , "</param>" , "</source>" , "</track>" , "</wbr>" }
384
+
385
+ func (voidElementCloserParser ) Parse (pi * parse.Input ) (n Node , ok bool , err error ) {
386
+ var ve string
387
+ for _ , ve = range voidElementCloseTags {
388
+ s , canPeekLen := pi .Peek (len (ve ))
389
+ if ! canPeekLen {
390
+ continue
391
+ }
392
+ if ! strings .EqualFold (s , ve ) {
393
+ continue
394
+ }
395
+ // Found a match.
396
+ ok = true
397
+ break
398
+ }
399
+ if ! ok {
400
+ return nil , false , nil
401
+ }
402
+ pi .Take (len (ve ))
403
+ return nil , true , nil
404
+ }
405
+
378
406
// Element.
379
407
var element elementParser
380
408
@@ -396,28 +424,19 @@ func (elementParser) Parse(pi *parse.Input) (n Node, ok bool, err error) {
396
424
397
425
// Once we've got an open tag, the rest must be present.
398
426
l := pi .Position ().Line
399
- endOfOpenTag := pi .Index ()
400
427
401
428
// If the element is self-closing, even if it's not really a void element (br, hr etc.), we can return early.
402
- if ot .Void {
429
+ if ot .Void || r . IsVoidElement () {
403
430
// Escape early, no need to try to parse children for self-closing elements.
404
431
return addTrailingSpaceAndValidate (start , r , pi )
405
432
}
406
433
407
- // Void elements _might_ have children, even though it's invalid.
408
- // We want to allow this to be parsed.
434
+ // Parse children.
409
435
closer := StripType (parse .All (parse .String ("</" ), parse .String (ot .Name ), parse .Rune ('>' )))
410
436
tnp := newTemplateNodeParser (closer , fmt .Sprintf ("<%s>: close tag" , ot .Name ))
411
437
nodes , _ , err := tnp .Parse (pi )
412
438
if err != nil {
413
439
notFoundErr , isNotFoundError := err .(UntilNotFoundError )
414
- if r .IsVoidElement () && isNotFoundError {
415
- // Void elements shouldn't have children, or a close tag, so this is expected.
416
- // When the template is reformatted, we won't reach here, because <hr> will be converted to <hr/>.
417
- // Return the element as we have it.
418
- pi .Seek (endOfOpenTag )
419
- return addTrailingSpaceAndValidate (start , r , pi )
420
- }
421
440
if isNotFoundError {
422
441
err = notFoundErr .ParseError
423
442
}
@@ -443,6 +462,10 @@ func (elementParser) Parse(pi *parse.Input) (n Node, ok bool, err error) {
443
462
}
444
463
445
464
func addTrailingSpaceAndValidate (start parse.Position , e Element , pi * parse.Input ) (n Node , ok bool , err error ) {
465
+ // Elide any void close tags.
466
+ if _ , _ , err = voidElementCloser .Parse (pi ); err != nil {
467
+ return e , false , err
468
+ }
446
469
// Add trailing space.
447
470
ws , _ , err := parse .Whitespace .Parse (pi )
448
471
if err != nil {
0 commit comments