Moved BindingGenerator from gen html project. It makes more sense here.
This commit is contained in:
173
Plugins/BindingPlugin/source.swift
Normal file
173
Plugins/BindingPlugin/source.swift
Normal file
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// 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)]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user