@@ -6,26 +6,38 @@ struct PackageToJS: CommandPlugin {
66 struct Options {
77 /// Product to build (default: executable target if there's only one)
88 var product : String ?
9+ /// Path to the output directory
10+ var outputPath : String ?
911 /// Name of the package (default: lowercased Package.swift name)
1012 var packageName : String ?
1113 /// Whether to explain the build plan
1214 var explain : Bool = false
1315
1416 static func parse( from extractor: inout ArgumentExtractor ) -> Options {
1517 let product = extractor. extractOption ( named: " product " ) . last
18+ let outputPath = extractor. extractOption ( named: " output " ) . last
1619 let packageName = extractor. extractOption ( named: " package-name " ) . last
1720 let explain = extractor. extractFlag ( named: " explain " )
18- return Options ( product: product, packageName: packageName, explain: explain != 0 )
21+ return Options (
22+ product: product, outputPath: outputPath, packageName: packageName,
23+ explain: explain != 0
24+ )
1925 }
2026
2127 static func help( ) -> String {
2228 return """
23- Usage: swift package --swift-sdk <swift-sdk> plugin run PackageToJS [options]
29+ Usage: swift package --swift-sdk <swift-sdk> [swift-package options] plugin run PackageToJS [options]
2430
2531 Options:
26- --product <product> Product to build (default: executable target if there's only one)
27- --package-name <name> Name of the package (default: lowercased Package.swift name)
28- --explain Whether to explain the build plan
32+ --product <product> Product to build (default: executable target if there's only one)
33+ --output <path> Path to the output directory (default: .build/plugins/PackageToJS/outputs/Package)
34+ --package-name <name> Name of the package (default: lowercased Package.swift name)
35+ --explain Whether to explain the build plan
36+
37+ Examples:
38+ $ swift package --swift-sdk wasm32-unknown-wasi plugin js
39+ $ swift package --swift-sdk wasm32-unknown-wasi plugin js --product Example
40+ $ swift package --swift-sdk wasm32-unknown-wasi -c release plugin js
2941 """
3042 }
3143 }
@@ -74,26 +86,38 @@ struct PackageToJS: CommandPlugin {
7486
7587 func performCommand( context: PluginContext , arguments: [ String ] ) throws {
7688 if arguments. contains ( where: { [ " -h " , " --help " ] . contains ( $0) } ) {
77- print ( Options . help ( ) )
89+ printStderr ( Options . help ( ) )
7890 return
7991 }
8092
8193 var extractor = ArgumentExtractor ( arguments)
8294 let options = Options . parse ( from: & extractor)
8395
96+ if extractor. remainingArguments. count > 0 {
97+ printStderr (
98+ " Unexpected arguments: \( extractor. remainingArguments. joined ( separator: " " ) ) " )
99+ printStderr ( Options . help ( ) )
100+ exit ( 1 )
101+ }
102+
84103 // Build products
85104 let ( build, productName) = try buildWasm ( options: options, context: context)
86105 guard build. succeeded else {
87106 for diagnostic in Self . friendlyBuildDiagnostics {
88107 if let message = diagnostic ( build, arguments) {
89- fputs ( " \n " + message + " \n " , stderr )
108+ printStderr ( " \n " + message)
90109 }
91110 }
92111 exit ( 1 )
93112 }
94113
95114 let productArtifact = try build. findWasmArtifact ( for: productName)
96- let outputDir = context. pluginWorkDirectory. appending ( subpath: " Package " )
115+ let outputDir =
116+ if let outputPath = options. outputPath {
117+ URL ( fileURLWithPath: outputPath)
118+ } else {
119+ context. pluginWorkDirectoryURL. appending ( path: " Package " )
120+ }
97121 guard
98122 let selfPackage = findPackageInDependencies (
99123 package : context. package , id: " javascriptkit " )
@@ -128,7 +152,9 @@ struct PackageToJS: CommandPlugin {
128152 parameters. otherSwiftcFlags = [
129153 " -static-stdlib " , " -Xclang-linker " , " -mexec-model=reactor " ,
130154 ]
131- parameters. otherLinkerFlags = [ " --export-if-defined=__main_argc_argv " ]
155+ parameters. otherLinkerFlags = [
156+ " --export-if-defined=__main_argc_argv "
157+ ]
132158 }
133159 let productName = try options. product ?? deriveDefaultProduct ( package : context. package )
134160 let build = try self . packageManager. build ( . product( productName) , parameters: parameters)
@@ -142,14 +168,14 @@ struct PackageToJS: CommandPlugin {
142168 context: PluginContext ,
143169 wasmProductArtifact: PackageManager . BuildResult . BuiltArtifact ,
144170 selfPackage: Package ,
145- outputDir: Path
171+ outputDir: URL
146172 ) -> MiniMake . TaskKey {
147- let selfPackageURL = selfPackage. directory
173+ let selfPackageURL = selfPackage. directoryURL
148174 let selfPath = String ( #filePath)
149175
150176 // Prepare output directory
151177 let outputDirTask = make. addTask (
152- inputFiles: [ selfPath] , output: outputDir. string , attributes: [ . silent]
178+ inputFiles: [ selfPath] , output: outputDir. path , attributes: [ . silent]
153179 ) {
154180 guard !FileManager. default. fileExists ( atPath: $0. output) else { return }
155181 try FileManager . default. createDirectory (
@@ -169,7 +195,7 @@ struct PackageToJS: CommandPlugin {
169195 let wasmFilename = " main.wasm "
170196 let wasm = make. addTask (
171197 inputFiles: [ selfPath, wasmProductArtifact. path. string] , inputTasks: [ outputDirTask] ,
172- output: outputDir. appending ( subpath : wasmFilename) . string
198+ output: outputDir. appending ( path : wasmFilename) . path
173199 ) {
174200 try syncFile ( from: wasmProductArtifact. path. string, to: $0. output)
175201 }
@@ -178,7 +204,7 @@ struct PackageToJS: CommandPlugin {
178204 // Write package.json
179205 let packageJSON = make. addTask (
180206 inputFiles: [ selfPath] , inputTasks: [ outputDirTask] ,
181- output: outputDir. appending ( subpath : " package.json " ) . string
207+ output: outputDir. appending ( path : " package.json " ) . path
182208 ) {
183209 let packageJSON = """
184210 {
@@ -207,12 +233,12 @@ struct PackageToJS: CommandPlugin {
207233 ( " Plugins/PackageToJS/Templates/index.d.ts " , " index.d.ts " ) ,
208234 ( " Sources/JavaScriptKit/Runtime/index.mjs " , " runtime.js " ) ,
209235 ] {
210- let inputPath = selfPackageURL. appending ( subpath : file) . string
236+ let inputPath = selfPackageURL. appending ( path : file)
211237 let copied = make. addTask (
212- inputFiles: [ selfPath, inputPath] , inputTasks: [ outputDirTask] ,
213- output: outputDir. appending ( subpath : output) . string
238+ inputFiles: [ selfPath, inputPath. path ] , inputTasks: [ outputDirTask] ,
239+ output: outputDir. appending ( path : output) . path
214240 ) {
215- var content = try String ( contentsOfFile : inputPath)
241+ var content = try String ( contentsOf : inputPath)
216242 for (key, value) in substitutions {
217243 content = content. replacingOccurrences ( of: key, with: value)
218244 }
@@ -306,6 +332,10 @@ private func findPackageInDependencies(package: Package, id: Package.ID) -> Pack
306332 return visit ( package : package )
307333}
308334
335+ private func printStderr( _ message: String ) {
336+ fputs ( message + " \n " , stderr)
337+ }
338+
309339private struct PackageToJSError : Swift . Error , CustomStringConvertible {
310340 let description : String
311341
0 commit comments