Last active
January 31, 2023 00:43
-
-
Save cjnevin/c5df3714713fda300a58afe6b4527dcb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env swift | |
import Foundation | |
let script = CommandLine.arguments[1] | |
let fm = FileManager.default | |
enum Library: Hashable { | |
case core(String) | |
case service(String) | |
case ui(String) | |
var text: String { | |
switch self { | |
case .core(let text), .service(let text), .ui(let text): | |
return text | |
} | |
} | |
var path: String { | |
switch self { | |
case .core: return "/Core" | |
case .service: return "/Services" | |
case .ui: return "/UI" | |
} | |
} | |
var kind: String { | |
switch self { | |
case .core: return "Core" | |
case .service: return "Service" | |
case .ui: return "UI" | |
} | |
} | |
var textWithSuffix: String { | |
text + kind | |
} | |
var isCore: Bool { | |
switch self { | |
case .core: return true | |
default: return false | |
} | |
} | |
var isService: Bool { | |
switch self { | |
case .service: return true | |
default: return false | |
} | |
} | |
} | |
do { | |
let files = try fm.contentsOfDirectory(atPath: script) | |
let directory = URL(filePath: script) | |
let name = directory.lastPathComponent | |
let rootDirectory = directory.appending(path: "/Output") | |
let appDirectory = rootDirectory.appending(path: "/App/\(name)") | |
let outputDirectory = rootDirectory.appending(path: "/Features/\(name)") | |
let testDirectory = rootDirectory.appending(path: "/Tests/\(name)") | |
let coreDirectory = outputDirectory.appending(path: "/Core") | |
let servicesDirectory = outputDirectory.appending(path: "/Services") | |
let uiDirectory = outputDirectory.appending(path: "/UI") | |
try? fm.createDirectory(at: appDirectory, withIntermediateDirectories: true) | |
try? fm.createDirectory(at: coreDirectory, withIntermediateDirectories: true) | |
try? fm.createDirectory(at: servicesDirectory, withIntermediateDirectories: true) | |
try? fm.createDirectory(at: uiDirectory, withIntermediateDirectories: true) | |
try? fm.createDirectory(at: testDirectory, withIntermediateDirectories: true) | |
var libraries: [Library] = [] | |
for file in files { | |
let isUI = file.localizedStandardContains("ViewModel.swift") | |
|| file.localizedStandardContains("ViewController.swift") | |
|| file.localizedStandardContains("View.swift") | |
|| file.localizedStandardContains(".xcassets") | |
|| file.localizedStandardContains(".plist") | |
let isService = file.localizedStandardContains("Service.swift") | |
let isCoordinator = file.localizedStandardContains("Coordinator.swift") | |
let isSwift = file.localizedStandardContains(".swift") | |
let source = directory.appending(path: file) | |
if isUI { | |
try? fm.copyItem(at: source, to: uiDirectory.appending(path: file)) | |
libraries.append(.ui(name)) | |
} | |
else if isService { | |
try? fm.copyItem(at: source, to: servicesDirectory.appending(path: file)) | |
libraries.append(.service(name)) | |
} | |
else if isCoordinator { | |
try? fm.copyItem(at: source, to: appDirectory.appending(path: file)) | |
} | |
else if isSwift { | |
try? fm.copyItem(at: source, to: coreDirectory.appending(path: file)) | |
libraries.append(.core(name)) | |
} | |
else { | |
print("unhandled file \(file)") | |
} | |
} | |
print(libraries) | |
let filtered = Set(libraries).sorted(by: { $0.textWithSuffix < $1.textWithSuffix }) | |
let packageText = filtered.map { | |
".library(name: \"\($0.textWithSuffix)\", targets: [\"\($0.textWithSuffix)\"])," | |
}.joined(separator: "\n ") | |
let targetText = filtered.map { | |
".target(name: \"\($0.textWithSuffix)\", dependencies: [\($0.dependencies(in: libraries))], path: \"Features/\(outputDirectory.lastPathComponent)\($0.path)\")," | |
}.joined(separator: "\n ") | |
let testTarget = filtered.map { | |
".testTarget(name: \"\($0.textWithSuffix)Tests\", dependencies: [\"\($0.textWithSuffix)\"], path: \"Tests/\(testDirectory.lastPathComponent)/\($0.kind)Tests\")," | |
}.joined(separator: "\n ") | |
let text = """ | |
// swift-tools-version: 5.7 | |
// The swift-tools-version declares the minimum version of Swift required to build this package. | |
import PackageDescription | |
let package = Package( | |
name: \(name), | |
products: [ | |
// Products define the executables and libraries a package produces, and make them visible to other packages. | |
\(packageText) | |
], | |
dependencies: [], | |
targets: [ | |
// Targets are the basic building blocks of a package. A target can define a module or a test suite. | |
// Targets can depend on other targets in this package, and on products in packages this package depends on. | |
\(targetText) | |
\(testTarget) | |
] | |
) | |
""" | |
fm.createFile(atPath: rootDirectory.appending(path: "/Package.txt").relativePath, contents: text.data(using: .utf8)) | |
} | |
catch { | |
print("failed to read directory") | |
} | |
extension Library { | |
func dependencies(in other: [Library]) -> String { | |
switch self { | |
case .core: return "" | |
case .service: | |
return other.filter(\.isCore).map(\.textWithSuffix).map { "\"\($0)\"" }.joined(separator: ", ") | |
case .ui: | |
return other.filter(\.isService).map(\.textWithSuffix).map { "\"\($0)\"" }.joined(separator: ", ") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
./main.swift ../Example