Skip to content

Commit

Permalink
Merge pull request #185 from realm/jp-rule-description
Browse files Browse the repository at this point in the history
Perform major refactor of rule description, identifiers and examples
  • Loading branch information
jpsim committed Nov 4, 2015
2 parents 921d666 + dcdc805 commit b3624c4
Show file tree
Hide file tree
Showing 37 changed files with 511 additions and 653 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

##### Breaking

* None.
* API: Rename RuleExample to RuleDescription, remove StyleViolationType and
combine Rule().identifier and Rule().example into Rule.description.
[JP Simard](https://github.com/jpsim)
[#183](https://github.com/realm/SwiftLint/issues/183)

##### Enhancements

Expand Down
18 changes: 10 additions & 8 deletions Source/SwiftLintFramework/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,17 @@ public struct Configuration {
included: [String] = [],
excluded: [String] = [],
reporter: String = "xcode",
rules: [Rule] = Configuration.rulesFromYAML(nil)) {
rules: [Rule] = Configuration.rulesFromYAML()) {
self.disabledRules = disabledRules
self.included = included
self.excluded = excluded
self.reporter = reporter

// Validate that all rule identifiers map to a defined rule

let validRuleIdentifiers = Configuration.rulesFromYAML(nil).map { $0.identifier }
let validRuleIdentifiers = Configuration.rulesFromYAML().map {
$0.dynamicType.description.identifier
}

let ruleSet = Set(disabledRules)
let invalidRules = ruleSet.filter({ !validRuleIdentifiers.contains($0) })
Expand Down Expand Up @@ -79,7 +81,7 @@ public struct Configuration {
return nil
}

self.rules = rules.filter { !disabledRules.contains($0.identifier) }
self.rules = rules.filter { !disabledRules.contains($0.dynamicType.description.identifier) }
}

public init?(yaml: String) {
Expand Down Expand Up @@ -125,9 +127,9 @@ public struct Configuration {
}
}

public static func rulesFromYAML(yaml: Yaml?) -> [Rule] {
public static func rulesFromYAML(yaml: Yaml? = nil) -> [Rule] {
var rules = [Rule]()
if let params = yaml?[.String(LineLengthRule().identifier)].arrayOfInts {
if let params = yaml?[.String(LineLengthRule.description.identifier)].arrayOfInts {
rules.append(LineLengthRule(parameters: ruleParametersFromArray(params)))
} else {
rules.append(LineLengthRule())
Expand All @@ -138,7 +140,7 @@ public struct Configuration {
rules.append(TrailingNewlineRule())
rules.append(OperatorFunctionWhitespaceRule())
rules.append(ForceCastRule())
if let params = yaml?[.String(FileLengthRule().identifier)].arrayOfInts {
if let params = yaml?[.String(FileLengthRule.description.identifier)].arrayOfInts {
rules.append(FileLengthRule(parameters: ruleParametersFromArray(params)))
} else {
rules.append(FileLengthRule())
Expand All @@ -147,12 +149,12 @@ public struct Configuration {
rules.append(ColonRule())
rules.append(TypeNameRule())
rules.append(VariableNameRule())
if let params = yaml?[.String(TypeBodyLengthRule().identifier)].arrayOfInts {
if let params = yaml?[.String(TypeBodyLengthRule.description.identifier)].arrayOfInts {
rules.append(TypeBodyLengthRule(parameters: ruleParametersFromArray(params)))
} else {
rules.append(TypeBodyLengthRule())
}
if let params = yaml?[.String(FunctionBodyLengthRule().identifier)].arrayOfInts {
if let params = yaml?[.String(FunctionBodyLengthRule.description.identifier)].arrayOfInts {
rules.append(FunctionBodyLengthRule(parameters: ruleParametersFromArray(params)))
} else {
rules.append(FunctionBodyLengthRule())
Expand Down
9 changes: 3 additions & 6 deletions Source/SwiftLintFramework/Linter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,13 @@ public struct Linter {
}).first else {
return true
}
return !violationRegion.disabledRuleIdentifiers.contains(rule.identifier)
return !violationRegion.disabledRuleIdentifiers.contains(
rule.dynamicType.description.identifier
)
}
}
}

/**
Initialize a Linter by passing in a File.

:param: file File to lint.
*/
public init(file: File, configuration: Configuration = Configuration()!) {
self.file = file
rules = configuration.rules
Expand Down
4 changes: 2 additions & 2 deletions Source/SwiftLintFramework/Reporters/CSVReporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ public struct CSVReporter: Reporter {
violation.location.line,
violation.location.character,
violation.severity.rawValue,
violation.type.description,
violation.ruleDescription.name,
violation.reason,
violation.ruleId
violation.ruleDescription.identifier
]
return values.map({ $0?.description ?? "" })
}
Expand Down
4 changes: 2 additions & 2 deletions Source/SwiftLintFramework/Reporters/JSONReporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public struct JSONReporter: Reporter {
"line": violation.location.line ?? NSNull(),
"character": violation.location.character ?? NSNull(),
"severity": violation.severity.rawValue,
"type": violation.type.description,
"rule_id": violation.ruleId ?? NSNull(),
"type": violation.ruleDescription.name,
"rule_id": violation.ruleDescription.identifier,
"reason": violation.reason ?? NSNull()
]
}
Expand Down
4 changes: 2 additions & 2 deletions Source/SwiftLintFramework/Reporters/XcodeReporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public struct XcodeReporter: Reporter {
// {full_path_to_file}{:line}{:character}: {error,warning}: {content}
return "\(violation.location): " +
"\(violation.severity.rawValue.lowercaseString): " +
"\(violation.type) Violation: " +
"\(violation.ruleDescription.name) Violation: " +
(violation.reason ?? "") + " " +
"(" + (violation.ruleId ?? "") + ")"
"(" + (violation.ruleDescription.identifier) + ")"
}
}
3 changes: 1 addition & 2 deletions Source/SwiftLintFramework/Rule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ import SourceKittenFramework

public protocol Rule {
init()
var identifier: String { get }
static var description: RuleDescription { get }
func validateFile(file: File) -> [StyleViolation]
var example: RuleExample { get }
}

public protocol ParameterizedRule: Rule {
Expand Down
31 changes: 31 additions & 0 deletions Source/SwiftLintFramework/RuleDescription.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// RuleDescription.swift
// SwiftLint
//
// Created by Chris Eidhof on 25/05/15.
// Copyright (c) 2015 Realm. All rights reserved.
//

public struct RuleDescription: Equatable {
public let identifier: String
public let name: String
public let description: String
public let nonTriggeringExamples: [String]
public let triggeringExamples: [String]

public init(identifier: String, name: String, description: String,
nonTriggeringExamples: [String] = [],
triggeringExamples: [String] = []) {
self.identifier = identifier
self.name = name
self.description = description
self.nonTriggeringExamples = nonTriggeringExamples
self.triggeringExamples = triggeringExamples
}
}

// MARK: Equatable

public func == (lhs: RuleDescription, rhs: RuleDescription) -> Bool {
return lhs.identifier == rhs.identifier
}
27 changes: 0 additions & 27 deletions Source/SwiftLintFramework/RuleExample.swift

This file was deleted.

35 changes: 16 additions & 19 deletions Source/SwiftLintFramework/Rules/ColonRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,10 @@ import SourceKittenFramework
public struct ColonRule: Rule {
public init() {}

public let identifier = "colon"

public func validateFile(file: File) -> [StyleViolation] {
let pattern1 = file.matchPattern("\\w+\\s+:\\s*\\S+",
withSyntaxKinds: [.Identifier, .Typeidentifier])
let pattern2 = file.matchPattern("\\w+:(?:\\s{0}|\\s{2,})\\S+",
withSyntaxKinds: [.Identifier, .Typeidentifier])
return (pattern1 + pattern2).map { range in
return StyleViolation(type: .Colon,
location: Location(file: file, offset: range.location),
severity: .Warning,
ruleId: self.identifier,
reason: "When specifying a type, always associate the colon with the identifier")
}
}

public let example = RuleExample(
ruleName: "Colon Rule",
ruleDescription: "This rule checks whether you associate the colon with the identifier.",
public static let description = RuleDescription(
identifier: "colon",
name: "Colon",
description: "This rule checks whether you associate the colon with the identifier.",
nonTriggeringExamples: [
"let abc: Void\n",
"let abc: [Void: Void]\n",
Expand All @@ -48,4 +33,16 @@ public struct ColonRule: Rule {
"func abc(def : Void) {}\n"
]
)

public func validateFile(file: File) -> [StyleViolation] {
let pattern1 = file.matchPattern("\\w+\\s+:\\s*\\S+",
withSyntaxKinds: [.Identifier, .Typeidentifier])
let pattern2 = file.matchPattern("\\w+:(?:\\s{0}|\\s{2,})\\S+",
withSyntaxKinds: [.Identifier, .Typeidentifier])
return (pattern1 + pattern2).map { range in
return StyleViolation(ruleDescription: self.dynamicType.description,
location: Location(file: file, offset: range.location),
reason: "When specifying a type, always associate the colon with the identifier")
}
}
}
38 changes: 17 additions & 21 deletions Source/SwiftLintFramework/Rules/CommaRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,12 @@ import Foundation
import SourceKittenFramework

public struct CommaRule: Rule {
public init() { }
public let identifier = "comma"
public init() {}

public func validateFile(file: File) -> [StyleViolation] {
let pattern = "(\\,[^\\s])|(\\s\\,)"
let excludingKinds = [SyntaxKind.Comment, .CommentMark, .CommentURL,
.DocComment, .DocCommentField, .String]

return file.matchPattern(pattern, excludingSyntaxKinds: excludingKinds).flatMap { match in
return StyleViolation(type: .Comma,
location: Location(file: file, offset: match.location),
severity: .Warning,
ruleId: self.identifier,
reason: "One space before and no after must be present next to " +
"commas")
}
}

public let example = RuleExample(
ruleName: "Comma Spacing Rule",
ruleDescription: "One space before and no after must be present next to " +
"any comma.",
public static let description = RuleDescription(
identifier: "comma",
name: "Comma Spacing",
description: "One space before and no after must be present next to any comma.",
nonTriggeringExamples: [
"func abc(a: String, b: String) { }",
"abc(a: \"string\", b: \"string\"",
Expand All @@ -43,4 +27,16 @@ public struct CommaRule: Rule {
"enum a { case a ,b }"
]
)

public func validateFile(file: File) -> [StyleViolation] {
let pattern = "(\\,[^\\s])|(\\s\\,)"
let excludingKinds: [SyntaxKind] = [.Comment, .CommentMark, .CommentURL,
.DocComment, .DocCommentField, .String]

return file.matchPattern(pattern, excludingSyntaxKinds: excludingKinds).flatMap { match in
return StyleViolation(ruleDescription: self.dynamicType.description,
location: Location(file: file, offset: match.location),
reason: "One space before and no after must be present next to commas")
}
}
}
48 changes: 22 additions & 26 deletions Source/SwiftLintFramework/Rules/ControlStatementRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,10 @@ import SourceKittenFramework
public struct ControlStatementRule: Rule {
public init() {}

public let identifier = "control_statement"

public func validateFile(file: File) -> [StyleViolation] {
let statements = ["if", "for", "guard", "switch", "while"]
return statements.flatMap { statementKind -> [StyleViolation] in
let pattern = statementKind == "guard"
? "\(statementKind)\\s*\\([^,]*\\)\\s*else\\s*\\{"
: "\(statementKind)\\s*\\([^,]*\\)\\s*\\{"
return file.matchPattern(pattern).flatMap { match, syntaxKinds in
if syntaxKinds.first != .Keyword {
return nil
}
return StyleViolation(type: .ControlStatement,
location: Location(file: file, offset: match.location),
severity: .Warning,
ruleId: self.identifier,
reason: "\(statementKind) statements shouldn't wrap their conditionals in " +
"parentheses.")
}
}
}

public let example = RuleExample(
ruleName: "Control Statement Rule",
ruleDescription: "if,for,while,do statements shouldn't wrap their conditionals in " +
"parentheses.",
public static let description = RuleDescription(
identifier: "control_statement",
name: "Control Statement",
description: "if,for,while,do statements shouldn't wrap their conditionals in parentheses.",
nonTriggeringExamples: [
"if condition {\n",
"if (a, b) == (0, 1) {\n",
Expand Down Expand Up @@ -69,4 +47,22 @@ public struct ControlStatementRule: Rule {
"switch (foo) {\n",
]
)

public func validateFile(file: File) -> [StyleViolation] {
let statements = ["if", "for", "guard", "switch", "while"]
return statements.flatMap { statementKind -> [StyleViolation] in
let pattern = statementKind == "guard"
? "\(statementKind)\\s*\\([^,]*\\)\\s*else\\s*\\{"
: "\(statementKind)\\s*\\([^,]*\\)\\s*\\{"
return file.matchPattern(pattern).flatMap { match, syntaxKinds in
if syntaxKinds.first != .Keyword {
return nil
}
return StyleViolation(ruleDescription: self.dynamicType.description,
location: Location(file: file, offset: match.location),
reason: "\(statementKind) statements shouldn't wrap their conditionals in " +
"parentheses.")
}
}
}
}
21 changes: 8 additions & 13 deletions Source/SwiftLintFramework/Rules/FileLengthRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,25 @@ public struct FileLengthRule: ParameterizedRule {
self.parameters = parameters
}

public let identifier = "file_length"

public let parameters: [RuleParameter<Int>]

public static let description = RuleDescription(
identifier: "file_length",
name: "File Line Length",
description: "Enforce maximum file length"
)

public func validateFile(file: File) -> [StyleViolation] {
let lineCount = file.lines.count
for parameter in parameters.reverse() {
if lineCount > parameter.value {
return [StyleViolation(type: .Length,
location: Location(file: file.path, line: lineCount),
return [StyleViolation(ruleDescription: self.dynamicType.description,
severity: parameter.severity,
ruleId: self.identifier,
location: Location(file: file.path, line: lineCount),
reason: "File should contain \(parameters.first!.value) lines or less: " +
"currently contains \(lineCount)")]
}
}
return []
}

public let example = RuleExample(
ruleName: "File Line Length Rule",
ruleDescription: "Enforce maximum file length",
nonTriggeringExamples: [],
triggeringExamples: [],
showExamples: false
)
}
Loading

0 comments on commit b3624c4

Please # to comment.