From 39dda01f47b04fba9ac985344401587c5363dd2c Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Mon, 24 Aug 2015 15:44:00 -0700 Subject: [PATCH] [Fixes #484] Attributes parsed correctly when newlines precedes attributes --- .../Parser/HtmlMarkupParser.Block.cs | 4 +- .../CSharpTagHelperRenderingTest.cs | 1 + .../Parser/Html/HtmlAttributeTest.cs | 48 ++++++++++++++++- ...gleTagHelperWithNewlineBeforeAttributes.cs | 53 +++++++++++++++++++ ...agHelperWithNewlineBeforeAttributes.cshtml | 4 ++ 5 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/SingleTagHelperWithNewlineBeforeAttributes.cs create mode 100644 test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/SingleTagHelperWithNewlineBeforeAttributes.cshtml diff --git a/src/Microsoft.AspNet.Razor/Parser/HtmlMarkupParser.Block.cs b/src/Microsoft.AspNet.Razor/Parser/HtmlMarkupParser.Block.cs index 90a1ade056..de4835f967 100644 --- a/src/Microsoft.AspNet.Razor/Parser/HtmlMarkupParser.Block.cs +++ b/src/Microsoft.AspNet.Razor/Parser/HtmlMarkupParser.Block.cs @@ -405,9 +405,9 @@ namespace Microsoft.AspNet.Razor.Parser private void TagContent() { - if (!At(HtmlSymbolType.WhiteSpace)) + if (!At(HtmlSymbolType.WhiteSpace) && !At(HtmlSymbolType.NewLine)) { - // We should be right after the tag name, so if there's no whitespace, something is wrong + // We should be right after the tag name, so if there's no whitespace or new line, something is wrong RecoverToEndOfTag(); } else diff --git a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs index a096546305..cd9c86b89b 100644 --- a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs @@ -1483,6 +1483,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator return new TheoryData> { { "SingleTagHelper", null, DefaultPAndInputTagHelperDescriptors }, + { "SingleTagHelperWithNewlineBeforeAttributes", null, DefaultPAndInputTagHelperDescriptors }, { "BasicTagHelpers", null, DefaultPAndInputTagHelperDescriptors }, { "BasicTagHelpers.RemoveTagHelper", null, DefaultPAndInputTagHelperDescriptors }, { "BasicTagHelpers.Prefixed", null, PrefixedPAndInputTagHelperDescriptors }, diff --git a/test/Microsoft.AspNet.Razor.Test/Parser/Html/HtmlAttributeTest.cs b/test/Microsoft.AspNet.Razor.Test/Parser/Html/HtmlAttributeTest.cs index 1348da2975..52124442e0 100644 --- a/test/Microsoft.AspNet.Razor.Test/Parser/Html/HtmlAttributeTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/Parser/Html/HtmlAttributeTest.cs @@ -1,9 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Linq; using Microsoft.AspNet.Razor.Chunks.Generators; -using Microsoft.AspNet.Razor.Editor; using Microsoft.AspNet.Razor.Parser; using Microsoft.AspNet.Razor.Parser.SyntaxTree; using Microsoft.AspNet.Razor.Test.Framework; @@ -60,6 +60,52 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html Factory.Markup(" />").Accepts(AcceptedCharacters.None)))); } + [Fact] + public void NewLinePrecedingAttribute() + { + ParseBlockTest($"", + new MarkupBlock( + new MarkupTagBlock( + Factory.Markup("(Environment.NewLine + "href='", 2, 0, 2), suffix: new LocationTagged("'", 13, 1, 9)), + Factory.Markup(Environment.NewLine + "href='").With(SpanChunkGenerator.Null), + Factory.Markup("Foo").With(new LiteralAttributeChunkGenerator(prefix: new LocationTagged(string.Empty, 10, 1, 6), value: new LocationTagged("Foo", 10, 1, 6))), + Factory.Markup("'").With(SpanChunkGenerator.Null)), + Factory.Markup(" />").Accepts(AcceptedCharacters.None)))); + } + + [Fact] + public void NewLineBetweenAttributes() + { + ParseBlockTest($"", + new MarkupBlock( + new MarkupTagBlock( + Factory.Markup("(Environment.NewLine + "href='", 2, 0, 2), suffix: new LocationTagged("'", 13, 1, 9)), + Factory.Markup(Environment.NewLine + "href='").With(SpanChunkGenerator.Null), + Factory.Markup("Foo").With(new LiteralAttributeChunkGenerator(prefix: new LocationTagged(string.Empty, 10, 1, 6), value: new LocationTagged("Foo", 10, 1, 6))), + Factory.Markup("'").With(SpanChunkGenerator.Null)), + new MarkupBlock(new AttributeBlockChunkGenerator(name: "abcd", prefix: new LocationTagged(Environment.NewLine + "abcd='", 14, 1, 0), suffix: new LocationTagged("'", 25, 2, 9)), + Factory.Markup(Environment.NewLine + "abcd='").With(SpanChunkGenerator.Null), + Factory.Markup("Bar").With(new LiteralAttributeChunkGenerator(prefix: new LocationTagged(string.Empty, 22, 2, 6), value: new LocationTagged("Bar", 22, 2, 6))), + Factory.Markup("'").With(SpanChunkGenerator.Null)), + Factory.Markup(" />").Accepts(AcceptedCharacters.None)))); + } + + [Fact] + public void WhitespaceAndNewLinePrecedingAttribute() + { + ParseBlockTest($"", + new MarkupBlock( + new MarkupTagBlock( + Factory.Markup("(" " + Environment.NewLine + "href='", 2, 0, 2), suffix: new LocationTagged("'", 14, 1, 9)), + Factory.Markup(" " + Environment.NewLine + "href='").With(SpanChunkGenerator.Null), + Factory.Markup("Foo").With(new LiteralAttributeChunkGenerator(prefix: new LocationTagged(string.Empty, 11, 1, 6), value: new LocationTagged("Foo", 11, 1, 6))), + Factory.Markup("'").With(SpanChunkGenerator.Null)), + Factory.Markup(" />").Accepts(AcceptedCharacters.None)))); + } + [Fact] public void UnquotedLiteralAttribute() { diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/SingleTagHelperWithNewlineBeforeAttributes.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/SingleTagHelperWithNewlineBeforeAttributes.cs new file mode 100644 index 0000000000..0ae69dc8a5 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/SingleTagHelperWithNewlineBeforeAttributes.cs @@ -0,0 +1,53 @@ +#pragma checksum "SingleTagHelperWithNewlineBeforeAttributes.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "95e2e2bab663b8be9934a66150af50a2a6ee08e7" +namespace TestOutput +{ + using Microsoft.AspNet.Razor.Runtime.TagHelpers; + using System; + using System.Threading.Tasks; + + public class SingleTagHelperWithNewlineBeforeAttributes + { + #line hidden + #pragma warning disable 0414 + private TagHelperContent __tagHelperStringValueBuffer = null; + #pragma warning restore 0414 + private TagHelperExecutionContext __tagHelperExecutionContext = null; + private TagHelperRunner __tagHelperRunner = null; + private TagHelperScopeManager __tagHelperScopeManager = new TagHelperScopeManager(); + private PTagHelper __PTagHelper = null; + #line hidden + public SingleTagHelperWithNewlineBeforeAttributes() + { + } + + #pragma warning disable 1998 + public override async Task ExecuteAsync() + { + __tagHelperRunner = __tagHelperRunner ?? new TagHelperRunner(); + Instrumentation.BeginContext(33, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", TagMode.StartTagAndEndTag, "test", async() => { + Instrumentation.BeginContext(73, 11, true); + WriteLiteral("Body of Tag"); + Instrumentation.EndContext(); + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __PTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__PTagHelper); + __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw("Hello World")); +#line 4 "SingleTagHelperWithNewlineBeforeAttributes.cshtml" + __PTagHelper.Age = 1337; + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(35, 53, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + } + #pragma warning restore 1998 + } +} diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/SingleTagHelperWithNewlineBeforeAttributes.cshtml b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/SingleTagHelperWithNewlineBeforeAttributes.cshtml new file mode 100644 index 0000000000..b974a60055 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/SingleTagHelperWithNewlineBeforeAttributes.cshtml @@ -0,0 +1,4 @@ +@addTagHelper "something, nice" + +

Body of Tag

\ No newline at end of file