174 lines
6.1 KiB
Swift
174 lines
6.1 KiB
Swift
//
|
|
// source.swift
|
|
// gen_html
|
|
//
|
|
// Created by Isaac Paul on 9/30/25.
|
|
//
|
|
|
|
import Foundation
|
|
import PackagePlugin
|
|
|
|
final class AppError: LocalizedError, Sendable {
|
|
|
|
let message: String
|
|
|
|
init(_ message: String) {
|
|
self.message = message
|
|
}
|
|
init(_ message: String, _ error:Error) {
|
|
self.message = "\(message) : \(error.localizedDescription)"
|
|
}
|
|
|
|
static func failure<T>(_ message: String) -> Result<T, AppError> {
|
|
return .failure(AppError(message))
|
|
}
|
|
|
|
var errorDescription: String? {
|
|
get {
|
|
return message
|
|
}
|
|
}
|
|
|
|
var failureReason: String? { get { return message } }
|
|
}
|
|
|
|
let toolName = "BindingGenerator"
|
|
|
|
extension BindingPlugin: BuildToolPlugin {
|
|
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
|
|
guard let swiftTarget = target as? SwiftSourceModuleTarget else {
|
|
print("Unexpected target: \(type(of: target)). Needs SwiftSourceModuleTarget")
|
|
throw AppError("Unexpected target: \(type(of: target)). Needs SwiftSourceModuleTarget")
|
|
}
|
|
let toolUrl = try context.tool(named: toolName).url
|
|
|
|
return try createBuildCommands(
|
|
outputDir: context.pluginWorkDirectoryURL,
|
|
inputDir: swiftTarget.directoryURL,
|
|
inputFiles: swiftTarget.sourceFiles,
|
|
toolExe: toolUrl
|
|
)
|
|
}
|
|
}
|
|
|
|
#if canImport(XcodeProjectPlugin)
|
|
|
|
import XcodeProjectPlugin
|
|
import System
|
|
|
|
// The entry point for Xcode project builds.
|
|
extension BindingPlugin: XcodeBuildToolPlugin {
|
|
func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {
|
|
let toolUrl = try context.tool(named: toolName).url
|
|
return try createBuildCommands(
|
|
outputDir: context.pluginWorkDirectoryURL,
|
|
inputDir: context.xcodeProject.directoryURL,
|
|
inputFiles: target.inputFiles,
|
|
toolExe: toolUrl
|
|
)
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
struct Config: Codable {
|
|
var root_path: String?
|
|
}
|
|
|
|
extension URL {
|
|
func isHtml() -> Bool {
|
|
return self.pathExtension == "html" || self.pathExtension == "htm"
|
|
}
|
|
}
|
|
|
|
extension String {
|
|
func uppercaseFirstLetter() -> String {
|
|
guard let firstLetter = self.first else { return self }
|
|
return firstLetter.uppercased() + self.dropFirst()
|
|
}
|
|
}
|
|
|
|
@main
|
|
struct BindingPlugin {
|
|
|
|
private static let configFile = "binding_generator_plugin.json"
|
|
|
|
private func createBuildCommands(
|
|
outputDir: URL,
|
|
inputDir: URL,
|
|
inputFiles: FileList,
|
|
toolExe: URL
|
|
) throws -> [Command] {
|
|
|
|
let configFilePath = inputFiles.first(where: { $0.url.lastPathComponent == BindingPlugin.configFile })
|
|
let configFileURL = configFilePath?.url
|
|
|
|
//let listSearchDir: [String]
|
|
let htmlFiles = inputFiles.filter { $0.url.isHtml() }.map { $0.url }
|
|
let rootPath:URL
|
|
|
|
if let configFileURL = configFileURL {
|
|
|
|
let configData = try Data(contentsOf: configFileURL)
|
|
let config = try JSONDecoder().decode(Config.self, from: configData)
|
|
|
|
let baseDirectory:URL = configFileURL.deletingLastPathComponent()
|
|
if let configRootPath = config.root_path {
|
|
rootPath = baseDirectory.appending(path: configRootPath)
|
|
} else {
|
|
rootPath = inputDir
|
|
}
|
|
/*
|
|
for source in config.sources ?? [] {
|
|
let sourceFileOrDirectory = baseDirectory.appendingPathComponent(source)
|
|
if sourceFileOrDirectory.isHtml() {
|
|
htmlFiles.append(sourceFileOrDirectory)
|
|
} else {
|
|
let files = try FileManager.default.contentsOfDirectory(
|
|
at: sourceFileOrDirectory,
|
|
includingPropertiesForKeys: nil
|
|
)
|
|
let filteredFiles = files.filter { $0.isHtml() }
|
|
htmlFiles.append(contentsOf: filteredFiles)
|
|
}
|
|
}*/
|
|
|
|
} else {
|
|
rootPath = inputDir
|
|
}
|
|
/*
|
|
/Users/isaacpaul/Projects/swift-projects/HRW/Plugins/BindingPlugin/source.swift:146:13: error: 'let' cannot appear nested inside another 'var' or 'let' pattern
|
|
<unknown>:0: error: error opening input file '/Users/isaacpaul/Library/Developer/Xcode/DerivedData/HRW-bicwrilrmihgqogjvxyqtcosfaro/Build/Intermediates.noindex/BuildToolPluginIntermediates/hrw.output/HRWTests/BindingPlugin/Example.swift' (No such file or directory)
|
|
//
|
|
Showing All Messages
|
|
Error opening input file '/Users/isaacpaul/Library/Developer/Xcode/DerivedData/HRW-bicwrilrmihgqogjvxyqtcosfaro/Build/Intermediates.noindex/BuildToolPluginIntermediates/hrw.output/HRWTests/BindingPlugin/ExampleBinding.swift' (No such file or directory)
|
|
*/
|
|
return htmlFiles.map { eachFile in
|
|
let fileName = eachFile.lastPathComponent
|
|
let ext = eachFile.pathExtension
|
|
let extIndex = fileName.index(fileName.startIndex, offsetBy: fileName.count - (ext.count + 1))
|
|
let withoutExt = String(fileName[fileName.startIndex..<extIndex])
|
|
let targetFileName = "\(withoutExt.uppercaseFirstLetter()).swift"
|
|
|
|
let rootFP = FilePath(rootPath.path)
|
|
var inputFP = FilePath(eachFile.path)
|
|
let outputDirFP = FilePath(outputDir.path)
|
|
|
|
let _ = inputFP.removePrefix(rootFP)
|
|
inputFP.removeLastComponent()
|
|
//let idk = outputDirFP.pushing(inputFP)
|
|
let outputFileA = outputDir.appendingPathComponent(inputFP.string)
|
|
let outputFile = outputFileA.appendingPathComponent(targetFileName)
|
|
print("Expected path: \(outputFile.path)")
|
|
|
|
return .buildCommand(
|
|
displayName: "Generating binding to \(outputFile.path)",
|
|
executable: toolExe,
|
|
arguments: ["-o", outputDir.path, "-i", eachFile.path, "-b", rootPath.path],
|
|
inputFiles: [eachFile],
|
|
outputFiles: [URL(fileURLWithPath: outputFile.path)]
|
|
)
|
|
}
|
|
}
|
|
}
|