Skip to content

Commit

Permalink
DependencyClient - Ignore @Dependency and `@DependencyEndpointIgnor…
Browse files Browse the repository at this point in the history
…ed` properties (#212)
  • Loading branch information
freak4pc authored May 6, 2024
1 parent d71fdd2 commit cf57a1c
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Sources/DependenciesMacros/Macros.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ public macro DependencyEndpoint(method: String = "") =
module: "DependenciesMacrosPlugin", type: "DependencyEndpointMacro"
)

@attached(accessor, names: named(willSet))
public macro DependencyEndpointIgnored() =
#externalMacro(module: "DependenciesMacrosPlugin", type: "DependencyEndpointIgnoredMacro")

/// The error thrown by "unimplemented" closures produced by ``DependencyEndpoint(method:)``
public struct Unimplemented: Error {
let endpoint: String
Expand Down
37 changes: 33 additions & 4 deletions Sources/DependenciesMacrosPlugin/DependencyClientMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro {
providingAttributesFor member: M,
in context: C
) throws -> [AttributeSyntax] {
if member.as(VariableDeclSyntax.self)?.isIgnored == true {
return []
}

guard
let property = member.as(VariableDeclSyntax.self),
property.bindingSpecifier.tokenKind != .keyword(.let),
Expand Down Expand Up @@ -62,6 +66,7 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro {
}
)
}

return attributes
}

Expand Down Expand Up @@ -94,6 +99,7 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro {
let isEndpoint =
property.hasDependencyEndpointMacroAttached
|| property.bindingSpecifier.tokenKind != .keyword(.let) && property.isClosure

let propertyAccess = Access(modifiers: property.modifiers)
guard
var binding = property.bindings.first,
Expand All @@ -117,6 +123,8 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro {
if propertyAccess == .private, binding.initializer != nil { continue }
accesses.insert(propertyAccess ?? .internal)

if property.isIgnored { continue }

guard let type = binding.typeAnnotation?.type ?? binding.initializer?.value.literalType
else {
context.diagnose(
Expand Down Expand Up @@ -156,6 +164,7 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro {
)
return []
}

if var attributedTypeSyntax = type.as(AttributedTypeSyntax.self),
attributedTypeSyntax.baseType.is(FunctionTypeSyntax.self)
{
Expand Down Expand Up @@ -258,23 +267,43 @@ private struct Property {
var isEndpoint: Bool
}

extension VariableDeclSyntax {
fileprivate var isStatic: Bool {
fileprivate extension VariableDeclSyntax {
var isStatic: Bool {
self.modifiers.contains { modifier in
modifier.name.tokenKind == .keyword(.static)
}
}

fileprivate var hasDependencyEndpointMacroAttached: Bool {
static let dependencyEndpointName = "DependencyEndpoint"
static let dependencyEndpointIgnoredName = "DependencyEndpointIgnored"
static let dependencyName = "Dependency"

func hasMacroAttached(_ macro: String) -> Bool {
self.attributes.contains {
guard
case let .attribute(attribute) = $0,
let attributeName = attribute.attributeName.as(IdentifierTypeSyntax.self)?.name.text,
["DependencyEndpoint"].qualified("DependenciesMacros").contains(attributeName)
[macro].qualified("DependenciesMacros").contains(attributeName)
else { return false }
return true
}
}

var hasDependencyEndpointMacroAttached: Bool {
hasMacroAttached(Self.dependencyEndpointName)
}

var hasDependencyEndpointIgnoredMacroAttached: Bool {
hasMacroAttached(Self.dependencyEndpointIgnoredName)
}

var hasDependencyMacroAttached: Bool {
hasMacroAttached(Self.dependencyName)
}

var isIgnored: Bool {
hasDependencyMacroAttached || hasDependencyEndpointIgnoredMacroAttached
}
}

extension ExprSyntax {
Expand Down
13 changes: 13 additions & 0 deletions Sources/DependenciesMacrosPlugin/DependencyEndpointMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,16 @@ extension TupleTypeElementSyntax {
.tokenKind == .keyword(.inout)
}
}

public struct DependencyEndpointIgnoredMacro: AccessorMacro {
public static func expansion<
Context: MacroExpansionContext,
Declaration: DeclSyntaxProtocol
>(
of node: AttributeSyntax,
providingAccessorsOf declaration: Declaration,
in context: Context
) throws -> [AccessorDeclSyntax] {
return []
}
}
1 change: 1 addition & 0 deletions Sources/DependenciesMacrosPlugin/Plugins.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ struct MacrosPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
DependencyClientMacro.self,
DependencyEndpointMacro.self,
DependencyEndpointIgnoredMacro.self
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ final class DependencyClientMacroTests: BaseTestCase {
}

func testBasics() {

assertMacro {
"""
@DependencyClient
Expand Down Expand Up @@ -616,6 +617,82 @@ final class DependencyClientMacroTests: BaseTestCase {
}
}

func testWithDependencyEndpointIgnored() {
assertMacro {
"""
@DependencyClient
struct Client: Sendable {
let id = UUID()
var endpoint: @Sendable () -> Void
@DependencyEndpointIgnored
var ignoredVar: @Sendable () -> Void
}
"""
} expansion: {
"""
struct Client: Sendable {
let id = UUID()
@DependencyEndpoint
var endpoint: @Sendable () -> Void
@DependencyEndpointIgnored
var ignoredVar: @Sendable () -> Void
init(
endpoint: @Sendable @escaping () -> Void
) {
self.endpoint = endpoint
}
init() {
}
}
"""
}
}

func testWithDependencyMacro() {
assertMacro {
"""
@DependencyClient
struct Client: Sendable {
@Dependency(TypedDependency.self) var typedDependency
@Dependency(TypedDependency.self) var typedDependency: TypedDependency
@Dependency(\\.dependency1) var dependency1
@Dependency(\\.dependency2) var dependency2: DependencyTwo
let id = UUID()
var endpoint: @Sendable () -> Void
}
"""
} expansion: {
#"""
struct Client: Sendable {
@Dependency(TypedDependency.self) var typedDependency
@Dependency(TypedDependency.self) var typedDependency: TypedDependency
@Dependency(\.dependency1) var dependency1
@Dependency(\.dependency2) var dependency2: DependencyTwo
let id = UUID()
@DependencyEndpoint
var endpoint: @Sendable () -> Void
init(
endpoint: @Sendable @escaping () -> Void
) {
self.endpoint = endpoint
}
init() {
}
}
"""#
}
}

func testLet_WithDefault() {
assertMacro {
"""
Expand Down

0 comments on commit cf57a1c

Please sign in to comment.