diff --git a/Mist/Extensions/ButtonStyle+Extension.swift b/Mist/Extensions/ButtonStyle+Extension.swift index 069f2dd..6c50f46 100644 --- a/Mist/Extensions/ButtonStyle+Extension.swift +++ b/Mist/Extensions/ButtonStyle+Extension.swift @@ -8,6 +8,7 @@ import SwiftUI extension ButtonStyle where Self == MistActionButtonStyle { + /// Action button style static var mistAction: Self { .init() } diff --git a/Mist/Extensions/Dictionary+Extension.swift b/Mist/Extensions/Dictionary+Extension.swift index d4dd8d1..8f31a69 100644 --- a/Mist/Extensions/Dictionary+Extension.swift +++ b/Mist/Extensions/Dictionary+Extension.swift @@ -6,6 +6,9 @@ // extension Dictionary where Key == String { + /// Provides a firmware CSV string representation. + /// + /// - Returns: A firmware CSV string representation. func firmwareCSVString() -> String { guard let name: String = self["name"] as? String, @@ -44,6 +47,9 @@ extension Dictionary where Key == String { return string } + /// Provides an installer CSV string representation. + /// + /// - Returns: An installer CSV string representation. func installerCSVString() -> String { guard let identifier: String = self["identifier"] as? String, diff --git a/Mist/Extensions/Double+Extension.swift b/Mist/Extensions/Double+Extension.swift index aaef4c0..cf3ec30 100644 --- a/Mist/Extensions/Double+Extension.swift +++ b/Mist/Extensions/Double+Extension.swift @@ -15,6 +15,9 @@ extension Double { /// gigabytes constant static let gigabyte: Double = .megabyte * 1_000 + /// Pretty formatted string representation of the double, as bytes. + /// + /// - Returns: A pretty formatted bytes string. func bytesString() -> String { if self < .kilobyte { "\(Int(self)) bytes" diff --git a/Mist/Extensions/FileManager+Extension.swift b/Mist/Extensions/FileManager+Extension.swift index cd317e6..4fb8448 100644 --- a/Mist/Extensions/FileManager+Extension.swift +++ b/Mist/Extensions/FileManager+Extension.swift @@ -8,6 +8,14 @@ import Foundation extension FileManager { + /// Provides the size of a specified directory, in bytes. + /// + /// - Parameters: + /// - url: The URL of the directory to query. + /// + /// - Throws: An `Error` if the directory size is unable to be determined. + /// + /// - Returns: The size of the directory in bytes. func sizeOfDirectory(at url: URL) throws -> UInt64 { var enumeratorError: Error? diff --git a/Mist/Extensions/Scene+Extension.swift b/Mist/Extensions/Scene+Extension.swift index b735f95..49131ee 100644 --- a/Mist/Extensions/Scene+Extension.swift +++ b/Mist/Extensions/Scene+Extension.swift @@ -8,6 +8,9 @@ import SwiftUI extension Scene { + /// Fixes the window size across all macOS versions. + /// + /// - Returns: A modified window for macOS 13.0 Ventura and later otherwise an unmodified window. func fixedWindow() -> some Scene { if #available(macOS 13.0, *) { // swiftformat:disable:next redundantReturn diff --git a/Mist/Extensions/Sequence+Extension.swift b/Mist/Extensions/Sequence+Extension.swift index 714b8b6..53a0dfb 100644 --- a/Mist/Extensions/Sequence+Extension.swift +++ b/Mist/Extensions/Sequence+Extension.swift @@ -9,24 +9,45 @@ import Foundation import Yams extension Sequence where Iterator.Element == [String: Any] { + /// Provides a firmware CSV string representation. + /// + /// - Returns: A firmware CSV string representation. func firmwaresCSVString() -> String { "Name,Version,Build,Size,URL,Date,Compatible,Signed,Beta\n" + map { $0.firmwareCSVString() }.joined() } + /// Provides an installer CSV string representation. + /// + /// - Returns: An installer CSV string representation. func installersCSVString() -> String { "Identifier,Name,Version,Build,Size,Date,Compatible,Beta\n" + map { $0.installerCSVString() }.joined() } + /// Provides a JSON string representation. + /// + /// - Throws: An `Error` if a JSON string representation cannot be created. + /// + /// - Returns: A JSON string representation. func jsonString() throws -> String { let data: Data = try JSONSerialization.data(withJSONObject: self, options: [.prettyPrinted, .sortedKeys]) return String(decoding: data, as: UTF8.self) } + /// Provides a Property List string representation. + /// + /// - Throws: An `Error` if a Property List string representation cannot be created. + /// + /// - Returns: A Property List string representation. func propertyListString() throws -> String { let data: Data = try PropertyListSerialization.data(fromPropertyList: self, format: .xml, options: .bitWidth) return String(decoding: data, as: UTF8.self) } + /// Provides a YAML string representation. + /// + /// - Throws: An `Error` if a YAML string representation cannot be created. + /// + /// - Returns: A YAML string representation. func yamlString() throws -> String { try Yams.dump(object: self) } diff --git a/Mist/Extensions/String+Extension.swift b/Mist/Extensions/String+Extension.swift index 6e6b233..9bf3905 100644 --- a/Mist/Extensions/String+Extension.swift +++ b/Mist/Extensions/String+Extension.swift @@ -8,24 +8,49 @@ import Foundation extension String { + /// App name static let appName: String = "mist" + /// App identifier static let appIdentifier: String = "com.ninxsoft.\(appName)" + /// Helper identifier static let helperIdentifier: String = "\(appIdentifier).helper" + /// Helper LaunchDaemon URL static let helperLaunchDaemonURL: String = "/Library/LaunchDaemons/\(helperIdentifier).plist" + /// Helper URL static let helperURL: String = "/Library/PrivilegedHelperTools/\(helperIdentifier)" + /// Repository URL static let repositoryURL: String = "https://github.com/ninxsoft/Mist" + /// Filename template static let filenameTemplate: String = "Install %NAME% %VERSION%_%BUILD%" + /// Firmware filename template static let firmwareFilenameTemplate: String = "\(filenameTemplate).ipsw" + /// Application filename template static let applicationFilenameTemplate: String = "\(filenameTemplate).app" + /// Disk Image filename template static let diskImageFilenameTemplate: String = "\(filenameTemplate).dmg" + /// ISO filename template static let isoFilenameTemplate: String = "\(filenameTemplate).iso" + /// Package filename template static let packageFilenameTemplate: String = "\(filenameTemplate).pkg" + /// Package identifier template static let packageIdentifierTemplate: String = "com.company.pkg.%NAME%.%VERSION%.%BUILD%" + /// Tempoarary directory static let temporaryDirectory: String = "/private/tmp/\(appIdentifier)" + /// Cache directory static let cacheDirectory: String = "/Users/Shared/Mist/Cache" + /// TCC database path static let tccDatabasePath: String = "/Library/Application Support/com.apple.TCC/TCC.db" + /// Log URL static let logURL: String = "\(appName)://log" + /// Provides a string replacing placeholder `name`, `version` and `build` values. + /// + /// - Parameters: + /// - name: A firmware / installer name. + /// - version: A firmware / installer version. + /// - build: A firmware / installer build. + /// + /// - Returns: A string with name, version and build placeholders substituted. func stringWithSubstitutions(name: String, version: String, build: String) -> String { replacingOccurrences(of: "%NAME%", with: name) .replacingOccurrences(of: "%VERSION%", with: version) diff --git a/Mist/Extensions/UInt32+Extension.swift b/Mist/Extensions/UInt32+Extension.swift index 129b2f2..0f884f1 100644 --- a/Mist/Extensions/UInt32+Extension.swift +++ b/Mist/Extensions/UInt32+Extension.swift @@ -8,6 +8,9 @@ import Foundation extension UInt32 { + /// Hexadecimal representation of the 32-bit unsigned integer. + /// + /// - Returns: A hexademical string. func hexString() -> String { String(format: "0x%08X", self) } diff --git a/Mist/Extensions/UInt64+Extension.swift b/Mist/Extensions/UInt64+Extension.swift index 9b2d97e..30f8884 100644 --- a/Mist/Extensions/UInt64+Extension.swift +++ b/Mist/Extensions/UInt64+Extension.swift @@ -15,6 +15,9 @@ extension UInt64 { /// gigabytes constant static let gigabyte: UInt64 = .megabyte * 1_000 + /// Pretty formatted string representation of the 64-bit unsigned integer, as bytes. + /// + /// - Returns: A pretty formatted bytes string. func bytesString() -> String { if self < .kilobyte { "\(self) bytes" @@ -27,6 +30,9 @@ extension UInt64 { } } + /// Hexadecimal representation of the 64-bit unsigned integer. + /// + /// - Returns: A hexademical string. func hexString() -> String { String(format: "0x%016X", self) } diff --git a/Mist/Extensions/UInt8+Extension.swift b/Mist/Extensions/UInt8+Extension.swift index 850b478..860b387 100644 --- a/Mist/Extensions/UInt8+Extension.swift +++ b/Mist/Extensions/UInt8+Extension.swift @@ -8,6 +8,9 @@ import Foundation extension UInt8 { + /// Hexadecimal representation of the 8-bit unsigned integer. + /// + /// - Returns: A hexademical string. func hexString() -> String { String(format: "0x%02X", self) } diff --git a/Mist/Extensions/UNNotificationAction+Extension.swift b/Mist/Extensions/UNNotificationAction+Extension.swift index 5ff1931..2009703 100644 --- a/Mist/Extensions/UNNotificationAction+Extension.swift +++ b/Mist/Extensions/UNNotificationAction+Extension.swift @@ -8,6 +8,7 @@ import UserNotifications extension UNNotificationAction { + /// Mist Notification Action identifiers enum Identifier { /// Show Identifier static let show: String = "Show" diff --git a/Mist/Extensions/UNNotificationCategory+Extension.swift b/Mist/Extensions/UNNotificationCategory+Extension.swift index 9633763..776ddea 100644 --- a/Mist/Extensions/UNNotificationCategory+Extension.swift +++ b/Mist/Extensions/UNNotificationCategory+Extension.swift @@ -8,6 +8,7 @@ import UserNotifications extension UNNotificationCategory { + /// Mist Notification identifiers enum Identifier { /// Success Identifier static let success: String = "Success" diff --git a/Mist/Extensions/URL+Extension.swift b/Mist/Extensions/URL+Extension.swift index d788f9e..b4077b2 100644 --- a/Mist/Extensions/URL+Extension.swift +++ b/Mist/Extensions/URL+Extension.swift @@ -9,6 +9,11 @@ import CryptoKit import Foundation extension URL { + /// Provides the size of the file at the URL, in bytes. + /// + /// - Throws: An `Error` if the file size is unable to be determined. + /// + /// - Returns: The file size of the provided URL, in bytes. func fileSize() throws -> UInt64 { let urlResourceKeys: Set = [ .isRegularFileKey, @@ -27,6 +32,9 @@ extension URL { return UInt64(resourceValues.totalFileAllocatedSize ?? resourceValues.fileAllocatedSize ?? 0) } + /// Provides the SHA1 hash of the file at the URL. + /// + /// - Returns: The SHA1 hash of the file at the provided URL, or `nil` if a has is unable to be determined. func shasum() -> String? { let length: Int = 1_024 * 1_024 * 50 // 50 MB diff --git a/Mist/Extensions/[UInt8]+Extension.swift b/Mist/Extensions/[UInt8]+Extension.swift index d345593..5c9400a 100644 --- a/Mist/Extensions/[UInt8]+Extension.swift +++ b/Mist/Extensions/[UInt8]+Extension.swift @@ -6,16 +6,34 @@ // extension [UInt8] { + /// Provides an 8-bit unsigned integer based of the provided offset in the 8-bit unsigned integer array. + /// + /// - Parameters: + /// - offset: The offset in the array of unsigned 8-bit integers. + /// + /// - Returns: The 8-bit unsigned integer in the array at the provided offset. func uInt8(at offset: Int) -> UInt8 { self[offset] } + /// Provides a 32-bit unsigned integer based of the provided offset in the 8-bit unsigned integer array. + /// + /// - Parameters: + /// - offset: The offset in the array of unsigned 8-bit integers. + /// + /// - Returns: The 32-bit unsigned integer in the array at the provided offset. func uInt32(at offset: Int) -> UInt32 { self[offset ... offset + 0x03].reversed().reduce(0) { $0 << 0x08 + UInt32($1) } } + /// Provides a 64-bit unsigned integer based of the provided offset in the 8-bit unsigned integer array. + /// + /// - Parameters: + /// - offset: The offset in the array of unsigned 8-bit integers. + /// + /// - Returns: The 64-bit unsigned integer in the array at the provided offset. func uInt64(at offset: Int) -> UInt64 { self[offset ... offset + 0x07].reversed().reduce(0) { $0 << 0x08 + UInt64($1) diff --git a/Shared/XPCRoute+Extension.swift b/Shared/XPCRoute+Extension.swift index 30c13e8..e3a963a 100644 --- a/Shared/XPCRoute+Extension.swift +++ b/Shared/XPCRoute+Extension.swift @@ -8,6 +8,7 @@ import SecureXPC extension XPCRoute { + /// Default XPC Route static let commandRoute: XPCRouteWithMessageWithReply = XPCRoute.named("com.ninxsoft.mist.helper") .withMessageType(HelperToolCommandRequest.self) .withReplyType(HelperToolCommandResponse.self)