diff --git a/source/Models/CommandLineOptions/GenerateOptions.cs b/source/Models/CommandLineOptions/GenerateOptions.cs index eb50030a3990e1de1159383fd59a872de56c63cb..8435eafc4d260e4d34e10954bc6cfd5b4d79e5b4 100644 --- a/source/Models/CommandLineOptions/GenerateOptions.cs +++ b/source/Models/CommandLineOptions/GenerateOptions.cs @@ -8,6 +8,9 @@ internal class GenerateOptions : IGenerateOptions /// public string Source { get; init; } = "."; + /// + public bool Draft { get; init; } + /// public bool Future { get; init; } diff --git a/source/Models/CommandLineOptions/IGenerateOptions.cs b/source/Models/CommandLineOptions/IGenerateOptions.cs index 74e249af077fe7832cd8203f30c7730dd41bfa14..72a911465389312a9d9b9619c081cc0739444edf 100644 --- a/source/Models/CommandLineOptions/IGenerateOptions.cs +++ b/source/Models/CommandLineOptions/IGenerateOptions.cs @@ -11,12 +11,17 @@ public interface IGenerateOptions string Source { get; } /// - /// Consider future content + /// Include draft content + /// + bool Draft { get; } + + /// + /// Include future content /// bool Future { get; } /// - /// Consider expired content + /// Include expired content /// bool Expired { get; } } \ No newline at end of file diff --git a/source/Models/FrontMatter.cs b/source/Models/FrontMatter.cs index 8ea9df48bf66a24c26d6b0a09ec24c87779dcd81..9c5629b95d5c7b235ddfbf8b601af9c119b5ce63 100644 --- a/source/Models/FrontMatter.cs +++ b/source/Models/FrontMatter.cs @@ -22,6 +22,9 @@ internal class FrontMatter : IFrontMatter /// public string? URL { get; init; } + /// + public bool? Draft { get; init; } + /// public List? Aliases { get; init; } diff --git a/source/Models/IFrontMatter.cs b/source/Models/IFrontMatter.cs index a06b57016e48a4ab3230a5935f480a0395d4ac57..8da34d5244c95dbd2760f2814dd3ef116f020282 100644 --- a/source/Models/IFrontMatter.cs +++ b/source/Models/IFrontMatter.cs @@ -48,6 +48,12 @@ public interface IFrontMatter : IParams /// string? URL { get; } + /// + /// True for draft content. It will not be rendered unless + /// a option is set to true. + /// + bool? Draft { get; } + /// /// Date of the post. Will be used as the if it's not set. /// Unless the option is set to true, diff --git a/source/Models/IPage.cs b/source/Models/IPage.cs index 98ad8105e845e62e5b17f366bb570a7084385f21..1f739e5be43d6dd9ed2fa61ca4bc51b574d372cd 100644 --- a/source/Models/IPage.cs +++ b/source/Models/IPage.cs @@ -112,10 +112,7 @@ public interface IPage : IFrontMatter /// /// Get all URLs related to this content. /// - public List Urls - { - get; - } + public List Urls { get; } /// /// Gets the Permalink path for the file. diff --git a/source/Models/ISite.cs b/source/Models/ISite.cs index be775bd75448eebffb9725a321e31c26589ee0a4..99a833e8df241cf72514e457bbed3642473a24c8 100644 --- a/source/Models/ISite.cs +++ b/source/Models/ISite.cs @@ -114,6 +114,15 @@ public interface ISite : IParams /// public void PostProcessPage(in IPage page, IPage? parent = null, bool overwrite = false); + /// + /// Check if the page have the conditions to be published: valid date and not draft, + /// unless a command line option to force it. + /// + /// Page or front matter + /// options + /// + public bool IsValidPage(in IFrontMatter frontMatter, IGenerateOptions? options); + /// /// Check if the page have a publishing date from the past. /// diff --git a/source/Models/Page.cs b/source/Models/Page.cs index 70f360ee2dea312c4871ea552ef331dc52320ccf..8f83c0c1bfda44c5cf72eac8934563e4718f99ba 100644 --- a/source/Models/Page.cs +++ b/source/Models/Page.cs @@ -27,6 +27,9 @@ internal class Page : IPage /// public string? URL => frontMatter.URL; + /// + public bool? Draft => frontMatter.Draft; + /// public List? Aliases => frontMatter.Aliases; diff --git a/source/Models/Site.cs b/source/Models/Site.cs index 95ce7f09661048b4cefb783057b0be9f0c00db31..560163139aa85d7d0463c28e4f647af5ac7fb47c 100644 --- a/source/Models/Site.cs +++ b/source/Models/Site.cs @@ -45,17 +45,17 @@ internal class Site : ISite /// /// Site description /// - public string? Description => settings.Description; + public string? Description => settings.Description; /// /// Copyright information /// - public string? Copyright => settings.Copyright; + public string? Copyright => settings.Copyright; /// /// The base URL that will be used to build internal links. /// - public string BaseURL => settings.BaseURL; + public string BaseURL => settings.BaseURL; /// /// The appearance of a URL is either ugly or pretty. @@ -415,12 +415,18 @@ internal class Site : ISite } } - /// - /// Check if the page have a publishing date from the past. - /// - /// Page or front matter - /// options - /// + /// + public bool IsValidPage(in IFrontMatter frontMatter, IGenerateOptions? options) + { + if (frontMatter is null) + { + throw new ArgumentNullException(nameof(frontMatter)); + } + return IsValidDate(frontMatter, options) + && (frontMatter.Draft is null || frontMatter.Draft == false || (options?.Draft ?? false)); + } + + /// public bool IsValidDate(in IFrontMatter frontMatter, IGenerateOptions? options) { if (frontMatter is null) diff --git a/source/Program.cs b/source/Program.cs index 59e04c31fd2292e43db16e54ae69500bbd40e806..2a118e39bab66b647f0e40472d568ae5afa54c9a 100644 --- a/source/Program.cs +++ b/source/Program.cs @@ -52,6 +52,7 @@ internal class Program // Shared options between the commands var sourceOption = new Option(new[] { "--source", "-s" }, () => ".", "Source directory path"); + var draftOption = new Option(new[] { "--draft", "-d" }, "Include draft content"); var futureOption = new Option(new[] { "--future", "-f" }, "Include content with dates in the future"); var expiredOption = new Option(new[] { "--expired", "-e" }, "Include content with ExpiredDate dates from the past"); var verboseOption = new Option(new[] { "--verbose", "-v" }, "Verbose output"); @@ -62,12 +63,13 @@ internal class Program Command buildCommandHandler = new("build", "Builds the site") { sourceOption, + draftOption, buildOutputOption, futureOption, expiredOption, verboseOption }; - buildCommandHandler.SetHandler((source, output, future, expired, verbose) => + buildCommandHandler.SetHandler((source, output, draft, future, expired, verbose) => { logger = CreateLogger(verbose); @@ -75,28 +77,31 @@ internal class Program source: source, output: output) { + Draft = draft, Future = future, Expired = expired }; _ = new BuildCommand(buildOptions, logger); }, - sourceOption, buildOutputOption, futureOption, expiredOption, verboseOption); + sourceOption, buildOutputOption, draftOption, futureOption, expiredOption, verboseOption); // ServerCommand setup Command serveCommandHandler = new("serve", "Starts the server") { sourceOption, + draftOption, futureOption, expiredOption, verboseOption }; - serveCommandHandler.SetHandler(async (source, future, expired, verbose) => + serveCommandHandler.SetHandler(async (source, draft, future, expired, verbose) => { logger = CreateLogger(verbose); ServeOptions serverOptions = new() { Source = source, + Draft = draft, Future = future, Expired = expired }; @@ -105,7 +110,7 @@ internal class Program await serveCommand.RunServer(); await Task.Delay(-1); // Wait forever. }, - sourceOption, futureOption, expiredOption, verboseOption); + sourceOption, draftOption, futureOption, expiredOption, verboseOption); RootCommand rootCommand = new("SuCoS commands") { diff --git a/test/Models/PageTests.cs b/test/Models/PageTests.cs index cc77b7b74d6ed5d11a63f1c05594bb58e6a450a7..9e51d147213ac175053570ad8c87463449554fdf 100644 --- a/test/Models/PageTests.cs +++ b/test/Models/PageTests.cs @@ -112,10 +112,10 @@ word03 word04 word05 6 7 eight [Theory] [InlineData(null, null, true)] - [InlineData(null, "2024-06-28", false)] - [InlineData("2022-06-28", null, true)] - [InlineData("2024-06-28", "2022-06-28", false)] - [InlineData("2022-06-28", "2024-06-28", true)] + [InlineData(null, "2024-01-01", false)] + [InlineData("2022-01-01", null, true)] + [InlineData("2024-01-01", "2022-01-01", false)] + [InlineData("2022-01-01", "2024-01-01", true)] public void IsDatePublishable_ShouldReturnCorrectValues(string? publishDate, string? date, bool expectedValue) { var page = new Page(new FrontMatter @@ -130,6 +130,61 @@ word03 word04 word05 6 7 eight Assert.Equal(expectedValue, site.IsDatePublishable(page)); } + [Theory] + // Draft as null + [InlineData(null, null, null, false, true)] + [InlineData(null, "2024-01-01", null, false, false)] + [InlineData("2022-01-01", null, null, false, true)] + [InlineData("2024-01-01", "2022-01-01", null, false, false)] + [InlineData("2022-01-01", "2024-01-01", null, false, true)] + // Draft as false + [InlineData(null, null, false, false, true)] + [InlineData(null, "2024-01-01", false, false, false)] + [InlineData("2022-01-01", null, false, false, true)] + [InlineData("2024-01-01", "2022-01-01", false, false, false)] + [InlineData("2022-01-01", "2024-01-01", false, false, true)] + // Draft as true + [InlineData(null, null, true, false, false)] + [InlineData(null, "2024-01-01", true, false, false)] + [InlineData("2022-01-01", null, true, false, false)] + [InlineData("2024-01-01", "2022-01-01", true, false, false)] + [InlineData("2022-01-01", "2024-01-01", true, false, false)] + // Draft as null, option -d + [InlineData(null, null, null, true, true)] + [InlineData(null, "2024-01-01", null, true, false)] + [InlineData("2022-01-01", null, null, true, true)] + [InlineData("2024-01-01", "2022-01-01", null, true, false)] + [InlineData("2022-01-01", "2024-01-01", null, true, true)] + // Draft as false, option -d + [InlineData(null, null, false, true, true)] + [InlineData(null, "2024-01-01", false, true, false)] + [InlineData("2022-01-01", null, false, true, true)] + [InlineData("2024-01-01", "2022-01-01", false, true, false)] + [InlineData("2022-01-01", "2024-01-01", false, true, true)] + // Draft as true, option -d + [InlineData(null, null, true, true, true)] + [InlineData(null, "2024-01-01", true, true, false)] + [InlineData("2022-01-01", null, true, true, true)] + [InlineData("2024-01-01", "2022-01-01", true, true, false)] + [InlineData("2022-01-01", "2024-01-01", true, true, true)] + public void IsValidPage_ShouldReturnCorrectValues(string? publishDate, string? date, bool? draft, bool draftOption, bool expectedValue) + { + var page = new Page(new FrontMatter + { + Title = titleCONST, + SourcePath = sourcePathCONST, + PublishDate = publishDate is null ? null : DateTime.Parse(publishDate, CultureInfo.InvariantCulture), + Date = date is null ? null : DateTime.Parse(date, CultureInfo.InvariantCulture), + Draft = draft + }, site); + + var options = new Mock(); + options.Setup(o => o.Draft).Returns(draftOption); + + // Assert + Assert.Equal(expectedValue, site.IsValidPage(page, options.Object)); + } + [Theory] [InlineData(false, false)] [InlineData(true, true)]