Browse Source

Simplify generated code (#2131)

Motivation:

A number of things have changed since the generated code was initially
designed, which means it can be simplified and improved.

Modifications:

- As services are namespaced within a namespace-service enum (rather
than within a service enum in a namespace enum), they no longer need to
be grouped by namespace.
- As deployment targets must be set in the package manifest, the
generated code no longer needs to be annotated with availability guards
so these have been removed.

Result:

Simpler code generation, better generated code.
George Barnett 1 year ago
parent
commit
d70fbad6c4

+ 3 - 2
Sources/GRPCCodeGen/Internal/Renderer/TextBasedRenderer.swift

@@ -1134,8 +1134,9 @@ struct TextBasedRenderer: RendererProtocol {
   /// Renders the specified code block.
   func renderCodeBlock(_ description: CodeBlock) {
     if let comment = description.comment { renderComment(comment) }
-    let item = description.item
-    renderCodeBlockItem(item)
+    if let item = description.item {
+      renderCodeBlockItem(item)
+    }
   }
 
   /// Renders the specified code blocks.

+ 7 - 10
Sources/GRPCCodeGen/Internal/StructuredSwift+Server.swift

@@ -97,16 +97,13 @@ extension ExtensionDescription {
     return ExtensionDescription(
       onType: extensionName,
       declarations: [
-        .guarded(
-          .grpc,
-          .function(
-            .registerMethods(
-              accessLevel: accessLevel,
-              serviceNamespace: serviceNamespace,
-              methods: methods,
-              serializer: serializer,
-              deserializer: deserializer
-            )
+        .function(
+          .registerMethods(
+            accessLevel: accessLevel,
+            serviceNamespace: serviceNamespace,
+            methods: methods,
+            serializer: serializer,
+            deserializer: deserializer
           )
         )
       ]

+ 4 - 7
Sources/GRPCCodeGen/Internal/StructuredSwift+ServiceMetadata.swift

@@ -288,13 +288,10 @@ extension EnumDescription {
       typealiasNames.append("Client")
     }
     let typealiases: [Declaration] = typealiasNames.map { alias in
-      .guarded(
-        .grpc,
-        .typealias(
-          accessModifier: accessModifier,
-          name: alias,
-          existingType: .member(name + "_" + alias)
-        )
+      .typealias(
+        accessModifier: accessModifier,
+        name: alias,
+        existingType: .member(name + "_" + alias)
       )
     }
     description.members.append(contentsOf: typealiases)

+ 0 - 12
Sources/GRPCCodeGen/Internal/StructuredSwift+Types.swift

@@ -14,18 +14,6 @@
  * limitations under the License.
  */
 
-extension AvailabilityDescription {
-  package static let grpc = AvailabilityDescription(
-    osVersions: [
-      OSVersion(os: .macOS, version: "15.0"),
-      OSVersion(os: .iOS, version: "18.0"),
-      OSVersion(os: .watchOS, version: "11.0"),
-      OSVersion(os: .tvOS, version: "18.0"),
-      OSVersion(os: .visionOS, version: "2.0"),
-    ]
-  )
-}
-
 extension ExistingTypeDescription {
   fileprivate static func grpcCore(_ typeName: String) -> Self {
     return .member(["GRPCCore", typeName])

+ 1 - 1
Sources/GRPCCodeGen/Internal/StructuredSwiftRepresentation.swift

@@ -1207,7 +1207,7 @@ struct CodeBlock: Equatable, Codable, Sendable {
   var comment: Comment?
 
   /// The code block item that appears below the comment.
-  var item: CodeBlockItem
+  var item: CodeBlockItem?
 }
 
 /// A description of a Swift file.

+ 4 - 20
Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift

@@ -79,22 +79,6 @@ struct ClientCodeTranslator {
   init() {}
 
   func translate(
-    accessModifier: AccessModifier,
-    services: [ServiceDescriptor],
-    serializer: (String) -> String,
-    deserializer: (String) -> String
-  ) -> [CodeBlock] {
-    services.flatMap { service in
-      self.translate(
-        accessModifier: accessModifier,
-        service: service,
-        serializer: serializer,
-        deserializer: deserializer
-      )
-    }
-  }
-
-  private func translate(
     accessModifier: AccessModifier,
     service: ServiceDescriptor,
     serializer: (String) -> String,
@@ -114,7 +98,7 @@ struct ClientCodeTranslator {
     blocks.append(
       CodeBlock(
         comment: .preFormatted(service.documentation),
-        item: .declaration(.guarded(.grpc, .protocol(clientProtocol)))
+        item: .declaration(.protocol(clientProtocol))
       )
     )
 
@@ -126,7 +110,7 @@ struct ClientCodeTranslator {
       deserializer: deserializer
     )
     blocks.append(
-      CodeBlock(item: .declaration(.guarded(.grpc, .extension(extensionWithDefaults))))
+      CodeBlock(item: .declaration(.extension(extensionWithDefaults)))
     )
 
     let extensionWithExplodedAPI: ExtensionDescription = .explodedClientMethods(
@@ -135,7 +119,7 @@ struct ClientCodeTranslator {
       methods: service.methods
     )
     blocks.append(
-      CodeBlock(item: .declaration(.guarded(.grpc, .extension(extensionWithExplodedAPI))))
+      CodeBlock(item: .declaration(.extension(extensionWithExplodedAPI)))
     )
 
     let clientStruct: StructDescription = .client(
@@ -148,7 +132,7 @@ struct ClientCodeTranslator {
     blocks.append(
       CodeBlock(
         comment: .preFormatted(service.documentation),
-        item: .declaration(.guarded(.grpc, .struct(clientStruct)))
+        item: .declaration(.struct(clientStruct))
       )
     )
 

+ 38 - 22
Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift

@@ -28,34 +28,50 @@ struct IDLToStructuredSwiftTranslator: Translator {
     try self.validateInput(codeGenerationRequest)
     let accessModifier = AccessModifier(accessLevel)
 
+    var codeBlocks: [CodeBlock] = []
     let metadataTranslator = MetadataTranslator()
-    var codeBlocks = metadataTranslator.translate(
-      accessModifier: accessModifier,
-      services: codeGenerationRequest.services,
-      client: client,
-      server: server
-    )
+    let serverTranslator = ServerCodeTranslator()
+    let clientTranslator = ClientCodeTranslator()
 
-    if server {
-      let translator = ServerCodeTranslator()
-      let blocks = translator.translate(
-        accessModifier: accessModifier,
-        services: codeGenerationRequest.services,
-        serializer: codeGenerationRequest.lookupSerializer,
-        deserializer: codeGenerationRequest.lookupDeserializer
+    for service in codeGenerationRequest.services {
+      codeBlocks.append(
+        CodeBlock(comment: .mark("\(service.fullyQualifiedName)", sectionBreak: true))
       )
-      codeBlocks.append(contentsOf: blocks)
-    }
 
-    if client {
-      let translator = ClientCodeTranslator()
-      let blocks = translator.translate(
+      let metadata = metadataTranslator.translate(
         accessModifier: accessModifier,
-        services: codeGenerationRequest.services,
-        serializer: codeGenerationRequest.lookupSerializer,
-        deserializer: codeGenerationRequest.lookupDeserializer
+        service: service,
+        client: client,
+        server: server
       )
-      codeBlocks.append(contentsOf: blocks)
+      codeBlocks.append(contentsOf: metadata)
+
+      if server {
+        codeBlocks.append(
+          CodeBlock(comment: .mark("\(service.fullyQualifiedName) (server)", sectionBreak: false))
+        )
+
+        let blocks = serverTranslator.translate(
+          accessModifier: accessModifier,
+          service: service,
+          serializer: codeGenerationRequest.lookupSerializer,
+          deserializer: codeGenerationRequest.lookupDeserializer
+        )
+        codeBlocks.append(contentsOf: blocks)
+      }
+
+      if client {
+        codeBlocks.append(
+          CodeBlock(comment: .mark("\(service.fullyQualifiedName) (client)", sectionBreak: false))
+        )
+        let blocks = clientTranslator.translate(
+          accessModifier: accessModifier,
+          service: service,
+          serializer: codeGenerationRequest.lookupSerializer,
+          deserializer: codeGenerationRequest.lookupDeserializer
+        )
+        codeBlocks.append(contentsOf: blocks)
+      }
     }
 
     let fileDescription = FileDescription(

+ 0 - 16
Sources/GRPCCodeGen/Internal/Translator/MetadataTranslator.swift

@@ -18,22 +18,6 @@ struct MetadataTranslator {
   init() {}
 
   func translate(
-    accessModifier: AccessModifier,
-    services: [ServiceDescriptor],
-    client: Bool,
-    server: Bool
-  ) -> [CodeBlock] {
-    return services.flatMap { service in
-      self.translate(
-        accessModifier: accessModifier,
-        service: service,
-        client: client,
-        server: server
-      )
-    }
-  }
-
-  private func translate(
     accessModifier: AccessModifier,
     service: ServiceDescriptor,
     client: Bool,

+ 4 - 20
Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift

@@ -61,22 +61,6 @@ struct ServerCodeTranslator {
   init() {}
 
   func translate(
-    accessModifier: AccessModifier,
-    services: [ServiceDescriptor],
-    serializer: (String) -> String,
-    deserializer: (String) -> String
-  ) -> [CodeBlock] {
-    return services.flatMap { service in
-      self.translate(
-        accessModifier: accessModifier,
-        service: service,
-        serializer: serializer,
-        deserializer: deserializer
-      )
-    }
-  }
-
-  private func translate(
     accessModifier: AccessModifier,
     service: ServiceDescriptor,
     serializer: (String) -> String,
@@ -106,7 +90,7 @@ struct ServerCodeTranslator {
     blocks.append(
       CodeBlock(
         comment: .preFormatted(service.documentation),
-        item: .declaration(.guarded(.grpc, .protocol(streamingServiceProtocol)))
+        item: .declaration(.protocol(streamingServiceProtocol))
       )
     )
 
@@ -122,7 +106,7 @@ struct ServerCodeTranslator {
     blocks.append(
       CodeBlock(
         comment: .doc("Conformance to `GRPCCore.RegistrableRPCService`."),
-        item: .declaration(.guarded(.grpc, .extension(registerExtension)))
+        item: .declaration(.extension(registerExtension))
       )
     )
 
@@ -136,7 +120,7 @@ struct ServerCodeTranslator {
     blocks.append(
       CodeBlock(
         comment: .preFormatted(service.documentation),
-        item: .declaration(.guarded(.grpc, .protocol(serviceProtocol)))
+        item: .declaration(.protocol(serviceProtocol))
       )
     )
 
@@ -150,7 +134,7 @@ struct ServerCodeTranslator {
     blocks.append(
       CodeBlock(
         comment: .doc("Partial conformance to `\(streamingServiceProtocolName)`."),
-        item: .declaration(.guarded(.grpc, .extension(streamingServiceDefaultImplExtension)))
+        item: .declaration(.extension(streamingServiceDefaultImplExtension))
       )
     )
 

+ 0 - 16
Tests/GRPCCodeGenTests/Internal/StructuredSwift+MetadataTests.swift

@@ -21,18 +21,6 @@ import Testing
 extension StructuedSwiftTests {
   @Suite("Metadata")
   struct Metadata {
-    @Test("@available(...)")
-    func grpcAvailability() async throws {
-      let availability: AvailabilityDescription = .grpc
-      let structDecl = StructDescription(name: "Ignored")
-      let expected = """
-        @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
-        struct Ignored {}
-        """
-
-      #expect(render(.guarded(availability, .struct(structDecl))) == expected)
-    }
-
     @Test("typealias Input = <Name>", arguments: AccessModifier.allCases)
     func methodInputTypealias(access: AccessModifier) {
       let decl: TypealiasDescription = .methodInput(accessModifier: access, name: "Foo")
@@ -263,9 +251,7 @@ extension StructuedSwiftTests {
 
       if config.server {
         expected += """
-            @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
             \(access) typealias StreamingServiceProtocol = Foo_StreamingServiceProtocol
-            @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
             \(access) typealias ServiceProtocol = Foo_ServiceProtocol
           """
       }
@@ -276,9 +262,7 @@ extension StructuedSwiftTests {
         }
 
         expected += """
-            @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
             \(access) typealias ClientProtocol = Foo_ClientProtocol
-            @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
             \(access) typealias Client = Foo_Client
           """
       }

+ 1 - 5
Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift

@@ -40,7 +40,6 @@ struct ClientCodeTranslatorSnippetBasedTests {
 
     let expectedSwift = """
       /// Documentation for ServiceA
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       public protocol NamespaceA_ServiceA_ClientProtocol: Sendable {
           /// Documentation for MethodA
           func methodA<Result>(
@@ -51,7 +50,6 @@ struct ClientCodeTranslatorSnippetBasedTests {
               onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<NamespaceA_ServiceAResponse>) async throws -> Result
           ) async throws -> Result where Result: Sendable
       }
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       extension NamespaceA_ServiceA.ClientProtocol {
           public func methodA<Result>(
               request: GRPCCore.ClientRequest<NamespaceA_ServiceARequest>,
@@ -69,7 +67,6 @@ struct ClientCodeTranslatorSnippetBasedTests {
               )
           }
       }
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       extension NamespaceA_ServiceA.ClientProtocol {
           /// Documentation for MethodA
           public func methodA<Result>(
@@ -92,7 +89,6 @@ struct ClientCodeTranslatorSnippetBasedTests {
           }
       }
       /// Documentation for ServiceA
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       public struct NamespaceA_ServiceA_Client: NamespaceA_ServiceA.ClientProtocol {
           private let client: GRPCCore.GRPCClient
 
@@ -131,7 +127,7 @@ struct ClientCodeTranslatorSnippetBasedTests {
     service: ServiceDescriptor
   ) -> String {
     let translator = ClientCodeTranslator()
-    let codeBlocks = translator.translate(accessModifier: accessLevel, services: [service]) {
+    let codeBlocks = translator.translate(accessModifier: accessLevel, service: service) {
       "GRPCProtobuf.ProtobufSerializer<\($0)>()"
     } deserializer: {
       "GRPCProtobuf.ProtobufDeserializer<\($0)>()"

+ 4 - 7
Tests/GRPCCodeGenTests/Internal/Translator/IDLToStructuredSwiftTranslatorSnippetBasedTests.swift

@@ -212,14 +212,14 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase {
       @_spi(Secret) internal import Foo
       @_spi(Secret) internal import enum Foo.Bar
 
+      // MARK: - namespaceA.ServiceA
+
       public enum NamespaceA_ServiceA {
           public static let descriptor = GRPCCore.ServiceDescriptor.namespaceA_ServiceA
           public enum Method {
               public static let descriptors: [GRPCCore.MethodDescriptor] = []
           }
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias StreamingServiceProtocol = NamespaceA_ServiceA_StreamingServiceProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias ServiceProtocol = NamespaceA_ServiceA_ServiceProtocol
       }
 
@@ -230,23 +230,20 @@ final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase {
           )
       }
 
+      // MARK: namespaceA.ServiceA (server)
+
       /// Documentation for AService
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       public protocol NamespaceA_ServiceA_StreamingServiceProtocol: GRPCCore.RegistrableRPCService {}
 
       /// Conformance to `GRPCCore.RegistrableRPCService`.
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       extension NamespaceA_ServiceA.StreamingServiceProtocol {
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public func registerMethods(with router: inout GRPCCore.RPCRouter) {}
       }
 
       /// Documentation for AService
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       public protocol NamespaceA_ServiceA_ServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol {}
 
       /// Partial conformance to `NamespaceA_ServiceA_StreamingServiceProtocol`.
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       extension NamespaceA_ServiceA.ServiceProtocol {
       }
       """

+ 1 - 7
Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift

@@ -48,7 +48,6 @@ final class ServerCodeTranslatorSnippetBasedTests {
 
     let expectedSwift = """
       /// Documentation for ServiceA
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       public protocol NamespaceA_ServiceA_StreamingServiceProtocol: GRPCCore.RegistrableRPCService {
           /// Documentation for unaryMethod
           func unary(
@@ -57,9 +56,7 @@ final class ServerCodeTranslatorSnippetBasedTests {
           ) async throws -> GRPCCore.StreamingServerResponse<NamespaceA_ServiceAResponse>
       }
       /// Conformance to `GRPCCore.RegistrableRPCService`.
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       extension NamespaceA_ServiceA.StreamingServiceProtocol {
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public func registerMethods(with router: inout GRPCCore.RPCRouter) {
               router.registerHandler(
                   forMethod: NamespaceA_ServiceA.Method.Unary.descriptor,
@@ -75,7 +72,6 @@ final class ServerCodeTranslatorSnippetBasedTests {
           }
       }
       /// Documentation for ServiceA
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       public protocol NamespaceA_ServiceA_ServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol {
           /// Documentation for unaryMethod
           func unary(
@@ -84,7 +80,6 @@ final class ServerCodeTranslatorSnippetBasedTests {
           ) async throws -> GRPCCore.ServerResponse<NamespaceA_ServiceAResponse>
       }
       /// Partial conformance to `NamespaceA_ServiceA_StreamingServiceProtocol`.
-      @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
       extension NamespaceA_ServiceA.ServiceProtocol {
           public func unary(
               request: GRPCCore.StreamingServerRequest<NamespaceA_ServiceARequest>,
@@ -108,12 +103,11 @@ final class ServerCodeTranslatorSnippetBasedTests {
     service: ServiceDescriptor
   ) -> String {
     let translator = ServerCodeTranslator()
-    let codeBlocks = translator.translate(accessModifier: accessLevel, services: [service]) {
+    let codeBlocks = translator.translate(accessModifier: accessLevel, service: service) {
       "GRPCProtobuf.ProtobufSerializer<\($0)>()"
     } deserializer: {
       "GRPCProtobuf.ProtobufDeserializer<\($0)>()"
     }
-
     let renderer = TextBasedRenderer.default
     renderer.renderCodeBlocks(codeBlocks)
     return renderer.renderedContents()

+ 8 - 26
Tests/GRPCCodeGenTests/Internal/Translator/TypealiasTranslatorSnippetBasedTests.swift

@@ -57,13 +57,9 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase {
                   MethodA.descriptor
               ]
           }
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias StreamingServiceProtocol = NamespaceA_ServiceA_StreamingServiceProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias ServiceProtocol = NamespaceA_ServiceA_ServiceProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias ClientProtocol = NamespaceA_ServiceA_ClientProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias Client = NamespaceA_ServiceA_Client
       }
       extension GRPCCore.ServiceDescriptor {
@@ -101,13 +97,9 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase {
           public enum Method {
               public static let descriptors: [GRPCCore.MethodDescriptor] = []
           }
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias StreamingServiceProtocol = NamespaceA_ServiceA_StreamingServiceProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias ServiceProtocol = NamespaceA_ServiceA_ServiceProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias ClientProtocol = NamespaceA_ServiceA_ClientProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias Client = NamespaceA_ServiceA_Client
       }
       extension GRPCCore.ServiceDescriptor {
@@ -145,9 +137,7 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase {
           public enum Method {
               public static let descriptors: [GRPCCore.MethodDescriptor] = []
           }
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias StreamingServiceProtocol = NamespaceA_ServiceA_StreamingServiceProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias ServiceProtocol = NamespaceA_ServiceA_ServiceProtocol
       }
       extension GRPCCore.ServiceDescriptor {
@@ -185,9 +175,7 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase {
           public enum Method {
               public static let descriptors: [GRPCCore.MethodDescriptor] = []
           }
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias ClientProtocol = NamespaceA_ServiceA_ClientProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias Client = NamespaceA_ServiceA_Client
       }
       extension GRPCCore.ServiceDescriptor {
@@ -275,13 +263,9 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase {
                   MethodA.descriptor
               ]
           }
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias StreamingServiceProtocol = ServiceA_StreamingServiceProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias ServiceProtocol = ServiceA_ServiceProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias ClientProtocol = ServiceA_ClientProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           public typealias Client = ServiceA_Client
       }
       extension GRPCCore.ServiceDescriptor {
@@ -319,13 +303,9 @@ final class TypealiasTranslatorSnippetBasedTests: XCTestCase {
           package enum Method {
               package static let descriptors: [GRPCCore.MethodDescriptor] = []
           }
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           package typealias StreamingServiceProtocol = NamespaceA_ServiceA_StreamingServiceProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           package typealias ServiceProtocol = NamespaceA_ServiceA_ServiceProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           package typealias ClientProtocol = NamespaceA_ServiceA_ClientProtocol
-          @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
           package typealias Client = NamespaceA_ServiceA_Client
       }
       extension GRPCCore.ServiceDescriptor {
@@ -355,12 +335,14 @@ extension TypealiasTranslatorSnippetBasedTests {
     accessLevel: SourceGenerator.Config.AccessLevel
   ) throws {
     let translator = MetadataTranslator()
-    let codeBlocks = translator.translate(
-      accessModifier: AccessModifier(accessLevel),
-      services: request.services,
-      client: client,
-      server: server
-    )
+    let codeBlocks = request.services.flatMap { service in
+      translator.translate(
+        accessModifier: AccessModifier(accessLevel),
+        service: service,
+        client: client,
+        server: server
+      )
+    }
     let renderer = TextBasedRenderer.default
     renderer.renderCodeBlocks(codeBlocks)
     let contents = renderer.renderedContents()