Skip to content

Commit

Permalink
Allow constants to define custom root comment summary
Browse files Browse the repository at this point in the history
Since now most specific packages just extend and project @(Constant) items, they effectively are all "constants", and the comment on the root class used to be "Provides access project-defined constants.". This no longer is the case for the following:

- Metadata: exposes project-defined AssemblyMetadata, not "constants"
- AssemblyInfo: exposes [Assembly*] attributes
- Git: build-time source repo information, not even project constants
- Vsix: manifest values, again, not even project values.

We should therefore allow a new metadata beside the `Root` attribute we added to allow custom roots: `RootComment`. Since each constant is emitted as a standalone file, we would have duplication, but we want to keep this approach for performance reasons.

We default to the old comment if none is specified.
Example of a custom constant with a custom root and its comment:

```xml
<Constant Include="Foo.Bar" Value="Baz" Comment="A Bar value" Root="." RootComment="All the foos!" />
```
  • Loading branch information
kzu committed Sep 30, 2024
1 parent c04f7e8 commit 9558384
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/ThisAssembly.Constants/CSharp.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ namespace {{ Namespace }};
{{ Visibility }}partial class ThisAssembly
{
/// <summary>
/// Provides access project-defined constants.
/// {{ RootArea.Comment }}
/// </summary>
{{ render RootArea }}
}
21 changes: 13 additions & 8 deletions src/ThisAssembly.Constants/ConstantsGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
&& itemType == "Constant")
.Select((x, ct) =>
{
x.Right.GetOptions(x.Left).TryGetValue("build_metadata.Constant.Value", out var value);
x.Right.GetOptions(x.Left).TryGetValue("build_metadata.Constant.Type", out var type);
x.Right.GetOptions(x.Left).TryGetValue("build_metadata.Constant.Comment", out var comment);
x.Right.GetOptions(x.Left).TryGetValue("build_metadata.Constant.Root", out var root);
var options = x.Right.GetOptions(x.Left);
options.TryGetValue("build_metadata.Constant.Value", out var value);
options.TryGetValue("build_metadata.Constant.Type", out var type);
options.TryGetValue("build_metadata.Constant.Comment", out var comment);
options.TryGetValue("build_metadata.Constant.Root", out var root);
options.TryGetValue("build_metadata.Constant.RootComment", out var rootComment);
if (string.IsNullOrEmpty(rootComment))
rootComment = "Provides access project-defined constants.";
// Revert auto-escaping due to https://github.com/dotnet/roslyn/issues/51692
if (value != null && value.StartsWith("|") && value.EndsWith("|"))
Expand All @@ -53,7 +58,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
}
}
return (name, value: value ?? "", type: string.IsNullOrWhiteSpace(type) ? null : type, comment: string.IsNullOrWhiteSpace(comment) ? null : comment, root!);
return (name, value: value ?? "", type: string.IsNullOrWhiteSpace(type) ? null : type, comment: string.IsNullOrWhiteSpace(comment) ? null : comment, root!, rootComment!);
});

// Read the ThisAssemblyNamespace property or default to null
Expand All @@ -72,9 +77,9 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
}

void GenerateConstant(SourceProductionContext spc,
(((string name, string value, string? type, string? comment, string root), ((string? ns, string? visibility), ParseOptions parse)), StatusOptions options) args)
(((string name, string value, string? type, string? comment, string root, string rootComment), ((string? ns, string? visibility), ParseOptions parse)), StatusOptions options) args)
{
var (((name, value, type, comment, root), ((ns, visibility), parse)), options) = args;
var (((name, value, type, comment, root, rootComment), ((ns, visibility), parse)), options) = args;
var cs = (CSharpParseOptions)parse;

if (!string.IsNullOrWhiteSpace(ns) &&
Expand All @@ -93,7 +98,7 @@ void GenerateConstant(SourceProductionContext spc,
comment = "/// " + string.Join(Environment.NewLine + "/// ", value.Replace("\\n", Environment.NewLine).Trim(['\r', '\n']).Split([Environment.NewLine], StringSplitOptions.None));

// Revert normalization of newlines performed in MSBuild to workaround the limitation in editorconfig.
var rootArea = Area.Load([new(name, value.Replace("\\n", Environment.NewLine).Trim(['\r', '\n']), comment, type ?? "string"),], root);
var rootArea = Area.Load([new(name, value.Replace("\\n", Environment.NewLine).Trim(['\r', '\n']), comment, type ?? "string"),], root, rootComment);
// For now, we only support C# though
var file = parse.Language.Replace("#", "Sharp") + ".sbntxt";
var template = Template.Parse(EmbeddedResource.GetContent(file), file);
Expand Down
8 changes: 4 additions & 4 deletions src/ThisAssembly.Constants/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ record Model(Area RootArea, string? Namespace, bool IsPublic)
}

[DebuggerDisplay("Name = {Name}, NestedAreas = {NestedAreas.Count}, Values = {Values.Count}")]
record Area(string Name, string Prefix)
record Area(string Name, string Prefix, string Comment)
{
public List<Area> NestedAreas { get; init; } = new();
public List<Constant> Values { get; init; } = new();
Expand All @@ -48,9 +48,9 @@ static string EscapeIdentifier(string identifier)
return result;
}

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

foreach (var constant in constants)
{
Expand Down Expand Up @@ -96,7 +96,7 @@ 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 + ".", "");
currentArea.NestedAreas.Add(existing);
}

Expand Down
1 change: 1 addition & 0 deletions src/ThisAssembly.Constants/ThisAssembly.Constants.targets
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<CompilerVisibleItemMetadata Include="Constant" MetadataName="Value" />
<CompilerVisibleItemMetadata Include="Constant" MetadataName="Type" />
<CompilerVisibleItemMetadata Include="Constant" MetadataName="Root" />
<CompilerVisibleItemMetadata Include="Constant" MetadataName="RootComment" />

<!-- Make sure we're always private to the referencing project.
Prevents analyzers from "flowing out" of the referencing project. -->
Expand Down

0 comments on commit 9558384

Please sign in to comment.