feat(08-01): add pkg/dorks foundation (schema, loader, registry, executor)
- Dork schema with Validate() mirroring provider YAML pattern - go:embed loader tolerating empty definitions tree - Registry with List/Get/Stats/ListBySource/ListByCategory - Executor interface + Runner dispatch + ErrSourceNotImplemented - Placeholder definitions/.gitkeep and repo-root dorks/.gitkeep - Full unit test coverage for registry, validation, and runner dispatch
This commit is contained in:
92
pkg/dorks/registry.go
Normal file
92
pkg/dorks/registry.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package dorks
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Registry is the in-memory store of loaded dork definitions. It is built
|
||||
// once at startup (via NewRegistry) and is safe for concurrent reads.
|
||||
type Registry struct {
|
||||
dorks []Dork
|
||||
byID map[string]int
|
||||
bySource map[string][]int
|
||||
byCategory map[string][]int
|
||||
}
|
||||
|
||||
// NewRegistry loads every embedded dork YAML file, validates them, and
|
||||
// returns a ready-to-query Registry. An empty definitions tree is tolerated
|
||||
// and yields an empty (but non-nil) Registry.
|
||||
func NewRegistry() (*Registry, error) {
|
||||
ds, err := loadDorks()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading dorks: %w", err)
|
||||
}
|
||||
return NewRegistryFromDorks(ds), nil
|
||||
}
|
||||
|
||||
// NewRegistryFromDorks builds a Registry from an explicit slice of dorks
|
||||
// without touching the embedded filesystem. Intended for tests.
|
||||
func NewRegistryFromDorks(ds []Dork) *Registry {
|
||||
r := &Registry{
|
||||
dorks: make([]Dork, len(ds)),
|
||||
byID: make(map[string]int, len(ds)),
|
||||
bySource: make(map[string][]int),
|
||||
byCategory: make(map[string][]int),
|
||||
}
|
||||
copy(r.dorks, ds)
|
||||
for i, d := range r.dorks {
|
||||
r.byID[d.ID] = i
|
||||
r.bySource[d.Source] = append(r.bySource[d.Source], i)
|
||||
r.byCategory[d.Category] = append(r.byCategory[d.Category], i)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// List returns all loaded dorks. The returned slice must not be mutated.
|
||||
func (r *Registry) List() []Dork {
|
||||
return r.dorks
|
||||
}
|
||||
|
||||
// Get returns the dork with the given id and a boolean indicating whether it
|
||||
// was found.
|
||||
func (r *Registry) Get(id string) (Dork, bool) {
|
||||
idx, ok := r.byID[id]
|
||||
if !ok {
|
||||
return Dork{}, false
|
||||
}
|
||||
return r.dorks[idx], true
|
||||
}
|
||||
|
||||
// ListBySource returns every dork declared for the given source.
|
||||
func (r *Registry) ListBySource(source string) []Dork {
|
||||
idxs := r.bySource[source]
|
||||
out := make([]Dork, 0, len(idxs))
|
||||
for _, i := range idxs {
|
||||
out = append(out, r.dorks[i])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ListByCategory returns every dork tagged with the given category.
|
||||
func (r *Registry) ListByCategory(category string) []Dork {
|
||||
idxs := r.byCategory[category]
|
||||
out := make([]Dork, 0, len(idxs))
|
||||
for _, i := range idxs {
|
||||
out = append(out, r.dorks[i])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Stats returns aggregate counts grouped by source and category.
|
||||
func (r *Registry) Stats() Stats {
|
||||
s := Stats{
|
||||
Total: len(r.dorks),
|
||||
BySource: make(map[string]int, len(r.bySource)),
|
||||
ByCategory: make(map[string]int, len(r.byCategory)),
|
||||
}
|
||||
for src, idxs := range r.bySource {
|
||||
s.BySource[src] = len(idxs)
|
||||
}
|
||||
for cat, idxs := range r.byCategory {
|
||||
s.ByCategory[cat] = len(idxs)
|
||||
}
|
||||
return s
|
||||
}
|
||||
Reference in New Issue
Block a user