Skip to content

Commit 1ed3e18

Browse files
committed
Improve handling of Optional referenced types.
1 parent d01e68a commit 1ed3e18

File tree

6 files changed

+28
-9
lines changed

6 files changed

+28
-9
lines changed

Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateTypealias.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ extension FileTranslator {
2828
let typealiasDescription = TypealiasDescription(
2929
accessModifier: config.access,
3030
name: typeName.shortSwiftName,
31-
existingType: .init(existingTypeUsage.withOptional(false))
31+
existingType: .init(existingTypeUsage)
3232
)
3333
let typealiasComment: Comment? = typeName.docCommentWithUserDescription(userDescription)
3434
return .commentable(typealiasComment, .typealias(typealiasDescription))

Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ extension TypesFileTranslator {
7070
let decl = try translateSchema(
7171
typeName: typeName,
7272
schema: parameter.schema,
73-
overrides: .init(isOptional: !parameter.required, userDescription: parameter.parameter.description)
73+
overrides: .init(userDescription: parameter.parameter.description)
7474
)
7575
return decl
7676
}

Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseHeader.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ extension TypesFileTranslator {
114114
let decl = try translateSchema(
115115
typeName: typeName,
116116
schema: header.schema,
117-
overrides: .init(isOptional: header.isOptional, userDescription: header.header.description)
117+
overrides: .init(userDescription: header.header.description)
118118
)
119119
return decl
120120
}

Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeAssigner.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ struct TypeAssigner {
345345
swiftComponent: asSwiftSafeName(originalName) + suffix,
346346
jsonComponent: jsonReferenceComponentOverride ?? originalName
347347
)
348-
.asUsage.withOptional(try typeMatcher.isOptional(schema, components: components))
348+
.asUsage.withOptional(try typeMatcher.isOptionalRoot(schema, components: components))
349349
}
350350

351351
/// Returns a type name for a reusable component.

Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeMatcher.swift

+20-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ struct TypeMatcher {
7878
},
7979
genericArrayHandler: { TypeName.arrayContainer.asUsage }
8080
)?
81-
.withOptional(isOptional(schema, components: components))
81+
.withOptional(isOptionalRoot(schema, components: components))
8282
}
8383

8484
/// Returns a Boolean value that indicates whether the schema
@@ -331,6 +331,25 @@ struct TypeMatcher {
331331
return result
332332
}
333333

334+
/// Returns a Boolean value indicating whether the schema is optional at the root of any references.
335+
/// - Parameters:
336+
/// - schema: The reference to check.
337+
/// - components: The OpenAPI components for looking up references.
338+
/// - Throws: An error if there's an issue while checking the schema.
339+
/// - Returns: `true` if the schema is an optional root, `false` otherwise.
340+
func isOptionalRoot(_ schema: JSONSchema, components: OpenAPI.Components) throws -> Bool {
341+
let directlyOptional = schema.nullable || !schema.required
342+
switch schema.value {
343+
case .null(_):
344+
return true
345+
case .reference(let ref, _):
346+
let indirectlyOptional = try isOptional(ref, components: components)
347+
return directlyOptional && !indirectlyOptional
348+
default:
349+
return directlyOptional
350+
}
351+
}
352+
334353
// MARK: - Private
335354

336355
/// Returns the type name of a built-in type that matches the specified

Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ final class SnippetBasedReferenceTests: XCTestCase {
237237
""",
238238
"""
239239
public enum Schemas {
240-
public typealias Null = OpenAPIRuntime.OpenAPIValueContainer
240+
public typealias Null = OpenAPIRuntime.OpenAPIValueContainer?
241241
public typealias NullArray = [Components.Schemas.Null]
242242
}
243243
""")
@@ -520,17 +520,17 @@ final class SnippetBasedReferenceTests: XCTestCase {
520520
"""
521521
public enum Schemas {
522522
public typealias MyRequiredString = Swift.String
523-
public typealias MyNullableString = Swift.String
523+
public typealias MyNullableString = Swift.String?
524524
public struct MyObject: Codable, Hashable, Sendable {
525525
public var id: Swift.Int64
526526
public var alias: Swift.String?
527527
public var requiredString: Components.Schemas.MyRequiredString
528-
public var nullableString: Components.Schemas.MyNullableString?
528+
public var nullableString: Components.Schemas.MyNullableString
529529
public init(
530530
id: Swift.Int64,
531531
alias: Swift.String? = nil,
532532
requiredString: Components.Schemas.MyRequiredString,
533-
nullableString: Components.Schemas.MyNullableString? = nil
533+
nullableString: Components.Schemas.MyNullableString
534534
) {
535535
self.id = id
536536
self.alias = alias

0 commit comments

Comments
 (0)