krz/hutch

an ios client for sourcehut

clone: git clone https://gitbay.org/krz/hutch.git

v2.13.1: Hutch/App/DeepLink.swift · raw

 1import Foundation
 2
 3/// Represents a parsed `hutch://` deep link.
 4enum DeepLink: Equatable {
 5    case home
 6    /// hutch://git/<owner>/<repo>
 7    case repository(owner: String, repo: String)
 8    /// hutch://todo/<owner>/<tracker>/<ticketId>
 9    case ticket(owner: String, tracker: String, ticketId: Int)
10    /// hutch://builds/<jobId>
11    case build(jobId: Int)
12
13    /// Attempt to parse a URL into a DeepLink.
14    /// Expected format: hutch://<path>
15    init?(url: URL) {
16        guard url.scheme == "hutch" else { return nil }
17
18        // url.host gives the first path component for opaque URLs;
19        // use standardized path components from the full string.
20        let components = url.pathComponents(fromScheme: "hutch")
21
22        switch components.first {
23        case "home", nil:
24            self = .home
25
26        case "git" where components.count >= 3:
27            let owner = components[1]
28            let repo = components[2]
29            self = .repository(owner: owner, repo: repo)
30
31        case "todo" where components.count >= 4:
32            let owner = components[1]
33            let tracker = components[2]
34            guard let ticketId = Int(components[3]) else { return nil }
35            self = .ticket(owner: owner, tracker: tracker, ticketId: ticketId)
36
37        case "builds" where components.count >= 2:
38            guard let jobId = Int(components[1]) else { return nil }
39            self = .build(jobId: jobId)
40
41        default:
42            return nil
43        }
44    }
45}
46
47private extension URL {
48    /// Parse path components from a custom-scheme URL.
49    /// For `hutch://git/~user/repo`, returns `["git", "~user", "repo"]`.
50    func pathComponents(fromScheme scheme: String) -> [String] {
51        // Remove scheme prefix and split by "/"
52        var str = absoluteString
53        if str.hasPrefix("\(scheme)://") {
54            str = String(str.dropFirst("\(scheme)://".count))
55        }
56        return str.split(separator: "/").map(String.init)
57    }
58}