diff --git a/fixtures/anyof.json b/fixtures/anyof.json new file mode 100644 index 0000000..8b3d4fe --- /dev/null +++ b/fixtures/anyof.json @@ -0,0 +1,91 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/invopop/jsonschema/root-any-of", + "$ref": "#/$defs/RootAnyOf", + "$defs": { + "ChildAnyOf": { + "anyOf": [ + { + "required": [ + "child1", + "child4" + ], + "title": "group1" + }, + { + "required": [ + "child2", + "child3" + ], + "title": "group2" + } + ], + "properties": { + "child1": { + "type": "string" + }, + "child2": { + "type": "string" + }, + "child3": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array" + } + ] + }, + "child4": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object" + }, + "RootAnyOf": { + "anyOf": [ + { + "required": [ + "field1", + "field4" + ], + "title": "group1" + }, + { + "required": [ + "field2" + ], + "title": "group2" + } + ], + "properties": { + "field1": { + "type": "string" + }, + "field2": { + "type": "string" + }, + "field3": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array" + } + ] + }, + "field4": { + "type": "string" + }, + "child": { + "$ref": "#/$defs/ChildAnyOf" + } + }, + "additionalProperties": false, + "type": "object" + } + } +} \ No newline at end of file diff --git a/reflect.go b/reflect.go index 36ee30a..06e8a3a 100644 --- a/reflect.go +++ b/reflect.go @@ -683,6 +683,21 @@ func (t *Schema) genericKeywords(tags []string, parent *Schema, propertyName str parent.OneOf = append(parent.OneOf, typeFound) } typeFound.Required = append(typeFound.Required, propertyName) + case "anyof_required": + var typeFound *Schema + for i := range parent.AnyOf { + if parent.AnyOf[i].Title == nameValue[1] { + typeFound = parent.AnyOf[i] + } + } + if typeFound == nil { + typeFound = &Schema{ + Title: nameValue[1], + Required: []string{}, + } + parent.AnyOf = append(parent.AnyOf, typeFound) + } + typeFound.Required = append(typeFound.Required, propertyName) case "oneof_type": if t.OneOf == nil { t.OneOf = make([]*Schema, 0, 1) @@ -694,6 +709,17 @@ func (t *Schema) genericKeywords(tags []string, parent *Schema, propertyName str Type: ty, }) } + case "anyof_type": + if t.AnyOf == nil { + t.AnyOf = make([]*Schema, 0, 1) + } + t.Type = "" + types := strings.Split(nameValue[1], ";") + for _, ty := range types { + t.AnyOf = append(t.AnyOf, &Schema{ + Type: ty, + }) + } case "enum": switch t.Type { case "string": diff --git a/reflect_test.go b/reflect_test.go index 72e6922..2cce0b0 100644 --- a/reflect_test.go +++ b/reflect_test.go @@ -147,6 +147,21 @@ type ChildOneOf struct { Child4 string `json:"child4" jsonschema:"oneof_required=group1"` } +type RootAnyOf struct { + Field1 string `json:"field1" jsonschema:"anyof_required=group1"` + Field2 string `json:"field2" jsonschema:"anyof_required=group2"` + Field3 interface{} `json:"field3" jsonschema:"anyof_type=string;array"` + Field4 string `json:"field4" jsonschema:"anyof_required=group1"` + Field5 ChildAnyOf `json:"child"` +} + +type ChildAnyOf struct { + Child1 string `json:"child1" jsonschema:"anyof_required=group1"` + Child2 string `json:"child2" jsonschema:"anyof_required=group2"` + Child3 interface{} `json:"child3" jsonschema:"anyof_required=group2,oneof_type=string;array"` + Child4 string `json:"child4" jsonschema:"anyof_required=group1"` +} + type Text string type TextNamed string @@ -331,6 +346,7 @@ func TestSchemaGeneration(t *testing.T) { {&TestUser{}, &Reflector{DoNotReference: true}, "fixtures/no_reference.json"}, {&TestUser{}, &Reflector{DoNotReference: true, AssignAnchor: true}, "fixtures/no_reference_anchor.json"}, {&RootOneOf{}, &Reflector{RequiredFromJSONSchemaTags: true}, "fixtures/oneof.json"}, + {&RootAnyOf{}, &Reflector{RequiredFromJSONSchemaTags: true}, "fixtures/anyof.json"}, {&CustomTypeField{}, &Reflector{ Mapper: func(i reflect.Type) *Schema { if i == reflect.TypeOf(CustomTime{}) {