Skip to content

Commit bba613b

Browse files
[CodeGenLib] SourceGenerator public API
Motivation: The SourceGenerator is responsible for transforming the CodeGenerationRequest input into a SourceFile object. Modifications: - created the public SourceGenerator struct that contains a Configuration struct (visibility level + indentation) and the `generate()` function. - the `generate()` function translates the input object into a StructuredSwiftRepresentation oject, then renders the latter into a SourceFile object. - modified tests to include Visibility. Result: The user can now generate a SourceFile that contains generated code, using a CodeGenerationRequest object and the SourceGenerator API.
1 parent b8ccbf3 commit bba613b

14 files changed

+550
-288
lines changed

Sources/GRPCCodeGen/Internal/Renderer/TextBasedRenderer.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,18 @@ final class StringCodeWriter {
4040
/// The current nesting level.
4141
private var level: Int
4242

43+
/// The indentation for each level as the number of spaces.
44+
internal let indentation: Int
45+
4346
/// Whether the next call to `writeLine` will continue writing to the last
4447
/// stored line. Otherwise a new line is appended.
4548
private var nextWriteAppendsToLastLine: Bool = false
4649

4750
/// Creates a new empty writer.
48-
init() {
51+
init(indentation: Int) {
4952
self.level = 0
5053
self.lines = []
54+
self.indentation = indentation
5155
}
5256

5357
/// Concatenates the stored lines of code into a single string.
@@ -67,7 +71,7 @@ final class StringCodeWriter {
6771
let existingLine = lines.removeLast()
6872
newLine = existingLine + line
6973
} else {
70-
let indentation = Array(repeating: " ", count: 4 * level).joined()
74+
let indentation = Array(repeating: " ", count: self.indentation * level).joined()
7175
newLine = indentation + line
7276
}
7377
lines.append(newLine)
@@ -119,7 +123,11 @@ struct TextBasedRenderer: RendererProtocol {
119123
private let writer: StringCodeWriter
120124

121125
/// Creates a new empty renderer.
122-
static var `default`: TextBasedRenderer { .init(writer: StringCodeWriter()) }
126+
static var `default`: TextBasedRenderer { .init(indentation: 4) }
127+
128+
init(indentation: Int) {
129+
self.writer = StringCodeWriter(indentation: indentation)
130+
}
123131

124132
// MARK: - Internals
125133

Sources/GRPCCodeGen/Internal/StructuredSwiftRepresentation.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ struct WhereClause: Equatable, Codable {
344344
struct ExtensionDescription: Equatable, Codable {
345345

346346
/// An access modifier.
347-
var accessModifier: AccessModifier?
347+
var accessModifier: AccessModifier? = nil
348348

349349
/// The name of the extended type.
350350
///
@@ -694,6 +694,7 @@ struct ClosureSignatureDescription: Equatable, Codable {
694694
/// The ``@escaping`` attribute.
695695
var escaping: Bool = false
696696
}
697+
697698
/// A description of the associated value of an enum case.
698699
///
699700
/// For example, in `case foo(bar: String)`, the associated value
@@ -1385,7 +1386,7 @@ extension Declaration {
13851386
/// extended type.
13861387
/// - Returns: An extension declaration.
13871388
static func `extension`(
1388-
accessModifier: AccessModifier?,
1389+
accessModifier: AccessModifier? = nil,
13891390
onType: String,
13901391
conformances: [String] = [],
13911392
whereClause: WhereClause? = nil,

Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@
4242
/// body
4343
/// )
4444
/// }
45-
/// struct foo_BarClient: foo.Bar.ClientProtocol {
46-
/// let client: GRPCCore.GRPCClient
47-
/// init(client: GRPCCore.GRPCClient) {
45+
/// public struct foo_BarClient: foo.Bar.ClientProtocol {
46+
/// private let client: GRPCCore.GRPCClient
47+
/// public init(client: GRPCCore.GRPCClient) {
4848
/// self.client = client
4949
/// }
50-
/// func methodA<R: Sendable>(
50+
/// public func methodA<R: Sendable>(
5151
/// request: ClientRequest.Stream<namespaceA.ServiceA.Methods.methodA.Input>,
5252
/// serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
5353
/// deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
@@ -64,6 +64,12 @@
6464
/// }
6565
///```
6666
struct ClientCodeTranslator: SpecializedTranslator {
67+
var accessLevel: SourceGenerator.Configuration.AccessLevel
68+
69+
init(accessLevel: SourceGenerator.Configuration.AccessLevel) {
70+
self.accessLevel = accessLevel
71+
}
72+
6773
func translate(from codeGenerationRequest: CodeGenerationRequest) throws -> [CodeBlock] {
6874
var codeBlocks = [CodeBlock]()
6975

@@ -108,6 +114,7 @@ extension ClientCodeTranslator {
108114

109115
let clientProtocol = Declaration.protocol(
110116
ProtocolDescription(
117+
accessModifier: self.accessModifier,
111118
name: "\(service.namespacedPrefix)ClientProtocol",
112119
conformances: ["Sendable"],
113120
members: methods
@@ -125,7 +132,8 @@ extension ClientCodeTranslator {
125132
for: $0,
126133
in: service,
127134
from: codeGenerationRequest,
128-
generateSerializerDeserializer: true
135+
generateSerializerDeserializer: true,
136+
accessModifier: self.accessModifier
129137
)
130138
}
131139
let clientProtocolExtension = Declaration.extension(
@@ -141,7 +149,8 @@ extension ClientCodeTranslator {
141149
for method: CodeGenerationRequest.ServiceDescriptor.MethodDescriptor,
142150
in service: CodeGenerationRequest.ServiceDescriptor,
143151
from codeGenerationRequest: CodeGenerationRequest,
144-
generateSerializerDeserializer: Bool
152+
generateSerializerDeserializer: Bool,
153+
accessModifier: AccessModifier? = nil
145154
) -> Declaration {
146155
let methodParameters = self.makeParameters(
147156
for: method,
@@ -150,6 +159,7 @@ extension ClientCodeTranslator {
150159
generateSerializerDeserializer: generateSerializerDeserializer
151160
)
152161
let functionSignature = FunctionSignatureDescription(
162+
accessModifier: accessModifier,
153163
kind: .function(
154164
name: method.name,
155165
isStatic: false
@@ -303,6 +313,7 @@ extension ClientCodeTranslator {
303313
in codeGenerationRequest: CodeGenerationRequest
304314
) -> Declaration {
305315
let clientProperty = Declaration.variable(
316+
accessModifier: .private,
306317
kind: .let,
307318
left: "client",
308319
type: .member(["GRPCCore", "GRPCClient"])
@@ -317,6 +328,7 @@ extension ClientCodeTranslator {
317328

318329
return .struct(
319330
StructDescription(
331+
accessModifier: self.accessModifier,
320332
name: "\(service.namespacedPrefix)Client",
321333
conformances: ["\(service.namespacedTypealiasPrefix).ClientProtocol"],
322334
members: [clientProperty, initializer] + methods
@@ -333,6 +345,7 @@ extension ClientCodeTranslator {
333345
)
334346
return .function(
335347
signature: .init(
348+
accessModifier: self.accessModifier,
336349
kind: .initializer,
337350
parameters: [.init(label: "client", type: .member(["GRPCCore", "GRPCClient"]))]
338351
),
@@ -394,6 +407,7 @@ extension ClientCodeTranslator {
394407
)
395408

396409
return .function(
410+
accessModifier: self.accessModifier,
397411
kind: .function(
398412
name: "\(method.name)",
399413
isStatic: false

Sources/GRPCCodeGen/Internal/Translator/IDLToStructuredSwiftTranslator.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,23 @@
1414
* limitations under the License.
1515
*/
1616

17+
/// Creates a representation for the server and client code, as well as for the enums containing useful type aliases and properties.
18+
/// The representation is generated based on the ``CodeGenerationRequest`` object and user specifications,
19+
/// using types from ``StructuredSwiftRepresentation``.
1720
struct IDLToStructuredSwiftTranslator: Translator {
1821
func translate(
1922
codeGenerationRequest: CodeGenerationRequest,
23+
accessLevel: SourceGenerator.Configuration.AccessLevel,
2024
client: Bool,
2125
server: Bool
2226
) throws -> StructuredSwiftRepresentation {
2327
try self.validateInput(codeGenerationRequest)
24-
let typealiasTranslator = TypealiasTranslator(client: client, server: server)
28+
let typealiasTranslator = TypealiasTranslator(
29+
client: client,
30+
server: server,
31+
accessLevel: accessLevel
32+
)
33+
2534
let topComment = Comment.doc(codeGenerationRequest.leadingTrivia)
2635
let imports = try codeGenerationRequest.dependencies.reduce(
2736
into: [ImportDescription(moduleName: "GRPCCore")]
@@ -35,14 +44,14 @@ struct IDLToStructuredSwiftTranslator: Translator {
3544
)
3645

3746
if server {
38-
let serverCodeTranslator = ServerCodeTranslator()
47+
let serverCodeTranslator = ServerCodeTranslator(accessLevel: accessLevel)
3948
codeBlocks.append(
4049
contentsOf: try serverCodeTranslator.translate(from: codeGenerationRequest)
4150
)
4251
}
4352

4453
if client {
45-
let clientCodeTranslator = ClientCodeTranslator()
54+
let clientCodeTranslator = ClientCodeTranslator(accessLevel: accessLevel)
4655
codeBlocks.append(
4756
contentsOf: try clientCodeTranslator.translate(from: codeGenerationRequest)
4857
)

Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@
5454
/// }
5555
///```
5656
struct ServerCodeTranslator: SpecializedTranslator {
57+
var accessLevel: SourceGenerator.Configuration.AccessLevel
58+
59+
init(accessLevel: SourceGenerator.Configuration.AccessLevel) {
60+
self.accessLevel = accessLevel
61+
}
62+
5763
func translate(from codeGenerationRequest: CodeGenerationRequest) throws -> [CodeBlock] {
5864
var codeBlocks = [CodeBlock]()
5965
for service in codeGenerationRequest.services {
@@ -112,6 +118,7 @@ extension ServerCodeTranslator {
112118

113119
let streamingProtocol = Declaration.protocol(
114120
.init(
121+
accessModifier: self.accessModifier,
115122
name: self.protocolName(service: service, streaming: true),
116123
conformances: ["GRPCCore.RegistrableRPCService"],
117124
members: methods
@@ -123,9 +130,11 @@ extension ServerCodeTranslator {
123130

124131
private func makeStreamingMethodSignature(
125132
for method: CodeGenerationRequest.ServiceDescriptor.MethodDescriptor,
126-
in service: CodeGenerationRequest.ServiceDescriptor
133+
in service: CodeGenerationRequest.ServiceDescriptor,
134+
accessModifier: AccessModifier? = nil
127135
) -> FunctionSignatureDescription {
128136
return FunctionSignatureDescription(
137+
accessModifier: accessModifier,
129138
kind: .function(name: method.name),
130139
parameters: [
131140
.init(
@@ -157,7 +166,6 @@ extension ServerCodeTranslator {
157166
let streamingProtocol = self.protocolNameTypealias(service: service, streaming: true)
158167
let registerRPCMethod = self.makeRegisterRPCsMethod(for: service, in: codeGenerationRequest)
159168
return .extension(
160-
accessModifier: .public,
161169
onType: streamingProtocol,
162170
declarations: [registerRPCMethod]
163171
)
@@ -168,7 +176,8 @@ extension ServerCodeTranslator {
168176
in codeGenerationRequest: CodeGenerationRequest
169177
) -> Declaration {
170178
let registerRPCsSignature = FunctionSignatureDescription(
171-
kind: .function(name: "registerRPCs"),
179+
accessModifier: self.accessModifier,
180+
kind: .function(name: "registerMethods"),
172181
parameters: [
173182
.init(
174183
label: "with",
@@ -280,14 +289,20 @@ extension ServerCodeTranslator {
280289
return .commentable(
281290
.doc(service.documentation),
282291
.protocol(
283-
ProtocolDescription(name: protocolName, conformances: [streamingProtocol], members: methods)
292+
ProtocolDescription(
293+
accessModifier: self.accessModifier,
294+
name: protocolName,
295+
conformances: [streamingProtocol],
296+
members: methods
297+
)
284298
)
285299
)
286300
}
287301

288302
private func makeServiceProtocolMethod(
289303
for method: CodeGenerationRequest.ServiceDescriptor.MethodDescriptor,
290-
in service: CodeGenerationRequest.ServiceDescriptor
304+
in service: CodeGenerationRequest.ServiceDescriptor,
305+
accessModifier: AccessModifier? = nil
291306
) -> Declaration {
292307
let inputStreaming = method.isInputStreaming ? "Stream" : "Single"
293308
let outputStreaming = method.isOutputStreaming ? "Stream" : "Single"
@@ -304,6 +319,7 @@ extension ServerCodeTranslator {
304319
)
305320

306321
let functionSignature = FunctionSignatureDescription(
322+
accessModifier: accessModifier,
307323
kind: .function(name: method.name),
308324
parameters: [
309325
.init(
@@ -338,7 +354,10 @@ extension ServerCodeTranslator {
338354
}
339355

340356
let protocolName = self.protocolNameTypealias(service: service, streaming: false)
341-
return .extension(accessModifier: .public, onType: protocolName, declarations: methods)
357+
return .extension(
358+
onType: protocolName,
359+
declarations: methods
360+
)
342361
}
343362

344363
private func makeServiceProtocolExtensionMethod(
@@ -354,7 +373,11 @@ extension ServerCodeTranslator {
354373
let returnStatement = CodeBlock(item: .expression(self.makeReturnStatement(for: method)))
355374

356375
return .function(
357-
signature: self.makeStreamingMethodSignature(for: method, in: service),
376+
signature: self.makeStreamingMethodSignature(
377+
for: method,
378+
in: service,
379+
accessModifier: self.accessModifier
380+
),
358381
body: [response, returnStatement]
359382
)
360383
}

Sources/GRPCCodeGen/Internal/Translator/SpecializedTranslator.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
/// Represents one responsibility of the ``Translator``: either the type aliases translation,
1818
/// the server code translation or the client code translation.
1919
protocol SpecializedTranslator {
20+
21+
/// The ``SourceGenerator.Configuration.AccessLevel`` object used to represent the visibility level used in the generated code.
22+
var accessLevel: SourceGenerator.Configuration.AccessLevel { get }
23+
2024
/// Generates an array of ``CodeBlock`` elements that will be part of the ``StructuredSwiftRepresentation`` object
2125
/// created by the ``Translator``.
2226
///
@@ -27,3 +31,19 @@ protocol SpecializedTranslator {
2731
/// - SeeAlso: ``CodeGenerationRequest``, ``Translator``, ``CodeBlock``.
2832
func translate(from codeGenerationRequest: CodeGenerationRequest) throws -> [CodeBlock]
2933
}
34+
35+
extension SpecializedTranslator {
36+
/// The access modifier that corresponds with the access level from ``SourceGenerator.Configuration``.
37+
internal var accessModifier: AccessModifier {
38+
get {
39+
switch accessLevel.level {
40+
case .internal:
41+
return AccessModifier.internal
42+
case .package:
43+
return AccessModifier.package
44+
case .public:
45+
return AccessModifier.public
46+
}
47+
}
48+
}
49+
}

Sources/GRPCCodeGen/Internal/Translator/Translator.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ protocol Translator {
2121
/// Translates the provided ``CodeGenerationRequest`` object, into Swift code representation.
2222
/// - Parameters:
2323
/// - codeGenerationRequest: The IDL described RPCs representation.
24+
/// - accessLevel: The access level that will restrict the protocols, extensions and methods in the generated code.
2425
/// - client: Whether or not client code should be generated from the IDL described RPCs representation.
2526
/// - server: Whether or not server code should be generated from the IDL described RPCs representation.
2627
/// - Returns: A structured Swift representation of the generated code.
2728
/// - Throws: An error if there are issues translating the codeGenerationRequest.
2829
func translate(
2930
codeGenerationRequest: CodeGenerationRequest,
31+
accessLevel: SourceGenerator.Configuration.AccessLevel,
3032
client: Bool,
3133
server: Bool
3234
) throws -> StructuredSwiftRepresentation

0 commit comments

Comments
 (0)