KotlinCompat.swift 75 lignes · 2729 octets
import Foundation

// Small Kotlin-stdlib compatibility helpers shared by the ported domain code.

extension String {
    /// Kotlin `isBlank()`.
    var isBlank: Bool { allSatisfy { $0.isWhitespace } }

    /// Kotlin `isNotBlank()`.
    var isNotBlank: Bool { !isBlank }

    /// Kotlin `takeIf { it.isNotBlank() }` / `ifBlank { null }`.
    var nilIfBlank: String? { isBlank ? nil : self }

    /// Kotlin `String.lines()` — splits on \r\n, \n and \r.
    func kotlinLines() -> [String] {
        replacingOccurrences(of: "\r\n", with: "\n")
            .replacingOccurrences(of: "\r", with: "\n")
            .components(separatedBy: "\n")
    }
}

extension Array where Element: Hashable {
    /// Kotlin `distinct()` — keeps the first occurrence, preserves order.
    func distinctPreservingOrder() -> [Element] {
        var seen = Set<Element>()
        return filter { seen.insert($0).inserted }
    }
}

/// Thin NSRegularExpression wrapper mirroring the Kotlin `Regex` call sites.
final class KotlinRegex {
    private let regex: NSRegularExpression

    /// Patterns are compile-time constants ported from Kotlin; a parse failure is a programmer error.
    init(_ pattern: String, options: NSRegularExpression.Options = []) {
        // swiftlint:disable:next force_try
        regex = try! NSRegularExpression(pattern: pattern, options: options)
    }

    /// Kotlin `containsMatchIn`.
    func containsMatchIn(_ s: String) -> Bool {
        regex.firstMatch(in: s, options: [], range: NSRange(s.startIndex..., in: s)) != nil
    }

    /// Kotlin `findAll(...).map { it.value }`.
    func findAll(_ s: String) -> [String] {
        regex.matches(in: s, options: [], range: NSRange(s.startIndex..., in: s)).compactMap {
            Range($0.range, in: s).map { String(s[$0]) }
        }
    }

    /// Kotlin `String.replace(regex, replacement)` — literal replacement string.
    func replace(_ s: String, with replacement: String) -> String {
        regex.stringByReplacingMatches(
            in: s,
            options: [],
            range: NSRange(s.startIndex..., in: s),
            withTemplate: NSRegularExpression.escapedTemplate(for: replacement)
        )
    }

    /// Kotlin `Regex.split` — segments between matches, including empty ones.
    func split(_ s: String) -> [String] {
        var result: [String] = []
        var lastEnd = s.startIndex
        for m in regex.matches(in: s, options: [], range: NSRange(s.startIndex..., in: s)) {
            guard let r = Range(m.range, in: s) else { continue }
            result.append(String(s[lastEnd..<r.lowerBound]))
            lastEnd = r.upperBound
        }
        result.append(String(s[lastEnd...]))
        return result
    }
}