import Foundation import SourceKittenFramework extension String { internal func hasTrailingWhitespace() -> Bool { if isEmpty { return false } if let unicodescalar = unicodeScalars.last { return CharacterSet.whitespaces.contains(unicodescalar) } return false } internal func isUppercase() -> Bool { return self == uppercased() } internal func isLowercase() -> Bool { return self == lowercased() } internal func nameStrippingLeadingUnderscoreIfPrivate(_ dict: SourceKittenDictionary) -> String { if let acl = dict.accessibility, acl.isPrivate && first == "_" { return String(self[index(after: startIndex)...]) } return self } private subscript (range: Range) -> String { let nsrange = NSRange(location: range.lowerBound, length: range.upperBound - range.lowerBound) if let indexRange = nsrangeToIndexRange(nsrange) { return String(self[indexRange]) } queuedFatalError("invalid range") } internal func substring(from: Int, length: Int? = nil) -> String { if let length = length { return self[from.. Int? { if let range = range(of: search, options: [.literal, .backwards]) { return distance(from: startIndex, to: range.lowerBound) } return nil } internal func nsrangeToIndexRange(_ nsrange: NSRange) -> Range? { guard nsrange.location != NSNotFound else { return nil } let from16 = utf16.index(utf16.startIndex, offsetBy: nsrange.location, limitedBy: utf16.endIndex) ?? utf16.endIndex let to16 = utf16.index(from16, offsetBy: nsrange.length, limitedBy: utf16.endIndex) ?? utf16.endIndex guard let fromIndex = Index(from16, within: self), let toIndex = Index(to16, within: self) else { return nil } return fromIndex.. String { return bridge().absolutePathRepresentation().bridge().standardizingPath } internal var isFile: Bool { if self.isEmpty { return false } var isDirectoryObjC: ObjCBool = false if FileManager.default.fileExists(atPath: self, isDirectory: &isDirectoryObjC) { return !isDirectoryObjC.boolValue } return false } /// Count the number of occurrences of the given character in `self` /// - Parameter character: Character to count /// - Returns: Number of times `character` occurs in `self` public func countOccurrences(of character: Character) -> Int { return self.reduce(0, { $1 == character ? $0 + 1 : $0 }) } /// If self is a path, this method can be used to get a path expression relative to a root directory public func path(relativeTo rootDirectory: String) -> String { var rootDirComps = rootDirectory.components(separatedBy: "/") let rootDirCompsCount = rootDirComps.count while true { let sharedRootDir = rootDirComps.joined(separator: "/") if hasPrefix(sharedRootDir) { let path = (0 ..< rootDirCompsCount - rootDirComps.count).map { _ in "/.." }.flatMap { $0 } + String(dropFirst(sharedRootDir.count)) return String(path.dropFirst()) // Remove leading '/' } else { rootDirComps = rootDirComps.dropLast() } } } }