@@ -43,24 +43,84 @@ public struct AddTarget {
43
43
throw ManifestEditError . cannotFindPackage
44
44
}
45
45
46
+ // Create a mutable version of target to which we can add more
47
+ // content when needed.
48
+ var target = target
49
+
50
+ // Macro targets need to depend on a couple of libraries from
51
+ // SwiftSyntax.
52
+ if target. type == . macro {
53
+ target. dependencies. append ( contentsOf: macroTargetDependencies)
54
+ }
55
+
46
56
let manifestEdits = try packageCall. appendingToArrayArgument (
47
57
label: " targets " ,
48
58
trailingLabels: Self . argumentLabelsAfterTargets,
49
59
newElement: target. asSyntax ( )
50
60
)
51
61
52
62
let outerDirectory : String ? = switch target. type {
53
- case . binary, . macro , . plugin, . system: nil
54
- case . executable, . regular: " Sources "
63
+ case . binary, . plugin, . system: nil
64
+ case . executable, . regular, . macro : " Sources "
55
65
case . test: " Tests "
56
66
}
57
67
58
68
guard let outerDirectory else {
59
69
return PackageEditResult ( manifestEdits: manifestEdits)
60
70
}
61
71
62
- let sourceFilePath = try RelativePath ( validating: outerDirectory)
63
- . appending ( components: [ target. name, " \( target. name) .swift " ] )
72
+ let outerPath = try RelativePath ( validating: outerDirectory)
73
+
74
+ /// The set of auxiliary files this refactoring will create.
75
+ var auxiliaryFiles : AuxiliaryFiles = [ ]
76
+
77
+ // Add the primary source file. Every target type has this.
78
+ addPrimarySourceFile (
79
+ outerPath: outerPath,
80
+ target: target,
81
+ to: & auxiliaryFiles
82
+ )
83
+
84
+ // Perform any other actions that are needed for this target type.
85
+ switch target. type {
86
+ case . macro:
87
+ // Macros need a file that introduces the main entrypoint
88
+ // describing all of the macros.
89
+ auxiliaryFiles. addSourceFile (
90
+ path: outerPath. appending (
91
+ components: [ target. name, " ProvidedMacros.swift " ]
92
+ ) ,
93
+ sourceCode: """
94
+ import SwiftCompilerPlugin
95
+
96
+ @main
97
+ struct \( raw: target. name) Macros: CompilerPlugin {
98
+ let providingMacros: [Macro.Type] = [
99
+ \( raw: target. name) .self,
100
+ ]
101
+ }
102
+ """
103
+ )
104
+
105
+ default : break ;
106
+ }
107
+
108
+ return PackageEditResult (
109
+ manifestEdits: manifestEdits,
110
+ auxiliaryFiles: auxiliaryFiles
111
+ )
112
+ }
113
+
114
+ /// Add the primary source file for a target to the list of auxiliary
115
+ /// source files.
116
+ fileprivate static func addPrimarySourceFile(
117
+ outerPath: RelativePath ,
118
+ target: TargetDescription ,
119
+ to auxiliaryFiles: inout AuxiliaryFiles
120
+ ) {
121
+ let sourceFilePath = outerPath. appending (
122
+ components: [ target. name, " \( target. name) .swift " ]
123
+ )
64
124
65
125
// Introduce imports for each of the dependencies that were specified.
66
126
var importModuleNames = target. dependencies. map {
@@ -83,9 +143,22 @@ public struct AddTarget {
83
143
}
84
144
85
145
let sourceFileText : SourceFileSyntax = switch target. type {
86
- case . binary, . macro , . plugin, . system:
146
+ case . binary, . plugin, . system:
87
147
fatalError ( " should have exited above " )
88
148
149
+ case . macro:
150
+ """
151
+ \( imports)
152
+ struct \( raw: target. name) : Macro {
153
+ /// TODO: Implement one or more of the protocols that inherit
154
+ /// from Macro. The appropriate macro protocol is determined
155
+ /// by the " macro " declaration that \( raw: target. name) implements.
156
+ /// Examples include:
157
+ /// @freestanding(expression) macro --> ExpressionMacro
158
+ /// @attached(member) macro --> MemberMacro
159
+ }
160
+ """
161
+
89
162
case . test:
90
163
"""
91
164
\( imports)
@@ -113,9 +186,9 @@ public struct AddTarget {
113
186
"""
114
187
}
115
188
116
- return PackageEditResult (
117
- manifestEdits : manifestEdits ,
118
- auxiliaryFiles : [ ( sourceFilePath , sourceFileText) ]
189
+ auxiliaryFiles . addSourceFile (
190
+ path : sourceFilePath ,
191
+ sourceCode : sourceFileText
119
192
)
120
193
}
121
194
}
@@ -131,3 +204,24 @@ fileprivate extension TargetDescription.Dependency {
131
204
}
132
205
}
133
206
}
207
+
208
+ /// The array of auxiliary files that can be added by a package editing
209
+ /// operation.
210
+ fileprivate typealias AuxiliaryFiles = [ ( RelativePath , SourceFileSyntax ) ]
211
+
212
+ fileprivate extension AuxiliaryFiles {
213
+ /// Add a source file to the list of auxiliary files.
214
+ mutating func addSourceFile(
215
+ path: RelativePath ,
216
+ sourceCode: SourceFileSyntax
217
+ ) {
218
+ self . append ( ( path, sourceCode) )
219
+ }
220
+ }
221
+
222
+ /// The set of dependencies we need to introduce to a newly-created macro
223
+ /// target.
224
+ fileprivate let macroTargetDependencies : [ TargetDescription . Dependency ] = [
225
+ . product( name: " SwiftCompilerPlugin " , package : " swift-syntax " ) ,
226
+ . product( name: " SwiftSyntaxMacros " , package : " swift-syntax " ) ,
227
+ ]
0 commit comments