diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperBlockRewriter.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperBlockRewriter.cs index ff156ca870..3bda1518c2 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperBlockRewriter.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperBlockRewriter.cs @@ -378,12 +378,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy var htmlSymbol = firstChild.Symbols[firstChild.Symbols.Count - 1] as HtmlSymbol; switch (htmlSymbol.Type) { - // Treat NoQuotes and DoubleQuotes equivalently. We purposefully do not persist NoQuotes - // ValueStyles at code generation time to protect users from rendering dynamic content with spaces - // that can break attributes. - // Ex: where @value results in the test "hello world". - // This way, the above code would render . case HtmlSymbolType.Equals: + if (builder.Children.Count == 2 && + builder.Children[1] is Span value && + value.Kind == SpanKindInternal.Markup) + { + // Attribute value is a string literal. Eg: . + result.AttributeValueStyle = HtmlAttributeValueStyle.NoQuotes; + } + else + { + // Could be an expression, treat NoQuotes and DoubleQuotes equivalently. We purposefully do not persist NoQuotes + // ValueStyles at code generation time to protect users from rendering dynamic content with spaces + // that can break attributes. + // Ex: where @value results in the test "hello world". + // This way, the above code would render . + result.AttributeValueStyle = HtmlAttributeValueStyle.DoubleQuotes; + } + break; case HtmlSymbolType.DoubleQuote: result.AttributeValueStyle = HtmlAttributeValueStyle.DoubleQuotes; break; diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TagHelperBlockRewriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TagHelperBlockRewriterTest.cs index 0c087b7d47..f975bbbdf7 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TagHelperBlockRewriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TagHelperBlockRewriterTest.cs @@ -460,7 +460,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new TagHelperAttributeNode( "bar", factory.Markup("false"), - HtmlAttributeValueStyle.DoubleQuotes) + HtmlAttributeValueStyle.NoQuotes) })), new [] { @@ -556,7 +556,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new MarkupTagHelperBlock("p", new List { - new TagHelperAttributeNode("class", factory.Markup("btn")) + new TagHelperAttributeNode("class", factory.Markup("btn"), HtmlAttributeValueStyle.NoQuotes) })), new [] { @@ -572,7 +572,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new MarkupTagHelperBlock("p", new List { - new TagHelperAttributeNode("class", factory.Markup("btn")) + new TagHelperAttributeNode("class", factory.Markup("btn"), HtmlAttributeValueStyle.NoQuotes) })), new [] { @@ -757,7 +757,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new MarkupTagHelperBlock("p", new List { - new TagHelperAttributeNode("class", factory.Markup("some")) + new TagHelperAttributeNode("class", factory.Markup("some"), HtmlAttributeValueStyle.NoQuotes) })), new [] { @@ -1238,7 +1238,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new MarkupTagHelperBlock("p", new List { - new TagHelperAttributeNode("class", factory.Markup("foo")), + new TagHelperAttributeNode("class", factory.Markup("foo"), HtmlAttributeValueStyle.NoQuotes), new TagHelperAttributeNode( "dynamic", new MarkupBlock( @@ -1254,7 +1254,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharactersInternal.NonWhiteSpace)))), HtmlAttributeValueStyle.DoubleQuotes), - new TagHelperAttributeNode("style", factory.Markup("color:red;")) + new TagHelperAttributeNode("style", factory.Markup("color:red;"), HtmlAttributeValueStyle.NoQuotes) }, new MarkupTagHelperBlock("strong")), blockFactory.MarkupTagBlock("")), @@ -2467,9 +2467,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new MarkupTagHelperBlock("p", new List { - new TagHelperAttributeNode("class", factory.Markup("foo")), + new TagHelperAttributeNode("class", factory.Markup("foo"), HtmlAttributeValueStyle.NoQuotes), new TagHelperAttributeNode("dynamic", dateTimeNow(21)), - new TagHelperAttributeNode("style", factory.Markup("color:red;")) + new TagHelperAttributeNode("style", factory.Markup("color:red;"), HtmlAttributeValueStyle.NoQuotes) })) }; yield return new object[] @@ -2479,9 +2479,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new MarkupTagHelperBlock("p", new List { - new TagHelperAttributeNode("class", factory.Markup("foo")), + new TagHelperAttributeNode("class", factory.Markup("foo"), HtmlAttributeValueStyle.NoQuotes), new TagHelperAttributeNode("dynamic", dateTimeNow(21)), - new TagHelperAttributeNode("style", factory.Markup("color:red;")) + new TagHelperAttributeNode("style", factory.Markup("color:red;"), HtmlAttributeValueStyle.NoQuotes) }, factory.Markup("Hello World"))) }; @@ -2492,7 +2492,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new MarkupTagHelperBlock("p", new List { - new TagHelperAttributeNode("class", factory.Markup("foo")), + new TagHelperAttributeNode("class", factory.Markup("foo"), HtmlAttributeValueStyle.NoQuotes), new TagHelperAttributeNode("dynamic", dateTimeNow(21)), new TagHelperAttributeNode( "style", @@ -2513,7 +2513,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new MarkupTagHelperBlock("p", new List { - new TagHelperAttributeNode("class", factory.Markup("foo")), + new TagHelperAttributeNode("class", factory.Markup("foo"), HtmlAttributeValueStyle.NoQuotes), new TagHelperAttributeNode("dynamic", dateTimeNow(21)) }, factory.Markup("Hello")), @@ -2521,7 +2521,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new MarkupTagHelperBlock("p", new List { - new TagHelperAttributeNode("style", factory.Markup("color:red;")), + new TagHelperAttributeNode("style", factory.Markup("color:red;"), HtmlAttributeValueStyle.NoQuotes), new TagHelperAttributeNode("dynamic", dateTimeNow(73)) }, factory.Markup("World"))) @@ -2533,9 +2533,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new MarkupTagHelperBlock("p", new List { - new TagHelperAttributeNode("class", factory.Markup("foo")), + new TagHelperAttributeNode("class", factory.Markup("foo"), HtmlAttributeValueStyle.NoQuotes), new TagHelperAttributeNode("dynamic", dateTimeNow(21)), - new TagHelperAttributeNode("style", factory.Markup("color:red;")) + new TagHelperAttributeNode("style", factory.Markup("color:red;"), HtmlAttributeValueStyle.NoQuotes) }, factory.Markup("Hello World "), new MarkupTagBlock( diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_DesignTime.ir.txt index 0b6d78075e..c9bec0b781 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_DesignTime.ir.txt +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_DesignTime.ir.txt @@ -60,6 +60,6 @@ Document - SetTagHelperProperty - (247:14,8 [8] TagHelpersWithWeirdlySpacedAttributes.cshtml) - type - Type - HtmlAttributeValueStyle.DoubleQuotes HtmlContent - (247:14,8 [8] TagHelpersWithWeirdlySpacedAttributes.cshtml) RazorIRToken - (247:14,8 [8] TagHelpersWithWeirdlySpacedAttributes.cshtml) - Html - password - AddTagHelperHtmlAttribute - - data-content - HtmlAttributeValueStyle.DoubleQuotes + AddTagHelperHtmlAttribute - - data-content - HtmlAttributeValueStyle.NoQuotes HtmlContent - (270:14,31 [4] TagHelpersWithWeirdlySpacedAttributes.cshtml) RazorIRToken - (270:14,31 [4] TagHelpersWithWeirdlySpacedAttributes.cshtml) - Html - blah diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_Runtime.codegen.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_Runtime.codegen.cs index 5c73f1aba6..f2b390a120 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_Runtime.codegen.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_Runtime.codegen.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests.TestFiles private static readonly global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute __tagHelperAttribute_2 = new global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute("data-content", new global::Microsoft.AspNetCore.Html.HtmlString("hello"), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes); private static readonly global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute __tagHelperAttribute_3 = new global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute("data-content", new global::Microsoft.AspNetCore.Html.HtmlString("hello2"), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.SingleQuotes); private static readonly global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute __tagHelperAttribute_4 = new global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute("type", "password", global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes); - private static readonly global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute __tagHelperAttribute_5 = new global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute("data-content", new global::Microsoft.AspNetCore.Html.HtmlString("blah"), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes); + private static readonly global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute __tagHelperAttribute_5 = new global::Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute("data-content", new global::Microsoft.AspNetCore.Html.HtmlString("blah"), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.NoQuotes); #line hidden #pragma warning disable 0414 private string __tagHelperStringValueBuffer = null; diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_Runtime.ir.txt b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_Runtime.ir.txt index 2f231c1c29..32e54b7981 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_Runtime.ir.txt +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/TagHelpersWithWeirdlySpacedAttributes_Runtime.ir.txt @@ -7,7 +7,7 @@ Document - DeclarePreallocatedTagHelperHtmlAttribute - - __tagHelperAttribute_2 - data-content - hello - HtmlAttributeValueStyle.DoubleQuotes DeclarePreallocatedTagHelperHtmlAttribute - - __tagHelperAttribute_3 - data-content - hello2 - HtmlAttributeValueStyle.SingleQuotes DeclarePreallocatedTagHelperAttribute - - __tagHelperAttribute_4 - type - password - HtmlAttributeValueStyle.DoubleQuotes - DeclarePreallocatedTagHelperHtmlAttribute - - __tagHelperAttribute_5 - data-content - blah - HtmlAttributeValueStyle.DoubleQuotes + DeclarePreallocatedTagHelperHtmlAttribute - - __tagHelperAttribute_5 - data-content - blah - HtmlAttributeValueStyle.NoQuotes DeclareTagHelperFields - - TestNamespace.PTagHelper - TestNamespace.InputTagHelper - TestNamespace.InputTagHelper2 MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync HtmlContent - (33:1,0 [2] TagHelpersWithWeirdlySpacedAttributes.cshtml)