Skip to content

Commit 0969e1c

Browse files
committed
Initial implementation of allowed_types option for one-declaration-per-file rule
1 parent e1ac6f8 commit 0969e1c

File tree

3 files changed

+52
-4
lines changed

3 files changed

+52
-4
lines changed

Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDeclarationPerFileRule.swift

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import SwiftSyntax
22

33
@SwiftSyntaxRule(optIn: true)
44
struct OneDeclarationPerFileRule: Rule {
5-
var configuration = SeverityConfiguration<Self>(.warning)
6-
5+
var configuration = OneDeclarationPerFileConfiguration()
76
static let description = RuleDescription(
87
identifier: "one_declaration_per_file",
98
name: "One Declaration per File",
@@ -22,6 +21,18 @@ struct OneDeclarationPerFileRule: Rule {
2221
struct N {}
2322
}
2423
"""),
24+
Example("""
25+
enum Foo {
26+
}
27+
struct Bar {
28+
}
29+
""",
30+
configuration: ["allowed_types": ["enum", "struct"]]),
31+
Example("""
32+
struct Foo {}
33+
struct Bar {}
34+
""",
35+
configuration: ["allowed_types": ["struct"]]),
2536
],
2637
triggeringExamples: [
2738
Example("""
@@ -36,14 +47,24 @@ struct OneDeclarationPerFileRule: Rule {
3647
struct Foo {}
3748
↓struct Bar {}
3849
"""),
50+
Example("""
51+
struct Foo {}
52+
↓enum Bar {}
53+
""",
54+
configuration: ["allowed_types": ["protocol"]]),
3955
]
4056
)
4157
}
4258

4359
private extension OneDeclarationPerFileRule {
4460
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
61+
private let allowedTypes: Set<String>
4562
private var declarationVisited = false
4663
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
64+
override init(configuration: OneDeclarationPerFileConfiguration, file: SwiftLintFile) {
65+
allowedTypes = Set(configuration.enabledTypes.map(\.rawValue))
66+
super.init(configuration: configuration, file: file)
67+
}
4768

4869
override func visitPost(_ node: ActorDeclSyntax) {
4970
appendViolationIfNeeded(node: node.actorKeyword)
@@ -66,10 +87,10 @@ private extension OneDeclarationPerFileRule {
6687
}
6788

6889
func appendViolationIfNeeded(node: TokenSyntax) {
69-
if declarationVisited {
90+
defer { declarationVisited = true }
91+
if declarationVisited && !allowedTypes.contains(node.text) {
7092
violations.append(node.positionAfterSkippingLeadingTrivia)
7193
}
72-
declarationVisited = true
7394
}
7495
}
7596
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import SwiftLintCore
2+
3+
@AutoConfigParser
4+
struct OneDeclarationPerFileConfiguration: SeverityBasedRuleConfiguration {
5+
typealias Parent = OneDeclarationPerFileRule
6+
7+
@AcceptableByConfigurationElement
8+
enum AllowedType: String, CaseIterable {
9+
case `actor`
10+
case `class`
11+
case `enum`
12+
case `protocol`
13+
case `struct`
14+
static let all = Set(allCases)
15+
}
16+
17+
@ConfigurationElement(key: "severity")
18+
private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning)
19+
20+
@ConfigurationElement(key: "allowed_types")
21+
private(set) var allowedTypes: [AllowedType] = []
22+
23+
var enabledTypes: Set<AllowedType> {
24+
Set(self.allowedTypes)
25+
}
26+
}

Tests/IntegrationTests/default_rule_configurations.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ one_declaration_per_file:
788788
meta:
789789
opt-in: true
790790
correctable: false
791+
allowed_types: []
791792
opening_brace:
792793
severity: warning
793794
ignore_multiline_type_headers: false

0 commit comments

Comments
 (0)