@@ -6,6 +6,7 @@ open System.IO
66open System.Text
77open FSharpLint.Framework
88open FSharpLint.Application
9+ open System.Linq
910
1011/// Output format the linter will use.
1112type private OutputFormat =
@@ -19,6 +20,12 @@ type private FileType =
1920 | File = 3
2021 | Source = 4
2122
23+ type private ExitCode =
24+ | Error = - 1
25+ | Success = 0
26+ | NoSuchRuleName = 1
27+ | NoSuggestedFix = 2
28+
2229let fileTypeHelp = " Input type the linter will run against. If this is not set, the file type will be inferred from the file extension."
2330
2431// Allowing underscores in union case names for proper Argu command line option formatting.
@@ -90,7 +97,7 @@ let private inferFileType (target:string) =
9097 FileType.Source
9198
9299let private start ( arguments : ParseResults < ToolArgs >) ( toolsPath : Ionide.ProjInfo.Types.ToolsPath ) =
93- let mutable exitCode = 0
100+ let mutable exitCode = ExitCode.Success
94101
95102 let output =
96103 match arguments.TryGetResult Format with
@@ -99,9 +106,9 @@ let private start (arguments:ParseResults<ToolArgs>) (toolsPath:Ionide.ProjInfo.
99106 | Some _
100107 | None -> Output.StandardOutput() :> Output.IOutput
101108
102- let handleError ( str : string ) =
109+ let handleError ( status : ExitCode ) ( str : string ) =
103110 output.WriteError str
104- exitCode <- - 1
111+ exitCode <- status
105112
106113 let outputWarnings ( warnings : List < Suggestion.LintWarning >) =
107114 String.Format( Resources.GetString " ConsoleFinished" , List.length warnings)
@@ -111,25 +118,45 @@ let private start (arguments:ParseResults<ToolArgs>) (toolsPath:Ionide.ProjInfo.
111118 | LintResult.Success warnings ->
112119 outputWarnings warnings
113120 if List.isEmpty warnings |> not then
114- exitCode <- - 1
115- | LintResult.Failure failure -> handleError failure.Description
121+ exitCode <- ExitCode.Error
122+ | LintResult.Failure failure -> handleError ExitCode.Error failure.Description
116123
117124 let handleFixResult ( ruleName : string ) = function
118125 | LintResult.Success warnings ->
119126 Resources.GetString " ConsoleApplyingSuggestedFixFile" |> output.WriteInfo
120- List.iter ( fun ( element : Suggestion.LintWarning ) ->
121- let sourceCode = File.ReadAllText element.FilePath
122- match element.Details.SuggestedFix with
123- | Some suggestedFix when String.Equals( ruleName, element.RuleName, StringComparison.InvariantCultureIgnoreCase) ->
124- suggestedFix.Force()
125- |> Option.map ( fun suggestedFix ->
126- let updatedSourceCode = sourceCode.Replace( suggestedFix.FromText, suggestedFix.ToText)
127- File.WriteAllText( element.FilePath, updatedSourceCode, Encoding.UTF8)) |> ignore
128- | _ -> ()) warnings
127+ let increment = 1
128+ let noFixIncrement = 0
129+ let countSuggestedFix =
130+ List.fold ( fun acc elem -> acc + elem) 0 (
131+ List.map ( fun ( element : Suggestion.LintWarning ) ->
132+ let sourceCode = File.ReadAllText element.FilePath
133+ if String.Equals( ruleName, element.RuleName, StringComparison.InvariantCultureIgnoreCase) then
134+ match element.Details.SuggestedFix with
135+ | Some suggestedFix ->
136+ suggestedFix.Force()
137+ |> Option.map ( fun suggestedFix ->
138+ let updatedSourceCode =
139+ sourceCode.Replace(
140+ suggestedFix.FromText,
141+ suggestedFix.ToText
142+ )
143+ File.WriteAllText(
144+ element.FilePath,
145+ updatedSourceCode,
146+ Encoding.UTF8)
147+ )
148+ |> ignore |> fun () -> increment
149+ | None -> noFixIncrement
150+ else
151+ noFixIncrement) warnings)
129152 outputWarnings warnings
130- if List.isEmpty warnings |> not then
131- exitCode <- 0
132- | LintResult.Failure failure -> handleError failure.Description
153+
154+ if countSuggestedFix > 0 then
155+ exitCode <- ExitCode.Success
156+ else
157+ exitCode <- ExitCode.NoSuggestedFix
158+
159+ | LintResult.Failure failure -> handleError ExitCode.Error failure.Description
133160
134161 let linting fileType lintParams target toolsPath shouldFix maybeRuleName =
135162 try
@@ -143,14 +170,14 @@ let private start (arguments:ParseResults<ToolArgs>) (toolsPath:Ionide.ProjInfo.
143170 if shouldFix then
144171 match maybeRuleName with
145172 | Some ruleName -> handleFixResult ruleName lintResult
146- | None -> exitCode <- 1
173+ | None -> exitCode <- ExitCode.NoSuchRuleName
147174 else
148175 handleLintResult lintResult
149176 with
150177 | e ->
151178 let target = if fileType = FileType.Source then " source" else target
152179 sprintf " Lint failed while analysing %s .\n Failed with: %s \n Stack trace: %s " target e.Message e.StackTrace
153- |> handleError
180+ |> ( handleError ExitCode.Error )
154181
155182 let getParams config =
156183 let paramConfig =
@@ -176,15 +203,33 @@ let private start (arguments:ParseResults<ToolArgs>) (toolsPath:Ionide.ProjInfo.
176203 let fixParams = getParams None
177204 let ruleName , target = fixArgs.GetResult Fix_ Target
178205 let fileType = fixArgs.TryGetResult Fix_ File_ Type |> Option.defaultValue ( inferFileType target)
179-
180- linting fileType fixParams target toolsPath true ( Some ruleName)
206+
207+ let allRules =
208+ match getConfig fixParams.Configuration with
209+ | Ok config -> Some ( Configuration.flattenConfig config false )
210+ | _ -> None
211+
212+ let allRuleNames =
213+ match allRules with
214+ | Some rules -> ( fun ( loadedRules : Configuration.LoadedRules ) -> ([|
215+ loadedRules.LineRules.IndentationRule |> Option.map ( fun rule -> rule.Name) |> Option.toArray
216+ loadedRules.LineRules.NoTabCharactersRule |> Option.map ( fun rule -> rule.Name) |> Option.toArray
217+ loadedRules.LineRules.GenericLineRules |> Array.map ( fun rule -> rule.Name)
218+ loadedRules.AstNodeRules |> Array.map ( fun rule -> rule.Name)
219+ |] |> Array.concat |> Set.ofArray)) rules
220+ | _ -> Set.empty
221+
222+ if allRuleNames.Any( fun aRuleName -> String.Equals( aRuleName, ruleName, StringComparison.InvariantCultureIgnoreCase)) then
223+ linting fileType fixParams target toolsPath true ( Some ruleName)
224+ else
225+ sprintf " Rule '%s ' does not exist." ruleName |> ( handleError ExitCode.NoSuchRuleName)
181226
182227 match arguments.GetSubCommand() with
183228 | Lint lintArgs -> applyLint lintArgs
184229 | Fix fixArgs -> applySuggestedFix fixArgs
185230 | _ -> ()
186231
187- exitCode
232+ int exitCode
188233
189234/// Must be called only once per process.
190235/// We're calling it globally so we can call main multiple times from our tests.
0 commit comments