Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Sep 28, 2025

  • Fix availability attribute defaults to nil instead of .deprecated()
  • Update macro definitions to default to nil
  • Update macro implementations to default to nil
  • Update documentation to reflect optional availability
  • Fix availability parsing to handle both .deprecated() and .deprecated("custom message")
  • Update all tests to remove default @available attributes
  • Add tests for explicit availability requests
  • Fix .value property access for Never error types (was incorrectly generating .value())
  • Remove @AwaitablePromiseProtocol macro entirely from codebase
  • All 126 tests passing

Summary of Changes

The @AwaitablePublisher, @AwaitableCompletion, and @Awaitable macros were incorrectly defaulting to .deprecated() availability, causing @available(*, deprecated) attributes to be added even when not requested.

Fixed:

  1. Changed default availability from .deprecated() to nil in all three macro definitions and implementations
  2. Updated availability parsing to handle both simple availability (.deprecated()) and availability with custom messages (.deprecated("custom message"))
  3. Fixed .value property access for Publisher with Never error type - was incorrectly generating .value() with parentheses
  4. Updated all tests to match correct behavior - no availability attribute unless explicitly requested
  5. Added comprehensive tests for explicit availability cases

Behavior:

  • @AwaitablePublisher - no availability attribute
  • @AwaitablePublisher(.deprecated()) - adds default deprecation message
  • @AwaitablePublisher(.deprecated("custom")) - adds custom deprecation message
  • Same for @AwaitableCompletion and @Awaitable

Removed Macros

Removed @AwaitablePromiseProtocol macro completely from the codebase:

  • Deleted macro implementation file (AwaitfulableMacro.swift)
  • Removed macro definition from public API
  • Removed plugin registration
  • Deleted associated test files (2 files)
  • Removed usage examples from SampleApp
  • Removed documentation references from README

The PromiseKit integration now only includes:

  • @AwaitlessPromise - async → Promise conversion
  • @AwaitablePromise - Promise → async conversion

All existing tests still pass (126 tests total).

Fixes #42

Original prompt

This section details on the original issue you should resolve

<issue_title>New macro in @awaitable family</issue_title>
<issue_description>Create a new macros that mirrors existing macros that use Awaitless.run, like:

  • @AwaitlessPublisher
  • @AwaitlessCompletion
  • @Awaitlessable

That create the opposite code: convert a publisher or completion in a class or protocol into an async function that provide async/await feature with native Swift functions.

  1. Call them AwaitablePublisher and AwaitableCompletion
  2. Rename existing Awaitable to AwaitablePromise
  3. Call the new protocol to Awaitable. It should convert both: publishers and completion functions</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #42

💡 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.

Copilot AI and others added 4 commits September 28, 2025 22:56
…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>
Copilot AI changed the title [WIP] New macro in @Awaitable family Add new @Awaitable family macros for converting legacy APIs to async/await Sep 28, 2025
Copilot AI requested a review from bonkey September 28, 2025 23:15
@codecov
Copy link

codecov bot commented Sep 28, 2025

Codecov Report

❌ Patch coverage is 74.88869% with 282 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.42%. Comparing base (a1e5f89) to head (5117b53).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
Sources/AwaitlessKitMacros/AwaitableMacro.swift 53.74% 210 Missing ⚠️
.../AwaitlessKitMacros/AwaitableCompletionMacro.swift 91.90% 31 Missing ⚠️
...s/AwaitlessKitMacros/AwaitablePublisherMacro.swift 90.31% 25 Missing ⚠️
...ces/AwaitlessKitMacros/AwaitlessMacroHelpers.swift 0.00% 10 Missing ⚠️
.../AwaitlessKitMacros/AwaitlessKitMacrosPlugin.swift 0.00% 3 Missing ⚠️
...ces/AwaitlessKitPromiseMacros/AwaitableMacro.swift 0.00% 2 Missing ⚠️
...romiseMacros/AwaitlessKitPromiseMacrosPlugin.swift 0.00% 1 Missing ⚠️
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.
📢 Have feedback on the report? Share it here.

Copy link
Owner

@bonkey bonkey left a 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 {
Copy link
Owner

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

Copy link
Contributor Author

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 {
Copy link
Owner

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

Copy link
Contributor Author

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 {
Copy link
Owner

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

Copy link
Contributor Author

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 {
Copy link
Owner

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

Copy link
Contributor Author

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 {
Copy link
Owner

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

Copy link
Contributor Author

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 {
Copy link
Owner

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

Copy link
Contributor Author

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 {
Copy link
Owner

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

Copy link
Contributor Author

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 {
Copy link
Owner

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

Copy link
Contributor Author

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 {
Copy link
Owner

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

Copy link
Contributor Author

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>
Copy link
Contributor Author

Copilot AI commented Oct 11, 2025

@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 f...

Fixed in commit e606d9b. The @available(*, deprecated) attribute now only appears when explicitly requested via @AwaitablePublisher(.deprecated()), @AwaitableCompletion(.deprecated()), or @Awaitable(.deprecated()). The macros default to nil availability (no attribute) when not specified, matching the behavior of existing @Awaitless* macros. Added comprehensive tests for both default and explicit availability cases.

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:

  • ocsp.apple.com
    • Triggering command: /usr/share/swift/usr/bin/swift-build (dns block)
    • Triggering command: /usr/share/swift/usr/bin/swift-test --parallel --filter AwaitablePublisher (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from bonkey October 11, 2025 10:01
Copy link
Owner

@bonkey bonkey left a 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>
Copy link
Contributor Author

Copilot AI commented Oct 11, 2025

@copilot Remove AwaitablePromiseProtocol altogether from everywhere

Removed in commit (pending). Deleted the @AwaitablePromiseProtocol macro completely from the codebase including:

  • Macro definition and implementation
  • Plugin registration
  • Test files (2 files)
  • SampleApp usage examples
  • README documentation

The PromiseKit integration now only includes @AwaitlessPromise and @AwaitablePromise macros. All 126 tests pass.

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:

  • ocsp.apple.com
    • Triggering command: /usr/share/swift/usr/bin/swift-build (dns block)
    • Triggering command: /usr/share/swift/usr/bin/swift-test --parallel (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from bonkey October 11, 2025 11:45
@bonkey bonkey marked this pull request as ready for review October 11, 2025 12:57
Copilot AI review requested due to automatic review settings October 11, 2025 12:57
@bonkey bonkey enabled auto-merge (squash) October 11, 2025 12:57
Copy link
Contributor

Copilot AI left a 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() to nil across all macros
  • Removed @AwaitablePromiseProtocol macro 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"
Copy link

Copilot AI Oct 11, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines +204 to +221
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))
Copy link

Copilot AI Oct 11, 2025

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.

Suggested change
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)
]

Copilot uses AI. Check for mistakes.
Comment on lines +477 to +480
for argument in arguments {
if argument.label?.text != "prefix", argument.label?.text != "extensionGeneration",
let memberAccess = argument.expression.as(MemberAccessExprSyntax.self)
{
Copy link

Copilot AI Oct 11, 2025

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.

Copilot uses AI. Check for mistakes.
}

let arguments = LabeledExprListSyntax([
LabeledExprSyntax(expression: DeclReferenceExprSyntax(baseName: .binaryOperator("*")), trailingComma: .commaToken()),
Copy link

Copilot AI Oct 11, 2025

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.

Copilot uses AI. Check for mistakes.
@bonkey bonkey merged commit 604f2a7 into main Oct 11, 2025
26 of 28 checks passed
@bonkey bonkey deleted the copilot/fix-63323e6a-f512-4d33-8335-e67730ea8c50 branch October 11, 2025 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New macro in @Awaitable family

2 participants