From 51a60f4f6b2f9576db6511405e4427a1dbbd5195 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Tue, 25 Jul 2023 15:30:03 +0200 Subject: [PATCH] Move ContentType.identifier logic into the translator --- .../Translator/Content/ContentInspector.swift | 2 +- .../Translator/Content/ContentSwiftName.swift | 36 ++++++++++++ .../Translator/Content/ContentType.swift | 13 ----- .../RequestBody/translateRequestBody.swift | 6 +- .../Responses/translateResponse.swift | 2 +- .../Responses/translateResponseOutcome.swift | 4 +- .../TestUtilities.swift | 14 +++-- .../Content/Test_ContentSwiftName.swift | 58 +++++++++++++++++++ 8 files changed, 111 insertions(+), 24 deletions(-) create mode 100644 Sources/_OpenAPIGeneratorCore/Translator/Content/ContentSwiftName.swift create mode 100644 Tests/OpenAPIGeneratorCoreTests/Translator/Content/Test_ContentSwiftName.swift diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift index 50704f3a..b5a2e58a 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift @@ -52,7 +52,7 @@ extension FileTranslator { else { return nil } - let identifier = content.contentType.identifier + let identifier = contentSwiftName(content.contentType) let associatedType = try TypeAssigner.typeUsage( usingNamingHint: identifier, withSchema: content.schema, diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentSwiftName.swift b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentSwiftName.swift new file mode 100644 index 00000000..5efbb552 --- /dev/null +++ b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentSwiftName.swift @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftOpenAPIGenerator open source project +// +// Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// +import OpenAPIKit30 + +extension FileTranslator { + + /// Returns a Swift-safe identifier used as the name of the content + /// enum case. + /// + /// - Parameter contentType: The content type for which to compute the name. + func contentSwiftName(_ contentType: ContentType) -> String { + if config.featureFlags.contains(.multipleContentTypes) { + return "unsupported" + } else { + switch contentType { + case .json: + return "json" + case .text: + return "text" + case .binary: + return "binary" + } + } + } +} diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentType.swift b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentType.swift index 1db30f73..c67f20a1 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentType.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentType.swift @@ -69,19 +69,6 @@ enum ContentType: Hashable { } } - /// An identifier used as the Payload.Content enum case name - /// in generated code. - var identifier: String { - switch self { - case .json: - return "json" - case .text: - return "text" - case .binary: - return "binary" - } - } - /// The coding strategy appropriate for this content type. var codingStrategy: CodingStrategy { switch self { diff --git a/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift b/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift index 041a9e00..e43b564b 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift @@ -56,7 +56,7 @@ extension TypesFileTranslator { ) bodyMembers.append(contentsOf: inlineTypeDecls) } - let identifier = content.content.contentType.identifier + let identifier = contentSwiftName(content.content.contentType) let associatedType = content.resolvedTypeUsage let contentCase: Declaration = .enumCase( .init( @@ -178,7 +178,7 @@ extension ClientFileTranslator { let typedContent = requestBody.content let content = typedContent.content let contentType = content.contentType - let contentTypeIdentifier = contentType.identifier + let contentTypeIdentifier = contentSwiftName(contentType) let contentTypeHeaderValue = contentType.headerValueForSending let transformReturnExpr: Expression = .return( @@ -270,7 +270,7 @@ extension ServerFileTranslator { let contentTypeUsage = typedContent.resolvedTypeUsage let content = typedContent.content let contentType = content.contentType - let contentTypeIdentifier = contentType.identifier + let contentTypeIdentifier = contentSwiftName(contentType) let codingStrategyName = contentType.codingStrategy.runtimeName let isOptional = !requestBody.request.required diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift index 8bbd1666..7d7796da 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift @@ -63,7 +63,7 @@ extension TypesFileTranslator { response.content, inParent: bodyTypeName ) { - let identifier = typedContent.content.contentType.identifier + let identifier = contentSwiftName(typedContent.content.contentType) let associatedType = typedContent.resolvedTypeUsage if TypeMatcher.isInlinable(typedContent.content.schema), let inlineType = typedContent.typeUsage { let inlineTypeDecls = try translateSchema( diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseOutcome.swift b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseOutcome.swift index a6dab94b..422042d1 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseOutcome.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseOutcome.swift @@ -169,7 +169,7 @@ extension ClientFileTranslator { argumentNames: ["value"], body: [ .expression( - .dot(typedContent.content.contentType.identifier) + .dot(contentSwiftName(typedContent.content.contentType)) .call([ .init(label: nil, expression: .identifier("value")) ]) @@ -323,7 +323,7 @@ extension ServerFileTranslator { let contentType = typedContent.content.contentType let switchContentCases: [SwitchCaseDescription] = [ .init( - kind: .case(.dot(contentType.identifier), ["value"]), + kind: .case(.dot(contentSwiftName(contentType)), ["value"]), body: [ .expression( .return( diff --git a/Tests/OpenAPIGeneratorCoreTests/TestUtilities.swift b/Tests/OpenAPIGeneratorCoreTests/TestUtilities.swift index a9af2b79..e10f1ca3 100644 --- a/Tests/OpenAPIGeneratorCoreTests/TestUtilities.swift +++ b/Tests/OpenAPIGeneratorCoreTests/TestUtilities.swift @@ -25,20 +25,26 @@ class Test_Core: XCTestCase { func makeTranslator( components: OpenAPI.Components = .noComponents, - diagnostics: any DiagnosticCollector = PrintingDiagnosticCollector() + diagnostics: any DiagnosticCollector = PrintingDiagnosticCollector(), + featureFlags: FeatureFlags = [] ) -> any FileTranslator { makeTypesTranslator( components: components, - diagnostics: diagnostics + diagnostics: diagnostics, + featureFlags: featureFlags ) } func makeTypesTranslator( components: OpenAPI.Components = .noComponents, - diagnostics: any DiagnosticCollector = PrintingDiagnosticCollector() + diagnostics: any DiagnosticCollector = PrintingDiagnosticCollector(), + featureFlags: FeatureFlags = [] ) -> TypesFileTranslator { TypesFileTranslator( - config: .init(mode: .types), + config: .init( + mode: .types, + featureFlags: featureFlags + ), diagnostics: diagnostics, components: components ) diff --git a/Tests/OpenAPIGeneratorCoreTests/Translator/Content/Test_ContentSwiftName.swift b/Tests/OpenAPIGeneratorCoreTests/Translator/Content/Test_ContentSwiftName.swift new file mode 100644 index 00000000..5671ad61 --- /dev/null +++ b/Tests/OpenAPIGeneratorCoreTests/Translator/Content/Test_ContentSwiftName.swift @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftOpenAPIGenerator open source project +// +// Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// +import XCTest +import OpenAPIKit30 +@testable import _OpenAPIGeneratorCore + +final class Test_ContentSwiftName: Test_Core { + + func testExisting() throws { + let nameMaker = makeTranslator(featureFlags: []).contentSwiftName + let cases: [(String, String)] = [ + ("application/json", "json"), + ("application/x-www-form-urlencoded", "binary"), + ("multipart/form-data", "binary"), + ("text/plain", "text"), + ("*/*", "binary"), + ("application/xml", "binary"), + ("application/octet-stream", "binary"), + ("application/myformat+json", "json"), + ("foo/bar", "binary"), + ] + try _testIdentifiers(cases: cases, nameMaker: nameMaker) + } + + func testProposed() throws { + let nameMaker = makeTranslator(featureFlags: [.multipleContentTypes]).contentSwiftName + let cases: [(String, String)] = [ + ("application/json", "unsupported"), + ("application/x-www-form-urlencoded", "unsupported"), + ("multipart/form-data", "unsupported"), + ("text/plain", "unsupported"), + ("*/*", "unsupported"), + ("application/xml", "unsupported"), + ("application/octet-stream", "unsupported"), + ("application/myformat+json", "unsupported"), + ("foo/bar", "unsupported"), + ] + try _testIdentifiers(cases: cases, nameMaker: nameMaker) + } + + func _testIdentifiers(cases: [(String, String)], nameMaker: (ContentType) -> String) throws { + for item in cases { + let contentType = try XCTUnwrap(ContentType(item.0)) + XCTAssertEqual(nameMaker(contentType), item.1, "Case \(item.0) failed") + } + } +}