Skip to content

Commit 9f56b78

Browse files
[CodeGenLib] Differentiate type names from identifying names (#1759)
Motivation: The names of the namespaces/service/methods used in the type names in the generated code can be different from the names identifying the namespaces/service/methods in the IDL. This is why we need to have different properties for them. Methods also have a third name - for the function signatures. Modifications: - Created the Name struct which contains the name in three formats - Added the name properties in the ServiceDescriptor and MethodDescriptor from CodeGenerationRequest - Modified the existing tests accordingly - Added new validation methods verifying the generated names - Added tests for the new checks Result: Users will be able to set an identifying name, a generated upper case name and a generated upper case name for the namespaces, services and methods which are used in the generated code. --------- Co-authored-by: George Barnett <[email protected]>
1 parent 378b6e8 commit 9f56b78

9 files changed

+895
-451
lines changed

Sources/GRPCCodeGen/CodeGenerationRequest.swift

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -216,17 +216,21 @@ public struct CodeGenerationRequest {
216216
}
217217

218218
/// Represents a service described in an IDL file.
219-
public struct ServiceDescriptor {
219+
public struct ServiceDescriptor: Hashable {
220220
/// Documentation from comments above the IDL service description.
221221
public var documentation: String
222222

223-
/// Service name.
224-
public var name: String
223+
/// The service name in different formats.
224+
///
225+
/// All properties of this object must be unique for each service from within a namespace.
226+
public var name: Name
225227

226-
/// The service namespace.
228+
/// The service namespace in different formats.
227229
///
228-
/// For `.proto` files it is the package name.
229-
public var namespace: String
230+
/// All different services from within the same namespace must have
231+
/// the same ``Name`` object as this property.
232+
/// For `.proto` files the base name of this object is the package name.
233+
public var namespace: Name
230234

231235
/// A description of each method of a service.
232236
///
@@ -235,8 +239,8 @@ public struct CodeGenerationRequest {
235239

236240
public init(
237241
documentation: String,
238-
name: String,
239-
namespace: String,
242+
name: Name,
243+
namespace: Name,
240244
methods: [MethodDescriptor]
241245
) {
242246
self.documentation = documentation
@@ -246,12 +250,15 @@ public struct CodeGenerationRequest {
246250
}
247251

248252
/// Represents a method described in an IDL file.
249-
public struct MethodDescriptor {
253+
public struct MethodDescriptor: Hashable {
250254
/// Documentation from comments above the IDL method description.
251255
public var documentation: String
252256

253-
/// Method name.
254-
public var name: String
257+
/// Method name in different formats.
258+
///
259+
/// All properties of this object must be unique for each method
260+
/// from within a service.
261+
public var name: Name
255262

256263
/// Identifies if the method is input streaming.
257264
public var isInputStreaming: Bool
@@ -267,7 +274,7 @@ public struct CodeGenerationRequest {
267274

268275
public init(
269276
documentation: String,
270-
name: String,
277+
name: Name,
271278
isInputStreaming: Bool,
272279
isOutputStreaming: Bool,
273280
inputType: String,
@@ -282,4 +289,32 @@ public struct CodeGenerationRequest {
282289
}
283290
}
284291
}
292+
293+
/// Represents the name associated with a namespace, service or a method, in three different formats.
294+
public struct Name: Hashable {
295+
/// The base name is the name used for the namespace/service/method in the IDL file, so it should follow
296+
/// the specific casing of the IDL.
297+
///
298+
/// The base name is also used in the descriptors that identify a specific method or service :
299+
/// `<service_namespace_baseName>.<service_baseName>.<method_baseName>`.
300+
public var base: String
301+
302+
/// The `generatedUpperCase` name is used in the generated code. It is expected
303+
/// to be the UpperCamelCase version of the base name
304+
///
305+
/// For example, if `base` is "fooBar", then `generatedUpperCase` is "FooBar".
306+
public var generatedUpperCase: String
307+
308+
/// The `generatedLowerCase` name is used in the generated code. It is expected
309+
/// to be the lowerCamelCase version of the base name
310+
///
311+
/// For example, if `base` is "FooBar", then `generatedLowerCase` is "fooBar".
312+
public var generatedLowerCase: String
313+
314+
public init(base: String, generatedUpperCase: String, generatedLowerCase: String) {
315+
self.base = base
316+
self.generatedUpperCase = generatedUpperCase
317+
self.generatedLowerCase = generatedLowerCase
318+
}
319+
}
285320
}

Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,23 @@
2222
/// a representation for the following generated code:
2323
///
2424
/// ```swift
25-
/// public protocol foo_BarClientProtocol: Sendable {
25+
/// public protocol Foo_BarClientProtocol: Sendable {
2626
/// func baz<R: Sendable>(
2727
/// request: ClientRequest.Single<foo.Bar.Methods.baz.Input>,
2828
/// serializer: some MessageSerializer<foo.Bar.Methods.baz.Input>,
2929
/// deserializer: some MessageDeserializer<foo.Bar.Methods.baz.Output>,
30-
/// _ body: @Sendable @escaping (ClientResponse.Single<foo.Bar.Methods.baz.Output>) async throws -> R
31-
/// ) async throws -> ServerResponse.Stream<foo.Bar.Methods.bazOutput>
30+
/// _ body: @Sendable @escaping (ClientResponse.Single<foo.Bar.Methods.Baz.Output>) async throws -> R
31+
/// ) async throws -> ServerResponse.Stream<foo.Bar.Methods.Baz.Output>
3232
/// }
33-
/// extension foo.Bar.ClientProtocol {
33+
/// extension Foo.Bar.ClientProtocol {
3434
/// public func get<R: Sendable>(
35-
/// request: ClientRequest.Single<foo.Bar.Methods.baz.Input>,
36-
/// _ body: @Sendable @escaping (ClientResponse.Single<foo.Bar.Methods.baz.Output>) async throws -> R
35+
/// request: ClientRequest.Single<Foo.Bar.Methods.Baz.Input>,
36+
/// _ body: @Sendable @escaping (ClientResponse.Single<Foo.Bar.Methods.Baz.Output>) async throws -> R
3737
/// ) async rethrows -> R {
3838
/// try await self.baz(
3939
/// request: request,
40-
/// serializer: ProtobufSerializer<foo.Bar.Methods.baz.Input>(),
41-
/// deserializer: ProtobufDeserializer<foo.Bar.Methods.baz.Output>(),
40+
/// serializer: ProtobufSerializer<Foo.Bar.Methods.Baz.Input>(),
41+
/// deserializer: ProtobufDeserializer<Foo.Bar.Methods.Baz.Output>(),
4242
/// body
4343
/// )
4444
/// }
@@ -55,7 +55,7 @@
5555
/// ) async rethrows -> R {
5656
/// try await self.client.clientStreaming(
5757
/// request: request,
58-
/// descriptor: namespaceA.ServiceA.Methods.methodA.descriptor,
58+
/// descriptor: NamespaceA.ServiceA.Methods.MethodA.descriptor,
5959
/// serializer: serializer,
6060
/// deserializer: deserializer,
6161
/// handler: body
@@ -115,7 +115,7 @@ extension ClientCodeTranslator {
115115
let clientProtocol = Declaration.protocol(
116116
ProtocolDescription(
117117
accessModifier: self.accessModifier,
118-
name: "\(service.namespacedPrefix)ClientProtocol",
118+
name: "\(service.namespacedGeneratedName)ClientProtocol",
119119
conformances: ["Sendable"],
120120
members: methods
121121
)
@@ -138,7 +138,7 @@ extension ClientCodeTranslator {
138138
}
139139
let clientProtocolExtension = Declaration.extension(
140140
ExtensionDescription(
141-
onType: "\(service.namespacedTypealiasPrefix).ClientProtocol",
141+
onType: "\(service.namespacedTypealiasGeneratedName).ClientProtocol",
142142
declarations: methods
143143
)
144144
)
@@ -161,7 +161,7 @@ extension ClientCodeTranslator {
161161
let functionSignature = FunctionSignatureDescription(
162162
accessModifier: accessModifier,
163163
kind: .function(
164-
name: method.name,
164+
name: method.name.generatedLowerCase,
165165
isStatic: false
166166
),
167167
generics: [.member("R")],
@@ -190,7 +190,10 @@ extension ClientCodeTranslator {
190190
) -> [CodeBlock] {
191191
let functionCall = Expression.functionCall(
192192
calledExpression: .memberAccess(
193-
MemberAccessDescription(left: .identifierPattern("self"), right: method.name)
193+
MemberAccessDescription(
194+
left: .identifierPattern("self"),
195+
right: method.name.generatedLowerCase
196+
)
194197
),
195198
arguments: [
196199
FunctionArgumentDescription(label: "request", expression: .identifierPattern("request")),
@@ -329,8 +332,8 @@ extension ClientCodeTranslator {
329332
return .struct(
330333
StructDescription(
331334
accessModifier: self.accessModifier,
332-
name: "\(service.namespacedPrefix)Client",
333-
conformances: ["\(service.namespacedTypealiasPrefix).ClientProtocol"],
335+
name: "\(service.namespacedGeneratedName)Client",
336+
conformances: ["\(service.namespacedTypealiasGeneratedName).ClientProtocol"],
334337
members: [clientProperty, initializer] + methods
335338
)
336339
)
@@ -393,7 +396,7 @@ extension ClientCodeTranslator {
393396
.init(
394397
label: "descriptor",
395398
expression: .identifierPattern(
396-
"\(service.namespacedTypealiasPrefix).Methods.\(method.name).descriptor"
399+
"\(service.namespacedTypealiasGeneratedName).Methods.\(method.name.generatedUpperCase).descriptor"
397400
)
398401
),
399402
.init(label: "serializer", expression: .identifierPattern("serializer")),
@@ -409,7 +412,7 @@ extension ClientCodeTranslator {
409412
return .function(
410413
accessModifier: self.accessModifier,
411414
kind: .function(
412-
name: "\(method.name)",
415+
name: "\(method.name.generatedLowerCase)",
413416
isStatic: false
414417
),
415418
generics: [.member("R")],
@@ -432,7 +435,8 @@ extension ClientCodeTranslator {
432435
service: CodeGenerationRequest.ServiceDescriptor,
433436
type: InputOutputType
434437
) -> String {
435-
var components: String = "\(service.namespacedTypealiasPrefix).Methods.\(method.name)"
438+
var components: String =
439+
"\(service.namespacedTypealiasGeneratedName).Methods.\(method.name.generatedUpperCase)"
436440

437441
switch type {
438442
case .input:

0 commit comments

Comments
 (0)