如何用Swift命令行工具程序化生成含指定代码的Swift文件集
Absolutely! Swift is perfectly suited for building command-line tools that programmatically generate Swift files—this is a common use case for boilerplate generators, code scaffolding tools, and more. Let’s break down how to build this, with a complete example and practical tips.
Step 1: Set Up Your Project
First, create a new Swift command-line executable project using Swift Package Manager:
swift package init --type executable
This will set up a basic project structure with a main.swift file where we’ll write our code.
Step 2: Full Working Example Code
Replace the contents of main.swift with this code. It handles command-line arguments, creates output directories, and generates Swift files from a template:
import Foundation // Holds our generation settings parsed from command-line args struct GenerationConfig { let numberOfFiles: Int let outputDirectory: URL let templateContent: String } // Parse command-line arguments into a usable config func parseCommandLineArguments() -> GenerationConfig? { let args = CommandLine.arguments // Expected usage: ./FileGenerator --count 5 --output ./GeneratedFiles --template "class {{className}} { func doSomething() {} }" guard args.count == 7, args[1] == "--count", let fileCount = Int(args[2]), fileCount > 0, args[3] == "--output", args[5] == "--template" else { print("❌ Invalid arguments!") print("Usage: \(args[0]) --count <positive-number> --output <directory-path> --template <code-template>") print("Tip: Use {{className}} in your template as a placeholder for the generated class name") return nil } let outputDirURL = URL(filePath: args[4], directoryHint: .isDirectory) return GenerationConfig( numberOfFiles: fileCount, outputDirectory: outputDirURL, templateContent: args[6] ) } // Generate and write the Swift files func generateFiles(with config: GenerationConfig) throws { // Create output directory if it doesn't exist (including parent folders) try FileManager.default.createDirectory( at: config.outputDirectory, withIntermediateDirectories: true, attributes: nil ) for fileIndex in 1...config.numberOfFiles { // Replace placeholders in the template let className = "GeneratedClass\(fileIndex)" let finalCode = config.templateContent.replacingOccurrences( of: "{{className}}", with: className ) // Define the file path let fileURL = config.outputDirectory.appending(path: "\(className).swift") // Write the code to the file try finalCode.write( to: fileURL, atomically: true, encoding: .utf8 ) print("✅ Generated: \(fileURL.path)") } } // Run the tool do { guard let config = parseCommandLineArguments() else { exit(1) } try generateFiles(with: config) print("\n🎉 All files generated successfully!") } catch { print("\n❌ Error: \(error.localizedDescription)") exit(1) }
Step 3: Compile and Run the Tool
- Compile the project:
swift build - Run the tool (replace the example values with your own):
.build/debug/FileGenerator --count 3 --output ./MyGeneratedFiles --template "class {{className}} { let identifier = \"{{className}}_id\"; func performTask() { print(\"Running task for {{className}}\") } }"
This will generate 3 Swift files in the MyGeneratedFiles directory, each with a unique class name replacing the {{className}} placeholder.
Practical Tips & Best Practices
- Use a Proper Argument Parser: For more complex tools, use Apple’s official
ArgumentParserlibrary to simplify argument parsing (no more manual string checks!). Add it as a dependency in yourPackage.swift, then define your arguments with property wrappers like@Argumentand@Option. - Leverage Template Engines: For advanced templates (conditionals, loops), use libraries like
Stencil—it’s designed for Swift and makes complex code generation much cleaner. - Validate & Sanitize Input: Add checks for things like:
- Ensuring the output directory is writable
- Overwriting existing files only with user confirmation
- Sanitizing class names to avoid invalid Swift identifiers
- Format Generated Code: Automatically format your generated files with
swift formatby adding a process call after writing the file:let formatProcess = Process() formatProcess.executableURL = URL(filePath: "/usr/bin/swift") formatProcess.arguments = ["format", "--in-place", fileURL.path] try formatProcess.run() formatProcess.waitUntilExit() - Add Logging: For larger tools, consider using a logging library (or even simple print statements with different levels) to keep track of what’s happening during generation.
内容的提问来源于stack exchange,提问作者Sarwesh reddy

