Skip to content

Commit

Permalink
Add leading comment to generated initializer to explain Macro compati…
Browse files Browse the repository at this point in the history
…bility
  • Loading branch information
dfed committed Dec 26, 2023
1 parent 20c99d0 commit 97f6b40
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 5 deletions.
15 changes: 10 additions & 5 deletions Sources/SafeDIMacros/Macros/InstantiableMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,16 @@ public struct InstantiableMacro: MemberMacro {
.contains(where: { $0.isValid(forFulfilling: visitor.dependencies) })
guard hasMemberwiseInitializerForInjectableProperties else {
if visitor.uninitializedPropertyNames.isEmpty {
return [
DeclSyntax(
Initializer.generateRequiredInitializer(for: visitor.dependencies)
)
]
var initializer = Initializer.generateRequiredInitializer(for: visitor.dependencies)
initializer.leadingTrivia = Trivia(stringLiteral: """
// A generated initializer that has one argument per SafeDI-injected property.
// Because this initializer is generated by a Swift Macro, it can not be used by other Swift Macros.
// As a result, this initializer can not be used within a #Preview macro closure.
// This initiailizer is only generated because you have not written this macro yourself.
// Copy/pasting this generated macro into your code will enable this initializer to be used within other Swift Macros.
""")
return [DeclSyntax(initializer)]
} else {
var membersWithInitializer = declaration.memberBlock.members
membersWithInitializer.insert(
Expand Down
78 changes: 78 additions & 0 deletions Tests/SafeDIMacrosTests/InstantiableMacroTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,35 @@ final class InstantiableMacroTests: XCTestCase {
"""
public struct ExampleService {
// A generated initializer that has one argument per SafeDI-injected property.
// Because this initializer is generated by a Swift Macro, it can not be used by other Swift Macros.
// As a result, this initializer can not be used within a #Preview macro closure.
// This initiailizer is only generated because you have not written this macro yourself.
// Copy/pasting this generated macro into your code will enable this initializer to be used within other Swift Macros.
public init() {
}
}
"""
}
}

func test_declaration_doesNotGenerateRequiredInitializerWithoutDependenciesIfItAlreadyExists() {
assertMacro {
"""
@Instantiable
public struct ExampleService {
public init() {}
}
"""
} expansion: {
"""
public struct ExampleService {
public init() {}
}
"""
}
}

func test_declaration_generatesRequiredInitializerWithoutAnyDependenciesAndInitializedVariable() {
assertMacro {
"""
Expand All @@ -77,6 +99,11 @@ final class InstantiableMacroTests: XCTestCase {
public struct ExampleService {
var initializedVariable = "test"
// A generated initializer that has one argument per SafeDI-injected property.
// Because this initializer is generated by a Swift Macro, it can not be used by other Swift Macros.
// As a result, this initializer can not be used within a #Preview macro closure.
// This initiailizer is only generated because you have not written this macro yourself.
// Copy/pasting this generated macro into your code will enable this initializer to be used within other Swift Macros.
public init() {
}
}
Expand All @@ -97,13 +124,44 @@ final class InstantiableMacroTests: XCTestCase {
public struct ExampleService {
var initializedVariable { "test" }
// A generated initializer that has one argument per SafeDI-injected property.
// Because this initializer is generated by a Swift Macro, it can not be used by other Swift Macros.
// As a result, this initializer can not be used within a #Preview macro closure.
// This initiailizer is only generated because you have not written this macro yourself.
// Copy/pasting this generated macro into your code will enable this initializer to be used within other Swift Macros.
public init() {
}
}
"""
}
}

func test_declaration_doesNotGenerateRequiredInitializerWithDependenciesIfItAlreadyExists() {
assertMacro {
"""
@Instantiable
public struct ExampleService {
@Instantiated
let receivedA: ReceivedA
public init(receivedA: ReceivedA) {
self.receivedA = receivedA
}
}
"""
} expansion: {
"""
public struct ExampleService {
let receivedA: ReceivedA
public init(receivedA: ReceivedA) {
self.receivedA = receivedA
}
}
"""
}
}

func test_declaration_generatesRequiredInitializerWithDependencies() {
assertMacro {
"""
Expand All @@ -118,6 +176,11 @@ final class InstantiableMacroTests: XCTestCase {
public struct ExampleService {
let receivedA: ReceivedA
// A generated initializer that has one argument per SafeDI-injected property.
// Because this initializer is generated by a Swift Macro, it can not be used by other Swift Macros.
// As a result, this initializer can not be used within a #Preview macro closure.
// This initiailizer is only generated because you have not written this macro yourself.
// Copy/pasting this generated macro into your code will enable this initializer to be used within other Swift Macros.
public init(receivedA: ReceivedA) {
self.receivedA = receivedA
}
Expand All @@ -144,6 +207,11 @@ final class InstantiableMacroTests: XCTestCase {
let initializedProperty = 5
// A generated initializer that has one argument per SafeDI-injected property.
// Because this initializer is generated by a Swift Macro, it can not be used by other Swift Macros.
// As a result, this initializer can not be used within a #Preview macro closure.
// This initiailizer is only generated because you have not written this macro yourself.
// Copy/pasting this generated macro into your code will enable this initializer to be used within other Swift Macros.
public init(receivedA: ReceivedA) {
self.receivedA = receivedA
}
Expand Down Expand Up @@ -183,6 +251,11 @@ final class InstantiableMacroTests: XCTestCase {
let forwardedB: ForwardedB
let receivedA: ReceivedA
// A generated initializer that has one argument per SafeDI-injected property.
// Because this initializer is generated by a Swift Macro, it can not be used by other Swift Macros.
// As a result, this initializer can not be used within a #Preview macro closure.
// This initiailizer is only generated because you have not written this macro yourself.
// Copy/pasting this generated macro into your code will enable this initializer to be used within other Swift Macros.
public init(forwardedA: ForwardedA, forwardedB: ForwardedB, receivedA: ReceivedA) {
self.forwardedA = forwardedA
self.forwardedB = forwardedB
Expand All @@ -207,6 +280,11 @@ final class InstantiableMacroTests: XCTestCase {
public struct ExampleService {
private let instantiatableAInstantiator: Instantiator<ReceivedA>
// A generated initializer that has one argument per SafeDI-injected property.
// Because this initializer is generated by a Swift Macro, it can not be used by other Swift Macros.
// As a result, this initializer can not be used within a #Preview macro closure.
// This initiailizer is only generated because you have not written this macro yourself.
// Copy/pasting this generated macro into your code will enable this initializer to be used within other Swift Macros.
public init(instantiatableAInstantiator: Instantiator<ReceivedA>) {
self.instantiatableAInstantiator = instantiatableAInstantiator
}
Expand Down

0 comments on commit 97f6b40

Please sign in to comment.