Skip to content

Commit 735ea1c

Browse files
committed
feat: alias single anyOf/allOf types
fixes #296
1 parent 8e9686a commit 735ea1c

File tree

10 files changed

+221
-0
lines changed

10 files changed

+221
-0
lines changed

pkg/generator/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ type Config struct {
4040
// DisableCustomTypesForMaps configures the generator to avoid creating a custom type for maps,
4141
// and to use the map type directly.
4242
DisableCustomTypesForMaps bool
43+
// AliasSingleAllOfAnyOfRefs will convert types with a single nested anyOf or allOf ref type into a type alias.
44+
AliasSingleAllOfAnyOfRefs bool
4345
}
4446

4547
type SchemaMapping struct {

pkg/generator/schema_generator.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,18 @@ func (g *schemaGenerator) generateAnyOfType(t *schemas.Type, scope nameScope) (c
849849
return nil, errEmptyInAnyOf
850850
}
851851

852+
if g.config.AliasSingleAllOfAnyOfRefs && len(t.AnyOf) == 1 && t.IsEmptyObject() {
853+
childType := t.AnyOf[0]
854+
if childType.Ref != "" {
855+
resolvedType, err := g.resolveRef(childType)
856+
if err == nil {
857+
return g.generateTypeInline(resolvedType, scope)
858+
} else {
859+
g.warner(fmt.Sprintf("Could not resolve ref %q: %v", childType.Ref, err))
860+
}
861+
}
862+
}
863+
852864
rAnyOf := g.resolveRefs(t.AnyOf)
853865

854866
var isCycle bool
@@ -902,6 +914,18 @@ func (g *schemaGenerator) generateAnyOfType(t *schemas.Type, scope nameScope) (c
902914
}
903915

904916
func (g *schemaGenerator) generateAllOfType(t *schemas.Type, scope nameScope) (codegen.Type, error) {
917+
if g.config.AliasSingleAllOfAnyOfRefs && len(t.AllOf) == 1 && t.IsEmptyObject() {
918+
subType := t.AllOf[0]
919+
if subType.Ref != "" {
920+
resolvedType, err := g.resolveRef(subType)
921+
if err == nil {
922+
return g.generateTypeInline(resolvedType, scope)
923+
} else {
924+
g.warner(fmt.Sprintf("Could not resolve subtype ref %q: %v", subType.Ref, err))
925+
}
926+
}
927+
}
928+
905929
rAllOf := g.resolveRefs(t.AllOf)
906930

907931
allOfType, err := schemas.AllOf(rAllOf, t)

pkg/schemas/model.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ type Type struct {
208208
Dereferenced bool `json:"-"` // Marks that his type has been dereferenced.
209209
}
210210

211+
func (value *Type) IsEmptyObject() bool {
212+
return len(value.Properties) == 0 && value.AdditionalProperties == nil
213+
}
214+
211215
func (value *Type) SetSubSchemaType(sst SubSchemaType) {
212216
value.subSchemaType = sst
213217
}

tests/data/aliasSingleAllOfAnyOfRefs/allOf/allOf.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2019-09/schema",
3+
"type": "object",
4+
"allOf": [
5+
{
6+
"$ref": "#/definitions/Thing"
7+
}
8+
],
9+
"definitions": {
10+
"Thing": {
11+
"allOf": [
12+
{
13+
"properties": {
14+
"values": {
15+
"type": "array",
16+
"items": {
17+
"$ref": "#/definitions/Value"
18+
}
19+
}
20+
}
21+
}
22+
]
23+
},
24+
"Value": {
25+
"type": "number"
26+
}
27+
}
28+
}

tests/data/aliasSingleAllOfAnyOfRefs/anyOf/anyOf.go

Lines changed: 90 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2019-09/schema",
3+
"type": "object",
4+
"anyOf": [
5+
{
6+
"$ref": "#/definitions/Thing"
7+
}
8+
],
9+
"definitions": {
10+
"Thing": {
11+
"anyOf": [
12+
{
13+
"properties": {
14+
"values": {
15+
"type": "array",
16+
"items": {
17+
"$ref": "#/definitions/Value"
18+
}
19+
}
20+
}
21+
}
22+
]
23+
},
24+
"Value": {
25+
"type": "number"
26+
}
27+
}
28+
}

tests/data/aliasSingleAllOfAnyOfRefs/externalRef/externalRef.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"id": "https://example.com/refExternalFileAllOfNestedRefs",
4+
"type": "object",
5+
"allOf": [
6+
{
7+
"$ref": "../allOf/allOf.json#/$defs/Thing"
8+
}
9+
]
10+
}

tests/generation_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,15 @@ func TestMinSizeInt(t *testing.T) {
226226
testExamples(t, cfg, "./data/minSizedInts")
227227
}
228228

229+
func TestAliasSingleAllOfAnyOfRefs(t *testing.T) {
230+
t.Parallel()
231+
232+
cfg := basicConfig
233+
cfg.AliasSingleAllOfAnyOfRefs = true
234+
235+
testExamples(t, cfg, "./data/aliasSingleAllOfAnyOfRefs")
236+
}
237+
229238
func TestSchemaExtensions(t *testing.T) {
230239
t.Parallel()
231240

0 commit comments

Comments
 (0)