diff --git a/source/Models/FrontMatter.cs b/source/Models/FrontMatter.cs
index b4ac972f334c5c0a939b9adb06ebf1b85829b326..2895bd8bf9e76205a850132cfcf530e7b6859be0 100644
--- a/source/Models/FrontMatter.cs
+++ b/source/Models/FrontMatter.cs
@@ -1,3 +1,6 @@
+using Serilog;
+using SuCoS.Helpers;
+using SuCoS.Parser;
using YamlDotNet.Serialization;
namespace SuCoS.Models;
@@ -104,4 +107,58 @@ public class FrontMatter : IFrontMatter
SourceRelativePath = sourcePath;
SourceFullPath = sourcePath;
}
+
+ ///
+ /// Create a front matter from a given metadata + content
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static FrontMatter Parse(
+ string metadata,
+ in string rawContent,
+ in string fileFullPath,
+ in string fileRelativePath,
+ IMetadataParser parser
+ )
+ {
+ ArgumentNullException.ThrowIfNull(fileFullPath);
+ ArgumentNullException.ThrowIfNull(fileRelativePath);
+ ArgumentNullException.ThrowIfNull(parser);
+
+ var frontMatter = parser.Parse(metadata);
+ var section = SiteHelper.GetSection(fileRelativePath);
+ frontMatter.RawContent = rawContent;
+ frontMatter.Section = section;
+ frontMatter.SourceRelativePath = fileRelativePath;
+ frontMatter.SourceFullPath = fileFullPath;
+ frontMatter.Type ??= section;
+ return frontMatter;
+ }
+
+ ///
+ /// Create a front matter from a given content
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static FrontMatter Parse(
+ in string fileFullPath,
+ in string fileRelativePath,
+ IMetadataParser parser,
+ string content
+ )
+ {
+ ArgumentNullException.ThrowIfNull(fileFullPath);
+ ArgumentNullException.ThrowIfNull(fileRelativePath);
+ ArgumentNullException.ThrowIfNull(parser);
+
+ var (metadata, rawContent) = parser.SplitFrontMatter(content);
+ return Parse(metadata, rawContent, fileFullPath, fileRelativePath, parser);
+ }
}
diff --git a/source/Models/Site.cs b/source/Models/Site.cs
index 67f58c3b86d462efdad3dc788d531190757ab01d..a70d290c117b88139ae321df3c5904adb471bb50 100644
--- a/source/Models/Site.cs
+++ b/source/Models/Site.cs
@@ -1,3 +1,4 @@
+using CommandLine;
using Serilog;
using SuCoS.Helpers;
using SuCoS.Models.CommandLineOptions;
@@ -330,13 +331,20 @@ public class Site : ISite
}
}
- private Page? ParseSourceFile(in string filePath, in IPage? parent, BundleType bundleType = BundleType.none)
+ private Page? ParseSourceFile(in string fileFullPath, in IPage? parent, BundleType bundleType = BundleType.none)
{
Page? page = null;
try
{
- var frontMatter = Parser.ParseFrontmatterAndMarkdownFromFile(filePath, SourceContentPath)
- ?? throw new FormatException($"Error parsing front matter for {filePath}");
+ var fileContent = File.ReadAllText(fileFullPath);
+ var fileRelativePath = Path.GetRelativePath(
+ SourceContentPath ?? string.Empty,
+ fileFullPath
+ );
+ // var frontMatter = Parser.ParseFrontmatterAndMarkdown(fileFullPath, fileRelativePath, fileContent)
+ // ?? throw new FormatException($"Error parsing front matter for {fileFullPath}");
+ var frontMatter = FrontMatter.Parse(fileFullPath, fileRelativePath, Parser, fileContent)
+ ?? throw new FormatException($"Error parsing front matter for {fileFullPath}");
if (IsValidPage(frontMatter, Options))
{
@@ -349,7 +357,7 @@ public class Site : ISite
}
catch (Exception ex)
{
- Logger.Error(ex, "Error parsing file {file}", filePath);
+ Logger.Error(ex, "Error parsing file {file}", fileFullPath);
}
// Use interlocked to safely increment the counter in a multi-threaded environment
diff --git a/source/Parsers/IMetadataParser.cs b/source/Parsers/IMetadataParser.cs
index 84d293089e8c46db6ecc3f46f8a5f0838d69b678..21974a94e426209de83929f6a9f238f3e75e826b 100644
--- a/source/Parsers/IMetadataParser.cs
+++ b/source/Parsers/IMetadataParser.cs
@@ -7,22 +7,12 @@ namespace SuCoS.Parser;
///
public interface IMetadataParser
{
- ///
- /// Extract the front matter from the content file.
- ///
- ///
- ///
- ///
- IFrontMatter? ParseFrontmatterAndMarkdownFromFile(in string fileFullPath, in string sourceContentPath);
-
///
/// Extract the front matter from the content.
///
- ///
///
- ///
///
- IFrontMatter? ParseFrontmatterAndMarkdown(in string fileFullPath, in string fileRelativePath, in string fileContent);
+ (string, string) SplitFrontMatter(in string fileContent);
///
/// Parse a string content to the T class.
diff --git a/source/Parsers/YAMLParser.cs b/source/Parsers/YAMLParser.cs
index 7c1fbd79f00a4ea0dfe142c54506b394578683a0..6b186f766728fcb57494232075e2a448682ac646 100644
--- a/source/Parsers/YAMLParser.cs
+++ b/source/Parsers/YAMLParser.cs
@@ -1,4 +1,5 @@
using System.Text;
+using FolkerKinzel.Strings;
using SuCoS.Helpers;
using SuCoS.Models;
using YamlDotNet.Serialization;
@@ -26,45 +27,71 @@ public class YAMLParser : IMetadataParser
.Build();
}
+ // ///
+ // public IFrontMatter ParseFrontmatterAndMarkdown(
+ // in string fileFullPath,
+ // in string fileRelativePath,
+ // in string fileContent
+ // )
+ // {
+ // var (yaml, rawContent) = SplitFrontMatter(fileContent);
+
+ // // Now, you can parse the YAML front matter
+ // var page = ParseYAML(fileFullPath, fileRelativePath, yaml, rawContent);
+
+ // return page;
+ // }
+
+ // private FrontMatter ParseYAML(
+ // in string fileFullPath,
+ // in string fileRelativePath,
+ // string yaml,
+ // in string rawContent
+ // )
+ // {
+ // var frontMatter =
+ // deserializer.Deserialize(
+ // new StringReader(yaml)
+ // ) ?? throw new FormatException("Error parsing front matter");
+ // var section = SiteHelper.GetSection(fileRelativePath);
+ // frontMatter.RawContent = rawContent;
+ // frontMatter.Section = section;
+ // frontMatter.SourceRelativePath = fileRelativePath;
+ // frontMatter.SourceFullPath = fileFullPath;
+ // frontMatter.Type ??= section;
+ // return frontMatter;
+ // }
+
///
- public IFrontMatter ParseFrontmatterAndMarkdownFromFile(
- in string fileFullPath,
- in string? sourceContentPath = null
- )
+ public T Parse(string content)
{
- ArgumentNullException.ThrowIfNull(fileFullPath);
-
- string? fileContent;
- string? fileRelativePath;
try
{
- fileContent = File.ReadAllText(fileFullPath);
- fileRelativePath = Path.GetRelativePath(
- sourceContentPath ?? string.Empty,
- fileFullPath
- );
+ return deserializer.Deserialize(content);
}
- catch (Exception ex)
+ catch
{
- throw new FileNotFoundException(fileFullPath, ex);
+ throw new FormatException("Error parsing front matter");
}
-
- return ParseFrontmatterAndMarkdown(
- fileFullPath,
- fileRelativePath,
- fileContent
- );
}
///
- public IFrontMatter ParseFrontmatterAndMarkdown(
- in string fileFullPath,
- in string fileRelativePath,
- in string fileContent
- )
+ public void Export(T data, string path)
{
- ArgumentNullException.ThrowIfNull(fileRelativePath);
+ var deserializer = new SerializerBuilder()
+ .IgnoreFields()
+ .ConfigureDefaultValuesHandling(
+ DefaultValuesHandling.OmitEmptyCollections
+ | DefaultValuesHandling.OmitDefaults
+ | DefaultValuesHandling.OmitNull)
+ .Build();
+ var dataString = deserializer.Serialize(data);
+ File.WriteAllText(path, dataString);
+ }
+ ///
+ public (string, string) SplitFrontMatter(in string fileContent)
+ {
using var content = new StringReader(fileContent);
var frontMatterBuilder = new StringBuilder();
string? line;
@@ -74,55 +101,12 @@ public class YAMLParser : IMetadataParser
{
_ = frontMatterBuilder.AppendLine(line);
}
+ frontMatterBuilder.TrimEnd();
// Join the read lines to form the front matter
var yaml = frontMatterBuilder.ToString();
var rawContent = content.ReadToEnd();
- // Now, you can parse the YAML front matter
- var page = ParseYAML(fileFullPath, fileRelativePath, yaml, rawContent);
-
- return page;
- }
-
- private FrontMatter ParseYAML(
- in string fileFullPath,
- in string fileRelativePath,
- string yaml,
- in string rawContent
- )
- {
- var frontMatter =
- deserializer.Deserialize(
- new StringReader(yaml)
- ) ?? throw new FormatException("Error parsing front matter");
- var section = SiteHelper.GetSection(fileRelativePath);
- frontMatter.RawContent = rawContent;
- frontMatter.Section = section;
- frontMatter.SourceRelativePath = fileRelativePath;
- frontMatter.SourceFullPath = fileFullPath;
- frontMatter.Type ??= section;
- return frontMatter;
- }
-
- ///
- public T Parse(string content)
- {
- var data = deserializer.Deserialize(content);
- return data;
- }
-
- ///
- public void Export(T data, string path)
- {
- var deserializer = new SerializerBuilder()
- .IgnoreFields()
- .ConfigureDefaultValuesHandling(
- DefaultValuesHandling.OmitEmptyCollections
- | DefaultValuesHandling.OmitDefaults
- | DefaultValuesHandling.OmitNull)
- .Build();
- var dataString = deserializer.Serialize(data);
- File.WriteAllText(path, dataString);
+ return (yaml, rawContent);
}
}
diff --git a/test/Parser/YAMLParserTests.cs b/test/Parser/YAMLParserTests.cs
index 4f8c8ffb9e4eee7dfa7ba298fc4698170d3f7df3..2b24f24227546d04a00e3fec24786b6aa95aa3f1 100644
--- a/test/Parser/YAMLParserTests.cs
+++ b/test/Parser/YAMLParserTests.cs
@@ -93,7 +93,7 @@ Date: 2023-04-01
public void ParseFrontmatter_ShouldParseTitleCorrectly(string fileContent, string expectedTitle)
{
// Arrange
- var frontMatter = parser.ParseFrontmatterAndMarkdown(fileRelativePathCONST, fileFullPathCONST, fileContent);
+ var frontMatter = FrontMatter.Parse(fileRelativePathCONST, fileFullPathCONST, parser, fileContent);
// Assert
Assert.Equal(expectedTitle, frontMatter.Title);
@@ -114,7 +114,7 @@ Date: 2023/01/01
var expectedDate = DateTime.Parse(expectedDateString, CultureInfo.InvariantCulture);
// Act
- var frontMatter = parser.ParseFrontmatterAndMarkdown(fileRelativePathCONST, fileFullPathCONST, fileContent);
+ var frontMatter = FrontMatter.Parse(fileRelativePathCONST, fileFullPathCONST, parser, fileContent);
// Assert
Assert.Equal(expectedDate, frontMatter.Date);
@@ -130,7 +130,7 @@ Date: 2023/01/01
var expectedExpiryDate = DateTime.Parse("2024-06-01", CultureInfo.InvariantCulture);
// Act
- var frontMatter = parser.ParseFrontmatterAndMarkdown(fileRelativePathCONST, fileFullPathCONST, pageContent);
+ var frontMatter = FrontMatter.Parse(fileRelativePathCONST, fileFullPathCONST, parser, pageContent);
// Assert
Assert.Equal("Test Title", frontMatter.Title);
@@ -142,7 +142,7 @@ Date: 2023/01/01
}
[Fact]
- public void ParseFrontmatter_ShouldThrowException_WhenInvalidYAMLSyntax()
+ public void ParseFrontmatter_ShouldThrowFormatException_WhenInvalidYAMLSyntax()
{
// Arrange
const string fileContent = @"---
@@ -151,7 +151,8 @@ Title
";
// Assert
- Assert.Throws(() => parser.ParseFrontmatterAndMarkdown(fileRelativePathCONST, fileFullPathCONST, fileContent));
+ Assert.Throws(() =>
+ FrontMatter.Parse(fileRelativePathCONST, fileFullPathCONST, parser, fileContent));
}
[Fact]
@@ -172,7 +173,8 @@ Title
public void ParseParams_ShouldFillParamsWithNonMatchingFields()
{
// Arrange
- var page = new Page(parser.ParseFrontmatterAndMarkdown(string.Empty, string.Empty, pageContent), site);
+ var frontMatter = FrontMatter.Parse(string.Empty, string.Empty, parser, pageContent);
+ var page = new Page(frontMatter, site);
// Assert
Assert.False(page.Params.ContainsKey("customParam"));
@@ -184,7 +186,7 @@ Title
{
// Arrange
var date = DateTime.Parse("2023-07-01", CultureInfo.InvariantCulture);
- var frontMatter = parser.ParseFrontmatterAndMarkdown(string.Empty, string.Empty, pageContent);
+ var frontMatter = FrontMatter.Parse(string.Empty, string.Empty, parser, pageContent);
Page page = new(frontMatter, site);
// Act
@@ -198,7 +200,7 @@ Title
public void ParseFrontmatter_ShouldCreateTags()
{
// Arrange
- var frontMatter = parser.ParseFrontmatterAndMarkdown(string.Empty, string.Empty, pageContent);
+ var frontMatter = FrontMatter.Parse(string.Empty, string.Empty, parser, pageContent);
Page page = new(frontMatter, site);
// Act
@@ -209,39 +211,26 @@ Title
}
[Fact]
- public void ParseFrontmatter_ShouldThrowExceptionWhenSiteIsNull()
+ public void FrontMatterParse_RawContentNull()
{
- _ = Assert.Throws(() => parser.ParseFrontmatterAndMarkdownFromFile(null!, "fakeFilePath"));
+ _ = Assert.Throws(() => FrontMatter.Parse("invalidFrontmatter", "", "fakePath", "fakePath", frontMatterParser));
}
[Fact]
- public void ParseFrontmatter_ShouldThrowExceptionWhenFilePathIsNull()
- {
- _ = Assert.Throws(() => parser.ParseFrontmatterAndMarkdownFromFile(null!));
- }
-
- [Fact]
- public void ParseFrontmatter_ShouldThrowExceptionWhenFilePathDoesNotExist()
- {
- _ = Assert.Throws(() => parser.ParseFrontmatterAndMarkdownFromFile("fakePath"));
- }
-
- [Fact]
- public void ParseFrontmatter_ShouldThrowExceptionWhenFilePathDoesNotExist2()
+ public void ParseYAML_ShouldThrowExceptionWhenFrontmatterIsInvalid()
{
- _ = Assert.Throws(() => parser.ParseFrontmatterAndMarkdown(null!, null!, "fakeContent"));
+ _ = Assert.Throws(() => parser.Parse("invalidFrontmatter"));
}
[Fact]
- public void ParseFrontmatter_ShouldHandleEmptyFileContent()
+ public void ParseYAML_ShouldSplitTheMetadata()
{
- _ = Assert.Throws(() => parser.ParseFrontmatterAndMarkdown("fakeFilePath", "/fakeFilePath", string.Empty));
- }
+ // Act
+ var (metadata, rawContent) = parser.SplitFrontMatter(pageContent);
- [Fact]
- public void ParseYAML_ShouldThrowExceptionWhenFrontmatterIsInvalid()
- {
- _ = Assert.Throws(() => parser.ParseFrontmatterAndMarkdown("fakeFilePath", "/fakeFilePath", "invalidFrontmatter"));
+ // Assert
+ Assert.Equal(pageFrontmaterCONST.TrimEnd(), metadata);
+ Assert.Equal(pageMarkdownCONST, rawContent);
}
[Fact]
@@ -256,16 +245,6 @@ Title
Assert.Equal("https://www.example.com/", siteSettings.BaseURL);
}
- [Fact]
- public void ParseSiteSettings_ShouldReturnContent()
- {
- // Arrange
- var frontMatter = parser.ParseFrontmatterAndMarkdown("fakeFilePath", "/fakeFilePath", pageContent);
-
- // Assert
- Assert.Equal(pageMarkdownCONST, frontMatter.RawContent);
- }
-
[Fact]
public void SiteParams_ShouldHandleEmptyContent()