Skip to content

Commit d03909b

Browse files
committed
APIClientScope
1 parent 700841d commit d03909b

File tree

5 files changed

+50
-1
lines changed

5 files changed

+50
-1
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Foundation
2+
3+
public protocol APIClientScope {
4+
5+
/// The API client used in this scope.
6+
var client: APIClient { get set }
7+
}
8+
9+
extension APIClientScope {
10+
11+
/// Returns a copy of the API client scope with the client transformed by the given closure.
12+
public func mapClient(_ transform: (APIClient) -> APIClient) -> Self {
13+
var copy = self
14+
copy.client = transform(copy.client)
15+
return copy
16+
}
17+
}

Sources/SwiftAPIClient/Macros.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,15 @@ public macro PATCH(_ path: String...) = #externalMacro(module: "SwiftAPIClientMa
282282
@attached(peer, names: arbitrary)
283283
@attached(memberAttribute)
284284
@attached(member, names: arbitrary)
285+
@attached(extension, conformances: APIClientScope)
285286
public macro Path(_ path: String...) = #externalMacro(module: "SwiftAPIClientMacros", type: "SwiftAPIClientPathMacro")
286287

287288
/// Macro that generates an API client struct.
288289
/// The struct can contain functions with `Call`, `GET`, `POST`, `PUT`, `PATCH`, and `DELETE` macros, as well as structs with the `Path` macro.
289290
/// If you specify a custom init, you must initialize the `client` property.
290291
@attached(memberAttribute)
291292
@attached(member, names: arbitrary)
293+
@attached(extension, conformances: APIClientScope)
292294
public macro API() = #externalMacro(module: "SwiftAPIClientMacros", type: "SwiftAPIClientPathMacro")
293295

294296
@propertyWrapper

Sources/SwiftAPIClientMacros/SwiftAPIClientMacros.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public struct SwiftAPIClientCallMacro: PeerMacro {
142142
}
143143
}
144144

145-
public struct SwiftAPIClientPathMacro: MemberMacro, MemberAttributeMacro, PeerMacro {
145+
public struct SwiftAPIClientPathMacro: MemberMacro, MemberAttributeMacro, PeerMacro, ExtensionMacro {
146146

147147
public static func expansion(
148148
of node: AttributeSyntax,
@@ -157,6 +157,18 @@ public struct SwiftAPIClientPathMacro: MemberMacro, MemberAttributeMacro, PeerMa
157157
return ["@available(*, unavailable)", "@APICallFakeBuilder"]
158158
}
159159

160+
public static func expansion(
161+
of node: AttributeSyntax,
162+
attachedTo declaration: some DeclGroupSyntax,
163+
providingExtensionsOf type: some TypeSyntaxProtocol,
164+
conformingTo protocols: [TypeSyntax],
165+
in context: some MacroExpansionContext
166+
) throws -> [ExtensionDeclSyntax] {
167+
guard declaration.is(StructDeclSyntax.self) || declaration.is(EnumDeclSyntax.self) else { return [] }
168+
let scopeExtension = try ExtensionDeclSyntax("extension \(type.trimmed): APIClientScope {}")
169+
return [scopeExtension]
170+
}
171+
160172
public static func expansion(
161173
of node: AttributeSyntax,
162174
providingPeersOf declaration: some DeclSyntaxProtocol,

Tests/SwiftAPIClientMacrosTests/APIMacroTests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ final class APIMacroTests: XCTestCase {
2929
self.client = client
3030
}
3131
}
32+
33+
extension Pets: APIClientScope {
34+
}
3235
""",
3336
macros: macros,
3437
indentationWidth: .spaces(2)
@@ -57,6 +60,9 @@ final class APIMacroTests: XCTestCase {
5760
5861
public var client: APIClient
5962
}
63+
64+
extension Pets: APIClientScope {
65+
}
6066
""",
6167
macros: macros,
6268
indentationWidth: .spaces(2)

Tests/SwiftAPIClientMacrosTests/PathMacroTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ final class PathMacroTests: XCTestCase {
3434
var pets: Pets {
3535
Pets (client: client.path("pets"))
3636
}
37+
38+
extension Pets: APIClientScope {
39+
}
3740
""",
3841
macros: macros,
3942
indentationWidth: .spaces(2)
@@ -65,6 +68,9 @@ final class PathMacroTests: XCTestCase {
6568
var pets: Pets {
6669
Pets (client: client.path("some", "long", "path"))
6770
}
71+
72+
extension Pets: APIClientScope {
73+
}
6874
""",
6975
macros: macros,
7076
indentationWidth: .spaces(2)
@@ -96,6 +102,9 @@ final class PathMacroTests: XCTestCase {
96102
func pets(_ long: String, id: UUID) -> Pets {
97103
Pets (client: client.path("some", "\\(long)", "path", "\\(id)"))
98104
}
105+
106+
extension Pets: APIClientScope {
107+
}
99108
""",
100109
macros: macros,
101110
indentationWidth: .spaces(2)
@@ -132,6 +141,9 @@ final class PathMacroTests: XCTestCase {
132141
var pets: Pets {
133142
Pets (client: client.path("pets"))
134143
}
144+
145+
extension Pets: APIClientScope {
146+
}
135147
""",
136148
macros: macros,
137149
indentationWidth: .spaces(2)

0 commit comments

Comments
 (0)