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 }