Files
SwiftLint/Source/SwiftLintFramework/Rules/Style/TrailingNewlineRule.swift
T
Zev Eisenberg fcf848608e Add Inline test failure messages (#3040)
* Add Example wrapper in order to display test failures inline when running in Xcode.
* Stop using Swift 5.1-only features so we can compile on Xcode 10.2.
* Wrap strings in Example.
* Add Changelog entry.
* Wrap all examples in Example struct.
* Better and more complete capturing of line numbers.
* Fix broken test.
* Better test traceability.
* Address or disable linting warnings.
* Add documentation comments.
* Disable linter for a few cases.
* Limit mutability and add copy-and-mutate utility functions.
* Limit scope of mutability.
2020-02-02 10:35:37 +02:00

74 lines
2.4 KiB
Swift

import Foundation
import SourceKittenFramework
extension String {
private func countOfTrailingCharacters(in characterSet: CharacterSet) -> Int {
var count = 0
for char in unicodeScalars.lazy.reversed() {
if !characterSet.contains(char) {
break
}
count += 1
}
return count
}
fileprivate func trailingNewlineCount() -> Int? {
return countOfTrailingCharacters(in: .newlines)
}
}
public struct TrailingNewlineRule: CorrectableRule, ConfigurationProviderRule, SourceKitFreeRule {
public var configuration = SeverityConfiguration(.warning)
public init() {}
public static let description = RuleDescription(
identifier: "trailing_newline",
name: "Trailing Newline",
description: "Files should have a single trailing newline.",
kind: .style,
nonTriggeringExamples: [
Example("let a = 0\n")
],
triggeringExamples: [
Example("let a = 0"),
Example("let a = 0\n\n")
],
corrections: [
Example("let a = 0"): Example("let a = 0\n"),
Example("let b = 0\n\n"): Example("let b = 0\n"),
Example("let c = 0\n\n\n\n"): Example("let c = 0\n")
]
)
public func validate(file: SwiftLintFile) -> [StyleViolation] {
if file.contents.trailingNewlineCount() == 1 {
return []
}
return [StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
location: Location(file: file.path, line: max(file.lines.count, 1)))]
}
public func correct(file: SwiftLintFile) -> [Correction] {
guard let count = file.contents.trailingNewlineCount(), count != 1 else {
return []
}
guard let lastLineRange = file.lines.last?.range else {
return []
}
if file.ruleEnabled(violatingRanges: [lastLineRange], for: self).isEmpty {
return []
}
if count < 1 {
file.append("\n")
} else {
let index = file.contents.index(file.contents.endIndex, offsetBy: 1 - count)
file.write(file.contents[..<index])
}
let location = Location(file: file.path, line: max(file.lines.count, 1))
return [Correction(ruleDescription: type(of: self).description, location: location)]
}
}