Skip to content

Commit cf57a1c

Browse files
authored
DependencyClient - Ignore @Dependency and @DependencyEndpointIgnored properties (#212)
1 parent d71fdd2 commit cf57a1c

File tree

5 files changed

+128
-4
lines changed

5 files changed

+128
-4
lines changed

Sources/DependenciesMacros/Macros.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ public macro DependencyEndpoint(method: String = "") =
209209
module: "DependenciesMacrosPlugin", type: "DependencyEndpointMacro"
210210
)
211211

212+
@attached(accessor, names: named(willSet))
213+
public macro DependencyEndpointIgnored() =
214+
#externalMacro(module: "DependenciesMacrosPlugin", type: "DependencyEndpointIgnoredMacro")
215+
212216
/// The error thrown by "unimplemented" closures produced by ``DependencyEndpoint(method:)``
213217
public struct Unimplemented: Error {
214218
let endpoint: String

Sources/DependenciesMacrosPlugin/DependencyClientMacro.swift

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro {
1212
providingAttributesFor member: M,
1313
in context: C
1414
) throws -> [AttributeSyntax] {
15+
if member.as(VariableDeclSyntax.self)?.isIgnored == true {
16+
return []
17+
}
18+
1519
guard
1620
let property = member.as(VariableDeclSyntax.self),
1721
property.bindingSpecifier.tokenKind != .keyword(.let),
@@ -62,6 +66,7 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro {
6266
}
6367
)
6468
}
69+
6570
return attributes
6671
}
6772

@@ -94,6 +99,7 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro {
9499
let isEndpoint =
95100
property.hasDependencyEndpointMacroAttached
96101
|| property.bindingSpecifier.tokenKind != .keyword(.let) && property.isClosure
102+
97103
let propertyAccess = Access(modifiers: property.modifiers)
98104
guard
99105
var binding = property.bindings.first,
@@ -117,6 +123,8 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro {
117123
if propertyAccess == .private, binding.initializer != nil { continue }
118124
accesses.insert(propertyAccess ?? .internal)
119125

126+
if property.isIgnored { continue }
127+
120128
guard let type = binding.typeAnnotation?.type ?? binding.initializer?.value.literalType
121129
else {
122130
context.diagnose(
@@ -156,6 +164,7 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro {
156164
)
157165
return []
158166
}
167+
159168
if var attributedTypeSyntax = type.as(AttributedTypeSyntax.self),
160169
attributedTypeSyntax.baseType.is(FunctionTypeSyntax.self)
161170
{
@@ -258,23 +267,43 @@ private struct Property {
258267
var isEndpoint: Bool
259268
}
260269

261-
extension VariableDeclSyntax {
262-
fileprivate var isStatic: Bool {
270+
fileprivate extension VariableDeclSyntax {
271+
var isStatic: Bool {
263272
self.modifiers.contains { modifier in
264273
modifier.name.tokenKind == .keyword(.static)
265274
}
266275
}
267276

268-
fileprivate var hasDependencyEndpointMacroAttached: Bool {
277+
static let dependencyEndpointName = "DependencyEndpoint"
278+
static let dependencyEndpointIgnoredName = "DependencyEndpointIgnored"
279+
static let dependencyName = "Dependency"
280+
281+
func hasMacroAttached(_ macro: String) -> Bool {
269282
self.attributes.contains {
270283
guard
271284
case let .attribute(attribute) = $0,
272285
let attributeName = attribute.attributeName.as(IdentifierTypeSyntax.self)?.name.text,
273-
["DependencyEndpoint"].qualified("DependenciesMacros").contains(attributeName)
286+
[macro].qualified("DependenciesMacros").contains(attributeName)
274287
else { return false }
275288
return true
276289
}
277290
}
291+
292+
var hasDependencyEndpointMacroAttached: Bool {
293+
hasMacroAttached(Self.dependencyEndpointName)
294+
}
295+
296+
var hasDependencyEndpointIgnoredMacroAttached: Bool {
297+
hasMacroAttached(Self.dependencyEndpointIgnoredName)
298+
}
299+
300+
var hasDependencyMacroAttached: Bool {
301+
hasMacroAttached(Self.dependencyName)
302+
}
303+
304+
var isIgnored: Bool {
305+
hasDependencyMacroAttached || hasDependencyEndpointIgnoredMacroAttached
306+
}
278307
}
279308

280309
extension ExprSyntax {

Sources/DependenciesMacrosPlugin/DependencyEndpointMacro.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,16 @@ extension TupleTypeElementSyntax {
376376
.tokenKind == .keyword(.inout)
377377
}
378378
}
379+
380+
public struct DependencyEndpointIgnoredMacro: AccessorMacro {
381+
public static func expansion<
382+
Context: MacroExpansionContext,
383+
Declaration: DeclSyntaxProtocol
384+
>(
385+
of node: AttributeSyntax,
386+
providingAccessorsOf declaration: Declaration,
387+
in context: Context
388+
) throws -> [AccessorDeclSyntax] {
389+
return []
390+
}
391+
}

Sources/DependenciesMacrosPlugin/Plugins.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ struct MacrosPlugin: CompilerPlugin {
66
let providingMacros: [Macro.Type] = [
77
DependencyClientMacro.self,
88
DependencyEndpointMacro.self,
9+
DependencyEndpointIgnoredMacro.self
910
]
1011
}

Tests/DependenciesMacrosPluginTests/DependencyClientMacroTests.swift

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ final class DependencyClientMacroTests: BaseTestCase {
1313
}
1414

1515
func testBasics() {
16+
1617
assertMacro {
1718
"""
1819
@DependencyClient
@@ -616,6 +617,82 @@ final class DependencyClientMacroTests: BaseTestCase {
616617
}
617618
}
618619

620+
func testWithDependencyEndpointIgnored() {
621+
assertMacro {
622+
"""
623+
@DependencyClient
624+
struct Client: Sendable {
625+
626+
let id = UUID()
627+
var endpoint: @Sendable () -> Void
628+
629+
@DependencyEndpointIgnored
630+
var ignoredVar: @Sendable () -> Void
631+
}
632+
"""
633+
} expansion: {
634+
"""
635+
struct Client: Sendable {
636+
637+
let id = UUID()
638+
@DependencyEndpoint
639+
var endpoint: @Sendable () -> Void
640+
641+
@DependencyEndpointIgnored
642+
var ignoredVar: @Sendable () -> Void
643+
644+
init(
645+
endpoint: @Sendable @escaping () -> Void
646+
) {
647+
self.endpoint = endpoint
648+
}
649+
650+
init() {
651+
}
652+
}
653+
"""
654+
}
655+
}
656+
657+
func testWithDependencyMacro() {
658+
assertMacro {
659+
"""
660+
@DependencyClient
661+
struct Client: Sendable {
662+
@Dependency(TypedDependency.self) var typedDependency
663+
@Dependency(TypedDependency.self) var typedDependency: TypedDependency
664+
@Dependency(\\.dependency1) var dependency1
665+
@Dependency(\\.dependency2) var dependency2: DependencyTwo
666+
667+
let id = UUID()
668+
var endpoint: @Sendable () -> Void
669+
}
670+
"""
671+
} expansion: {
672+
#"""
673+
struct Client: Sendable {
674+
@Dependency(TypedDependency.self) var typedDependency
675+
@Dependency(TypedDependency.self) var typedDependency: TypedDependency
676+
@Dependency(\.dependency1) var dependency1
677+
@Dependency(\.dependency2) var dependency2: DependencyTwo
678+
679+
let id = UUID()
680+
@DependencyEndpoint
681+
var endpoint: @Sendable () -> Void
682+
683+
init(
684+
endpoint: @Sendable @escaping () -> Void
685+
) {
686+
self.endpoint = endpoint
687+
}
688+
689+
init() {
690+
}
691+
}
692+
"""#
693+
}
694+
}
695+
619696
func testLet_WithDefault() {
620697
assertMacro {
621698
"""

0 commit comments

Comments
 (0)