1
0
html/validate.go
2025-10-06 00:37:10 +02:00

77 lines
1.3 KiB
Go

package html
import (
"errors"
"fmt"
"regexp"
"strings"
)
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 {
if strings.HasPrefix(name, "!") {
return nil
}
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)
}
isDeclaration := strings.HasPrefix(name, "!")
for _, ai := range a {
for _, name := range ai.names {
if isDeclaration {
continue
}
if err := validateAttributeName(name); err != nil {
return fmt.Errorf("tag %s: %w", name, err)
}
}
}
for _, ci := range c {
if tag, ok := ci.(Tag); ok {
if rg.script {
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
}