Skip to content

Commit

Permalink
Add human readable reporter that’s also funny because emoji.
Browse files Browse the repository at this point in the history
  • Loading branch information
justMaku authored and jpsim committed Dec 8, 2016
1 parent fa2628a commit d97632e
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 4 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
[Denis Lebedev](https://github.com/garnett)
[#544](https://github.com/realm/SwiftLint/issues/544)

* Add `EmojiReporter`: a human friendly reporter.
[Michał Kałużny](https://github.com/justMaku)

##### Bug Fixes

* Fix `weak_delegate` rule reporting a violation for variables containing
but not ending in `delegate`.
[Phil Webster](https://github.com/philwebster)

* Fix `weak_delegate` rule reporting a violation for variables in protocols
declarations.
[Marcelo Fabri](https://github.com/marcelofabri)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ variable_name:
- id
- URL
- GlobalAPIKey
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit)
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, emoji)
```
#### Defining Custom Rules
Expand Down
2 changes: 1 addition & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ variable_name:
- id
- URL
- GlobalAPIKey
reporter: "xcode" # 报告类型 (xcode, json, csv, checkstyle)
reporter: "xcode" # 报告类型 (xcode, json, csv, checkstyle, junit, emoji)
```
#### 定义自定义规则
Expand Down
24 changes: 24 additions & 0 deletions Source/SwiftLintFramework/Extensions/Array+SwiftLint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,27 @@ extension Array where Element: NSTextCheckingResult {
return map { $0.range }
}
}

extension Array where Element: Equatable {
var unique: [Element] {
var uniqueValues: [Element] = []
forEach { item in
if !uniqueValues.contains(item) {
uniqueValues += [item]
}
}
return uniqueValues
}
}

extension Array {
// swiftlint:disable:next line_length
func group<U: Hashable>(by transform: (Element) -> U) -> [U: [Element]] {
var dictionary: [U: [Element]] = [:]
for element in self {
let key = transform(element)
if case nil = dictionary[key]?.append(element) { dictionary[key] = [element] }
}
return dictionary
}
}
2 changes: 2 additions & 0 deletions Source/SwiftLintFramework/Protocols/Reporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public func reporterFromString(_ string: String) -> Reporter.Type {
return JUnitReporter.self
case HTMLReporter.identifier:
return HTMLReporter.self
case EmojiReporter.identifier:
return EmojiReporter.self
default:
fatalError("no reporter with identifier '\(string)' available.")
}
Expand Down
71 changes: 71 additions & 0 deletions Source/SwiftLintFramework/Reporters/EmojiReporter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// EmojiReporter.swift
// SwiftLint
//
// Created by Michał Kałużny on 01/12/2016.
// Copyright © 2016 Realm. All rights reserved.
//

import Foundation

public struct EmojiReporter: Reporter {
public static let identifier = "emoji"
public static let isRealtime = false

public var description: String {
return "Reports violations in the format that's both fun and easy to read."
}

public static func generateReport(_ violations: [StyleViolation]) -> String {
return violations.group { (violation) in
violation.location.file ?? "Other"
}.map { (filename, violations) in
return reportFor(file: filename, with: violations)
}.joined(separator: "\n")
}

private static func reportFor(file: String, with violations: [StyleViolation]) -> String {
var lines: [String] = []

let sortedViolatons = violations.sorted { (lhs, rhs) -> Bool in
switch (lhs.severity, rhs.severity) {
case (.warning, .error): return false
case (.error, .warning): return true
case (_, _):
switch (lhs.location.line, rhs.location.line) {
case (.some(let lhs), .some(let rhs)): return lhs < rhs
case (.some, .none): return true
case (.none, .some): return false
case (.none, .none): return false
}
}
}

lines.append(file)

for violation in sortedViolatons {
var line = ""
line += emojiFor(violationSeverity: violation.severity)
line += " "

if let locationLine = violation.location.line {
line += "Line \(locationLine): "
}

line += violation.reason

lines.append(line)
}

return lines.joined(separator: "\n")
}

private static func emojiFor(violationSeverity: ViolationSeverity) -> String {
switch violationSeverity {
case .error:
return "⛔️"
case .warning:
return "⚠️"
}
}
}
4 changes: 4 additions & 0 deletions SwiftLint.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
24B4DF0D1D6DFDE90097803B /* RedundantNilCoalescingRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24B4DF0B1D6DFA370097803B /* RedundantNilCoalescingRule.swift */; };
24E17F721B14BB3F008195BE /* File+Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E17F701B1481FF008195BE /* File+Cache.swift */; };
2E02005F1C54BF680024D09D /* CyclomaticComplexityRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E02005E1C54BF680024D09D /* CyclomaticComplexityRule.swift */; };
2E336D1B1DF08BFB00CCFE77 /* EmojiReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E336D191DF08AF200CCFE77 /* EmojiReporter.swift */; };
2E5761AA1C573B83003271AF /* FunctionParameterCountRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E5761A91C573B83003271AF /* FunctionParameterCountRule.swift */; };
3B0B14541C505D6300BE82F7 /* SeverityConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B0B14531C505D6300BE82F7 /* SeverityConfiguration.swift */; };
3B1150CA1C31FC3F00D83B1E /* Yaml+SwiftLint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B1150C91C31FC3F00D83B1E /* Yaml+SwiftLint.swift */; };
Expand Down Expand Up @@ -203,6 +204,7 @@
24B4DF0B1D6DFA370097803B /* RedundantNilCoalescingRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedundantNilCoalescingRule.swift; sourceTree = "<group>"; };
24E17F701B1481FF008195BE /* File+Cache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "File+Cache.swift"; sourceTree = "<group>"; };
2E02005E1C54BF680024D09D /* CyclomaticComplexityRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CyclomaticComplexityRule.swift; sourceTree = "<group>"; };
2E336D191DF08AF200CCFE77 /* EmojiReporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmojiReporter.swift; sourceTree = "<group>"; };
2E5761A91C573B83003271AF /* FunctionParameterCountRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FunctionParameterCountRule.swift; sourceTree = "<group>"; };
3B0B14531C505D6300BE82F7 /* SeverityConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeverityConfiguration.swift; sourceTree = "<group>"; };
3B1150C91C31FC3F00D83B1E /* Yaml+SwiftLint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Yaml+SwiftLint.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -620,6 +622,7 @@
E86396C81BADB2B9002C9E88 /* JSONReporter.swift */,
E86396C41BADAC15002C9E88 /* XcodeReporter.swift */,
4A9A3A391DC1D75F00DF5183 /* HTMLReporter.swift */,
2E336D191DF08AF200CCFE77 /* EmojiReporter.swift */,
);
path = Reporters;
sourceTree = "<group>";
Expand Down Expand Up @@ -973,6 +976,7 @@
D44254271DB9C15C00492EA4 /* SyntacticSugarRule.swift in Sources */,
E88198441BEA93D200333A11 /* ColonRule.swift in Sources */,
E809EDA11B8A71DF00399043 /* Configuration.swift in Sources */,
2E336D1B1DF08BFB00CCFE77 /* EmojiReporter.swift in Sources */,
E8EA41171C2D1DBE004F9930 /* CheckstyleReporter.swift in Sources */,
006ECFC41C44E99E00EF6364 /* LegacyConstantRule.swift in Sources */,
E88DEA731B0984C400A66CB0 /* String+SwiftLint.swift in Sources */,
Expand Down
12 changes: 11 additions & 1 deletion Tests/SwiftLintFrameworkTests/ReporterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class ReporterTests: XCTestCase {
CSVReporter.self,
CheckstyleReporter.self,
JUnitReporter.self,
HTMLReporter.self
HTMLReporter.self,
EmojiReporter.self
]
for reporter in reporters {
XCTAssertEqual(reporter.identifier, reporterFromString(reporter.identifier).identifier)
Expand Down Expand Up @@ -46,6 +47,15 @@ class ReporterTests: XCTestCase {
)
}

func testEmojiReporter() {
XCTAssertEqual(
EmojiReporter.generateReport(generateViolations()),
"filename\n" +
"⛔️ Line 1: Violation Reason.\n" +
"⚠️ Line 1: Violation Reason."
)
}

func testJSONReporter() {
XCTAssertEqual(
JSONReporter.generateReport(generateViolations()),
Expand Down

0 comments on commit d97632e

Please sign in to comment.