squadron/internal/jsonschema/jsonschema.go
Kevin Franklin Kim 4b88ffbd15
feat: bump linter
2025-10-10 11:54:31 +02:00

125 lines
3.0 KiB
Go

package jsonschema
import (
"context"
"encoding/json"
"path"
"strings"
"github.com/pkg/errors"
)
// JSONSchema represents the structure of a JSON schema
type JSONSchema struct {
baseSchema map[string]any
}
// New takes a URL to the base JSON schema and returns a JSONSchema instance
func New() *JSONSchema {
return &JSONSchema{}
}
func (js *JSONSchema) LoadBaseSchema(ctx context.Context, url string) error {
baseSchema, err := LoadMap(ctx, url)
if err != nil {
return err
}
js.baseSchema = baseSchema
return nil
}
// SetSquadronUnitSchema overrides the base schema at the given path with another JSON schema from a URL
func (js *JSONSchema) SetSquadronUnitSchema(ctx context.Context, squadron, unit, url string) error {
var ref string
if strings.HasPrefix(url, "http") {
ref = strings.TrimPrefix(url, "https:")
ref = strings.TrimPrefix(ref, "http:")
ref = strings.TrimPrefix(ref, "//")
} else {
ref = path.Clean(url)
ref = strings.TrimPrefix(ref, "..")
ref = strings.TrimPrefix(ref, ".")
ref = strings.TrimPrefix(ref, "/")
}
ref = strings.TrimSuffix(ref, "/")
ref = strings.ReplaceAll(ref, "/", "-")
ref = strings.ToLower(ref)
// retrieve definitions
defsMap := js.ensure(js.baseSchema, "$defs", map[string]any{})
// add definition
if _, ok := defsMap[ref]; !ok {
valuesMap, err := LoadMap(ctx, url)
if err != nil {
return errors.Wrap(err, "failed to load map: "+url)
}
delete(valuesMap, "$schema")
js.ensure(defsMap, ref, valuesMap)
}
// extend Config
configMap := js.ensure(defsMap, "Config", map[string]any{})
configPropertiesMap := js.ensure(configMap, "properties", map[string]any{})
squadronsMap := js.ensure(configPropertiesMap, "squadron", map[string]any{})
squadronsPropertiesMap := js.ensure(squadronsMap, "properties", map[string]any{})
squadronMap := js.ensure(squadronsPropertiesMap, squadron, map[string]any{
"additionalProperties": map[string]any{
"$ref": "#/$defs/Unit",
},
"type": "object",
})
squadronPropertiesMap := js.ensure(squadronMap, "properties", map[string]any{})
_ = js.ensure(squadronPropertiesMap, unit, map[string]any{
"anyOf": []map[string]any{
{
"$ref": "#/$defs/Unit",
},
{
"type": "object",
"properties": map[string]any{
"values": map[string]any{
"$ref": "#/$defs/" + ref,
},
},
},
},
})
return nil
}
// String outputs the resulting JSON schema as string
func (js *JSONSchema) String() (string, error) {
output, err := json.Marshal(js.baseSchema)
if err != nil {
return "", err
}
return string(output), nil
}
// PrettyString outputs the resulting JSON schema as a formatted string
func (js *JSONSchema) PrettyString() (string, error) {
output, err := json.MarshalIndent(js.baseSchema, "", " ")
if err != nil {
return "", err
}
return string(output), nil
}
func (js *JSONSchema) ensure(source map[string]any, name string, initial map[string]any) map[string]any {
ret, ok := source[name].(map[string]any)
if !ok {
ret = initial
source[name] = ret
}
return ret
}