SwiftLint/Source/SwiftLintFramework/Rules/Metrics/ClosureBodyLengthRule.swift

52 lines
2.2 KiB
Swift

import SourceKittenFramework
public struct ClosureBodyLengthRule: ASTRule, ConfigurationProviderRule, AutomaticTestableRule {
public var configuration = SeverityLevelsConfiguration(warning: 20, error: 100)
public init() {}
public static let description = RuleDescription(
identifier: "closure_body_length",
name: "Closure Body Length",
description: "Closure bodies should not span too many lines.",
kind: .metrics,
minSwiftVersion: .fourDotTwo,
isOptIn: true,
nonTriggeringExamples: ClosureBodyLengthRuleExamples.nonTriggeringExamples,
triggeringExamples: ClosureBodyLengthRuleExamples.triggeringExamples
)
// MARK: - ASTRule
public func validate(file: File,
kind: SwiftExpressionKind,
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
guard
kind == .closure,
let offset = dictionary.offset,
let bodyOffset = dictionary.bodyOffset,
let bodyLength = dictionary.bodyLength,
let startLine = file.contents.bridge().lineAndCharacter(forByteOffset: bodyOffset)?.line,
let endLine = file.contents.bridge().lineAndCharacter(forByteOffset: bodyOffset + bodyLength)?.line
else {
return []
}
return configuration.params.compactMap { parameter in
let (exceeds, lineCount) = file.exceedsLineCountExcludingCommentsAndWhitespace(startLine,
endLine,
parameter.value)
guard exceeds else { return nil }
let reason = "Closure body should span \(configuration.warning) lines or less "
+ "excluding comments and whitespace: currently spans \(lineCount) lines"
return StyleViolation(ruleDescription: type(of: self).description,
severity: parameter.severity,
location: Location(file: file, byteOffset: offset),
reason: reason)
}
}
}