package interp import ( "errors" "fmt" "io/fs" "sync" "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 { FormatGroups map[string]decode.Group formatResolveOnce sync.Once formatResolved bool EnvFuncFns []EnvFuncFn FSs []fs.ReadDirFS } func NewRegistry() *Registry { return &Registry{ FormatGroups: map[string]decode.Group{}, formatResolveOnce: sync.Once{}, } } func (r *Registry) format(groupName string, format decode.Format, single bool) { if r.formatResolved { // for now can't change after resolved panic("registry already resolved") } group, ok := r.FormatGroups[groupName] if ok { if !single { panic(fmt.Sprintf("%s: format already registered", groupName)) } } else { group = decode.Group{} } r.FormatGroups[groupName] = append(group, format) } func (r *Registry) Format(format decode.Format) decode.Format { r.format(format.Name, format, false) for _, g := range format.Groups { r.format(g, format, true) } r.format("all", format, true) 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, func(a, b decode.Format) bool { if a.ProbeOrder == b.ProbeOrder { return a.Name < b.Name } return a.ProbeOrder < b.ProbeOrder }) } func (r *Registry) resolveFormats() error { for _, fs := range r.FormatGroups { for _, f := range fs { for _, d := range f.Dependencies { var group decode.Group for _, dName := range d.Names { df, ok := r.FormatGroups[dName] if !ok { return fmt.Errorf("%s: can't find format dependency %s", f.Name, dName) } group = append(group, df...) } sortFormats(group) *d.Group = group } } } for _, fs := range r.FormatGroups { sortFormats(fs) } r.formatResolved = true return nil } func (r *Registry) FormatGroup(name string) (decode.Group, error) { r.formatResolveOnce.Do(func() { if err := r.resolveFormats(); err != nil { panic(err) } }) if g, ok := r.FormatGroups[name]; ok { return g, nil } return nil, errors.New("format group not found") } func (r *Registry) MustFormatGroup(name string) decode.Group { g, err := r.FormatGroup(name) if err == nil { return g } panic(err) } func (r *Registry) MustAll() decode.Group { return r.MustFormatGroup("all") }