78 lines
1.3 KiB
Go
78 lines
1.3 KiB
Go
package html
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
var symbolExp = regexp.MustCompile(`^[a-zA-Z][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
|
|
}
|
|
|
|
isDeclaration := strings.HasPrefix(name, "!")
|
|
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)
|
|
}
|
|
|
|
if isDeclaration && len(c) > 0 {
|
|
return fmt.Errorf("declarations cannot have children (%s)", 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
|
|
}
|