gitbay/MRs/Suggestion.swift

v1.12.0
gitbay-ios/gitbay/MRs/Suggestion.swift history · blame · raw

46 lines · 1893 bytes

 1import Foundation
 2
 3/// The change a review thread's ```suggestion block proposes, as
 4/// `mr threads` carries it: lines `startLine` through `endLine` of `path`,
 5/// `original` replaced by `replacement`. Both texts end every line with
 6/// its terminator, so "" is no lines.
 7nonisolated struct Suggestion: Decodable, Sendable, Hashable {
 8    let path: String
 9    let startLine: Int64
10    let endLine: Int64
11    let original: String
12    let replacement: String
13    /// The lines it replaces have changed at the head, or the file moved;
14    /// it cannot be applied then, and `reason` says which.
15    let outdated: Bool
16    let reason: String?
17    /// "server" where `mr apply-suggestion` commits it; "local" where the
18    /// repository requires signed commits, which only a clone can make.
19    let apply: String
20
21    enum CodingKeys: String, CodingKey {
22        case path, original, replacement, outdated, reason, apply
23        case startLine = "start_line"
24        case endLine = "end_line"
25    }
26
27    var appliesOnServer: Bool { apply == "server" }
28
29    /// The text as lines, without the terminator the last one carries.
30    static func lines(_ text: String) -> [String] {
31        guard !text.isEmpty else { return [] }
32        var lines = text.components(separatedBy: "\n")
33        if lines.last == "" { lines.removeLast() }
34        return lines
35    }
36
37    /// A comment's text without its ```suggestion block, which the thread
38    /// draws as replaced and proposed lines instead.
39    static func withoutBlock(_ body: String) -> String {
40        guard let start = body.range(of: "```suggestion") else { return body }
41        let afterOpen = body[start.upperBound...]
42        guard let close = afterOpen.range(of: "```") else { return body }
43        let rest = body[..<start.lowerBound] + body[close.upperBound...]
44        return rest.trimmingCharacters(in: .whitespacesAndNewlines)
45    }
46}