66using System . Text . RegularExpressions ;
77using Elastic . Markdown . IO ;
88using Microsoft . Extensions . Logging ;
9+ using static System . StringComparison ;
910
1011namespace Elastic . Markdown . Refactor ;
1112
1213public record ChangeSet ( IFileInfo From , IFileInfo To ) ;
1314public record Change ( IFileInfo Source , string OriginalContent , string NewContent ) ;
1415public record LinkModification ( string OldLink , string NewLink , string SourceFile , int LineNumber , int ColumnNumber ) ;
1516
16- public class Move ( IFileSystem readFileSystem , IFileSystem writeFileSystem , DocumentationSet documentationSet , ILoggerFactory loggerFactory )
17+ public partial class Move ( IFileSystem readFileSystem , IFileSystem writeFileSystem , DocumentationSet documentationSet , ILoggerFactory loggerFactory )
1718{
18- private const string ChangeFormatString = "Change \e [31m{0}\e [0m to \e [32m{1}\e [0m at \e [34m{2}:{3}:{4}\e [0m" ;
1919
2020 private readonly ILogger _logger = loggerFactory . CreateLogger < Move > ( ) ;
2121 private readonly Dictionary < ChangeSet , List < Change > > _changes = [ ] ;
@@ -35,7 +35,7 @@ public async Task<int> Execute(string source, string target, bool isDryRun, Canc
3535 foreach ( var ( fromFile , toFile ) in fromFiles . Zip ( toFiles ) )
3636 {
3737 var changeSet = new ChangeSet ( fromFile , toFile ) ;
38- _logger . LogInformation ( $ "Requested to move from '{ fromFile } ' to '{ toFile } " ) ;
38+ _logger . LogInformation ( "Requested to move from '{FromFile }' to '{ToFile}'" , fromFile , toFile ) ;
3939 await SetupChanges ( changeSet , ctx ) ;
4040 }
4141
@@ -49,7 +49,7 @@ private async Task SetupChanges(ChangeSet changeSet, Cancel ctx)
4949
5050 var sourceContent = await readFileSystem . File . ReadAllTextAsync ( sourcePath , ctx ) ;
5151
52- var markdownLinkRegex = new Regex ( @"\[([^\]]*)\]\(((?:\.{0,2}\/)?[^:)]+\.md(?:#[^)]*)?)\)" , RegexOptions . Compiled ) ;
52+ var markdownLinkRegex = MarkdownLinkRegex ( ) ;
5353
5454 var change = Regex . Replace ( sourceContent , markdownLinkRegex . ToString ( ) , match =>
5555 {
@@ -64,13 +64,12 @@ private async Task SetupChanges(ChangeSet changeSet, Cancel ctx)
6464 var fullPath = Path . GetFullPath ( Path . Combine ( sourceDirectory , originalPath ) ) ;
6565 var relativePath = Path . GetRelativePath ( targetDirectory , fullPath ) ;
6666
67- if ( originalPath . StartsWith ( "./" ) && ! relativePath . StartsWith ( "./" ) )
68- newPath = "./" + relativePath ;
69- else
70- newPath = relativePath ;
67+ newPath = originalPath . StartsWith ( "./" , OrdinalIgnoreCase ) && ! relativePath . StartsWith ( "./" , OrdinalIgnoreCase )
68+ ? "./" + relativePath
69+ : relativePath ;
7170 }
7271 var newLink = $ "[{ match . Groups [ 1 ] . Value } ]({ newPath } )";
73- var lineNumber = sourceContent . Substring ( 0 , match . Index ) . Count ( c => c == '\n ' ) + 1 ;
72+ var lineNumber = sourceContent [ .. match . Index ] . Count ( c => c == '\n ' ) + 1 ;
7473 var columnNumber = match . Index - sourceContent . LastIndexOf ( '\n ' , match . Index ) ;
7574 if ( ! _linkModifications . ContainsKey ( changeSet ) )
7675 _linkModifications [ changeSet ] = [ ] ;
@@ -104,14 +103,14 @@ private async Task<int> MoveAndRewriteLinks(bool isDryRun, Cancel ctx)
104103 {
105104 foreach ( var ( oldLink , newLink , sourceFile , lineNumber , columnNumber ) in linkModifications )
106105 {
107- _logger . LogInformation ( string . Format (
108- ChangeFormatString ,
106+ _logger . LogInformation (
107+ "Change \e [31m{OldLink} \e [0m to \e [32m{NewLink} \e [0m at \e [34m{SourceFile}:{LineNumber}:{Column} \e [0m" ,
109108 oldLink ,
110109 newLink ,
111110 sourceFile == changeSet . From . FullName && ! isDryRun ? changeSet . To . FullName : sourceFile ,
112111 lineNumber ,
113112 columnNumber
114- ) ) ;
113+ ) ;
115114 }
116115 }
117116
@@ -125,13 +124,13 @@ private async Task<int> MoveAndRewriteLinks(bool isDryRun, Cancel ctx)
125124 foreach ( var ( filePath , _, newContent ) in changes )
126125 {
127126 if ( ! filePath . Directory ! . Exists )
128- writeFileSystem . Directory . CreateDirectory ( filePath . Directory . FullName ) ;
127+ _ = writeFileSystem . Directory . CreateDirectory ( filePath . Directory . FullName ) ;
129128 await writeFileSystem . File . WriteAllTextAsync ( filePath . FullName , newContent , ctx ) ;
130129
131130 }
132131
133132 var targetDirectory = Path . GetDirectoryName ( changeSet . To . FullName ) ;
134- readFileSystem . Directory . CreateDirectory ( targetDirectory ! ) ;
133+ _ = readFileSystem . Directory . CreateDirectory ( targetDirectory ! ) ;
135134 readFileSystem . File . Move ( changeSet . From . FullName , changeSet . To . FullName ) ;
136135 }
137136 }
@@ -172,15 +171,16 @@ private bool ValidateInputs(string source, string target, out IFileInfo[] fromFi
172171 //from does not exist at all
173172 if ( ! fromFile . Exists && ! fromDirectory . Exists )
174173 {
175- _logger . LogError ( ! string . IsNullOrEmpty ( fromFile . Extension )
176- ? $ "Source file '{ fromFile } ' does not exist"
177- : $ "Source directory '{ fromDirectory } ' does not exist") ;
174+ if ( ! string . IsNullOrEmpty ( fromFile . Extension ) )
175+ _logger . LogError ( "Source file '{File}' does not exist" , fromFile ) ;
176+ else
177+ _logger . LogError ( "Source directory '{Directory}' does not exist" , fromDirectory ) ;
178178 return false ;
179179 }
180180 //moving file
181181 if ( fromFile . Exists )
182182 {
183- if ( ! fromFile . Extension . Equals ( ".md" , StringComparison . OrdinalIgnoreCase ) )
183+ if ( ! fromFile . Extension . Equals ( ".md" , OrdinalIgnoreCase ) )
184184 {
185185 _logger . LogError ( "Source path must be a markdown file. Directory paths are not supported yet" ) ;
186186 return false ;
@@ -190,14 +190,14 @@ private bool ValidateInputs(string source, string target, out IFileInfo[] fromFi
190190 if ( toFile . Extension == string . Empty )
191191 toFile = readFileSystem . FileInfo . New ( Path . Combine ( toDirectory . FullName , fromFile . Name ) ) ;
192192
193- if ( ! toFile . Extension . Equals ( ".md" , StringComparison . OrdinalIgnoreCase ) )
193+ if ( ! toFile . Extension . Equals ( ".md" , OrdinalIgnoreCase ) )
194194 {
195- _logger . LogError ( $ "Target path '{ toFile . FullName } ' must be a markdown file.") ;
195+ _logger . LogError ( "Target path '{FullName}' must be a markdown file." , toFile . FullName ) ;
196196 return false ;
197197 }
198198 if ( toFile . Exists )
199199 {
200- _logger . LogError ( $ "Target file { target } already exists") ;
200+ _logger . LogError ( "Target file {Target } already exists" , target ) ;
201201 return false ;
202202 }
203203 fromFiles = [ fromFile ] ;
@@ -208,22 +208,22 @@ private bool ValidateInputs(string source, string target, out IFileInfo[] fromFi
208208 {
209209 if ( toDirectory . Exists )
210210 {
211- _logger . LogError ( $ "Target directory '{ toDirectory . FullName } ' already exists.") ;
211+ _logger . LogError ( "Target directory '{FullName}' already exists." , toDirectory . FullName ) ;
212212 return false ;
213213 }
214214
215- if ( toDirectory . FullName . StartsWith ( fromDirectory . FullName ) )
215+ if ( toDirectory . FullName . StartsWith ( fromDirectory . FullName , OrdinalIgnoreCase ) )
216216 {
217- _logger . LogError ( $ "Can not move source directory '{ toDirectory . FullName } ' to a { toFile . FullName } " ) ;
217+ _logger . LogError ( "Can not move source directory '{SourceDirectory }' to a '{TargetFile}'" , toDirectory . FullName , toFile . FullName ) ;
218218 return false ;
219219 }
220220
221221 fromFiles = fromDirectory . GetFiles ( "*.md" , SearchOption . AllDirectories ) ;
222- toFiles = fromFiles . Select ( f =>
222+ toFiles = [ .. fromFiles . Select ( f =>
223223 {
224224 var relative = Path . GetRelativePath ( fromDirectory . FullName , f . FullName ) ;
225225 return readFileSystem . FileInfo . New ( Path . Combine ( toDirectory . FullName , relative ) ) ;
226- } ) . ToArray ( ) ;
226+ } ) ] ;
227227 }
228228
229229 return true ;
@@ -293,12 +293,12 @@ private string ReplaceLinks(
293293 else
294294 {
295295 var relativeTarget = Path . GetRelativePath ( Path . GetDirectoryName ( value . FilePath ) ! , target ) ;
296- newLink = originalPath . StartsWith ( "./" ) && ! relativeTarget . StartsWith ( "./" )
296+ newLink = originalPath . StartsWith ( "./" , OrdinalIgnoreCase ) && ! relativeTarget . StartsWith ( "./" , OrdinalIgnoreCase )
297297 ? $ "[{ match . Groups [ 1 ] . Value } ](./{ relativeTarget } { anchor } )"
298298 : $ "[{ match . Groups [ 1 ] . Value } ]({ relativeTarget } { anchor } )";
299299 }
300300
301- var lineNumber = content . Substring ( 0 , match . Index ) . Count ( c => c == '\n ' ) + 1 ;
301+ var lineNumber = content [ .. match . Index ] . Count ( c => c == '\n ' ) + 1 ;
302302 var columnNumber = match . Index - content . LastIndexOf ( '\n ' , match . Index ) ;
303303 if ( ! _linkModifications . ContainsKey ( changeSet ) )
304304 _linkModifications [ changeSet ] = [ ] ;
@@ -311,4 +311,7 @@ private string ReplaceLinks(
311311 ) ) ;
312312 return newLink ;
313313 } ) ;
314+
315+ [ GeneratedRegex ( @"\[([^\]]*)\]\(((?:\.{0,2}\/)?[^:)]+\.md(?:#[^)]*)?)\)" , RegexOptions . Compiled ) ]
316+ private static partial Regex MarkdownLinkRegex ( ) ;
314317}
0 commit comments