@@ -22,9 +22,10 @@ type private FileType =
2222
2323type private ExitCode =
2424 | Error = - 1
25- | Success = 0
25+ | Success = 0 // for `fix` when the file is changed and for `fix --check` when there are no fixes available.
2626 | NoSuchRuleName = 1
27- | NoSuggestedFix = 2
27+ | NoSuggestedFix = 2 // only for fix (without --check)
28+ | FixExists = 3 //only for fix --check
2829
2930let fileTypeHelp = " Input type the linter will run against. If this is not set, the file type will be inferred from the file extension."
3031
6364and private FixArgs =
6465 | [<MainCommand; Mandatory>] Fix_ Target of ruleName : string * target : string
6566 | Fix_ File_ Type of FileType
67+ | Check
6668// fsharplint:enable UnionDefinitionIndentation
6769with
6870 interface IArgParserTemplate with
6971 member this.Usage =
7072 match this with
7173 | Fix_ Target _ -> " Rule name to be applied with suggestedFix and input to lint."
7274 | Fix_ File_ Type _ -> fileTypeHelp
75+ | Check _ -> " If passed to the fix command, the linter will only check if the fix is needed."
7376// fsharplint:enable UnionCasesNames
7477
7578let private parserProgress ( output : Output.IOutput ) = function
@@ -106,7 +109,7 @@ let private start (arguments:ParseResults<ToolArgs>) (toolsPath:Ionide.ProjInfo.
106109 | Some _
107110 | None -> Output.StandardOutput() :> Output.IOutput
108111
109- let handleError ( status : ExitCode ) ( str : string ) =
112+ let handleError ( status : ExitCode ) ( str : string ) =
110113 output.WriteError str
111114 exitCode <- status
112115
@@ -121,44 +124,64 @@ let private start (arguments:ParseResults<ToolArgs>) (toolsPath:Ionide.ProjInfo.
121124 exitCode <- ExitCode.Error
122125 | LintResult.Failure failure -> handleError ExitCode.Error failure.Description
123126
124- let handleFixResult ( ruleName : string ) = function
127+ let handleFixResult ( ruleName : string ) ( checkFlag : bool ) = function
125128 | LintResult.Success warnings ->
126- Resources.GetString " ConsoleApplyingSuggestedFixFile " |> output.WriteInfo
127- let increment = 1
129+ if checkFlag |> not then
130+ Resources.GetString " ConsoleApplyingSuggestedFixFile " |> output.WriteInfo
128131 let noFixIncrement = 0
129- let countSuggestedFix =
130- List.fold ( fun acc elem -> acc + elem) 0 (
132+ let foundFixIncrement = 1
133+ let noSuggestedFixIncrement = 2
134+ let countFixStatus =
135+ List.fold ( fun ( accNoFix , accFoundFix , accNoSuggestedFix ) elem ->
136+ if elem = noFixIncrement then
137+ ( accNoFix + 1 , accFoundFix, accNoSuggestedFix)
138+ elif elem = foundFixIncrement then
139+ ( accNoFix, accFoundFix + 1 , accNoSuggestedFix)
140+ elif elem = noSuggestedFixIncrement then
141+ ( accNoFix, accFoundFix, accNoSuggestedFix + 1 )
142+ else
143+ failwith " Code should never reach here!" ) ( 0 , 0 , 0 ) (
131144 List.map ( fun ( element : Suggestion.LintWarning ) ->
132145 let sourceCode = File.ReadAllText element.FilePath
133146 if String.Equals( ruleName, element.RuleName, StringComparison.InvariantCultureIgnoreCase) then
134147 match element.Details.SuggestedFix with
135148 | Some suggestedFix ->
136- suggestedFix.Force()
137- |> Option.map ( fun suggestedFix ->
138- let updatedSourceCode =
139- sourceCode.Replace(
140- suggestedFix.FromText,
141- suggestedFix.ToText
149+ (( fun checkFlag ->
150+ if not checkFlag then
151+ ( suggestedFix.Force()
152+ |> Option.map ( fun suggestedFix ->
153+ let updatedSourceCode =
154+ sourceCode.Replace(
155+ suggestedFix.FromText,
156+ suggestedFix.ToText
157+ )
158+ File.WriteAllText(
159+ element.FilePath,
160+ updatedSourceCode,
161+ Encoding.UTF8)
142162 )
143- File.WriteAllText(
144- element.FilePath,
145- updatedSourceCode,
146- Encoding.UTF8)
147- )
148- |> ignore |> fun () -> increment
149- | None -> noFixIncrement
163+ ) |> ignore
164+ else
165+ ()
166+ ) checkFlag)
167+ |> ignore |> fun () -> foundFixIncrement
168+ | None -> noSuggestedFixIncrement
150169 else
151170 noFixIncrement) warnings)
152171 outputWarnings warnings
153-
154- if countSuggestedFix > 0 then
172+ let ( accNoFix , accFoundFix , accNoSuggestedFix ) = countFixStatus
173+ if not checkFlag && accFoundFix > 0 then
155174 exitCode <- ExitCode.Success
156- else
175+ elif not checkFlag then
157176 exitCode <- ExitCode.NoSuggestedFix
177+ elif checkFlag && accFoundFix > 0 then
178+ exitCode <- ExitCode.FixExists
179+ elif checkFlag then
180+ exitCode <- ExitCode.Success
158181
159182 | LintResult.Failure failure -> handleError ExitCode.Error failure.Description
160183
161- let linting fileType lintParams target toolsPath shouldFix maybeRuleName =
184+ let linting fileType lintParams target toolsPath shouldFix maybeRuleName checkFlag =
162185 try
163186 let lintResult =
164187 match fileType with
@@ -169,7 +192,7 @@ let private start (arguments:ParseResults<ToolArgs>) (toolsPath:Ionide.ProjInfo.
169192 | _ -> Lint.lintProject lintParams target toolsPath
170193 if shouldFix then
171194 match maybeRuleName with
172- | Some ruleName -> handleFixResult ruleName lintResult
195+ | Some ruleName -> handleFixResult ruleName checkFlag lintResult
173196 | None -> exitCode <- ExitCode.NoSuchRuleName
174197 else
175198 handleLintResult lintResult
@@ -197,12 +220,13 @@ let private start (arguments:ParseResults<ToolArgs>) (toolsPath:Ionide.ProjInfo.
197220 let target = lintArgs.GetResult Target
198221 let fileType = lintArgs.TryGetResult File_ Type |> Option.defaultValue ( inferFileType target)
199222
200- linting fileType lintParams target toolsPath false None
223+ linting fileType lintParams target toolsPath false None false
201224
202225 let applySuggestedFix ( fixArgs : ParseResults < FixArgs >) =
203226 let fixParams = getParams None
204227 let ruleName , target = fixArgs.GetResult Fix_ Target
205228 let fileType = fixArgs.TryGetResult Fix_ File_ Type |> Option.defaultValue ( inferFileType target)
229+ let checkFlag = fixArgs.Contains Check
206230
207231 let allRules =
208232 match getConfig fixParams.Configuration with
@@ -220,7 +244,7 @@ let private start (arguments:ParseResults<ToolArgs>) (toolsPath:Ionide.ProjInfo.
220244 | _ -> Set.empty
221245
222246 if allRuleNames.Any( fun aRuleName -> String.Equals( aRuleName, ruleName, StringComparison.InvariantCultureIgnoreCase)) then
223- linting fileType fixParams target toolsPath true ( Some ruleName)
247+ linting fileType fixParams target toolsPath true ( Some ruleName) checkFlag
224248 else
225249 sprintf " Rule '%s ' does not exist." ruleName |> ( handleError ExitCode.NoSuchRuleName)
226250
0 commit comments