Update Markdown Helper to write json files for tables and yaml

This commit is contained in:
Mike Phares 2025-06-20 18:07:40 -07:00
parent 116d5e9734
commit 7566ce1306
5 changed files with 543 additions and 174 deletions

1
.gitignore vendored
View File

@ -336,3 +336,4 @@ ASALocalRun/
.extensions-vscode-oss
.extensions-vscode-insiders
.vscode/.UserSecrets/secrets.json
.vscode/.helper

277
.vscode/launch.json vendored
View File

@ -1,128 +1,153 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/bin/Debug/net8.0/win-x64/File-Folder-Helper.dll",
"args": [
"s",
"X",
"D:/5-Other-Small/Proxmox/DiskInfo",
"Day-Helper-2025-06-18",
"*.json",
"D:/5-Other-Small/Proxmox/Disk-Info-Old",
"-2025-",
"1",
"s",
"X",
"D:/Tmp",
"Day-Helper-2025-06-02",
"infineon\\MESPhares",
"BACKLOG~BIORAD2~BIORAD3~BIORAD4~BIORAD5~CDE4~CDE5~CDE6~DEP08CEPIEPSILON~DEP08SIASM~DEP08SIHTRPLC~EC~HGCV1~HGCV2~HGCV3~MESAFIBACKLOG~MET06AWCT~MET08ANLYSDIFAAST230~MET08AWCT~MET08DDUPSFS6420~MET08DDUPSP1TBI~MET08RESIHGCV~MET08RESIMAPCDE~MET08RESISRP2100~MET08THFTIRQS408M~MET08THFTIRSTRATUS~METCLIMATEC~R29~R32~R36~R47~R55~R57~R61~R62~R65~R70~R72~R73~R74~R75~R77~SP101~SPV01~SRP~TENCOR1~TENCOR2~TENCOR3~TRENDLOG~WC6INCH1~WC6INCH2~WC6INCH3~WC6INCH4~WC8INCH1~WC8INCH2~WC8INCH3",
"s",
"X",
"D:/5-Other-Small/Proxmox/ffnm",
"Day-Helper-2025-05-21",
"*.pdf",
"*.md",
"2",
"MM-dd-yy",
"Trans Date~Effective Date~Description~Withdrawal Deposit~Balance",
"s",
"X",
"D:/Tmp/phares/VisualStudioCode",
"Day-Helper-2025-05-19",
"D:/Tmp/phares/VisualStudioCode/.vscode/input.json",
"s",
"X",
"D:/Tmp/phares/VisualStudioCode",
"Day-Helper-2025-05-19",
"D:/Tmp/phares/VisualStudioCodeLeft",
"z-include-patterns.nsv",
"z-exclude-patterns.nsv",
"http://localhost:5004",
"/api/SyncV1/?",
",L",
".G",
"+~G~~L~+~Custom-Default",
"",
"+~G~~G~-~Mirror",
"+~G~~~~Update",
"+~G~~L~+~Custom-Default",
"-~G~~G~+~Custom-A",
"-~L~~L~+~Custom-B",
"+~L~~L~-~Custom-C",
"s",
"X",
"\\\\mesfs.infineon.com\\EC_Characterization_Si\\Archive\\BIORAD4\\2025_Week_16\\2025-04-17",
"Day-Helper-2025-02-19",
"csv-*.pdsf",
"*.pdsf",
"Time,HeaderUniqueId,UniqueId,Date,Wafer,Position,BIORAD4",
",BIORAD4",
",BIORAD4",
"Test|EventId,Date|DateTime,Position|Slot,DeltaThicknessSlotsOneAndTwentyFive|Actual Delta Thick Pts 1 and 25,PercentDeltaThicknessSlotsOneAndTwentyFive|% Delta Thick Pts 1 and 25,MID|Cassette,Lot|Batch,Title|Batch,Wafer|Text,Thickness|Site,MeanThickness|GradeMean,|BIORAD4",
"Time,A_LOGISTICS,B_LOGISTICS,Test,Count,Index,MesEntity,MID,Date,Employee,Lot,PSN,Reactor,Recipe,Cassette,GradeStdDev,HeaderUniqueId,Layer,MeanThickness,PassFail,RDS,Slot,Title,UniqueId,Wafer,Zone,Mean,Position,StdDev,Thickness,ThicknessSlotOne,ThicknessSlotTwentyFive,DeltaThicknessSlotsOneAndTwentyFive,PercentDeltaThicknessSlotsOneAndTwentyFive",
"Time,A_LOGISTICS,B_LOGISTICS,Count,Sequence,MesEntity,Index,Batch,Cassette,DateTime,Destination,Mean,PassFail,Recipe,Reference,Site,Slot,Source,StdDev,Text,GradeMean,GradeStdDev,RDS,PSN,Reactor,Layer,Zone,Employee,InferredLot,Thickness First Slot,Thickness Last Slot,Actual Delta Thick Pts 1 and 25,% Delta Thick Pts 1 and 25,EventId",
"0,1,2,31,3,6,5,8,9,27,7,23,24,13,8,21,-1,25,20,12,22,16,7,-1,19,26,11,16,18,15,-1,-1,29,30",
"s",
"X",
"C:/Users/phares/AppData/Roaming/FreeFileSync",
"Day-Helper-2025-04-21",
"GlobalSettings.xml",
"LastSync|Config",
"s",
"X",
"L:/Tmp/MET08ANLYSDIFAAST230",
"Day-Helper-2025-03-06",
"*.pdsf",
"s",
"X",
"D:/ProgramData/VisualStudioCode|D:/6-Other-Large-Z/Linux-Ubuntu-Phares/home/lphares/dorico",
"Day-Helper-2025-04-07",
"z-include-patterns.nsv",
"z-exclude-patterns.nsv",
"https://isccvm57294f1ed/VisualStudioCode|hxttps://dorico.phares.duckdns.org|hxttps://mestsa006.infineon.com/VisualStudioCode",
"+|G|G|G|-",
"||||",
"666",
"777",
"888",
"999",
"s",
"X",
"C:/Users/PHARES/AppData/Local/IFXApps/gatus",
"Day-Helper-2025-04-04",
"*.json",
".metrics",
"https://messa010ec.infineon.com/metrics",
"gatus_results_endpoint_success",
"666",
"777",
"888",
"999",
""
],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
},
{
"type": "node",
"request": "launch",
"name": "node Launch Current Opened File",
"program": "${file}"
}
]
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/bin/Debug/net8.0/win-x64/File-Folder-Helper.dll",
"args": [
"s",
"M",
"D:/5-Other-Small/Notes/Infineon",
"-d",
"D:/5-Other-Small/Notes/Infineon/.vscode/helper",
"s",
"X",
"D:/5-Other-Small/Proxmox/DiskInfo",
"Day-Helper-2025-06-18",
"*.json",
"D:/5-Other-Small/Proxmox/Disk-Info-Old",
"-2025-",
"1",
"s",
"X",
"D:/Tmp",
"Day-Helper-2025-06-02",
"infineon\\MESPhares",
"BACKLOG~BIORAD2~BIORAD3~BIORAD4~BIORAD5~CDE4~CDE5~CDE6~DEP08CEPIEPSILON~DEP08SIASM~DEP08SIHTRPLC~EC~HGCV1~HGCV2~HGCV3~MESAFIBACKLOG~MET06AWCT~MET08ANLYSDIFAAST230~MET08AWCT~MET08DDUPSFS6420~MET08DDUPSP1TBI~MET08RESIHGCV~MET08RESIMAPCDE~MET08RESISRP2100~MET08THFTIRQS408M~MET08THFTIRSTRATUS~METCLIMATEC~R29~R32~R36~R47~R55~R57~R61~R62~R65~R70~R72~R73~R74~R75~R77~SP101~SPV01~SRP~TENCOR1~TENCOR2~TENCOR3~TRENDLOG~WC6INCH1~WC6INCH2~WC6INCH3~WC6INCH4~WC8INCH1~WC8INCH2~WC8INCH3",
"s",
"X",
"D:/5-Other-Small/Proxmox/ffnm",
"Day-Helper-2025-05-21",
"*.pdf",
"*.md",
"2",
"MM-dd-yy",
"Trans Date~Effective Date~Description~Withdrawal Deposit~Balance",
"s",
"X",
"D:/Tmp/phares/VisualStudioCode",
"Day-Helper-2025-05-19",
"D:/Tmp/phares/VisualStudioCode/.vscode/input.json",
"s",
"X",
"D:/Tmp/phares/VisualStudioCode",
"Day-Helper-2025-05-19",
"D:/Tmp/phares/VisualStudioCodeLeft",
"z-include-patterns.nsv",
"z-exclude-patterns.nsv",
"http://localhost:5004",
"/api/SyncV1/?",
",L",
".G",
"+~G~~L~+~Custom-Default",
"",
"+~G~~G~-~Mirror",
"+~G~~~~Update",
"+~G~~L~+~Custom-Default",
"-~G~~G~+~Custom-A",
"-~L~~L~+~Custom-B",
"+~L~~L~-~Custom-C",
"s",
"X",
"\\\\mesfs.infineon.com\\EC_Characterization_Si\\Archive\\BIORAD4\\2025_Week_16\\2025-04-17",
"Day-Helper-2025-02-19",
"csv-*.pdsf",
"*.pdsf",
"Time,HeaderUniqueId,UniqueId,Date,Wafer,Position,BIORAD4",
",BIORAD4",
",BIORAD4",
"Test|EventId,Date|DateTime,Position|Slot,DeltaThicknessSlotsOneAndTwentyFive|Actual Delta Thick Pts 1 and 25,PercentDeltaThicknessSlotsOneAndTwentyFive|% Delta Thick Pts 1 and 25,MID|Cassette,Lot|Batch,Title|Batch,Wafer|Text,Thickness|Site,MeanThickness|GradeMean,|BIORAD4",
"Time,A_LOGISTICS,B_LOGISTICS,Test,Count,Index,MesEntity,MID,Date,Employee,Lot,PSN,Reactor,Recipe,Cassette,GradeStdDev,HeaderUniqueId,Layer,MeanThickness,PassFail,RDS,Slot,Title,UniqueId,Wafer,Zone,Mean,Position,StdDev,Thickness,ThicknessSlotOne,ThicknessSlotTwentyFive,DeltaThicknessSlotsOneAndTwentyFive,PercentDeltaThicknessSlotsOneAndTwentyFive",
"Time,A_LOGISTICS,B_LOGISTICS,Count,Sequence,MesEntity,Index,Batch,Cassette,DateTime,Destination,Mean,PassFail,Recipe,Reference,Site,Slot,Source,StdDev,Text,GradeMean,GradeStdDev,RDS,PSN,Reactor,Layer,Zone,Employee,InferredLot,Thickness First Slot,Thickness Last Slot,Actual Delta Thick Pts 1 and 25,% Delta Thick Pts 1 and 25,EventId",
"0,1,2,31,3,6,5,8,9,27,7,23,24,13,8,21,-1,25,20,12,22,16,7,-1,19,26,11,16,18,15,-1,-1,29,30",
"s",
"X",
"C:/Users/phares/AppData/Roaming/FreeFileSync",
"Day-Helper-2025-04-21",
"GlobalSettings.xml",
"LastSync|Config",
"s",
"X",
"L:/Tmp/MET08ANLYSDIFAAST230",
"Day-Helper-2025-03-06",
"*.pdsf",
"s",
"X",
"D:/ProgramData/VisualStudioCode|D:/6-Other-Large-Z/Linux-Ubuntu-Phares/home/lphares/dorico",
"Day-Helper-2025-04-07",
"z-include-patterns.nsv",
"z-exclude-patterns.nsv",
"https://isccvm57294f1ed/VisualStudioCode|hxttps://dorico.phares.duckdns.org|hxttps://mestsa006.infineon.com/VisualStudioCode",
"+|G|G|G|-",
"||||",
"666",
"777",
"888",
"999",
"s",
"X",
"C:/Users/PHARES/AppData/Local/IFXApps/gatus",
"Day-Helper-2025-04-04",
"*.json",
".metrics",
"https://messa010ec.infineon.com/metrics",
"gatus_results_endpoint_success",
"666",
"777",
"888",
"999",
""
],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
},
{
"type": "node",
"request": "launch",
"name": "node Launch Current Opened File",
"program": "${file}"
},
{
"type": "bun",
"internalConsoleOptions": "neverOpen",
"request": "launch",
"name": "Debug File",
"program": "${file}",
"cwd": "${workspaceFolder}",
"stopOnEntry": false,
"watchMode": false
},
{
"type": "bun",
"internalConsoleOptions": "neverOpen",
"request": "launch",
"name": "Run File",
"program": "${file}",
"cwd": "${workspaceFolder}",
"noDebug": true,
"watchMode": false
}
]
}

4
.vscode/mklink.md vendored
View File

@ -35,3 +35,7 @@ mklink /J "C:\Users\phares\.vscode-insiders\extensions\infineon-technologies-ag-
mkdir "L:\DevOps\MESA_FI\file-folder-helper\bin\Release\net8.0\win-x64"
mklink /J "L:\DevOps\MESA_FI\file-folder-helper\bin\Release\net8.0\win-x64\publish" "D:\5-Other-Small\Proxmox\publish"
```
```bash 1750459968132 = 638860567681320000 = 2025-3.Summer = Fri Jun 20 2025 15:52:47 GMT-0700 (Mountain Standard Time)
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.vscode\.helper" "D:\5-Other-Small\Notes\Infineon\.vscode\helper"
```

View File

@ -16,8 +16,20 @@ internal static partial class HelperMarkdown
private record Input(string? Destination,
string Source,
string? ReplaceWithTitle,
bool UseProcessStart);
private record Table(ReadOnlyCollection<string> Columns,
int ColumnsLine,
ReadOnlyCollection<ReadOnlyCollection<string>> Rows,
string? Title);
private record Block(int Line,
string? Json,
int RowCount,
ReadOnlyCollection<string>? Rows,
string? Title);
private record Record(string Directory,
string File,
string[] Lines);
@ -30,7 +42,7 @@ internal static partial class HelperMarkdown
string FileNameWithoutExtension,
ReadOnlyDictionary<string, object> FrontMatterYaml,
string H1,
bool IsGitOthersModifiedAndDeletedExcludingStandard,
bool? IsGitOthersModifiedAndDeletedExcludingStandard,
bool IsKanbanIndex,
bool IsKanbanMarkdown,
DateTime LastWriteDateTime,
@ -49,15 +61,27 @@ internal static partial class HelperMarkdown
private record MarkdownFileH1AndRelativePath(MarkdownFile? MarkdownFile, string[]? Lines, string? H1, string? RelativePath);
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(Dictionary<string, object>))]
internal partial class DictionaryStringAndObjectSourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(Dictionary<string, JsonElement>))]
internal partial class DictionaryStringAndJsonElementSourceGenerationContext : JsonSerializerContext
{
}
[GeneratedRegex("([A-Z]+(.))")]
private static partial Regex UpperCase();
[GeneratedRegex("(~~)?(#)([a-zA-Z0-9]{6})(~~)?( )")]
private static partial Regex HtmlColor();
[GeneratedRegex("[\\s!?.,@:;|\\\\/\"'`£$%\\^&*{}[\\]()<>~#+\\-=_¬]+")]
private static partial Regex InvalidCharacter();
private static MarkdownExtra GetMarkdownExtra(MarkdownFileAndLines markdownFileAndLines)
{
MarkdownExtra result;
@ -301,10 +325,10 @@ internal static partial class HelperMarkdown
if (!directoryInfo.Exists || (!string.IsNullOrEmpty(directoryInfo.LinkTarget) && !Directory.Exists(directoryInfo.LinkTarget)))
continue;
collection.AddRange(GetFiles(appSettings, directoryInfo, SearchOption.TopDirectoryOnly));
foreach (FileInfo file in collection)
results.Add(file);
foreach (FileInfo fileInfo in collection)
results.Add(fileInfo);
}
return new(results);
return (from l in results orderby l.FullName select l).ToArray().AsReadOnly();
}
internal static LineNumber GetLineNumbers(FileInfo fileInfo)
@ -525,7 +549,7 @@ internal static partial class HelperMarkdown
h1Check = $"# {h1[2..]}";
if (h1Check.Length == h1.Length && h1Check != h1)
{
if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
lines[markdownFile.LineNumber.H1.Value] = h1Check;
File.WriteAllLines(markdownFile.File, lines);
@ -541,7 +565,7 @@ internal static partial class HelperMarkdown
checkName = Path.Combine(markdownFile.Directory, checkFileName);
if (checkName == markdownFile.File)
continue;
if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
File.Move(markdownFile.File, checkName);
result += 1;
@ -658,6 +682,7 @@ internal static partial class HelperMarkdown
Input result;
string? destination = null;
bool useProcessStart = false;
string? replaceWithTitle = null;
string source = Path.GetFullPath(args[0]);
for (int i = 1; i < args.Count; i++)
{
@ -667,6 +692,8 @@ internal static partial class HelperMarkdown
useProcessStart = args[i + 1] == "true";
else if (args[i][1] == 'd')
destination = Path.GetFullPath(args[i + 1]);
else if (args[i][1] == 't')
replaceWithTitle = args[i + 1];
i++;
}
}
@ -678,11 +705,11 @@ internal static partial class HelperMarkdown
if (!Directory.Exists(destination))
_ = Directory.CreateDirectory(destination);
}
result = new(destination, source, useProcessStart);
result = new(Destination: destination, Source: source, ReplaceWithTitle: replaceWithTitle, UseProcessStart: useProcessStart);
return result;
}
private static ReadOnlyDictionary<string, MarkdownFileAndLines> GetRelativeToCollection(AppSettings appSettings, Input input, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
private static ReadOnlyDictionary<string, MarkdownFileAndLines> GetRelativeToCollection(AppSettings appSettings, Input input, ReadOnlyCollection<string>? gitOthersModifiedAndDeletedExcludingStandardFiles)
{
Dictionary<string, MarkdownFileAndLines> results = [];
string h1;
@ -696,17 +723,22 @@ internal static partial class HelperMarkdown
string fileNameWithoutExtension;
ReadOnlyCollection<string> lines;
ReadOnlyDictionary<string, object> frontMatterYaml;
bool isGitOthersModifiedAndDeletedExcludingStandard;
bool? isGitOthersModifiedAndDeletedExcludingStandard;
ReadOnlyCollection<FileInfo> files = GetFiles(appSettings, input);
foreach (FileInfo fileInfo in files)
{ // cSpell:disable
if (fileInfo.DirectoryName is null)
continue;
key = Path.GetRelativePath(input.Source, fileInfo.FullName);
isWithinSource = fileInfo.FullName.Contains(input.Source);
isGitOthersModifiedAndDeletedExcludingStandard = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(fileInfo.FullName);
if (!isWithinSource && results.ContainsKey(key))
continue;
if (gitOthersModifiedAndDeletedExcludingStandardFiles is null)
isGitOthersModifiedAndDeletedExcludingStandard = null;
else
{
isWithinSource = fileInfo.FullName.Contains(input.Source);
isGitOthersModifiedAndDeletedExcludingStandard = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(fileInfo.FullName);
if (!isWithinSource && results.ContainsKey(key))
continue;
}
lineNumber = GetLineNumbers(fileInfo);
lines = lineNumber.Lines;
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName);
@ -716,7 +748,7 @@ internal static partial class HelperMarkdown
(type, h1) = GetTypeAndH1(appSettings, h1, lines, lineNumber);
else
{
if (!isGitOthersModifiedAndDeletedExcludingStandard)
if (isGitOthersModifiedAndDeletedExcludingStandard is not null && !isGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
type = appSettings.DefaultNoteType;
File.WriteAllLines(fileInfo.FullName, ["---", $"type: {type}\"", "---", string.Empty, $"# {h1}"]);
@ -724,20 +756,20 @@ internal static partial class HelperMarkdown
}
isKanbanMarkdown = fileInfo.Name.EndsWith(".knb.md");
isKanbanIndex = fileNameWithoutExtension == "index" && type.StartsWith("kanb", StringComparison.OrdinalIgnoreCase);
markdownFile = new(fileInfo.CreationTime,
fileInfo.DirectoryName,
fileInfo.Extension,
fileInfo.FullName,
fileInfo.Name,
fileNameWithoutExtension,
frontMatterYaml,
h1,
isGitOthersModifiedAndDeletedExcludingStandard,
isKanbanIndex,
isKanbanMarkdown,
fileInfo.LastWriteTime,
lineNumber,
type);
markdownFile = new(CreationDateTime: fileInfo.CreationTime,
Directory: fileInfo.DirectoryName,
Extension: fileInfo.Extension,
File: fileInfo.FullName,
FileName: fileInfo.Name,
FileNameWithoutExtension: fileNameWithoutExtension,
FrontMatterYaml: frontMatterYaml,
H1: h1,
IsGitOthersModifiedAndDeletedExcludingStandard: isGitOthersModifiedAndDeletedExcludingStandard,
IsKanbanIndex: isKanbanIndex,
IsKanbanMarkdown: isKanbanMarkdown,
LastWriteDateTime: fileInfo.LastWriteTime,
LineNumber: lineNumber,
Type: type);
results.Add(key, new(markdownFile, lines.ToArray()));
} // cSpell:restore
return new(results);
@ -763,7 +795,7 @@ internal static partial class HelperMarkdown
markdownFile = relativeTo.Value.MarkdownFile;
if (markdownFile.IsKanbanMarkdown)
continue;
if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
if (markdownFile.LineNumber.FrontMatterYamlEnd is null)
continue;
@ -797,7 +829,7 @@ internal static partial class HelperMarkdown
circularReference = false;
lines = relativeTo.Value.Lines;
markdownFile = relativeTo.Value.MarkdownFile;
if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
for (int i = 0; i < lines.Length; i++)
{
@ -859,7 +891,7 @@ internal static partial class HelperMarkdown
found = false;
lines = relativeTo.Value.Lines;
markdownFile = relativeTo.Value.MarkdownFile;
if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
for (int i = 0; i < lines.Length; i++)
{
@ -912,7 +944,7 @@ internal static partial class HelperMarkdown
write = false;
lines = relativeTo.Value.Lines;
markdownFile = relativeTo.Value.MarkdownFile;
if (!input.UseProcessStart && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (!input.UseProcessStart && markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
for (int i = 0; i < lines.Length; i++)
{
@ -940,7 +972,7 @@ internal static partial class HelperMarkdown
}
if (!write)
continue;
if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
File.WriteAllLines(markdownFile.File, lines);
result += 1;
@ -975,7 +1007,7 @@ internal static partial class HelperMarkdown
markdownFile = relativeTo.Value.MarkdownFile;
if (markdownFile.IsKanbanIndex)
continue;
if (!input.UseProcessStart && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (!input.UseProcessStart && markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
if (!File.Exists(markdownFile.File))
continue;
@ -1040,7 +1072,7 @@ internal static partial class HelperMarkdown
}
if (!write)
continue;
if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
File.WriteAllLines(markdownFile.File, lines);
result += 1;
@ -1057,18 +1089,12 @@ internal static partial class HelperMarkdown
MarkdownFileAndLines? markdownFileAndLines = GetKanbanIndexMarkdownFileAndLines(relativeToCollection);
if (markdownFileAndLines is not null && File.Exists(markdownFileAndLines.MarkdownFile.File))
{
ReadOnlyDictionary<string, List<Card>> columnsToCards;
ReadOnlyDictionary<string, List<Card>> columnsToCards = GetColumnsToCards(input, relativeToCollection, markdownFileAndLines);
string jsonFile = Path.Combine(input.Destination, $"{nameof(columnsToCards)}.json");
if (File.Exists(jsonFile))
File.Delete(jsonFile);
columnsToCards = GetColumnsToCards(input, relativeToCollection, markdownFileAndLines);
if (columnsToCards.Count == 0)
File.WriteAllText(jsonFile, "{}");
else
{
string json = JsonSerializer.Serialize(columnsToCards, ColumnsAndCardsSourceGenerationContext.Default.ReadOnlyDictionaryStringListCard);
string old = !File.Exists(jsonFile) ? string.Empty : File.ReadAllText(jsonFile);
string json = columnsToCards.Count == 0 ? "{}" : JsonSerializer.Serialize(columnsToCards, ColumnsAndCardsSourceGenerationContext.Default.ReadOnlyDictionaryStringListCard);
if (json != old)
File.WriteAllText(jsonFile, json);
}
}
}
@ -1122,7 +1148,7 @@ internal static partial class HelperMarkdown
results.Insert(0, string.Empty);
}
results.Insert(0, "---");
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
{
results.Insert(0, updatedLine);
results.Insert(0, createdLine);
@ -1140,7 +1166,7 @@ internal static partial class HelperMarkdown
}
if (markdownFile.LineNumber.Type is null)
results.Insert(markdownFile.LineNumber.FrontMatterYamlEnd.Value, typeLine);
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
{
if (markdownFile.LineNumber.Updated is null)
results.Insert(markdownFile.LineNumber.FrontMatterYamlEnd.Value, updatedLine);
@ -1176,7 +1202,7 @@ internal static partial class HelperMarkdown
}
if (results.Count == lines.Length && string.Join('\r', lines) == string.Join('\r', results))
continue;
if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard)
if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard is not null && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard.Value)
continue;
File.WriteAllLines(markdownFile.File, results);
File.SetLastWriteTime(markdownFile.File, markdownFile.LastWriteDateTime);
@ -1235,7 +1261,313 @@ internal static partial class HelperMarkdown
logger.LogInformation("{updated} Markdown file(s) were updated", updated);
}
if (!string.IsNullOrEmpty(input.Destination))
{
SaveColumnToCards(input, relativeToCollection);
SaveTablesToJson(appSettings, logger, input);
}
}
private static void SaveTablesToJson(AppSettings appSettings, ILogger<Worker> logger, Input input)
{
if (string.IsNullOrEmpty(input.Destination))
throw new NotSupportedException();
string[] lines;
string fileName;
List<Block> blocks;
MarkdownFile markdownFile;
List<string> fileNames = [];
ReadOnlyCollection<Table> tables;
ReadOnlyCollection<Block> javaScriptObjectNotationBlocks;
ReadOnlyCollection<Block> yetAnotherMarkupLanguageBlocks;
ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles: null);
foreach (KeyValuePair<string, MarkdownFileAndLines> relativeTo in relativeToCollection)
{
if (relativeTo.Value.Lines.Length == 0)
continue;
lines = relativeTo.Value.Lines;
markdownFile = relativeTo.Value.MarkdownFile;
if (markdownFile.IsKanbanIndex)
continue;
if (markdownFile.IsKanbanMarkdown)
continue;
if (markdownFile.FileName.StartsWith("index.yml.md"))
continue;
if (!File.Exists(markdownFile.File))
continue;
tables = GetTables(lines);
javaScriptObjectNotationBlocks = GetJavaScriptObjectNotationBlocks(lines);
yetAnotherMarkupLanguageBlocks = GetYetAnotherMarkupLanguageBlocks(lines);
if (tables.Count == 0 && javaScriptObjectNotationBlocks.Count == 0 && yetAnotherMarkupLanguageBlocks.Count == 0)
continue;
fileName = Path.Combine(input.Destination, $"{markdownFile.FileNameWithoutExtension}.json");
if (fileNames.Contains(fileName))
continue;
fileNames.Add(fileName);
blocks = [];
blocks.AddRange(GetBlocks(tables));
blocks.AddRange(javaScriptObjectNotationBlocks);
blocks.AddRange(GetBlocks(logger, markdownFile, yetAnotherMarkupLanguageBlocks));
if (blocks.Count == 0)
continue;
WriteBlocks(logger, input, markdownFile, fileName, blocks.AsReadOnly());
}
}
private static ReadOnlyCollection<Table> GetTables(string[] lines)
{
List<Table> results = [];
Table table;
string? title;
string[] segments;
int? columnsLine = null;
List<ReadOnlyCollection<string>> rows = [];
string[]? columns = null;
for (int i = 0; i < lines.Length; i++)
{
if (columns is null && (!lines[i].StartsWith('|') || !lines[i].EndsWith('|') || i + 3 >= lines.Length))
continue;
if (columns is null && (lines[i + 1].Length < 3 || lines[i + 1][0] != '|' || (lines[i + 1][1] is not ':' and not '-')))
continue;
if (columns is null)
{
columnsLine = i;
segments = lines[i][1..^1].Split('|');
columns = (from l in segments select l.Trim()).ToArray();
i++;
continue;
}
segments = lines[i].Length < 3 ? [] : lines[i][1..^1].Split('|');
rows.Add((from l in segments select l.Trim()).ToArray().AsReadOnly());
if (columns is not null && columnsLine is not null && string.IsNullOrEmpty(lines[i]))
{
if (columnsLine.Value - 2 > 0 && lines[columnsLine.Value - 2].StartsWith('#'))
title = lines[columnsLine.Value - 2];
else if (columnsLine.Value - 4 > 0 && lines[columnsLine.Value - 4].StartsWith('#'))
title = lines[columnsLine.Value - 4];
else
title = null;
rows.RemoveAt(rows.Count - 1);
table = new(columns.AsReadOnly(), columnsLine.Value, rows.AsReadOnly(), title);
results.Add(table);
columnsLine = null;
columns = null;
rows = [];
}
}
return results.AsReadOnly();
}
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 ReadOnlyCollection<Block> GetBlocks(ReadOnlyCollection<Table> tables)
{
List<Block> results = [];
Block block;
string json;
foreach (Table table in tables)
{
if (table.Title is null)
continue;
if (table.Rows.Count == 0)
continue;
json = GetJson(table);
block = new(Line: table.ColumnsLine, Json: json, RowCount: table.Rows.Count, Rows: null, Title: table.Title);
results.Add(block);
}
return results.AsReadOnly();
}
private static string GetJson(Table table)
{
string result;
string line;
string value;
string[] segments;
List<string> lines = [];
for (int i = 0; i < table.Rows.Count; i++)
{
line = "{";
segments = table.Rows[i].ToArray();
if (segments.Length != table.Columns.Count)
break;
for (int c = 0; c < segments.Length; c++)
{
value = segments[c].Replace("\\", "\\\\").Replace("\"", "\\\"");
line += string.Concat('"', table.Columns[c].Trim('"'), '"', ':', '"', value, '"', ',');
}
line = string.Concat(line[..^1], '}');
lines.Add(line);
}
result = string.Concat('[', Environment.NewLine, string.Join($",{Environment.NewLine}", lines), Environment.NewLine, ']');
return result;
}
private static ReadOnlyCollection<Block> GetJavaScriptObjectNotationBlocks(string[] lines)
{
List<Block> results = [];
string json;
string? title;
int? blockLine = null;
List<string> rows = [];
Block javaScriptObjectNotationBlock;
for (int i = 0; i < lines.Length; i++)
{
if (blockLine is null && !lines[i].StartsWith("```json"))
continue;
if (blockLine is null)
{
blockLine = i;
continue;
}
rows.Add(lines[i]);
if (blockLine is not null && lines[i] == "```")
{
rows.RemoveAt(rows.Count - 1);
if (blockLine.Value - 2 > 0 && lines[blockLine.Value - 2].StartsWith('#'))
title = lines[blockLine.Value - 2];
else if (blockLine.Value - 4 > 0 && lines[blockLine.Value - 4].StartsWith('#'))
title = lines[blockLine.Value - 4];
else
title = null;
if (string.IsNullOrEmpty(title))
continue;
json = string.Join(Environment.NewLine, rows);
javaScriptObjectNotationBlock = new(Line: blockLine.Value, Json: json, RowCount: rows.Count, Rows: null, Title: title);
results.Add(javaScriptObjectNotationBlock);
blockLine = null;
rows = [];
}
}
return results.AsReadOnly();
}
private static ReadOnlyCollection<Block> GetYetAnotherMarkupLanguageBlocks(string[] lines)
{
List<Block> results = [];
string? title = null;
int? blockLine = null;
List<string> rows = [];
Block yetAnotherMarkupLanguageBlock;
if (lines[0] == "---")
{
for (int i = 1; i < lines.Length; i++)
{
rows.Add(lines[i]);
if (lines[i] == "---")
{
rows.RemoveAt(rows.Count - 1);
yetAnotherMarkupLanguageBlock = new(Line: 0, Json: null, RowCount: rows.Count, Rows: rows.AsReadOnly(), Title: title);
results.Add(yetAnotherMarkupLanguageBlock);
rows = [];
}
}
}
rows = [];
for (int i = 0; i < lines.Length; i++)
{
if (blockLine is null && !lines[i].StartsWith("```yml") && !lines[i].StartsWith("```yaml"))
continue;
if (blockLine is null)
{
blockLine = i;
continue;
}
rows.Add(lines[i]);
if (blockLine is not null && lines[i] == "```")
{
rows.RemoveAt(rows.Count - 1);
if (blockLine.Value - 2 > 0 && lines[blockLine.Value - 2].StartsWith('#'))
title = lines[blockLine.Value - 2];
else if (blockLine.Value - 4 > 0 && lines[blockLine.Value - 4].StartsWith('#'))
title = lines[blockLine.Value - 4];
else
title = null;
yetAnotherMarkupLanguageBlock = new(Line: blockLine.Value, Json: null, RowCount: rows.Count, Rows: rows.AsReadOnly(), Title: title);
results.Add(yetAnotherMarkupLanguageBlock);
blockLine = null;
rows = [];
}
}
return results.AsReadOnly();
}
private static ReadOnlyCollection<Block> GetBlocks(ILogger<Worker> logger, MarkdownFile markdownFile, ReadOnlyCollection<Block> yetAnotherMarkupLanguageBlocks)
{
List<Block> results = [];
string key;
Block block;
string json;
string text;
Dictionary<string, object>? keyValuePairs;
Dictionary<string, object> keyValuePairsB = [];
#pragma warning disable IL3050
IDeserializer deserializer = new DeserializerBuilder().Build();
#pragma warning restore IL3050
foreach (Block yaml in yetAnotherMarkupLanguageBlocks)
{
if (yaml.Rows is null || yaml.RowCount == 0)
continue;
if (yaml.Title is null && yaml.Line != 0)
continue;
text = string.Join(Environment.NewLine, yaml.Rows);
try
{ keyValuePairs = deserializer.Deserialize<Dictionary<string, object>>(text); }
catch (Exception)
{
keyValuePairs = null;
logger.LogWarning("Invalid yaml file for <{file}>", markdownFile.FileName);
}
if (keyValuePairs is null)
continue;
keyValuePairsB.Clear();
foreach (KeyValuePair<string, object> keyValuePair in keyValuePairs)
{
key = GetParamCase(keyValuePair.Key);
if (keyValuePairsB.ContainsKey(key))
continue;
keyValuePairsB.Add(key, keyValuePair.Value);
}
try
{ json = JsonSerializer.Serialize(keyValuePairsB, DictionaryStringAndObjectSourceGenerationContext.Default.DictionaryStringObject); }
catch (Exception)
{
logger.LogWarning("yaml contains special values not allowed in AOT <{file}>", markdownFile.FileName);
continue;
}
block = new(Line: yaml.Line, Json: json, RowCount: yaml.Rows.Count, Rows: null, Title: yaml.Title);
results.Add(block);
}
return results.AsReadOnly();
}
private static void WriteBlocks(ILogger<Worker> logger, Input input, MarkdownFile markdownFile, string fileName, ReadOnlyCollection<Block> blocks)
{
string paramCase;
List<string> lines = [];
foreach (Block block in blocks.OrderBy(l => l.Line))
{
paramCase = block.Title is null ? $"Line-{block.Line}" : GetParamCase(block.Title);
if (!string.IsNullOrEmpty(input.ReplaceWithTitle) && paramCase == input.ReplaceWithTitle)
paramCase = GetParamCase(markdownFile.FileNameWithoutExtension);
lines.Add($"\"{paramCase}\": {block.Json}");
}
string old = !File.Exists(fileName) ? string.Empty : File.ReadAllText(fileName);
string json = string.Concat('{', Environment.NewLine, string.Join($",{Environment.NewLine}", lines), Environment.NewLine, '}');
if (json != old)
{
File.WriteAllText(fileName, json);
logger.LogInformation("Updated json file for <{fileName}>", fileName);
}
}
}

7
Scripts/markdown.js Normal file
View File

@ -0,0 +1,7 @@
// import data from './oi-metrology-viewer-0-Line-yaml.json' with { type: 'json' };
// import data from '../.vscode/oi-metrology-viewer-0-Line-yaml.json' with { type: 'json' };
import data from '../.vscode/.helper/hosts-legend-table.json' with { type: 'json' };
data.forEach(element => {
console.log(element.Concat);
});