feat: renderer

This commit is contained in:
2025-08-19 17:20:24 +02:00
parent 6db87db325
commit 210b31aef8
38 changed files with 727 additions and 299 deletions

93
validator/validator.go Normal file
View File

@@ -0,0 +1,93 @@
// Package validator provides a validator for the marka data.
package validator
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"sync"
"git.max-richter.dev/max/marka/registry"
"github.com/santhosh-tekuri/jsonschema/v6"
)
var (
loadOnce sync.Once
compiler *jsonschema.Compiler
compileErr error
schemaCache sync.Map
)
// ValidateSchema validates instance against the Schema.org JSON Schema named `schemaName`.
// Examples: ValidateSchema(inst, "Recipe"), ValidateSchema(inst, "schema:Recipe").
func ValidateSchema(instance any, schemaName string) error {
if err := ensureCompiler(); err != nil {
return err
}
ref := normalizeRef(schemaName)
if v, ok := schemaCache.Load(ref); ok {
if err := v.(*jsonschema.Schema).Validate(instance); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
return nil
}
sch, err := compiler.Compile(ref)
if err != nil {
return fmt.Errorf("failed to compile schema %q: %w", ref, err)
}
schemaCache.Store(ref, sch)
if err := sch.Validate(instance); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
return nil
}
func ensureCompiler() error {
loadOnce.Do(func() {
c := jsonschema.NewCompiler()
rawSchemas, err := registry.GetSchemas()
if err != nil {
compileErr = fmt.Errorf("read schema directory: %w", err)
return
}
for _, rawSchema := range rawSchemas {
js, err := jsonschema.UnmarshalJSON(bytes.NewReader(rawSchema))
if err != nil {
compileErr = err
return
}
id := extractID(rawSchema)
if err := c.AddResource(id, js); err != nil {
compileErr = fmt.Errorf("add resource %s: %w", id, err)
return
}
}
compiler = c
})
return compileErr
}
func extractID(raw []byte) string {
var tmp struct {
ID string `json:"$id"`
}
_ = json.Unmarshal(raw, &tmp)
return strings.TrimSpace(tmp.ID)
}
func normalizeRef(name string) string {
n := strings.TrimSpace(name)
if strings.HasPrefix(n, "schema:") || strings.HasPrefix(n, "http://") || strings.HasPrefix(n, "https://") {
return n
}
return "schema:" + n
}