<commit_before>import Foundation
import SourceKittenFramework

private extension File {
    func violatingTrailingSemicolonRanges() -> [NSRange] {
        return match(pattern: "(;+([^\\S\\n]?)*)+;?$",
                     excludingSyntaxKinds: SyntaxKind.commentAndStringKinds)
    }
}

public struct TrailingSemicolonRule: CorrectableRule, ConfigurationProviderRule, AutomaticTestableRule {
    public var configuration = SeverityConfiguration(.warning)

    public init() {}

    public static let description = RuleDescription(
        identifier: "trailing_semicolon",
        name: "Trailing Semicolon",
        description: "Lines should not have trailing semicolons.",
        kind: .idiomatic,
        nonTriggeringExamples: [ "let a = 0\n" ],
        triggeringExamples: [
            "let a = 0↓;\n",
            "let a = 0↓;\nlet b = 1\n",
            "let a = 0↓;;\n",
            "let a = 0↓;    ;;\n",
            "let a = 0↓; ; ;\n"
        ],
        corrections: [
            "let a = 0↓;\n": "let a = 0\n",
            "let a = 0↓;\nlet b = 1\n": "let a = 0\nlet b = 1\n",
            "let a = 0↓;;\n": "let a = 0\n",
            "let a = 0↓;    ;;\n": "let a = 0\n",
            "let a = 0↓; ; ;\n": "let a = 0\n"
        ]
    )

    public func validate(file: File) -> [StyleViolation] {
        return file.violatingTrailingSemicolonRanges().map {
            StyleViolation(ruleDescription: type(of: self).description,
                           severity: configuration.severity,
                           location: Location(file: file, characterOffset: $0.location))
        }
    }

    public func correct(file: File) -> [Correction] {
        let violatingRanges = file.ruleEnabled(violatingRanges: file.violatingTrailingSemicolonRanges(), for: self)
        let adjustedRanges = violatingRanges.reduce([NSRange]()) { adjustedRanges, element in
            let adjustedLocation = element.location - adjustedRanges.count
            let adjustedRange = NSRange(location: adjustedLocation, length: element.length)
            return adjustedRanges + [adjustedRange]
        }
        if adjustedRanges.isEmpty {
            return []
        }
        var correctedContents = file.contents
        for range in adjustedRanges {
            if let indexRange = correctedContents.nsrangeToIndexRange(range) {
                correctedContents = correctedContents
                    .replacingCharacters(in: indexRange, with: "")
            }
        }
        file.write(correctedContents)
        return adjustedRanges.map {
            Correction(ruleDescription: type(of: self).description,
                       location: Location(file: file, characterOffset: $0.location))
        }
    }
}<commit_msg>Migrate TrailingSemicolonRule<commit_after>import Foundation
import SourceKittenFramework

public struct TrailingSemicolonRule: SubstitutionCorrectableRule, ConfigurationProviderRule, AutomaticTestableRule {
    public var configuration = SeverityConfiguration(.warning)

    public init() {}

    public static let description = RuleDescription(
        identifier: "trailing_semicolon",
        name: "Trailing Semicolon",
        description: "Lines should not have trailing semicolons.",
        kind: .idiomatic,
        nonTriggeringExamples: [ "let a = 0\n" ],
        triggeringExamples: [
            "let a = 0↓;\n",
            "let a = 0↓;\nlet b = 1\n",
            "let a = 0↓;;\n",
            "let a = 0↓;    ;;\n",
            "let a = 0↓; ; ;\n"
        ],
        corrections: [
            "let a = 0↓;\n": "let a = 0\n",
            "let a = 0↓;\nlet b = 1\n": "let a = 0\nlet b = 1\n",
            "let a = 0↓;;\n": "let a = 0\n",
            "let a = 0↓;    ;;\n": "let a = 0\n",
            "let a = 0↓; ; ;\n": "let a = 0\n"
        ]
    )

    public func validate(file: File) -> [StyleViolation] {
        return violationRanges(in: file).map {
            StyleViolation(ruleDescription: type(of: self).description,
                           severity: configuration.severity,
                           location: Location(file: file, characterOffset: $0.location))
        }
    }

    public func violationRanges(in file: File) -> [NSRange] {
        return file.match(pattern: "(;+([^\\S\\n]?)*)+;?$",
                          excludingSyntaxKinds: SyntaxKind.commentAndStringKinds)
    }

    public func substitution(for violationRange: NSRange, in file: File) -> (NSRange, String) {
        return (violationRange, "")
    }
}
{'fraction_non_alphanumeric': 0.12605602489995554, 'fraction_numerical': 0.009115162294353045, 'mean_word_length': 2.0563858695652173, 'pattern_counts': {'":': 10, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '830019', 'n_tokens_mistral': 1366, 'n_tokens_neox': 1321, 'n_words': 322}