2025-09-11 20:50:00 +02:00
|
|
|
package html
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"regexp"
|
2025-10-05 14:27:48 +02:00
|
|
|
"strings"
|
2025-09-11 20:50:00 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
symbolExp = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9-_.]*$`)
|
|
|
|
|
scriptTagExp = regexp.MustCompile(`<\s*/?\s*[sS][cC][rR][iI][pP][tT]([^a-zA-Z0-9]+|$)`)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func validateSymbol(s string) error {
|
|
|
|
|
if !symbolExp.MatchString(s) {
|
|
|
|
|
return errors.New("invalid symbol")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func validateTagName(name string) error {
|
|
|
|
|
return validateSymbol(name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func validateAttributeName(name string) error {
|
|
|
|
|
return validateSymbol(name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func validate(name string, children []any) error {
|
|
|
|
|
if err := validateTagName(name); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a, c, rgs := groupChildren(children)
|
|
|
|
|
rg := mergeRenderingGuides(rgs)
|
|
|
|
|
if rg.void && len(c) > 0 {
|
|
|
|
|
return fmt.Errorf("tag %s is void but it has children", name)
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-05 14:27:48 +02:00
|
|
|
isDeclaration := strings.HasPrefix(name, "!")
|
2025-09-11 20:50:00 +02:00
|
|
|
for _, ai := range a {
|
|
|
|
|
for name := range ai {
|
2025-10-05 14:27:48 +02:00
|
|
|
if isDeclaration {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-11 20:50:00 +02:00
|
|
|
if err := validateAttributeName(name); err != nil {
|
|
|
|
|
return fmt.Errorf("tag %s: %w", name, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, ci := range c {
|
|
|
|
|
if tag, ok := ci.(Tag); ok {
|
2025-10-05 14:27:48 +02:00
|
|
|
if rg.script {
|
2025-09-11 20:50:00 +02:00
|
|
|
return fmt.Errorf("tag %s does not allow child elements", name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var v validator
|
|
|
|
|
tag(&v)
|
|
|
|
|
if v.err != nil {
|
|
|
|
|
return v.err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|