diff --git a/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift index ab1da8ee7..c90bbffbf 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift @@ -15,7 +15,6 @@ */ struct IDLToStructuredSwiftTranslator: Translator { - private let typealiasTranslator = TypealiasTranslator() private let serverCodeTranslator = ServerCodeTranslator() func translate( @@ -23,13 +22,14 @@ struct IDLToStructuredSwiftTranslator: Translator { client: Bool, server: Bool ) throws -> StructuredSwiftRepresentation { + let typealiasTranslator = TypealiasTranslator(client: client, server: server) let topComment = Comment.doc(codeGenerationRequest.leadingTrivia) let imports: [ImportDescription] = [ ImportDescription(moduleName: "GRPCCore") ] var codeBlocks: [CodeBlock] = [] codeBlocks.append( - contentsOf: try self.typealiasTranslator.translate(from: codeGenerationRequest) + contentsOf: try typealiasTranslator.translate(from: codeGenerationRequest) ) if server { diff --git a/Sources/GRPCCodeGen/Internal/Translator/TypealiasTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/TypealiasTranslator.swift index 1737b38ae..a502675df 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/TypealiasTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/TypealiasTranslator.swift @@ -53,6 +53,14 @@ /// A ``CodeGenerationRequest`` can contain multiple namespaces, so the TypealiasTranslator will create a ``CodeBlock`` /// for each namespace. struct TypealiasTranslator: SpecializedTranslator { + let client: Bool + let server: Bool + + init(client: Bool, server: Bool) { + self.client = client + self.server = server + } + func translate(from codeGenerationRequest: CodeGenerationRequest) throws -> [CodeBlock] { var codeBlocks: [CodeBlock] = [] let services = codeGenerationRequest.services @@ -169,9 +177,21 @@ extension TypealiasTranslator { let methodDescriptorsDeclaration = self.makeMethodDescriptors(for: service) serviceEnum.members.append(methodDescriptorsDeclaration) - // Create the streaming and non-streaming service protocol type aliases. - let serviceProtocols = self.makeServiceProtocolsTypealiases(for: service) - serviceEnum.members.append(contentsOf: serviceProtocols) + if self.server { + // Create the streaming and non-streaming service protocol type aliases. + let serviceProtocols = self.makeServiceProtocolsTypealiases(for: service) + serviceEnum.members.append(contentsOf: serviceProtocols) + } + + if self.client { + // Create the client protocol type alias. + let clientProtocol = self.makeClientProtocolTypealias(for: service) + serviceEnum.members.append(clientProtocol) + + // Create type alias for Client struct. + let clientStruct = self.makeClientStructTypealias(for: service) + serviceEnum.members.append(clientStruct) + } return .enum(serviceEnum) } @@ -236,7 +256,7 @@ extension TypealiasTranslator { let descriptorDeclarationRight = Expression.functionCall( FunctionCallDescription( - calledExpression: .identifierType(.member(["MethodDescriptor"])), + calledExpression: .identifierType(.member("MethodDescriptor")), arguments: [ FunctionArgumentDescription( label: "service", @@ -277,7 +297,7 @@ extension TypealiasTranslator { isStatic: true, kind: .let, left: .identifier(.pattern("methods")), - type: .array(.member(["MethodDescriptor"])), + type: .array(.member("MethodDescriptor")), right: .literal(.array(methodDescriptors)) ) } @@ -285,26 +305,33 @@ extension TypealiasTranslator { private func makeServiceProtocolsTypealiases( for service: CodeGenerationRequest.ServiceDescriptor ) -> [Declaration] { - let namespacedPrefix: String - - if service.namespace.isEmpty { - namespacedPrefix = service.name - } else { - namespacedPrefix = "\(service.namespace)_\(service.name)" - } - - let streamingServiceProtocolName = "\(namespacedPrefix)ServiceStreamingProtocol" let streamingServiceProtocolTypealias = Declaration.typealias( name: "StreamingServiceProtocol", - existingType: .member([streamingServiceProtocolName]) + existingType: .member("\(service.namespacedPrefix)ServiceStreamingProtocol") ) - - let serviceProtocolName = "\(namespacedPrefix)ServiceProtocol" let serviceProtocolTypealias = Declaration.typealias( name: "ServiceProtocol", - existingType: .member([serviceProtocolName]) + existingType: .member("\(service.namespacedPrefix)ServiceProtocol") ) return [streamingServiceProtocolTypealias, serviceProtocolTypealias] } + + private func makeClientProtocolTypealias( + for service: CodeGenerationRequest.ServiceDescriptor + ) -> Declaration { + return .typealias( + name: "ClientProtocol", + existingType: .member("\(service.namespacedPrefix)ClientProtocol") + ) + } + + private func makeClientStructTypealias( + for service: CodeGenerationRequest.ServiceDescriptor + ) -> Declaration { + return .typealias( + name: "Client", + existingType: .member("\(service.namespacedPrefix)Client") + ) + } } diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift index f888faab3..b677217cd 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift @@ -58,13 +58,125 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { ] typealias StreamingServiceProtocol = namespaceA_ServiceAServiceStreamingProtocol typealias ServiceProtocol = namespaceA_ServiceAServiceProtocol + typealias ClientProtocol = namespaceA_ServiceAClientProtocol + typealias Client = namespaceA_ServiceAClient } } """ try self.assertTypealiasTranslation( codeGenerationRequest: makeCodeGenerationRequest(services: [service]), - expectedSwift: expectedSwift + expectedSwift: expectedSwift, + client: true, + server: true + ) + } + + func testTypealiasTranslatorNoMethodsServiceClientAndServer() throws { + let service = ServiceDescriptor( + documentation: "Documentation for ServiceA", + name: "ServiceA", + namespace: "namespaceA", + methods: [] + ) + let expectedSwift = + """ + enum namespaceA { + enum ServiceA { + enum Methods {} + static let methods: [MethodDescriptor] = [] + typealias StreamingServiceProtocol = namespaceA_ServiceAServiceStreamingProtocol + typealias ServiceProtocol = namespaceA_ServiceAServiceProtocol + typealias ClientProtocol = namespaceA_ServiceAClientProtocol + typealias Client = namespaceA_ServiceAClient + } + } + """ + + try self.assertTypealiasTranslation( + codeGenerationRequest: makeCodeGenerationRequest(services: [service]), + expectedSwift: expectedSwift, + client: true, + server: true + ) + } + + func testTypealiasTranslatorServer() throws { + let service = ServiceDescriptor( + documentation: "Documentation for ServiceA", + name: "ServiceA", + namespace: "namespaceA", + methods: [] + ) + let expectedSwift = + """ + enum namespaceA { + enum ServiceA { + enum Methods {} + static let methods: [MethodDescriptor] = [] + typealias StreamingServiceProtocol = namespaceA_ServiceAServiceStreamingProtocol + typealias ServiceProtocol = namespaceA_ServiceAServiceProtocol + } + } + """ + + try self.assertTypealiasTranslation( + codeGenerationRequest: makeCodeGenerationRequest(services: [service]), + expectedSwift: expectedSwift, + client: false, + server: true + ) + } + + func testTypealiasTranslatorClient() throws { + let service = ServiceDescriptor( + documentation: "Documentation for ServiceA", + name: "ServiceA", + namespace: "namespaceA", + methods: [] + ) + let expectedSwift = + """ + enum namespaceA { + enum ServiceA { + enum Methods {} + static let methods: [MethodDescriptor] = [] + typealias ClientProtocol = namespaceA_ServiceAClientProtocol + typealias Client = namespaceA_ServiceAClient + } + } + """ + + try self.assertTypealiasTranslation( + codeGenerationRequest: makeCodeGenerationRequest(services: [service]), + expectedSwift: expectedSwift, + client: true, + server: false + ) + } + + func testTypealiasTranslatorNoClientNoServer() throws { + let service = ServiceDescriptor( + documentation: "Documentation for ServiceA", + name: "ServiceA", + namespace: "namespaceA", + methods: [] + ) + let expectedSwift = + """ + enum namespaceA { + enum ServiceA { + enum Methods {} + static let methods: [MethodDescriptor] = [] + } + } + """ + + try self.assertTypealiasTranslation( + codeGenerationRequest: makeCodeGenerationRequest(services: [service]), + expectedSwift: expectedSwift, + client: false, + server: false ) } @@ -101,12 +213,16 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { ] typealias StreamingServiceProtocol = ServiceAServiceStreamingProtocol typealias ServiceProtocol = ServiceAServiceProtocol + typealias ClientProtocol = ServiceAClientProtocol + typealias Client = ServiceAClient } """ try self.assertTypealiasTranslation( codeGenerationRequest: makeCodeGenerationRequest(services: [service]), - expectedSwift: expectedSwift + expectedSwift: expectedSwift, + client: true, + server: true ) } @@ -161,13 +277,17 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { ] typealias StreamingServiceProtocol = namespaceA_ServiceAServiceStreamingProtocol typealias ServiceProtocol = namespaceA_ServiceAServiceProtocol + typealias ClientProtocol = namespaceA_ServiceAClientProtocol + typealias Client = namespaceA_ServiceAClient } } """ try self.assertTypealiasTranslation( codeGenerationRequest: makeCodeGenerationRequest(services: [service]), - expectedSwift: expectedSwift + expectedSwift: expectedSwift, + client: true, + server: true ) } @@ -186,13 +306,17 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { static let methods: [MethodDescriptor] = [] typealias StreamingServiceProtocol = namespaceA_ServiceAServiceStreamingProtocol typealias ServiceProtocol = namespaceA_ServiceAServiceProtocol + typealias ClientProtocol = namespaceA_ServiceAClientProtocol + typealias Client = namespaceA_ServiceAClient } } """ try self.assertTypealiasTranslation( codeGenerationRequest: makeCodeGenerationRequest(services: [service]), - expectedSwift: expectedSwift + expectedSwift: expectedSwift, + client: true, + server: true ) } @@ -219,19 +343,25 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { static let methods: [MethodDescriptor] = [] typealias StreamingServiceProtocol = namespacea_AServiceServiceStreamingProtocol typealias ServiceProtocol = namespacea_AServiceServiceProtocol + typealias ClientProtocol = namespacea_AServiceClientProtocol + typealias Client = namespacea_AServiceClient } enum BService { enum Methods {} static let methods: [MethodDescriptor] = [] typealias StreamingServiceProtocol = namespacea_BServiceServiceStreamingProtocol typealias ServiceProtocol = namespacea_BServiceServiceProtocol + typealias ClientProtocol = namespacea_BServiceClientProtocol + typealias Client = namespacea_BServiceClient } } """ try self.assertTypealiasTranslation( codeGenerationRequest: makeCodeGenerationRequest(services: [serviceB, serviceA]), - expectedSwift: expectedSwift + expectedSwift: expectedSwift, + client: true, + server: true ) } @@ -257,18 +387,24 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { static let methods: [MethodDescriptor] = [] typealias StreamingServiceProtocol = AServiceServiceStreamingProtocol typealias ServiceProtocol = AServiceServiceProtocol + typealias ClientProtocol = AServiceClientProtocol + typealias Client = AServiceClient } enum BService { enum Methods {} static let methods: [MethodDescriptor] = [] typealias StreamingServiceProtocol = BServiceServiceStreamingProtocol typealias ServiceProtocol = BServiceServiceProtocol + typealias ClientProtocol = BServiceClientProtocol + typealias Client = BServiceClient } """ try self.assertTypealiasTranslation( codeGenerationRequest: makeCodeGenerationRequest(services: [serviceB, serviceA]), - expectedSwift: expectedSwift + expectedSwift: expectedSwift, + client: true, + server: true ) } @@ -295,6 +431,8 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { static let methods: [MethodDescriptor] = [] typealias StreamingServiceProtocol = anamespace_AServiceServiceStreamingProtocol typealias ServiceProtocol = anamespace_AServiceServiceProtocol + typealias ClientProtocol = anamespace_AServiceClientProtocol + typealias Client = anamespace_AServiceClient } } enum bnamespace { @@ -303,13 +441,17 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { static let methods: [MethodDescriptor] = [] typealias StreamingServiceProtocol = bnamespace_BServiceServiceStreamingProtocol typealias ServiceProtocol = bnamespace_BServiceServiceProtocol + typealias ClientProtocol = bnamespace_BServiceClientProtocol + typealias Client = bnamespace_BServiceClient } } """ try self.assertTypealiasTranslation( codeGenerationRequest: makeCodeGenerationRequest(services: [serviceB, serviceA]), - expectedSwift: expectedSwift + expectedSwift: expectedSwift, + client: true, + server: true ) } @@ -333,6 +475,8 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { static let methods: [MethodDescriptor] = [] typealias StreamingServiceProtocol = BServiceServiceStreamingProtocol typealias ServiceProtocol = BServiceServiceProtocol + typealias ClientProtocol = BServiceClientProtocol + typealias Client = BServiceClient } enum anamespace { enum AService { @@ -340,13 +484,17 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { static let methods: [MethodDescriptor] = [] typealias StreamingServiceProtocol = anamespace_AServiceServiceStreamingProtocol typealias ServiceProtocol = anamespace_AServiceServiceProtocol + typealias ClientProtocol = anamespace_AServiceClientProtocol + typealias Client = anamespace_AServiceClient } } """ try self.assertTypealiasTranslation( codeGenerationRequest: makeCodeGenerationRequest(services: [serviceA, serviceB]), - expectedSwift: expectedSwift + expectedSwift: expectedSwift, + client: true, + server: true ) } @@ -359,7 +507,7 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { ) let codeGenerationRequest = makeCodeGenerationRequest(services: [serviceA, serviceA]) - let translator = TypealiasTranslator() + let translator = TypealiasTranslator(client: true, server: true) XCTAssertThrowsError( ofType: CodeGenError.self, try translator.translate(from: codeGenerationRequest) @@ -387,7 +535,7 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { ) let codeGenerationRequest = makeCodeGenerationRequest(services: [serviceA, serviceA]) - let translator = TypealiasTranslator() + let translator = TypealiasTranslator(client: true, server: true) XCTAssertThrowsError( ofType: CodeGenError.self, try translator.translate(from: codeGenerationRequest) @@ -423,7 +571,7 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { ) let codeGenerationRequest = makeCodeGenerationRequest(services: [service]) - let translator = TypealiasTranslator() + let translator = TypealiasTranslator(client: true, server: true) XCTAssertThrowsError( ofType: CodeGenError.self, try translator.translate(from: codeGenerationRequest) @@ -456,7 +604,7 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { methods: [] ) let codeGenerationRequest = makeCodeGenerationRequest(services: [serviceA, serviceB]) - let translator = TypealiasTranslator() + let translator = TypealiasTranslator(client: true, server: true) XCTAssertThrowsError( ofType: CodeGenError.self, try translator.translate(from: codeGenerationRequest) @@ -479,9 +627,11 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase { extension TypealiasTranslatorSnippetBasedTests { private func assertTypealiasTranslation( codeGenerationRequest: CodeGenerationRequest, - expectedSwift: String + expectedSwift: String, + client: Bool, + server: Bool ) throws { - let translator = TypealiasTranslator() + let translator = TypealiasTranslator(client: client, server: server) let codeBlocks = try translator.translate(from: codeGenerationRequest) let renderer = TextBasedRenderer.default renderer.renderCodeBlocks(codeBlocks)