<commit_before>import Foundation
import SourceKittenFramework

private let typeAndExtensionKinds = SwiftDeclarationKind.typeKinds + [.extension, .protocol]

private extension Dictionary where Key: ExpressibleByStringLiteral {
    func recursiveDeclaredTypeNames() -> [String] {
        let subNames = substructure.flatMap { $0.recursiveDeclaredTypeNames() }
        if let kind = kind.flatMap(SwiftDeclarationKind.init),
            typeAndExtensionKinds.contains(kind), let name = name {
            return [name] + subNames
        }
        return subNames
    }
}

public struct FileNameRule: ConfigurationProviderRule, OptInRule {
    public var configuration = FileNameConfiguration(
        severity: .warning,
        excluded: ["main.swift", "LinuxMain.swift"],
        prefixPattern: "",
        suffixPattern: "\\+.*"
    )

    public init() {}

    public static let description = RuleDescription(
        identifier: "file_name",
        name: "File Name",
        description: "File name should match a type or extension declared in the file (if any).",
        kind: .idiomatic
    )

    public func validate(file: File) -> [StyleViolation] {
        guard let filePath = file.path,
            case let fileName = filePath.bridge().lastPathComponent,
            !configuration.excluded.contains(fileName) else {
            return []
        }

        let prefixRegex = regex("\\A\(configuration.prefixPattern)")
        let suffixRegex = regex("\(configuration.suffixPattern)\\z")

        var typeInFileName = fileName.components(separatedBy: ".").first ?? fileName

        if let match = prefixRegex.firstMatch(in: typeInFileName, options: [], range: typeInFileName.fullNSRange) {
            if let range = typeInFileName.nsrangeToIndexRange(match.range) {
                typeInFileName.removeSubrange(range)
            }
        }

        if let match = suffixRegex.firstMatch(in: typeInFileName, options: [], range: typeInFileName.fullNSRange) {
            if let range = typeInFileName.nsrangeToIndexRange(match.range) {
                typeInFileName.removeSubrange(range)
            }
        }

        let allDeclaredTypeNames = file.structure.dictionary.recursiveDeclaredTypeNames()
        guard !allDeclaredTypeNames.isEmpty, !allDeclaredTypeNames.contains(typeInFileName) else {
            return []
        }

        return [StyleViolation(ruleDescription: type(of: self).description,
                               severity: configuration.severity.severity,
                               location: Location(file: filePath, line: 1))]
    }
}<commit_msg>Combine nested if-lets to single if-let<commit_after>import Foundation
import SourceKittenFramework

private let typeAndExtensionKinds = SwiftDeclarationKind.typeKinds + [.extension, .protocol]

private extension Dictionary where Key: ExpressibleByStringLiteral {
    func recursiveDeclaredTypeNames() -> [String] {
        let subNames = substructure.flatMap { $0.recursiveDeclaredTypeNames() }
        if let kind = kind.flatMap(SwiftDeclarationKind.init),
            typeAndExtensionKinds.contains(kind), let name = name {
            return [name] + subNames
        }
        return subNames
    }
}

public struct FileNameRule: ConfigurationProviderRule, OptInRule {
    public var configuration = FileNameConfiguration(
        severity: .warning,
        excluded: ["main.swift", "LinuxMain.swift"],
        prefixPattern: "",
        suffixPattern: "\\+.*"
    )

    public init() {}

    public static let description = RuleDescription(
        identifier: "file_name",
        name: "File Name",
        description: "File name should match a type or extension declared in the file (if any).",
        kind: .idiomatic
    )

    public func validate(file: File) -> [StyleViolation] {
        guard let filePath = file.path,
            case let fileName = filePath.bridge().lastPathComponent,
            !configuration.excluded.contains(fileName) else {
            return []
        }

        let prefixRegex = regex("\\A\(configuration.prefixPattern)")
        let suffixRegex = regex("\(configuration.suffixPattern)\\z")

        var typeInFileName = fileName.components(separatedBy: ".").first ?? fileName

        if let match = prefixRegex.firstMatch(in: typeInFileName, options: [], range: typeInFileName.fullNSRange),
            let range = typeInFileName.nsrangeToIndexRange(match.range) {
            typeInFileName.removeSubrange(range)
        }

        if let match = suffixRegex.firstMatch(in: typeInFileName, options: [], range: typeInFileName.fullNSRange),
            let range = typeInFileName.nsrangeToIndexRange(match.range) {
            typeInFileName.removeSubrange(range)
        }

        let allDeclaredTypeNames = file.structure.dictionary.recursiveDeclaredTypeNames()
        guard !allDeclaredTypeNames.isEmpty, !allDeclaredTypeNames.contains(typeInFileName) else {
            return []
        }

        return [StyleViolation(ruleDescription: type(of: self).description,
                               severity: configuration.severity.severity,
                               location: Location(file: filePath, line: 1))]
    }
}
{'fraction_non_alphanumeric': 0.09575289575289575, 'fraction_numerical': 0.0007722007722007722, 'mean_word_length': 2.674468085106383, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, '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': '6882431', 'n_tokens_mistral': 1355, 'n_tokens_neox': 1311, 'n_words': 309}