88 lines
3.9 KiB
Swift
88 lines
3.9 KiB
Swift
import Foundation
|
|
import FileKit
|
|
|
|
public struct FileHeaderHandler {
|
|
|
|
public static func getHeader(of file: FileRepresentation, includeTimestamp: Bool) -> String {
|
|
let path: String
|
|
if let absolutePath = file.sourceFile.path {
|
|
path = getRelativePath(from: absolutePath)
|
|
} else {
|
|
path = "unknown"
|
|
}
|
|
let generationInfo = "// MARK: - Mocks generated from file: \(path)" + (includeTimestamp ? " at \(Date())\n" : "")
|
|
let header = getHeader(of: file)
|
|
return generationInfo + "\n" + header + "\n"
|
|
}
|
|
|
|
public static func getImports(of file: FileRepresentation, testableFrameworks: [String]) -> String {
|
|
var imports = Array(Set(file.declarations.only(Import.self).map { "import \($0.importee)\n" })).sorted().joined(separator: "")
|
|
if imports.isEmpty == false {
|
|
imports = "\n\(imports)"
|
|
}
|
|
return "import Cuckoo\n" + getTestableImports(testableFrameworks: testableFrameworks) + imports
|
|
}
|
|
|
|
private static func getRelativePath(from absolutePath: String) -> String {
|
|
let path = Path(absolutePath)
|
|
let base = path.commonAncestor(Path.current)
|
|
let components = path.components.suffix(from: base.components.endIndex)
|
|
let result = components.map { $0.rawValue }.joined(separator: Path.separator)
|
|
let difference = Path.current.components.endIndex - base.components.endIndex
|
|
return (0..<difference).reduce(result) { acc, _ in ".." + Path.separator + acc }
|
|
}
|
|
|
|
private static func getHeader(of file: FileRepresentation) -> String {
|
|
let possibleHeaderEnd = getPossibleHeaderEnd(current: file.sourceFile.contents.unicodeScalars.count, declarations: file.declarations)
|
|
let possibleHeader = String(file.sourceFile.contents.utf8.prefix(possibleHeaderEnd)) ?? ""
|
|
let singleLine = getPrefixToLastSingleLineComment(text: possibleHeader)
|
|
let multiLine = getPrefixToLastMultiLineComment(text: possibleHeader)
|
|
return singleLine.count > multiLine.count ? singleLine : multiLine
|
|
}
|
|
|
|
private static func getPossibleHeaderEnd(current: Int, declarations: [Token]) -> Int {
|
|
return declarations.reduce(current) { minimum, declaration in
|
|
let declarationMinimum: Int
|
|
switch declaration {
|
|
case let containerToken as ContainerToken:
|
|
declarationMinimum = containerToken.range.lowerBound
|
|
case let method as Method:
|
|
declarationMinimum = method.range.lowerBound
|
|
case let importToken as Import:
|
|
declarationMinimum = importToken.range.lowerBound
|
|
default:
|
|
declarationMinimum = minimum
|
|
}
|
|
return min(declarationMinimum, minimum)
|
|
}
|
|
}
|
|
|
|
private static func getPrefixToLastSingleLineComment(text: String) -> String {
|
|
if let range = text.range(of: "//", options: .backwards) {
|
|
let lastLine = text.lineRange(for: range)
|
|
return String(text[..<lastLine.upperBound])
|
|
} else {
|
|
return ""
|
|
}
|
|
}
|
|
|
|
private static func getPrefixToLastMultiLineComment(text: String) -> String {
|
|
if let range = text.range(of: "*/", options: .backwards) {
|
|
return String(text[..<range.upperBound]) + "\n"
|
|
} else {
|
|
return ""
|
|
}
|
|
}
|
|
|
|
private static func getTestableImports(testableFrameworks: [String]) -> String {
|
|
func replaceIllegalCharacters(_ char: UnicodeScalar) -> Character {
|
|
if CharacterSet.letters.contains(UnicodeScalar(char.value)!) || CharacterSet.decimalDigits.contains(UnicodeScalar(char.value)!) {
|
|
return Character(char)
|
|
} else {
|
|
return "_"
|
|
}
|
|
}
|
|
return testableFrameworks.map { String($0.unicodeScalars.map(replaceIllegalCharacters)) }.map { "@testable import \($0)\n" }.joined(separator: "")
|
|
}
|
|
}
|