3131using  System . Collections . ObjectModel ; 
3232using  System . Collections ; 
3333using  System . Diagnostics ; 
34+ using  System . Text ; 
3435
3536namespace  Microsoft . Windows . PowerShell . ScriptAnalyzer 
3637{ 
@@ -1443,43 +1444,67 @@ public Dictionary<string, List<string>> CheckRuleExtension(string[] path, PathIn
14431444            return  results ; 
14441445        } 
14451446
1446- #endregion
1447+          #endregion
14471448
14481449
14491450        /// <summary> 
14501451        /// Analyzes a script file or a directory containing script files. 
14511452        /// </summary> 
14521453        /// <param name="path">The path of the file or directory to analyze.</param> 
1454+         /// <param name="shouldProcess">Whether the action should be executed.</param> 
14531455        /// <param name="searchRecursively"> 
14541456        /// If true, recursively searches the given file path and analyzes any 
14551457        /// script files that are found. 
14561458        /// </param> 
14571459        /// <returns>An enumeration of DiagnosticRecords that were found by rules.</returns> 
1458-         public  IEnumerable < DiagnosticRecord >  AnalyzePath ( string  path ,  bool  searchRecursively  =  false ) 
1460+         public  IEnumerable < DiagnosticRecord >  AnalyzePath ( string  path ,  Func < string ,   string ,   bool >   shouldProcess ,   bool  searchRecursively  =  false ) 
14591461        { 
1460-             List < string >  scriptFilePaths  =  new   List < string > ( ) ; 
1462+             List < string >  scriptFilePaths  =  ScriptPathList ( path ,   searchRecursively ) ; 
14611463
1462-             if   ( path   ==   null ) 
1464+             foreach   ( string   scriptFilePath   in   scriptFilePaths ) 
14631465            { 
1464-                 this . outputWriter . ThrowTerminatingError ( 
1465-                     new  ErrorRecord ( 
1466-                         new  FileNotFoundException ( ) , 
1467-                         string . Format ( CultureInfo . CurrentCulture ,  Strings . FileNotFound ,  path ) , 
1468-                         ErrorCategory . InvalidArgument , 
1469-                         this ) ) ; 
1466+                 if  ( shouldProcess ( scriptFilePath ,  $ "Analyzing file { scriptFilePath } ") ) 
1467+                 { 
1468+                     // Yield each record in the result so that the caller can pull them one at a time 
1469+                     foreach  ( var  diagnosticRecord  in  this . AnalyzeFile ( scriptFilePath ) ) 
1470+                     { 
1471+                         yield  return  diagnosticRecord ; 
1472+                     } 
1473+                 } 
14701474            } 
1475+         } 
1476+ 
1477+         /// <summary> 
1478+         /// Analyzes a script file or a directory containing script files and fixes warning where possible. 
1479+         /// </summary> 
1480+         /// <param name="path">The path of the file or directory to analyze.</param> 
1481+         /// <param name="shouldProcess">Whether the action should be executed.</param> 
1482+         /// <param name="searchRecursively"> 
1483+         /// If true, recursively searches the given file path and analyzes any 
1484+         /// script files that are found. 
1485+         /// </param> 
1486+         /// <returns>An enumeration of DiagnosticRecords that were found by rules and could not be fixed automatically.</returns> 
1487+         public  IEnumerable < DiagnosticRecord >  AnalyzeAndFixPath ( string  path ,  Func < string ,  string ,  bool >  shouldProcess ,  bool  searchRecursively  =  false ) 
1488+         { 
1489+             List < string >  scriptFilePaths  =  ScriptPathList ( path ,  searchRecursively ) ; 
14711490
1472-             // Create in advance the list of script file paths to analyze.  This 
1473-             // is an optimization over doing the whole operation at once 
1474-             // and calling .Concat on IEnumerables to join results. 
1475-             this . BuildScriptPathList ( path ,  searchRecursively ,  scriptFilePaths ) ; 
14761491            foreach  ( string  scriptFilePath  in  scriptFilePaths ) 
14771492            { 
1478-                 // Yield each record in the result so that the 
1479-                 // caller can pull them one at a time 
1480-                 foreach  ( var  diagnosticRecord  in  this . AnalyzeFile ( scriptFilePath ) ) 
1493+                 if  ( shouldProcess ( scriptFilePath ,  $ "Analyzing and fixing file { scriptFilePath } ") ) 
14811494                { 
1482-                     yield  return  diagnosticRecord ; 
1495+                     var  fileEncoding  =  GetFileEncoding ( scriptFilePath ) ; 
1496+                     bool  fixesWereApplied ; 
1497+                     var  scriptFileContentWithFixes  =  Fix ( File . ReadAllText ( scriptFilePath ,  fileEncoding ) ,  out  fixesWereApplied ) ; 
1498+                     if  ( fixesWereApplied ) 
1499+                     { 
1500+                         File . WriteAllText ( scriptFilePath ,  scriptFileContentWithFixes ,  fileEncoding ) ; 
1501+                     } 
1502+ 
1503+                     // Yield each record in the result so that the caller can pull them one at a time 
1504+                     foreach  ( var  diagnosticRecord  in  this . AnalyzeFile ( scriptFilePath ) ) 
1505+                     { 
1506+                         yield  return  diagnosticRecord ; 
1507+                     } 
14831508                } 
14841509            } 
14851510        } 
@@ -1531,16 +1556,17 @@ public IEnumerable<DiagnosticRecord> AnalyzeScriptDefinition(string scriptDefini
15311556        /// Fix the violations in the given script text. 
15321557        /// </summary> 
15331558        /// <param name="scriptDefinition">The script text to be fixed.</param> 
1559+         /// <param name="updatedRange">Whether any warnings were fixed.</param> 
15341560        /// <returns>The fixed script text.</returns> 
1535-         public  string  Fix ( string  scriptDefinition ) 
1561+         public  string  Fix ( string  scriptDefinition ,   out   bool   fixesWereApplied ) 
15361562        { 
15371563            if  ( scriptDefinition  ==  null ) 
15381564            { 
15391565                throw  new  ArgumentNullException ( nameof ( scriptDefinition ) ) ; 
15401566            } 
15411567
15421568            Range  updatedRange ; 
1543-             return  Fix ( new  EditableText ( scriptDefinition ) ,  null ,  out  updatedRange ) . ToString ( ) ; 
1569+             return  Fix ( new  EditableText ( scriptDefinition ) ,  null ,  out  updatedRange ,   out   fixesWereApplied ) . ToString ( ) ; 
15441570        } 
15451571
15461572        /// <summary> 
@@ -1549,8 +1575,9 @@ public string Fix(string scriptDefinition)
15491575        /// <param name="text">An object of type `EditableText` that encapsulates the script text to be fixed.</param> 
15501576        /// <param name="range">The range in which the fixes are allowed.</param> 
15511577        /// <param name="updatedRange">The updated range after the fixes have been applied.</param> 
1578+         /// <param name="updatedRange">Whether any warnings were fixed.</param> 
15521579        /// <returns>The same instance of `EditableText` that was passed to the method, but the instance encapsulates the fixed script text. This helps in chaining the Fix method.</returns> 
1553-         public  EditableText  Fix ( EditableText  text ,  Range  range ,  out  Range  updatedRange ) 
1580+         public  EditableText  Fix ( EditableText  text ,  Range  range ,  out  Range  updatedRange ,   out   bool   fixesWereApplied ) 
15541581        { 
15551582            if  ( text  ==  null ) 
15561583            { 
@@ -1583,7 +1610,9 @@ public EditableText Fix(EditableText text, Range range, out Range updatedRange)
15831610                this . outputWriter . WriteVerbose ( $ "Found { corrections . Count }  violations.") ; 
15841611                int  unusedCorrections ; 
15851612                Fix ( text ,  corrections ,  out  unusedCorrections ) ; 
1586-                 this . outputWriter . WriteVerbose ( $ "Fixed { corrections . Count  -  unusedCorrections }  violations.") ; 
1613+                 var  numberOfFixedViolatons  =  corrections . Count  -  unusedCorrections ; 
1614+                 fixesWereApplied  =  numberOfFixedViolatons  >  0 ; 
1615+                 this . outputWriter . WriteVerbose ( $ "Fixed { numberOfFixedViolatons }  violations.") ; 
15871616
15881617                // This is an indication of an infinite loop. There is a small chance of this. 
15891618                // It is better to abort the fixing operation at this point. 
@@ -1613,6 +1642,18 @@ public EditableText Fix(EditableText text, Range range, out Range updatedRange)
16131642            return  text ; 
16141643        } 
16151644
1645+         private  static Encoding  GetFileEncoding ( string  path ) 
1646+         { 
1647+             using  ( var  stream  =  new  FileStream ( path ,  FileMode . Open ) ) 
1648+             { 
1649+                 using  ( var  reader  =  new  StreamReader ( stream ) ) 
1650+                 { 
1651+                     reader . Peek ( ) ;  // needed in order to populate the CurrentEncoding property 
1652+                     return  reader . CurrentEncoding ; 
1653+                 } 
1654+             } 
1655+         } 
1656+ 
16161657        private  static Range  SnapToEdges ( EditableText  text ,  Range  range ) 
16171658        { 
16181659            // todo add TextLines.Validate(range) and TextLines.Validate(position) 
@@ -1655,6 +1696,28 @@ private static EditableText Fix(
16551696            return  text ; 
16561697        } 
16571698
1699+         private  List < string >  ScriptPathList ( string  path ,  bool  searchRecursively ) 
1700+         { 
1701+             List < string >  scriptFilePaths  =  new  List < string > ( ) ; 
1702+ 
1703+             if  ( path  ==  null ) 
1704+             { 
1705+                 this . outputWriter . ThrowTerminatingError ( 
1706+                     new  ErrorRecord ( 
1707+                         new  FileNotFoundException ( ) , 
1708+                         string . Format ( CultureInfo . CurrentCulture ,  Strings . FileNotFound ,  path ) , 
1709+                         ErrorCategory . InvalidArgument , 
1710+                         this ) ) ; 
1711+             } 
1712+ 
1713+             // Create in advance the list of script file paths to analyze.  This 
1714+             // is an optimization over doing the whole operation at once 
1715+             // and calling .Concat on IEnumerables to join results. 
1716+             this . BuildScriptPathList ( path ,  searchRecursively ,  scriptFilePaths ) ; 
1717+ 
1718+             return  scriptFilePaths ; 
1719+         } 
1720+ 
16581721        private  void  BuildScriptPathList ( 
16591722            string  path , 
16601723            bool  searchRecursively , 
0 commit comments