Skip to content

Commit 658814e

Browse files
authored
Fix casing of generated services and methods (#8)
Motivation: Given a method name, say `ImportCSV`, from a `.proto` file, the generated method name in upper and lower camel case is `ImportCsv` and `importCsv` respectively. The generated method name (which is already expected to be in upper camel case) in upper and lower camel case should be `ImportCSV` and `importCSV` respectively. Modifications: - Replace the method used for generating service and method names in lower camel case with a newly implemented method. - Do not convert the base names of services and methods to upper camel case as they are expected to already be in upper camel case. Result: The casing of service and method names will be preserved when generating stubs.
1 parent 0e95676 commit 658814e

File tree

3 files changed

+95
-5
lines changed

3 files changed

+95
-5
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2024, gRPC Authors All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package enum CamelCaser {
18+
/// Converts a string from upper camel case to lower camel case.
19+
package static func toLowerCamelCase(_ input: String) -> String {
20+
guard let indexOfFirstLowercase = input.firstIndex(where: { $0.isLowercase }) else {
21+
return input.lowercased()
22+
}
23+
24+
if indexOfFirstLowercase == input.startIndex {
25+
// `input` already begins with a lower case letter. As in: "importCSV".
26+
return input
27+
} else if indexOfFirstLowercase == input.index(after: input.startIndex) {
28+
// The second character in `input` is lower case. As in: "ImportCSV".
29+
// returns "importCSV"
30+
return input[input.startIndex].lowercased() + input[indexOfFirstLowercase...]
31+
} else {
32+
// The first lower case character is further within `input`. Tentatively, `input` begins
33+
// with one or more abbreviations. Therefore, the last encountered upper case character
34+
// could be the beginning of the next word. As in: "FOOBARImportCSV".
35+
36+
let leadingAbbreviation = input[..<input.index(before: indexOfFirstLowercase)]
37+
let followingWords = input[input.index(before: indexOfFirstLowercase)...]
38+
39+
// returns "foobarImportCSV"
40+
return leadingAbbreviation.lowercased() + followingWords
41+
}
42+
}
43+
}

Sources/GRPCProtobufCodeGen/ProtobufCodeGenParser.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616

1717
internal import Foundation
18-
internal import SwiftProtobuf
1918
internal import SwiftProtobufPluginLibrary
2019

2120
internal import struct GRPCCodeGen.CodeGenerationRequest
@@ -125,8 +124,9 @@ extension CodeGenerationRequest.ServiceDescriptor {
125124
}
126125
let name = CodeGenerationRequest.Name(
127126
base: descriptor.name,
128-
generatedUpperCase: NamingUtils.toUpperCamelCase(descriptor.name),
129-
generatedLowerCase: NamingUtils.toLowerCamelCase(descriptor.name)
127+
// The service name from the '.proto' file is expected to be in upper camel case
128+
generatedUpperCase: descriptor.name,
129+
generatedLowerCase: CamelCaser.toLowerCamelCase(descriptor.name)
130130
)
131131

132132
// Packages that are based on the path of the '.proto' file usually
@@ -145,8 +145,9 @@ extension CodeGenerationRequest.ServiceDescriptor.MethodDescriptor {
145145
fileprivate init(descriptor: MethodDescriptor, protobufNamer: SwiftProtobufNamer) {
146146
let name = CodeGenerationRequest.Name(
147147
base: descriptor.name,
148-
generatedUpperCase: NamingUtils.toUpperCamelCase(descriptor.name),
149-
generatedLowerCase: NamingUtils.toLowerCamelCase(descriptor.name)
148+
// The method name from the '.proto' file is expected to be in upper camel case
149+
generatedUpperCase: descriptor.name,
150+
generatedLowerCase: CamelCaser.toLowerCamelCase(descriptor.name)
150151
)
151152
let documentation = descriptor.protoSourceComments()
152153
self.init(
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2024, gRPC Authors All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import GRPCProtobufCodeGen
18+
import Testing
19+
20+
@Suite("CamelCaser")
21+
struct CamelCaserTests {
22+
@Test(
23+
"Convert to lower camel case",
24+
arguments: [
25+
("ImportCsv", "importCsv"),
26+
("ImportCSV", "importCSV"),
27+
("CSVImport", "csvImport"),
28+
("importCSV", "importCSV"),
29+
("FOOBARImport", "foobarImport"),
30+
("FOO_BARImport", "foo_barImport"),
31+
("My_CSVImport", "my_CSVImport"),
32+
("_CSVImport", "_csvImport"),
33+
("V2Request", "v2Request"),
34+
("V2_Request", "v2_Request"),
35+
("CSV", "csv"),
36+
("I", "i"),
37+
("i", "i"),
38+
("I_", "i_"),
39+
("_", "_"),
40+
("", ""),
41+
]
42+
)
43+
func toLowerCamelCase(_ input: String, expectedOutput: String) async throws {
44+
#expect(CamelCaser.toLowerCamelCase(input) == expectedOutput)
45+
}
46+
}

0 commit comments

Comments
 (0)