Skip to content

Commit 445e55b

Browse files
authored
[Generator] Fix nested coding (#271)
[Generator] Fix nested coding ### Motivation Fixes #263. Depends on apple/swift-openapi-runtime#50. ### Modifications This started as a "simple" fix for Date coding, which was broken when nested in oneOf/allOf/anyOf, and resulted in a refactoring of how we generate custom Codable implementations. I wrote it up in a new article for maintainers, that has all the detail that should explain this PR: https://github.com/apple/swift-openapi-generator/blob/d735ac18354cee03bd3b087e229948593394e9c0/Sources/swift-openapi-generator/Documentation.docc/Development/Generating-custom-Codable-conformance-methods.md ### Result Now Dates are correctly encoded/decoded even when nested in oneOf/allOf/anyOf. ### Test Plan Updated reference tests to cover more of these tricky cases (that's why they were added to the file-based reference tests), updated snippet tests as well, and unit tests. Verified that the motivating use case - the k8s API, now parses responses correctly when Dates are nested in allOf. Reviewed by: glbrntt Builds: ✔︎ pull request validation (5.8) - Build finished. ✔︎ pull request validation (5.9) - Build finished. ✔︎ pull request validation (compatibility test) - Build finished. ✔︎ pull request validation (docc test) - Build finished. ✔︎ pull request validation (integration test) - Build finished. ✔︎ pull request validation (nightly) - Build finished. ✔︎ pull request validation (soundness) - Build finished. #271
1 parent 2b00744 commit 445e55b

File tree

13 files changed

+659
-100
lines changed

13 files changed

+659
-100
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ let package = Package(
8080
// Tests-only: Runtime library linked by generated code, and also
8181
// helps keep the runtime library new enough to work with the generated
8282
// code.
83-
.package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.2.0")),
83+
.package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.2.2")),
8484

8585
// Build and preview docs
8686
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),

Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ extension FileTranslator {
4141
type: AllOrAnyOf,
4242
schemas: [JSONSchema]
4343
) throws -> Declaration {
44-
let properties: [PropertyBlueprint] =
44+
let properties: [(property: PropertyBlueprint, isKeyValuePair: Bool)] =
4545
try schemas
4646
.enumerated()
4747
.map { index, schema in
@@ -75,23 +75,30 @@ extension FileTranslator {
7575
} else {
7676
associatedDeclarations = []
7777
}
78-
return PropertyBlueprint(
78+
let blueprint = PropertyBlueprint(
7979
comment: comment,
8080
originalName: key,
8181
typeUsage: propertyType,
8282
associatedDeclarations: associatedDeclarations,
8383
asSwiftSafeName: swiftSafeName
8484
)
85+
let isKeyValuePairSchema = try TypeMatcher.isKeyValuePair(
86+
schema,
87+
components: components
88+
)
89+
return (blueprint, isKeyValuePairSchema)
8590
}
8691
let comment: Comment? =
8792
typeName
8893
.docCommentWithUserDescription(openAPIDescription)
94+
let isKeyValuePairValues = properties.map(\.isKeyValuePair)
95+
let propertyValues = properties.map(\.property)
8996
let codableStrategy: StructBlueprint.OpenAPICodableStrategy
9097
switch type {
9198
case .allOf:
92-
codableStrategy = .allOf
99+
codableStrategy = .allOf(propertiesIsKeyValuePairSchema: isKeyValuePairValues)
93100
case .anyOf:
94-
codableStrategy = .anyOf
101+
codableStrategy = .anyOf(propertiesIsKeyValuePairSchema: isKeyValuePairValues)
95102
}
96103
let structDecl = translateStructBlueprint(
97104
.init(
@@ -101,7 +108,7 @@ extension FileTranslator {
101108
conformances: Constants.ObjectStruct.conformances,
102109
shouldGenerateCodingKeys: false,
103110
codableStrategy: codableStrategy,
104-
properties: properties
111+
properties: propertyValues
105112
)
106113
)
107114
return structDecl
@@ -124,7 +131,7 @@ extension FileTranslator {
124131
discriminator: OpenAPI.Discriminator?,
125132
schemas: [JSONSchema]
126133
) throws -> Declaration {
127-
let cases: [(String, [String]?, Comment?, TypeUsage, [Declaration])]
134+
let cases: [(String, [String]?, Bool, Comment?, TypeUsage, [Declaration])]
128135
if let discriminator {
129136
// > When using the discriminator, inline schemas will not be considered.
130137
// > — https://spec.openapis.org/oas/v3.0.3#discriminator-object
@@ -147,7 +154,7 @@ extension FileTranslator {
147154
parent: typeName
148155
)
149156
let caseName = safeSwiftNameForOneOfMappedType(mappedType)
150-
return (caseName, mappedType.rawNames, comment, mappedType.typeName.asUsage, [])
157+
return (caseName, mappedType.rawNames, true, comment, mappedType.typeName.asUsage, [])
151158
}
152159
} else {
153160
cases = try schemas.enumerated()
@@ -183,12 +190,16 @@ extension FileTranslator {
183190
} else {
184191
associatedDeclarations = []
185192
}
186-
return (caseName, nil, comment, childType, associatedDeclarations)
193+
let isKeyValuePair = try TypeMatcher.isKeyValuePair(
194+
schema,
195+
components: components
196+
)
197+
return (caseName, nil, isKeyValuePair, comment, childType, associatedDeclarations)
187198
}
188199
}
189200

190201
let caseDecls: [Declaration] = cases.flatMap { caseInfo in
191-
let (caseName, _, comment, childType, associatedDeclarations) = caseInfo
202+
let (caseName, _, _, comment, childType, associatedDeclarations) = caseInfo
192203
return associatedDeclarations + [
193204
.commentable(
194205
comment,
@@ -205,8 +216,6 @@ extension FileTranslator {
205216
]
206217
}
207218

208-
let caseNames = cases.map(\.0)
209-
210219
let codingKeysDecls: [Declaration]
211220
let decoder: Declaration
212221
if let discriminator {
@@ -232,11 +241,11 @@ extension FileTranslator {
232241
} else {
233242
codingKeysDecls = []
234243
decoder = translateOneOfWithoutDiscriminatorDecoder(
235-
caseNames: caseNames
244+
cases: cases.map { ($0.0, $0.2) }
236245
)
237246
}
238247

239-
let encoder = translateOneOfEncoder(caseNames: caseNames)
248+
let encoder = translateOneOfEncoder(cases: cases.map { ($0.0, $0.2) })
240249

241250
let comment: Comment? =
242251
typeName

0 commit comments

Comments
 (0)