diff --git a/src/ThisAssembly.Constants/CSharp.sbntxt b/src/ThisAssembly.Constants/CSharp.sbntxt index 38c39e4c..bc32330e 100644 --- a/src/ThisAssembly.Constants/CSharp.sbntxt +++ b/src/ThisAssembly.Constants/CSharp.sbntxt @@ -45,7 +45,6 @@ {{ obsolete }} {{~ if RawStrings && value.IsText ~}} public {{ Modifier }} string {{ value.Name | string.replace "-" "_" | string.replace " " "_" }} ={{ Lambda }} - """ {{ value.Value }} """; diff --git a/src/ThisAssembly.Constants/ConstantsGenerator.cs b/src/ThisAssembly.Constants/ConstantsGenerator.cs index 553e695a..ed48ac6b 100644 --- a/src/ThisAssembly.Constants/ConstantsGenerator.cs +++ b/src/ThisAssembly.Constants/ConstantsGenerator.cs @@ -2,6 +2,7 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Xml.Linq; using Devlooped.Sponsors; @@ -94,12 +95,12 @@ void GenerateConstant(SourceProductionContext spc, } if (comment != null) - comment = "/// " + string.Join(Environment.NewLine + "/// ", new XText(comment).ToString().Trim().Replace("\\n", Environment.NewLine).Trim(['\r', '\n']).Split([Environment.NewLine], StringSplitOptions.None)); + comment = "/// " + string.Join(Environment.NewLine + "/// ", new XText(comment).ToString().Trim().Replace("`n", Environment.NewLine).Trim(['\r', '\n']).Split([Environment.NewLine], StringSplitOptions.None)); else - comment = "/// " + string.Join(Environment.NewLine + "/// ", new XText(value).ToString().Replace("\\n", Environment.NewLine).Trim(['\r', '\n']).Split([Environment.NewLine], StringSplitOptions.None)); + comment = "/// " + string.Join(Environment.NewLine + "/// ", new XText(value).ToString().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, rootComment); + 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); @@ -123,17 +124,35 @@ void GenerateConstant(SourceProductionContext spc, 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, options: cs) - .NormalizeWhitespace() - .GetText() - .ToString(); + // Apply formatting since indenting isn't that nice in Scriban when rendering nested + // structures via functions. + // We alos rewrite to prepend a newline leading trivia before the raw string literals if any + var node = new RawStringLiteralRewriter().Visit( + SyntaxFactory.ParseCompilationUnit(output, options: cs).NormalizeWhitespace(eol: Environment.NewLine)); + + output = node.GetText().ToString(); } spc.AddSource($"{root}.{name}.g.cs", SourceText.From(output, Encoding.UTF8)); } -} + + class RawStringLiteralRewriter : CSharpSyntaxRewriter + { + public override SyntaxToken VisitToken(SyntaxToken token) + { + // See https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.csharp.syntaxkind?view=roslyn-dotnet-4.13.0 + // MultiLineRawStringLiteralToken = 8519 + // Utf8MultiLineRawStringLiteralToken = 8522 + if (token.RawKind == 8519 || token.RawKind == 8522) + return token.WithLeadingTrivia( + token.LeadingTrivia.Add( + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? + SyntaxFactory.CarriageReturnLineFeed : + SyntaxFactory.LineFeed)); + + return base.VisitToken(token); + } + } +} \ No newline at end of file diff --git a/src/ThisAssembly.Constants/ThisAssembly.Constants.targets b/src/ThisAssembly.Constants/ThisAssembly.Constants.targets index d38c12a4..cfae943b 100644 --- a/src/ThisAssembly.Constants/ThisAssembly.Constants.targets +++ b/src/ThisAssembly.Constants/ThisAssembly.Constants.targets @@ -50,8 +50,8 @@ - $([MSBuild]::ValueOrDefault('%(Constant.Value)', '').Replace($([System.Environment]::NewLine), '\n')) - $([MSBuild]::ValueOrDefault('%(Constant.Comment)', '').Replace($([System.Environment]::NewLine), '\n')) + $([MSBuild]::ValueOrDefault('%(Constant.Value)', '').Replace(' ', '`n').Replace(' ', '`n')) + $([MSBuild]::ValueOrDefault('%(Constant.Comment)', '').Replace(' ', '`n').Replace(' ', '`n')) diff --git a/src/ThisAssembly.Tests/Tests.cs b/src/ThisAssembly.Tests/Tests.cs index 4ef0ac36..b4eeba6d 100644 --- a/src/ThisAssembly.Tests/Tests.cs +++ b/src/ThisAssembly.Tests/Tests.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.IO; +using Microsoft.IdentityModel.Tokens; using Xunit; using Xunit.Abstractions; //using ThisAssembly = ThisAssemblyTests @@ -191,4 +192,8 @@ public void CanUseGitBranchConstants() [Fact] public void CanUseSemicolonsInConstant() => Assert.Equal("A;B;C", ThisAssembly.Constants.WithSemiColon); + + /// + [Fact] + public void CanReadJsonConstant() => JsonWebKey.Create(ThisAssembly.Metadata.Funding.GitHub.devlooped); } diff --git a/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj b/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj index f4a8eff1..fe4ee467 100644 --- a/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj +++ b/src/ThisAssembly.Tests/ThisAssembly.Tests.csproj @@ -119,4 +119,18 @@ + + + + + + + + $([System.IO.File]::ReadAllText('$(MSBuildProjectDirectory)\$(BaseIntermediateOutputPath)devlooped.jwk')) + + + + + +