Skip to content

Commit de5e0fb

Browse files
Add experimental frontmatter value to doc source generator
Can be used for Labs to mark experimental components when we interleave things together.
1 parent 895399a commit de5e0fb

File tree

3 files changed

+66
-10
lines changed

3 files changed

+66
-10
lines changed

CommunityToolkit.Tooling.SampleGen.Tests/ToolkitSampleMetadataTests.Documentation.cs

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using CommunityToolkit.Tooling.SampleGen.Attributes;
65
using CommunityToolkit.Tooling.SampleGen.Diagnostics;
7-
using Microsoft.CodeAnalysis;
8-
using Microsoft.CodeAnalysis.CSharp;
9-
using Microsoft.VisualStudio.TestTools.UnitTesting;
106
using CommunityToolkit.Tooling.SampleGen.Tests.Helpers;
7+
using Microsoft.VisualStudio.TestTools.UnitTesting;
118

129
namespace CommunityToolkit.Tooling.SampleGen.Tests;
1310

@@ -184,12 +181,15 @@ public void DocumentationInvalidDiscussionId()
184181
icon: assets/icon.png
185182
---
186183
# This is some test documentation...
187-
Without an invalid discussion id.";
184+
Without an invalid discussion-id.";
188185

189186
var result = string.Empty.RunSourceGenerator<ToolkitSampleMetadataGenerator>(SAMPLE_ASM_NAME, markdown);
190187

191188
result.AssertNoCompilationErrors();
192189
result.AssertDiagnosticsAre(DiagnosticDescriptors.MarkdownYAMLFrontMatterException, DiagnosticDescriptors.DocumentationHasNoSamples);
190+
191+
var diag = result.Diagnostics.First((d) => d.Descriptor == DiagnosticDescriptors.MarkdownYAMLFrontMatterException);
192+
Assert.IsTrue(diag.GetMessage().Contains("discussion-id"));
193193
}
194194

195195
[TestMethod]
@@ -209,12 +209,44 @@ public void DocumentationInvalidIssueId()
209209
icon: assets/icon.png
210210
---
211211
# This is some test documentation...
212-
Without an invalid discussion id.";
212+
Without an invalid issue-id.";
213+
214+
var result = string.Empty.RunSourceGenerator<ToolkitSampleMetadataGenerator>(SAMPLE_ASM_NAME, markdown);
215+
216+
result.AssertNoCompilationErrors();
217+
result.AssertDiagnosticsAre(DiagnosticDescriptors.MarkdownYAMLFrontMatterException, DiagnosticDescriptors.DocumentationHasNoSamples);
218+
219+
var diag = result.Diagnostics.First((d) => d.Descriptor == DiagnosticDescriptors.MarkdownYAMLFrontMatterException);
220+
Assert.IsTrue(diag.GetMessage().Contains("issue-id"));
221+
}
222+
223+
[TestMethod]
224+
public void DocumentationInvalidIsExperimental()
225+
{
226+
string markdown = @"---
227+
title: Canvas Layout
228+
author: mhawker
229+
description: A canvas-like VirtualizingLayout for use in an ItemsRepeater
230+
keywords: CanvasLayout, ItemsRepeater, VirtualizingLayout, Canvas, Layout, Panel, Arrange
231+
dev_langs:
232+
- csharp
233+
category: Controls
234+
subcategory: Layout
235+
discussion-id: 0
236+
issue-id: 0
237+
icon: assets/icon.png
238+
experimental: No
239+
---
240+
# This is some test documentation...
241+
Without an invalid experimental value.";
213242

214243
var result = string.Empty.RunSourceGenerator<ToolkitSampleMetadataGenerator>(SAMPLE_ASM_NAME, markdown);
215244

216245
result.AssertNoCompilationErrors();
217246
result.AssertDiagnosticsAre(DiagnosticDescriptors.MarkdownYAMLFrontMatterException, DiagnosticDescriptors.DocumentationHasNoSamples);
247+
248+
var diag = result.Diagnostics.First((d) => d.Descriptor == DiagnosticDescriptors.MarkdownYAMLFrontMatterException);
249+
Assert.IsTrue(diag.GetMessage().Contains("experimental"));
218250
}
219251

220252
[TestMethod]
@@ -232,6 +264,7 @@ public void DocumentationValidWithRegistry()
232264
discussion-id: 0
233265
issue-id: 0
234266
icon: assets/icon.png
267+
experimental: true
235268
---
236269
# This is some test documentation...
237270
Which is valid.
@@ -258,7 +291,7 @@ public static class ToolkitDocumentRegistry
258291
{
259292
public static System.Collections.Generic.IEnumerable<CommunityToolkit.Tooling.SampleGen.Metadata.ToolkitFrontMatter> Execute()
260293
{
261-
yield return new CommunityToolkit.Tooling.SampleGen.Metadata.ToolkitFrontMatter() { Title = "Canvas Layout", Author = "mhawker", Description = "A canvas-like VirtualizingLayout for use in an ItemsRepeater", Keywords = "CanvasLayout, ItemsRepeater, VirtualizingLayout, Canvas, Layout, Panel, Arrange", Category = ToolkitSampleCategory.Controls, Subcategory = ToolkitSampleSubcategory.Layout, DiscussionId = 0, IssueId = 0, Icon = @"experiment/samples/assets/icon.png", FilePath = @"experiment\samples\documentation.md", SampleIdReferences = new string[] { "Sample" } };
294+
yield return new CommunityToolkit.Tooling.SampleGen.Metadata.ToolkitFrontMatter() { Title = "Canvas Layout", Author = "mhawker", Description = "A canvas-like VirtualizingLayout for use in an ItemsRepeater", Keywords = "CanvasLayout, ItemsRepeater, VirtualizingLayout, Canvas, Layout, Panel, Arrange", Category = ToolkitSampleCategory.Controls, Subcategory = ToolkitSampleSubcategory.Layout, DiscussionId = 0, IssueId = 0, Icon = @"experiment/samples/assets/icon.png", FilePath = @"experiment\samples\documentation.md", SampleIdReferences = new string[] { "Sample" }, IsExperimental = true };
262295
}
263296
}
264297
""", "Unexpected code generated");

CommunityToolkit.Tooling.SampleGen/Metadata/ToolkitFrontMatter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public sealed class ToolkitFrontMatter : DocsFrontMatter
1919
public ToolkitSampleSubcategory Subcategory { get; set; }
2020
public int DiscussionId { get; set; }
2121
public int IssueId { get; set; }
22+
public bool? IsExperimental { get; set; }
2223

2324
//// Extra Metadata needed for Sample App
2425
public string? FilePath { get; set; }

CommunityToolkit.Tooling.SampleGen/ToolkitSampleMetadataGenerator.Documentation.cs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ public partial class ToolkitSampleMetadataGenerator
4646
private const string MarkdownRegexSampleTagExpression = @"^>\s*\[!SAMPLE\s*(?<sampleid>.*)\s*\]\s*$";
4747
private static readonly Regex MarkdownRegexSampleTag = new Regex(MarkdownRegexSampleTagExpression, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
4848

49+
private const string FrontMatterRegexIsExperimentalExpression = @"^experimental:\s*(?<experimental>.*)$";
50+
private static readonly Regex FrontMatterRegexIsExperimental = new Regex(FrontMatterRegexIsExperimentalExpression, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
51+
4952
private static void ReportDocumentDiagnostics(SourceProductionContext ctx, Dictionary<string, ToolkitSampleRecord> sampleMetadata, IEnumerable<AdditionalText> markdownFileData, IEnumerable<(ToolkitSampleAttribute Attribute, string AttachedQualifiedTypeName, ISymbol Symbol)> toolkitSampleAttributeData, ImmutableArray<ToolkitFrontMatter> docFrontMatter)
5053
{
5154
// Keep track of all sample ids and remove them as we reference them so we know if we have any unreferenced samples.
@@ -126,6 +129,8 @@ private ImmutableArray<ToolkitFrontMatter> GatherDocumentFrontMatter(SourceProdu
126129
var discussion = ParseYamlField(ref ctx, file.Path, ref frontmatter, FrontMatterRegexDiscussionId, "discussionid")?.Trim();
127130
var issue = ParseYamlField(ref ctx, file.Path, ref frontmatter, FrontMatterRegexIssueId, "issueid")?.Trim();
128131

132+
var experimental = ParseYamlField(ref ctx, file.Path, ref frontmatter, FrontMatterRegexIsExperimental, "experimental", true)?.Trim();
133+
129134
// Check we have all the fields we expect to continue (errors will have been spit out otherwise already from the ParseYamlField method)
130135
if (title == null || description == null || keywords == null ||
131136
category == null || subcategory == null || discussion == null || issue == null || icon == null)
@@ -204,6 +209,18 @@ private ImmutableArray<ToolkitFrontMatter> GatherDocumentFrontMatter(SourceProdu
204209
return null;
205210
}
206211

212+
bool isExperimental = false;
213+
if (experimental != null && !bool.TryParse(experimental, out isExperimental))
214+
{
215+
ctx.ReportDiagnostic(
216+
Diagnostic.Create(
217+
DiagnosticDescriptors.MarkdownYAMLFrontMatterException,
218+
Location.Create(file.Path, TextSpan.FromBounds(0, 1), new LinePositionSpan(LinePosition.Zero, LinePosition.Zero)),
219+
file.Path,
220+
"Can't parse optional experimental field, must be a boolean value like 'true' or 'false' or remove it."));
221+
return null;
222+
}
223+
207224
// Finally, construct the complete object.
208225
return new ToolkitFrontMatter()
209226
{
@@ -218,16 +235,17 @@ private ImmutableArray<ToolkitFrontMatter> GatherDocumentFrontMatter(SourceProdu
218235
DiscussionId = discussionId,
219236
IssueId = issueId,
220237
Icon = iconpath,
238+
IsExperimental = isExperimental,
221239
};
222240
}
223241
}).OfType<ToolkitFrontMatter>().ToImmutableArray();
224242
}
225243

226-
private string? ParseYamlField(ref SourceProductionContext ctx, string filepath, ref string content, Regex pattern, string captureGroupName)
244+
private string? ParseYamlField(ref SourceProductionContext ctx, string filepath, ref string content, Regex pattern, string captureGroupName, bool optional = false)
227245
{
228246
var match = pattern.Match(content);
229247

230-
if (!match.Success)
248+
if (!optional && !match.Success)
231249
{
232250
ctx.ReportDiagnostic(
233251
Diagnostic.Create(
@@ -237,6 +255,10 @@ private ImmutableArray<ToolkitFrontMatter> GatherDocumentFrontMatter(SourceProdu
237255
captureGroupName));
238256
return null;
239257
}
258+
else if (optional && !match.Success)
259+
{
260+
return null;
261+
}
240262

241263
return match.Groups[captureGroupName].Value.Trim();
242264
}
@@ -270,6 +292,6 @@ private static string FrontMatterToRegistryCall(ToolkitFrontMatter metadata)
270292
var categoryParam = $"{nameof(ToolkitSampleCategory)}.{metadata.Category}";
271293
var subcategoryParam = $"{nameof(ToolkitSampleSubcategory)}.{metadata.Subcategory}";
272294

273-
return @$"yield return new {typeof(ToolkitFrontMatter).FullName}() {{ Title = ""{metadata.Title}"", Author = ""{metadata.Author}"", Description = ""{metadata.Description}"", Keywords = ""{metadata.Keywords}"", Category = {categoryParam}, Subcategory = {subcategoryParam}, DiscussionId = {metadata.DiscussionId}, IssueId = {metadata.IssueId}, Icon = @""{metadata.Icon}"", FilePath = @""{metadata.FilePath}"", SampleIdReferences = new string[] {{ ""{string.Join("\",\"", metadata.SampleIdReferences)}"" }} }};"; // TODO: Add list of sample ids in document
295+
return @$"yield return new {typeof(ToolkitFrontMatter).FullName}() {{ Title = ""{metadata.Title}"", Author = ""{metadata.Author}"", Description = ""{metadata.Description}"", Keywords = ""{metadata.Keywords}"", Category = {categoryParam}, Subcategory = {subcategoryParam}, DiscussionId = {metadata.DiscussionId}, IssueId = {metadata.IssueId}, Icon = @""{metadata.Icon}"", FilePath = @""{metadata.FilePath}"", SampleIdReferences = new string[] {{ ""{string.Join("\",\"", metadata.SampleIdReferences)}"" }}, IsExperimental = {metadata.IsExperimental.ToString().ToLowerInvariant()} }};"; // TODO: Add list of sample ids in document
274296
}
275297
}

0 commit comments

Comments
 (0)