1
0
html/query.go

135 lines
2.2 KiB
Go

package html
type nameQuery struct {
value string
}
type attributesQuery struct {
value Attributes
}
type attributeQuery struct {
name string
value any
found bool
}
type childrenQuery struct {
value []any
}
type validator struct {
err error
}
type renderGuidesQuery struct {
value []renderGuide
}
func groupChildren(c []any) ([]Attributes, []any, []renderGuide) {
var (
a []Attributes
cc []any
rg []renderGuide
)
for _, ci := range c {
if ai, ok := ci.(Attributes); ok {
a = append(a, ai)
continue
}
if rgi, ok := ci.(renderGuide); ok {
rg = append(rg, rgi)
continue
}
cc = append(cc, ci)
}
return a, cc, rg
}
func mergeAttributes(c []any) Attributes {
a, _, _ := groupChildren(c)
if len(a) == 0 {
return Attributes{}
}
to := Attributes{values: make(map[string]any)}
for i := len(a) - 1; i >= 0; i-- {
for _, name := range a[i].names {
if _, set := to.values[name]; set {
continue
}
to.names = append(to.names, name)
to.values[name] = a[i].values[name]
}
}
return to
}
func findAttribute(c []any, name string) (any, bool) {
a, _, _ := groupChildren(c)
for i := len(a) - 1; i >= 0; i-- {
value, ok := a[i].values[name]
if ok {
return value, true
}
}
return nil, false
}
func handleQuery(name string, children []any) bool {
if len(children) == 0 {
return false
}
last := len(children) - 1
lastChild := children[last]
if q, ok := lastChild.(*nameQuery); ok {
q.value = name
return true
}
if q, ok := lastChild.(*attributesQuery); ok {
q.value = mergeAttributes(children[:last])
return true
}
if q, ok := lastChild.(*attributeQuery); ok {
q.value, q.found = findAttribute(children[:last], q.name)
return true
}
if q, ok := lastChild.(*childrenQuery); ok {
_, q.value, _ = groupChildren(children[:last])
return true
}
if q, ok := lastChild.(*renderGuidesQuery); ok {
_, _, q.value = groupChildren(children[:last])
return true
}
if v, ok := lastChild.(*validator); ok {
v.err = validate(name, children[:last])
return true
}
if r, ok := lastChild.(*renderer); ok {
if err := validate(name, children[:last]); err != nil {
r.err = err
return true
}
r.render(name, children[:last])
return true
}
return false
}