Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/SwaggerProvider.DesignTime/DefinitionCompiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,12 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: b

providedField, providedProperty

let registerInNsAndInDef tyPath (ns: NamespaceAbstraction) (name, ty: Type) =
let registerInDef tyPath (ty: Type) =
if not <| pathToType.ContainsKey tyPath then
pathToType.Add(tyPath, ty)
//else failwithf "Second time compilation of type definition '%s'. This is a bug in DefinitionCompiler" tyPath

let registerInNsAndInDef tyPath (ns: NamespaceAbstraction) (name, ty: Type) =
registerInDef tyPath ty

match ty with
| :? ProvidedTypeDefinition as prTy -> ns.RegisterType(name, prTy)
Expand All @@ -252,6 +254,8 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: b
| true, def ->
let ns, tyName = tyPath |> DefinitionPath.Parse |> nsRoot.Resolve
let ty = compileBySchema ns tyName def true (registerInNsAndInDef tyPath ns) true
// An alias can resolve to an existing provided type, so only cache its component path here.
registerInDef tyPath ty
ty :> Type
| false, _ when tyPath.StartsWith DefinitionPath.DefinitionPrefix ->
failwithf $"Cannot find definition '%s{tyPath}' in schema definitions %A{pathToType.Keys |> Seq.toArray}"
Expand Down Expand Up @@ -605,6 +609,7 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: b
enumTy.AddMember field
intValue <- intValue + 1L

registerNew(tyName, enumTy :> Type)
enumTy :> Type
| _ ->
ns.MarkTypeAsNameAlias tyName
Expand Down Expand Up @@ -641,9 +646,6 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: b
elTy.MakeArrayType 1
| ty, format -> failwithf $"Type %s{tyName}(%A{ty},%s{format}) should be caught by other match statement (%A{resolvedType})"

if fromByPathCompiler then
registerNew(tyName, tyType)

if isRequired then
tyType
else if tyType.IsValueType then
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"openapi": "3.0.0",
"info": {
"title": "Named oneOf object alias",
"version": "1.0.0"
},
"paths": {
"/parent": {
"get": {
"operationId": "getParent",
"responses": {
"200": {
"description": "Parent response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Parent"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Parent": {
"oneOf": [
{
"$ref": "#/components/schemas/Parent_Child"
}
]
},
"Parent_Child": {
"type": "object",
"required": [
"childValue"
],
"properties": {
"childValue": {
"type": "string"
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Swagger.NamedObjectAliases.Tests

open SwaggerProvider
open Xunit
open FsUnitTyped

[<Literal>]
let Schema = __SOURCE_DIRECTORY__ + "/Schemas/v3/named-object-alias-oneof.json"

type Api = OpenApiClientProvider<Schema, SsrfProtection=false>

[<Fact>]
let ``named component alias response resolves to the referenced object type``() =
let methodInfo =
typeof<Api.Client>.GetMethods()
|> Array.filter(fun candidate -> candidate.Name = "GetParent")
|> Array.exactlyOne

let responseType = methodInfo.ReturnType.GetGenericArguments() |> Array.exactlyOne

responseType |> shouldEqual typeof<Api.Parent_Child>

let response = Api.Parent_Child("oneOf")
response.ChildValue |> shouldEqual "oneOf"
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<Compile Include="Swagger.I0181.Tests.fs" />
<Compile Include="Swagger.I0219.Tests.fs" />
<Compile Include="Swagger.I0279.Tests.fs" />
<Compile Include="Swagger.NamedObjectAliases.Tests.fs" />
<Compile Include="Swagger.NullableDate.Tests.fs" />
<Compile Include="Swagger.SchemaReaderErrors.Tests.fs" />
<Compile Include="Swashbuckle.ReturnControllers.Tests.fs" />
Expand Down
25 changes: 18 additions & 7 deletions tests/SwaggerProvider.Tests/Schema.V3SchemaCompilationTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,13 @@ let private anyOfSingleRefSchema =
}"""

[<Fact>]
let ``allOf single $ref resolves to the referenced type without creating a new object type``() =
let ``allOf single $ref resolves to exactly one referenced type``() =
let types = compileV3Schema allOfSingleRefSchema false
// PetRef collapses into Pet via ReleaseNameReservation; the referenced type is present.
types |> List.exists(fun t -> t.Name = "Pet") |> shouldEqual true
// PetRef collapses into Pet via ReleaseNameReservation; the referenced type is registered once.
types
|> List.filter(fun t -> t.Name = "Pet")
|> List.length
|> shouldEqual 1

[<Fact>]
let ``allOf single $ref does not produce a separate wrapper type``() =
Expand All @@ -89,19 +92,27 @@ let ``allOf single $ref does not produce a separate wrapper type``() =
types |> List.exists(fun t -> t.Name = "PetRef") |> shouldEqual false

[<Fact>]
let ``oneOf single $ref resolves to the referenced type``() =
let ``oneOf single $ref resolves to exactly one referenced type``() =
let types = compileV3Schema oneOfSingleRefSchema false
types |> List.exists(fun t -> t.Name = "Dog") |> shouldEqual true

types
|> List.filter(fun t -> t.Name = "Dog")
|> List.length
|> shouldEqual 1

[<Fact>]
let ``oneOf single $ref does not produce a separate wrapper type``() =
let types = compileV3Schema oneOfSingleRefSchema false
types |> List.exists(fun t -> t.Name = "DogRef") |> shouldEqual false

[<Fact>]
let ``anyOf single $ref resolves to the referenced type``() =
let ``anyOf single $ref resolves to exactly one referenced type``() =
let types = compileV3Schema anyOfSingleRefSchema false
types |> List.exists(fun t -> t.Name = "Cat") |> shouldEqual true

types
|> List.filter(fun t -> t.Name = "Cat")
|> List.length
|> shouldEqual 1

[<Fact>]
let ``anyOf single $ref does not produce a separate wrapper type``() =
Expand Down
Loading