diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseOutcome.swift b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseOutcome.swift index a5187b4d..5fb29ce3 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseOutcome.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseOutcome.swift @@ -23,17 +23,18 @@ extension TypesFileTranslator { /// - operation: The OpenAPI operation. /// - operationJSONPath: The JSON path to the operation in the OpenAPI /// document. - /// - Returns: A declaration of the enum case and a declaration of the + /// - Returns: A tuple containing a declaration of the enum case, a declaration of the /// structure unique to the response that contains the response headers - /// and a body payload. + /// and a body payload, a declaration of a throwing getter and, an optional convenience static property. /// - Throws: An error if there's an issue generating the declarations, such /// as unsupported response types or invalid definitions. func translateResponseOutcomeInTypes( _ outcome: OpenAPI.Operation.ResponseOutcome, operation: OperationDescription, operationJSONPath: String - ) throws -> (payloadStruct: Declaration?, enumCase: Declaration, throwingGetter: Declaration) { - + ) throws -> ( + payloadStruct: Declaration?, enumCase: Declaration, staticMember: Declaration?, throwingGetter: Declaration + ) { let typedResponse = try typedResponse(from: outcome, operation: operation) let responseStructTypeName = typedResponse.typeUsage.typeName let responseKind = outcome.status.value.asKind @@ -55,14 +56,36 @@ extension TypesFileTranslator { } associatedValues.append(.init(type: .init(responseStructTypeName))) - let enumCaseDesc = EnumCaseDescription(name: enumCaseName, kind: .nameWithAssociatedValues(associatedValues)) - let enumCaseDecl: Declaration = .commentable( - responseKind.docComment( - userDescription: typedResponse.response.description, - jsonPath: operationJSONPath + "/responses/" + responseKind.jsonPathComponent - ), - .enumCase(enumCaseDesc) + let enumCaseDocComment = responseKind.docComment( + userDescription: typedResponse.response.description, + jsonPath: operationJSONPath + "/responses/" + responseKind.jsonPathComponent ) + let enumCaseDesc = EnumCaseDescription(name: enumCaseName, kind: .nameWithAssociatedValues(associatedValues)) + let enumCaseDecl: Declaration = .commentable(enumCaseDocComment, .enumCase(enumCaseDesc)) + + let staticMemberDecl: Declaration? + let responseHasNoHeaders = typedResponse.response.headers?.isEmpty ?? true + let responseHasNoContent = typedResponse.response.content.isEmpty + if responseHasNoContent && responseHasNoHeaders && !responseKind.wantsStatusCode { + let staticMemberDesc = VariableDescription( + accessModifier: config.access, + isStatic: true, + kind: .var, + left: .identifier(.pattern(enumCaseName)), + type: .member(["Self"]), + getter: [ + .expression( + .functionCall( + calledExpression: .dot(enumCaseName), + arguments: [.functionCall(calledExpression: .dot("init"))] + ) + ) + ] + ) + staticMemberDecl = .commentable(enumCaseDocComment, .variable(staticMemberDesc)) + } else { + staticMemberDecl = nil + } let throwingGetterDesc = VariableDescription( accessModifier: config.access, @@ -113,7 +136,7 @@ extension TypesFileTranslator { ) let throwingGetterDecl = Declaration.commentable(throwingGetterComment, .variable(throwingGetterDesc)) - return (responseStructDecl, enumCaseDecl, throwingGetterDecl) + return (responseStructDecl, enumCaseDecl, staticMemberDecl, throwingGetterDecl) } } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateOperations.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateOperations.swift index 55d01890..8beaae76 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateOperations.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateOperations.swift @@ -143,7 +143,8 @@ extension TypesFileTranslator { let documentedMembers: [Declaration] = documentedOutcomes.flatMap { inlineResponseDecl, caseDecl, - throwingGetter in [inlineResponseDecl, caseDecl, throwingGetter].compactMap { $0 } + staticDecl, + throwingGetter in [inlineResponseDecl, caseDecl, staticDecl, throwingGetter].compactMap { $0 } } let allMembers: [Declaration] diff --git a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Types.swift b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Types.swift index 2baf58a2..47b0390d 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Types.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Types.swift @@ -2279,6 +2279,14 @@ public enum Operations { /// /// HTTP response code: `204 noContent`. case noContent(Operations.createPetWithForm.Output.NoContent) + /// Successfully created pet using a url form + /// + /// - Remark: Generated from `#/paths//pets/create/post(createPetWithForm)/responses/204`. + /// + /// HTTP response code: `204 noContent`. + public static var noContent: Self { + .noContent(.init()) + } /// The associated value of the enum case if `self` is `.noContent`. /// /// - Throws: An error if `self` is not `.noContent`. @@ -2499,6 +2507,14 @@ public enum Operations { /// /// HTTP response code: `202 accepted`. case accepted(Operations.postStats.Output.Accepted) + /// Accepted data. + /// + /// - Remark: Generated from `#/paths//pets/stats/post(postStats)/responses/202`. + /// + /// HTTP response code: `202 accepted`. + public static var accepted: Self { + .accepted(.init()) + } /// The associated value of the enum case if `self` is `.accepted`. /// /// - Throws: An error if `self` is not `.accepted`. @@ -2541,6 +2557,14 @@ public enum Operations { /// /// HTTP response code: `204 noContent`. case noContent(Operations.probe.Output.NoContent) + /// Ack + /// + /// - Remark: Generated from `#/paths//probe//post(probe)/responses/204`. + /// + /// HTTP response code: `204 noContent`. + public static var noContent: Self { + .noContent(.init()) + } /// The associated value of the enum case if `self` is `.noContent`. /// /// - Throws: An error if `self` is not `.noContent`. @@ -2626,6 +2650,14 @@ public enum Operations { /// /// HTTP response code: `204 noContent`. case noContent(Operations.updatePet.Output.NoContent) + /// Successfully updated + /// + /// - Remark: Generated from `#/paths//pets/{petId}/patch(updatePet)/responses/204`. + /// + /// HTTP response code: `204 noContent`. + public static var noContent: Self { + .noContent(.init()) + } /// The associated value of the enum case if `self` is `.noContent`. /// /// - Throws: An error if `self` is not `.noContent`. @@ -3098,6 +3130,14 @@ public enum Operations { /// /// HTTP response code: `202 accepted`. case accepted(Operations.multipartUploadTyped.Output.Accepted) + /// Successfully accepted the data. + /// + /// - Remark: Generated from `#/paths//pets/multipart-typed/post(multipartUploadTyped)/responses/202`. + /// + /// HTTP response code: `202 accepted`. + public static var accepted: Self { + .accepted(.init()) + } /// The associated value of the enum case if `self` is `.accepted`. /// /// - Throws: An error if `self` is not `.accepted`.