Skip to content

Commit

Permalink
Merge pull request #30 from Nodsoft/develop
Browse files Browse the repository at this point in the history
Enhance frontmatter ingest & manifest generation
  • Loading branch information
SakuraIsayeki authored Aug 11, 2023
2 parents e80b8ec + b3dfbfd commit 2e8c5ba
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Nodsoft.MoltenObsidian\Nodsoft.MoltenObsidian.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
using System.Security.Cryptography;
using Nodsoft.MoltenObsidian.Vault;
using Nodsoft.MoltenObsidian.Vaults.FileSystem;
using Nodsoft.MoltenObsidian.Manifest;

namespace Nodsoft.MoltenObsidian.Tool.Services;
namespace Nodsoft.MoltenObsidian.Manifest;

/// <summary>
/// Provides manifest generation for a filesystem-based Molten Obsidian vault.
/// </summary>
public static class VaultManifestGenerator
{
/// <summary>
/// Generates a manifest for the specified filesystem vault.
/// Generates a manifest for the specified vault.
/// </summary>
/// <param name="vault">The path to the vault.</param>
/// <returns>A <see cref="RemoteVaultManifest"/> instance.</returns>
public static async Task<RemoteVaultManifest> GenerateManifestAsync(FileSystemVault vault)
public static async Task<RemoteVaultManifest> GenerateManifestAsync(IVault vault)
{
List<ManifestFile> files = new();

Expand Down Expand Up @@ -46,11 +44,27 @@ private static async Task<ManifestFile> ExtractManifestAsync(IVaultFile file)
// Read the file. We'll need it later.
await using Stream stream = await file.OpenReadAsync();

#if !NET7_0_OR_GREATER
byte[] fileBytes = new byte[stream.Length];
int readBytesCount = await stream.ReadAsync(fileBytes);

if (readBytesCount != stream.Length)
{
throw new InvalidOperationException("The file could not be read.");
}
#endif

// Build a new file object
return new()
{
Path = file.Path,
Hash = Convert.ToBase64String(await SHA256.HashDataAsync(stream)), // Create a SHA256 hash of the file

#if NET7_0_OR_GREATER
Hash = Convert.ToBase64String(await SHA256.HashDataAsync(stream)), // Create a SHA256 hash of the file
#else
Hash = Convert.ToBase64String(SHA256.HashData(fileBytes)), // Create a SHA256 hash of the file
#endif

Size = stream.Length,
ContentType = Manifest.MimeTypes.GetMimeType(file.Name), // A fuller namespace is required here because of a conflict with the other apparitions of MimeTypes.
Metadata = file is IVaultNote note ? (await note.ReadDocumentAsync()).Frontmatter : new()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using JetBrains.Annotations;
using Nodsoft.MoltenObsidian.Tool.Services;
using Nodsoft.MoltenObsidian.Vaults.FileSystem;
using Nodsoft.MoltenObsidian.Manifest;
using Spectre.Console;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ await AnsiConsole.Status().StartAsync("Generating static assets.", async ctx =>
if (settings.DebugMode)
{
AnsiConsole.Console.MarkupLine(/*lang=markdown*/$"[grey]Ignoring folders:[/] {string.Join("[grey], [/]", settings.IgnoredFolders ?? new[] { "*None*" })}");
AnsiConsole.Console.MarkupLine(/*lang=markdown*/$"[grey]Ignoring files:[/] {string.Join("[grey], [/]", settings.IgnoredFiles ?? new[] { "*None*" })}");
AnsiConsole.Console.MarkupLine(/*lang=md*/$"[grey]Ignoring folders:[/] {string.Join("[grey], [/]", settings.IgnoredFolders ?? new[] { "*None*" })}");
AnsiConsole.Console.MarkupLine(/*lang=md*/$"[grey]Ignoring files:[/] {string.Join("[grey], [/]", settings.IgnoredFiles ?? new[] { "*None*" })}");
AnsiConsole.Console.MarkupLine(settings.OutputPath is null
? /*lang=markdown*/$"[grey]Output path defaulted to current directory: [/]{Environment.CurrentDirectory}"
: /*lang=markdown*/$"[grey]Output path set: [/]{settings.OutputPath}"
? /*lang=md*/$"[grey]Output path defaulted to current directory: [/]{Environment.CurrentDirectory}"
: /*lang=md*/$"[grey]Output path set: [/]{settings.OutputPath}"
);
}
Expand All @@ -116,19 +116,12 @@ await AnsiConsole.Status().StartAsync("Generating static assets.", async ctx =>
}
List<InfoDataPair> fileData = await StaticSiteGenerator.CreateOutputFilesAsync(settings.OutputPath!.ToString(), pathFilePair);
// foreach((FileInfo file, byte[] data) in fileData)
// {
// await WriteDataAsync(file, data);
// }
await Task.WhenAll(fileData.Select(WriteDataAsync));
}
AnsiConsole.Console.MarkupLine(/*lang=markdown*/$"Wrote manifest to [green link]{settings.OutputPath}[/].");
AnsiConsole.Console.MarkupLine(/*lang=md*/$"Wrote static files to [green link]{settings.OutputPath}[/].");
});


return 0;
}

Expand All @@ -138,7 +131,7 @@ private static async Task WriteDataAsync(InfoDataPair pair)
{
pair.FileInfo.Directory.Create();
}
await using FileStream stream = pair.FileInfo.Open(FileMode.OpenOrCreate, FileAccess.Write);
await using FileStream stream = pair.FileInfo.Open(FileMode.Create, FileAccess.Write);
await stream.WriteAsync(pair.FileData);
await stream.FlushAsync();

Expand Down
59 changes: 53 additions & 6 deletions Nodsoft.MoltenObsidian/ObsidianText.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Nodsoft.MoltenObsidian.Converter;
using System.Text;
using Nodsoft.MoltenObsidian.Converter;
using Nodsoft.MoltenObsidian.Vault;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
Expand Down Expand Up @@ -97,14 +98,14 @@ public string ToHtml(ObsidianHtmlConverter converter) => _vaultFile is null
/// <returns>A tuple containing the YAML front matter and the remaining Obsidian Markdown content.</returns>
private static (string? frontMatter, string content) SplitYamlFrontMatter(string obsidianMarkdown)
{
// The front matter is a YAML document at the beginning of the file, delimited by three dashes.
static bool _LineDelimiterPredicate(string line) => line is "---";

// We need to find the first line with three dashes, and then the next line with three dashes.
// The content between the two lines is the front matter.
// If there is no front matter, the content is the whole file.
string[] lines = obsidianMarkdown.Split(new[] { Environment.NewLine }, StringSplitOptions.None);


string[] lines = SplitByNewline(obsidianMarkdown);
// string[] lines = obsidianMarkdown.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
TrimBom(ref lines[0]);

int firstLine = Array.FindIndex(lines, _LineDelimiterPredicate);
int secondLine = Array.FindIndex(lines, firstLine + 1, _LineDelimiterPredicate);

Expand All @@ -117,6 +118,9 @@ private static (string? frontMatter, string content) SplitYamlFrontMatter(string
string content = string.Join(Environment.NewLine, lines[(secondLine + 1)..]);

return (frontMatter, content);

// The front matter is a YAML document at the beginning of the file, delimited by three dashes.
static bool _LineDelimiterPredicate(string line) => line is "---";
}

/// <summary>
Expand All @@ -126,4 +130,47 @@ private static (string? frontMatter, string content) SplitYamlFrontMatter(string
/// <returns>A dictionary of key-value pairs.</returns>
/// <exception cref="YamlException">Thrown when the YAML front matter is invalid.</exception>
public static Dictionary<string, object> ParseYamlFrontMatter(string frontMatter) => _yamlDeserializer.Deserialize<Dictionary<string, object>>(frontMatter);

private static void TrimBom(scoped ref string text)
{
if (text.Length is not 0 && text[0] is '\uFEFF')
{
text = text[1..];
}
}

/// <summary>
/// Splits the specified string by newlines, handling first \r\n, then \r, then \n.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string[] SplitByNewline(ReadOnlySpan<char> input)
{
var result = new List<string>();

int previousIndex = 0;
for (int i = 0; i < input.Length; i++)
{
if (input[i] is '\n' || (input[i] is '\r' && (i == input.Length - 1 || input[i + 1] is not '\n')))
{
result.Add(input[previousIndex..i].ToString());

previousIndex = i + 1;
}
else if (input[i] is '\r' && i < input.Length - 1 && input[i + 1] is '\n')
{
result.Add(input[previousIndex..i].ToString());

previousIndex = i + 2;
i++;
}
}

if (previousIndex < input.Length)
{
result.Add(input[previousIndex..].ToString());
}

return result.ToArray();
}
}

0 comments on commit 2e8c5ba

Please sign in to comment.