Files
2022-07-30 20:47:39 +02:00

93 lines
3.1 KiB
Swift

//
// SwiftGenKit
// Copyright © 2022 SwiftGen
// MIT Licence
//
import Foundation
import Kanna
import PathKit
public enum CoreData {
public enum ParserError: Error, CustomStringConvertible {
case invalidFile(path: Path, reason: String)
case invalidFormat(reason: String)
public var description: String {
switch self {
case .invalidFile(let path, let reason):
return "error: Unable to parse file at \(path). \(reason)"
case .invalidFormat(let reason):
return "error: Invalid format. \(reason)"
}
}
}
private enum Constants {
static let modelExtension = "xcdatamodel"
static let modelBundleExtension = "xcdatamodeld"
static let currentVersionFile = ".xccurrentversion"
static let currentVersionKey = "_XCCurrentVersionName"
static let contentsFile = "contents"
}
public final class Parser: SwiftGenKit.Parser {
var models: [Model] = []
private let options: ParserOptionValues
public var warningHandler: Parser.MessageHandler?
public init(options: [String: Any] = [:], warningHandler: Parser.MessageHandler? = nil) throws {
self.options = try ParserOptionValues(options: options, available: Self.allOptions)
self.warningHandler = warningHandler
}
public static let defaultFilter = filterRegex(forExtensions: ["xcdatamodel", "xcdatamodeld"])
public static let filterOptions: Filter.Options = [.skipsHiddenFiles, .skipsPackageDescendants]
public func parse(path: Path, relativeTo parent: Path) throws {
if path.extension == Constants.modelBundleExtension {
guard let modelPath = findCurrentModel(path: path) else {
throw ParserError.invalidFile(path: path, reason: "Current version of Core Data model could not be found.")
}
try parse(path: modelPath, relativeTo: parent)
} else if path.extension == Constants.modelExtension {
try addModel(path: path)
} else {
throw ParserError.invalidFormat(reason: "Unknown file type for \(path)")
}
}
private func findCurrentModel(path: Path) -> Path? {
let currentVersionPath = path + Constants.currentVersionFile
if currentVersionPath.exists {
guard let currentVersionDictionary = NSDictionary(contentsOf: currentVersionPath.url) else {
return nil
}
guard let currentVersionModelFilename = currentVersionDictionary[Constants.currentVersionKey] as? String else {
return nil
}
return path + Path(currentVersionModelFilename)
} else {
return path.first { $0.extension == Constants.modelExtension }
}
}
private func addModel(path: Path) throws {
let contentsPath = path + Constants.contentsFile
guard contentsPath.exists else {
throw ParserError.invalidFormat(reason: "Only models in Xcode 4.0+ format are supported")
}
do {
let document = try Kanna.XML(xml: contentsPath.read(), encoding: .utf8)
let model = try Model(with: document)
models.append(model)
} catch {
throw ParserError.invalidFile(path: path, reason: "XML parser error: \(error).")
}
}
}
}