Download SSL Certificates Sort Subtasks of Markdown files Test BioRad EAF CopyDirectories json to Markdown Sort Day 2024 Q2 GitRemoteRemove Handle directoryInfo.LinkTarget better Remove StartAt Handle directoryInfo.LinkTarget
243 lines
11 KiB
C#
243 lines
11 KiB
C#
using File_Folder_Helper.Models;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Collections.ObjectModel;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace File_Folder_Helper.Helpers;
|
|
|
|
internal static partial class HelperKanbanMetadata
|
|
{
|
|
|
|
[GeneratedRegex("([A-Z]+(.))")]
|
|
private static partial Regex UpperCase();
|
|
|
|
[GeneratedRegex("[\\s!?.,@:;|\\\\/\"'`£$%\\^&*{}[\\]()<>~#+\\-=_¬]+")]
|
|
private static partial Regex InvalidCharacter();
|
|
|
|
private record Record(FileInfo FileInfo,
|
|
string Group,
|
|
int GroupCount,
|
|
int ItemLineNumber);
|
|
|
|
private static string GetParamCase(string value)
|
|
{
|
|
string result;
|
|
StringBuilder stringBuilder = new(value);
|
|
Match[] matches = UpperCase().Matches(value).ToArray();
|
|
for (int i = matches.Length - 1; i > -1; i--)
|
|
_ = stringBuilder.Insert(matches[i].Index, '-');
|
|
string[] segments = InvalidCharacter().Split(stringBuilder.ToString().ToLower());
|
|
result = string.Join('-', segments).Trim('-');
|
|
return result;
|
|
}
|
|
|
|
private static void TestParamCases()
|
|
{ // cSpell:disable
|
|
if (GetParamCase("PascalCase") != "pascal-case")
|
|
throw new Exception("PascalCase");
|
|
if (GetParamCase("camelCase") != "camel-case")
|
|
throw new Exception("camelCase");
|
|
if (GetParamCase("snake_case") != "snake-case")
|
|
throw new Exception("snake_case");
|
|
if (GetParamCase("No Case") != "no-case")
|
|
throw new Exception("No Case");
|
|
if (GetParamCase("With 2 numbers 3") != "with-2-numbers-3")
|
|
throw new Exception("With 2 numbers 3");
|
|
if (GetParamCase("Multiple spaces") != "multiple-spaces")
|
|
throw new Exception("Multiple spaces");
|
|
if (GetParamCase("Tab\tCharacter") != "tab-character")
|
|
throw new Exception("Tab\tCharacter");
|
|
if (GetParamCase("New\nLine") != "new-line")
|
|
throw new Exception("New\nLine");
|
|
if (GetParamCase("Punctuation, Characters") != "punctuation-characters")
|
|
throw new Exception("Punctuation, Characters");
|
|
if (GetParamCase("M!o?r.e, @p:u;n|c\\t/u\"a\'t`i£o$n% ^c&h*a{r}a[c]t(e)r<s> ~l#i+k-e= _t¬hese") != "m-o-r-e-p-u-n-c-t-u-a-t-i-o-n-c-h-a-r-a-c-t-e-r-s-l-i-k-e-t-hese")
|
|
throw new Exception("M!o?r.e, @p:u;n|c\\t/u\"a\'t`i£o$n% ^c&h*a{r}a[c]t(e)r<s> ~l#i+k-e= _t¬hese");
|
|
if (GetParamCase("This string ends with punctuation!") != "this-string-ends-with-punctuation")
|
|
throw new Exception("This string ends with punctuation!");
|
|
if (GetParamCase("?This string starts with punctuation") != "this-string-starts-with-punctuation")
|
|
throw new Exception("?This string starts with punctuation");
|
|
if (GetParamCase("#This string has punctuation at both ends&") != "this-string-has-punctuation-at-both-ends")
|
|
throw new Exception("#This string has punctuation at both ends&");
|
|
if (GetParamCase("軟件 測試") != "軟件-測試")
|
|
throw new Exception("軟件 測試");
|
|
if (GetParamCase("実験 試し") != "実験-試し")
|
|
throw new Exception("実験 試し");
|
|
if (GetParamCase("יקספּערמענאַל פּרובירן") != "יקספּערמענאַל-פּרובירן")
|
|
throw new Exception("יקספּערמענאַל פּרובירן");
|
|
if (GetParamCase("я надеюсь, что это сработает") != "я-надеюсь-что-это-сработает")
|
|
throw new Exception("я надеюсь, что это сработает");
|
|
} // cSpell:restore
|
|
|
|
private static List<Record> GetCollectionFromIndex(string sourceDirectory, ReadOnlyCollection<string> lines)
|
|
{
|
|
List<Record> results = [];
|
|
string line;
|
|
FileInfo fileInfo;
|
|
string[] segments;
|
|
int groupCount = 0;
|
|
string? group = null;
|
|
for (int i = 0; i < lines.Count; i++)
|
|
{
|
|
line = lines[i];
|
|
if (line.Length < 4)
|
|
continue;
|
|
if (line[..3] == "## ")
|
|
{
|
|
group = line[3..];
|
|
groupCount += 1;
|
|
continue;
|
|
}
|
|
if (group is null || line[..3] != "- [" || line[^1] != ')')
|
|
continue;
|
|
segments = line.Split("](");
|
|
if (segments.Length != 2)
|
|
continue;
|
|
fileInfo = new(Path.Combine(sourceDirectory, segments[1][..^1]));
|
|
if (!fileInfo.Exists)
|
|
continue;
|
|
results.Add(new(fileInfo, group, groupCount, i));
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static void WriteKanbanBoardFile(string directory, List<Record> records, string h1)
|
|
{
|
|
string? last = null;
|
|
List<string> results = [h1];
|
|
foreach (Record record in records)
|
|
{
|
|
if (last is null || record.Group != last)
|
|
{
|
|
results.Add(string.Empty);
|
|
results.Add($"## {record.Group}");
|
|
results.Add(string.Empty);
|
|
}
|
|
results.Add($"- [ ] {Path.GetFileNameWithoutExtension(record.FileInfo.Name)}");
|
|
last = record.Group;
|
|
}
|
|
string file = Path.Combine(directory, "index.knb.md");
|
|
if (File.Exists(file))
|
|
{
|
|
string allText = File.ReadAllText(file);
|
|
if (string.Join(Environment.NewLine, results) == allText)
|
|
results.Clear();
|
|
}
|
|
if (results.Count > 0)
|
|
File.WriteAllText(file, string.Join(Environment.NewLine, results));
|
|
}
|
|
|
|
private static void WriteKanbanBoardYmlView(string directory, List<Record> records, string kanbanIndexH1)
|
|
{
|
|
List<string> results = [kanbanIndexH1, string.Empty];
|
|
string h1;
|
|
TimeSpan timeSpan;
|
|
List<string> lines;
|
|
LineNumber lineNumber;
|
|
Record[] sorted = (from l in records orderby l.GroupCount, l.FileInfo.LastWriteTime descending select l).ToArray();
|
|
foreach (Record record in sorted)
|
|
{
|
|
if (record.ItemLineNumber == 0)
|
|
throw new NotSupportedException();
|
|
(lines, lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(record.FileInfo);
|
|
if (lines.Count == 0)
|
|
continue;
|
|
timeSpan = new(record.FileInfo.LastWriteTime.Ticks - record.FileInfo.CreationTime.Ticks);
|
|
h1 = lineNumber.H1 is null ? Path.GetFileNameWithoutExtension(record.FileInfo.Name) : lines[lineNumber.H1.Value];
|
|
results.Add($"#{h1}");
|
|
results.Add(string.Empty);
|
|
results.Add("```yaml");
|
|
results.Add($"CreationTime: {record.FileInfo.CreationTime:yyyy-MM-dd}");
|
|
results.Add($"LastWriteTime: {record.FileInfo.LastWriteTime:yyyy-MM-dd}");
|
|
results.Add($"TotalDays: {Math.Round(timeSpan.TotalDays, 2)}");
|
|
if (lineNumber.FrontMatterYamlEnd is not null && lines.Count >= lineNumber.FrontMatterYamlEnd.Value)
|
|
{
|
|
for (int i = 0; i < lineNumber.FrontMatterYamlEnd; i++)
|
|
{
|
|
if (lines[i] == "---")
|
|
continue;
|
|
results.Add(lines[i]);
|
|
}
|
|
}
|
|
results.Add($"status: {record.GroupCount}-{record.Group}");
|
|
results.Add("```");
|
|
results.Add(string.Empty);
|
|
}
|
|
string file = Path.Combine(directory, "index.yml.md");
|
|
if (File.Exists(file))
|
|
{
|
|
string allText = File.ReadAllText(file);
|
|
if (string.Join(Environment.NewLine, results) == allText)
|
|
results.Clear();
|
|
}
|
|
if (results.Count > 0)
|
|
File.WriteAllText(file, string.Join(Environment.NewLine, results));
|
|
}
|
|
|
|
internal static void SetMetadata(string sourceDirectory, ReadOnlyCollection<string> kanbanIndexFileLines, LineNumber kanbanIndexFileLineNumber, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
|
|
{
|
|
bool? match;
|
|
bool gitCheck;
|
|
string? paramCase;
|
|
string statusLine;
|
|
List<string> lines;
|
|
LineNumber lineNumber;
|
|
string? directory = Path.GetDirectoryName(sourceDirectory);
|
|
List<Record> records = GetCollectionFromIndex(sourceDirectory, kanbanIndexFileLines);
|
|
if (directory is not null && kanbanIndexFileLineNumber.H1 is not null)
|
|
{
|
|
string checkDirectory = Path.Combine(directory, ".vscode", "helper");
|
|
if (Directory.Exists(checkDirectory))
|
|
{
|
|
WriteKanbanBoardFile(checkDirectory, records, kanbanIndexFileLines[kanbanIndexFileLineNumber.H1.Value]);
|
|
WriteKanbanBoardYmlView(checkDirectory, records, kanbanIndexFileLines[kanbanIndexFileLineNumber.H1.Value]);
|
|
}
|
|
}
|
|
foreach (Record record in records)
|
|
{
|
|
if (record.ItemLineNumber == 0)
|
|
throw new NotSupportedException();
|
|
(lines, lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(record.FileInfo);
|
|
if (lines.Count == 0)
|
|
continue;
|
|
statusLine = $"status: {record.GroupCount}-{record.Group}";
|
|
paramCase = lineNumber.H1 is null ? null : GetParamCase(lines[lineNumber.H1.Value]);
|
|
match = lineNumber.H1 is null || paramCase is null ? null : Path.GetFileNameWithoutExtension(record.FileInfo.Name) == paramCase;
|
|
if (lineNumber.FrontMatterYamlEnd is null)
|
|
throw new NotSupportedException($"{nameof(SetMetadata)} must be executed first!");
|
|
if (lineNumber.H1 is not null && paramCase is not null && match is not null && !match.Value)
|
|
lines[lineNumber.H1.Value] = $"# {paramCase}";
|
|
if (lineNumber.Status is null)
|
|
lines.Insert(lineNumber.FrontMatterYamlEnd.Value, statusLine);
|
|
else
|
|
{
|
|
if ((match is null || match.Value) && lines[lineNumber.Status.Value] == statusLine)
|
|
continue;
|
|
lines[lineNumber.Status.Value] = statusLine;
|
|
}
|
|
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(record.FileInfo.FullName);
|
|
if (!gitCheck)
|
|
continue;
|
|
File.WriteAllLines(record.FileInfo.FullName, lines);
|
|
}
|
|
}
|
|
|
|
internal static void SetMetadata(ILogger logger, string sourceDirectory)
|
|
{
|
|
TestParamCases();
|
|
string fullPath = Path.GetFullPath(sourceDirectory);
|
|
if (!Directory.Exists(fullPath))
|
|
_ = Directory.CreateDirectory(fullPath);
|
|
string indexFile = Path.Combine(fullPath, "index.md");
|
|
if (!File.Exists(indexFile))
|
|
logger.LogInformation("<{indexFile}> doesn't exist!", indexFile);
|
|
else
|
|
{
|
|
FileInfo fileInfo = new(indexFile);
|
|
(List<string> lines, LineNumber lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(fileInfo);
|
|
SetMetadata(fullPath, new(lines), lineNumber, gitOthersModifiedAndDeletedExcludingStandardFiles: new([]));
|
|
}
|
|
}
|
|
|
|
} |