123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- package jsonschema
- import (
- "bytes"
- "encoding/json"
- "errors"
- )
- // Schema holds a JSON schema.
- type Schema struct {
- // Name is the name of the property. For the parent/root property, this
- // is "root". For child properties, this is the name of the property.
- Name string `json:"-"`
- // Type is the type of the property.
- //
- // TODO: Union types (e.g. make this a []string).
- Type string
- // PrefixItems is a list of schemas for each item in a tuple. By
- // default, the tuple is "closed." unless Items is set to true or a
- // valid Schema.
- PrefixItems []*Schema
- // Items is the schema for each item in a list.
- //
- // If it is missing, or its JSON value is "null" or "false", it is nil.
- // If the JSON value is "true", it is set to the empty Schema. If the
- // JSON value is an object, it will be decoded as a Schema.
- Items *Schema
- // MinItems specifies the minimum number of items allowed in a list.
- MinItems int
- // MaxItems specifies the maximum number of items allowed in a list.
- MaxItems int
- // Properties is the schema for each property of an object.
- Properties []*Schema
- // Format is the format of the property. This is used to validate the
- // property against a specific format.
- //
- // It is the callers responsibility to validate the property against
- // the format.
- Format string
- // Minimum specifies the minimum value for numeric properties.
- Minimum float64
- // Maximum specifies the maximum value for numeric properties.
- Maximum float64
- // Enum is a list of valid values for the property.
- Enum []json.RawMessage
- }
- func (s *Schema) UnmarshalJSON(data []byte) error {
- type S Schema
- w := struct {
- Properties props
- Items items
- *S
- }{
- S: (*S)(s),
- }
- if err := json.Unmarshal(data, &w); err != nil {
- return err
- }
- if w.Items.set {
- s.Items = &w.Items.Schema
- }
- s.Properties = w.Properties
- return nil
- }
- type items struct {
- Schema
- set bool
- }
- func (s *items) UnmarshalJSON(data []byte) error {
- switch b := data[0]; b {
- case 't':
- *s = items{set: true}
- case '{':
- type I items
- if err := json.Unmarshal(data, (*I)(s)); err != nil {
- return err
- }
- s.set = true
- case 'n', 'f':
- default:
- return errors.New("invalid Items")
- }
- return nil
- }
- // EffectiveType returns the effective type of the schema. If the Type field is
- // not empty, it is returned; otherwise:
- //
- // - If the schema has both Properties and Items, it returns an empty string.
- // - If the schema has Properties, it returns "object".
- // - If the schema has Items, it returns "array".
- // - If the schema has neither Properties nor Items, it returns "value".
- //
- // The returned string is never empty.
- func (d *Schema) EffectiveType() string {
- if d.Type == "" {
- if len(d.Properties) > 0 {
- return "object"
- }
- if len(d.PrefixItems) > 0 || d.Items != nil {
- return "array"
- }
- return "value"
- }
- return d.Type
- }
- // props is an ordered list of properties. The order of the properties
- // is the order in which they were defined in the schema.
- type props []*Schema
- var _ json.Unmarshaler = (*props)(nil)
- func (v *props) UnmarshalJSON(data []byte) error {
- if len(data) == 0 {
- return nil
- }
- if data[0] != '{' {
- return errors.New("expected object")
- }
- d := json.NewDecoder(bytes.NewReader(data))
- // TODO(bmizerany): Consider DisallowUnknownFields. Currently, we, like
- // llama.cpp, ignore unknown fields, which could be lead to unexpected
- // behavior for clients of this package, since they may not be aware
- // that "additionalFields", "itemsPrefix", etc, are being ignored.
- //
- // For now, just do what llama.cpp does.
- t, err := d.Token()
- if err != nil {
- return err
- }
- if t != json.Delim('{') {
- return errors.New("expected object")
- }
- for d.More() {
- // Use the first token (map key) as the property name, then
- // decode the rest of the object fields into a Schema and
- // append.
- t, err := d.Token()
- if err != nil {
- return err
- }
- if t == json.Delim('}') {
- return nil
- }
- s := &Schema{
- Name: t.(string),
- }
- if err := d.Decode(s); err != nil {
- return err
- }
- *v = append(*v, s)
- }
- return nil
- }
|