Skip to content

Commit

Permalink
Since types can be public, ensure we always have XML comments
Browse files Browse the repository at this point in the history
This is important in particular when we add intermediate automatic "area"
classes (such as when a constant is Foo.Bar.Baz), since in those cases,
the user has no way of specifying a comment to fix the issue.
kzu committed Oct 9, 2024
1 parent a316274 commit 583063f
Showing 10 changed files with 105 additions and 20 deletions.
6 changes: 3 additions & 3 deletions src/ThisAssembly.Constants/CSharp.sbntxt
Original file line number Diff line number Diff line change
@@ -34,6 +34,9 @@
{{~ end ~}}
{{ end }}
{{ func render }}
/// <summary>
/// {{ $0.Comment }}
/// </summary>
public static partial class {{ $0.Name | string.replace "-" "_" | string.replace " " "_" }}
{
{{~ for value in $0.Values ~}}
@@ -73,8 +76,5 @@ namespace {{ Namespace }};
/// </summary>
{{ Visibility }}partial class ThisAssembly
{
/// <summary>
/// {{ RootArea.Comment }}
/// </summary>
{{ render RootArea }}
}
25 changes: 20 additions & 5 deletions src/ThisAssembly.Constants/Model.cs
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.CSharp;

namespace ThisAssembly;
@@ -22,10 +23,21 @@ record Model(Area RootArea, string? Namespace, bool IsPublic)
}

[DebuggerDisplay("Name = {Name}, NestedAreas = {NestedAreas.Count}, Values = {Values.Count}")]
record Area(string Name, string Prefix, string Comment)
record Area(string Name, string Prefix)
{
public List<Area> NestedAreas { get; init; } = new();
public List<Constant> Values { get; init; } = new();
string? comment = null;
Area? parent = null;

public string Comment
{
get => comment ?? $"Provides access to constants under {Path}";
set => comment = value;
}

public string Path => parent == null ? Name : $"{parent.Path}/{Name}";

public List<Area> NestedAreas { get; init; } = [];
public List<Constant> Values { get; init; } = [];

static string EscapeIdentifier(string identifier)
{
@@ -50,7 +62,7 @@ static string EscapeIdentifier(string identifier)

public static Area Load(List<Constant> constants, string rootArea = "Constants", string comment = "Provides access project-defined constants.")
{
var root = new Area(rootArea, "", comment);
var root = new Area(rootArea, "") { Comment = comment };

foreach (var constant in constants)
{
@@ -96,7 +108,10 @@ static Area GetArea(Area area, IEnumerable<string> areaPath)
"Area name '{0}' is already in use as a value name under area '{1}'.",
areaName, currentArea.Name));

existing = new Area(areaName, currentArea.Prefix + areaName + ".", "");
existing = new Area(areaName, currentArea.Prefix + areaName + ".")
{
parent = currentArea
};
currentArea.NestedAreas.Add(existing);
}

17 changes: 14 additions & 3 deletions src/ThisAssembly.Resources/CSharp.sbntxt
Original file line number Diff line number Diff line change
@@ -31,17 +31,31 @@
{
{{~ if $0.IsText ~}}
private static string text;

/// <summary>
/// Gets the resource as plain text.
/// </summary>
public static string Text =>
text ??= EmbeddedResource.GetContent(@"{{ $0.Path }}");
{{~ end ~}}

/// <summary>
/// Gets the resource as a byte array.
/// </summary>
public static byte[] GetBytes() =>
EmbeddedResource.GetBytes(@"{{ $0.Path }}");

/// <summary>
/// Gets the resource as a stream.
/// </summary>
public static Stream GetStream() =>
EmbeddedResource.GetStream(@"{{ $0.Path }}");
}
{{ end }}
{{ func render }}
/// <summary>
/// {{ $0.Comment }}
/// </summary>
public static partial class {{ $0.Name | string.replace "-" "_" | string.replace " " "_" }}
{
{{~ if $0.Resources ~}}
@@ -65,8 +79,5 @@ namespace {{ Namespace }};
/// </summary>
{{ Visibility }}partial class ThisAssembly
{
/// <summary>
/// Provides access to assembly embedded resources.
/// </summary>
{{ render RootArea }}
}
32 changes: 26 additions & 6 deletions src/ThisAssembly.Resources/Model.cs
Original file line number Diff line number Diff line change
@@ -19,12 +19,34 @@ record Model(Area RootArea, string? Namespace, bool IsPublic)
[DebuggerDisplay("Name = {Name}")]
record Area(string Name)
{
public Area? NestedArea { get; private set; }
Area? nestedArea = null;
Area? parent = null;
string? comment = null;

public string? Comment
{
get => comment ?? $"Provides access to embedded resources under {Path}";
set => comment = value;
}

public Area? NestedArea
{
get => nestedArea;
set
{
nestedArea = value;
if (nestedArea != null)
nestedArea.parent = this;
}
}

public string Path => parent == null ? Name : $"{parent.Path}/{Name}";

public IEnumerable<Resource>? Resources { get; private set; }

public static Area Load(string basePath, List<Resource> resources, string rootArea = "Resources")
public static Area Load(string basePath, List<Resource> resources, string rootArea = "Resources", string comment = "Provides access to embedded resources.")
{
var root = new Area(rootArea);
var root = new Area(rootArea) { Comment = comment };

// Splits: ([area].)*[name]
var area = root;
@@ -36,9 +58,7 @@ public static Area Load(string basePath, List<Resource> resources, string rootAr
{
var partStr = PathSanitizer.Sanitize(part, parent);
parent = partStr;

area.NestedArea = new Area(partStr);
area = area.NestedArea;
area = area.NestedArea = new Area(partStr);
}

area.Resources = resources
2 changes: 1 addition & 1 deletion src/ThisAssembly.Resources/ResourcesGenerator.cs
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
if (!p.GlobalOptions.TryGetValue("build_property.EmbeddedResourceStringExtensions", out var extensions) ||
extensions == null)
return Array.Empty<string>();
return [];

return extensions.Split('|');
})
1 change: 1 addition & 0 deletions src/ThisAssembly.Strings/CSharp.sbntxt
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@
{{~ end ~}}
{{ end }}
{{ func render }}
/// <summary />
public static partial class {{ $0.Id }}
{
{{~ for value in $0.Values }}
3 changes: 3 additions & 0 deletions src/ThisAssembly.Tests/Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using System;

/// <summary />
public static class Extensions
{
/// <summary />
public static string ReplaceLineEndings(this string input) => ReplaceLineEndings(input, Environment.NewLine);

/// <summary />
public static string ReplaceLineEndings(this string input, string replacementText)
{
#if NET6_0_OR_GREATER
2 changes: 2 additions & 0 deletions src/ThisAssembly.Tests/ScribanTests.cs
Original file line number Diff line number Diff line change
@@ -9,8 +9,10 @@

namespace ThisAssemblyTests;

/// <summary />
public class ScribanTests(ITestOutputHelper Console)
{
/// <summary />
[Fact]
public void CanRenderModel()
{
31 changes: 31 additions & 0 deletions src/ThisAssembly.Tests/Tests.cs
Original file line number Diff line number Diff line change
@@ -9,16 +9,20 @@

namespace ThisAssemblyTests;

/// <summary />
public record class Tests(ITestOutputHelper Output)
{
/// <summary />
[Fact]
public void CanReadResourceFile()
=> Assert.NotNull(ResourceFile.Load("Resources.resx", "Strings"));

/// <summary />
[Fact]
public void CanUseInfo()
=> Assert.Equal("ThisAssembly.Tests", ThisAssembly.Info.Title);

/// <summary />
[Fact]
public void CanUseInfoDescription()
=> Assert.Equal(
@@ -29,6 +33,7 @@ with a newline and
// Some comments too.
""".ReplaceLineEndings(), ThisAssembly.Info.Description.ReplaceLineEndings());

/// <summary />
[Fact]
public void CanUseMultilineProjectProperty()
=> Assert.Equal(
@@ -39,112 +44,138 @@ with a newline and
// Some comments too.
""".ReplaceLineEndings(), ThisAssembly.Project.Multiline.ReplaceLineEndings());

/// <summary />
[Fact]
public void CanUseProjectFullFileContents()
{
Assert.NotEmpty(ThisAssembly.Project.ProjectFile);
Assert.False(ThisAssembly.Project.ProjectFile.StartsWith("|"));
}

/// <summary />
[Fact]
public void CanUseConstants()
=> Assert.Equal("Baz", ThisAssembly.Constants.Foo.Bar);

/// <summary />
[Fact]
public void CanUseTypedIntConstant()
=> Assert.Equal(123, ThisAssembly.Constants.TypedInt);

/// <summary />
[Fact]
public void CanUseTypedInt64Constant()
=> Assert.Equal(123, ThisAssembly.Constants.TypedInt64);

/// <summary />
[Fact]
public void CanUseTypedLongConstant()
=> Assert.Equal(123, ThisAssembly.Constants.TypedLong);

/// <summary />
[Fact]
public void CanUseTypedBoolConstant()
=> Assert.True(ThisAssembly.Constants.TypedBoolean);

/// <summary />
[Fact]
public void CanUseTypedDoubleConstant()
=> Assert.Equal(1.23, ThisAssembly.Constants.TypedDouble);

/// <summary />
[Fact]
public void CanUseTypedTimeSpanStaticProp()
=> Assert.Equal(TimeSpan.FromSeconds(5), ThisAssembly.Constants.TypedTimeSpan);

/// <summary />
[Fact]
public void CanUseFileConstants()
=> Assert.Equal(ThisAssembly.Constants.Content.Docs.License, Path.Combine("Content", "Docs", "License.md"));

/// <summary />
[Fact]
public void CanUseFileConstantInvalidIdentifier()
=> Assert.Equal(ThisAssembly.Constants.Content.Docs._12._Readme_copy_, Path.Combine("Content", "Docs", "12. Readme (copy).txt"));

/// <summary />
[Fact]
public void CanUseFileConstantLinkedFile()
=> Assert.Equal(ThisAssembly.Constants.Included.Readme, Path.Combine("Included", "Readme.txt"));

/// <summary />
[Fact]
public void CanUseMetadata()
=> Assert.Equal("Bar", ThisAssembly.Metadata.Foo);

/// <summary />
[Fact]
public void CanUseHierarchicalMetadata()
=> Assert.Equal("Baz", ThisAssembly.Metadata.Root.Foo.Bar);

/// <summary />
[Fact]
public void CanUseProjectProperty()
=> Assert.Equal("Bar", ThisAssembly.Project.Foo);

/// <summary />
[Fact]
public void CanUseStringsNamedArguments()
=> Assert.NotNull(ThisAssembly.Strings.Named("hello", "world"));

/// <summary />
[Fact]
public void CanUseStringsIndexedArguments()
=> Assert.NotNull(ThisAssembly.Strings.Indexed("hello", "world"));

/// <summary />
[Fact]
public void CanUseStringsNamedFormattedArguments()
=> Assert.Equal("Year 2020, Month 03", ThisAssembly.Strings.WithNamedFormat(new DateTime(2020, 3, 20)));

/// <summary />
[Fact]
public void CanUseStringsIndexedFormattedArguments()
=> Assert.Equal("Year 2020, Month 03", ThisAssembly.Strings.WithIndexedFormat(new DateTime(2020, 3, 20)));

/// <summary />
[Fact]
public void CanUseStringResource()
=> Assert.Equal("Value", ThisAssembly.Strings.Foo.Bar.Baz);

/// <summary />
[Fact]
public void CanUseTextResource()
=> Assert.NotNull(ThisAssembly.Resources.Content.Styles.Custom.Text);

/// <summary />
[Fact]
public void CanUseByteResource()
=> Assert.NotNull(ThisAssembly.Resources.Content.Styles.Main.GetBytes());

/// <summary />
[Fact]
public void CanUseSameNameDifferentExtensions()
=> Assert.NotNull(ThisAssembly.Resources.Content.Swagger.swagger_ui.css.GetBytes());

/// <summary />
[Fact]
public void CanUseFileInvalidCharacters()
=> Assert.NotNull(ThisAssembly.Resources.webhook_data.Text);

/// <summary />
[Fact]
public void CanUseGitConstants()
=> Assert.NotEmpty(ThisAssembly.Git.Commit);

/// <summary />
[Fact]
public void CanUseGitBranchConstants()
{
Assert.NotEmpty(ThisAssembly.Git.Branch);
Output.WriteLine(ThisAssembly.Git.Branch);
}

/// <summary />
[Fact]
public void CanUseSemicolonsInConstant()
=> Assert.Equal("A;B;C", ThisAssembly.Constants.WithSemiColon);
6 changes: 4 additions & 2 deletions src/ThisAssembly.Tests/ThisAssembly.Tests.csproj
Original file line number Diff line number Diff line change
@@ -19,10 +19,12 @@
// Some comments too.</Description>
<TargetFramework Condition="'$(BuildingInsideVisualStudio)' == 'true'">net472</TargetFramework>
<RootNamespace>ThisAssemblyTests</RootNamespace>
<!--<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>-->
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<NoWarn>CS0618;CS8981;TA100;$(NoWarn)</NoWarn>
<PackageScribanIncludeSource>false</PackageScribanIncludeSource>
<ProjectFile>$([System.IO.File]::ReadAllText($(MSBuildProjectFullPath)))</ProjectFile>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<WarningsAsErrors>true</WarningsAsErrors>
</PropertyGroup>

<Import Project="..\*\ThisAssembly*.props" />
@@ -69,7 +71,7 @@
<ProjectProperty Include="Foo" />
<ProjectProperty Include="Description" />
<ProjectProperty Include="Multiline" />
<ProjectProperty Include="ProjectFile" Comment="Full project contents" />
<ProjectProperty Include="ProjectFile" />
<Constant Include="Foo.Raw" Value="$(Multiline)" Comment="$(Multiline)" />
<Constant Include="Foo.Bar" Value="Baz" Comment="Yay!" />
<Constant Include="Foo.Hello" Value="World" Comment="Comments make everything better 😍" />

0 comments on commit 583063f

Please sign in to comment.