Add new `sorted_enum_cases` rule (#4845)
This commit is contained in:
parent
58a07eb452
commit
b0cbb440c3
|
@ -42,6 +42,7 @@ disabled_rules:
|
|||
- prefixed_toplevel_constant
|
||||
- required_deinit
|
||||
- self_binding
|
||||
- sorted_enum_cases
|
||||
- strict_fileprivate
|
||||
- switch_case_on_newline
|
||||
- trailing_closure
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
|
||||
#### Enhancements
|
||||
|
||||
* None.
|
||||
* Add `sorted_enum_cases` rule which warns when enum cases are not sorted.
|
||||
[kimdv](https://github.com/kimdv)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
|
|
|
@ -179,6 +179,7 @@ let builtInRules: [Rule.Type] = [
|
|||
ShorthandOperatorRule.self,
|
||||
ShorthandOptionalBindingRule.self,
|
||||
SingleTestClassRule.self,
|
||||
SortedEnumCasesRule.self,
|
||||
SortedFirstLastRule.self,
|
||||
SortedImportsRule.self,
|
||||
StatementPositionRule.self,
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
import SwiftSyntax
|
||||
|
||||
struct SortedEnumCasesRule: ConfigurationProviderRule, SwiftSyntaxRule, OptInRule {
|
||||
var configuration = SeverityConfiguration(.warning)
|
||||
|
||||
init() {}
|
||||
|
||||
static let description = RuleDescription(
|
||||
identifier: "sorted_enum_cases",
|
||||
name: "Sorted Enum Cases",
|
||||
description: "Enum cases should be sorted",
|
||||
kind: .style,
|
||||
nonTriggeringExamples: [
|
||||
Example("""
|
||||
enum foo {
|
||||
case a
|
||||
case b
|
||||
case c
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
enum foo {
|
||||
case a, b, c
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
enum foo {
|
||||
case a
|
||||
case b, c
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
enum foo {
|
||||
case a(foo: Foo)
|
||||
case b(String), c
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
@frozen
|
||||
enum foo {
|
||||
case b
|
||||
case a
|
||||
case c, f, d
|
||||
}
|
||||
""")
|
||||
],
|
||||
triggeringExamples: [
|
||||
Example("""
|
||||
enum foo {
|
||||
↓case b
|
||||
↓case a
|
||||
case c
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
enum foo {
|
||||
case ↓b, ↓a, c
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
enum foo {
|
||||
↓case b, c
|
||||
↓case a
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
enum foo {
|
||||
case a
|
||||
case b, ↓d, ↓c
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
enum foo {
|
||||
case a(foo: Foo)
|
||||
case ↓c, ↓b(String)
|
||||
}
|
||||
""")
|
||||
]
|
||||
)
|
||||
|
||||
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
|
||||
Visitor(viewMode: .sourceAccurate)
|
||||
}
|
||||
}
|
||||
|
||||
private extension SortedEnumCasesRule {
|
||||
final class Visitor: ViolationsSyntaxVisitor {
|
||||
override var skippableDeclarations: [DeclSyntaxProtocol.Type] {
|
||||
return .allExcept(EnumDeclSyntax.self)
|
||||
}
|
||||
|
||||
override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind {
|
||||
guard !node.attributes.contains(attributeNamed: "frozen") else {
|
||||
return .skipChildren
|
||||
}
|
||||
|
||||
let cases = node.members.members.compactMap { $0.decl.as(EnumCaseDeclSyntax.self) }
|
||||
let sortedCases = cases
|
||||
.sorted(by: { $0.elements.first!.identifier.text < $1.elements.first!.identifier.text })
|
||||
|
||||
zip(sortedCases, cases).forEach { sortedCase, currentCase in
|
||||
if sortedCase.elements.first?.identifier.text != currentCase.elements.first?.identifier.text {
|
||||
violations.append(currentCase.positionAfterSkippingLeadingTrivia)
|
||||
}
|
||||
}
|
||||
|
||||
return .visitChildren
|
||||
}
|
||||
|
||||
override func visitPost(_ node: EnumCaseDeclSyntax) {
|
||||
let sortedElements = node.elements.sorted(by: { $0.identifier.text < $1.identifier.text })
|
||||
|
||||
zip(sortedElements, node.elements).forEach { sortedElement, currentElement in
|
||||
if sortedElement.identifier.text != currentElement.identifier.text {
|
||||
violations.append(currentElement.positionAfterSkippingLeadingTrivia)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1058,6 +1058,12 @@ class SingleTestClassRuleGeneratedTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
class SortedEnumCasesRuleGeneratedTests: XCTestCase {
|
||||
func testWithDefaultConfiguration() {
|
||||
verifyRule(SortedEnumCasesRule.description)
|
||||
}
|
||||
}
|
||||
|
||||
class SortedFirstLastRuleGeneratedTests: XCTestCase {
|
||||
func testWithDefaultConfiguration() {
|
||||
verifyRule(SortedFirstLastRule.description)
|
||||
|
|
Loading…
Reference in New Issue