|
1 | | -import Commandant |
| 1 | +import ArgumentParser |
2 | 2 | import SwiftLintFramework |
3 | 3 |
|
4 | | -struct AnalyzeCommand: CommandProtocol { |
5 | | - let verb = "analyze" |
6 | | - let function = "[Experimental] Run analysis rules" |
| 4 | +extension SwiftLint { |
| 5 | + struct Analyze: ParsableCommand { |
| 6 | + static let configuration = CommandConfiguration(abstract: "Run analysis rules") |
7 | 7 |
|
8 | | - func run(_ options: AnalyzeOptions) -> Result<(), CommandantError<()>> { |
9 | | - let options = LintOrAnalyzeOptions(options) |
10 | | - if options.autocorrect { |
11 | | - return autocorrect(options) |
12 | | - } else { |
13 | | - return LintOrAnalyzeCommand.run(options) |
14 | | - } |
15 | | - } |
16 | | - |
17 | | - private func autocorrect(_ options: LintOrAnalyzeOptions) -> Result<(), CommandantError<()>> { |
18 | | - let storage = RuleStorage() |
19 | | - let configuration = Configuration(options: options) |
20 | | - return configuration.visitLintableFiles(options: options, cache: nil, storage: storage) { linter in |
21 | | - let corrections = linter.correct(using: storage) |
22 | | - if !corrections.isEmpty && !options.quiet { |
23 | | - let correctionLogs = corrections.map({ $0.consoleDescription }) |
24 | | - queuedPrint(correctionLogs.joined(separator: "\n")) |
25 | | - } |
26 | | - }.flatMap { files in |
27 | | - if !options.quiet { |
28 | | - let pluralSuffix = { (collection: [Any]) -> String in |
29 | | - return collection.count != 1 ? "s" : "" |
30 | | - } |
31 | | - queuedPrintError("Done correcting \(files.count) file\(pluralSuffix(files))!") |
32 | | - } |
33 | | - return .success(()) |
34 | | - } |
35 | | - } |
36 | | -} |
| 8 | + @OptionGroup |
| 9 | + var common: LintOrAnalyzeArguments |
| 10 | + @Option(help: pathOptionDescription(for: .analyze)) |
| 11 | + var path: String? |
| 12 | + @Flag(help: quietOptionDescription(for: .analyze)) |
| 13 | + var quiet = false |
| 14 | + @Option(help: "The path of the full xcodebuild log to use when running AnalyzerRules.") |
| 15 | + var compilerLogPath: String? |
| 16 | + @Option(help: "The path of a compilation database to use when running AnalyzerRules.") |
| 17 | + var compileCommands: String? |
| 18 | + @Argument(help: pathsArgumentDescription(for: .analyze)) |
| 19 | + var paths = [String]() |
37 | 20 |
|
38 | | -struct AnalyzeOptions: OptionsProtocol { |
39 | | - let paths: [String] |
40 | | - let configurationFiles: [String] |
41 | | - let strict: Bool |
42 | | - let lenient: Bool |
43 | | - let forceExclude: Bool |
44 | | - let excludeByPrefix: Bool |
45 | | - let useScriptInputFiles: Bool |
46 | | - let benchmark: Bool |
47 | | - let reporter: String |
48 | | - let quiet: Bool |
49 | | - let enableAllRules: Bool |
50 | | - let autocorrect: Bool |
51 | | - let compilerLogPath: String |
52 | | - let compileCommands: String |
| 21 | + mutating func run() throws { |
| 22 | + let options = LintOrAnalyzeOptions( |
| 23 | + mode: .analyze, |
| 24 | + paths: paths + [path ?? ""], |
| 25 | + useSTDIN: false, |
| 26 | + configurationFiles: common.config, |
| 27 | + strict: common.strict, |
| 28 | + lenient: common.lenient, |
| 29 | + forceExclude: common.forceExclude, |
| 30 | + useExcludingByPrefix: common.useAlternativeExcluding, |
| 31 | + useScriptInputFiles: common.useScriptInputFiles, |
| 32 | + benchmark: common.benchmark, |
| 33 | + reporter: common.reporter, |
| 34 | + quiet: quiet, |
| 35 | + cachePath: nil, |
| 36 | + ignoreCache: true, |
| 37 | + enableAllRules: false, |
| 38 | + autocorrect: common.fix, |
| 39 | + compilerLogPath: compilerLogPath, |
| 40 | + compileCommands: compileCommands |
| 41 | + ) |
53 | 42 |
|
54 | | - // swiftlint:disable line_length |
55 | | - static func create(_ path: String) -> (_ configurationFiles: [String]) -> (_ strict: Bool) -> (_ lenient: Bool) -> (_ forceExclude: Bool) -> (_ excludeByPrefix: Bool) -> (_ useScriptInputFiles: Bool) -> (_ benchmark: Bool) -> (_ reporter: String) -> (_ quiet: Bool) -> (_ enableAllRules: Bool) -> (_ autocorrect: Bool) -> (_ compilerLogPath: String) -> (_ compileCommands: String) -> (_ paths: [String]) -> AnalyzeOptions { |
56 | | - return { configurationFiles in { strict in { lenient in { forceExclude in { excludeByPrefix in { useScriptInputFiles in { benchmark in { reporter in { quiet in { enableAllRules in { autocorrect in { compilerLogPath in { compileCommands in { paths in |
57 | | - let allPaths: [String] |
58 | | - if !path.isEmpty { |
59 | | - allPaths = [path] |
60 | | - } else { |
61 | | - allPaths = paths |
| 43 | + let result = LintOrAnalyzeCommand.run(options) |
| 44 | + switch result { |
| 45 | + case .success: |
| 46 | + return |
| 47 | + case .failure(let error): |
| 48 | + throw error |
62 | 49 | } |
63 | | - |
64 | | - return self.init(paths: allPaths, configurationFiles: configurationFiles, strict: strict, lenient: lenient, forceExclude: forceExclude, excludeByPrefix: excludeByPrefix, useScriptInputFiles: useScriptInputFiles, benchmark: benchmark, reporter: reporter, quiet: quiet, enableAllRules: enableAllRules, autocorrect: autocorrect, compilerLogPath: compilerLogPath, compileCommands: compileCommands) |
65 | | - // swiftlint:enable line_length |
66 | | - }}}}}}}}}}}}}} |
67 | | - } |
68 | | - |
69 | | - static func evaluate(_ mode: CommandMode) -> Result<AnalyzeOptions, CommandantError<CommandantError<()>>> { |
70 | | - return create |
71 | | - <*> mode <| pathOption(action: "analyze") |
72 | | - <*> mode <| configOption |
73 | | - <*> mode <| Option(key: "strict", defaultValue: false, |
74 | | - usage: "upgrades warnings to serious violations (errors)") |
75 | | - <*> mode <| Option(key: "lenient", defaultValue: false, |
76 | | - usage: "downgrades serious violations to warnings, warning threshold is disabled") |
77 | | - <*> mode <| Option(key: "force-exclude", defaultValue: false, |
78 | | - usage: "exclude files in config `excluded` even if their paths are explicitly specified") |
79 | | - <*> mode <| useAlternativeExcludingOption |
80 | | - <*> mode <| useScriptInputFilesOption |
81 | | - <*> mode <| Option(key: "benchmark", defaultValue: false, |
82 | | - usage: "save benchmarks to benchmark_files.txt " + |
83 | | - "and benchmark_rules.txt") |
84 | | - <*> mode <| Option(key: "reporter", defaultValue: "", |
85 | | - usage: "the reporter used to log errors and warnings") |
86 | | - <*> mode <| quietOption(action: "linting") |
87 | | - <*> mode <| Option(key: "enable-all-rules", defaultValue: false, |
88 | | - usage: "run all rules, even opt-in and disabled ones, ignoring `only_rules`") |
89 | | - <*> mode <| Option(key: "autocorrect", defaultValue: false, |
90 | | - usage: "correct violations whenever possible") |
91 | | - <*> mode <| Option(key: "compiler-log-path", defaultValue: "", |
92 | | - usage: "the path of the full xcodebuild log to use when linting AnalyzerRules") |
93 | | - <*> mode <| Option(key: "compile-commands", defaultValue: "", |
94 | | - usage: "the path of a compilation database to use when linting AnalyzerRules") |
95 | | - // This should go last to avoid eating other args |
96 | | - <*> mode <| pathsArgument(action: "analyze") |
| 50 | + } |
97 | 51 | } |
98 | 52 | } |
0 commit comments