Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ If needed, pluralize to `Tasks`, `PRs` or `Authors` and list multiple entries se

## [Unreleased]
### Added
- None.
- Added new `repeatIfAutoCorrected` option to `checkFileContents` method to repeat the check if last run did any auto-corrections.
Issue: [#29](https://github.com/Flinesoft/AnyLint/issues/29) | PR: [#31](https://github.com/Flinesoft/AnyLint/pull/31) | Author: [Cihat Gündüz](https://github.com/Jeehut)
### Changed
- None.
### Deprecated
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ There's 3 more parameters you can optionally set if needed:
1. `excludeFilters`: Array of `Regex` objects to exclude from the file paths to check.
2. `autoCorrectReplacement`: Replacement string which can reference any capture groups in the `regex`.
3. `autoCorrectExamples`: Example structs with `before` and `after` for autocorrection validation.
4. `repeatIfAutoCorrected`: Repeat check if at least one auto-correction was applied in last run. Defaults to `false`.

The `excludeFilters` can be used alternatively to the `includeFilters` or alongside them. If used alongside, exclusion will take precedence over inclusion.

Expand Down
21 changes: 20 additions & 1 deletion Sources/AnyLint/Checkers/FileContentsChecker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ struct FileContentsChecker {
let regex: Regex
let filePathsToCheck: [String]
let autoCorrectReplacement: String?
let repeatIfAutoCorrected: Bool
}

extension FileContentsChecker: Checker {
Expand Down Expand Up @@ -85,6 +86,24 @@ extension FileContentsChecker: Checker {
Statistics.shared.checkedFiles(at: [filePath])
}

return violations.reversed()
violations = violations.reversed()

if repeatIfAutoCorrected && violations.contains(where: { $0.appliedAutoCorrection != nil }) {
log.message("Repeating check \(checkInfo) because auto-corrections were applied on last run.", level: .debug)

// only paths where auto-corrections were applied need to be re-checked
let filePathsToReCheck = Array(Set(violations.filter { $0.appliedAutoCorrection != nil }.map { $0.filePath! })).sorted()

let violationsOnRechecks = try FileContentsChecker(
checkInfo: checkInfo,
regex: regex,
filePathsToCheck: filePathsToReCheck,
autoCorrectReplacement: autoCorrectReplacement,
repeatIfAutoCorrected: repeatIfAutoCorrected
).performCheck()
violations.append(contentsOf: violationsOnRechecks)
}

return violations
}
}
7 changes: 5 additions & 2 deletions Sources/AnyLint/Lint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum Lint {
/// - excludeFilters: An array of regexes defining which files should be excluded from the check. Will ignore all files matching any of the given regexes. Takes precedence over includes.
/// - autoCorrectReplacement: A replacement string which can reference any capture groups in the `regex` to use for autocorrection.
/// - autoCorrectExamples: An array of example structs with a `before` and an `after` String object to check if autocorrection works properly.
/// - repeatIfAutoCorrected: Repeat check if at least one auto-correction was applied in last run. Defaults to `false`.
public static func checkFileContents(
checkInfo: CheckInfo,
regex: Regex,
Expand All @@ -22,7 +23,8 @@ public enum Lint {
includeFilters: [Regex] = [#".*"#],
excludeFilters: [Regex] = [],
autoCorrectReplacement: String? = nil,
autoCorrectExamples: [AutoCorrection] = []
autoCorrectExamples: [AutoCorrection] = [],
repeatIfAutoCorrected: Bool = false
) throws {
validate(regex: regex, matchesForEach: matchingExamples, checkInfo: checkInfo)
validate(regex: regex, doesNotMatchAny: nonMatchingExamples, checkInfo: checkInfo)
Expand Down Expand Up @@ -58,7 +60,8 @@ public enum Lint {
checkInfo: checkInfo,
regex: regex,
filePathsToCheck: filePathsToCheck,
autoCorrectReplacement: autoCorrectReplacement
autoCorrectReplacement: autoCorrectReplacement,
repeatIfAutoCorrected: repeatIfAutoCorrected
).performCheck()

Statistics.shared.found(violations: violations, in: checkInfo)
Expand Down
76 changes: 72 additions & 4 deletions Tests/AnyLintTests/Checkers/FileContentsCheckerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
@testable import Utility
import XCTest

// swiftlint:disable function_body_length

final class FileContentsCheckerTests: XCTestCase {
override func setUp() {
log = Logger(outputType: .test)
Expand All @@ -20,7 +22,8 @@ final class FileContentsCheckerTests: XCTestCase {
checkInfo: checkInfo,
regex: #"(let|var) \w+=\w+"#,
filePathsToCheck: filePathsToCheck,
autoCorrectReplacement: nil
autoCorrectReplacement: nil,
repeatIfAutoCorrected: false
).performCheck()

XCTAssertEqual(violations.count, 2)
Expand Down Expand Up @@ -50,7 +53,8 @@ final class FileContentsCheckerTests: XCTestCase {
checkInfo: checkInfo,
regex: #"(let|var) \w+=\w+"#,
filePathsToCheck: filePathsToCheck,
autoCorrectReplacement: nil
autoCorrectReplacement: nil,
repeatIfAutoCorrected: false
).performCheck()

XCTAssertEqual(violations.count, 2)
Expand Down Expand Up @@ -81,7 +85,8 @@ final class FileContentsCheckerTests: XCTestCase {
checkInfo: checkInfo,
regex: #"(let|var) \w+=\w+"#,
filePathsToCheck: filePathsToCheck,
autoCorrectReplacement: nil
autoCorrectReplacement: nil,
repeatIfAutoCorrected: false
).performCheck()

XCTAssertEqual(violations.count, 6)
Expand Down Expand Up @@ -130,7 +135,8 @@ final class FileContentsCheckerTests: XCTestCase {
checkInfo: checkInfo,
regex: #"(let|var) (\w+)\s*=\s*(\w+)"#,
filePathsToCheck: filePathsToCheck,
autoCorrectReplacement: "$1 $2 = $3"
autoCorrectReplacement: "$1 $2 = $3",
repeatIfAutoCorrected: false
).performCheck()

XCTAssertEqual(violations.count, 2)
Expand All @@ -146,4 +152,66 @@ final class FileContentsCheckerTests: XCTestCase {
XCTAssertEqual(violations[1].locationInfo!.charInLine, 1)
}
}

func testRepeatIfAutoCorrected() {
let temporaryFiles: [TemporaryFile] = [
(subpath: "Sources/Hello.swift", contents: "let x = 500\nvar y = 10000"),
(subpath: "Sources/World.swift", contents: "let x = 50000000\nvar y = 100000000000000"),
]

withTemporaryFiles(temporaryFiles) { filePathsToCheck in
let checkInfo = CheckInfo(id: "LongNumbers", hint: "Format long numbers with `_` after each triple of digits from the right.", severity: .warning)
let violations = try FileContentsChecker(
checkInfo: checkInfo,
regex: #"(?<!\d)(\d+)(\d{3})(?!\d)"#,
filePathsToCheck: filePathsToCheck,
autoCorrectReplacement: "$1_$2",
repeatIfAutoCorrected: true
).performCheck()

XCTAssertEqual(violations.count, 7)

XCTAssertEqual(violations[0].checkInfo, checkInfo)
XCTAssertEqual(violations[0].filePath, "\(tempDir)/Sources/Hello.swift")
XCTAssertEqual(violations[0].locationInfo!.line, 2)
XCTAssertEqual(violations[0].locationInfo!.charInLine, 9)
XCTAssertEqual(violations[0].appliedAutoCorrection!.after, "10_000")

XCTAssertEqual(violations[1].checkInfo, checkInfo)
XCTAssertEqual(violations[1].filePath, "\(tempDir)/Sources/World.swift")
XCTAssertEqual(violations[1].locationInfo!.line, 1)
XCTAssertEqual(violations[1].locationInfo!.charInLine, 9)
XCTAssertEqual(violations[1].appliedAutoCorrection!.after, "50000_000")

XCTAssertEqual(violations[2].checkInfo, checkInfo)
XCTAssertEqual(violations[2].filePath, "\(tempDir)/Sources/World.swift")
XCTAssertEqual(violations[2].locationInfo!.line, 2)
XCTAssertEqual(violations[2].locationInfo!.charInLine, 9)
XCTAssertEqual(violations[2].appliedAutoCorrection!.after, "100000000000_000")

XCTAssertEqual(violations[3].checkInfo, checkInfo)
XCTAssertEqual(violations[3].filePath, "\(tempDir)/Sources/World.swift")
XCTAssertEqual(violations[3].locationInfo!.line, 1)
XCTAssertEqual(violations[3].locationInfo!.charInLine, 9)
XCTAssertEqual(violations[3].appliedAutoCorrection!.after, "50_000")

XCTAssertEqual(violations[4].checkInfo, checkInfo)
XCTAssertEqual(violations[4].filePath, "\(tempDir)/Sources/World.swift")
XCTAssertEqual(violations[4].locationInfo!.line, 2)
XCTAssertEqual(violations[4].locationInfo!.charInLine, 9)
XCTAssertEqual(violations[4].appliedAutoCorrection!.after, "100000000_000")

XCTAssertEqual(violations[5].checkInfo, checkInfo)
XCTAssertEqual(violations[5].filePath, "\(tempDir)/Sources/World.swift")
XCTAssertEqual(violations[5].locationInfo!.line, 2)
XCTAssertEqual(violations[5].locationInfo!.charInLine, 9)
XCTAssertEqual(violations[5].appliedAutoCorrection!.after, "100000_000")

XCTAssertEqual(violations[6].checkInfo, checkInfo)
XCTAssertEqual(violations[6].filePath, "\(tempDir)/Sources/World.swift")
XCTAssertEqual(violations[6].locationInfo!.line, 2)
XCTAssertEqual(violations[6].locationInfo!.charInLine, 9)
XCTAssertEqual(violations[6].appliedAutoCorrection!.after, "100_000")
}
}
}