Skip to content

Commit ca88604

Browse files
committed
Ensure we properly format multiline raw strings
We had weird newline formatting after applying C# whitespace normalization. A quick rewriter fixes that now. We use the devlooped JWT which requies preserving formatting for proper parsing as a test.
1 parent 55bc8fc commit ca88604

File tree

5 files changed

+51
-14
lines changed

5 files changed

+51
-14
lines changed

src/ThisAssembly.Constants/CSharp.sbntxt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
{{ obsolete }}
4646
{{~ if RawStrings && value.IsText ~}}
4747
public {{ Modifier }} string {{ value.Name | string.replace "-" "_" | string.replace " " "_" }} ={{ Lambda }}
48-
4948
"""
5049
{{ value.Value }}
5150
""";

src/ThisAssembly.Constants/ConstantsGenerator.cs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Globalization;
33
using System.IO;
44
using System.Linq;
5+
using System.Runtime.InteropServices;
56
using System.Text;
67
using System.Xml.Linq;
78
using Devlooped.Sponsors;
@@ -94,12 +95,12 @@ void GenerateConstant(SourceProductionContext spc,
9495
}
9596

9697
if (comment != null)
97-
comment = "/// " + string.Join(Environment.NewLine + "/// ", new XText(comment).ToString().Trim().Replace("\\n", Environment.NewLine).Trim(['\r', '\n']).Split([Environment.NewLine], StringSplitOptions.None));
98+
comment = "/// " + string.Join(Environment.NewLine + "/// ", new XText(comment).ToString().Trim().Replace("`n", Environment.NewLine).Trim(['\r', '\n']).Split([Environment.NewLine], StringSplitOptions.None));
9899
else
99-
comment = "/// " + string.Join(Environment.NewLine + "/// ", new XText(value).ToString().Replace("\\n", Environment.NewLine).Trim(['\r', '\n']).Split([Environment.NewLine], StringSplitOptions.None));
100+
comment = "/// " + string.Join(Environment.NewLine + "/// ", new XText(value).ToString().Replace("`n", Environment.NewLine).Trim(['\r', '\n']).Split([Environment.NewLine], StringSplitOptions.None));
100101

101102
// Revert normalization of newlines performed in MSBuild to workaround the limitation in editorconfig.
102-
var rootArea = Area.Load([new(name, value.Replace("\\n", Environment.NewLine).Trim(['\r', '\n']), comment, type ?? "string"),], root, rootComment);
103+
var rootArea = Area.Load([new(name, value.Replace("`n", Environment.NewLine).Trim(['\r', '\n']), comment, type ?? "string"),], root, rootComment);
103104
// For now, we only support C# though
104105
var file = parse.Language.Replace("#", "Sharp") + ".sbntxt";
105106
var template = Template.Parse(EmbeddedResource.GetContent(file), file);
@@ -123,17 +124,35 @@ void GenerateConstant(SourceProductionContext spc,
123124

124125
var output = template.Render(model, member => member.Name);
125126

126-
// Apply formatting since indenting isn't that nice in Scriban when rendering nested
127-
// structures via functions.
128127
if (parse.Language == LanguageNames.CSharp)
129128
{
130-
output = SyntaxFactory
131-
.ParseCompilationUnit(output, options: cs)
132-
.NormalizeWhitespace()
133-
.GetText()
134-
.ToString();
129+
// Apply formatting since indenting isn't that nice in Scriban when rendering nested
130+
// structures via functions.
131+
// We alos rewrite to prepend a newline leading trivia before the raw string literals if any
132+
var node = new RawStringLiteralRewriter().Visit(
133+
SyntaxFactory.ParseCompilationUnit(output, options: cs).NormalizeWhitespace(eol: Environment.NewLine));
134+
135+
output = node.GetText().ToString();
135136
}
136137

137138
spc.AddSource($"{root}.{name}.g.cs", SourceText.From(output, Encoding.UTF8));
138139
}
139-
}
140+
141+
class RawStringLiteralRewriter : CSharpSyntaxRewriter
142+
{
143+
public override SyntaxToken VisitToken(SyntaxToken token)
144+
{
145+
// See https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.csharp.syntaxkind?view=roslyn-dotnet-4.13.0
146+
// MultiLineRawStringLiteralToken = 8519
147+
// Utf8MultiLineRawStringLiteralToken = 8522
148+
if (token.RawKind == 8519 || token.RawKind == 8522)
149+
return token.WithLeadingTrivia(
150+
token.LeadingTrivia.Add(
151+
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
152+
SyntaxFactory.CarriageReturnLineFeed :
153+
SyntaxFactory.LineFeed));
154+
155+
return base.VisitToken(token);
156+
}
157+
}
158+
}

src/ThisAssembly.Constants/ThisAssembly.Constants.targets

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@
5050
<ItemGroup>
5151
<!-- Normalize newlines to avoid losing content -->
5252
<Constant Update="@(Constant)">
53-
<Value>$([MSBuild]::ValueOrDefault('%(Constant.Value)', '').Replace($([System.Environment]::NewLine), '\n'))</Value>
54-
<Comment>$([MSBuild]::ValueOrDefault('%(Constant.Comment)', '').Replace($([System.Environment]::NewLine), '\n'))</Comment>
53+
<Value>$([MSBuild]::ValueOrDefault('%(Constant.Value)', '').Replace('&#xD;&#xA;', '`n').Replace('&#xA;', '`n'))</Value>
54+
<Comment>$([MSBuild]::ValueOrDefault('%(Constant.Comment)', '').Replace('&#xD;&#xA;', '`n').Replace('&#xA;', '`n'))</Comment>
5555
</Constant>
5656
</ItemGroup>
5757
</Target>

src/ThisAssembly.Tests/Tests.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Diagnostics.CodeAnalysis;
33
using System.IO;
4+
using Microsoft.IdentityModel.Tokens;
45
using Xunit;
56
using Xunit.Abstractions;
67
//using ThisAssembly = ThisAssemblyTests
@@ -191,4 +192,8 @@ public void CanUseGitBranchConstants()
191192
[Fact]
192193
public void CanUseSemicolonsInConstant()
193194
=> Assert.Equal("A;B;C", ThisAssembly.Constants.WithSemiColon);
195+
196+
/// <summary />
197+
[Fact]
198+
public void CanReadJsonConstant() => JsonWebKey.Create(ThisAssembly.Metadata.Funding.GitHub.devlooped);
194199
}

src/ThisAssembly.Tests/ThisAssembly.Tests.csproj

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,18 @@
119119
<CompilerVisibleProperty Include="ThisAssembly" />
120120
</ItemGroup>
121121

122+
<Target Name="DownloadDevloopedJwk" BeforeTargets="GetAssemblyAttributes" Inputs="$(MSBuildProjectFullPath)" Outputs="$(MSBuildProjectDirectory)\$(BaseIntermediateOutputPath)devlooped.jwk">
123+
<Exec Command="curl --silent --output $(MSBuildProjectDirectory)\$(BaseIntermediateOutputPath)devlooped.jwk https://sponsorlink.devlooped.com/jwk" />
124+
</Target>
125+
126+
<Target Name="ReadDevloopedJwk" DependsOnTargets="DownloadDevloopedJwk" BeforeTargets="GetAssemblyAttributes">
127+
<PropertyGroup>
128+
<!-- Read public key we validate manifests against -->
129+
<DevloopedJwk>$([System.IO.File]::ReadAllText('$(MSBuildProjectDirectory)\$(BaseIntermediateOutputPath)devlooped.jwk'))</DevloopedJwk>
130+
</PropertyGroup>
131+
<ItemGroup>
132+
<AssemblyMetadata Include="Funding.GitHub.devlooped" Value="$(DevloopedJwk.Trim())" />
133+
</ItemGroup>
134+
</Target>
135+
122136
</Project>

0 commit comments

Comments
 (0)