Skip to content

Commit 9d9469f

Browse files
Generate deprecation annotations based on OpenAPI document (#92)
### Motivation The OpenAPI spec supports declaring various parts of the API as deprecated, including operations, parameters, schemas, and properties. These can be surfaced in the generated code by adding `@available(*, deprecated)` annotations to the functions, types, and properties. ### Modifications - Support for deprecated OpenAPI schemas. - Support for deprecated OpenAPI properties. - Support for deprecated OpenAPI operations. For deprecated operations, these are annotated on the function requirements in the generated `APIProtocol`. ### Result Deprecated annotations are generated for the parts of the API marked as deprecated in the OpenAPI document. ### Test Plan - Added `#/components/schemas/DeprecatedObject` to reference test. - Added `#/components/schemas/ObjectWithDeprecatedProperty` to reference test. - Marked `#/paths//probe//post` operation as deprecated in reference test. - Marked `#/components/parameters/My-Request-UUID` parameter as deprecated in reference test. - Unit tests for rendering `DeprecatedDescription` already existed. ### Resolves Resolves #26. --------- Signed-off-by: Si Beaumont <[email protected]>
1 parent 6b11135 commit 9d9469f

File tree

13 files changed

+102
-13
lines changed

13 files changed

+102
-13
lines changed

Sources/_OpenAPIGeneratorCore/Layers/StructuredSwiftRepresentation.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,3 +1451,13 @@ extension KeywordKind {
14511451
.try(hasPostfixQuestionMark: false)
14521452
}
14531453
}
1454+
1455+
extension Declaration {
1456+
/// Returns a new deprecated variant of the declaration if `shouldDeprecate` is true.
1457+
func deprecate(if shouldDeprecate: Bool) -> Self {
1458+
if shouldDeprecate {
1459+
return .deprecated(.init(), self)
1460+
}
1461+
return self
1462+
}
1463+
}

Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ extension FileTranslator {
2626
func translateObjectStruct(
2727
typeName: TypeName,
2828
openAPIDescription: String?,
29-
objectContext: JSONSchema.ObjectContext
29+
objectContext: JSONSchema.ObjectContext,
30+
isDeprecated: Bool
3031
) throws -> Declaration {
3132

3233
let documentedProperties: [PropertyBlueprint] =
@@ -61,6 +62,7 @@ extension FileTranslator {
6162
}
6263
return PropertyBlueprint(
6364
comment: comment,
65+
isDeprecated: value.deprecated,
6466
originalName: key,
6567
typeUsage: propertyType,
6668
associatedDeclarations: associatedDeclarations
@@ -86,6 +88,7 @@ extension FileTranslator {
8688
return translateStructBlueprint(
8789
StructBlueprint(
8890
comment: comment,
91+
isDeprecated: isDeprecated,
8992
access: config.access,
9093
typeName: typeName,
9194
conformances: Constants.ObjectStruct.conformances,

Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ extension FileTranslator {
9090
let objectDecl = try translateObjectStruct(
9191
typeName: typeName,
9292
openAPIDescription: overrides.userDescription ?? coreContext.description,
93-
objectContext: objectContext
93+
objectContext: objectContext,
94+
isDeprecated: coreContext.deprecated
9495
)
9596
return [objectDecl]
9697
case let .string(coreContext, _):

Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStructBlueprint.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,8 @@ extension FileTranslator {
6464
conformances: blueprint.conformances,
6565
members: members
6666
)
67-
let structDecl: Declaration = .struct(structDesc)
6867

69-
guard let comment = blueprint.comment else {
70-
return structDecl
71-
}
72-
return .commentable(comment, structDecl)
68+
return .commentable(blueprint.comment, .struct(structDesc).deprecate(if: blueprint.isDeprecated))
7369
}
7470

7571
/// Returns a declaration of an initializer declared in a structure.
@@ -144,6 +140,7 @@ extension FileTranslator {
144140
type: propertyTypeName
145141
)
146142
)
143+
.deprecate(if: property.isDeprecated)
147144
)
148145
return property.associatedDeclarations + [propertyDecl]
149146
}

Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/StructBlueprint.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ struct StructBlueprint {
2020
/// A documentation comment for the structure.
2121
var comment: Comment?
2222

23+
/// Whether the type should be annotated as deprecated.
24+
var isDeprecated: Bool = false
25+
2326
/// An access modifier.
2427
var access: AccessModifier?
2528

@@ -103,6 +106,9 @@ struct PropertyBlueprint {
103106
/// A documentation comment for the property.
104107
var comment: Comment? = nil
105108

109+
/// Whether the property should be annotated as deprecated.
110+
var isDeprecated: Bool = false
111+
106112
/// The original name of the property specified in the OpenAPI document.
107113
var originalName: String
108114

Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ extension TypesFileTranslator {
4444
associatedDeclarations = []
4545
}
4646
return .init(
47+
isDeprecated: parameter.parameter.deprecated,
4748
originalName: parameter.name,
4849
typeUsage: parameter.typeUsage,
4950
associatedDeclarations: associatedDeclarations

Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateAPIProtocol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ extension TypesFileTranslator {
5757
let function = FunctionDescription(signature: signature)
5858
return .commentable(
5959
operationComment,
60-
.function(function)
60+
.function(function).deprecate(if: description.operation.deprecated)
6161
)
6262
}
6363
}

Tests/OpenAPIGeneratorCoreTests/Translator/CommonTranslations/Test_translateStructBlueprint.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,16 @@ final class Test_translateStructBlueprint: Test_Core {
5353
)
5454
}
5555

56+
func testDeprecatedStruct() throws {
57+
let blueprint = StructBlueprint(isDeprecated: true, typeName: Self.testTypeName, properties: [])
58+
let decl = makeTypesTranslator().translateStructBlueprint(blueprint)
59+
XCTAssertEqual(decl.strippingTopComment.info.kind, .deprecated)
60+
}
61+
5662
func _testStruct(_ blueprint: StructBlueprint) throws -> [DeclInfo] {
5763
let translator = makeTypesTranslator()
5864
let decl = translator.translateStructBlueprint(blueprint)
59-
guard case .struct(let structDecl) = decl else {
65+
guard case .struct(let structDecl) = decl.strippingTopComment else {
6066
throw UnexpectedDeclError(actual: decl.info.kind, expected: .struct)
6167
}
6268
XCTAssertEqual(structDecl.name, "Foo")

Tests/OpenAPIGeneratorReferenceTests/Resources/Docs/petstore.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ paths:
116116
/probe/:
117117
post:
118118
operationId: probe
119+
deprecated: true
119120
responses:
120121
'204':
121122
description: Ack
@@ -202,6 +203,13 @@ components:
202203
schema:
203204
type: integer
204205
format: int64
206+
header.deprecatedHeader:
207+
name: deprecatedHeader
208+
in: header
209+
deprecated: true
210+
description: A deprecated header parameter
211+
schema:
212+
type: string
205213
schemas:
206214
Pet:
207215
type: object
@@ -370,6 +378,17 @@ components:
370378
- $ref: '#/components/schemas/MessagedExercise'
371379
discriminator:
372380
propertyName: kind
381+
DeprecatedObject:
382+
deprecated: true
383+
type: object
384+
properties: {}
385+
additionalProperties: false
386+
ObjectWithDeprecatedProperty:
387+
type: object
388+
properties:
389+
message:
390+
type: string
391+
deprecated: true
373392
responses:
374393
ErrorBadRequest:
375394
description: Bad request

Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Types.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ public protocol APIProtocol: Sendable {
2121
func createPet(_ input: Operations.createPet.Input) async throws -> Operations.createPet.Output
2222
/// - Remark: HTTP `POST /probe/`.
2323
/// - Remark: Generated from `#/paths//probe//post(probe)`.
24-
func probe(_ input: Operations.probe.Input) async throws -> Operations.probe.Output
24+
@available(*, deprecated) func probe(_ input: Operations.probe.Input) async throws
25+
-> Operations.probe.Output
2526
/// Update just a specific property of an existing pet. Nothing is updated if no request body is provided.
2627
///
2728
/// - Remark: HTTP `PATCH /pets/{petId}`.
@@ -577,6 +578,26 @@ public enum Components {
577578
}
578579
}
579580
}
581+
/// - Remark: Generated from `#/components/schemas/DeprecatedObject`.
582+
@available(*, deprecated)
583+
public struct DeprecatedObject: Codable, Equatable, Hashable, Sendable {
584+
/// Creates a new `DeprecatedObject`.
585+
public init() {}
586+
public init(from decoder: Decoder) throws {
587+
try decoder.ensureNoAdditionalProperties(knownKeys: [])
588+
}
589+
}
590+
/// - Remark: Generated from `#/components/schemas/ObjectWithDeprecatedProperty`.
591+
public struct ObjectWithDeprecatedProperty: Codable, Equatable, Hashable, Sendable {
592+
/// - Remark: Generated from `#/components/schemas/ObjectWithDeprecatedProperty/message`.
593+
@available(*, deprecated) public var message: Swift.String?
594+
/// Creates a new `ObjectWithDeprecatedProperty`.
595+
///
596+
/// - Parameters:
597+
/// - message:
598+
public init(message: Swift.String? = nil) { self.message = message }
599+
public enum CodingKeys: String, CodingKey { case message }
600+
}
580601
}
581602
/// Types generated from the `#/components/parameters` section of the OpenAPI document.
582603
public enum Parameters {
@@ -588,6 +609,10 @@ public enum Components {
588609
///
589610
/// - Remark: Generated from `#/components/parameters/path.petId`.
590611
public typealias path_petId = Swift.Int64
612+
/// A deprecated header parameter
613+
///
614+
/// - Remark: Generated from `#/components/parameters/header.deprecatedHeader`.
615+
public typealias header_deprecatedHeader = Swift.String
591616
}
592617
/// Types generated from the `#/components/requestBodies` section of the OpenAPI document.
593618
public enum RequestBodies {

0 commit comments

Comments
 (0)