Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Sources/GRPCCodeGen/CodeGenerationRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public struct CodeGenerationRequest {
public var fileName: String

/// Any comments at the top of the file such as documentation and copyright headers.
/// They will be placed at the top of the generated file.
/// They will be placed at the top of the generated file. They are already formatted,
/// meaning they contain "///" and new lines.
public var leadingTrivia: String

/// The Swift imports that the generated file depends on. The gRPC specific imports aren't required
Expand Down Expand Up @@ -218,6 +219,7 @@ public struct CodeGenerationRequest {
/// Represents a service described in an IDL file.
public struct ServiceDescriptor: Hashable {
/// Documentation from comments above the IDL service description.
/// It is already formatted, meaning it contains "///" and new lines.
public var documentation: String

/// The service name in different formats.
Expand Down Expand Up @@ -252,6 +254,7 @@ public struct CodeGenerationRequest {
/// Represents a method described in an IDL file.
public struct MethodDescriptor: Hashable {
/// Documentation from comments above the IDL method description.
/// It is already formatted, meaning it contains "///" and new lines.
public var documentation: String

/// Method name in different formats.
Expand Down
15 changes: 11 additions & 4 deletions Sources/GRPCCodeGen/Internal/Renderer/TextBasedRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,19 @@ struct TextBasedRenderer: RendererProtocol {
case .mark(let string, sectionBreak: false):
prefix = "// MARK:"
commentString = string
case .preFormatted(let string):
prefix = ""
commentString = string
}
let lines = commentString.transformingLines { line in
if line.isEmpty { return prefix }
return "\(prefix) \(line)"
if prefix.isEmpty {
writer.writeLine(commentString)
} else {
let lines = commentString.transformingLines { line in
if line.isEmpty { return prefix }
return "\(prefix) \(line)"
}
lines.forEach(writer.writeLine)
}
lines.forEach(writer.writeLine)
}

/// Renders the specified import statements.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@ enum Comment: Equatable, Codable {
/// For example: `// MARK: - Public methods`, with the optional
/// section break (`-`).
case mark(String, sectionBreak: Bool)

/// A comment that is already formatted,
/// meaning that it already has the `///` and
/// can contain multiple lines
///
/// For example both the string and the comment
/// can look like `/// Important type`.
case preFormatted(String)
}

/// A description of a literal.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct ClientCodeTranslator: SpecializedTranslator {
codeBlocks.append(
.declaration(
.commentable(
.doc(service.documentation),
.preFormatted(service.documentation),
self.makeClientProtocol(for: service, in: codeGenerationRequest)
)
)
Expand All @@ -88,7 +88,7 @@ struct ClientCodeTranslator: SpecializedTranslator {
codeBlocks.append(
.declaration(
.commentable(
.doc(service.documentation),
.preFormatted(service.documentation),
self.makeClientStruct(for: service, in: codeGenerationRequest)
)
)
Expand Down Expand Up @@ -179,7 +179,10 @@ extension ClientCodeTranslator {
)
return .function(signature: functionSignature, body: body)
} else {
return .commentable(.doc(method.documentation), .function(signature: functionSignature))
return .commentable(
.preFormatted(method.documentation),
.function(signature: functionSignature)
)
}
}

Expand Down Expand Up @@ -324,7 +327,7 @@ extension ClientCodeTranslator {
let initializer = self.makeClientVariable()
let methods = service.methods.map {
Declaration.commentable(
.doc($0.documentation),
.preFormatted($0.documentation),
self.makeClientMethod(for: $0, in: service, from: codeGenerationRequest)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct IDLToStructuredSwiftTranslator: Translator {
accessLevel: accessLevel
)

let topComment = Comment.doc(codeGenerationRequest.leadingTrivia)
let topComment = Comment.preFormatted(codeGenerationRequest.leadingTrivia)
let imports = try codeGenerationRequest.dependencies.reduce(
into: [ImportDescription(moduleName: "GRPCCore")]
) { partialResult, newDependency in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ extension ServerCodeTranslator {
) -> Declaration {
let methods = service.methods.compactMap {
Declaration.commentable(
.doc($0.documentation),
.preFormatted($0.documentation),
.function(
FunctionDescription(
signature: self.makeStreamingMethodSignature(for: $0, in: service)
Expand All @@ -125,7 +125,7 @@ extension ServerCodeTranslator {
)
)

return .commentable(.doc(service.documentation), streamingProtocol)
return .commentable(.preFormatted(service.documentation), streamingProtocol)
}

private func makeStreamingMethodSignature(
Expand Down Expand Up @@ -290,7 +290,7 @@ extension ServerCodeTranslator {
let streamingProtocol = self.protocolNameTypealias(service: service, streaming: true)

return .commentable(
.doc(service.documentation),
.preFormatted(service.documentation),
.protocol(
ProtocolDescription(
accessModifier: self.accessModifier,
Expand Down Expand Up @@ -344,7 +344,7 @@ extension ServerCodeTranslator {
)

return .commentable(
.doc(method.documentation),
.preFormatted(method.documentation),
.function(FunctionDescription(signature: functionSignature))
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {

func testClientCodeTranslatorUnaryMethod() throws {
let method = MethodDescriptor(
documentation: "Documentation for MethodA",
documentation: "/// Documentation for MethodA",
name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
isInputStreaming: false,
isOutputStreaming: false,
inputType: "NamespaceA_ServiceARequest",
outputType: "NamespaceA_ServiceAResponse"
)
let service = ServiceDescriptor(
documentation: "Documentation for ServiceA",
documentation: "/// Documentation for ServiceA",
name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
namespace: Name(base: "namespaceA", generatedUpperCase: "NamespaceA", generatedLowerCase: ""),
methods: [method]
Expand Down Expand Up @@ -98,15 +98,15 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {

func testClientCodeTranslatorClientStreamingMethod() throws {
let method = MethodDescriptor(
documentation: "Documentation for MethodA",
documentation: "/// Documentation for MethodA",
name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
isInputStreaming: true,
isOutputStreaming: false,
inputType: "NamespaceA_ServiceARequest",
outputType: "NamespaceA_ServiceAResponse"
)
let service = ServiceDescriptor(
documentation: "Documentation for ServiceA",
documentation: "/// Documentation for ServiceA",
name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
namespace: Name(base: "namespaceA", generatedUpperCase: "NamespaceA", generatedLowerCase: ""),
methods: [method]
Expand Down Expand Up @@ -169,15 +169,15 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {

func testClientCodeTranslatorServerStreamingMethod() throws {
let method = MethodDescriptor(
documentation: "Documentation for MethodA",
documentation: "/// Documentation for MethodA",
name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
isInputStreaming: false,
isOutputStreaming: true,
inputType: "NamespaceA_ServiceARequest",
outputType: "NamespaceA_ServiceAResponse"
)
let service = ServiceDescriptor(
documentation: "Documentation for ServiceA",
documentation: "/// Documentation for ServiceA",
name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
namespace: Name(base: "namespaceA", generatedUpperCase: "NamespaceA", generatedLowerCase: ""),
methods: [method]
Expand Down Expand Up @@ -240,15 +240,15 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {

func testClientCodeTranslatorBidirectionalStreamingMethod() throws {
let method = MethodDescriptor(
documentation: "Documentation for MethodA",
documentation: "/// Documentation for MethodA",
name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
isInputStreaming: true,
isOutputStreaming: true,
inputType: "NamespaceA_ServiceARequest",
outputType: "NamespaceA_ServiceAResponse"
)
let service = ServiceDescriptor(
documentation: "Documentation for ServiceA",
documentation: "/// Documentation for ServiceA",
name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
namespace: Name(base: "namespaceA", generatedUpperCase: "NamespaceA", generatedLowerCase: ""),
methods: [method]
Expand Down Expand Up @@ -311,23 +311,23 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {

func testClientCodeTranslatorMultipleMethods() throws {
let methodA = MethodDescriptor(
documentation: "Documentation for MethodA",
documentation: "/// Documentation for MethodA",
name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
isInputStreaming: true,
isOutputStreaming: false,
inputType: "NamespaceA_ServiceARequest",
outputType: "NamespaceA_ServiceAResponse"
)
let methodB = MethodDescriptor(
documentation: "Documentation for MethodB",
documentation: "/// Documentation for MethodB",
name: Name(base: "MethodB", generatedUpperCase: "MethodB", generatedLowerCase: "methodB"),
isInputStreaming: false,
isOutputStreaming: true,
inputType: "NamespaceA_ServiceARequest",
outputType: "NamespaceA_ServiceAResponse"
)
let service = ServiceDescriptor(
documentation: "Documentation for ServiceA",
documentation: "/// Documentation for ServiceA",
name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
namespace: Name(base: "namespaceA", generatedUpperCase: "NamespaceA", generatedLowerCase: ""),
methods: [methodA, methodB]
Expand Down Expand Up @@ -423,15 +423,15 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {

func testClientCodeTranslatorNoNamespaceService() throws {
let method = MethodDescriptor(
documentation: "Documentation for MethodA",
documentation: "/// Documentation for MethodA",
name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
isInputStreaming: false,
isOutputStreaming: false,
inputType: "ServiceARequest",
outputType: "ServiceAResponse"
)
let service = ServiceDescriptor(
documentation: "Documentation for ServiceA",
documentation: "/// Documentation for ServiceA",
name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
namespace: Name(base: "", generatedUpperCase: "", generatedLowerCase: ""),
methods: [method]
Expand Down Expand Up @@ -494,7 +494,7 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {

func testClientCodeTranslatorMultipleServices() throws {
let serviceA = ServiceDescriptor(
documentation: "Documentation for ServiceA",
documentation: "/// Documentation for ServiceA",
name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
namespace: Name(
base: "nammespaceA",
Expand All @@ -504,7 +504,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {
methods: []
)
let serviceB = ServiceDescriptor(
documentation: "Documentation for ServiceB",
documentation: """
/// Documentation for ServiceB
///
/// Line 2
""",
name: Name(base: "ServiceB", generatedUpperCase: "ServiceB", generatedLowerCase: ""),
namespace: Name(base: "", generatedUpperCase: "", generatedLowerCase: ""),
methods: []
Expand All @@ -523,10 +527,14 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase {
}
}
/// Documentation for ServiceB
///
/// Line 2
public protocol ServiceBClientProtocol: Sendable {}
extension ServiceB.ClientProtocol {
}
/// Documentation for ServiceB
///
/// Line 2
public struct ServiceBClient: ServiceB.ClientProtocol {
private let client: GRPCCore.GRPCClient
public init(client: GRPCCore.GRPCClient) {
Expand Down
Loading