-
Notifications
You must be signed in to change notification settings - Fork 0
Add new @Awaitable family macros for converting legacy APIs to async/await #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new @Awaitable family macros for converting legacy APIs to async/await #43
Conversation
…AwaitablePromiseProtocol Co-authored-by: bonkey <39100+bonkey@users.noreply.github.com>
Co-authored-by: bonkey <39100+bonkey@users.noreply.github.com>
Co-authored-by: bonkey <39100+bonkey@users.noreply.github.com>
…nal conversion capabilities Co-authored-by: bonkey <39100+bonkey@users.noreply.github.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #43 +/- ##
==========================================
- Coverage 81.08% 78.42% -2.67%
==========================================
Files 19 21 +2
Lines 2945 3759 +814
==========================================
+ Hits 2388 2948 +560
- Misses 557 811 +254 ☔ View full report in Codecov by Sentry. |
…Xcode project structure updates.
bonkey
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot @available(*, deprecated) should only appear when it's requested. Do check docs and other classes if they do it properly. It should also follow global config properly. Crete proper tests for all the cases.
| } | ||
|
|
||
| extension DataService { | ||
| @available(*, deprecated, message: "Combine support is deprecated; use async function instead", renamed: "fetchUser") public func fetchUser(id: String) async throws -> User { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot @available(*, deprecated) attribute should only appear when @Awaitable(.deprecated()) is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit e606d9b. The test now correctly expects no @available attribute by default.
| @available(*, deprecated, message: "Combine support is deprecated; use async function instead", renamed: "fetchUser") public func fetchUser(id: String) async throws -> User { | ||
| return try await self.fetchUser(id: id).async() | ||
| } | ||
| @available(*, deprecated, message: "Combine support is deprecated; use async function instead", renamed: "fetchData") public func fetchData() async -> Data { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot @Available(*, deprecated) attribute should only appear when @Awaitable(.deprecated()) is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit e606d9b. The test now correctly expects no @available attribute by default.
| // Implementation | ||
| } | ||
|
|
||
| @available(*, deprecated, message: "Completion handler support is deprecated; use async function instead", renamed: "fetchData") func fetchData() async throws -> Data { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot @Available(*, deprecated) attribute should only appear when @Awaitable(.deprecated()) is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit e606d9b. The test now correctly expects no @available attribute by default.
| // Implementation | ||
| } | ||
|
|
||
| @available(*, deprecated, message: "Completion handler support is deprecated; use async function instead", renamed: "fetchUser") func async_fetchUser(id: String) async throws -> User { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot @Available(*, deprecated) attribute should only appear when @Awaitable(.deprecated()) is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit e606d9b. The test now correctly expects no @available attribute by default.
| // Implementation | ||
| } | ||
|
|
||
| @available(*, deprecated, message: "Completion handler support is deprecated; use async function instead", renamed: "saveData") func saveData(_ data: Data) async throws { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot @Available(*, deprecated) attribute should only appear when @Awaitable(.deprecated()) is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit e606d9b. The test now correctly expects no @available attribute by default.
| } | ||
|
|
||
| extension DataService { | ||
| @available(*, deprecated, message: "Combine support is deprecated; use async function instead", renamed: "fetchUser") public func fetchUser(id: String) async throws -> User { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot @Available(*, deprecated) attribute should only appear when @Awaitable(.deprecated()) is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit e606d9b. The test now correctly expects no @available attribute by default.
| return publisher | ||
| } | ||
|
|
||
| @available(*, deprecated, message: "Combine support is deprecated; use async function instead", renamed: "fetchData") func fetchData() async throws -> Data { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot @Available(*, deprecated) attribute should only appear when @Awaitable(.deprecated()) is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit e606d9b. The test now correctly expects no @available attribute by default.
| return publisher | ||
| } | ||
|
|
||
| @available(*, deprecated, message: "Combine support is deprecated; use async function instead", renamed: "fetchUser") func async_fetchUser(id: String) async throws -> User { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot @Available(*, deprecated) attribute should only appear when @Awaitable(.deprecated()) is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit e606d9b. The test now correctly expects no @available attribute by default.
| return publisher | ||
| } | ||
|
|
||
| @available(*, deprecated, message: "Combine support is deprecated; use async function instead", renamed: "fetchData") func fetchData() async -> Data { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot @Available(*, deprecated) attribute should only appear when @Awaitable(.deprecated()) is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit e606d9b. The test now correctly expects no @available attribute by default.
…en explicitly requested Co-authored-by: bonkey <39100+bonkey@users.noreply.github.com>
Fixed in commit e606d9b. The Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
bonkey
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Remove AwaitablePromiseProtocol altogether from everywhere
Co-authored-by: bonkey <39100+bonkey@users.noreply.github.com>
Removed in commit (pending). Deleted the
The PromiseKit integration now only includes Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds a new family of @Awaitable* macros that provide the reverse functionality of the existing @Awaitless* macros, enabling conversion from legacy callback-based APIs to async/await. The key additions include @AwaitablePublisher, @AwaitableCompletion, and @Awaitable macros, while also fixing availability attribute defaults and removing the deprecated @AwaitablePromiseProtocol macro.
Key changes:
- Added three new macros for legacy API to async/await conversion
- Fixed availability attribute defaults from
.deprecated()tonilacross all macros - Removed
@AwaitablePromiseProtocolmacro completely from the codebase
Reviewed Changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| Sources/AwaitlessKitMacros/AwaitablePublisherMacro.swift | New macro implementation for converting Publisher functions to async/await |
| Sources/AwaitlessKitMacros/AwaitableCompletionMacro.swift | New macro implementation for converting completion handler functions to async/await |
| Sources/AwaitlessKitMacros/AwaitableMacro.swift | New protocol macro for generating async versions of both Publisher and completion methods |
| Sources/AwaitlessKit/AwaitlessKitMacros.swift | Added public macro definitions for the new @awaitable* family |
| Tests/AwaitlessKitTests/*.swift | Comprehensive test coverage for all new macros |
| Sources/AwaitlessKitPromiseMacros/AwaitableMacro.swift | Renamed from AwaitfulMacro to AwaitablePromiseMacro for consistency |
| SampleApp/SampleApp/AwaitlessPromiseExample.swift | Updated examples to use new macro names and demonstrate functionality |
| let genericArguments = identifierType.genericArgumentClause { | ||
| let args = Array(genericArguments.arguments) | ||
| let outputType = args.first?.argument ?? TypeSyntax(IdentifierTypeSyntax(name: .identifier("Void"))) | ||
| let errorType = args.count > 1 ? args[1].argument.description.trimmingCharacters(in: .whitespacesAndNewlines) : "Error" |
Copilot
AI
Oct 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for determining Never error type is scattered and duplicated. Consider extracting error type determination into a dedicated helper function to improve maintainability and reduce code duplication.
| var callArguments = Array(argumentList) | ||
|
|
||
| // If there are existing arguments, add a trailing comma to the last one | ||
| if !callArguments.isEmpty { | ||
| let lastIndex = callArguments.count - 1 | ||
| let lastArg = callArguments[lastIndex] | ||
| callArguments[lastIndex] = LabeledExprSyntax( | ||
| label: lastArg.label, | ||
| colon: lastArg.colon, | ||
| expression: lastArg.expression, | ||
| trailingComma: .commaToken() | ||
| ) | ||
| } | ||
|
|
||
| callArguments.append(LabeledExprSyntax( | ||
| label: .identifier("completion"), | ||
| colon: .colonToken(), | ||
| expression: completionClosure)) |
Copilot
AI
Oct 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complex manual array manipulation for adding trailing commas. Consider using array methods like map with index enumeration for cleaner code, or extract this logic into a helper function.
| var callArguments = Array(argumentList) | |
| // If there are existing arguments, add a trailing comma to the last one | |
| if !callArguments.isEmpty { | |
| let lastIndex = callArguments.count - 1 | |
| let lastArg = callArguments[lastIndex] | |
| callArguments[lastIndex] = LabeledExprSyntax( | |
| label: lastArg.label, | |
| colon: lastArg.colon, | |
| expression: lastArg.expression, | |
| trailingComma: .commaToken() | |
| ) | |
| } | |
| callArguments.append(LabeledExprSyntax( | |
| label: .identifier("completion"), | |
| colon: .colonToken(), | |
| expression: completionClosure)) | |
| let callArguments = argumentList.enumerated().map { index, arg in | |
| LabeledExprSyntax( | |
| label: arg.label, | |
| colon: arg.colon, | |
| expression: arg.expression, | |
| trailingComma: index < argumentList.count - 1 ? .commaToken() : nil | |
| ) | |
| } + [ | |
| LabeledExprSyntax( | |
| label: .identifier("completion"), | |
| colon: .colonToken(), | |
| expression: completionClosure) | |
| ] |
| for argument in arguments { | ||
| if argument.label?.text != "prefix", argument.label?.text != "extensionGeneration", | ||
| let memberAccess = argument.expression.as(MemberAccessExprSyntax.self) | ||
| { |
Copilot
AI
Oct 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The argument parsing logic is duplicated and complex with nested conditionals. This pattern appears multiple times across different macro files. Consider extracting this into a shared helper function to reduce duplication and improve maintainability.
| } | ||
|
|
||
| let arguments = LabeledExprListSyntax([ | ||
| LabeledExprSyntax(expression: DeclReferenceExprSyntax(baseName: .binaryOperator("*")), trailingComma: .commaToken()), |
Copilot
AI
Oct 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Magic string '*' is used without explanation. Consider adding a comment explaining why this specific token is used for availability attributes, or extract it as a named constant.
nilinstead of.deprecated()nilnil.deprecated()and.deprecated("custom message")@availableattributes.valueproperty access for Never error types (was incorrectly generating.value())@AwaitablePromiseProtocolmacro entirely from codebaseSummary of Changes
The
@AwaitablePublisher,@AwaitableCompletion, and@Awaitablemacros were incorrectly defaulting to.deprecated()availability, causing@available(*, deprecated)attributes to be added even when not requested.Fixed:
.deprecated()tonilin all three macro definitions and implementations.deprecated()) and availability with custom messages (.deprecated("custom message")).valueproperty access for Publisher with Never error type - was incorrectly generating.value()with parenthesesBehavior:
@AwaitablePublisher- no availability attribute@AwaitablePublisher(.deprecated())- adds default deprecation message@AwaitablePublisher(.deprecated("custom"))- adds custom deprecation message@AwaitableCompletionand@AwaitableRemoved Macros
Removed
@AwaitablePromiseProtocolmacro completely from the codebase:AwaitfulableMacro.swift)The PromiseKit integration now only includes:
@AwaitlessPromise- async → Promise conversion@AwaitablePromise- Promise → async conversionAll existing tests still pass (126 tests total).
Fixes #42
Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.