From e4cf7a6d3e094ecc904f87729d5ad303008774bd Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 14 May 2018 09:59:13 -0700 Subject: [PATCH] Fix #773 (for real this time) The problem is that the new HTML rewrite pass was traversing into attributes of all kinds and would turn any HTML content inside those attributes into elements where possible. The solution is to not do that. --- .../BlazorRuntimeNodeWriter.cs | 9 ++++- .../ComponentDocumentRewritePass.cs | 15 +++++++++ .../ComponentRenderingRazorIntegrationTest.cs | 33 +++++++++++++++++++ .../DesignTimeCodeGenerationTest.cs | 2 ++ .../RuntimeCodeGenerationTest.cs | 4 +++ .../Regression_772/TestComponent.codegen.cs | 1 - .../Regression_772/TestComponent.ir.txt | 2 ++ .../Regression_773/TestComponent.codegen.cs | 7 ++++ .../Regression_773/TestComponent.ir.txt | 31 +++++++++-------- .../Regression_773/TestComponent.mappings.txt | 9 +++-- .../Regression_772/TestComponent.codegen.cs | 2 +- .../Regression_772/TestComponent.ir.txt | 2 ++ .../Regression_773/TestComponent.codegen.cs | 6 ++-- .../Regression_773/TestComponent.ir.txt | 18 +++++----- 14 files changed, 110 insertions(+), 31 deletions(-) diff --git a/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs b/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs index c2fcefc275..fbeefdb176 100644 --- a/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs +++ b/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs @@ -355,7 +355,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor else if (node.Children.Count == 1 && node.Children[0] is HtmlContentIntermediateNode htmlNode) { // This is how string attributes are lowered by default, a single HTML node with a single HTML token. - context.CodeWriter.WriteStringLiteral(((IntermediateToken)htmlNode.Children[0]).Content); + var content = string.Join(string.Empty, GetHtmlTokens(htmlNode).Select(t => t.Content)); + context.CodeWriter.WriteStringLiteral(content); } else { @@ -391,6 +392,12 @@ namespace Microsoft.AspNetCore.Blazor.Razor // We generally expect all children to be CSharp, this is here just in case. return attribute.FindDescendantNodes().Where(t => t.IsCSharp).ToArray(); } + + IReadOnlyList GetHtmlTokens(HtmlContentIntermediateNode html) + { + // We generally expect all children to be HTML, this is here just in case. + return html.FindDescendantNodes().Where(t => t.IsHtml).ToArray(); + } } public override void WriteReferenceCapture(CodeRenderingContext context, RefExtensionNode node) diff --git a/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/ComponentDocumentRewritePass.cs b/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/ComponentDocumentRewritePass.cs index a9855aa694..86025cfc15 100644 --- a/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/ComponentDocumentRewritePass.cs +++ b/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/ComponentDocumentRewritePass.cs @@ -80,6 +80,21 @@ namespace Microsoft.AspNetCore.Blazor.Razor RewriteChildren(_source, node); } } + + public override void VisitHtmlAttribute(HtmlAttributeIntermediateNode node) + { + // Don't rewrite inside of attributes + } + + public override void VisitTagHelperHtmlAttribute(TagHelperHtmlAttributeIntermediateNode node) + { + // Don't rewrite inside of attributes + } + + public override void VisitTagHelperProperty(TagHelperPropertyIntermediateNode node) + { + // Don't rewrite inside of attributes + } private void RewriteChildren(RazorSourceDocument source, IntermediateNode node) { diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/ComponentRenderingRazorIntegrationTest.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/ComponentRenderingRazorIntegrationTest.cs index e5e699ab2e..e32d059e14 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/ComponentRenderingRazorIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/ComponentRenderingRazorIntegrationTest.cs @@ -409,5 +409,38 @@ namespace Test GetFrames((RenderFragment)innerFrames[1].AttributeValue), frame => AssertFrame.Text(frame, "Some text", 4)); } + + [Fact] // https://github.com/aspnet/Blazor/issues/773 + public void Regression_773() + { + // Arrange + AdditionalSyntaxTrees.Add(Parse(@" +using Microsoft.AspNetCore.Blazor.Components; + +namespace Test +{ + public class SurveyPrompt : BlazorComponent + { + [Parameter] private string Title { get; set; } + } +} +")); + + var component = CompileToComponent(@" +@addTagHelper *, TestAssembly +@page ""/"" + +Test!"" /> +"); + + // Act + var frames = GetRenderTree(component); + + // Assert + Assert.Collection( + frames, + frame => AssertFrame.Component(frame, "Test.SurveyPrompt", 2, 0), + frame => AssertFrame.Attribute(frame, "Title", "
Test!
", 1)); + } } } diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/DesignTimeCodeGenerationTest.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/DesignTimeCodeGenerationTest.cs index db68ebb1dc..88037c1d79 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/DesignTimeCodeGenerationTest.cs +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/DesignTimeCodeGenerationTest.cs @@ -425,6 +425,7 @@ namespace Test // Act var generated = CompileToCSharp(@" +@addTagHelper *, TestAssembly @page ""/""

Hello, world!

@@ -437,6 +438,7 @@ Welcome to your new app. // Assert AssertDocumentNodeMatchesBaseline(generated.CodeDocument); AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); + CompileToAssembly(generated); } [Fact] diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/RuntimeCodeGenerationTest.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/RuntimeCodeGenerationTest.cs index 13465e77fe..a1674e3ec4 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/RuntimeCodeGenerationTest.cs +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/RuntimeCodeGenerationTest.cs @@ -660,6 +660,8 @@ Welcome to your new app. [Fact] // https://github.com/aspnet/Blazor/issues/773 public void Regression_773() { + GenerateBaselines = true; + // Arrange AdditionalSyntaxTrees.Add(Parse(@" using Microsoft.AspNetCore.Blazor.Components; @@ -675,6 +677,7 @@ namespace Test // Act var generated = CompileToCSharp(@" +@addTagHelper *, TestAssembly @page ""/""

Hello, world!

@@ -687,6 +690,7 @@ Welcome to your new app. // Assert AssertDocumentNodeMatchesBaseline(generated.CodeDocument); AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); + CompileToAssembly(generated); } [Fact] diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_772/TestComponent.codegen.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_772/TestComponent.codegen.cs index e21dcde2b9..e2e9bbc888 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_772/TestComponent.codegen.cs +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_772/TestComponent.codegen.cs @@ -31,7 +31,6 @@ global::System.Object __typeHelper = "/"; protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder) { base.BuildRenderTree(builder); - __o = ; builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment)((builder2) => { } )); diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_772/TestComponent.ir.txt b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_772/TestComponent.ir.txt index a114b22a19..593ec5c598 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_772/TestComponent.ir.txt +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_772/TestComponent.ir.txt @@ -33,3 +33,5 @@ Document - IntermediateToken - (66:3,22 [32] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\nWelcome to your new app.\n\n ComponentExtensionNode - (98:7,0 [23] x:\dir\subdir\Test\TestComponent.cshtml) - SurveyPrompt - Test.SurveyPrompt ComponentAttributeExtensionNode - (119:7,21 [0] x:\dir\subdir\Test\TestComponent.cshtml) - Title - Title + HtmlContent - (119:7,21 [0] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (119:7,21 [0] x:\dir\subdir\Test\TestComponent.cshtml) - Html - diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.codegen.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.codegen.cs index 41a4248217..e2e9bbc888 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.codegen.cs +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.codegen.cs @@ -15,6 +15,10 @@ namespace Test #pragma warning disable 219 private void __RazorDirectiveTokenHelpers__() { ((System.Action)(() => { +global::System.Object __typeHelper = "*, TestAssembly"; + } + ))(); + ((System.Action)(() => { global::System.Object __typeHelper = "/"; } ))(); @@ -27,6 +31,9 @@ global::System.Object __typeHelper = "/"; protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder) { base.BuildRenderTree(builder); + builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment)((builder2) => { + } + )); } #pragma warning restore 1998 } diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.ir.txt b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.ir.txt index 96218d8006..cb620a3ff9 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.ir.txt +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.ir.txt @@ -11,7 +11,8 @@ Document - DesignTimeDirective - DirectiveToken - (14:0,14 [32] ) - "*, Microsoft.AspNetCore.Blazor" DirectiveToken - (14:0,14 [9] ) - "*, Test" - DirectiveToken - (6:0,6 [3] x:\dir\subdir\Test\TestComponent.cshtml) - "/" + DirectiveToken - (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml) - *, TestAssembly + DirectiveToken - (37:1,6 [3] x:\dir\subdir\Test\TestComponent.cshtml) - "/" CSharpCode - IntermediateToken - - CSharp - #pragma warning disable 0414 CSharpCode - @@ -21,16 +22,18 @@ Document - MethodDeclaration - - protected override - void - BuildRenderTree CSharpCode - IntermediateToken - - CSharp - base.BuildRenderTree(builder); - HtmlContent - (11:1,0 [2] x:\dir\subdir\Test\TestComponent.cshtml) - IntermediateToken - (11:1,0 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n - HtmlElement - (13:2,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - h1 - HtmlContent - (17:2,4 [13] x:\dir\subdir\Test\TestComponent.cshtml) - IntermediateToken - (17:2,4 [13] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello, world! - HtmlContent - (35:2,22 [32] x:\dir\subdir\Test\TestComponent.cshtml) - IntermediateToken - (35:2,22 [32] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\nWelcome to your new app.\n\n - HtmlElement - (67:6,0 [41] x:\dir\subdir\Test\TestComponent.cshtml) - surveyprompt - HtmlAttribute - - - - HtmlAttributeValue - - - IntermediateToken - - Html -
Test!
- HtmlContent - (108:6,41 [2] x:\dir\subdir\Test\TestComponent.cshtml) - IntermediateToken - (108:6,41 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n + HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n + HtmlContent - (42:2,0 [2] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (42:2,0 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n + HtmlElement - (44:3,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - h1 + HtmlContent - (48:3,4 [13] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (48:3,4 [13] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello, world! + HtmlContent - (66:3,22 [32] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (66:3,22 [32] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\nWelcome to your new app.\n\n + ComponentExtensionNode - (98:7,0 [41] x:\dir\subdir\Test\TestComponent.cshtml) - SurveyPrompt - Test.SurveyPrompt + ComponentAttributeExtensionNode - (119:7,21 [16] x:\dir\subdir\Test\TestComponent.cshtml) - Title - Title + HtmlContent - (119:7,21 [16] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (119:7,21 [16] x:\dir\subdir\Test\TestComponent.cshtml) - Html -
Test!
+ HtmlContent - (139:7,41 [2] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (139:7,41 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.mappings.txt b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.mappings.txt index e0c00d34b3..ed2bbca8b6 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.mappings.txt +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/DesignTimeCodeGenerationTest/Regression_773/TestComponent.mappings.txt @@ -1,5 +1,10 @@ -Source Location: (6:0,6 [3] x:\dir\subdir\Test\TestComponent.cshtml) +Source Location: (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml) +|*, TestAssembly| +Generated Location: (625:17,38 [15] ) +|*, TestAssembly| + +Source Location: (37:1,6 [3] x:\dir\subdir\Test\TestComponent.cshtml) |"/"| -Generated Location: (624:17,37 [3] ) +Generated Location: (741:21,37 [3] ) |"/"| diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_772/TestComponent.codegen.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_772/TestComponent.codegen.cs index 7d68051cbd..e84940c3b4 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_772/TestComponent.codegen.cs +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_772/TestComponent.codegen.cs @@ -21,7 +21,7 @@ namespace Test builder.CloseElement(); builder.AddContent(2, "\n\nWelcome to your new app.\n\n"); builder.OpenComponent(3); - builder.AddAttribute(4, "Title", ); + builder.AddAttribute(4, "Title", ""); builder.CloseComponent(); } #pragma warning restore 1998 diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_772/TestComponent.ir.txt b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_772/TestComponent.ir.txt index fa34764590..254965721c 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_772/TestComponent.ir.txt +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_772/TestComponent.ir.txt @@ -18,3 +18,5 @@ Document - IntermediateToken - (66:3,22 [32] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\nWelcome to your new app.\n\n ComponentExtensionNode - (98:7,0 [23] x:\dir\subdir\Test\TestComponent.cshtml) - SurveyPrompt - Test.SurveyPrompt ComponentAttributeExtensionNode - (119:7,21 [0] x:\dir\subdir\Test\TestComponent.cshtml) - Title - Title + HtmlContent - (119:7,21 [0] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (119:7,21 [0] x:\dir\subdir\Test\TestComponent.cshtml) - Html - diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_773/TestComponent.codegen.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_773/TestComponent.codegen.cs index f3807189a3..6a9b4db856 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_773/TestComponent.codegen.cs +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_773/TestComponent.codegen.cs @@ -20,9 +20,9 @@ namespace Test builder.AddContent(1, "Hello, world!"); builder.CloseElement(); builder.AddContent(2, "\n\nWelcome to your new app.\n\n"); - builder.OpenElement(3, "surveyprompt"); - builder.AddAttribute(4, "title", "
Test!
"); - builder.CloseElement(); + builder.OpenComponent(3); + builder.AddAttribute(4, "Title", "
Test!
"); + builder.CloseComponent(); } #pragma warning restore 1998 } diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_773/TestComponent.ir.txt b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_773/TestComponent.ir.txt index 0b1144b537..3cf7b01158 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_773/TestComponent.ir.txt +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/TestFiles/RuntimeCodeGenerationTest/Regression_773/TestComponent.ir.txt @@ -11,12 +11,12 @@ Document - MethodDeclaration - - protected override - void - BuildRenderTree CSharpCode - IntermediateToken - - CSharp - base.BuildRenderTree(builder); - HtmlElement - (13:2,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - h1 - HtmlContent - (17:2,4 [13] x:\dir\subdir\Test\TestComponent.cshtml) - IntermediateToken - (17:2,4 [13] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello, world! - HtmlContent - (35:2,22 [32] x:\dir\subdir\Test\TestComponent.cshtml) - IntermediateToken - (35:2,22 [32] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\nWelcome to your new app.\n\n - HtmlElement - (67:6,0 [41] x:\dir\subdir\Test\TestComponent.cshtml) - surveyprompt - HtmlAttribute - - - - HtmlAttributeValue - - - IntermediateToken - - Html -
Test!
+ HtmlElement - (44:3,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - h1 + HtmlContent - (48:3,4 [13] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (48:3,4 [13] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello, world! + HtmlContent - (66:3,22 [32] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (66:3,22 [32] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\nWelcome to your new app.\n\n + ComponentExtensionNode - (98:7,0 [41] x:\dir\subdir\Test\TestComponent.cshtml) - SurveyPrompt - Test.SurveyPrompt + ComponentAttributeExtensionNode - (119:7,21 [16] x:\dir\subdir\Test\TestComponent.cshtml) - Title - Title + HtmlContent - (119:7,21 [16] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (119:7,21 [16] x:\dir\subdir\Test\TestComponent.cshtml) - Html -
Test!