mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-15 12:07:42 +00:00
Some checks are pending
Keyman Build Summary / Summarize build status checks (push) Waiting to run
define errors for parsing issues and data validation handle errors during loading of data at launch
166 lines
3.4 KiB
Swift
166 lines
3.4 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 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?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case readmeFile
|
|
case graphicFile
|
|
}
|
|
}
|
|
|
|
struct PackageFile: Decodable {
|
|
let name: String?
|
|
let description: String?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case name
|
|
case description
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|