mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-26 01:27:42 +00:00
If the help file (welcome.htm) and readme file (readme.htm) are not listed in the options element of the kmp.json, check the file list. Read them from the package using their default filenames if they are found there.
185 lines
3.9 KiB
Swift
185 lines
3.9 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
|
|
|
|
let defaultHelpFilename = "welcome.htm"
|
|
let defaultReadmeFilename = "readme.htm"
|
|
|
|
public struct PackageSource: Identifiable, Decodable, Hashable, Equatable {
|
|
public var id = UUID()
|
|
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
|
|
}
|
|
if let fileArray = self.files {
|
|
if fileArray.contains(where: { $0.name == defaultReadmeFilename }) {
|
|
return defaultReadmeFilename
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
var helpFilename: String? {
|
|
if let filename = options?.welcomeFile {
|
|
return filename
|
|
}
|
|
if let fileArray = self.files {
|
|
if fileArray.contains(where: { $0.name == defaultHelpFilename }) {
|
|
return defaultHelpFilename
|
|
}
|
|
}
|
|
|
|
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)
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|