Skip to content

Commit cbfac0a

Browse files
authored
Add deprecation annotations for RPCs marked "deprecated=true" (#316)
This enhances the `ConnectClientGenerator` to inspect the `deprecated` option and annotate the generated service functions accordingly. - For async/await functions, the existing `@available` annotation, which only exists for iOS, is adjusted accordingly to introduce and deprecate the function at v13, since that is when concurrency was first made available. - @rebello95 should we consider adjusting both my deprecation annotation and the existing annotation to account for the other supported platforms of the library? - Since no pattern was established for generated callback functions, I enhanced their generation to include `@available` annotations for all supported platforms. The "introduced" and "deprecated" versions for those platforms were determined by the minimum supported version of the respective platform defined in `Package.swift`. Adding the following RPC... ```proto rpc SayDeprecated(SayRequest) returns (SayResponse) { option idempotency_level = NO_SIDE_EFFECTS; option deprecated = true; } ``` ...to the ElizaService defined in the [examples-go repository](https://github.com/connectrpc/examples-go/blob/main/proto/connectrpc/eliza/v1/eliza.proto), from which the Eliza sample app sources are generated, and regenerating the Swift service (setting `GenerateCallbackMethods=true` to also demonstrate callback behavior) yields the following result: ```swift @available(iOS, introduced: 12, deprecated: 12, message: "This function has been marked deprecated.") @available(macOS, introduced: 10.15, deprecated: 10.15, message: "This function has been marked deprecated.") @available(tvOS, introduced: 13, deprecated: 13, message: "This function has been marked deprecated.") @available(watchOS, introduced: 6, deprecated: 6, message: "This function has been marked deprecated.") @discardableResult func `sayDeprecated`(request: Connectrpc_Eliza_V1_SayRequest, headers: Connect.Headers, completion: @escaping @sendable (ResponseMessage<Connectrpc_Eliza_V1_SayResponse>) -> Void) -> Connect.Cancelable @available(iOS, introduced: 13, deprecated: 13, message: "This function has been marked deprecated.") func `sayDeprecated`(request: Connectrpc_Eliza_V1_SayRequest, headers: Connect.Headers) async -> ResponseMessage<Connectrpc_Eliza_V1_SayResponse> ``` The generated code for the existing `Say` RPC remains unchanged: ```swift /// Say is a unary RPC. Eliza responds to the prompt with a single sentence. @discardableResult func `say`(request: Connectrpc_Eliza_V1_SayRequest, headers: Connect.Headers, completion: @escaping @sendable (ResponseMessage<Connectrpc_Eliza_V1_SayResponse>) -> Void) -> Connect.Cancelable /// Say is a unary RPC. Eliza responds to the prompt with a single sentence. @available(iOS 13, *) func `say`(request: Connectrpc_Eliza_V1_SayRequest, headers: Connect.Headers) async -> ResponseMessage<Connectrpc_Eliza_V1_SayResponse> ``` The same additions have been made to the `ConnectMockGenerator`. Closes #305 --------- Signed-off-by: Eddie Seay <[email protected]>
1 parent 9bed141 commit cbfac0a

File tree

2 files changed

+62
-3
lines changed

2 files changed

+62
-3
lines changed

Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ final class ConnectMockGenerator: Generator {
117117

118118
private func printCallbackMethodMockImplementation(for method: MethodDescriptor) {
119119
self.printLine()
120+
if let availabilityAnnotation = method.callbackAvailabilityAnnotation() {
121+
self.printLine(availabilityAnnotation)
122+
}
120123
if !method.serverStreaming && !method.clientStreaming {
121124
self.printLine("@discardableResult")
122125
}
@@ -150,7 +153,9 @@ final class ConnectMockGenerator: Generator {
150153

151154
private func printAsyncAwaitMethodMockImplementation(for method: MethodDescriptor) {
152155
self.printLine()
153-
156+
if let availabilityAnnotation = method.asyncAwaitAvailabilityAnnotation() {
157+
self.printLine(availabilityAnnotation)
158+
}
154159
self.printLine(
155160
"\(self.typeVisibility) "
156161
+ method.asyncAwaitSignature(
@@ -219,4 +224,28 @@ private extension MethodDescriptor {
219224
"""
220225
}
221226
}
227+
228+
func callbackAvailabilityAnnotation() -> String? {
229+
if self.options.deprecated {
230+
// swiftlint:disable line_length
231+
return """
232+
@available(iOS, introduced: 12, deprecated: 12, message: "This RPC has been marked as deprecated in its `.proto` file.")
233+
@available(macOS, introduced: 10.15, deprecated: 10.15, message: "This RPC has been marked as deprecated in its `.proto` file.")
234+
@available(tvOS, introduced: 13, deprecated: 13, message: "This RPC has been marked as deprecated in its `.proto` file.")
235+
@available(watchOS, introduced: 6, deprecated: 6, message: "This RPC has been marked as deprecated in its `.proto` file.")
236+
"""
237+
// swiftlint:enable line_length
238+
} else {
239+
return nil
240+
}
241+
}
242+
243+
func asyncAwaitAvailabilityAnnotation() -> String? {
244+
if self.options.deprecated {
245+
// swiftlint:disable:next line_length
246+
return "@available(iOS, introduced: 13, deprecated: 13, message: \"This RPC has been marked as deprecated in its `.proto` file.\")"
247+
} else {
248+
return nil
249+
}
250+
}
222251
}

Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ final class ConnectClientGenerator: Generator {
119119
private func printCallbackMethodInterface(for method: MethodDescriptor) {
120120
self.printLine()
121121
self.printCommentsIfNeeded(for: method)
122+
if let availabilityAnnotation = method.callbackAvailabilityAnnotation() {
123+
self.printLine(availabilityAnnotation)
124+
}
122125
if !method.serverStreaming && !method.clientStreaming {
123126
self.printLine("@discardableResult")
124127
}
@@ -133,7 +136,7 @@ final class ConnectClientGenerator: Generator {
133136
private func printAsyncAwaitMethodInterface(for method: MethodDescriptor) {
134137
self.printLine()
135138
self.printCommentsIfNeeded(for: method)
136-
self.printLine("@available(iOS 13, *)")
139+
self.printLine(method.asyncAwaitAvailabilityAnnotation())
137140
self.printLine(
138141
method.asyncAwaitSignature(
139142
using: self.namer, includeDefaults: false, options: self.options
@@ -143,6 +146,9 @@ final class ConnectClientGenerator: Generator {
143146

144147
private func printCallbackMethodImplementation(for method: MethodDescriptor) {
145148
self.printLine()
149+
if let availabilityAnnotation = method.callbackAvailabilityAnnotation() {
150+
self.printLine(availabilityAnnotation)
151+
}
146152
if !method.serverStreaming && !method.clientStreaming {
147153
self.printLine("@discardableResult")
148154
}
@@ -162,7 +168,7 @@ final class ConnectClientGenerator: Generator {
162168

163169
private func printAsyncAwaitMethodImplementation(for method: MethodDescriptor) {
164170
self.printLine()
165-
self.printLine("@available(iOS 13, *)")
171+
self.printLine(method.asyncAwaitAvailabilityAnnotation())
166172
self.printLine(
167173
"\(self.visibility) "
168174
+ method.asyncAwaitSignature(
@@ -201,6 +207,30 @@ private extension MethodDescriptor {
201207
}
202208
}
203209

210+
func callbackAvailabilityAnnotation() -> String? {
211+
if self.options.deprecated {
212+
// swiftlint:disable line_length
213+
return """
214+
@available(iOS, introduced: 12, deprecated: 12, message: "This RPC has been marked as deprecated in its `.proto` file.")
215+
@available(macOS, introduced: 10.15, deprecated: 10.15, message: "This RPC has been marked as deprecated in its `.proto` file.")
216+
@available(tvOS, introduced: 13, deprecated: 13, message: "This RPC has been marked as deprecated in its `.proto` file.")
217+
@available(watchOS, introduced: 6, deprecated: 6, message: "This RPC has been marked as deprecated in its `.proto` file.")
218+
"""
219+
// swiftlint:enable line_length
220+
} else {
221+
return nil
222+
}
223+
}
224+
225+
func asyncAwaitAvailabilityAnnotation() -> String {
226+
if self.options.deprecated {
227+
// swiftlint:disable:next line_length
228+
return "@available(iOS, introduced: 13, deprecated: 13, message: \"This RPC has been marked as deprecated in its `.proto` file.\")"
229+
} else {
230+
return "@available(iOS 13, *)"
231+
}
232+
}
233+
204234
func callbackReturnValue() -> String {
205235
if self.clientStreaming && self.serverStreaming {
206236
return """

0 commit comments

Comments
 (0)