@@ -15,6 +15,7 @@ import PackageModel
15
15
import SwiftParser
16
16
import SwiftSyntax
17
17
import SwiftSyntaxBuilder
18
+ import struct TSCUtility. Version
18
19
19
20
/// Add a target to a manifest's source code.
20
21
public struct AddTarget {
@@ -34,7 +35,8 @@ public struct AddTarget {
34
35
/// new target.
35
36
public static func addTarget(
36
37
_ target: TargetDescription ,
37
- to manifest: SourceFileSyntax
38
+ to manifest: SourceFileSyntax ,
39
+ installedSwiftPMConfiguration: InstalledSwiftPMConfiguration = . default
38
40
) throws -> PackageEditResult {
39
41
// Make sure we have a suitable tools version in the manifest.
40
42
try manifest. checkEditManifestToolsVersion ( )
@@ -53,7 +55,7 @@ public struct AddTarget {
53
55
target. dependencies. append ( contentsOf: macroTargetDependencies)
54
56
}
55
57
56
- let manifestEdits = try packageCall. appendingToArrayArgument (
58
+ var newPackageCall = try packageCall. appendingToArrayArgument (
57
59
label: " targets " ,
58
60
trailingLabels: Self . argumentLabelsAfterTargets,
59
61
newElement: target. asSyntax ( )
@@ -66,7 +68,11 @@ public struct AddTarget {
66
68
}
67
69
68
70
guard let outerDirectory else {
69
- return PackageEditResult ( manifestEdits: manifestEdits)
71
+ return PackageEditResult (
72
+ manifestEdits: [
73
+ . replace( packageCall, with: newPackageCall. description)
74
+ ]
75
+ )
70
76
}
71
77
72
78
let outerPath = try RelativePath ( validating: outerDirectory)
@@ -82,31 +88,49 @@ public struct AddTarget {
82
88
)
83
89
84
90
// Perform any other actions that are needed for this target type.
91
+ var extraManifestEdits : [ SourceEdit ] = [ ]
85
92
switch target. type {
86
93
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
- """
94
+ addProvidedMacrosSourceFile (
95
+ outerPath: outerPath,
96
+ target: target,
97
+ to: & auxiliaryFiles
103
98
)
104
99
100
+ if !manifest. description. contains ( " swift-syntax " ) {
101
+ newPackageCall = try AddPackageDependency
102
+ . addPackageDependencyLocal (
103
+ . swiftSyntax(
104
+ configuration: installedSwiftPMConfiguration
105
+ ) ,
106
+ to: newPackageCall
107
+ )
108
+
109
+ // Look for the first import declaration and insert an
110
+ // import of `CompilerPluginSupport` there.
111
+ let newImport = " import CompilerPluginSupport \n "
112
+ for node in manifest. statements {
113
+ if let importDecl = node. item. as ( ImportDeclSyntax . self) {
114
+ let insertPos = importDecl
115
+ . positionAfterSkippingLeadingTrivia
116
+ extraManifestEdits. append (
117
+ SourceEdit (
118
+ range: insertPos..< insertPos,
119
+ replacement: newImport
120
+ )
121
+ )
122
+ break
123
+ }
124
+ }
125
+ }
126
+
105
127
default : break ;
106
128
}
107
129
108
130
return PackageEditResult (
109
- manifestEdits: manifestEdits,
131
+ manifestEdits: [
132
+ . replace( packageCall, with: newPackageCall. description)
133
+ ] + extraManifestEdits,
110
134
auxiliaryFiles: auxiliaryFiles
111
135
)
112
136
}
@@ -191,6 +215,30 @@ public struct AddTarget {
191
215
sourceCode: sourceFileText
192
216
)
193
217
}
218
+
219
+ /// Add a file that introduces the main entrypoint and provided macros
220
+ /// for a macro target.
221
+ fileprivate static func addProvidedMacrosSourceFile(
222
+ outerPath: RelativePath ,
223
+ target: TargetDescription ,
224
+ to auxiliaryFiles: inout AuxiliaryFiles
225
+ ) {
226
+ auxiliaryFiles. addSourceFile (
227
+ path: outerPath. appending (
228
+ components: [ target. name, " ProvidedMacros.swift " ]
229
+ ) ,
230
+ sourceCode: """
231
+ import SwiftCompilerPlugin
232
+
233
+ @main
234
+ struct \( raw: target. name) Macros: CompilerPlugin {
235
+ let providingMacros: [Macro.Type] = [
236
+ \( raw: target. name) .self,
237
+ ]
238
+ }
239
+ """
240
+ )
241
+ }
194
242
}
195
243
196
244
fileprivate extension TargetDescription . Dependency {
@@ -225,3 +273,28 @@ fileprivate let macroTargetDependencies: [TargetDescription.Dependency] = [
225
273
. product( name: " SwiftCompilerPlugin " , package : " swift-syntax " ) ,
226
274
. product( name: " SwiftSyntaxMacros " , package : " swift-syntax " ) ,
227
275
]
276
+
277
+ /// The package dependency for swift-syntax, for use in macros.
278
+ fileprivate extension PackageDependency {
279
+ /// Source control URL for the swift-syntax package.
280
+ static var swiftSyntaxURL : SourceControlURL {
281
+ " https://github.com/apple/swift-syntax.git "
282
+ }
283
+
284
+ /// Package dependency on the swift-syntax package.
285
+ static func swiftSyntax(
286
+ configuration: InstalledSwiftPMConfiguration
287
+ ) -> PackageDependency {
288
+ let swiftSyntaxVersionDefault = configuration
289
+ . swiftSyntaxVersionForMacroTemplate
290
+ let swiftSyntaxVersion = Version ( swiftSyntaxVersionDefault. description) !
291
+
292
+ return . sourceControl(
293
+ identity: PackageIdentity ( url: swiftSyntaxURL) ,
294
+ nameForTargetDependencyResolutionOnly: nil ,
295
+ location: . remote( swiftSyntaxURL) ,
296
+ requirement: . range( . upToNextMajor( from: swiftSyntaxVersion) ) ,
297
+ productFilter: . everything
298
+ )
299
+ }
300
+ }
0 commit comments