schema: rename nextSpec to ContentSpec.

This commit is contained in:
fiatjaf
2026-01-10 00:01:17 -03:00
parent 0d2dbb13ac
commit 24f89293d9

View File

@@ -48,46 +48,46 @@ func FetchSchemaFromURL(schemaURL string) (Schema, error) {
} }
type Schema struct { type Schema struct {
GenericTags map[string]nextSpec `yaml:"generic_tags"` GenericTags map[string]ContentSpec `yaml:"generic_tags"`
Kinds map[string]KindSchema `yaml:"kinds"` Kinds map[string]KindSchema `yaml:"kinds"`
} }
type KindSchema struct { type KindSchema struct {
Description string `yaml:"description"` Description string `yaml:"description"`
InUse bool `yaml:"in_use"` InUse bool `yaml:"in_use"`
Content nextSpec `yaml:"content"` Content ContentSpec `yaml:"content"`
Required []string `yaml:"required"` Required []string `yaml:"required"`
Multiple []string `yaml:"multiple"` Multiple []string `yaml:"multiple"`
Tags []TagSpec `yaml:"tags"` Tags []TagSpec `yaml:"tags"`
} }
type TagSpec struct { type TagSpec struct {
Name string `yaml:"name"` Name string `yaml:"name"`
Prefix string `yaml:"prefix"` Prefix string `yaml:"prefix"`
Next *nextSpec `yaml:"next"` Next *ContentSpec `yaml:"next"`
} }
type nextSpec struct { type ContentSpec struct {
Type string `yaml:"type"` Type string `yaml:"type"`
Required bool `yaml:"required"` Required bool `yaml:"required"`
Min int `yaml:"min"` Min int `yaml:"min"`
Max int `yaml:"max"` Max int `yaml:"max"`
Either []string `yaml:"either"` Either []string `yaml:"either"`
Next *nextSpec `yaml:"next"` Next *ContentSpec `yaml:"next"`
Variadic bool `yaml:"variadic"` Variadic bool `yaml:"variadic"`
} }
type Validator struct { type Validator struct {
Schema Schema Schema Schema
FailOnUnknownKind bool FailOnUnknownKind bool
FailOnUnknownType bool FailOnUnknownType bool
TypeValidators map[string]func(value string, spec *nextSpec) error TypeValidators map[string]func(value string, spec *ContentSpec) error
UnknownTypes []string UnknownTypes []string
} }
func NewValidatorFromBytes(schemaData []byte) (Validator, error) { func NewValidatorFromBytes(schemaData []byte) (Validator, error) {
schema := Schema{ schema := Schema{
GenericTags: make(map[string]nextSpec), GenericTags: make(map[string]ContentSpec),
Kinds: make(map[string]KindSchema), Kinds: make(map[string]KindSchema),
} }
if err := yaml.Unmarshal(schemaData, &schema); err != nil { if err := yaml.Unmarshal(schemaData, &schema); err != nil {
@@ -100,8 +100,8 @@ func NewValidatorFromBytes(schemaData []byte) (Validator, error) {
func NewValidatorFromSchema(sch Schema) Validator { func NewValidatorFromSchema(sch Schema) Validator {
validator := Validator{ validator := Validator{
Schema: sch, Schema: sch,
TypeValidators: map[string]func(value string, spec *nextSpec) error{ TypeValidators: map[string]func(value string, spec *ContentSpec) error{
"id": func(value string, spec *nextSpec) error { "id": func(value string, spec *ContentSpec) error {
if len(value) != 64 { if len(value) != 64 {
return fmt.Errorf("needed 64 hex chars") return fmt.Errorf("needed 64 hex chars")
} }
@@ -109,39 +109,39 @@ func NewValidatorFromSchema(sch Schema) Validator {
_, err := hex.Decode(hexdummydecoder, unsafe.Slice(unsafe.StringData(value), len(value))) _, err := hex.Decode(hexdummydecoder, unsafe.Slice(unsafe.StringData(value), len(value)))
return err return err
}, },
"pubkey": func(value string, spec *nextSpec) error { "pubkey": func(value string, spec *ContentSpec) error {
_, err := nostr.PubKeyFromHex(value) _, err := nostr.PubKeyFromHex(value)
return err return err
}, },
"addr": func(value string, spec *nextSpec) error { "addr": func(value string, spec *ContentSpec) error {
_, err := nostr.ParseAddrString(value) _, err := nostr.ParseAddrString(value)
return err return err
}, },
"kind": func(value string, spec *nextSpec) error { "kind": func(value string, spec *ContentSpec) error {
if _, err := strconv.ParseUint(value, 10, 16); err != nil { if _, err := strconv.ParseUint(value, 10, 16); err != nil {
return fmt.Errorf("not an unsigned integer: %w", err) return fmt.Errorf("not an unsigned integer: %w", err)
} }
return nil return nil
}, },
"relay": func(value string, spec *nextSpec) error { "relay": func(value string, spec *ContentSpec) error {
if url, err := url.Parse(value); err != nil || (url.Scheme != "ws" && url.Scheme != "wss") { if url, err := url.Parse(value); err != nil || (url.Scheme != "ws" && url.Scheme != "wss") {
return fmt.Errorf("must be ws or wss URL") return fmt.Errorf("must be ws or wss URL")
} }
return nil return nil
}, },
"json": func(value string, spec *nextSpec) error { "json": func(value string, spec *ContentSpec) error {
if !json.Valid(unsafe.Slice(unsafe.StringData(value), len(value))) { if !json.Valid(unsafe.Slice(unsafe.StringData(value), len(value))) {
return ErrInvalidJson return ErrInvalidJson
} }
return nil return nil
}, },
"constrained": func(value string, spec *nextSpec) error { "constrained": func(value string, spec *ContentSpec) error {
if !slices.Contains(spec.Either, value) { if !slices.Contains(spec.Either, value) {
return fmt.Errorf("not in allowed list") return fmt.Errorf("not in allowed list")
} }
return nil return nil
}, },
"hex": func(value string, spec *nextSpec) error { "hex": func(value string, spec *ContentSpec) error {
if spec.Min > 0 && len(value) < spec.Min { if spec.Min > 0 && len(value) < spec.Min {
return fmt.Errorf("hex value too short: %d < %d", len(value), spec.Min) return fmt.Errorf("hex value too short: %d < %d", len(value), spec.Min)
} }
@@ -151,29 +151,29 @@ func NewValidatorFromSchema(sch Schema) Validator {
_, err := hex.Decode(hexdummydecoder, unsafe.Slice(unsafe.StringData(value), len(value))) _, err := hex.Decode(hexdummydecoder, unsafe.Slice(unsafe.StringData(value), len(value)))
return err return err
}, },
"lowercase": func(value string, spec *nextSpec) error { "lowercase": func(value string, spec *ContentSpec) error {
if strings.ToLower(value) != value { if strings.ToLower(value) != value {
return fmt.Errorf("not lowercase") return fmt.Errorf("not lowercase")
} }
return nil return nil
}, },
"timestamp": func(value string, spec *nextSpec) error { "timestamp": func(value string, spec *ContentSpec) error {
_, err := strconv.ParseUint(value, 10, 64) _, err := strconv.ParseUint(value, 10, 64)
return err return err
}, },
"imeta": func(value string, spec *nextSpec) error { "imeta": func(value string, spec *ContentSpec) error {
if len(strings.SplitN(value, " ", 2)) == 2 { if len(strings.SplitN(value, " ", 2)) == 2 {
return nil return nil
} }
return fmt.Errorf("not a space-separated keyval") return fmt.Errorf("not a space-separated keyval")
}, },
"empty": func(value string, spec *nextSpec) error { "empty": func(value string, spec *ContentSpec) error {
if len(value) > 0 { if len(value) > 0 {
return fmt.Errorf("not empty") return fmt.Errorf("not empty")
} }
return nil return nil
}, },
"free": func(value string, spec *nextSpec) error { "free": func(value string, spec *ContentSpec) error {
return nil // accepts anything return nil // accepts anything
}, },
}, },
@@ -341,7 +341,7 @@ func (v *Validator) ValidateEvent(evt nostr.Event) error {
return nil return nil
} }
func collectTypes(spec *nextSpec, visitedTypes []string, cb func(string)) { func collectTypes(spec *ContentSpec, visitedTypes []string, cb func(string)) {
if spec == nil { if spec == nil {
return return
} }
@@ -377,7 +377,7 @@ func (v *Validator) findUnknownTypes(schema Schema) []string {
return unknown return unknown
} }
func (v *Validator) validateNext(tag nostr.Tag, index int, this *nextSpec) (failedIndex int, err error) { func (v *Validator) validateNext(tag nostr.Tag, index int, this *ContentSpec) (failedIndex int, err error) {
if len(tag) <= index { if len(tag) <= index {
if this.Required { if this.Required {
return index, fmt.Errorf("invalid tag '%s', missing index %d", tag[0], index) return index, fmt.Errorf("invalid tag '%s', missing index %d", tag[0], index)