From 6218f4b4d0ea62261aad10d86510e660f1689660 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Tue, 1 Oct 2024 12:02:59 +0200 Subject: [PATCH 1/3] [Refactor] Introduce TranslatorContext --- .../ClientTranslator/ClientTranslator.swift | 3 +- .../CommonTranslations/SwiftSafeNames.swift | 11 +------ .../translateAllAnyOneOf.swift | 4 +-- .../translateObjectStruct.swift | 4 +-- .../translateStringEnum.swift | 4 +-- .../CommonTypes/DiscriminatorExtensions.swift | 4 ++- .../CommonTypes/StructBlueprint.swift | 7 ++--- .../Translator/FileTranslator.swift | 16 ++++++++++ .../Multipart/MultipartContentInspector.swift | 2 +- .../Multipart/translateMultipart.swift | 10 +++---- .../Operations/OperationDescription.swift | 21 ++++++------- .../Parameters/TypedParameter.swift | 21 +++++++------ .../Parameters/translateParameter.swift | 2 +- .../RequestBody/translateRequestBody.swift | 2 +- .../Responses/TypedResponseHeader.swift | 19 ++++++------ .../Responses/translateResponse.swift | 4 +-- .../Responses/translateResponseHeader.swift | 2 +- .../ServerTranslator/ServerTranslator.swift | 6 +--- .../TypeAssignment/TypeAssigner.swift | 30 +++++++++---------- .../TypeAssignment/TypeMatcher.swift | 7 ++--- .../TypesTranslator/TypesFileTranslator.swift | 6 +--- .../translateAPIProtocol.swift | 4 +-- .../TypesTranslator/translateOperations.swift | 4 +-- .../TypesTranslator/translateServers.swift | 2 +- .../Extensions/Test_String.swift | 2 +- .../TestUtilities.swift | 6 ++-- .../Test_OperationDescription.swift | 2 +- .../SnippetBasedReferenceTests.swift | 10 ++----- 28 files changed, 103 insertions(+), 112 deletions(-) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/ClientTranslator/ClientTranslator.swift b/Sources/_OpenAPIGeneratorCore/Translator/ClientTranslator/ClientTranslator.swift index 29381dfb..4df9a035 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/ClientTranslator/ClientTranslator.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/ClientTranslator/ClientTranslator.swift @@ -37,8 +37,7 @@ struct ClientFileTranslator: FileTranslator { let imports = Constants.File.clientServerImports + config.additionalImports.map { ImportDescription(moduleName: $0) } - let clientMethodDecls = - try OperationDescription.all(from: doc.paths, in: components, asSwiftSafeName: swiftSafeName) + let clientMethodDecls = try OperationDescription.all(from: doc.paths, in: components, context: context) .map(translateClientMethod(_:)) let clientStructPropertyDecl: Declaration = .commentable( diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/SwiftSafeNames.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/SwiftSafeNames.swift index 35d04086..9a52bc04 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/SwiftSafeNames.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/SwiftSafeNames.swift @@ -13,16 +13,7 @@ //===----------------------------------------------------------------------===// import Foundation -extension FileTranslator { - - /// Returns a copy of the string modified to be a valid Swift identifier. - /// - /// - Parameter string: The string to convert to be safe for Swift. - /// - Returns: A Swift-safe version of the input string. - func swiftSafeName(for string: String) -> String { string.safeForSwiftCode } -} - -fileprivate extension String { +extension String { /// Returns a string sanitized to be usable as a Swift identifier. /// diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift index ad7a1b63..b007d6e2 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift @@ -78,7 +78,7 @@ extension TypesFileTranslator { originalName: key, typeUsage: propertyType, associatedDeclarations: associatedDeclarations, - asSwiftSafeName: swiftSafeName + context: context ) var referenceStack = ReferenceStack.empty let isKeyValuePairSchema = try TypeMatcher.isKeyValuePair( @@ -209,7 +209,7 @@ extension TypesFileTranslator { let decoder: Declaration if let discriminator { let originalName = discriminator.propertyName - let swiftName = swiftSafeName(for: originalName) + let swiftName = context.asSwiftSafeName(originalName) codingKeysDecls = [ .enum( accessModifier: config.access, diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift index 4b48e2e1..704d5b61 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift @@ -100,7 +100,7 @@ extension TypesFileTranslator { originalName: key, typeUsage: propertyType, associatedDeclarations: associatedDeclarations, - asSwiftSafeName: swiftSafeName + context: context ) } @@ -175,7 +175,7 @@ extension TypesFileTranslator { default: .emptyInit, isSerializedInTopLevelDictionary: false, associatedDeclarations: associatedDeclarations, - asSwiftSafeName: swiftSafeName + context: context ) return (.allowingAdditionalProperties, extraProperty) } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift index 3bc47bb8..9add9482 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift @@ -49,11 +49,11 @@ extension FileTranslator { // In nullable enum schemas, empty strings are parsed as Void. // This is unlikely to be fixed, so handling that case here. // https://github.com/apple/swift-openapi-generator/issues/118 - if isNullable && anyValue is Void { return (swiftSafeName(for: ""), .string("")) } + if isNullable && anyValue is Void { return (context.asSwiftSafeName(""), .string("")) } guard let rawValue = anyValue as? String else { throw GenericError(message: "Disallowed value for a string enum '\(typeName)': \(anyValue)") } - let caseName = swiftSafeName(for: rawValue) + let caseName = context.asSwiftSafeName(rawValue) return (caseName, .string(rawValue)) case .integer: let rawValue: Int diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/DiscriminatorExtensions.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/DiscriminatorExtensions.swift index b27a61c1..1bc1cd7f 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/DiscriminatorExtensions.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/DiscriminatorExtensions.swift @@ -79,7 +79,9 @@ extension FileTranslator { /// component. /// - Parameter type: The `OneOfMappedType` for which to determine the case name. /// - Returns: A string representing the safe Swift name for the specified `OneOfMappedType`. - func safeSwiftNameForOneOfMappedType(_ type: OneOfMappedType) -> String { swiftSafeName(for: type.rawNames[0]) } + func safeSwiftNameForOneOfMappedType(_ type: OneOfMappedType) -> String { + context.asSwiftSafeName(type.rawNames[0]) + } } extension OpenAPI.Discriminator { diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/StructBlueprint.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/StructBlueprint.swift index 2b3d7123..9eef5d6d 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/StructBlueprint.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/StructBlueprint.swift @@ -146,15 +146,14 @@ struct PropertyBlueprint { /// referring to them in the property. var associatedDeclarations: [Declaration] = [] - /// A converted function from user-provided strings to strings - /// safe to be used as a Swift identifier. - var asSwiftSafeName: (String) -> String + /// A set of configuration values that inform translation. + var context: TranslatorContext } extension PropertyBlueprint { /// A name that is verified to be a valid Swift identifier. - var swiftSafeName: String { asSwiftSafeName(originalName) } + var swiftSafeName: String { context.asSwiftSafeName(originalName) } /// The JSON path to the property. /// diff --git a/Sources/_OpenAPIGeneratorCore/Translator/FileTranslator.swift b/Sources/_OpenAPIGeneratorCore/Translator/FileTranslator.swift index ecbf9771..4f246521 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/FileTranslator.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/FileTranslator.swift @@ -43,3 +43,19 @@ protocol FileTranslator { /// - Throws: An error if translation encounters issues or errors during the process. func translateFile(parsedOpenAPI: ParsedOpenAPIRepresentation) throws -> StructuredSwiftRepresentation } + +extension FileTranslator { + + /// A new context from the file translator. + var context: TranslatorContext { TranslatorContext(asSwiftSafeName: { $0.safeForSwiftCode }) } +} + +/// A set of configuration values for concrete file translators. +struct TranslatorContext { + + /// A closure that returns a copy of the string modified to be a valid Swift identifier. + /// + /// - Parameter string: The string to convert to be safe for Swift. + /// - Returns: A Swift-safe version of the input string. + var asSwiftSafeName: (String) -> String +} diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift index 1c27dbd9..f5a83882 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift @@ -120,7 +120,7 @@ extension FileTranslator { } var parts: [MultipartSchemaTypedContent] = try topLevelObject.properties.compactMap { (key, value) -> MultipartSchemaTypedContent? in - let swiftSafeName = swiftSafeName(for: key) + let swiftSafeName = context.asSwiftSafeName(key) let typeName = typeName.appending( swiftComponent: swiftSafeName + Constants.Global.inlineTypeSuffix, jsonComponent: key diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/translateMultipart.swift b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/translateMultipart.swift index 186cfda8..2af6cc8f 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/translateMultipart.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/translateMultipart.swift @@ -64,7 +64,7 @@ extension TypesFileTranslator { typeUsage: headersTypeName.asUsage, default: headersStructBlueprint.hasEmptyInit ? .emptyInit : nil, associatedDeclarations: [headersStructDecl], - asSwiftSafeName: swiftSafeName + context: context ) } else { headersProperty = nil @@ -90,7 +90,7 @@ extension TypesFileTranslator { originalName: Constants.Operation.Body.variableName, typeUsage: bodyTypeUsage, associatedDeclarations: associatedDeclarations, - asSwiftSafeName: swiftSafeName + context: context ) let structDecl = translateStructBlueprint( .init( @@ -137,7 +137,7 @@ extension TypesFileTranslator { switch part { case .documentedTyped(let documentedPart): let caseDecl: Declaration = .enumCase( - name: swiftSafeName(for: documentedPart.originalName), + name: context.asSwiftSafeName(documentedPart.originalName), kind: .nameWithAssociatedValues([.init(type: .init(part.wrapperTypeUsage))]) ) let decl = try translateMultipartPartContent( @@ -404,7 +404,7 @@ extension FileTranslator { switch part { case .documentedTyped(let part): let originalName = part.originalName - let identifier = swiftSafeName(for: originalName) + let identifier = context.asSwiftSafeName(originalName) let contentType = part.partInfo.contentType let partTypeName = part.typeName let schema = part.schema @@ -613,7 +613,7 @@ extension FileTranslator { switch part { case .documentedTyped(let part): let originalName = part.originalName - let identifier = swiftSafeName(for: originalName) + let identifier = context.asSwiftSafeName(originalName) let contentType = part.partInfo.contentType let headersTypeName = part.typeName.appending( swiftComponent: Constants.Operation.Output.Payload.Headers.typeName, diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Operations/OperationDescription.swift b/Sources/_OpenAPIGeneratorCore/Translator/Operations/OperationDescription.swift index aea727dc..2a72252b 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Operations/OperationDescription.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Operations/OperationDescription.swift @@ -31,9 +31,8 @@ struct OperationDescription { /// The OpenAPI components, used to resolve JSON references. var components: OpenAPI.Components - /// A converted function from user-provided strings to strings - /// safe to be used as a Swift identifier. - var asSwiftSafeName: (String) -> String + /// A set of configuration values that inform translation. + var context: TranslatorContext /// The OpenAPI operation object. var operation: OpenAPI.Operation { endpoint.operation } @@ -52,7 +51,7 @@ extension OperationDescription { /// - Parameters: /// - map: The paths from the OpenAPI document. /// - components: The components from the OpenAPI document. - /// - asSwiftSafeName: A converted function from user-provided strings + /// - context: A set of configuration values that inform translation. /// to strings safe to be used as a Swift identifier. /// - Returns: An array of `OperationDescription` instances, each representing /// an operation discovered in the provided paths. @@ -62,11 +61,9 @@ extension OperationDescription { /// 1. OpenAPI 3.0.3 only supports external path references (cf. 3.1, which supports internal references too) /// 2. Swift OpenAPI Generator currently only supports OpenAPI 3.0.x. /// 3. Swift OpenAPI Generator currently doesn't support external references. - static func all( - from map: OpenAPI.PathItem.Map, - in components: OpenAPI.Components, - asSwiftSafeName: @escaping (String) -> String - ) throws -> [OperationDescription] { + static func all(from map: OpenAPI.PathItem.Map, in components: OpenAPI.Components, context: TranslatorContext) + throws -> [OperationDescription] + { try map.flatMap { path, value in let value = try value.resolve(in: components) return value.endpoints.map { endpoint in @@ -75,7 +72,7 @@ extension OperationDescription { endpoint: endpoint, pathParameters: value.parameters, components: components, - asSwiftSafeName: asSwiftSafeName + context: context ) } } @@ -86,7 +83,7 @@ extension OperationDescription { /// Uses the `operationID` value in the OpenAPI operation, if one was /// specified. Otherwise, computes a unique name from the operation's /// path and HTTP method. - var methodName: String { asSwiftSafeName(operationID) } + var methodName: String { context.asSwiftSafeName(operationID) } /// Returns the identifier for the operation. /// @@ -295,7 +292,7 @@ extension OperationDescription { } let newPath = OpenAPI.Path(newComponents, trailingSlash: path.trailingSlash) let names: [Expression] = orderedPathParameters.map { param in - .identifierPattern("input").dot("path").dot(asSwiftSafeName(param)) + .identifierPattern("input").dot("path").dot(context.asSwiftSafeName(param)) } let arrayExpr: Expression = .literal(.array(names)) return (newPath.rawValue, arrayExpr) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift index 66a0ce26..1564b08c 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift @@ -15,28 +15,27 @@ import OpenAPIKit /// A container for an OpenAPI parameter and its computed Swift type usage. struct TypedParameter { - + /// The OpenAPI parameter. var parameter: OpenAPI.Parameter - + /// The underlying schema. var schema: UnresolvedSchema - + /// The parameter serialization style. var style: OpenAPI.Parameter.SchemaContext.Style - + /// The parameter explode value. var explode: Bool - + /// The computed type usage. var typeUsage: TypeUsage - + /// The coding strategy appropriate for this parameter. var codingStrategy: CodingStrategy - /// A converted function from user-provided strings to strings - /// safe to be used as a Swift identifier. - var asSwiftSafeName: (String) -> String + /// A set of configuration values that inform translation. + var context: TranslatorContext } extension TypedParameter: CustomStringConvertible { @@ -49,7 +48,7 @@ extension TypedParameter { var name: String { parameter.name } /// The name of the parameter sanitized to be a valid Swift identifier. - var variableName: String { asSwiftSafeName(name) } + var variableName: String { context.asSwiftSafeName(name) } /// A Boolean value that indicates whether the parameter must be specified /// when performing the OpenAPI operation. @@ -208,7 +207,7 @@ extension FileTranslator { explode: explode, typeUsage: usage, codingStrategy: codingStrategy, - asSwiftSafeName: swiftSafeName + context: context ) } } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift index 0176a8cd..3dcdbe75 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift @@ -42,7 +42,7 @@ extension TypesFileTranslator { originalName: parameter.name, typeUsage: parameter.typeUsage, associatedDeclarations: associatedDeclarations, - asSwiftSafeName: swiftSafeName + context: context ) } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift b/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift index 76c0c6f7..09e7776d 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift @@ -92,7 +92,7 @@ extension TypesFileTranslator { typeUsage: bodyEnumTypeUsage, default: nil, associatedDeclarations: extraDecls, - asSwiftSafeName: swiftSafeName + context: context ) return bodyProperty } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift b/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift index 4cf5a85a..5d3a5e4e 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift @@ -16,31 +16,30 @@ import OpenAPIKit /// A container for an OpenAPI response header and its computed /// Swift type usage. struct TypedResponseHeader { - + /// The OpenAPI response header. var header: OpenAPI.Header - + /// The name of the header. var name: String - + /// The underlying schema. var schema: UnresolvedSchema - + /// The Swift type representing the response header. var typeUsage: TypeUsage - + /// The coding strategy appropriate for this parameter. var codingStrategy: CodingStrategy - /// A converted function from user-provided strings to strings - /// safe to be used as a Swift identifier. - var asSwiftSafeName: (String) -> String + /// A set of configuration values that inform translation. + var context: TranslatorContext } extension TypedResponseHeader { /// The name of the header sanitized to be a valid Swift identifier. - var variableName: String { asSwiftSafeName(name) } + var variableName: String { context.asSwiftSafeName(name) } /// A Boolean value that indicates whether the response header can /// be omitted in the HTTP response. @@ -152,7 +151,7 @@ extension FileTranslator { schema: schema, typeUsage: usage, codingStrategy: codingStrategy, - asSwiftSafeName: swiftSafeName + context: context ) } } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift index 13a44064..60f2bb95 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift @@ -50,7 +50,7 @@ extension TypesFileTranslator { typeUsage: headersTypeName.asUsage, default: headersStructBlueprint.hasEmptyInit ? .emptyInit : nil, associatedDeclarations: [headersStructDecl], - asSwiftSafeName: swiftSafeName + context: context ) } else { headersProperty = nil @@ -92,7 +92,7 @@ extension TypesFileTranslator { typeUsage: contentTypeUsage, default: hasNoContent ? .nil : nil, associatedDeclarations: [contentEnumDecl], - asSwiftSafeName: swiftSafeName + context: context ) } else { bodyProperty = nil diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseHeader.swift b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseHeader.swift index 229d575a..37feea59 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseHeader.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseHeader.swift @@ -78,7 +78,7 @@ extension TypesFileTranslator { typeUsage: typeUsage, default: header.header.required ? nil : .nil, associatedDeclarations: associatedDeclarations, - asSwiftSafeName: swiftSafeName + context: context ) } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/ServerTranslator/ServerTranslator.swift b/Sources/_OpenAPIGeneratorCore/Translator/ServerTranslator/ServerTranslator.swift index e62df4f6..3f54d4ad 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/ServerTranslator/ServerTranslator.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/ServerTranslator/ServerTranslator.swift @@ -35,11 +35,7 @@ struct ServerFileTranslator: FileTranslator { let imports = Constants.File.clientServerImports + config.additionalImports.map { ImportDescription(moduleName: $0) } - let allOperations = try OperationDescription.all( - from: doc.paths, - in: components, - asSwiftSafeName: swiftSafeName - ) + let allOperations = try OperationDescription.all(from: doc.paths, in: components, context: context) let (registerHandlersDecl, serverMethodDecls) = try translateRegisterHandlers(allOperations) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeAssigner.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeAssigner.swift index 72e18f8a..2c8ab438 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeAssigner.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeAssigner.swift @@ -41,9 +41,8 @@ import Foundation /// cases when it's a simple string schema. struct TypeAssigner { - /// A converted function from user-provided strings to strings - /// safe to be used as a Swift identifier. - var asSwiftSafeName: (String) -> String + /// A set of configuration values that inform translation. + var context: TranslatorContext /// Returns a type name for an OpenAPI-named component type. /// @@ -60,7 +59,7 @@ struct TypeAssigner { /// - Returns: A Swift type name for the specified component type. func typeName(forComponentOriginallyNamed originalName: String, in location: TypeLocation) -> TypeName { typeName(forLocation: location) - .appending(swiftComponent: asSwiftSafeName(originalName), jsonComponent: originalName) + .appending(swiftComponent: context.asSwiftSafeName(originalName), jsonComponent: originalName) } /// Returns the type name for an OpenAPI-named component namespace. @@ -126,7 +125,7 @@ struct TypeAssigner { if let ref = TypeMatcher.multipartElementTypeReferenceIfReferenceable(schema: schema, encoding: encoding) { multipartBodyElementTypeName = try typeName(for: ref) } else { - let swiftSafeName = asSwiftSafeName(hint) + let swiftSafeName = context.asSwiftSafeName(hint) multipartBodyElementTypeName = parent.appending( swiftComponent: swiftSafeName + Constants.Global.inlineTypeSuffix, jsonComponent: hint @@ -328,7 +327,7 @@ struct TypeAssigner { inParent parent: TypeName, subtype: SubtypeNamingMethod ) throws -> TypeUsage { - let typeMatcher = TypeMatcher(asSwiftSafeName: asSwiftSafeName) + let typeMatcher = TypeMatcher(context: context) // Check if this type can be simply referenced without // creating a new inline type. if let referenceableType = try typeMatcher.tryMatchReferenceableType(for: schema, components: components) { @@ -342,7 +341,7 @@ struct TypeAssigner { } return baseType.appending( - swiftComponent: asSwiftSafeName(originalName) + suffix, + swiftComponent: context.asSwiftSafeName(originalName) + suffix, jsonComponent: jsonReferenceComponentOverride ?? originalName ) .asUsage.withOptional(try typeMatcher.isOptional(schema, components: components)) @@ -405,7 +404,7 @@ struct TypeAssigner { of componentType: Component.Type ) -> TypeName { typeName(for: Component.self) - .appending(swiftComponent: asSwiftSafeName(key.rawValue), jsonComponent: key.rawValue) + .appending(swiftComponent: context.asSwiftSafeName(key.rawValue), jsonComponent: key.rawValue) } /// Returns a type name for a JSON reference. @@ -469,7 +468,8 @@ struct TypeAssigner { guard case let .component(name) = reference else { throw JSONReferenceParsingError.nonComponentPathsUnsupported(reference.name) } - return typeName(for: componentType).appending(swiftComponent: asSwiftSafeName(name), jsonComponent: name) + return typeName(for: componentType) + .appending(swiftComponent: context.asSwiftSafeName(name), jsonComponent: name) } /// Returns a type name for the namespace for the specified component type. @@ -493,7 +493,7 @@ struct TypeAssigner { { typeNameForComponents() .appending( - swiftComponent: asSwiftSafeName(componentType.openAPIComponentsKey).uppercasingFirstLetter, + swiftComponent: context.asSwiftSafeName(componentType.openAPIComponentsKey).uppercasingFirstLetter, jsonComponent: componentType.openAPIComponentsKey ) } @@ -526,14 +526,14 @@ struct TypeAssigner { case "application/pdf": return "pdf" case "image/jpeg": return "jpeg" default: - let safedType = asSwiftSafeName(contentType.originallyCasedType) - let safedSubtype = asSwiftSafeName(contentType.originallyCasedSubtype) + let safedType = context.asSwiftSafeName(contentType.originallyCasedType) + let safedSubtype = context.asSwiftSafeName(contentType.originallyCasedSubtype) let prefix = "\(safedType)_\(safedSubtype)" let params = contentType.lowercasedParameterPairs guard !params.isEmpty else { return prefix } let safedParams = params.map { pair in - pair.split(separator: "=").map { asSwiftSafeName(String($0)) }.joined(separator: "_") + pair.split(separator: "=").map { context.asSwiftSafeName(String($0)) }.joined(separator: "_") } .joined(separator: "_") return prefix + "_" + safedParams @@ -545,10 +545,10 @@ struct TypeAssigner { extension FileTranslator { /// A configured type assigner. - var typeAssigner: TypeAssigner { TypeAssigner(asSwiftSafeName: swiftSafeName) } + var typeAssigner: TypeAssigner { TypeAssigner(context: context) } /// A configured type matcher. - var typeMatcher: TypeMatcher { TypeMatcher(asSwiftSafeName: swiftSafeName) } + var typeMatcher: TypeMatcher { TypeMatcher(context: context) } } /// An error used during the parsing of JSON references specified in an diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeMatcher.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeMatcher.swift index 08ac4a1e..8c8c252a 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeMatcher.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeMatcher.swift @@ -16,9 +16,8 @@ import OpenAPIKit /// A set of functions that match Swift types onto OpenAPI types. struct TypeMatcher { - /// A converted function from user-provided strings to strings - /// safe to be used as a Swift identifier. - var asSwiftSafeName: (String) -> String + /// A set of configuration values that inform translation. + var context: TranslatorContext /// Returns the type name of a built-in type that matches the specified /// schema. @@ -71,7 +70,7 @@ struct TypeMatcher { test: { (schema) -> TypeUsage? in if let builtinType = Self._tryMatchBuiltinNonRecursive(for: schema) { return builtinType } guard case let .reference(ref, _) = schema else { return nil } - return try TypeAssigner(asSwiftSafeName: asSwiftSafeName).typeName(for: ref).asUsage + return try TypeAssigner(context: context).typeName(for: ref).asUsage }, matchedArrayHandler: { elementType, nullableItems in nullableItems ? elementType.asOptional.asArray : elementType.asArray diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/TypesFileTranslator.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/TypesFileTranslator.swift index fb0cc056..3ad52eb0 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/TypesFileTranslator.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/TypesFileTranslator.swift @@ -45,11 +45,7 @@ struct TypesFileTranslator: FileTranslator { let multipartSchemaNames = try parseSchemaNamesUsedInMultipart(paths: doc.paths, components: doc.components) let components = try translateComponents(doc.components, multipartSchemaNames: multipartSchemaNames) - let operationDescriptions = try OperationDescription.all( - from: doc.paths, - in: doc.components, - asSwiftSafeName: swiftSafeName - ) + let operationDescriptions = try OperationDescription.all(from: doc.paths, in: doc.components, context: context) let operations = try translateOperations(operationDescriptions) let typesFile = FileDescription( diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateAPIProtocol.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateAPIProtocol.swift index 3b061854..2f9134ed 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateAPIProtocol.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateAPIProtocol.swift @@ -22,7 +22,7 @@ extension TypesFileTranslator { /// - Throws: If `paths` contains any references. func translateAPIProtocol(_ paths: OpenAPI.PathItem.Map) throws -> Declaration { - let operations = try OperationDescription.all(from: paths, in: components, asSwiftSafeName: swiftSafeName) + let operations = try OperationDescription.all(from: paths, in: components, context: context) let functionDecls = operations.map(translateAPIProtocolDeclaration(operation:)) let protocolDescription = ProtocolDescription( @@ -38,7 +38,7 @@ extension TypesFileTranslator { /// Returns an extension to the `APIProtocol` protocol, with some syntactic sugar APIs. func translateAPIProtocolExtension(_ paths: OpenAPI.PathItem.Map) throws -> Declaration { - let operations = try OperationDescription.all(from: paths, in: components, asSwiftSafeName: swiftSafeName) + let operations = try OperationDescription.all(from: paths, in: components, context: context) // This looks for all initializers in the operation input struct and creates a flattened function. let flattenedOperations = try operations.flatMap { operation in diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateOperations.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateOperations.swift index df3576ac..55d01890 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateOperations.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateOperations.swift @@ -71,7 +71,7 @@ extension TypesFileTranslator { typeUsage: structTypeName.asUsage, default: defaultValue, associatedDeclarations: [structDecl], - asSwiftSafeName: swiftSafeName + context: context ) } let bodyProperty = try parseRequestBodyAsProperty( @@ -89,7 +89,7 @@ extension TypesFileTranslator { originalName: Constants.Operation.AcceptableContentType.variableName, typeUsage: description.acceptableArrayName, default: .expression(.dot("defaultValues").call([])), - asSwiftSafeName: swiftSafeName + context: context ) extraHeaderProperties = [acceptPropertyBlueprint] } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateServers.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateServers.swift index bb7a6552..84ed698e 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateServers.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateServers.swift @@ -26,7 +26,7 @@ extension TypesFileTranslator { func translateServer(index: Int, server: OpenAPI.Server) -> Declaration { let methodName = "\(Constants.ServerURL.propertyPrefix)\(index+1)" let safeVariables = server.variables.map { (key, value) in - (originalKey: key, swiftSafeKey: swiftSafeName(for: key), value: value) + (originalKey: key, swiftSafeKey: context.asSwiftSafeName(key), value: value) } let parameters: [ParameterDescription] = safeVariables.map { (originalKey, swiftSafeKey, value) in .init(label: swiftSafeKey, type: .init(TypeName.string), defaultValue: .literal(value.default)) diff --git a/Tests/OpenAPIGeneratorCoreTests/Extensions/Test_String.swift b/Tests/OpenAPIGeneratorCoreTests/Extensions/Test_String.swift index c9c58c94..9d10b45c 100644 --- a/Tests/OpenAPIGeneratorCoreTests/Extensions/Test_String.swift +++ b/Tests/OpenAPIGeneratorCoreTests/Extensions/Test_String.swift @@ -64,7 +64,7 @@ final class Test_String: Test_Core { ("application", "application"), ("vendor1+json", "vendor1_plus_json"), ] let translator = makeTranslator() - let asSwiftSafeName: (String) -> String = translator.swiftSafeName + let asSwiftSafeName: (String) -> String = translator.context.asSwiftSafeName for (input, sanitized) in cases { XCTAssertEqual(asSwiftSafeName(input), sanitized) } } } diff --git a/Tests/OpenAPIGeneratorCoreTests/TestUtilities.swift b/Tests/OpenAPIGeneratorCoreTests/TestUtilities.swift index 67d2e94a..a99d4d30 100644 --- a/Tests/OpenAPIGeneratorCoreTests/TestUtilities.swift +++ b/Tests/OpenAPIGeneratorCoreTests/TestUtilities.swift @@ -59,10 +59,12 @@ class Test_Core: XCTestCase { var typeMatcher: TypeMatcher { makeTranslator().typeMatcher } - var asSwiftSafeName: (String) -> String { makeTranslator().swiftSafeName } + var context: TranslatorContext { makeTranslator().context } + + var asSwiftSafeName: (String) -> String { context.asSwiftSafeName } func makeProperty(originalName: String, typeUsage: TypeUsage) -> PropertyBlueprint { - .init(originalName: originalName, typeUsage: typeUsage, asSwiftSafeName: asSwiftSafeName) + .init(originalName: originalName, typeUsage: typeUsage, context: context) } } diff --git a/Tests/OpenAPIGeneratorCoreTests/Translator/Operations/Test_OperationDescription.swift b/Tests/OpenAPIGeneratorCoreTests/Translator/Operations/Test_OperationDescription.swift index a5da80a4..6b37703c 100644 --- a/Tests/OpenAPIGeneratorCoreTests/Translator/Operations/Test_OperationDescription.swift +++ b/Tests/OpenAPIGeneratorCoreTests/Translator/Operations/Test_OperationDescription.swift @@ -144,7 +144,7 @@ final class Test_OperationDescription: Test_Core { endpoint: endpoint, pathParameters: pathItem.parameters, components: .init(), - asSwiftSafeName: { $0 } + context: .init(asSwiftSafeName: { $0 }) ) } } diff --git a/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift b/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift index 0196c5ee..f4811396 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift @@ -5284,7 +5284,7 @@ extension SnippetBasedReferenceTests { let operationDescriptions = try OperationDescription.all( from: document.paths, in: document.components, - asSwiftSafeName: types.swiftSafeName + context: types.context ) let operation = try XCTUnwrap(operationDescriptions.first) let generatedTypesStructuredSwift = try types.translateOperationInput(operation) @@ -5343,7 +5343,7 @@ extension SnippetBasedReferenceTests { let operationDescriptions = try OperationDescription.all( from: document.paths, in: document.components, - asSwiftSafeName: types.swiftSafeName + context: types.context ) let operation = try XCTUnwrap(operationDescriptions.first) let generatedTypesStructuredSwift = try types.translateOperationOutput(operation) @@ -5465,11 +5465,7 @@ extension SnippetBasedReferenceTests { ) throws { let (_, _, translator) = try makeTranslators() let paths = try YAMLDecoder().decode(OpenAPI.PathItem.Map.self, from: pathsYAML) - let operations = try OperationDescription.all( - from: paths, - in: .noComponents, - asSwiftSafeName: translator.swiftSafeName - ) + let operations = try OperationDescription.all(from: paths, in: .noComponents, context: translator.context) let (registerHandlersDecl, _) = try translator.translateRegisterHandlers(operations) try XCTAssertSwiftEquivalent(registerHandlersDecl, expectedSwift, file: file, line: line) } From eb8c75b17bbba496c6af94df54b0c644f67d1029 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Tue, 1 Oct 2024 12:36:16 +0200 Subject: [PATCH 2/3] Fix formatting --- .../Translator/Parameters/TypedParameter.swift | 12 ++++++------ .../Translator/Responses/TypedResponseHeader.swift | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift index 1564b08c..8f66192b 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift @@ -15,22 +15,22 @@ import OpenAPIKit /// A container for an OpenAPI parameter and its computed Swift type usage. struct TypedParameter { - + /// The OpenAPI parameter. var parameter: OpenAPI.Parameter - + /// The underlying schema. var schema: UnresolvedSchema - + /// The parameter serialization style. var style: OpenAPI.Parameter.SchemaContext.Style - + /// The parameter explode value. var explode: Bool - + /// The computed type usage. var typeUsage: TypeUsage - + /// The coding strategy appropriate for this parameter. var codingStrategy: CodingStrategy diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift b/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift index 5d3a5e4e..ad11fcbc 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift @@ -16,19 +16,19 @@ import OpenAPIKit /// A container for an OpenAPI response header and its computed /// Swift type usage. struct TypedResponseHeader { - + /// The OpenAPI response header. var header: OpenAPI.Header - + /// The name of the header. var name: String - + /// The underlying schema. var schema: UnresolvedSchema - + /// The Swift type representing the response header. var typeUsage: TypeUsage - + /// The coding strategy appropriate for this parameter. var codingStrategy: CodingStrategy From 7be022d4b4c5f1d0a95a1e2567c9a9e82f05f67f Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Tue, 1 Oct 2024 13:56:12 +0200 Subject: [PATCH 3/3] [Refactor] Introduce TranslatorContext (2/2) --- .../translateAllAnyOneOf.swift | 8 +++--- .../translateObjectStruct.swift | 4 +-- .../Multipart/MultipartContent.swift | 8 +++--- .../Multipart/translateMultipart.swift | 4 +-- .../Parameters/TypedParameter.swift | 12 ++------ .../RequestBody/translateRequestBody.swift | 3 +- .../Responses/translateResponse.swift | 2 +- .../Responses/translateResponseHeader.swift | 2 +- .../TypeAssignment/TypeAssigner.swift | 4 ++- .../TypeAssignment/TypeMatcher.swift | 28 +++++++++---------- .../TypeAssignment/Test_TypeMatcher.swift | 13 ++++----- 11 files changed, 40 insertions(+), 48 deletions(-) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift index b007d6e2..37ac8830 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift @@ -64,7 +64,7 @@ extension TypesFileTranslator { parent: typeName ) let associatedDeclarations: [Declaration] - if TypeMatcher.isInlinable(schema) { + if typeMatcher.isInlinable(schema) { associatedDeclarations = try translateSchema( typeName: propertyType.typeName, schema: schema, @@ -81,7 +81,7 @@ extension TypesFileTranslator { context: context ) var referenceStack = ReferenceStack.empty - let isKeyValuePairSchema = try TypeMatcher.isKeyValuePair( + let isKeyValuePairSchema = try typeMatcher.isKeyValuePair( schema, referenceStack: &referenceStack, components: components @@ -173,7 +173,7 @@ extension TypesFileTranslator { parent: typeName ) let associatedDeclarations: [Declaration] - if TypeMatcher.isInlinable(schema) { + if typeMatcher.isInlinable(schema) { associatedDeclarations = try translateSchema( typeName: childType.typeName, schema: schema, @@ -183,7 +183,7 @@ extension TypesFileTranslator { associatedDeclarations = [] } var referenceStack = ReferenceStack.empty - let isKeyValuePair = try TypeMatcher.isKeyValuePair( + let isKeyValuePair = try typeMatcher.isKeyValuePair( schema, referenceStack: &referenceStack, components: components diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift index 704d5b61..e2680fe6 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift @@ -85,7 +85,7 @@ extension TypesFileTranslator { parent: typeName ) let associatedDeclarations: [Declaration] - if TypeMatcher.isInlinable(value) { + if typeMatcher.isInlinable(value) { associatedDeclarations = try translateSchema( typeName: propertyType.typeName, schema: value, @@ -153,7 +153,7 @@ extension TypesFileTranslator { components: components, inParent: parent ) - if TypeMatcher.isInlinable(schema) { + if typeMatcher.isInlinable(schema) { associatedDeclarations = try translateSchema( typeName: valueTypeUsage.typeName, schema: schema, diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContent.swift b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContent.swift index 881e967b..290b3942 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContent.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContent.swift @@ -90,11 +90,11 @@ extension MultipartSchemaTypedContent { } } -extension SchemaContent { +extension TypeMatcher { /// Returns a Boolean value whether the schema is a multipart content type and is referenceable. - var isReferenceableMultipart: Bool { - guard contentType.isMultipart else { return false } - let ref = TypeMatcher.multipartElementTypeReferenceIfReferenceable(schema: schema, encoding: encoding) + func isReferenceableMultipart(_ content: SchemaContent) -> Bool { + guard content.contentType.isMultipart else { return false } + let ref = multipartElementTypeReferenceIfReferenceable(schema: content.schema, encoding: content.encoding) return ref == nil } } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/translateMultipart.swift b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/translateMultipart.swift index 2af6cc8f..b288ff1a 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/translateMultipart.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/translateMultipart.swift @@ -76,7 +76,7 @@ extension TypesFileTranslator { inParent: typeName.appending(swiftComponent: nil, jsonComponent: "content") ) let associatedDeclarations: [Declaration] - if TypeMatcher.isInlinable(schema) { + if typeMatcher.isInlinable(schema) { associatedDeclarations = try translateSchema( typeName: bodyTypeUsage.typeName, schema: schema, @@ -117,7 +117,7 @@ extension TypesFileTranslator { schema: JSONSchema ) throws -> [Declaration] { let associatedDeclarations: [Declaration] - if TypeMatcher.isInlinable(schema) { + if typeMatcher.isInlinable(schema) { associatedDeclarations = try translateSchema(typeName: typeName, schema: schema, overrides: .none) } else { associatedDeclarations = [] diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift index 8f66192b..e8eb0700 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift @@ -57,22 +57,14 @@ extension TypedParameter { /// The location of the parameter in the HTTP request. var location: OpenAPI.Parameter.Context.Location { parameter.location } - /// A schema to be inlined. - /// - /// - Returns: Nil when schema is referenceable. - var inlineableSchema: JSONSchema? { schema.inlineableSchema } -} - -extension UnresolvedSchema { - /// A schema to be inlined. /// /// - Returns: Nil when schema is referenceable. var inlineableSchema: JSONSchema? { - switch self { + switch schema { case .a: return nil case let .b(schema): - if TypeMatcher.isInlinable(schema) { return schema } + if TypeMatcher(context: context).isInlinable(schema) { return schema } return nil } } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift b/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift index 09e7776d..1a412704 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift @@ -46,7 +46,8 @@ extension TypesFileTranslator { let contentTypeName = typeName.appending(jsonComponent: "content") let contents = requestBody.contents for content in contents { - if TypeMatcher.isInlinable(content.content.schema) || content.content.isReferenceableMultipart { + if typeMatcher.isInlinable(content.content.schema) || typeMatcher.isReferenceableMultipart(content.content) + { let inlineTypeDecls = try translateRequestBodyContentInTypes(content) bodyMembers.append(contentsOf: inlineTypeDecls) } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift index 60f2bb95..a6754853 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponse.swift @@ -145,7 +145,7 @@ extension TypesFileTranslator { let associatedType = typedContent.resolvedTypeUsage let content = typedContent.content let schema = content.schema - if TypeMatcher.isInlinable(schema) || content.isReferenceableMultipart { + if typeMatcher.isInlinable(schema) || typeMatcher.isReferenceableMultipart(content) { let decls: [Declaration] if contentType.isMultipart { decls = try translateMultipartBody(typedContent) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseHeader.swift b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseHeader.swift index 37feea59..1096ae08 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseHeader.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Responses/translateResponseHeader.swift @@ -66,7 +66,7 @@ extension TypesFileTranslator { let schema = header.schema let typeUsage = header.typeUsage let associatedDeclarations: [Declaration] - if TypeMatcher.isInlinable(schema) { + if typeMatcher.isInlinable(schema) { associatedDeclarations = try translateSchema(typeName: typeUsage.typeName, schema: schema, overrides: .none) } else { associatedDeclarations = [] diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeAssigner.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeAssigner.swift index 2c8ab438..7f7a46ff 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeAssigner.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeAssigner.swift @@ -122,7 +122,9 @@ struct TypeAssigner { inParent parent: TypeName ) throws -> TypeUsage { let multipartBodyElementTypeName: TypeName - if let ref = TypeMatcher.multipartElementTypeReferenceIfReferenceable(schema: schema, encoding: encoding) { + if let ref = TypeMatcher(context: context) + .multipartElementTypeReferenceIfReferenceable(schema: schema, encoding: encoding) + { multipartBodyElementTypeName = try typeName(for: ref) } else { let swiftSafeName = context.asSwiftSafeName(hint) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeMatcher.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeMatcher.swift index 8c8c252a..1c503ae7 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeMatcher.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/TypeMatcher.swift @@ -42,7 +42,7 @@ struct TypeMatcher { func tryMatchBuiltinType(for schema: JSONSchema.Schema) -> TypeUsage? { Self._tryMatchRecursive( for: schema, - test: { schema in Self._tryMatchBuiltinNonRecursive(for: schema) }, + test: { schema in _tryMatchBuiltinNonRecursive(for: schema) }, matchedArrayHandler: { elementType, nullableItems in nullableItems ? elementType.asOptional.asArray : elementType.asArray }, @@ -68,7 +68,7 @@ struct TypeMatcher { try Self._tryMatchRecursive( for: schema.value, test: { (schema) -> TypeUsage? in - if let builtinType = Self._tryMatchBuiltinNonRecursive(for: schema) { return builtinType } + if let builtinType = _tryMatchBuiltinNonRecursive(for: schema) { return builtinType } guard case let .reference(ref, _) = schema else { return nil } return try TypeAssigner(context: context).typeName(for: ref).asUsage }, @@ -88,9 +88,9 @@ struct TypeMatcher { /// - A reference /// - Parameter schema: The schema to match a referenceable type for. /// - Returns: `true` if the schema is referenceable; `false` otherwise. - static func isReferenceable(_ schema: JSONSchema) -> Bool { + func isReferenceable(_ schema: JSONSchema) -> Bool { // This logic should be kept in sync with `tryMatchReferenceableType`. - _tryMatchRecursive( + Self._tryMatchRecursive( for: schema.value, test: { schema in if _tryMatchBuiltinNonRecursive(for: schema) != nil { return true } @@ -110,7 +110,7 @@ struct TypeMatcher { /// - A reference /// - Parameter schema: The schema to match a referenceable type for. /// - Returns: `true` if the schema is referenceable; `false` otherwise. - static func isReferenceable(_ schema: UnresolvedSchema?) -> Bool { + func isReferenceable(_ schema: UnresolvedSchema?) -> Bool { guard let schema else { // fragment type is referenceable return true @@ -132,7 +132,7 @@ struct TypeMatcher { /// referenceable. /// - Parameter schema: The schema to match a referenceable type for. /// - Returns: `true` if the schema is inlinable; `false` otherwise. - static func isInlinable(_ schema: JSONSchema) -> Bool { !isReferenceable(schema) } + func isInlinable(_ schema: JSONSchema) -> Bool { !isReferenceable(schema) } /// Returns a Boolean value that indicates whether the schema /// needs to be defined inline. @@ -143,14 +143,14 @@ struct TypeMatcher { /// referenceable. /// - Parameter schema: The schema to match a referenceable type for. /// - Returns: `true` if the schema is inlinable; `false` otherwise. - static func isInlinable(_ schema: UnresolvedSchema?) -> Bool { !isReferenceable(schema) } + func isInlinable(_ schema: UnresolvedSchema?) -> Bool { !isReferenceable(schema) } /// Return a reference to a multipart element type if the provided schema is referenceable. /// - Parameters: /// - schema: The schema to try to reference. /// - encoding: The associated encoding. /// - Returns: A reference if the schema is referenceable, nil otherwise. - static func multipartElementTypeReferenceIfReferenceable( + func multipartElementTypeReferenceIfReferenceable( schema: UnresolvedSchema?, encoding: OrderedDictionary? ) -> OpenAPI.Reference? { @@ -174,11 +174,9 @@ struct TypeMatcher { /// - components: The reusable components from the OpenAPI document. /// - Throws: An error if there's an issue while checking the schema. /// - Returns: `true` if the schema is a key-value pair; `false` otherwise. - static func isKeyValuePair( - _ schema: JSONSchema, - referenceStack: inout ReferenceStack, - components: OpenAPI.Components - ) throws -> Bool { + func isKeyValuePair(_ schema: JSONSchema, referenceStack: inout ReferenceStack, components: OpenAPI.Components) + throws -> Bool + { switch schema.value { case .object, .fragment: return true case .null, .boolean, .number, .integer, .string, .array, .not: return false @@ -222,7 +220,7 @@ struct TypeMatcher { /// - components: The reusable components from the OpenAPI document. /// - Throws: An error if there's an issue while checking the schema. /// - Returns: `true` if the schema is a key-value pair; `false` otherwise. - static func isKeyValuePair( + func isKeyValuePair( _ schema: UnresolvedSchema?, referenceStack: inout ReferenceStack, components: OpenAPI.Components @@ -285,7 +283,7 @@ struct TypeMatcher { /// - Parameter schema: The schema to match a referenceable type for. /// - Returns: A type usage for the schema if the schema is built-in. /// Otherwise, returns nil. - private static func _tryMatchBuiltinNonRecursive(for schema: JSONSchema.Schema) -> TypeUsage? { + private func _tryMatchBuiltinNonRecursive(for schema: JSONSchema.Schema) -> TypeUsage? { let typeName: TypeName switch schema { case .boolean(_): typeName = .swift("Bool") diff --git a/Tests/OpenAPIGeneratorCoreTests/Translator/TypeAssignment/Test_TypeMatcher.swift b/Tests/OpenAPIGeneratorCoreTests/Translator/TypeAssignment/Test_TypeMatcher.swift index a7e0b8e3..6ca197d2 100644 --- a/Tests/OpenAPIGeneratorCoreTests/Translator/TypeAssignment/Test_TypeMatcher.swift +++ b/Tests/OpenAPIGeneratorCoreTests/Translator/TypeAssignment/Test_TypeMatcher.swift @@ -127,8 +127,8 @@ final class Test_TypeMatcher: Test_Core { .fullyQualifiedSwiftName, name ) - XCTAssertTrue(TypeMatcher.isReferenceable(schema)) - XCTAssertFalse(TypeMatcher.isInlinable(schema)) + XCTAssertTrue(typeMatcher.isReferenceable(schema)) + XCTAssertFalse(typeMatcher.isInlinable(schema)) } } @@ -145,8 +145,8 @@ final class Test_TypeMatcher: Test_Core { typeMatcher.tryMatchBuiltinType(for: schema.value), "Type is expected to not match a builtin type: \(schema)" ) - XCTAssertFalse(TypeMatcher.isReferenceable(schema), "Expected schema not to be referenceable: \(schema)") - XCTAssertTrue(TypeMatcher.isInlinable(schema), "Expected schema to be inlinable: \(schema)") + XCTAssertFalse(typeMatcher.isReferenceable(schema), "Expected schema not to be referenceable: \(schema)") + XCTAssertTrue(typeMatcher.isInlinable(schema), "Expected schema to be inlinable: \(schema)") } } @@ -175,7 +175,7 @@ final class Test_TypeMatcher: Test_Core { for schema in Self.keyValuePairTypes { var referenceStack = ReferenceStack.empty XCTAssertTrue( - try TypeMatcher.isKeyValuePair(schema, referenceStack: &referenceStack, components: components), + try typeMatcher.isKeyValuePair(schema, referenceStack: &referenceStack, components: components), "Type is expected to be a key-value pair schema: \(schema)" ) } @@ -249,7 +249,7 @@ final class Test_TypeMatcher: Test_Core { ] func testMultipartElementTypeReferenceIfReferenceableTypes() throws { for (schema, encoding, name) in Self.multipartElementTypeReferenceIfReferenceableTypes { - let actualName = TypeMatcher.multipartElementTypeReferenceIfReferenceable( + let actualName = typeMatcher.multipartElementTypeReferenceIfReferenceable( schema: schema, encoding: encoding )? @@ -257,5 +257,4 @@ final class Test_TypeMatcher: Test_Core { XCTAssertEqual(actualName, name) } } - }