Skip to content

Commit

Permalink
Add ability to filter rules for generate-docs subcommand (realm#4195)
Browse files Browse the repository at this point in the history
Added rules filtering options, like in the `rules` subcommand.

<img width="880" alt="generate-docs--help" src="https://user-images.githubusercontent.com/7829589/189372666-2f5aba62-57a1-49dc-9155-c60f9e085984.png">

To achieve reuse with `rules` subcommand:
- extracted filtering logic into `RulesFilter` (and write tests)
- extracted filtering command line parameters into `RulesFilterOptions: ParsableArguments`
  • Loading branch information
kattouf authored Oct 4, 2022
1 parent c70510c commit 129a55f
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 46 deletions.
13 changes: 11 additions & 2 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ swift_library(
}),
)

swift_binary(
name = "swiftlint",
swift_library(
name = "swiftlint.library",
module_name = "swiftlint",
srcs = glob(["Source/swiftlint/**/*.swift"]),
visibility = ["//visibility:public"],
deps = [
Expand All @@ -43,6 +44,14 @@ swift_binary(
],
)

swift_binary(
name = "swiftlint",
visibility = ["//visibility:public"],
deps = [
":swiftlint.library",
],
)

# Linting

filegroup(
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
[JP Simard](https://github.com/jpims)
[#4031](https://github.com/realm/SwiftLint/issues/4031)

* Add ability to filter rules for `generate-docs` subcommand.
[kattouf](https://github.com/kattouf)

* Add new `excludes_trivial_init` configuration for `missing_docs` rule
to exclude initializers without any parameters.
[Marcelo Fabri](https://github.com/marcelofabri)
Expand Down
6 changes: 6 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ let package = Package(
"SwiftyTextTable",
]
),
.testTarget(
name: "CLITests",
dependencies: [
"swiftlint"
]
),
.target(
name: "SwiftLintFramework",
dependencies: frameworkDependencies
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
extension RulesFilter.ExcludingOptions {
static func excludingOptions(byCommandLineOptions rulesFilterOptions: RulesFilterOptions) -> Self {
var excludingOptions: Self = []

switch rulesFilterOptions.ruleEnablement {
case .enabled:
excludingOptions.insert(.disabled)
case .disabled:
excludingOptions.insert(.enabled)
case .none:
break
}

if rulesFilterOptions.correctable {
excludingOptions.insert(.uncorrectable)
}

return excludingOptions
}
}
20 changes: 20 additions & 0 deletions Source/swiftlint/Commands/Common/RulesFilterOptions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import ArgumentParser

enum RuleEnablementOptions: String, EnumerableFlag {
case enabled, disabled

static func name(for value: RuleEnablementOptions) -> NameSpecification {
return .shortAndLong
}

static func help(for value: RuleEnablementOptions) -> ArgumentHelp? {
return "Only show \(value.rawValue) rules"
}
}

struct RulesFilterOptions: ParsableArguments {
@Flag(exclusivity: .exclusive)
var ruleEnablement: RuleEnablementOptions?
@Flag(name: .shortAndLong, help: "Only display correctable rules")
var correctable = false
}
13 changes: 11 additions & 2 deletions Source/swiftlint/Commands/GenerateDocs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ import SwiftLintFramework

extension SwiftLint {
struct GenerateDocs: ParsableCommand {
static let configuration = CommandConfiguration(abstract: "Generates markdown documentation for all rules")
static let configuration = CommandConfiguration(
abstract: "Generates markdown documentation for selected group of rules"
)

@Option(help: "The directory where the documentation should be saved")
var path = "rule_docs"
@Option(help: "The path to a SwiftLint configuration file")
var config: String?
@OptionGroup var rulesFilterOptions: RulesFilterOptions

func run() throws {
try RuleListDocumentation(primaryRuleList)
let configuration = Configuration(configurationFiles: [config].compactMap({ $0 }))
let rulesFilter = RulesFilter(enabledRules: configuration.rules)
let rules = rulesFilter.getRules(excluding: .excludingOptions(byCommandLineOptions: rulesFilterOptions))

try RuleListDocumentation(rules)
.write(to: URL(fileURLWithPath: path, isDirectory: true))
ExitHelper.successfullyExit()
}
Expand Down
44 changes: 3 additions & 41 deletions Source/swiftlint/Commands/Rules.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,13 @@ import Foundation
import SwiftLintFramework
import SwiftyTextTable

enum RuleEnablementOptions: String, EnumerableFlag {
case enabled, disabled

static func name(for value: RuleEnablementOptions) -> NameSpecification {
return .shortAndLong
}

static func help(for value: RuleEnablementOptions) -> ArgumentHelp? {
return "Only show \(value.rawValue) rules"
}
}

extension SwiftLint {
struct Rules: ParsableCommand {
static let configuration = CommandConfiguration(abstract: "Display the list of rules and their identifiers")

@Option(help: "The path to a SwiftLint configuration file")
var config: String?
@Flag(exclusivity: .exclusive)
var ruleEnablement: RuleEnablementOptions?
@Flag(name: .shortAndLong, help: "Only display correctable rules")
var correctable = false
@OptionGroup var rulesFilterOptions: RulesFilterOptions
@Flag(name: .shortAndLong, help: "Display full configuration details")
var verbose = false
@Argument(help: "The rule identifier to display description for")
Expand All @@ -48,35 +33,12 @@ extension SwiftLint {
}

let configuration = Configuration(configurationFiles: [config].compactMap({ $0 }))
let rules = ruleList(configuration: configuration)
let rulesFilter = RulesFilter(enabledRules: configuration.rules)
let rules = rulesFilter.getRules(excluding: .excludingOptions(byCommandLineOptions: rulesFilterOptions))
let table = TextTable(ruleList: rules, configuration: configuration, verbose: verbose)
print(table.render())
ExitHelper.successfullyExit()
}

private func ruleList(configuration: Configuration) -> RuleList {
guard ruleEnablement != nil || correctable else {
return primaryRuleList
}

let filtered: [Rule.Type] = primaryRuleList.list.compactMap { ruleID, ruleType in
let configuredRule = configuration.rules.first { rule in
return type(of: rule).description.identifier == ruleID
}

if ruleEnablement == .enabled && configuredRule == nil {
return nil
} else if ruleEnablement == .disabled && configuredRule != nil {
return nil
} else if correctable && !(configuredRule is CorrectableRule) {
return nil
}

return ruleType
}

return RuleList(rules: filtered)
}
}
}

Expand Down
48 changes: 48 additions & 0 deletions Source/swiftlint/Helpers/RulesFilter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import SwiftLintFramework

extension RulesFilter {
struct ExcludingOptions: OptionSet {
let rawValue: Int

static let enabled = ExcludingOptions(rawValue: 1 << 0)
static let disabled = ExcludingOptions(rawValue: 1 << 1)
static let uncorrectable = ExcludingOptions(rawValue: 1 << 2)
}
}

class RulesFilter {
private let allRules: RuleList
private let enabledRules: [Rule]

init(allRules: RuleList = primaryRuleList, enabledRules: [Rule]) {
self.allRules = allRules
self.enabledRules = enabledRules
}

func getRules(excluding excludingOptions: ExcludingOptions) -> RuleList {
if excludingOptions.isEmpty {
return allRules
}

let filtered: [Rule.Type] = allRules.list.compactMap { ruleID, ruleType in
let enabledRule = enabledRules.first { rule in
type(of: rule).description.identifier == ruleID
}
let isRuleEnabled = enabledRule != nil

if excludingOptions.contains(.enabled) && isRuleEnabled {
return nil
}
if excludingOptions.contains(.disabled) && !isRuleEnabled {
return nil
}
if excludingOptions.contains(.uncorrectable) && !(ruleType is CorrectableRule.Type) {
return nil
}

return ruleType
}

return RuleList(rules: filtered)
}
}
16 changes: 16 additions & 0 deletions Tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@ load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library", "swift_test")

exports_files(["BUILD"])

swift_library(
name = "CLITests.library",
testonly = True,
srcs = glob(["CLITests/**/*.swift"]),
module_name = "CLITests",
deps = [
"//:swiftlint.library",
],
)

swift_test(
name = "CLITests",
visibility = ["//visibility:public"],
deps = [":CLITests.library"],
)

filegroup(
name = "SwiftLintFrameworkTestsSources",
srcs = glob(
Expand Down
Loading

0 comments on commit 129a55f

Please sign in to comment.