From 6218f4b4d0ea62261aad10d86510e660f1689660 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Tue, 1 Oct 2024 12:02:59 +0200 Subject: [PATCH 1/2] [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/2] 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