From e23ef71bea9b20497489b8d660ac4bd496132b64 Mon Sep 17 00:00:00 2001 From: Bruno Massa Date: Sun, 18 Jun 2023 21:15:02 -0300 Subject: [PATCH] feat: content Date and future command line --- source/BaseGeneratorCommand.cs | 49 +++++++++++++++++++++++++--------- source/BuildOptions.cs | 15 +++++------ source/IGenerateOptions.cs | 5 ++++ source/Models/Frontmatter.cs | 20 ++++++++++++++ source/Parser/YAMLParser.cs | 16 ++++++++--- source/Program.cs | 23 +++++++++------- source/ServeOptions.cs | 15 +++++------ 7 files changed, 100 insertions(+), 43 deletions(-) diff --git a/source/BaseGeneratorCommand.cs b/source/BaseGeneratorCommand.cs index 281f104..e901baa 100644 --- a/source/BaseGeneratorCommand.cs +++ b/source/BaseGeneratorCommand.cs @@ -17,6 +17,11 @@ namespace SuCoS; /// public abstract class BaseGeneratorCommand { + /// + /// Command line options + /// + readonly IGenerateOptions options; + /// /// The configuration file name. /// @@ -161,6 +166,7 @@ public abstract class BaseGeneratorCommand { throw new ArgumentNullException(nameof(options)); } + this.options = options; Log.Information("Source path: {source}", propertyValue: options.Source); @@ -217,12 +223,25 @@ public abstract class BaseGeneratorCommand try { var frontmatter = ReadSourceFrontmatter(file.filePath, file.content, site, frontmatterParser); - site.Pages.Add(frontmatter); - site.RegularPages.Add(frontmatter); + + if (IsValidDate(frontmatter)) + { + site.Pages.Add(frontmatter); + site.RegularPages.Add(frontmatter); + + // Convert the Markdown content to HTML + frontmatter.ContentPreRendered = Markdown.ToHtml(frontmatter.ContentRaw); + frontmatter.Permalink = "/" + GetOutputPath(file.filePath, site, frontmatter); + + if (site.HomePage is null && string.IsNullOrEmpty(frontmatter.SourcePath) && frontmatter.SourceFileNameWithoutExtension == "index") + { + site.HomePage = frontmatter; + } + } } - catch + catch (Exception ex) { - Log.Error("Error parsing file {file}. Skipped.", file.filePath); + Log.Error(ex, "Error parsing file {file}", file.filePath); } // Use interlocked to safely increment the counter in a multi-threaded environment @@ -348,18 +367,22 @@ public abstract class BaseGeneratorCommand var frontmatter = frontmatterParser.ParseFrontmatter(site, filePath, ref content, this) ?? throw new FormatException($"Error parsing frontmatter for {filePath}"); - // Convert the Markdown content to HTML - frontmatter.ContentPreRendered = Markdown.ToHtml(frontmatter.ContentRaw); - frontmatter.Permalink = "/" + GetOutputPath(filePath, site, frontmatter); - - if (site.HomePage is null && string.IsNullOrEmpty(frontmatter.SourcePath) && frontmatter.SourceFileNameWithoutExtension == "index") - { - site.HomePage = frontmatter; - } - return frontmatter; } + /// + /// Check if the page have a publishing date from the past. + /// + /// The given page + /// + bool IsValidDate(Frontmatter frontmatter) + { + return (frontmatter.PublishDate is null && frontmatter.Date is null) + || options.Future + || (frontmatter.PublishDate != null && (frontmatter.PublishDate <= DateTime.Now)) + || (frontmatter.Date != null && (frontmatter.Date <= DateTime.Now)); + } + /// /// Gets the output path for the file. /// diff --git a/source/BuildOptions.cs b/source/BuildOptions.cs index 11b073a..b1454b1 100644 --- a/source/BuildOptions.cs +++ b/source/BuildOptions.cs @@ -5,18 +5,15 @@ namespace SuCoS; /// public class BuildOptions : IGenerateOptions { - /// - /// The path of the source files. - /// + /// public string Source { get; set; } = "."; - /// - /// The path of the output files. - /// + /// public string Output { get; set; } = "./public"; - /// - /// If true, the program will print more information. - /// + /// + public bool Future { get; set; } = false; + + /// public bool Verbose { get; set; } = false; } diff --git a/source/IGenerateOptions.cs b/source/IGenerateOptions.cs index f11cf04..a89f3be 100644 --- a/source/IGenerateOptions.cs +++ b/source/IGenerateOptions.cs @@ -15,6 +15,11 @@ public interface IGenerateOptions /// public string Output { get; set; } + /// + /// Consider + /// + bool Future { get; set; } + /// /// If true, the program will print more information. /// diff --git a/source/Models/Frontmatter.cs b/source/Models/Frontmatter.cs index aa5bebe..323df8e 100644 --- a/source/Models/Frontmatter.cs +++ b/source/Models/Frontmatter.cs @@ -16,6 +16,26 @@ public class Frontmatter /// public string Title { get; init; } + /// + /// Gets or sets the date of the page. + /// + public DateTime? Date { get; set; } + + /// + /// Gets or sets the last modification date of the page. + /// + public DateTime? LastMod { get; set; } + + /// + /// Gets or sets the publish date of the page. + /// + public DateTime? PublishDate { get; set; } + + /// + /// Gets or sets the expiry date of the page. + /// + public DateTime? ExpiryDate { get; set; } + /// /// The path of the file, if it's a file. /// diff --git a/source/Parser/YAMLParser.cs b/source/Parser/YAMLParser.cs index 5ac8d4c..ae7453e 100644 --- a/source/Parser/YAMLParser.cs +++ b/source/Parser/YAMLParser.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text.RegularExpressions; +using Serilog; using SuCoS.Models; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; @@ -14,7 +16,7 @@ namespace SuCoS.Parser; public partial class YAMLParser : IFrontmatterParser { [GeneratedRegex(@"^---\s*[\r\n](?.*?)[\r\n]---\s*", RegexOptions.Singleline)] - private partial Regex _regex(); + private partial Regex regex(); /// public Frontmatter? ParseFrontmatter(Site site, string filePath, ref string fileContent, BaseGeneratorCommand frontmatterManager) @@ -25,7 +27,7 @@ public partial class YAMLParser : IFrontmatterParser } Frontmatter? frontmatter = null; - var match = _regex().Match(fileContent); + var match = regex().Match(fileContent); if (match.Success) { var frontmatterString = match.Groups["frontmatter"].Value; @@ -41,6 +43,10 @@ public partial class YAMLParser : IFrontmatterParser _ = frontmatterDictionary.TryGetValue("Title", out var titleValue); _ = frontmatterDictionary.TryGetValue("URL", out var urlValue); _ = frontmatterDictionary.TryGetValue("Type", out var typeValue); + _ = frontmatterDictionary.TryGetValue("Date", out var dateValue); + _ = frontmatterDictionary.TryGetValue("LastMod", out var dateLastModValue); + _ = frontmatterDictionary.TryGetValue("PublishDate", out var datePublishValue); + _ = frontmatterDictionary.TryGetValue("ExpiryDate", out var dateExpiryValue); var section = GetSection(site, filePath); List tags = new(); @@ -69,7 +75,11 @@ public partial class YAMLParser : IFrontmatterParser URL = urlValue?.ToString(), Section = section, Type = typeValue?.ToString() ?? section, - Kind = Kind.single + Kind = Kind.single, + Date = DateTime.TryParse(dateValue?.ToString(), out var parsedDate) ? parsedDate : null, + LastMod = DateTime.TryParse(dateLastModValue?.ToString(), out var parsedLastMod) ? parsedLastMod : null, + PublishDate = DateTime.TryParse(datePublishValue?.ToString(), out var parsedPublishDate) ? parsedPublishDate : null, + ExpiryDate = DateTime.TryParse(dateExpiryValue?.ToString(), out var parsedExpiryDate) ? parsedExpiryDate : null }; foreach (var tagName in tags) diff --git a/source/Program.cs b/source/Program.cs index 0dafccd..8e3266e 100644 --- a/source/Program.cs +++ b/source/Program.cs @@ -30,40 +30,45 @@ public class Program // Shared options between the commands var sourceOption = new Option(new[] { "--source", "-s" }, () => ".", "Source directory path"); + var futureOption = new Option(new[] { "--future", "-f" }, () => false, "Include content with dates in the future"); var verboseOption = new Option(new[] { "--verbose", "-v" }, () => false, "Verbose output"); // BuildCommand setup var buildOutputOption = new Option(new[] { "--output", "-o" }, () => "./public", "Output directory path"); Command buildCommand = new("build", "Builds the site") - { - sourceOption, - buildOutputOption, - verboseOption - }; - buildCommand.SetHandler((source, output, verbose) => + { + sourceOption, + buildOutputOption, + futureOption, + verboseOption + }; + buildCommand.SetHandler((source, output, future, verbose) => { BuildOptions buildOptions = new() { Source = source, Output = output, + Future = future, Verbose = verbose }; _ = new BuildCommand(buildOptions); }, - sourceOption, buildOutputOption, verboseOption); + sourceOption, buildOutputOption, futureOption, verboseOption); // ServerCommand setup Command serveCommand = new("serve", "Starts the server") { sourceOption, + futureOption, verboseOption }; - serveCommand.SetHandler(async (source, verbose) => + serveCommand.SetHandler(async (source, future, verbose) => { ServeOptions serverOptions = new() { Source = source, + Future = future, Verbose = verbose }; @@ -71,7 +76,7 @@ public class Program await serveCommand.RunServer(); await Task.Delay(-1); // Wait forever. }, - sourceOption, verboseOption); + sourceOption, futureOption, verboseOption); RootCommand rootCommand = new("SuCoS commands") { diff --git a/source/ServeOptions.cs b/source/ServeOptions.cs index b0a339a..d393250 100644 --- a/source/ServeOptions.cs +++ b/source/ServeOptions.cs @@ -5,18 +5,15 @@ namespace SuCoS; /// public class ServeOptions : IGenerateOptions { - /// - /// The path of the source files. - /// + /// public string Source { get; set; } = "."; - /// - /// The path of the output files. - /// + /// public string Output { get; set; } = "./public"; - /// - /// If true, the program will print more information. - /// + /// + public bool Future { get; set; } = false; + + /// public bool Verbose { get; set; } = false; } -- GitLab