172 lines
5.7 KiB
Swift
172 lines
5.7 KiB
Swift
import Foundation
|
|
|
|
private let formatter: DateFormatter = {
|
|
let formatter = DateFormatter()
|
|
formatter.dateStyle = .short
|
|
return formatter
|
|
}()
|
|
|
|
/// Reports violations as HTML.
|
|
public struct HTMLReporter: Reporter {
|
|
// MARK: - Reporter Conformance
|
|
|
|
public static let identifier = "html"
|
|
public static let isRealtime = false
|
|
|
|
public var description: String {
|
|
return "Reports violations as HTML."
|
|
}
|
|
|
|
public static func generateReport(_ violations: [StyleViolation]) -> String {
|
|
return generateReport(violations, swiftlintVersion: Version.current.value,
|
|
dateString: formatter.string(from: Date()))
|
|
}
|
|
|
|
// MARK: - Internal
|
|
|
|
// swiftlint:disable:next function_body_length
|
|
internal static func generateReport(_ violations: [StyleViolation], swiftlintVersion: String,
|
|
dateString: String) -> String {
|
|
let rows = violations.enumerated()
|
|
.map { generateSingleRow(for: $1, at: $0 + 1) }
|
|
.joined(separator: "\n")
|
|
|
|
let fileCount = Set(violations.compactMap({ $0.location.file })).count
|
|
let warningCount = violations.filter({ $0.severity == .warning }).count
|
|
let errorCount = violations.filter({ $0.severity == .error }).count
|
|
|
|
return """
|
|
<!doctype html>
|
|
<html>
|
|
\t<head>
|
|
\t\t<meta charset="utf-8" />
|
|
\t\t<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
\t\t
|
|
\t\t<style type="text/css">
|
|
\t\t\tbody {
|
|
\t\t\t\tfont-family: Arial, Helvetica, sans-serif;
|
|
\t\t\t\tfont-size: 0.9rem;
|
|
\t\t\t}
|
|
\t\t\t
|
|
\t\t\ttable {
|
|
\t\t\t\tborder: 1px solid gray;
|
|
\t\t\t\tborder-collapse: collapse;
|
|
\t\t\t\t-moz-box-shadow: 3px 3px 4px #AAA;
|
|
\t\t\t\t-webkit-box-shadow: 3px 3px 4px #AAA;
|
|
\t\t\t\tbox-shadow: 3px 3px 4px #AAA;
|
|
\t\t\t\tvertical-align: top;
|
|
\t\t\t\theight: 64px;
|
|
\t\t\t}
|
|
\t\t\t
|
|
\t\t\ttd, th {
|
|
\t\t\t\tborder: 1px solid #D3D3D3;
|
|
\t\t\t\tpadding: 5px 10px 5px 10px;
|
|
\t\t\t}
|
|
\t\t\t
|
|
\t\t\tth {
|
|
\t\t\t\tborder-bottom: 1px solid gray;
|
|
\t\t\t\tbackground-color: rgba(41,52,92,0.313);
|
|
\t\t\t}
|
|
\t\t\t
|
|
\t\t\t.error, .warning {
|
|
\t\t\t\ttext-align: center;
|
|
\t\t\t}
|
|
\t\t\t
|
|
\t\t\t.error {
|
|
\t\t\t\tbackground-color: #FF9D92;
|
|
\t\t\t\tcolor: #7F0800;
|
|
\t\t\t}
|
|
\t\t\t
|
|
\t\t\t.warning {
|
|
\t\t\t\tbackground-color: #FFF59E;
|
|
\t\t\t\tcolor: #7F7000;
|
|
\t\t\t}
|
|
\t\t</style>
|
|
\t\t
|
|
\t\t<title>SwiftLint Report</title>
|
|
\t</head>
|
|
\t<body>
|
|
\t\t<h1>SwiftLint Report</h1>
|
|
\t\t
|
|
\t\t<hr />
|
|
\t\t
|
|
\t\t<h2>Violations</h2>
|
|
\t\t
|
|
\t\t<table>
|
|
\t\t\t<thead>
|
|
\t\t\t\t<tr>
|
|
\t\t\t\t\t<th style="width: 60pt;">
|
|
\t\t\t\t\t\t<b>Serial No.</b>
|
|
\t\t\t\t\t</th>
|
|
\t\t\t\t\t<th style="width: 500pt;">
|
|
\t\t\t\t\t\t<b>File</b>
|
|
\t\t\t\t\t</th>
|
|
\t\t\t\t\t<th style="width: 60pt;">
|
|
\t\t\t\t\t\t<b>Location</b>
|
|
\t\t\t\t\t</th>
|
|
\t\t\t\t\t<th style="width: 60pt;">
|
|
\t\t\t\t\t\t<b>Severity</b>
|
|
\t\t\t\t\t</th>
|
|
\t\t\t\t\t<th style="width: 500pt;">
|
|
\t\t\t\t\t\t<b>Message</b>
|
|
\t\t\t\t\t</th>
|
|
\t\t\t\t</tr>
|
|
\t\t\t</thead>
|
|
\t\t\t<tbody>
|
|
\(rows)
|
|
\t\t\t</tbody>
|
|
\t\t</table>
|
|
\t\t
|
|
\t\t<br/>
|
|
\t\t
|
|
\t\t<h2>Summary</h2>
|
|
\t\t
|
|
\t\t<table>
|
|
\t\t\t<tbody>
|
|
\t\t\t\t<tr>
|
|
\t\t\t\t\t<td>Total files with violations</td>
|
|
\t\t\t\t\t<td>\(fileCount)</td>
|
|
\t\t\t\t</tr>
|
|
\t\t\t\t<tr>
|
|
\t\t\t\t\t<td>Total warnings</td>
|
|
\t\t\t\t\t<td>\(warningCount)</td>
|
|
\t\t\t\t</tr>
|
|
\t\t\t\t<tr>
|
|
\t\t\t\t\t<td>Total errors</td>
|
|
\t\t\t\t\t<td>\(errorCount)</td>
|
|
\t\t\t\t</tr>
|
|
\t\t\t</tbody>
|
|
\t\t</table>
|
|
\t\t
|
|
\t\t<hr />
|
|
\t\t
|
|
\t\t<p>
|
|
\t\t\tCreated with
|
|
\t\t\t<a href="https://github.com/realm/SwiftLint"><b>SwiftLint</b></a>
|
|
\t\t\t\(swiftlintVersion) on \(dateString)
|
|
\t\t</p>
|
|
\t</body>
|
|
</html>
|
|
"""
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private static func generateSingleRow(for violation: StyleViolation, at index: Int) -> String {
|
|
let severity: String = violation.severity.rawValue.capitalized
|
|
let location = violation.location
|
|
let file: String = (violation.location.relativeFile ?? "<nopath>").escapedForXML()
|
|
let line: Int = location.line ?? 0
|
|
let character: Int = location.character ?? 0
|
|
return """
|
|
\t\t\t\t<tr>
|
|
\t\t\t\t\t<td style="text-align: right;">\(index)</td>
|
|
\t\t\t\t\t<td>\(file)</td>
|
|
\t\t\t\t\t<td style="text-align: center;">\(line):\(character)</td>
|
|
\t\t\t\t\t<td class="\(severity.lowercased())">\(severity)</td>
|
|
\t\t\t\t\t<td>\(violation.reason.escapedForXML())</td>
|
|
\t\t\t\t</tr>
|
|
"""
|
|
}
|
|
}
|