diff --git a/src/Directory.targets b/src/Directory.targets
index 190069e0..d2a8362b 100644
--- a/src/Directory.targets
+++ b/src/Directory.targets
@@ -5,6 +5,7 @@
> This project uses SponsorLink and may issue IDE-only warnings if no active sponsorship is detected. Learn more at https://github.com/devlooped#sponsorlink.
+ $(PackFolder.StartsWith('analyzers/'))
@@ -12,12 +13,14 @@
+
+
-
+
+ /// Gets the content of the embedded resource at the specified relative path.
+ ///
public static string GetContent(string relativePath)
{
using var stream = GetStream(relativePath);
@@ -17,6 +23,9 @@ public static string GetContent(string relativePath)
return reader.ReadToEnd();
}
+ ///
+ /// Gets the bytes of the embedded resource at the specified relative path.
+ ///
public static byte[] GetBytes(string relativePath)
{
using var stream = GetStream(relativePath);
@@ -25,6 +34,10 @@ public static byte[] GetBytes(string relativePath)
return bytes;
}
+ ///
+ /// Gets the stream of the embedded resource at the specified relative path.
+ ///
+ ///
public static Stream GetStream(string relativePath)
{
#if DEBUG
diff --git a/src/Shared/PathSanitizer.cs b/src/Shared/PathSanitizer.cs
index 992cda7b..ff8b0d29 100644
--- a/src/Shared/PathSanitizer.cs
+++ b/src/Shared/PathSanitizer.cs
@@ -1,8 +1,15 @@
using System.Text.RegularExpressions;
-static class PathSanitizer
+///
+/// Sanitizes paths for use as identifiers.
+///
+public static class PathSanitizer
{
static readonly Regex invalidCharsRegex = new(@"\W");
+
+ ///
+ /// Sanitizes the specified path for use as an identifier.
+ ///
public static string Sanitize(string path, string parent)
{
var partStr = invalidCharsRegex.Replace(path, "_");
diff --git a/src/ThisAssembly.AssemblyInfo/AssemblyInfoGenerator.cs b/src/ThisAssembly.AssemblyInfo/AssemblyInfoGenerator.cs
index ffbe6e28..d5e3ec6a 100644
--- a/src/ThisAssembly.AssemblyInfo/AssemblyInfoGenerator.cs
+++ b/src/ThisAssembly.AssemblyInfo/AssemblyInfoGenerator.cs
@@ -1,14 +1,19 @@
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
+using Devlooped.Sponsors;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Scriban;
+using static Devlooped.Sponsors.SponsorLink;
+using Resources = Devlooped.Sponsors.Resources;
namespace ThisAssembly;
@@ -41,7 +46,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
// Read the ThisAssemblyNamespace property or default to null
var right = context.AnalyzerConfigOptionsProvider
.Select((c, t) => c.GlobalOptions.TryGetValue("build_property.ThisAssemblyNamespace", out var ns) && !string.IsNullOrEmpty(ns) ? ns : null)
- .Combine(context.ParseOptionsProvider);
+ .Combine(context.ParseOptionsProvider.Combine(context.GetStatusOptions()));
context.RegisterSourceOutput(
metadata.Combine(right),
@@ -74,11 +79,24 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
}
static void GenerateSource(SourceProductionContext spc,
- (ImmutableArray> attributes, (string? ns, ParseOptions parse)) arg)
+ (ImmutableArray> attributes, (string? ns, (ParseOptions parse, StatusOptions options))) arg)
{
- var (attributes, (ns, parse)) = arg;
+ var (attributes, (ns, (parse, options))) = arg;
+ var model = new Model([.. attributes], ns);
+ if (IsEditor)
+ {
+ var status = Diagnostics.GetOrSetStatus(options);
+ if (status == SponsorStatus.Unknown || status == SponsorStatus.Expired)
+ {
+ model.Warn = string.Format(CultureInfo.CurrentCulture, Resources.Editor_Disabled, Funding.Product, Funding.HelpUrl);
+ model.Remarks = Resources.Editor_DisabledRemarks;
+ }
+ else if (status == SponsorStatus.Grace && Diagnostics.TryGet() is { } grace && grace.Properties.TryGetValue(nameof(SponsorStatus.Grace), out var days))
+ {
+ model.Remarks = string.Format(CultureInfo.CurrentCulture, Resources.Editor_GraceRemarks, days);
+ }
+ }
- var model = new Model(attributes.ToList(), ns);
if (parse is CSharpParseOptions cs && (int)cs.LanguageVersion >= 1100)
model.RawStrings = true;
diff --git a/src/ThisAssembly.AssemblyInfo/CSharp.sbntxt b/src/ThisAssembly.AssemblyInfo/CSharp.sbntxt
index c4c7ed08..f2d3d736 100644
--- a/src/ThisAssembly.AssemblyInfo/CSharp.sbntxt
+++ b/src/ThisAssembly.AssemblyInfo/CSharp.sbntxt
@@ -7,6 +7,7 @@
//
//------------------------------------------------------------------------------
+using System;
using System.CodeDom.Compiler;
using System.Runtime.CompilerServices;
{{ if Namespace }}
@@ -21,19 +22,35 @@ partial class ThisAssembly
///
/// Gets the AssemblyInfo attributes.
///
+ {{~ if Remarks ~}}
+ {{ Remarks }}
+ ///
+ {{~ end ~}}
[GeneratedCode("ThisAssembly.AssemblyInfo", "{{ Version }}")]
[CompilerGenerated]
public static partial class Info
{
- {{~ for prop in Properties ~}}
+ {{- for prop in Properties ~}}
+
+ {{~ if Remarks ~}}
+ {{ Remarks }}
+ ///
+ {{~ end ~}}
+ {{~ if Warn ~}}
+ [Obsolete("{{ Warn }}", false
+ #if NET6_0_OR_GREATER
+ , UrlFormat = "{{ Url }}"
+ #endif
+ )]
+ {{~ end ~}}
{{~ if RawStrings ~}}
public const string {{ prop.Key }} =
-"""
-{{ prop.Value }}
-""";
+ """
+ {{ prop.Value }}
+ """;
{{~ else ~}}
public const string {{ prop.Key }} = @"{{ prop.Value }}";
{{~ end ~}}
{{~ end ~}}
}
-}
\ No newline at end of file
+}
diff --git a/src/ThisAssembly.AssemblyInfo/Model.cs b/src/ThisAssembly.AssemblyInfo/Model.cs
index da0ab9c2..1a988760 100644
--- a/src/ThisAssembly.AssemblyInfo/Model.cs
+++ b/src/ThisAssembly.AssemblyInfo/Model.cs
@@ -13,6 +13,9 @@ public Model(IEnumerable> properties, string? ns)
public string? Namespace { get; }
public bool RawStrings { get; set; } = false;
public string Version => Assembly.GetExecutingAssembly().GetName().Version.ToString(3);
+ public string Url => Devlooped.Sponsors.SponsorLink.Funding.HelpUrl;
+ public string? Warn { get; set; }
+ public string? Remarks { get; set; }
public List> Properties { get; }
}
diff --git a/src/ThisAssembly.Constants/CSharp.sbntxt b/src/ThisAssembly.Constants/CSharp.sbntxt
index a5af0287..e0231946 100644
--- a/src/ThisAssembly.Constants/CSharp.sbntxt
+++ b/src/ThisAssembly.Constants/CSharp.sbntxt
@@ -8,7 +8,7 @@
// the code is regenerated.
//
//------------------------------------------------------------------------------
-{{ func summary }}
+{{- func summary -}}
///
{{~ if $0.Comment ~}}
/// {{ $0.Comment }}
@@ -16,12 +16,30 @@
/// => @"{{ $0.Value }}"
{{~ end ~}}
///
+{{- end -}}
+{{ func obsolete }}
+{{~ if Warn ~}}
+[Obsolete("{{ Warn }}", false
+#if NET6_0_OR_GREATER
+ , UrlFormat = "{{ Url }}"
+#endif
+)]
+
+{{~ end }}
+{{ end }}
+{{ func remarks }}
+{{~ if Remarks ~}}
+{{ Remarks }}
+///
+{{~ end ~}}
{{ end }}
{{ func render }}
public static partial class {{ $0.Name | string.replace "-" "_" | string.replace " " "_" }}
{
{{~ for value in $0.Values ~}}
- {{- summary value ~}}
+ {{- summary value -}}
+ {{- remarks -}}
+ {{ obsolete }}
{{~ if RawStrings ~}}
public const string {{ value.Name | string.replace "-" "_" | string.replace " " "_" }} =
"""
diff --git a/src/ThisAssembly.Constants/ConstantsGenerator.cs b/src/ThisAssembly.Constants/ConstantsGenerator.cs
index a8aa44ee..c865fdd7 100644
--- a/src/ThisAssembly.Constants/ConstantsGenerator.cs
+++ b/src/ThisAssembly.Constants/ConstantsGenerator.cs
@@ -1,7 +1,9 @@
-using System.Collections.Generic;
+using System.Diagnostics.Tracing;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
+using Devlooped.Sponsors;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
@@ -58,15 +60,26 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Select((c, t) => c.GlobalOptions.TryGetValue("build_property.ThisAssemblyNamespace", out var ns) && !string.IsNullOrEmpty(ns) ? ns : null)
.Combine(context.ParseOptionsProvider);
- context.RegisterSourceOutput(
- files.Combine(right),
- GenerateConstant);
+ var inputs = files.Combine(right);
+ // this is required to ensure status is registered properly independently of analyzer runs.
+ var options = context.GetStatusOptions();
+ context.RegisterSourceOutput(inputs.Combine(options), GenerateConstant);
+ //(spc, source) =>
+ //{
+ // var status = Diagnostics.GetOrSetStatus(source.Right);
+ // var warn = IsEditor &&
+ // (status == Devlooped.Sponsors.SponsorStatus.Unknown || status == Devlooped.Sponsors.SponsorStatus.Expired);
+
+ // GenerateConstant(spc, source.Left, warn ? string.Format(
+ // CultureInfo.CurrentCulture, Resources.Editor_Disabled, Funding.Product, Funding.HelpUrl) : null);
+ //});
}
- void GenerateConstant(SourceProductionContext spc, ((string name, string value, string? comment, string root), (string? ns, ParseOptions parse)) args)
+ void GenerateConstant(SourceProductionContext spc,
+ (((string name, string value, string? comment, string root), (string? ns, ParseOptions parse)), StatusOptions options) args)
{
- var ((name, value, comment, root), (ns, parse)) = args;
+ var (((name, value, comment, root), (ns, parse)), options) = args;
var cs = (CSharpParseOptions)parse;
if (!string.IsNullOrWhiteSpace(ns) &&
@@ -87,24 +100,31 @@ void GenerateConstant(SourceProductionContext spc, ((string name, string value,
if ((int)cs.LanguageVersion >= 1100)
model.RawStrings = true;
+ if (IsEditor)
+ {
+ var status = Diagnostics.GetOrSetStatus(options);
+ if (status == SponsorStatus.Unknown || status == SponsorStatus.Expired)
+ {
+ model.Warn = string.Format(CultureInfo.CurrentCulture, Resources.Editor_Disabled, Funding.Product, Funding.HelpUrl);
+ model.Remarks = Resources.Editor_DisabledRemarks;
+ }
+ else if (status == SponsorStatus.Grace && Diagnostics.TryGet() is { } grace && grace.Properties.TryGetValue(nameof(SponsorStatus.Grace), out var days))
+ {
+ model.Remarks = string.Format(CultureInfo.CurrentCulture, Resources.Editor_GraceRemarks, days);
+ }
+ }
+
var output = template.Render(model, member => member.Name);
// Apply formatting since indenting isn't that nice in Scriban when rendering nested
// structures via functions.
if (parse.Language == LanguageNames.CSharp)
{
- output = SyntaxFactory.ParseCompilationUnit(output)
+ output = SyntaxFactory.ParseCompilationUnit(output, options: cs)
.NormalizeWhitespace()
.GetText()
.ToString();
}
- //else if (language == LanguageNames.VisualBasic)
- //{
- // output = Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseCompilationUnit(output)
- // .NormalizeWhitespace()
- // .GetText()
- // .ToString();
- //}
spc.AddSource($"{root}.{name}.g.cs", SourceText.From(output, Encoding.UTF8));
}
diff --git a/src/ThisAssembly.Constants/Model.cs b/src/ThisAssembly.Constants/Model.cs
index 8945f776..9e7f3cde 100644
--- a/src/ThisAssembly.Constants/Model.cs
+++ b/src/ThisAssembly.Constants/Model.cs
@@ -13,6 +13,9 @@ record Model(Area RootArea, string? Namespace)
{
public bool RawStrings { get; set; } = false;
public string Version => Assembly.GetExecutingAssembly().GetName().Version.ToString(3);
+ public string Url => Devlooped.Sponsors.SponsorLink.Funding.HelpUrl;
+ public string? Warn { get; set; }
+ public string? Remarks { get; set; }
}
[DebuggerDisplay("Name = {Name}, NestedAreas = {NestedAreas.Count}, Values = {Values.Count}")]
diff --git a/src/ThisAssembly.Strings/CSharp.sbntxt b/src/ThisAssembly.Strings/CSharp.sbntxt
index 039d67b6..2a467d9a 100644
--- a/src/ThisAssembly.Strings/CSharp.sbntxt
+++ b/src/ThisAssembly.Strings/CSharp.sbntxt
@@ -16,11 +16,22 @@
/// = "{{ $0.Value }}"
{{~ end ~}}
///
+ {{~ if Remarks ~}}
+ {{ Remarks }}
+ ///
+ {{~ end ~}}
+ {{~ if Warn ~}}
+ [Obsolete("{{ Warn }}", false
+ #if NET6_0_OR_GREATER
+ , UrlFormat = "{{ Url }}"
+ #endif
+ )]
+ {{~ end ~}}
{{ end }}
{{ func render }}
public static partial class {{ $0.Id }}
{
- {{~ for value in $0.Values ~}}
+ {{~ for value in $0.Values }}
{{~ if!(value.HasFormat) ~}}
{{- summary value ~}}
public static string {{ value.Id }} => Strings.GetResourceManager("{{ $1 }}").GetString("{{ value.Name }}");
@@ -70,7 +81,7 @@ using System;
using System.Globalization;
{{ if Namespace }}
namespace {{ Namespace }};
-{{~ end ~}}
+{{ end }}
///
/// Provides access to the current assembly information.
@@ -80,5 +91,6 @@ partial class ThisAssembly
///
/// Provides access to the assembly strings.
///
+ {{- remarks -}}
{{ render RootArea ResourceName }}
}
\ No newline at end of file
diff --git a/src/ThisAssembly.Strings/Model.cs b/src/ThisAssembly.Strings/Model.cs
index 46475a61..2169d992 100644
--- a/src/ThisAssembly.Strings/Model.cs
+++ b/src/ThisAssembly.Strings/Model.cs
@@ -10,6 +10,9 @@
record Model(ResourceArea RootArea, string ResourceName, string? Namespace)
{
public string? Version => Assembly.GetExecutingAssembly().GetName().Version?.ToString(3);
+ public string Url => Devlooped.Sponsors.SponsorLink.Funding.HelpUrl;
+ public string? Warn { get; set; }
+ public string? Remarks { get; set; }
}
static class ResourceFile
@@ -131,8 +134,8 @@ static ResourceValue GetValue(string resourceId, string resourceName, string res
[DebuggerDisplay("Id = {Id}, NestedAreas = {NestedAreas.Count}, Values = {Values.Count}")]
record ResourceArea(string Id, string Prefix)
{
- public List NestedAreas { get; init; } = new List();
- public List Values { get; init; } = new List();
+ public List NestedAreas { get; init; } = [];
+ public List Values { get; init; } = [];
}
[DebuggerDisplay("{Id} = {Value}")]
diff --git a/src/ThisAssembly.Strings/StringsGenerator.cs b/src/ThisAssembly.Strings/StringsGenerator.cs
index 73aae59f..97945aba 100644
--- a/src/ThisAssembly.Strings/StringsGenerator.cs
+++ b/src/ThisAssembly.Strings/StringsGenerator.cs
@@ -1,11 +1,15 @@
using System;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Resources;
using System.Text;
+using Devlooped.Sponsors;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using Scriban;
+using static Devlooped.Sponsors.SponsorLink;
namespace ThisAssembly;
@@ -46,24 +50,37 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
context.RegisterSourceOutput(
- files.Combine(right),
+ files.Combine(right).Combine(context.ParseOptionsProvider.Combine(context.GetStatusOptions())),
GenerateSource);
}
static void GenerateSource(SourceProductionContext spc,
- ((string fileName, SourceText? text, string resourceName), (string? ns, string language)) arg)
+ (((string fileName, SourceText? text, string resourceName), (string? ns, string language)),(ParseOptions parse, StatusOptions options)) arg)
{
- var ((fileName, resourceText, resourceName), (ns, language)) = arg;
+ var (((fileName, resourceText, resourceName), (ns, language)), (parse, options)) = arg;
var file = language.Replace("#", "Sharp") + ".sbntxt";
var template = Template.Parse(EmbeddedResource.GetContent(file), file);
var rootArea = ResourceFile.LoadText(resourceText!.ToString(), "Strings");
var model = new Model(rootArea, resourceName, ns);
+ if (IsEditor)
+ {
+ var status = Diagnostics.GetOrSetStatus(options);
+ if (status == SponsorStatus.Unknown || status == SponsorStatus.Expired)
+ {
+ model.Warn = string.Format(CultureInfo.CurrentCulture, Resources.Editor_Disabled, Funding.Product, Funding.HelpUrl);
+ model.Remarks = Resources.Editor_DisabledRemarks;
+ }
+ else if (status == SponsorStatus.Grace && Diagnostics.TryGet() is { } grace && grace.Properties.TryGetValue(nameof(SponsorStatus.Grace), out var days))
+ {
+ model.Remarks = string.Format(CultureInfo.CurrentCulture, Resources.Editor_GraceRemarks, days);
+ }
+ }
var output = template.Render(model, member => member.Name);
- output = Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseCompilationUnit(output)
+ output = SyntaxFactory.ParseCompilationUnit(output, options: parse as CSharpParseOptions)
.NormalizeWhitespace()
.GetText()
.ToString();
diff --git a/src/ThisAssembly.Tests/Funding.cs b/src/ThisAssembly.Tests/Funding.cs
new file mode 100644
index 00000000..dc856909
--- /dev/null
+++ b/src/ThisAssembly.Tests/Funding.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace Devlooped.Sponsors;
+
+partial class SponsorLink
+{
+ public partial class Funding
+ {
+ public const string HelpUrl = "https://github.com/devlooped#sponsorlink";
+ }
+}
diff --git a/src/ThisAssembly.Tests/ScribanTests.cs b/src/ThisAssembly.Tests/ScribanTests.cs
new file mode 100644
index 00000000..c0831e46
--- /dev/null
+++ b/src/ThisAssembly.Tests/ScribanTests.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Scriban;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace ThisAssemblyTests;
+
+public class ScribanTests(ITestOutputHelper Console)
+{
+ [Fact]
+ public void CanRenderModel()
+ {
+ var source =
+ """
+ {{ func remarks }}
+ ///
+ {{ end }}
+ ///
+ /// {{ summary }}
+ ///
+ {{ remarks }}
+ """;
+
+ var template = Template.Parse(source);
+ var output = template.Render(new
+ {
+ summary = "This is a summary",
+ url = "https://github.com/devlooped#sponsorlink"
+ });
+
+ Assert.Contains("https://github.com/devlooped#sponsorlink", output);
+ Console.WriteLine(output);
+ }
+}
diff --git a/src/ThisAssembly.Tests/Tests.cs b/src/ThisAssembly.Tests/Tests.cs
index b29f5a85..3b596946 100644
--- a/src/ThisAssembly.Tests/Tests.cs
+++ b/src/ThisAssembly.Tests/Tests.cs
@@ -1,8 +1,9 @@
-using System.Diagnostics.CodeAnalysis;
+using System;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
-using Devlooped;
using Xunit;
using Xunit.Abstractions;
+//using ThisAssembly = ThisAssemblyTests
[assembly: SuppressMessage("SponsorLink", "SL04")]
@@ -10,7 +11,6 @@ namespace ThisAssemblyTests;
public record class Tests(ITestOutputHelper Output)
{
- DateTime dxt = DateTime.Now;
[Fact]
public void CanReadResourceFile()
=> Assert.NotNull(ResourceFile.Load("Resources.resx", "Strings"));
diff --git a/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj b/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj
index 6e72472b..d5b132b7 100644
--- a/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj
+++ b/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj
@@ -3,7 +3,7 @@
false
net8.0
- Devlooped
+ ThisAssemblyTests
A Description
with a newline and
@@ -17,10 +17,11 @@
net472
ThisAssemblyTests
true
- CS8981;$(NoWarn)
+ CS0618;CS8981;TA100;$(NoWarn)
+ false
-
+
@@ -40,6 +41,7 @@
+
@@ -81,7 +83,7 @@
-
+
@@ -93,4 +95,12 @@
+
+
+ $(Version)
+
+
+
+
+