1
1
mirror of https://github.com/wader/fq.git synced 2024-11-23 09:56:07 +03:00
fq/pkg/interp/registry.go
Mattias Wadman 0d0147643a gomod: Update x/exp and gomarkdown
Add cmp package from go 1.21 to have cmp.Compare to make sort easier
2023-08-09 14:36:51 +02:00

128 lines
2.6 KiB
Go

package interp
import (
"errors"
"fmt"
"io/fs"
"strings"
"sync"
"github.com/wader/fq/internal/cmpex"
"github.com/wader/fq/internal/gojqex"
"github.com/wader/fq/pkg/decode"
"golang.org/x/exp/slices"
)
type EnvFuncFn func(env *Interp) gojqex.Function
type Registry struct {
allGroup *decode.Group
groups map[string]*decode.Group
formatResolveOnce sync.Once
formatResolved bool
EnvFuncFns []EnvFuncFn
FSs []fs.ReadDirFS
}
func NewRegistry() *Registry {
return &Registry{
allGroup: &decode.Group{Name: "all"},
groups: map[string]*decode.Group{},
formatResolveOnce: sync.Once{},
}
}
func (r *Registry) Format(group *decode.Group, format *decode.Format) *decode.Format {
if r.formatResolved {
// for now can't change after resolved
panic("registry already resolved")
}
if _, ok := r.groups[group.Name]; ok {
panic(fmt.Sprintf("%s: format already registered", group.Name))
}
group.Formats = append(group.Formats, format)
r.groups[group.Name] = group
format.Name = group.Name
for _, g := range format.Groups {
r.groups[g.Name] = g
g.Formats = append(g.Formats, format)
}
r.allGroup.Formats = append(r.allGroup.Formats, format)
return format
}
func (r *Registry) FS(fs fs.ReadDirFS) {
r.FSs = append(r.FSs, fs)
}
func (r *Registry) Func(funcFn EnvFuncFn) {
r.EnvFuncFns = append(r.EnvFuncFns, funcFn)
}
func sortFormats(g *decode.Group) {
slices.SortFunc(g.Formats, func(a, b *decode.Format) int {
if a.ProbeOrder == b.ProbeOrder {
return strings.Compare(a.Name, b.Name)
}
return cmpex.Compare(a.ProbeOrder, b.ProbeOrder)
})
}
func (r *Registry) resolveGroups() {
r.formatResolveOnce.Do(func() {
for _, g := range r.groups {
for _, f := range g.Formats {
for _, d := range f.Dependencies {
if len(d.Out.Formats) != 0 {
// already resolved
continue
}
for _, dg := range d.Groups {
d.Out.Formats = append(d.Out.Formats, dg.Formats...)
}
sortFormats(d.Out)
}
}
}
for _, g := range r.groups {
sortFormats(g)
}
r.formatResolved = true
})
}
func (r *Registry) Group(name string) (*decode.Group, error) {
r.resolveGroups()
if g, ok := r.groups[name]; ok {
return g, nil
}
return nil, errors.New("format group not found")
}
func (r *Registry) MustGroup(name string) *decode.Group {
g, err := r.Group(name)
if err == nil {
return g
}
panic(err)
}
func (r *Registry) Groups() map[string]*decode.Group {
r.resolveGroups()
return r.groups
}
func (r *Registry) MustAll() *decode.Group {
r.resolveGroups()
return r.allGroup
}