mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-11 19:35:32 +00:00
177 lines
3.7 KiB
Swift
177 lines
3.7 KiB
Swift
/*
|
|
* Keyman is copyright (C) SIL Global. MIT License.
|
|
*
|
|
* Created by Shawn Schantz on 2025-12-19
|
|
*
|
|
* Value object for loading a package from kmp.json
|
|
*
|
|
*/
|
|
|
|
|
|
import Foundation
|
|
|
|
public struct PackageSource: Identifiable, Decodable, Hashable, Equatable {
|
|
public var id = UUID()
|
|
var directoryUrl: URL?
|
|
var kmpJsonFileUrl: URL?
|
|
let system: SystemInfo?
|
|
let options: Options?
|
|
let info: Info
|
|
let files: [PackageFile]?
|
|
let keyboards: [KeyboardSource]?
|
|
|
|
// computed properties for convenience
|
|
var packageName: String {
|
|
return info.name.description
|
|
}
|
|
var packageVersion: String {
|
|
return info.version.description
|
|
}
|
|
var copyright: String? {
|
|
if let copy = info.copyright?.description {
|
|
return copy
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
var readmeFilename: String? {
|
|
if let filename = options?.readmeFile {
|
|
return filename
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
var helpFilename: String? {
|
|
if let filename = options?.welcomeFile {
|
|
return filename
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
var graphicFilename: String? {
|
|
if let filename = options?.graphicFile {
|
|
return filename
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case system
|
|
case options
|
|
case info
|
|
case files
|
|
case keyboards
|
|
}
|
|
|
|
public init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
directoryUrl = nil
|
|
kmpJsonFileUrl = nil
|
|
|
|
self.info = try container.decode(Info.self, forKey: .info)
|
|
self.keyboards = try container.decodeIfPresent([KeyboardSource].self, forKey: .keyboards)
|
|
self.system = try container.decodeIfPresent(SystemInfo.self, forKey: .system)
|
|
self.options = try container.decodeIfPresent(Options.self, forKey: .options)
|
|
self.files = try container.decodeIfPresent([PackageFile].self, forKey: .files)
|
|
|
|
if files?.isEmpty ?? true {
|
|
throw LoadPackageError.containsNoFiles
|
|
}
|
|
|
|
if keyboards?.isEmpty ?? true {
|
|
throw LoadPackageError.containsNoKeyboards
|
|
}
|
|
}
|
|
|
|
public func hash(into hasher: inout Hasher) {
|
|
hasher.combine(id) // only combine the unique ID
|
|
}
|
|
|
|
// Custom Equatable conformance (required by Hashable)
|
|
public static func == (lhs: PackageSource, rhs: PackageSource) -> Bool {
|
|
return lhs.id == rhs.id // only compare unique IDs
|
|
}
|
|
}
|
|
|
|
struct Info: Decodable {
|
|
let name: DescribedValue
|
|
let version: DescribedValue
|
|
let copyright: DescribedValue?
|
|
let author: Author?
|
|
let website: Website?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case name
|
|
case copyright
|
|
case author
|
|
case version
|
|
case website
|
|
}
|
|
}
|
|
|
|
struct DescribedValue: Decodable {
|
|
let description: String
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case description
|
|
}
|
|
}
|
|
|
|
struct Author: Decodable {
|
|
let description: String?
|
|
let url: String?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case description
|
|
case url
|
|
}
|
|
}
|
|
|
|
struct Website: Decodable {
|
|
let description: String?
|
|
let url: String?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case description
|
|
case url
|
|
}
|
|
}
|
|
|
|
struct SystemInfo: Decodable {
|
|
let keymanDeveloperVersion: String?
|
|
let fileVersion: String?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case keymanDeveloperVersion
|
|
case fileVersion
|
|
}
|
|
}
|
|
|
|
struct Options: Decodable {
|
|
let readmeFile: String?
|
|
let graphicFile: String?
|
|
let licenseFile: String?
|
|
let welcomeFile: String?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case readmeFile
|
|
case graphicFile
|
|
case licenseFile
|
|
case welcomeFile
|
|
}
|
|
}
|
|
|
|
struct PackageFile: Decodable {
|
|
let name: String?
|
|
let description: String?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case name
|
|
case description
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|