Change HTML in nested C# blocks to properly handle dots.
- Prior to this change adding a `.` after an implicit expression would result in compile errors due to Razor thinking the `.` was part of the C# (normally not the case). - Added a code generation and unit tests to validate behavior. #491
This commit is contained in:
parent
f843aec538
commit
d458e8ecb2
|
|
@ -631,6 +631,11 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
|
||||
private void ParseWithOtherParser(Action<ParserBase> parseAction)
|
||||
{
|
||||
// When transitioning to the HTML parser we no longer want to act as if we're in a nested C# state.
|
||||
// For instance, if <div>@hello.</div> is in a nested C# block we don't want the trailing '.' to be handled
|
||||
// as C#; it should be handled as a period because it's wrapped in markup.
|
||||
var wasNested = IsNested;
|
||||
IsNested = false;
|
||||
using (PushSpanConfig())
|
||||
{
|
||||
Context.SwitchActiveParser();
|
||||
|
|
@ -638,6 +643,7 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
Context.SwitchActiveParser();
|
||||
}
|
||||
Initialize(Span);
|
||||
IsNested = wasNested;
|
||||
NextToken();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("NestedCSharp")]
|
||||
[InlineData("NullConditionalExpressions")]
|
||||
[InlineData("NestedCodeBlocks")]
|
||||
[InlineData("CodeBlock")]
|
||||
|
|
@ -75,6 +76,55 @@ namespace Microsoft.AspNet.Razor.Test.Generator
|
|||
RunTest(testType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpChunkGeneratorCorrectlyGeneratesMappingsForNestedCSharp()
|
||||
{
|
||||
RunTest(
|
||||
"NestedCSharp",
|
||||
"NestedCSharp.DesignTime",
|
||||
designTimeMode: true,
|
||||
tabTest: TabTest.NoTabs,
|
||||
expectedDesignTimePragmas: new List<LineMapping>
|
||||
{
|
||||
BuildLineMapping(
|
||||
documentAbsoluteIndex: 2,
|
||||
documentLineIndex: 0,
|
||||
generatedAbsoluteIndex: 522,
|
||||
generatedLineIndex: 22,
|
||||
characterOffsetIndex: 2,
|
||||
contentLength: 6),
|
||||
BuildLineMapping(
|
||||
documentAbsoluteIndex: 9,
|
||||
documentLineIndex: 1,
|
||||
documentCharacterOffsetIndex: 5,
|
||||
generatedAbsoluteIndex: 598,
|
||||
generatedLineIndex: 29,
|
||||
generatedCharacterOffsetIndex: 4,
|
||||
contentLength: 53),
|
||||
BuildLineMapping(
|
||||
documentAbsoluteIndex: 82,
|
||||
documentLineIndex: 4,
|
||||
generatedAbsoluteIndex: 730,
|
||||
generatedLineIndex: 37,
|
||||
characterOffsetIndex: 13,
|
||||
contentLength: 16),
|
||||
BuildLineMapping(
|
||||
documentAbsoluteIndex: 115,
|
||||
documentLineIndex: 5,
|
||||
generatedAbsoluteIndex: 825,
|
||||
generatedLineIndex: 42,
|
||||
characterOffsetIndex: 14,
|
||||
contentLength: 7),
|
||||
BuildLineMapping(
|
||||
documentAbsoluteIndex: 122,
|
||||
documentLineIndex: 6,
|
||||
generatedAbsoluteIndex: 903,
|
||||
generatedLineIndex: 49,
|
||||
characterOffsetIndex: 5,
|
||||
contentLength: 2),
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpChunkGeneratorCorrectlyGeneratesMappingsForNullConditionalOperator()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,31 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
|
|||
{
|
||||
public class CSharpBlockTest : CsHtmlCodeParserTestBase
|
||||
{
|
||||
[Fact]
|
||||
public void ParseBlock_NestedCodeBlockWithMarkupSetsDotAsMarkup()
|
||||
{
|
||||
ParseBlockTest("if (true) { @if(false) { <div>@something.</div> } }",
|
||||
new StatementBlock(
|
||||
Factory.Code("if (true) { ").AsStatement(),
|
||||
new StatementBlock(
|
||||
Factory.CodeTransition(),
|
||||
Factory.Code("if(false) {").AsStatement(),
|
||||
new MarkupBlock(
|
||||
Factory.Markup(" "),
|
||||
BlockFactory.MarkupTagBlock("<div>", AcceptedCharacters.None),
|
||||
Factory.EmptyHtml(),
|
||||
new ExpressionBlock(
|
||||
Factory.CodeTransition(),
|
||||
Factory.Code("something")
|
||||
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false)
|
||||
.Accepts(AcceptedCharacters.NonWhiteSpace)),
|
||||
Factory.Markup("."),
|
||||
BlockFactory.MarkupTagBlock("</div>", AcceptedCharacters.None),
|
||||
Factory.Markup(" ").Accepts(AcceptedCharacters.None)),
|
||||
Factory.Code("}").AsStatement()),
|
||||
Factory.Code(" }").AsStatement()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseBlockMethodThrowsArgNullExceptionOnNullContext()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,34 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
|
|||
{
|
||||
private static readonly TestFile Nested1000 = TestFile.Create("TestFiles/nested-1000.html");
|
||||
|
||||
[Fact]
|
||||
public void ParseDocument_NestedCodeBlockWithMarkupSetsDotAsMarkup()
|
||||
{
|
||||
ParseDocumentTest("@if (true) { @if(false) { <div>@something.</div> } }",
|
||||
new MarkupBlock(
|
||||
Factory.EmptyHtml(),
|
||||
new StatementBlock(
|
||||
Factory.CodeTransition(),
|
||||
Factory.Code("if (true) { ").AsStatement(),
|
||||
new StatementBlock(
|
||||
Factory.CodeTransition(),
|
||||
Factory.Code("if(false) {").AsStatement(),
|
||||
new MarkupBlock(
|
||||
Factory.Markup(" "),
|
||||
BlockFactory.MarkupTagBlock("<div>", AcceptedCharacters.None),
|
||||
Factory.EmptyHtml(),
|
||||
new ExpressionBlock(
|
||||
Factory.CodeTransition(),
|
||||
Factory.Code("something")
|
||||
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false)
|
||||
.Accepts(AcceptedCharacters.NonWhiteSpace)),
|
||||
Factory.Markup("."),
|
||||
BlockFactory.MarkupTagBlock("</div>", AcceptedCharacters.None),
|
||||
Factory.Markup(" ").Accepts(AcceptedCharacters.None)),
|
||||
Factory.Code("}").AsStatement()),
|
||||
Factory.Code(" }").AsStatement())));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseDocumentMethodThrowsArgNullExceptionOnNullContext()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
namespace TestOutput
|
||||
{
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class NestedCSharp
|
||||
{
|
||||
private static object @__o;
|
||||
private void @__RazorDesignTimeHelpers__()
|
||||
{
|
||||
#pragma warning disable 219
|
||||
#pragma warning restore 219
|
||||
}
|
||||
#line hidden
|
||||
public NestedCSharp()
|
||||
{
|
||||
}
|
||||
|
||||
#pragma warning disable 1998
|
||||
public override async Task ExecuteAsync()
|
||||
{
|
||||
#line 1 "NestedCSharp.cshtml"
|
||||
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 2 "NestedCSharp.cshtml"
|
||||
foreach (var result in (dynamic)Url)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 5 "NestedCSharp.cshtml"
|
||||
__o = result.SomeValue;
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
#line 6 "NestedCSharp.cshtml"
|
||||
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 7 "NestedCSharp.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
#pragma checksum "NestedCSharp.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "2b9e8dcf7c08153c15ac84973938a7c0254f2369"
|
||||
namespace TestOutput
|
||||
{
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class NestedCSharp
|
||||
{
|
||||
#line hidden
|
||||
public NestedCSharp()
|
||||
{
|
||||
}
|
||||
|
||||
#pragma warning disable 1998
|
||||
public override async Task ExecuteAsync()
|
||||
{
|
||||
#line 1 "NestedCSharp.cshtml"
|
||||
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 2 "NestedCSharp.cshtml"
|
||||
foreach (var result in (dynamic)Url)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
Instrumentation.BeginContext(54, 27, true);
|
||||
WriteLiteral(" <div>\r\n ");
|
||||
Instrumentation.EndContext();
|
||||
Instrumentation.BeginContext(82, 16, false);
|
||||
#line 5 "NestedCSharp.cshtml"
|
||||
Write(result.SomeValue);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
Instrumentation.EndContext();
|
||||
Instrumentation.BeginContext(98, 19, true);
|
||||
WriteLiteral(".\r\n </div>\r\n");
|
||||
Instrumentation.EndContext();
|
||||
#line 7 "NestedCSharp.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 7 "NestedCSharp.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
@{
|
||||
@foreach (var result in (dynamic)Url)
|
||||
{
|
||||
<div>
|
||||
@result.SomeValue.
|
||||
</div>
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue