diff --git a/README.md b/README.md index 100ad0c..4510cd2 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ type TestUser struct { BirthDate time.Time `json:"birth_date,omitempty" jsonschema:"oneof_required=date"` YearOfBirth string `json:"year_of_birth,omitempty" jsonschema:"oneof_required=year"` Metadata interface{} `json:"metadata,omitempty" jsonschema:"oneof_type=string;array"` + IPAddress2 interface{} `json:"ip_address2,omitempty" jsonschema:"anyof_ref=#/$defs/ipv4;#/$defs/ipv6"` + IPAddresses2 []interface{} `json:"ip_addresses2,omitempty" jsonschema:"anyof_ref=#/$defs/ipv4;#/$defs/ipv6"` FavColor string `json:"fav_color,omitempty" jsonschema:"enum=red,enum=green,enum=blue"` } ``` @@ -49,7 +51,8 @@ jsonschema.Reflect(&TestUser{}) ```json { - "$schema": "http://json-schema.org/draft/2020-12/schema", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/invopop/jsonschema_test/sample-user", "$ref": "#/$defs/SampleUser", "$defs": { "SampleUser": { @@ -103,6 +106,29 @@ jsonschema.Reflect(&TestUser{}) } ] }, + "ip_address2": { + "anyOf": [ + { + "$ref": "#/$defs/ipv4" + }, + { + "$ref": "#/$defs/ipv6" + } + ] + }, + "ip_addresses2": { + "items": { + "anyOf": [ + { + "$ref": "#/$defs/ipv4" + }, + { + "$ref": "#/$defs/ipv6" + } + ] + }, + "type": "array" + }, "fav_color": { "type": "string", "enum": ["red", "green", "blue"] diff --git a/examples_test.go b/examples_test.go index 82cae05..603becc 100644 --- a/examples_test.go +++ b/examples_test.go @@ -9,14 +9,16 @@ import ( ) type SampleUser struct { - ID int `json:"id"` - Name string `json:"name" jsonschema:"title=the name,description=The name of a friend,example=joe,example=lucy,default=alex"` - Friends []int `json:"friends,omitempty" jsonschema_description:"The list of IDs, omitted when empty"` - Tags map[string]interface{} `json:"tags,omitempty" jsonschema_extras:"a=b,foo=bar,foo=bar1"` - BirthDate time.Time `json:"birth_date,omitempty" jsonschema:"oneof_required=date"` - YearOfBirth string `json:"year_of_birth,omitempty" jsonschema:"oneof_required=year"` - Metadata interface{} `json:"metadata,omitempty" jsonschema:"oneof_type=string;array"` - FavColor string `json:"fav_color,omitempty" jsonschema:"enum=red,enum=green,enum=blue"` + ID int `json:"id"` + Name string `json:"name" jsonschema:"title=the name,description=The name of a friend,example=joe,example=lucy,default=alex"` + Friends []int `json:"friends,omitempty" jsonschema_description:"The list of IDs, omitted when empty"` + Tags map[string]interface{} `json:"tags,omitempty" jsonschema_extras:"a=b,foo=bar,foo=bar1"` + BirthDate time.Time `json:"birth_date,omitempty" jsonschema:"oneof_required=date"` + YearOfBirth string `json:"year_of_birth,omitempty" jsonschema:"oneof_required=year"` + Metadata interface{} `json:"metadata,omitempty" jsonschema:"oneof_type=string;array"` + IPAddress2 interface{} `json:"ip_address2,omitempty" jsonschema:"anyof_ref=#/$defs/ipv4;#/$defs/ipv6"` + IPAddresses2 []interface{} `json:"ip_addresses2,omitempty" jsonschema:"anyof_ref=#/$defs/ipv4;#/$defs/ipv6"` + FavColor string `json:"fav_color,omitempty" jsonschema:"enum=red,enum=green,enum=blue"` } func ExampleReflect() { @@ -93,6 +95,29 @@ func ExampleReflect() { // } // ] // }, + // "ip_address2": { + // "anyOf": [ + // { + // "$ref": "#/$defs/ipv4" + // }, + // { + // "$ref": "#/$defs/ipv6" + // } + // ] + // }, + // "ip_addresses2": { + // "items": { + // "anyOf": [ + // { + // "$ref": "#/$defs/ipv4" + // }, + // { + // "$ref": "#/$defs/ipv6" + // } + // ] + // }, + // "type": "array" + // }, // "fav_color": { // "type": "string", // "enum": [ diff --git a/fixtures/anyof.json b/fixtures/anyof.json index 8b3d4fe..bf768a1 100644 --- a/fixtures/anyof.json +++ b/fixtures/anyof.json @@ -82,6 +82,19 @@ }, "child": { "$ref": "#/$defs/ChildAnyOf" + }, + "field6": { + "anyOf": [ + { + "$ref": "Outer" + }, + { + "$ref": "OuterNamed" + }, + { + "$ref": "OuterPtr" + } + ] } }, "additionalProperties": false, diff --git a/reflect.go b/reflect.go index 6ebc6be..1796fa6 100644 --- a/reflect.go +++ b/reflect.go @@ -720,6 +720,21 @@ func (t *Schema) genericKeywords(tags []string, parent *Schema, propertyName str parent.AnyOf = append(parent.AnyOf, typeFound) } typeFound.Required = append(typeFound.Required, propertyName) + case "anyof_ref": + subSchema := t + if t.Items != nil { + subSchema = t.Items + } + if subSchema.AnyOf == nil { + subSchema.AnyOf = make([]*Schema, 0, 1) + } + subSchema.Ref = "" + refs := strings.Split(nameValue[1], ";") + for _, r := range refs { + subSchema.AnyOf = append(subSchema.AnyOf, &Schema{ + Ref: r, + }) + } case "oneof_type": if t.OneOf == nil { t.OneOf = make([]*Schema, 0, 1) diff --git a/reflect_test.go b/reflect_test.go index c0d2c9f..e36213e 100644 --- a/reflect_test.go +++ b/reflect_test.go @@ -153,6 +153,7 @@ type RootAnyOf struct { Field3 interface{} `json:"field3" jsonschema:"anyof_type=string;array"` Field4 string `json:"field4" jsonschema:"anyof_required=group1"` Field5 ChildAnyOf `json:"child"` + Field6 interface{} `json:"field6" jsonschema:"anyof_ref=Outer;OuterNamed;OuterPtr"` } type ChildAnyOf struct {