Skip to content

Commit 1d2877e

Browse files
Restore Razor v3 whitespace behavior when langversion < 5. Fixes #28085 (#28191)
* Add legacy 3.1 fork of the whitespace tests, with baselines based on 5.0 behavior * Remove non-applicable Legacy_3_1_WhiteSpace_WithPreserveWhitespace test * Set the legacy tests to run with RazorLanguageVersion.Version_3_0 * Add legacy fork of the whitespace pass * Consolidate both versions of whitespace pass and show it doesn't affect the baselines * Revert BOM change * Fix test
1 parent e47cbf6 commit 1d2877e

File tree

48 files changed

+1501
-9
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1501
-9
lines changed

src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/IntegrationTests/CodeGenerationIntegrationTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public CodeGenerationIntegrationTest()
1919
: base(generateBaselines: null, projectDirectoryHint: "Microsoft.AspNetCore.Mvc.Razor.Extensions")
2020
{
2121
Configuration = RazorConfiguration.Create(
22-
RazorLanguageVersion.Version_3_0,
22+
RazorLanguageVersion.Latest,
2323
"MVC-3.0",
2424
new[] { new AssemblyExtension("MVC-3.0", typeof(ExtensionInitializer).Assembly) });
2525
}

src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentWhitespacePass.cs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,38 @@ protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentInte
3939
return;
4040
}
4141

42-
// Respect @preservewhitespace directives
43-
if (PreserveWhitespaceIsEnabled(documentNode))
42+
var razorLanguageVersion = codeDocument.GetParserOptions().Version;
43+
var useLegacyBehavior = razorLanguageVersion.CompareTo(RazorLanguageVersion.Version_5_0) < 0;
44+
if (useLegacyBehavior)
4445
{
45-
return;
46-
}
46+
// Prior to 5.0, the whitespace pass only applied to the BuildRenderTree method, and
47+
// only removed the top-level leading and trailing whitespace
4748

48-
var @class = documentNode.FindPrimaryClass();
49-
if (@class != null)
49+
var method = documentNode.FindPrimaryMethod();
50+
if (method != null)
51+
{
52+
RemoveContiguousWhitespace(method.Children, TraversalDirection.Forwards);
53+
RemoveContiguousWhitespace(method.Children, TraversalDirection.Backwards);
54+
}
55+
}
56+
else
5057
{
51-
var visitor = new Visitor();
52-
visitor.Visit(@class);
58+
// From 5.0 onwards, the whitespace pass applies as broadly as possible. It removes leading
59+
// and trailing whitespace from all methods, elements, and child component blocks. There's
60+
// also a directive that can disable it.
61+
62+
// Respect @preservewhitespace directives
63+
if (PreserveWhitespaceIsEnabled(documentNode))
64+
{
65+
return;
66+
}
67+
68+
var @class = documentNode.FindPrimaryClass();
69+
if (@class != null)
70+
{
71+
var visitor = new Visitor();
72+
visitor.Visit(@class);
73+
}
5374
}
5475
}
5576

src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4768,6 +4768,240 @@ @preservewhitespace true
47684768
int Foo = 18;
47694769
}
47704770
4771+
");
4772+
4773+
// Assert
4774+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
4775+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
4776+
CompileToAssembly(generated);
4777+
}
4778+
4779+
#endregion
4780+
4781+
#region Legacy 3.1 Whitespace
4782+
4783+
[Fact]
4784+
public void Legacy_3_1_LeadingWhiteSpace_WithDirective()
4785+
{
4786+
// Arrange/Act
4787+
_configuration = RazorConfiguration.Create(
4788+
RazorLanguageVersion.Version_3_0,
4789+
base.Configuration.ConfigurationName,
4790+
base.Configuration.Extensions);
4791+
4792+
var generated = CompileToCSharp(@"
4793+
4794+
@using System
4795+
4796+
<h1>Hello</h1>");
4797+
4798+
// Assert
4799+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
4800+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
4801+
CompileToAssembly(generated);
4802+
}
4803+
4804+
[Fact]
4805+
public void Legacy_3_1_LeadingWhiteSpace_WithCSharpExpression()
4806+
{
4807+
// Arrange/Act
4808+
_configuration = RazorConfiguration.Create(
4809+
RazorLanguageVersion.Version_3_0,
4810+
base.Configuration.ConfigurationName,
4811+
base.Configuration.Extensions);
4812+
4813+
var generated = CompileToCSharp(@"
4814+
4815+
@(""My value"")
4816+
4817+
<h1>Hello</h1>");
4818+
4819+
// Assert
4820+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
4821+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
4822+
CompileToAssembly(generated);
4823+
}
4824+
4825+
[Fact]
4826+
public void Legacy_3_1_LeadingWhiteSpace_WithComponent()
4827+
{
4828+
// Arrange
4829+
_configuration = RazorConfiguration.Create(
4830+
RazorLanguageVersion.Version_3_0,
4831+
base.Configuration.ConfigurationName,
4832+
base.Configuration.Extensions);
4833+
4834+
AdditionalSyntaxTrees.Add(Parse(@"
4835+
using Microsoft.AspNetCore.Components;
4836+
4837+
namespace Test
4838+
{
4839+
public class SomeOtherComponent : ComponentBase
4840+
{
4841+
[Parameter] public RenderFragment ChildContent { get; set; }
4842+
}
4843+
}
4844+
"));
4845+
4846+
// Act
4847+
var generated = CompileToCSharp(@"
4848+
<SomeOtherComponent>
4849+
<h1>Child content at @DateTime.Now</h1>
4850+
<p>Very @(""good"")</p>
4851+
</SomeOtherComponent>
4852+
4853+
<h1>Hello</h1>");
4854+
4855+
// Assert
4856+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
4857+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
4858+
CompileToAssembly(generated);
4859+
}
4860+
4861+
[Fact]
4862+
public void Legacy_3_1_TrailingWhiteSpace_WithDirective()
4863+
{
4864+
// Arrange/Act
4865+
_configuration = RazorConfiguration.Create(
4866+
RazorLanguageVersion.Version_3_0,
4867+
base.Configuration.ConfigurationName,
4868+
base.Configuration.Extensions);
4869+
4870+
var generated = CompileToCSharp(@"
4871+
<h1>Hello</h1>
4872+
4873+
@page ""/my/url""
4874+
4875+
");
4876+
4877+
// Assert
4878+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
4879+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
4880+
CompileToAssembly(generated);
4881+
}
4882+
4883+
[Fact]
4884+
public void Legacy_3_1_TrailingWhiteSpace_WithCSharpExpression()
4885+
{
4886+
// Arrange/Act
4887+
_configuration = RazorConfiguration.Create(
4888+
RazorLanguageVersion.Version_3_0,
4889+
base.Configuration.ConfigurationName,
4890+
base.Configuration.Extensions);
4891+
4892+
var generated = CompileToCSharp(@"
4893+
<h1>Hello</h1>
4894+
4895+
@(""My value"")
4896+
4897+
");
4898+
4899+
// Assert
4900+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
4901+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
4902+
CompileToAssembly(generated);
4903+
}
4904+
4905+
[Fact]
4906+
public void Legacy_3_1_TrailingWhiteSpace_WithComponent()
4907+
{
4908+
// Arrange
4909+
_configuration = RazorConfiguration.Create(
4910+
RazorLanguageVersion.Version_3_0,
4911+
base.Configuration.ConfigurationName,
4912+
base.Configuration.Extensions);
4913+
4914+
AdditionalSyntaxTrees.Add(Parse(@"
4915+
using Microsoft.AspNetCore.Components;
4916+
4917+
namespace Test
4918+
{
4919+
public class SomeOtherComponent : ComponentBase
4920+
{
4921+
}
4922+
}
4923+
"));
4924+
4925+
// Act
4926+
var generated = CompileToCSharp(@"
4927+
<h1>Hello</h1>
4928+
4929+
<SomeOtherComponent />
4930+
4931+
");
4932+
4933+
// Assert
4934+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
4935+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
4936+
CompileToAssembly(generated);
4937+
}
4938+
4939+
[Fact]
4940+
public void Legacy_3_1_Whitespace_BetweenElementAndFunctions()
4941+
{
4942+
// Arrange
4943+
_configuration = RazorConfiguration.Create(
4944+
RazorLanguageVersion.Version_3_0,
4945+
base.Configuration.ConfigurationName,
4946+
base.Configuration.Extensions);
4947+
4948+
// Act
4949+
var generated = CompileToCSharp(@"
4950+
<elem attr=@Foo />
4951+
@code {
4952+
int Foo = 18;
4953+
}
4954+
");
4955+
4956+
// Assert
4957+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
4958+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
4959+
CompileToAssembly(generated);
4960+
}
4961+
4962+
[Fact]
4963+
public void Legacy_3_1_WhiteSpace_InsideAttribute_InMarkupBlock()
4964+
{
4965+
// Arrange
4966+
_configuration = RazorConfiguration.Create(
4967+
RazorLanguageVersion.Version_3_0,
4968+
base.Configuration.ConfigurationName,
4969+
base.Configuration.Extensions);
4970+
4971+
// Act
4972+
var generated = CompileToCSharp(@"<div class=""first second"">Hello</div>");
4973+
4974+
// Assert
4975+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
4976+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
4977+
CompileToAssembly(generated);
4978+
}
4979+
4980+
[Fact]
4981+
public void Legacy_3_1_WhiteSpace_InMarkupInFunctionsBlock()
4982+
{
4983+
// Arrange
4984+
_configuration = RazorConfiguration.Create(
4985+
RazorLanguageVersion.Version_3_0,
4986+
base.Configuration.ConfigurationName,
4987+
base.Configuration.Extensions);
4988+
4989+
// Act
4990+
var generated = CompileToCSharp(@"
4991+
@using Microsoft.AspNetCore.Components.Rendering
4992+
@code {
4993+
void MyMethod(RenderTreeBuilder __builder)
4994+
{
4995+
<ul>
4996+
@for (var i = 0; i < 100; i++)
4997+
{
4998+
<li>
4999+
@i
5000+
</li>
5001+
}
5002+
</ul>
5003+
}
5004+
}
47715005
");
47725006

47735007
// Assert
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// <auto-generated/>
2+
#pragma warning disable 1591
3+
namespace Test
4+
{
5+
#line hidden
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Threading.Tasks;
10+
using Microsoft.AspNetCore.Components;
11+
public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
12+
{
13+
#pragma warning disable 219
14+
private void __RazorDirectiveTokenHelpers__() {
15+
}
16+
#pragma warning restore 219
17+
#pragma warning disable 0414
18+
private static System.Object __o = null;
19+
#pragma warning restore 0414
20+
#pragma warning disable 1998
21+
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
22+
{
23+
#nullable restore
24+
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
25+
__o = "My value";
26+
27+
#line default
28+
#line hidden
29+
#nullable disable
30+
}
31+
#pragma warning restore 1998
32+
}
33+
}
34+
#pragma warning restore 1591
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Document -
2+
NamespaceDeclaration - - Test
3+
UsingDirective - (3:1,1 [12] ) - System
4+
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
5+
UsingDirective - (53:3,1 [17] ) - System.Linq
6+
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
7+
UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
8+
ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
9+
DesignTimeDirective -
10+
CSharpCode -
11+
IntermediateToken - - CSharp - #pragma warning disable 0414
12+
CSharpCode -
13+
IntermediateToken - - CSharp - private static System.Object __o = null;
14+
CSharpCode -
15+
IntermediateToken - - CSharp - #pragma warning restore 0414
16+
MethodDeclaration - - protected override - void - BuildRenderTree
17+
CSharpExpression - (2:0,2 [10] x:\dir\subdir\Test\TestComponent.cshtml)
18+
LazyIntermediateToken - (2:0,2 [10] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "My value"
19+
HtmlContent - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml)
20+
LazyIntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
21+
MarkupElement - (17:2,0 [14] x:\dir\subdir\Test\TestComponent.cshtml) - h1
22+
HtmlContent - (21:2,4 [5] x:\dir\subdir\Test\TestComponent.cshtml)
23+
LazyIntermediateToken - (21:2,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Source Location: (2:0,2 [10] x:\dir\subdir\Test\TestComponent.cshtml)
2+
|"My value"|
3+
Generated Location: (858:24,6 [10] )
4+
|"My value"|
5+

0 commit comments

Comments
 (0)