From f7e1b16b90d1891f13ce0dcc8552f6c62a750ccf Mon Sep 17 00:00:00 2001 From: George Barnett Date: Mon, 20 Jan 2025 17:30:41 +0000 Subject: [PATCH 1/2] Simplify code gen lib interface Motivation: When reviewing APIs I noticed a few inconsistencies and some abstractions which are more complicated than they need to be. We should simplify this before we commit to a stable API. Modifications: - Replace the 'Name' type with a more concrete 'ServiceName' and 'MethodName'. They carry approximately equivalent information but the information is expressed in terms of what the names are used for (i.e. a function vs. what the expected format of the name is, e.g. lowercase). This makes it easier for users to understand how the names will be used and leaves room for more customisation in the future. - The service descriptor used two names: a namespace name and a service name. These have now been compressed into a single object (not all namespace name values were used). The namespace name was never used in isolation so this was adding unnecessary complexity. - The top-level 'SourceGenerator' type has been renamed 'CodeGenerator'. This is consistent with being a 'CodeGen' module and having a 'CodeGenerationRequest'. - The closures for returning code snippets to create a serializer/deserializer were renamed to make their user clearer. - Accidental public API was removed. Result: Slightly smaller and more consistent API. --- .../GRPCCodeGen/CodeGenerationRequest.swift | 210 ++++++++++++++---- ...rceGenerator.swift => CodeGenerator.swift} | 12 +- .../Internal/StructuredSwift+Client.swift | 14 +- .../Internal/StructuredSwift+Server.swift | 20 +- .../StructuredSwift+ServiceMetadata.swift | 18 +- .../Translator/ClientCodeTranslator.swift | 12 +- .../IDLToStructuredSwiftTranslator.swift | 56 ++--- .../Translator/ServerCodeTranslator.swift | 20 +- .../Translator/SpecializedTranslator.swift | 2 +- .../Internal/Translator/Translator.swift | 2 +- .../StructuredSwift+ClientTests.swift | 39 ++-- .../StructuredSwift+ImportTests.swift | 8 +- .../StructuredSwift+MetadataTests.swift | 4 +- .../StructuredSwift+ServerTests.swift | 12 +- ...lientCodeTranslatorSnippetBasedTests.swift | 9 +- ...uredSwiftTranslatorSnippetBasedTests.swift | 139 ++++++------ ...erverCodeTranslatorSnippetBasedTests.swift | 15 +- .../Internal/Translator/TestFunctions.swift | 4 +- ...TypealiasTranslatorSnippetBasedTests.swift | 13 +- 19 files changed, 365 insertions(+), 244 deletions(-) rename Sources/GRPCCodeGen/{SourceGenerator.swift => CodeGenerator.swift} (89%) diff --git a/Sources/GRPCCodeGen/CodeGenerationRequest.swift b/Sources/GRPCCodeGen/CodeGenerationRequest.swift index d6d0f73d1..f6b91d8bd 100644 --- a/Sources/GRPCCodeGen/CodeGenerationRequest.swift +++ b/Sources/GRPCCodeGen/CodeGenerationRequest.swift @@ -44,11 +44,11 @@ public struct CodeGenerationRequest { /// /// For example, to serialize Protobuf messages you could specify a serializer as: /// ```swift - /// request.lookupSerializer = { messageType in + /// request.makeSerializerCodeSnippet = { messageType in /// "ProtobufSerializer<\(messageType)>()" /// } /// ``` - public var lookupSerializer: (_ messageType: String) -> String + public var makeSerializerCodeSnippet: (_ messageType: String) -> String /// Closure that receives a message type as a `String` and returns a code snippet to /// initialize a `MessageDeserializer` for that type as a `String`. @@ -58,26 +58,64 @@ public struct CodeGenerationRequest { /// /// For example, to serialize Protobuf messages you could specify a serializer as: /// ```swift - /// request.lookupDeserializer = { messageType in + /// request.makeDeserializerCodeSnippet = { messageType in /// "ProtobufDeserializer<\(messageType)>()" /// } /// ``` - public var lookupDeserializer: (_ messageType: String) -> String + public var makeDeserializerCodeSnippet: (_ messageType: String) -> String public init( fileName: String, leadingTrivia: String, dependencies: [Dependency], services: [ServiceDescriptor], - lookupSerializer: @escaping (String) -> String, - lookupDeserializer: @escaping (String) -> String + makeSerializerCodeSnippet: @escaping (_ messageType: String) -> String, + makeDeserializerCodeSnippet: @escaping (_ messageType: String) -> String ) { self.fileName = fileName self.leadingTrivia = leadingTrivia self.dependencies = dependencies self.services = services - self.lookupSerializer = lookupSerializer - self.lookupDeserializer = lookupDeserializer + self.makeSerializerCodeSnippet = makeSerializerCodeSnippet + self.makeDeserializerCodeSnippet = makeDeserializerCodeSnippet + } +} + +extension CodeGenerationRequest { + @available(*, deprecated, renamed: "makeSerializerSnippet") + public var lookupSerializer: (_ messageType: String) -> String { + get { self.makeSerializerCodeSnippet } + set { self.makeSerializerCodeSnippet = newValue } + } + + @available(*, deprecated, renamed: "makeDeserializerSnippet") + public var lookupDeserializer: (_ messageType: String) -> String { + get { self.makeDeserializerCodeSnippet } + set { self.makeDeserializerCodeSnippet = newValue } + } + + @available( + *, + deprecated, + renamed: + "init(fileName:leadingTrivia:dependencies:services:lookupSerializer:lookupDeserializer:)" + ) + public init( + fileName: String, + leadingTrivia: String, + dependencies: [Dependency], + services: [ServiceDescriptor], + lookupSerializer: @escaping (String) -> String, + lookupDeserializer: @escaping (String) -> String + ) { + self.init( + fileName: fileName, + leadingTrivia: leadingTrivia, + dependencies: dependencies, + services: services, + makeSerializerCodeSnippet: lookupSerializer, + makeDeserializerCodeSnippet: lookupDeserializer + ) } } @@ -88,7 +126,7 @@ public struct Dependency: Equatable { public var item: Item? /// The access level to be included in imports of this dependency. - public var accessLevel: SourceGenerator.Config.AccessLevel + public var accessLevel: CodeGenerator.Config.AccessLevel /// The name of the imported module or of the module an item is imported from. public var module: String @@ -107,7 +145,7 @@ public struct Dependency: Equatable { module: String, spi: String? = nil, preconcurrency: PreconcurrencyRequirement = .notRequired, - accessLevel: SourceGenerator.Config.AccessLevel + accessLevel: CodeGenerator.Config.AccessLevel ) { self.item = item self.module = module @@ -228,23 +266,27 @@ public struct ServiceDescriptor: Hashable { /// It is already formatted, meaning it contains "///" and new lines. public var documentation: String - /// The service name in different formats. - /// - /// All properties of this object must be unique for each service from within a namespace. - public var name: Name - - /// The service namespace in different formats. - /// - /// All different services from within the same namespace must have - /// the same ``Name`` object as this property. - /// For `.proto` files the base name of this object is the package name. - public var namespace: Name + /// The name of the service. + public var name: ServiceName /// A description of each method of a service. /// /// - SeeAlso: ``MethodDescriptor``. public var methods: [MethodDescriptor] + public init( + documentation: String, + name: ServiceName, + methods: [MethodDescriptor] + ) { + self.documentation = documentation + self.name = name + self.methods = methods + } +} + +extension ServiceDescriptor { + @available(*, deprecated, renamed: "init(documentation:name:methods:)") public init( documentation: String, name: Name, @@ -252,9 +294,25 @@ public struct ServiceDescriptor: Hashable { methods: [MethodDescriptor] ) { self.documentation = documentation - self.name = name - self.namespace = namespace self.methods = methods + + let identifier = namespace.base.isEmpty ? name.base : namespace.base + "." + name.base + + let upper = + namespace.generatedUpperCase.isEmpty + ? name.generatedUpperCase + : namespace.generatedUpperCase + "_" + name.generatedUpperCase + + let lower = + namespace.generatedLowerCase.isEmpty + ? name.generatedUpperCase + : namespace.generatedLowerCase + "_" + name.generatedUpperCase + + self.name = ServiceName( + identifyingName: identifier, + typeName: upper, + propertyName: lower + ) } } @@ -268,7 +326,7 @@ public struct MethodDescriptor: Hashable { /// /// All properties of this object must be unique for each method /// from within a service. - public var name: Name + public var name: MethodName /// Identifies if the method is input streaming. public var isInputStreaming: Bool @@ -284,7 +342,7 @@ public struct MethodDescriptor: Hashable { public init( documentation: String, - name: Name, + name: MethodName, isInputStreaming: Bool, isOutputStreaming: Bool, inputType: String, @@ -299,7 +357,94 @@ public struct MethodDescriptor: Hashable { } } +extension MethodDescriptor { + @available(*, deprecated, message: "Use MethodName instead of Name") + public init( + documentation: String, + name: Name, + isInputStreaming: Bool, + isOutputStreaming: Bool, + inputType: String, + outputType: String + ) { + self.documentation = documentation + self.name = MethodName( + identifyingName: name.base, + typeName: name.generatedUpperCase, + functionName: name.generatedLowerCase + ) + self.isInputStreaming = isInputStreaming + self.isOutputStreaming = isOutputStreaming + self.inputType = inputType + self.outputType = outputType + } +} + +public struct ServiceName: Hashable { + /// The identifying name as used in the service/method descriptors including any namespace. + /// + /// This value is also used to identify the service to the remote peer, usually as part of the + /// ":path" pseudoheader if doing gRPC over HTTP/2. + /// + /// If the service is declared in package "foo.bar" and the service is called "Baz" then this + /// value should be "foo.bar.Baz". + public var identifyingName: String + + /// The name as used on types including any namespace. + /// + /// This is used to generate a namespace for each service which contains a number of client and + /// server protocols and concrete types. + /// + /// If the service is declared in package "foo.bar" and the service is called "Baz" then this + /// value should be "Foo\_Bar\_Baz". + public var typeName: String + + /// The name as used as a property. + /// + /// This is used to provide a convenience getter for a descriptor of the service. + /// + /// If the service is declared in package "foo.bar" and the service is called "Baz" then this + /// value should be "foo\_bar\_Baz". + public var propertyName: String + + public init(identifyingName: String, typeName: String, propertyName: String) { + self.identifyingName = identifyingName + self.typeName = typeName + self.propertyName = propertyName + } +} + +public struct MethodName: Hashable { + /// The identifying name as used in the service/method descriptors. + /// + /// This value is also used to identify the method to the remote peer, usually as part of the + /// ":path" pseudoheader if doing gRPC over HTTP/2. + /// + /// This value typically starts with an uppercase character, for example "Get". + public var identifyingName: String + + /// The name as used on types including any namespace. + /// + /// This is used to generate a namespace for each method which contains information about + /// the method. + /// + /// This value typically starts with an uppercase character, for example "Get". + public var typeName: String + + /// The name as used as a property. + /// + /// This value typically starts with an lowercase character, for example "get". + public var functionName: String + + public init(identifyingName: String, typeName: String, functionName: String) { + self.identifyingName = identifyingName + self.typeName = typeName + self.functionName = functionName + } +} + /// Represents the name associated with a namespace, service or a method, in three different formats. +@available(*, deprecated, message: "Use ServiceName/MethodName instead.") public struct Name: Hashable { /// The base name is the name used for the namespace/service/method in the IDL file, so it should follow /// the specific casing of the IDL. @@ -327,6 +472,7 @@ public struct Name: Hashable { } } +@available(*, deprecated, message: "Use ServiceName/MethodName instead.") extension Name { /// The base name replacing occurrences of "." with "_". /// @@ -335,17 +481,3 @@ extension Name { return self.base.replacing(".", with: "_") } } - -extension ServiceDescriptor { - var namespacedServicePropertyName: String { - let prefix: String - - if self.namespace.normalizedBase.isEmpty { - prefix = "" - } else { - prefix = self.namespace.normalizedBase + "_" - } - - return prefix + self.name.normalizedBase - } -} diff --git a/Sources/GRPCCodeGen/SourceGenerator.swift b/Sources/GRPCCodeGen/CodeGenerator.swift similarity index 89% rename from Sources/GRPCCodeGen/SourceGenerator.swift rename to Sources/GRPCCodeGen/CodeGenerator.swift index e8a92ec5f..adac1a6c9 100644 --- a/Sources/GRPCCodeGen/SourceGenerator.swift +++ b/Sources/GRPCCodeGen/CodeGenerator.swift @@ -14,8 +14,12 @@ * limitations under the License. */ -/// Creates a ``SourceFile`` containing the generated code for the RPCs represented in a ``CodeGenerationRequest`` object. -public struct SourceGenerator: Sendable { +@available(*, deprecated, renamed: "CodeGenerator") +public typealias SourceGenerator = CodeGenerator + +/// Generates ``SourceFile`` objects containing generated code for the RPCs represented +/// in a ``CodeGenerationRequest`` object. +public struct CodeGenerator: Sendable { /// The options regarding the access level, indentation for the generated code /// and whether to generate server and client code. public var config: Config @@ -79,8 +83,8 @@ public struct SourceGenerator: Sendable { } } - /// The function that transforms a ``CodeGenerationRequest`` object into a ``SourceFile`` object containing - /// the generated code, in accordance to the configurations set by the user for the ``SourceGenerator``. + /// Transforms a ``CodeGenerationRequest`` object into a ``SourceFile`` object containing + /// the generated code. public func generate( _ request: CodeGenerationRequest ) throws -> SourceFile { diff --git a/Sources/GRPCCodeGen/Internal/StructuredSwift+Client.swift b/Sources/GRPCCodeGen/Internal/StructuredSwift+Client.swift index 4e9cc905b..511724702 100644 --- a/Sources/GRPCCodeGen/Internal/StructuredSwift+Client.swift +++ b/Sources/GRPCCodeGen/Internal/StructuredSwift+Client.swift @@ -213,7 +213,7 @@ extension ProtocolDescription { .preFormatted(docs(for: method)), .function( signature: .clientMethod( - name: method.name.generatedLowerCase, + name: method.name.functionName, input: method.inputType, output: method.outputType, streamingInput: method.isInputStreaming, @@ -256,7 +256,7 @@ extension ExtensionDescription { .function( .clientMethodWithDefaults( accessLevel: accessLevel, - name: method.name.generatedLowerCase, + name: method.name.functionName, input: method.inputType, output: method.outputType, streamingInput: method.isInputStreaming, @@ -506,7 +506,7 @@ extension ExtensionDescription { .function( .clientMethodExploded( accessLevel: accessLevel, - name: method.name.generatedLowerCase, + name: method.name.functionName, input: method.inputType, output: method.outputType, streamingInput: method.isInputStreaming, @@ -716,11 +716,11 @@ extension StructDescription { .function( .clientMethod( accessLevel: accessLevel, - name: method.name.generatedLowerCase, + name: method.name.functionName, input: method.inputType, output: method.outputType, serviceEnum: serviceEnum, - methodEnum: method.name.generatedUpperCase, + methodEnum: method.name.typeName, streamingInput: method.isInputStreaming, streamingOutput: method.isOutputStreaming ) @@ -735,7 +735,7 @@ private func docs( for method: MethodDescriptor, serializers includeSerializers: Bool = true ) -> String { - let summary = "/// Call the \"\(method.name.base)\" method." + let summary = "/// Call the \"\(method.name.identifyingName)\" method." let request: String if method.isInputStreaming { @@ -773,7 +773,7 @@ private func docs( } private func explodedDocs(for method: MethodDescriptor) -> String { - let summary = "/// Call the \"\(method.name.base)\" method." + let summary = "/// Call the \"\(method.name.identifyingName)\" method." var parameters = """ /// - Parameters: """ diff --git a/Sources/GRPCCodeGen/Internal/StructuredSwift+Server.swift b/Sources/GRPCCodeGen/Internal/StructuredSwift+Server.swift index 7af446a5e..a3525c13e 100644 --- a/Sources/GRPCCodeGen/Internal/StructuredSwift+Server.swift +++ b/Sources/GRPCCodeGen/Internal/StructuredSwift+Server.swift @@ -58,7 +58,7 @@ extension ProtocolDescription { ) -> Self { func docs(for method: MethodDescriptor) -> String { let summary = """ - /// Handle the "\(method.name.normalizedBase)" method. + /// Handle the "\(method.name.identifyingName)" method. """ let parameters = """ @@ -83,7 +83,7 @@ extension ProtocolDescription { .preFormatted(docs(for: method)), .function( signature: .serverMethod( - name: method.name.generatedLowerCase, + name: method.name.functionName, input: method.inputType, output: method.outputType, streamingInput: true, @@ -143,7 +143,7 @@ extension ProtocolDescription { ) -> Self { func docs(for method: MethodDescriptor) -> String { let summary = """ - /// Handle the "\(method.name.normalizedBase)" method. + /// Handle the "\(method.name.identifyingName)" method. """ let request: String @@ -182,7 +182,7 @@ extension ProtocolDescription { .preFormatted(docs(for: method)), .function( signature: .serverMethod( - name: method.name.generatedLowerCase, + name: method.name.functionName, input: method.inputType, output: method.outputType, streamingInput: method.isInputStreaming, @@ -329,8 +329,8 @@ extension FunctionDescription { .functionCall( .registerWithRouter( serviceNamespace: serviceNamespace, - methodNamespace: method.name.generatedUpperCase, - methodName: method.name.generatedLowerCase, + methodNamespace: method.name.typeName, + methodName: method.name.functionName, inputDeserializer: deserializer(method.inputType), outputSerializer: serializer(method.outputType) ) @@ -468,7 +468,7 @@ extension ExtensionDescription { return .function( .serverStreamingMethodsCallingMethod( accessLevel: accessModifier, - name: method.name.generatedLowerCase, + name: method.name.functionName, input: method.inputType, output: method.outputType, streamingInput: method.isInputStreaming, @@ -540,7 +540,7 @@ extension ProtocolDescription { ) -> Self { func docs(for method: MethodDescriptor) -> String { let summary = """ - /// Handle the "\(method.name.normalizedBase)" method. + /// Handle the "\(method.name.identifyingName)" method. """ let requestText = @@ -587,7 +587,7 @@ extension ProtocolDescription { .preFormatted(docs(for: method)), .function( signature: .simpleServerMethod( - name: method.name.generatedLowerCase, + name: method.name.functionName, input: method.inputType, output: method.outputType, streamingInput: method.isInputStreaming, @@ -754,7 +754,7 @@ extension ExtensionDescription { .function( .serviceProtocolDefaultImplementation( accessModifier: accessModifier, - name: method.name.generatedLowerCase, + name: method.name.functionName, input: method.inputType, output: method.outputType, streamingInput: method.isInputStreaming, diff --git a/Sources/GRPCCodeGen/Internal/StructuredSwift+ServiceMetadata.swift b/Sources/GRPCCodeGen/Internal/StructuredSwift+ServiceMetadata.swift index 2804eaab0..18502832a 100644 --- a/Sources/GRPCCodeGen/Internal/StructuredSwift+ServiceMetadata.swift +++ b/Sources/GRPCCodeGen/Internal/StructuredSwift+ServiceMetadata.swift @@ -236,12 +236,12 @@ extension EnumDescription { // Add a namespace for each method. let methodNamespaces: [Declaration] = methods.map { method in return .commentable( - .doc("Namespace for \"\(method.name.base)\" metadata."), + .doc("Namespace for \"\(method.name.typeName)\" metadata."), .enum( .methodNamespace( accessModifier: accessModifier, - name: method.name.base, - literalMethod: method.name.base, + name: method.name.typeName, + literalMethod: method.name.identifyingName, literalFullyQualifiedService: literalFullyQualifiedService, inputType: method.inputType, outputType: method.outputType @@ -254,7 +254,7 @@ extension EnumDescription { // Add an array of method descriptors let methodDescriptorsArray: VariableDescription = .methodDescriptorsArray( accessModifier: accessModifier, - methodNamespaceNames: methods.map { $0.name.base } + methodNamespaceNames: methods.map { $0.name.typeName } ) description.members.append( .commentable( @@ -329,14 +329,14 @@ extension [CodeBlock] { let serviceNamespace: EnumDescription = .serviceNamespace( accessModifier: accessModifier, - name: service.namespacedGeneratedName, - literalFullyQualifiedService: service.fullyQualifiedName, + name: service.name.typeName, + literalFullyQualifiedService: service.name.identifyingName, methods: service.methods ) blocks.append( CodeBlock( comment: .doc( - "Namespace containing generated types for the \"\(service.fullyQualifiedName)\" service." + "Namespace containing generated types for the \"\(service.name.identifyingName)\" service." ), item: .declaration(.enum(serviceNamespace)) ) @@ -344,8 +344,8 @@ extension [CodeBlock] { let descriptorExtension: ExtensionDescription = .serviceDescriptor( accessModifier: accessModifier, - propertyName: service.namespacedServicePropertyName, - literalFullyQualifiedService: service.fullyQualifiedName + propertyName: service.name.propertyName, + literalFullyQualifiedService: service.name.identifyingName ) blocks.append(CodeBlock(item: .declaration(.extension(descriptorExtension)))) diff --git a/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift index b77cddbb9..611c09078 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift @@ -87,13 +87,13 @@ struct ClientCodeTranslator { var blocks = [CodeBlock]() let `extension` = ExtensionDescription( - onType: service.namespacedGeneratedName, + onType: service.name.typeName, declarations: [ // protocol ClientProtocol { ... } .commentable( .preFormatted( Docs.suffix( - self.clientProtocolDocs(serviceName: service.fullyQualifiedName), + self.clientProtocolDocs(serviceName: service.name.identifyingName), withDocs: service.documentation ) ), @@ -110,7 +110,7 @@ struct ClientCodeTranslator { .commentable( .preFormatted( Docs.suffix( - self.clientDocs(serviceName: service.fullyQualifiedName), + self.clientDocs(serviceName: service.name.identifyingName), withDocs: service.documentation ) ), @@ -118,7 +118,7 @@ struct ClientCodeTranslator { .client( accessLevel: accessModifier, name: "Client", - serviceEnum: service.namespacedGeneratedName, + serviceEnum: service.name.typeName, clientProtocol: "ClientProtocol", methods: service.methods ) @@ -130,7 +130,7 @@ struct ClientCodeTranslator { let extensionWithDefaults: ExtensionDescription = .clientMethodSignatureWithDefaults( accessLevel: accessModifier, - name: "\(service.namespacedGeneratedName).ClientProtocol", + name: "\(service.name.typeName).ClientProtocol", methods: service.methods, serializer: serializer, deserializer: deserializer @@ -144,7 +144,7 @@ struct ClientCodeTranslator { let extensionWithExplodedAPI: ExtensionDescription = .explodedClientMethods( accessLevel: accessModifier, - on: "\(service.namespacedGeneratedName).ClientProtocol", + on: "\(service.name.typeName).ClientProtocol", methods: service.methods ) blocks.append( diff --git a/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift index eccc65ba3..2d3a7746e 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift @@ -22,7 +22,7 @@ package struct IDLToStructuredSwiftTranslator: Translator { func translate( codeGenerationRequest: CodeGenerationRequest, - accessLevel: SourceGenerator.Config.AccessLevel, + accessLevel: CodeGenerator.Config.AccessLevel, accessLevelOnImports: Bool, client: Bool, server: Bool @@ -37,7 +37,7 @@ package struct IDLToStructuredSwiftTranslator: Translator { for service in codeGenerationRequest.services { codeBlocks.append( - CodeBlock(comment: .mark("\(service.fullyQualifiedName)", sectionBreak: true)) + CodeBlock(comment: .mark("\(service.name.identifyingName)", sectionBreak: true)) ) let metadata = metadataTranslator.translate( @@ -48,27 +48,27 @@ package struct IDLToStructuredSwiftTranslator: Translator { if server { codeBlocks.append( - CodeBlock(comment: .mark("\(service.fullyQualifiedName) (server)", sectionBreak: false)) + CodeBlock(comment: .mark("\(service.name.identifyingName) (server)", sectionBreak: false)) ) let blocks = serverTranslator.translate( accessModifier: accessModifier, service: service, - serializer: codeGenerationRequest.lookupSerializer, - deserializer: codeGenerationRequest.lookupDeserializer + serializer: codeGenerationRequest.makeSerializerCodeSnippet, + deserializer: codeGenerationRequest.makeDeserializerCodeSnippet ) codeBlocks.append(contentsOf: blocks) } if client { codeBlocks.append( - CodeBlock(comment: .mark("\(service.fullyQualifiedName) (client)", sectionBreak: false)) + CodeBlock(comment: .mark("\(service.name.identifyingName) (client)", sectionBreak: false)) ) let blocks = clientTranslator.translate( accessModifier: accessModifier, service: service, - serializer: codeGenerationRequest.lookupSerializer, - deserializer: codeGenerationRequest.lookupDeserializer + serializer: codeGenerationRequest.makeSerializerCodeSnippet, + deserializer: codeGenerationRequest.makeDeserializerCodeSnippet ) codeBlocks.append(contentsOf: blocks) } @@ -101,7 +101,7 @@ package struct IDLToStructuredSwiftTranslator: Translator { package func makeImports( dependencies: [Dependency], - accessLevel: SourceGenerator.Config.AccessLevel, + accessLevel: CodeGenerator.Config.AccessLevel, accessLevelOnImports: Bool ) throws -> [ImportDescription] { var imports: [ImportDescription] = [] @@ -125,7 +125,7 @@ package struct IDLToStructuredSwiftTranslator: Translator { } extension AccessModifier { - init(_ accessLevel: SourceGenerator.Config.AccessLevel) { + init(_ accessLevel: CodeGenerator.Config.AccessLevel) { switch accessLevel.level { case .internal: self = .internal case .package: self = .package @@ -173,7 +173,7 @@ extension IDLToStructuredSwiftTranslator { let servicesByGeneratedEnumName = Dictionary( grouping: codeGenerationRequest.services, - by: { $0.namespacedGeneratedName } + by: { $0.name.typeName } ) try self.checkServiceEnumNamesAreUnique(for: servicesByGeneratedEnumName) @@ -205,39 +205,39 @@ extension IDLToStructuredSwiftTranslator { ) throws { // Check that the method descriptors are unique, by checking that the base names // of the methods of a specific service are unique. - let baseNames = service.methods.map { $0.name.base } + let baseNames = service.methods.map { $0.name.identifyingName } if let duplicatedBase = baseNames.getFirstDuplicate() { throw CodeGenError( code: .nonUniqueMethodName, message: """ Methods of a service must have unique base names. \ - \(duplicatedBase) is used as a base name for multiple methods of the \(service.name.base) service. + \(duplicatedBase) is used as a base name for multiple methods of the \(service.name.identifyingName) service. """ ) } // Check that generated upper case names for methods are unique within a service, to ensure that // the enums containing type aliases for each method of a service. - let upperCaseNames = service.methods.map { $0.name.generatedUpperCase } + let upperCaseNames = service.methods.map { $0.name.typeName } if let duplicatedGeneratedUpperCase = upperCaseNames.getFirstDuplicate() { throw CodeGenError( code: .nonUniqueMethodName, message: """ Methods of a service must have unique generated upper case names. \ - \(duplicatedGeneratedUpperCase) is used as a generated upper case name for multiple methods of the \(service.name.base) service. + \(duplicatedGeneratedUpperCase) is used as a generated upper case name for multiple methods of the \(service.name.identifyingName) service. """ ) } // Check that generated lower case names for methods are unique within a service, to ensure that // the function declarations and definitions from the same protocols and extensions have unique names. - let lowerCaseNames = service.methods.map { $0.name.generatedLowerCase } + let lowerCaseNames = service.methods.map { $0.name.functionName } if let duplicatedLowerCase = lowerCaseNames.getFirstDuplicate() { throw CodeGenError( code: .nonUniqueMethodName, message: """ Methods of a service must have unique lower case names. \ - \(duplicatedLowerCase) is used as a signature name for multiple methods of the \(service.name.base) service. + \(duplicatedLowerCase) is used as a signature name for multiple methods of the \(service.name.identifyingName) service. """ ) } @@ -248,9 +248,7 @@ extension IDLToStructuredSwiftTranslator { ) throws { var descriptors: Set = [] for service in services { - let name = - service.namespace.base.isEmpty - ? service.name.base : "\(service.namespace.base).\(service.name.base)" + let name = service.name.identifyingName let (inserted, _) = descriptors.insert(name) if !inserted { throw CodeGenError( @@ -265,24 +263,6 @@ extension IDLToStructuredSwiftTranslator { } } -extension ServiceDescriptor { - var namespacedGeneratedName: String { - if self.namespace.generatedUpperCase.isEmpty { - return self.name.generatedUpperCase - } else { - return "\(self.namespace.generatedUpperCase)_\(self.name.generatedUpperCase)" - } - } - - var fullyQualifiedName: String { - if self.namespace.base.isEmpty { - return self.name.base - } else { - return "\(self.namespace.base).\(self.name.base)" - } - } -} - extension [String] { internal func getFirstDuplicate() -> String? { var seen = Set() diff --git a/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift index a2e91a83e..e563981e6 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift @@ -69,13 +69,13 @@ struct ServerCodeTranslator { var blocks = [CodeBlock]() let `extension` = ExtensionDescription( - onType: service.namespacedGeneratedName, + onType: service.name.typeName, declarations: [ // protocol StreamingServiceProtocol { ... } .commentable( .preFormatted( Docs.suffix( - self.streamingServiceDocs(serviceName: service.fullyQualifiedName), + self.streamingServiceDocs(serviceName: service.name.identifyingName), withDocs: service.documentation ) ), @@ -92,7 +92,7 @@ struct ServerCodeTranslator { .commentable( .preFormatted( Docs.suffix( - self.serviceDocs(serviceName: service.fullyQualifiedName), + self.serviceDocs(serviceName: service.name.identifyingName), withDocs: service.documentation ) ), @@ -100,7 +100,7 @@ struct ServerCodeTranslator { .service( accessLevel: accessModifier, name: "ServiceProtocol", - streamingProtocol: "\(service.namespacedGeneratedName).StreamingServiceProtocol", + streamingProtocol: "\(service.name.typeName).StreamingServiceProtocol", methods: service.methods ) ) @@ -110,7 +110,7 @@ struct ServerCodeTranslator { .commentable( .preFormatted( Docs.suffix( - self.simpleServiceDocs(serviceName: service.fullyQualifiedName), + self.simpleServiceDocs(serviceName: service.name.identifyingName), withDocs: service.documentation ) ), @@ -118,7 +118,7 @@ struct ServerCodeTranslator { .simpleServiceProtocol( accessModifier: accessModifier, name: "SimpleServiceProtocol", - serviceProtocol: "\(service.namespacedGeneratedName).ServiceProtocol", + serviceProtocol: "\(service.name.typeName).ServiceProtocol", methods: service.methods ) ) @@ -130,8 +130,8 @@ struct ServerCodeTranslator { // extension .StreamingServiceProtocol> { ... } let registerExtension: ExtensionDescription = .registrableRPCServiceDefaultImplementation( accessLevel: accessModifier, - on: "\(service.namespacedGeneratedName).StreamingServiceProtocol", - serviceNamespace: service.namespacedGeneratedName, + on: "\(service.name.typeName).StreamingServiceProtocol", + serviceNamespace: service.name.typeName, methods: service.methods, serializer: serializer, deserializer: deserializer @@ -147,7 +147,7 @@ struct ServerCodeTranslator { let streamingServiceDefaultImplExtension: ExtensionDescription = .streamingServiceProtocolDefaultImplementation( accessModifier: accessModifier, - on: "\(service.namespacedGeneratedName).ServiceProtocol", + on: "\(service.name.typeName).ServiceProtocol", methods: service.methods ) blocks.append( @@ -162,7 +162,7 @@ struct ServerCodeTranslator { // extension _SimpleServiceProtocol { ... } let serviceDefaultImplExtension: ExtensionDescription = .serviceProtocolDefaultImplementation( accessModifier: accessModifier, - on: "\(service.namespacedGeneratedName).SimpleServiceProtocol", + on: "\(service.name.typeName).SimpleServiceProtocol", methods: service.methods ) blocks.append( diff --git a/Sources/GRPCCodeGen/Internal/Translator/SpecializedTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/SpecializedTranslator.swift index 1db3fce02..1ac3c4bee 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/SpecializedTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/SpecializedTranslator.swift @@ -19,7 +19,7 @@ protocol SpecializedTranslator { /// The ``SourceGenerator.Config.AccessLevel`` object used to represent the visibility level used in the generated code. - var accessLevel: SourceGenerator.Config.AccessLevel { get } + var accessLevel: CodeGenerator.Config.AccessLevel { get } /// Generates an array of ``CodeBlock`` elements that will be part of the ``StructuredSwiftRepresentation`` object /// created by the ``Translator``. diff --git a/Sources/GRPCCodeGen/Internal/Translator/Translator.swift b/Sources/GRPCCodeGen/Internal/Translator/Translator.swift index 36b1c665f..9d0a043b0 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/Translator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/Translator.swift @@ -29,7 +29,7 @@ protocol Translator { /// - Throws: An error if there are issues translating the codeGenerationRequest. func translate( codeGenerationRequest: CodeGenerationRequest, - accessLevel: SourceGenerator.Config.AccessLevel, + accessLevel: CodeGenerator.Config.AccessLevel, accessLevelOnImports: Bool, client: Bool, server: Bool diff --git a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ClientTests.swift b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ClientTests.swift index 6404a751a..700a8b895 100644 --- a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ClientTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ClientTests.swift @@ -103,7 +103,7 @@ extension StructuredSwiftTests { methods: [ .init( documentation: "/// Some docs", - name: .init(base: "Bar", generatedUpperCase: "Bar", generatedLowerCase: "bar"), + name: MethodName(identifyingName: "Bar", typeName: "Bar", functionName: "bar"), isInputStreaming: false, isOutputStreaming: false, inputType: "BarInput", @@ -187,7 +187,7 @@ extension StructuredSwiftTests { methods: [ MethodDescriptor( documentation: "", - name: .init(base: "Bar", generatedUpperCase: "Bar", generatedLowerCase: "bar"), + name: MethodName(identifyingName: "Bar", typeName: "Bar", functionName: "bar"), isInputStreaming: false, isOutputStreaming: false, inputType: "BarInput", @@ -342,7 +342,7 @@ extension StructuredSwiftTests { methods: [ .init( documentation: "/// Some docs", - name: .init(base: "Bar", generatedUpperCase: "Bar", generatedLowerCase: "bar"), + name: MethodName(identifyingName: "Bar", typeName: "Bar", functionName: "bar"), isInputStreaming: false, isOutputStreaming: true, inputType: "Input", @@ -439,10 +439,10 @@ extension StructuredSwiftTests { methods: [ .init( documentation: "/// Unary docs", - name: .init( - base: "Unary", - generatedUpperCase: "Unary", - generatedLowerCase: "unary" + name: MethodName( + identifyingName: "Unary", + typeName: "Unary", + functionName: "unary" ), isInputStreaming: false, isOutputStreaming: false, @@ -451,11 +451,12 @@ extension StructuredSwiftTests { ), .init( documentation: "/// ClientStreaming docs", - name: .init( - base: "ClientStreaming", - generatedUpperCase: "ClientStreaming", - generatedLowerCase: "clientStreaming" + name: MethodName( + identifyingName: "ClientStreaming", + typeName: "ClientStreaming", + functionName: "clientStreaming" ), + isInputStreaming: true, isOutputStreaming: false, inputType: "Input", @@ -463,10 +464,10 @@ extension StructuredSwiftTests { ), .init( documentation: "/// ServerStreaming docs", - name: .init( - base: "ServerStreaming", - generatedUpperCase: "ServerStreaming", - generatedLowerCase: "serverStreaming" + name: MethodName( + identifyingName: "ServerStreaming", + typeName: "ServerStreaming", + functionName: "serverStreaming" ), isInputStreaming: false, isOutputStreaming: true, @@ -475,10 +476,10 @@ extension StructuredSwiftTests { ), .init( documentation: "/// BidiStreaming docs", - name: .init( - base: "BidiStreaming", - generatedUpperCase: "BidiStreaming", - generatedLowerCase: "bidiStreaming" + name: MethodName( + identifyingName: "BidiStreaming", + typeName: "BidiStreaming", + functionName: "bidiStreaming" ), isInputStreaming: true, isOutputStreaming: true, diff --git a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ImportTests.swift b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ImportTests.swift index ff1d34dbe..c079d5f5c 100644 --- a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ImportTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ImportTests.swift @@ -22,7 +22,7 @@ extension StructuredSwiftTests { struct Import { static let translator = IDLToStructuredSwiftTranslator() - static let allAccessLevels: [SourceGenerator.Config.AccessLevel] = [ + static let allAccessLevels: [CodeGenerator.Config.AccessLevel] = [ .internal, .public, .package, ] @@ -30,7 +30,7 @@ extension StructuredSwiftTests { "import rendering", arguments: allAccessLevels ) - func imports(accessLevel: SourceGenerator.Config.AccessLevel) throws { + func imports(accessLevel: CodeGenerator.Config.AccessLevel) throws { var dependencies = [Dependency]() dependencies.append(Dependency(module: "Foo", accessLevel: .public)) dependencies.append( @@ -117,7 +117,7 @@ extension StructuredSwiftTests { "preconcurrency import rendering", arguments: allAccessLevels ) - func preconcurrencyImports(accessLevel: SourceGenerator.Config.AccessLevel) throws { + func preconcurrencyImports(accessLevel: CodeGenerator.Config.AccessLevel) throws { var dependencies = [Dependency]() dependencies.append( Dependency( @@ -167,7 +167,7 @@ extension StructuredSwiftTests { "SPI import rendering", arguments: allAccessLevels ) - func spiImports(accessLevel: SourceGenerator.Config.AccessLevel) throws { + func spiImports(accessLevel: CodeGenerator.Config.AccessLevel) throws { var dependencies = [Dependency]() dependencies.append( Dependency(module: "Foo", spi: "Secret", accessLevel: .internal) diff --git a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+MetadataTests.swift b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+MetadataTests.swift index 1b8d9afd2..06c87be43 100644 --- a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+MetadataTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+MetadataTests.swift @@ -143,7 +143,7 @@ extension StructuredSwiftTests { methods: [ .init( documentation: "", - name: .init(base: "Foo", generatedUpperCase: "Foo", generatedLowerCase: "foo"), + name: MethodName(identifyingName: "Foo", typeName: "Foo", functionName: "foo"), isInputStreaming: false, isOutputStreaming: false, inputType: "FooInput", @@ -201,7 +201,7 @@ extension StructuredSwiftTests { methods: [ .init( documentation: "", - name: .init(base: "Bar", generatedUpperCase: "Bar", generatedLowerCase: "bar"), + name: MethodName(identifyingName: "Bar", typeName: "Bar", functionName: "bar"), isInputStreaming: false, isOutputStreaming: false, inputType: "BarInput", diff --git a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ServerTests.swift b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ServerTests.swift index ba44a6896..7db009ce4 100644 --- a/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ServerTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/StructuredSwift+ServerTests.swift @@ -80,7 +80,7 @@ extension StructuredSwiftTests { methods: [ .init( documentation: "/// Some docs", - name: .init(base: "Foo", generatedUpperCase: "Foo", generatedLowerCase: "foo"), + name: MethodName(identifyingName: "Foo", typeName: "Foo", functionName: "foo"), isInputStreaming: false, isOutputStreaming: false, inputType: "FooInput", @@ -123,7 +123,7 @@ extension StructuredSwiftTests { methods: [ .init( documentation: "/// Some docs", - name: .init(base: "Foo", generatedUpperCase: "Foo", generatedLowerCase: "foo"), + name: MethodName(identifyingName: "Foo", typeName: "Foo", functionName: "foo"), isInputStreaming: false, isOutputStreaming: false, inputType: "FooInput", @@ -206,7 +206,7 @@ extension StructuredSwiftTests { methods: [ .init( documentation: "", - name: .init(base: "Bar", generatedUpperCase: "Bar", generatedLowerCase: "bar"), + name: MethodName(identifyingName: "Bar", typeName: "Bar", functionName: "bar"), isInputStreaming: false, isOutputStreaming: false, inputType: "BarInput", @@ -321,7 +321,7 @@ extension StructuredSwiftTests { methods: [ .init( documentation: "", - name: .init(base: "Foo", generatedUpperCase: "Foo", generatedLowerCase: "foo"), + name: MethodName(identifyingName: "Foo", typeName: "Foo", functionName: "foo"), isInputStreaming: false, isOutputStreaming: false, inputType: "FooInput", @@ -330,7 +330,7 @@ extension StructuredSwiftTests { // Will be ignored as a bidirectional streaming method. .init( documentation: "", - name: .init(base: "Bar", generatedUpperCase: "Bar", generatedLowerCase: "bar"), + name: MethodName(identifyingName: "Bar", typeName: "Bar", functionName: "bar"), isInputStreaming: true, isOutputStreaming: true, inputType: "BarInput", @@ -421,7 +421,7 @@ extension StructuredSwiftTests { methods: [ .init( documentation: "", - name: .init(base: "Foo", generatedUpperCase: "Foo", generatedLowerCase: "foo"), + name: MethodName(identifyingName: "Foo", typeName: "Foo", functionName: "foo"), isInputStreaming: false, isOutputStreaming: false, inputType: "Input", diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift index 7d1d7504d..fd380c806 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift @@ -24,7 +24,7 @@ struct ClientCodeTranslatorSnippetBasedTests { func translate() { let method = MethodDescriptor( documentation: "/// Documentation for MethodA", - name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"), + name: MethodName(identifyingName: "MethodA", typeName: "MethodA", functionName: "methodA"), isInputStreaming: false, isOutputStreaming: false, inputType: "NamespaceA_ServiceARequest", @@ -33,8 +33,11 @@ struct ClientCodeTranslatorSnippetBasedTests { let service = ServiceDescriptor( documentation: "/// Documentation for ServiceA", - name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""), - namespace: Name(base: "namespaceA", generatedUpperCase: "NamespaceA", generatedLowerCase: ""), + name: ServiceName( + identifyingName: "namespaceA.ServiceA", + typeName: "NamespaceA_ServiceA", + propertyName: "" + ), methods: [method] ) diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/IDLToStructuredSwiftTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/IDLToStructuredSwiftTranslatorSnippetBasedTests.swift index e765f52fe..1848df575 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/IDLToStructuredSwiftTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/IDLToStructuredSwiftTranslatorSnippetBasedTests.swift @@ -37,11 +37,10 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { let serviceA = ServiceDescriptor( documentation: "/// Documentation for AService\n", - name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: "serviceA"), - namespace: Name( - base: "namespaceA", - generatedUpperCase: "NamespaceA", - generatedLowerCase: "namespaceA" + name: ServiceName( + identifyingName: "namespaceA.ServiceA", + typeName: "NamespaceA_ServiceA", + propertyName: "namespaceA_ServiceA" ), methods: [] ) @@ -161,7 +160,7 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { private func assertIDLToStructuredSwiftTranslation( codeGenerationRequest: CodeGenerationRequest, expectedSwift: String, - accessLevel: SourceGenerator.Config.AccessLevel, + accessLevel: CodeGenerator.Config.AccessLevel, server: Bool = false ) throws { let translator = IDLToStructuredSwiftTranslator() @@ -181,8 +180,11 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { func testSameNameServicesNoNamespaceError() throws { let serviceA = ServiceDescriptor( documentation: "Documentation for AService", - name: Name(base: "AService", generatedUpperCase: "AService", generatedLowerCase: "aService"), - namespace: Name(base: "", generatedUpperCase: "", generatedLowerCase: ""), + name: ServiceName( + identifyingName: "AService", + typeName: "AService", + propertyName: "aService" + ), methods: [] ) @@ -215,15 +217,21 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { func testSameDescriptorsServicesNoNamespaceError() throws { let serviceA = ServiceDescriptor( documentation: "Documentation for AService", - name: Name(base: "AService", generatedUpperCase: "AService", generatedLowerCase: "aService"), - namespace: Name(base: "", generatedUpperCase: "", generatedLowerCase: ""), + name: ServiceName( + identifyingName: "AService", + typeName: "AService", + propertyName: "aService" + ), methods: [] ) let serviceB = ServiceDescriptor( documentation: "Documentation for BService", - name: Name(base: "AService", generatedUpperCase: "AService", generatedLowerCase: "aService"), - namespace: Name(base: "", generatedUpperCase: "", generatedLowerCase: ""), + name: ServiceName( + identifyingName: "AService", + typeName: "AService", + propertyName: "aService" + ), methods: [] ) @@ -254,11 +262,10 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { func testSameDescriptorsSameNamespaceError() throws { let serviceA = ServiceDescriptor( documentation: "Documentation for AService", - name: Name(base: "AService", generatedUpperCase: "AService", generatedLowerCase: "aService"), - namespace: Name( - base: "namespacea", - generatedUpperCase: "NamespaceA", - generatedLowerCase: "namespacea" + name: ServiceName( + identifyingName: "namespacea.AService", + typeName: "NamespaceA_AService", + propertyName: "namespacea_aService" ), methods: [] ) @@ -292,21 +299,19 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { func testSameGeneratedNameServicesSameNamespaceError() throws { let serviceA = ServiceDescriptor( documentation: "/// Documentation for AService\n", - name: Name(base: "AService", generatedUpperCase: "AService", generatedLowerCase: "aService"), - namespace: Name( - base: "namespacea", - generatedUpperCase: "NamespaceA", - generatedLowerCase: "namespacea" + name: ServiceName( + identifyingName: "namespacea.AService", + typeName: "NamespaceA_AService", + propertyName: "namespacea_aService" ), methods: [] ) let serviceB = ServiceDescriptor( documentation: "/// Documentation for BService\n", - name: Name(base: "BService", generatedUpperCase: "AService", generatedLowerCase: "aService"), - namespace: Name( - base: "namespacea", - generatedUpperCase: "NamespaceA", - generatedLowerCase: "namespacea" + name: ServiceName( + identifyingName: "namespacea.BService", + typeName: "NamespaceA_AService", + propertyName: "namespacea_aService" ), methods: [] ) @@ -322,8 +327,7 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { client: true, server: true ) - ) { - error in + ) { error in XCTAssertEqual( error as CodeGenError, CodeGenError( @@ -340,7 +344,7 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { func testSameBaseNameMethodsSameServiceError() throws { let methodA = MethodDescriptor( documentation: "Documentation for MethodA", - name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"), + name: MethodName(identifyingName: "MethodA", typeName: "MethodA", functionName: "methodA"), isInputStreaming: false, isOutputStreaming: false, inputType: "NamespaceA_ServiceARequest", @@ -348,11 +352,10 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { ) let service = ServiceDescriptor( documentation: "Documentation for AService", - name: Name(base: "AService", generatedUpperCase: "AService", generatedLowerCase: "aService"), - namespace: Name( - base: "namespacea", - generatedUpperCase: "NamespaceA", - generatedLowerCase: "namespacea" + name: ServiceName( + identifyingName: "namespacea.AService", + typeName: "NamespaceA_AService", + propertyName: "namespacea_aService" ), methods: [methodA, methodA] ) @@ -368,15 +371,14 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { client: true, server: true ) - ) { - error in + ) { error in XCTAssertEqual( error as CodeGenError, CodeGenError( code: .nonUniqueMethodName, message: """ Methods of a service must have unique base names. \ - MethodA is used as a base name for multiple methods of the AService service. + MethodA is used as a base name for multiple methods of the namespacea.AService service. """ ) ) @@ -386,7 +388,11 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { func testSameGeneratedUpperCaseNameMethodsSameServiceError() throws { let methodA = MethodDescriptor( documentation: "Documentation for MethodA", - name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"), + name: MethodName( + identifyingName: "MethodA", + typeName: "MethodA", + functionName: "methodA" + ), isInputStreaming: false, isOutputStreaming: false, inputType: "NamespaceA_ServiceARequest", @@ -394,7 +400,11 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { ) let methodB = MethodDescriptor( documentation: "Documentation for MethodA", - name: Name(base: "MethodB", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"), + name: MethodName( + identifyingName: "MethodB", + typeName: "MethodA", + functionName: "methodA" + ), isInputStreaming: false, isOutputStreaming: false, inputType: "NamespaceA_ServiceARequest", @@ -402,11 +412,10 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { ) let service = ServiceDescriptor( documentation: "Documentation for AService", - name: Name(base: "AService", generatedUpperCase: "AService", generatedLowerCase: "aService"), - namespace: Name( - base: "namespacea", - generatedUpperCase: "NamespaceA", - generatedLowerCase: "namespacea" + name: ServiceName( + identifyingName: "namespacea.AService", + typeName: "NamespaceA_AService", + propertyName: "namespacea_AService" ), methods: [methodA, methodB] ) @@ -422,15 +431,15 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { client: true, server: true ) - ) { - error in + ) { error in XCTAssertEqual( error as CodeGenError, CodeGenError( code: .nonUniqueMethodName, message: """ Methods of a service must have unique generated upper case names. \ - MethodA is used as a generated upper case name for multiple methods of the AService service. + MethodA is used as a generated upper case name for multiple methods of the \ + namespacea.AService service. """ ) ) @@ -440,7 +449,7 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { func testSameLowerCaseNameMethodsSameServiceError() throws { let methodA = MethodDescriptor( documentation: "Documentation for MethodA", - name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"), + name: MethodName(identifyingName: "MethodA", typeName: "MethodA", functionName: "methodA"), isInputStreaming: false, isOutputStreaming: false, inputType: "NamespaceA_ServiceARequest", @@ -448,7 +457,7 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { ) let methodB = MethodDescriptor( documentation: "Documentation for MethodA", - name: Name(base: "MethodB", generatedUpperCase: "MethodB", generatedLowerCase: "methodA"), + name: MethodName(identifyingName: "MethodB", typeName: "MethodB", functionName: "methodA"), isInputStreaming: false, isOutputStreaming: false, inputType: "NamespaceA_ServiceARequest", @@ -456,11 +465,10 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { ) let service = ServiceDescriptor( documentation: "Documentation for AService", - name: Name(base: "AService", generatedUpperCase: "AService", generatedLowerCase: "aService"), - namespace: Name( - base: "namespacea", - generatedUpperCase: "NamespaceA", - generatedLowerCase: "namespacea" + name: ServiceName( + identifyingName: "namespacea.AService", + typeName: "NamespaceA_AService", + propertyName: "namespacea_aService" ), methods: [methodA, methodB] ) @@ -484,7 +492,8 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { code: .nonUniqueMethodName, message: """ Methods of a service must have unique lower case names. \ - methodA is used as a signature name for multiple methods of the AService service. + methodA is used as a signature name for multiple methods of the \ + namespacea.AService service. """ ) ) @@ -494,21 +503,19 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase { func testSameGeneratedNameNoNamespaceServiceAndNamespaceError() throws { let serviceA = ServiceDescriptor( documentation: "Documentation for SameName service with no namespace", - name: Name( - base: "SameName", - generatedUpperCase: "SameName_BService", - generatedLowerCase: "sameName" + name: ServiceName( + identifyingName: "SameName", + typeName: "SameName_BService", + propertyName: "sameName" ), - namespace: Name(base: "", generatedUpperCase: "", generatedLowerCase: ""), methods: [] ) let serviceB = ServiceDescriptor( documentation: "Documentation for BService", - name: Name(base: "BService", generatedUpperCase: "BService", generatedLowerCase: "bService"), - namespace: Name( - base: "sameName", - generatedUpperCase: "SameName", - generatedLowerCase: "sameName" + name: ServiceName( + identifyingName: "sameName.BService", + typeName: "SameName_BService", + propertyName: "sameName" ), methods: [] ) diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift index b0475ce50..1b41acc1c 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift @@ -24,7 +24,7 @@ final class ServerCodeTranslatorSnippetBasedTests { func translate() { let method = MethodDescriptor( documentation: "/// Documentation for unaryMethod", - name: Name(base: "UnaryMethod", generatedUpperCase: "Unary", generatedLowerCase: "unary"), + name: MethodName(identifyingName: "UnaryMethod", typeName: "Unary", functionName: "unary"), isInputStreaming: false, isOutputStreaming: false, inputType: "NamespaceA_ServiceARequest", @@ -33,15 +33,10 @@ final class ServerCodeTranslatorSnippetBasedTests { let service = ServiceDescriptor( documentation: "/// Documentation for ServiceA", - name: Name( - base: "AlongNameForServiceA", - generatedUpperCase: "ServiceA", - generatedLowerCase: "serviceA" - ), - namespace: Name( - base: "namespaceA", - generatedUpperCase: "NamespaceA", - generatedLowerCase: "namespaceA" + name: ServiceName( + identifyingName: "namespaceA.AlongNameForServiceA", + typeName: "NamespaceA_ServiceA", + propertyName: "namespaceA_serviceA" ), methods: [method] ) diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/TestFunctions.swift b/Tests/GRPCCodeGenTests/Internal/Translator/TestFunctions.swift index 24c7dd330..afd957638 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/TestFunctions.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/TestFunctions.swift @@ -80,10 +80,10 @@ internal func makeCodeGenerationRequest( leadingTrivia: "/// Some really exciting license header 2023.\n", dependencies: dependencies, services: services, - lookupSerializer: { + makeSerializerCodeSnippet: { "GRPCProtobuf.ProtobufSerializer<\($0)>()" }, - lookupDeserializer: { + makeDeserializerCodeSnippet: { "GRPCProtobuf.ProtobufDeserializer<\($0)>()" } ) diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift index 8713b784a..ba6d4d249 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift @@ -24,7 +24,7 @@ struct TypealiasTranslatorSnippetBasedTests { func testTypealiasTranslator() throws { let method = MethodDescriptor( documentation: "Documentation for MethodA", - name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"), + name: MethodName(identifyingName: "MethodA", typeName: "MethodA", functionName: "methodA"), isInputStreaming: false, isOutputStreaming: false, inputType: "NamespaceA_ServiceARequest", @@ -32,11 +32,10 @@ struct TypealiasTranslatorSnippetBasedTests { ) let service = ServiceDescriptor( documentation: "Documentation for ServiceA", - name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: "serviceA"), - namespace: Name( - base: "namespaceA", - generatedUpperCase: "NamespaceA", - generatedLowerCase: "namespaceA" + name: ServiceName( + identifyingName: "namespaceA.ServiceA", + typeName: "NamespaceA_ServiceA", + propertyName: "namespaceA_ServiceA" ), methods: [method] ) @@ -78,7 +77,7 @@ struct TypealiasTranslatorSnippetBasedTests { extension TypealiasTranslatorSnippetBasedTests { func render( - accessLevel: SourceGenerator.Config.AccessLevel, + accessLevel: CodeGenerator.Config.AccessLevel, service: ServiceDescriptor ) -> String { let translator = MetadataTranslator() From 1c9706ef92a265d1eaab81713c5f22985e1e6b6c Mon Sep 17 00:00:00 2001 From: George Barnett Date: Wed, 22 Jan 2025 16:59:27 +0000 Subject: [PATCH 2/2] Fix naming --- Sources/GRPCCodeGen/CodeGenerationRequest.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/GRPCCodeGen/CodeGenerationRequest.swift b/Sources/GRPCCodeGen/CodeGenerationRequest.swift index f6b91d8bd..fc69c1bcf 100644 --- a/Sources/GRPCCodeGen/CodeGenerationRequest.swift +++ b/Sources/GRPCCodeGen/CodeGenerationRequest.swift @@ -298,20 +298,20 @@ extension ServiceDescriptor { let identifier = namespace.base.isEmpty ? name.base : namespace.base + "." + name.base - let upper = + let typeName = namespace.generatedUpperCase.isEmpty ? name.generatedUpperCase : namespace.generatedUpperCase + "_" + name.generatedUpperCase - let lower = + let propertyName = namespace.generatedLowerCase.isEmpty ? name.generatedUpperCase : namespace.generatedLowerCase + "_" + name.generatedUpperCase self.name = ServiceName( identifyingName: identifier, - typeName: upper, - propertyName: lower + typeName: typeName, + propertyName: propertyName ) } }