From 3361507c290a991210932fe25236ce76d4cd1a15 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 14 Aug 2015 10:03:58 -0700 Subject: [PATCH] Remove ability to specify ignored '@' in the middle of non-string TagHelper bound attributes. Fixes #436 --- .../TagHelpers/TagHelperBlockRewriter.cs | 87 ++++-- .../CSharpTagHelperRenderingTest.cs | 248 ++++++++++++++++-- .../TagHelpers/TagHelperBlockRewriterTest.cs | 93 +++++-- .../TagHelperParseTreeRewriterTest.cs | 19 +- .../Output/ComplexTagHelpers.DesignTime.cs | 10 +- .../CodeGenerator/Output/ComplexTagHelpers.cs | 10 +- ...sitionsInTagHelperAttributes.DesignTime.cs | 90 +++++++ .../TransitionsInTagHelperAttributes.cs | 169 ++++++++++++ .../TransitionsInTagHelperAttributes.cshtml | 12 + 9 files changed, 663 insertions(+), 75 deletions(-) create mode 100644 test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.DesignTime.cs create mode 100644 test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.cs create mode 100644 test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/TransitionsInTagHelperAttributes.cshtml diff --git a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs index 5b710f14b9..abfefc23d8 100644 --- a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs +++ b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -271,10 +272,13 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal var result = CreateTryParseResult(name, descriptors); // If we're not after an equal then we should treat the value as if it were a minimized attribute. - var attributeValueBuilder = afterEquals ? builder : null; - result.AttributeValueNode = - CreateMarkupAttribute(attributeValueBuilder, result.IsBoundNonStringAttribute); + Span attributeValue = null; + if (afterEquals) + { + attributeValue = CreateMarkupAttribute(builder, result.IsBoundNonStringAttribute); + } + result.AttributeValueNode = attributeValue; return result; } @@ -362,12 +366,58 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal } } - result.AttributeValueNode = ConvertToMarkupAttributeBlock(block, result.IsBoundNonStringAttribute); + var isFirstSpan = true; + + result.AttributeValueNode = ConvertToMarkupAttributeBlock( + block, + (parentBlock, span) => + { + // If the attribute was requested by a tag helper but the corresponding property was not a + // string, then treat its value as code. A non-string value can be any C# value so we need + // to ensure the SyntaxTreeNode reflects that. + if (result.IsBoundNonStringAttribute) + { + // For bound non-string attributes, we'll only allow a transition span to appear at the very + // beginning of the attribute expression. All later transitions would appear as code so that + // they are part of the generated output. E.g. + // key="@value" -> MyTagHelper.key = value + // key=" @value" -> MyTagHelper.key = @value + // key="1 + @case" -> MyTagHelper.key = 1 + @case + // key="@int + @case" -> MyTagHelper.key = int + @case + // key="@(a + b) -> MyTagHelper.key = a + b + // key="4 + @(a + b)" -> MyTagHelper.key = 4 + @(a + b) + if (isFirstSpan && span.Kind == SpanKind.Transition) + { + // do nothing. + } + else + { + var spanBuilder = new SpanBuilder(span); + + if (parentBlock.Type == BlockType.Expression && + (spanBuilder.Kind == SpanKind.Transition || + spanBuilder.Kind == SpanKind.MetaCode)) + { + // Change to a MarkupChunkGenerator so that the '@' \ parenthesis is generated as part of the output. + spanBuilder.ChunkGenerator = new MarkupChunkGenerator(); + } + + spanBuilder.Kind = SpanKind.Code; + span = spanBuilder.Build(); + } + } + + isFirstSpan = false; + + return span; + }); return result; } - private static Block ConvertToMarkupAttributeBlock(Block block, bool isBoundNonStringAttribute) + private static Block ConvertToMarkupAttributeBlock( + Block block, + Func createMarkupAttribute) { var blockBuilder = new BlockBuilder { @@ -381,12 +431,11 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal if (child.IsBlock) { - markupAttributeChild = ConvertToMarkupAttributeBlock((Block)child, isBoundNonStringAttribute); + markupAttributeChild = ConvertToMarkupAttributeBlock((Block)child, createMarkupAttribute); } else { - var spanBuilder = new SpanBuilder((Span)child); - markupAttributeChild = CreateMarkupAttribute(spanBuilder, isBoundNonStringAttribute); + markupAttributeChild = createMarkupAttribute(block, (Span)child); } blockBuilder.Children.Add(markupAttributeChild); @@ -504,25 +553,19 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal return nodeStart + firstNonWhitespaceSymbol.Start; } - private static SyntaxTreeNode CreateMarkupAttribute(SpanBuilder builder, bool isBoundNonStringAttribute) + private static Span CreateMarkupAttribute(SpanBuilder builder, bool isBoundNonStringAttribute) { - Span value = null; + Debug.Assert(builder != null); - // Builder will be null in the case of minimized attributes - if (builder != null) + // If the attribute was requested by a tag helper but the corresponding property was not a string, + // then treat its value as code. A non-string value can be any C# value so we need to ensure the + // SyntaxTreeNode reflects that. + if (isBoundNonStringAttribute) { - // If the attribute was requested by a tag helper but the corresponding property was not a string, - // then treat its value as code. A non-string value can be any C# value so we need to ensure the - // SyntaxTreeNode reflects that. - if (isBoundNonStringAttribute) - { - builder.Kind = SpanKind.Code; - } - - value = builder.Build(); + builder.Kind = SpanKind.Code; } - return value; + return builder.Build(); } private static bool IsNullOrWhitespaceAttributeValue(SyntaxTreeNode attributeValue) diff --git a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs index 6a3ce59a3f..21e80eea24 100644 --- a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs @@ -405,7 +405,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator get { // Test resource name, baseline resource name, expected TagHelperDescriptors, expected LineMappings - return new TheoryData, List> + return new TheoryData, IList> { { "SingleTagHelper", @@ -622,18 +622,34 @@ namespace Microsoft.AspNet.Razor.Test.Generator characterOffsetIndex: 14, contentLength: 21), BuildLineMapping( - documentAbsoluteIndex: 837, + documentAbsoluteIndex: 836, documentLineIndex: 22, - documentCharacterOffsetIndex: 30, + documentCharacterOffsetIndex: 29, generatedAbsoluteIndex: 3832, generatedLineIndex: 154, generatedCharacterOffsetIndex: 28, + contentLength: 1), + BuildLineMapping( + documentAbsoluteIndex: 837, + documentLineIndex: 22, + documentCharacterOffsetIndex: 30, + generatedAbsoluteIndex: 3833, + generatedLineIndex: 154, + generatedCharacterOffsetIndex: 29, contentLength: 7), + BuildLineMapping( + documentAbsoluteIndex: 844, + documentLineIndex: 22, + documentCharacterOffsetIndex: 37, + generatedAbsoluteIndex: 3840, + generatedLineIndex: 154, + generatedCharacterOffsetIndex: 36, + contentLength: 1), BuildLineMapping( documentAbsoluteIndex: 711, documentLineIndex: 20, documentCharacterOffsetIndex: 39, - generatedAbsoluteIndex: 4007, + generatedAbsoluteIndex: 4009, generatedLineIndex: 160, generatedCharacterOffsetIndex: 38, contentLength: 23), @@ -641,38 +657,62 @@ namespace Microsoft.AspNet.Razor.Test.Generator documentAbsoluteIndex: 734, documentLineIndex: 20, documentCharacterOffsetIndex: 62, - generatedAbsoluteIndex: 4030, + generatedAbsoluteIndex: 4032, generatedLineIndex: 160, generatedCharacterOffsetIndex: 61, contentLength: 7), + BuildLineMapping( + documentAbsoluteIndex: 976, + documentLineIndex: 25, + documentCharacterOffsetIndex: 61, + generatedAbsoluteIndex: 4306, + generatedLineIndex: 167, + generatedCharacterOffsetIndex: 60, + contentLength: 1), BuildLineMapping( documentAbsoluteIndex: 977, documentLineIndex: 25, documentCharacterOffsetIndex: 62, - generatedAbsoluteIndex: 4304, + generatedAbsoluteIndex: 4307, generatedLineIndex: 167, - generatedCharacterOffsetIndex: 60, + generatedCharacterOffsetIndex: 61, contentLength: 30), + BuildLineMapping( + documentAbsoluteIndex: 1007, + documentLineIndex: 25, + documentCharacterOffsetIndex: 92, + generatedAbsoluteIndex: 4337, + generatedLineIndex: 167, + generatedCharacterOffsetIndex: 91, + contentLength: 1), BuildLineMapping( documentAbsoluteIndex: 879, documentLineIndex: 24, documentCharacterOffsetIndex: 16, - generatedAbsoluteIndex: 4483, + generatedAbsoluteIndex: 4487, generatedLineIndex: 173, generatedCharacterOffsetIndex: 19, contentLength: 8), + BuildLineMapping( + documentAbsoluteIndex: 887, + documentLineIndex: 24, + documentCharacterOffsetIndex: 24, + generatedAbsoluteIndex: 4495, + generatedLineIndex: 173, + generatedCharacterOffsetIndex: 27, + contentLength: 1), BuildLineMapping( documentAbsoluteIndex: 888, documentLineIndex: 24, documentCharacterOffsetIndex: 25, - generatedAbsoluteIndex: 4491, + generatedAbsoluteIndex: 4496, generatedLineIndex: 173, - generatedCharacterOffsetIndex: 27, + generatedCharacterOffsetIndex: 28, contentLength: 23), BuildLineMapping( documentAbsoluteIndex: 1106, documentLineIndex: 28, - generatedAbsoluteIndex: 4749, + generatedAbsoluteIndex: 4754, generatedLineIndex: 180, characterOffsetIndex: 28, contentLength: 30), @@ -680,45 +720,73 @@ namespace Microsoft.AspNet.Razor.Test.Generator documentAbsoluteIndex: 1044, documentLineIndex: 27, documentCharacterOffsetIndex: 16, - generatedAbsoluteIndex: 4928, + generatedAbsoluteIndex: 4933, generatedLineIndex: 186, generatedCharacterOffsetIndex: 19, contentLength: 30), BuildLineMapping( documentAbsoluteIndex: 1234, documentLineIndex: 31, - generatedAbsoluteIndex: 5193, + generatedAbsoluteIndex: 5198, generatedLineIndex: 193, characterOffsetIndex: 28, contentLength: 3), + BuildLineMapping( + documentAbsoluteIndex: 1237, + documentLineIndex: 31, + generatedAbsoluteIndex: 5201, + generatedLineIndex: 193, + characterOffsetIndex: 31, + contentLength: 2), BuildLineMapping( documentAbsoluteIndex: 1239, documentLineIndex: 31, - documentCharacterOffsetIndex: 33, - generatedAbsoluteIndex: 5196, + generatedAbsoluteIndex: 5203, generatedLineIndex: 193, - generatedCharacterOffsetIndex: 31, + characterOffsetIndex: 33, contentLength: 27), + BuildLineMapping( + documentAbsoluteIndex: 1266, + documentLineIndex: 31, + generatedAbsoluteIndex: 5230, + generatedLineIndex: 193, + characterOffsetIndex: 60, + contentLength: 1), BuildLineMapping( documentAbsoluteIndex: 1267, documentLineIndex: 31, - documentCharacterOffsetIndex: 61, - generatedAbsoluteIndex: 5223, + generatedAbsoluteIndex: 5231, generatedLineIndex: 193, - generatedCharacterOffsetIndex: 58, + characterOffsetIndex: 61, contentLength: 10), + BuildLineMapping( + documentAbsoluteIndex: 1171, + documentLineIndex: 30, + documentCharacterOffsetIndex: 17, + generatedAbsoluteIndex: 5390, + generatedLineIndex: 199, + generatedCharacterOffsetIndex: 19, + contentLength: 1), BuildLineMapping( documentAbsoluteIndex: 1172, documentLineIndex: 30, documentCharacterOffsetIndex: 18, - generatedAbsoluteIndex: 5382, + generatedAbsoluteIndex: 5391, generatedLineIndex: 199, - generatedCharacterOffsetIndex: 19, + generatedCharacterOffsetIndex: 20, contentLength: 29), + BuildLineMapping( + documentAbsoluteIndex: 1201, + documentLineIndex: 30, + documentCharacterOffsetIndex: 47, + generatedAbsoluteIndex: 5420, + generatedLineIndex: 199, + generatedCharacterOffsetIndex: 49, + contentLength: 1), BuildLineMapping( documentAbsoluteIndex: 1309, documentLineIndex: 34, - generatedAbsoluteIndex: 5482, + generatedAbsoluteIndex: 5492, generatedLineIndex: 204, characterOffsetIndex: 0, contentLength: 1), @@ -1204,6 +1272,139 @@ namespace Microsoft.AspNet.Razor.Test.Generator contentLength: 2), } }, + { + "TransitionsInTagHelperAttributes", + "TransitionsInTagHelperAttributes.DesignTime", + DefaultPAndInputTagHelperDescriptors, + new[] + { + BuildLineMapping( + documentAbsoluteIndex: 14, + documentLineIndex: 0, + generatedAbsoluteIndex: 509, + generatedLineIndex: 15, + characterOffsetIndex: 14, + contentLength: 17), + BuildLineMapping( + documentAbsoluteIndex: 35, + documentLineIndex: 1, + generatedAbsoluteIndex: 947, + generatedLineIndex: 33, + characterOffsetIndex: 2, + contentLength: 59), + BuildLineMapping( + documentAbsoluteIndex: 122, + documentLineIndex: 6, + generatedAbsoluteIndex: 1172, + generatedLineIndex: 42, + characterOffsetIndex: 23, + contentLength: 4), + BuildLineMapping( + documentAbsoluteIndex: 157, + documentLineIndex: 7, + documentCharacterOffsetIndex: 12, + generatedAbsoluteIndex: 1326, + generatedLineIndex: 48, + generatedCharacterOffsetIndex: 6, + contentLength: 6), + BuildLineMapping( + documentAbsoluteIndex: 171, + documentLineIndex: 7, + generatedAbsoluteIndex: 1443, + generatedLineIndex: 53, + characterOffsetIndex: 26, + contentLength: 2), + BuildLineMapping( + documentAbsoluteIndex: 202, + documentLineIndex: 8, + generatedAbsoluteIndex: 1610, + generatedLineIndex: 59, + characterOffsetIndex: 21, + contentLength: 5), + BuildLineMapping( + documentAbsoluteIndex: 207, + documentLineIndex: 8, + generatedAbsoluteIndex: 1615, + generatedLineIndex: 59, + characterOffsetIndex: 26, + contentLength: 1), + BuildLineMapping( + documentAbsoluteIndex: 208, + documentLineIndex: 8, + generatedAbsoluteIndex: 1616, + generatedLineIndex: 59, + characterOffsetIndex: 27, + contentLength: 3), + BuildLineMapping( + documentAbsoluteIndex: 241, + documentLineIndex: 9, + documentCharacterOffsetIndex: 22, + generatedAbsoluteIndex: 1785, + generatedLineIndex: 65, + generatedCharacterOffsetIndex: 21, + contentLength: 3), + BuildLineMapping( + documentAbsoluteIndex: 274, + documentLineIndex: 10, + documentCharacterOffsetIndex: 22, + generatedAbsoluteIndex: 1954, + generatedLineIndex: 71, + generatedCharacterOffsetIndex: 21, + contentLength: 1), + BuildLineMapping( + documentAbsoluteIndex: 275, + documentLineIndex: 10, + documentCharacterOffsetIndex: 23, + generatedAbsoluteIndex: 1955, + generatedLineIndex: 71, + generatedCharacterOffsetIndex: 22, + contentLength: 4), + BuildLineMapping( + documentAbsoluteIndex: 279, + documentLineIndex: 10, + documentCharacterOffsetIndex: 27, + generatedAbsoluteIndex: 1959, + generatedLineIndex: 71, + generatedCharacterOffsetIndex: 26, + contentLength: 1), + BuildLineMapping( + documentAbsoluteIndex: 307, + documentLineIndex: 11, + documentCharacterOffsetIndex: 19, + generatedAbsoluteIndex: 2111, + generatedLineIndex: 77, + generatedCharacterOffsetIndex: 6, + contentLength: 6), + BuildLineMapping( + documentAbsoluteIndex: 321, + documentLineIndex: 11, + generatedAbsoluteIndex: 2236, + generatedLineIndex: 82, + characterOffsetIndex: 33, + contentLength: 4), + BuildLineMapping( + documentAbsoluteIndex: 325, + documentLineIndex: 11, + generatedAbsoluteIndex: 2240, + generatedLineIndex: 82, + characterOffsetIndex: 37, + contentLength: 2), + BuildLineMapping( + documentAbsoluteIndex: 327, + documentLineIndex: 11, + generatedAbsoluteIndex: 2242, + generatedLineIndex: 82, + characterOffsetIndex: 39, + contentLength: 8), + BuildLineMapping( + documentAbsoluteIndex: 335, + documentLineIndex: 11, + generatedAbsoluteIndex: 2250, + generatedLineIndex: 82, + characterOffsetIndex: 47, + contentLength: 1), + } + }, }; } } @@ -1213,7 +1414,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator public void TagHelpers_GenerateExpectedDesignTimeOutput(string testName, string baseLineName, IEnumerable tagHelperDescriptors, - List expectedDesignTimePragmas) + IList expectedDesignTimePragmas) { // Act & Assert RunTagHelperTest(testName, @@ -1248,6 +1449,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator }, { "DuplicateAttributeTagHelpers", null, DefaultPAndInputTagHelperDescriptors }, { "DynamicAttributeTagHelpers", null, DynamicAttributeTagHelpers_Descriptors }, + { "TransitionsInTagHelperAttributes", null, DefaultPAndInputTagHelperDescriptors } }; } } diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs index 908fa4140f..aba10bf28b 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs @@ -782,6 +782,48 @@ namespace Microsoft.AspNet.Razor.TagHelpers factory.CodeMarkup("DateTime.Now")) })) }, + { + "", + new MarkupBlock( + new MarkupTagHelperBlock("person", + TagMode.SelfClosing, + attributes: new List> + { + new KeyValuePair( + "age", + new MarkupBlock( + new MarkupBlock( + new ExpressionBlock( + factory.CodeTransition(), + factory + .Code("DateTime.Now.Year") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))))) + })) + }, + { + "", + new MarkupBlock( + new MarkupTagHelperBlock("person", + TagMode.SelfClosing, + attributes: new List> + { + new KeyValuePair( + "age", + new MarkupBlock( + new MarkupBlock( + factory.CodeMarkup(" "), + new ExpressionBlock( + factory + .CodeTransition() + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()), + factory + .Code("DateTime.Now.Year") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))))) + })) + }, { "", new MarkupBlock( @@ -819,7 +861,10 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupBlock( factory.CodeMarkup(" "), new ExpressionBlock( - factory.CodeTransition().As(SpanKind.Code), + factory + .CodeTransition() + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()), factory .Code("value") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) @@ -832,7 +877,10 @@ namespace Microsoft.AspNet.Razor.TagHelpers factory.CodeMarkup("(bool)"), new MarkupBlock( new ExpressionBlock( - factory.CodeTransition().As(SpanKind.Code), + factory + .CodeTransition() + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()), factory .Code("Bag[\"val\"]") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) @@ -848,11 +896,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupBlock( factory.CodeMarkup(" "), new ExpressionBlock( - factory.CodeTransition().As(SpanKind.Code), - factory - .Code("DateTime.Now") - .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) - .Accepts(AcceptedCharacters.NonWhiteSpace))) + factory + .CodeTransition() + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()), + factory + .Code("DateTime.Now") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))) )) })) }, @@ -928,21 +979,27 @@ namespace Microsoft.AspNet.Razor.TagHelpers "age", new MarkupBlock( new MarkupBlock( - factory.CodeMarkup("@").Accepts(AcceptedCharacters.None), + factory.CodeMarkup("@") + .Accepts(AcceptedCharacters.None) + .With(new MarkupChunkGenerator()), factory.CodeMarkup("@") .With(SpanChunkGenerator.Null) .Accepts(AcceptedCharacters.None)), new MarkupBlock( factory.EmptyHtml().As(SpanKind.Code), new ExpressionBlock( - factory.CodeTransition().As(SpanKind.Code), + factory.CodeTransition() + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()), factory.MetaCode("(") .Accepts(AcceptedCharacters.None) - .As(SpanKind.Code), + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()), factory.Code("11+1").AsExpression(), factory.MetaCode(")") .Accepts(AcceptedCharacters.None) - .As(SpanKind.Code))))), + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()))))), new KeyValuePair( "birthday", factory.CodeMarkup("DateTime.Now")), @@ -1950,7 +2007,9 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupBlock( factory.CodeMarkup(" "), new ExpressionBlock( - factory.CodeTransition().As(SpanKind.Code), + factory.CodeTransition() + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()), factory.Code("true") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace))), @@ -1974,14 +2033,18 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupBlock( factory.CodeMarkup(" "), new ExpressionBlock( - factory.CodeTransition().As(SpanKind.Code), + factory.CodeTransition() + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()), factory.MetaCode("(") .Accepts(AcceptedCharacters.None) - .As(SpanKind.Code), + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()), factory.Code("true").AsExpression(), factory.MetaCode(")") .Accepts(AcceptedCharacters.None) - .As(SpanKind.Code))), + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()))), factory.CodeMarkup(" "))) } })), diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs index 6437a49070..b9872db90e 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs @@ -1254,7 +1254,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupBlock( new ExpressionBlock( - factory.CodeTransition().As(SpanKind.Code), + factory.CodeTransition(), factory.Code("DateTime.Now") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace))))) @@ -1276,7 +1276,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupBlock( new ExpressionBlock( - factory.CodeTransition().As(SpanKind.Code), + factory.CodeTransition(), factory.Code("DateTime.Now") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace))))) @@ -1297,12 +1297,21 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "bound", new MarkupBlock( new MarkupBlock( - factory.CodeMarkup("@").Accepts(AcceptedCharacters.None), - factory.CodeMarkup("@").With(SpanChunkGenerator.Null).Accepts(AcceptedCharacters.None)), + factory + .CodeMarkup("@") + .With(new MarkupChunkGenerator()) + .Accepts(AcceptedCharacters.None), + factory + .CodeMarkup("@") + .With(SpanChunkGenerator.Null) + .Accepts(AcceptedCharacters.None)), new MarkupBlock( factory.EmptyHtml().As(SpanKind.Code), new ExpressionBlock( - factory.CodeTransition().As(SpanKind.Code), + factory + .CodeTransition() + .As(SpanKind.Code) + .With(new MarkupChunkGenerator()), factory.Code("DateTime.Now") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace))))) diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.DesignTime.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.DesignTime.cs index dfcdb0e3f3..c30f8a8474 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.DesignTime.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.DesignTime.cs @@ -152,7 +152,7 @@ __o = DateTime.Now; __InputTagHelper = CreateTagHelper(); __InputTagHelper2 = CreateTagHelper(); #line 23 "ComplexTagHelpers.cshtml" -__InputTagHelper2.Checked = @object; +__InputTagHelper2.Checked = (@object); #line default #line hidden @@ -165,13 +165,13 @@ __InputTagHelper2.Checked = @object; __InputTagHelper = CreateTagHelper(); __InputTagHelper2 = CreateTagHelper(); #line 26 "ComplexTagHelpers.cshtml" - __InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014; + __InputTagHelper2.Checked = (DateTimeOffset.Now.Year > 2014); #line default #line hidden __PTagHelper = CreateTagHelper(); #line 25 "ComplexTagHelpers.cshtml" -__PTagHelper.Age = -1970 + DateTimeOffset.Now.Year; +__PTagHelper.Age = -1970 + @DateTimeOffset.Now.Year; #line default #line hidden @@ -191,13 +191,13 @@ __PTagHelper.Age = DateTimeOffset.Now.Year - 1970; __InputTagHelper = CreateTagHelper(); __InputTagHelper2 = CreateTagHelper(); #line 32 "ComplexTagHelpers.cshtml" -__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014 ; +__InputTagHelper2.Checked = @( DateTimeOffset.Now.Year ) > 2014 ; #line default #line hidden __PTagHelper = CreateTagHelper(); #line 31 "ComplexTagHelpers.cshtml" -__PTagHelper.Age = "My age is this long.".Length; +__PTagHelper.Age = ("My age is this long.".Length); #line default #line hidden diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.cs index ec820ef688..9a2d7ceb36 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.cs @@ -276,7 +276,7 @@ if(true) { __InputTagHelper2 = CreateTagHelper(); __tagHelperExecutionContext.Add(__InputTagHelper2); #line 23 "ComplexTagHelpers.cshtml" -__InputTagHelper2.Checked = @object; +__InputTagHelper2.Checked = (@object); #line default #line hidden @@ -323,7 +323,7 @@ __InputTagHelper2.Checked = @object; __tagHelperExecutionContext.AddHtmlAttribute("unbound", Html.Raw("hello")); __tagHelperExecutionContext.AddHtmlAttribute("unbound", Html.Raw("world")); #line 26 "ComplexTagHelpers.cshtml" - __InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014; + __InputTagHelper2.Checked = (DateTimeOffset.Now.Year > 2014); #line default #line hidden @@ -341,7 +341,7 @@ __InputTagHelper2.Checked = @object; __PTagHelper = CreateTagHelper(); __tagHelperExecutionContext.Add(__PTagHelper); #line 25 "ComplexTagHelpers.cshtml" -__PTagHelper.Age = -1970 + DateTimeOffset.Now.Year; +__PTagHelper.Age = -1970 + @DateTimeOffset.Now.Year; #line default #line hidden @@ -409,7 +409,7 @@ __PTagHelper.Age = DateTimeOffset.Now.Year - 1970; __InputTagHelper2 = CreateTagHelper(); __tagHelperExecutionContext.Add(__InputTagHelper2); #line 32 "ComplexTagHelpers.cshtml" -__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014 ; +__InputTagHelper2.Checked = @( DateTimeOffset.Now.Year ) > 2014 ; #line default #line hidden @@ -427,7 +427,7 @@ __InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014 ; __PTagHelper = CreateTagHelper(); __tagHelperExecutionContext.Add(__PTagHelper); #line 31 "ComplexTagHelpers.cshtml" -__PTagHelper.Age = "My age is this long.".Length; +__PTagHelper.Age = ("My age is this long.".Length); #line default #line hidden diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.DesignTime.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.DesignTime.cs new file mode 100644 index 0000000000..3325164f6d --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.DesignTime.cs @@ -0,0 +1,90 @@ +namespace TestOutput +{ + using Microsoft.AspNet.Razor.Runtime.TagHelpers; + using System; + using System.Threading.Tasks; + + public class TransitionsInTagHelperAttributes + { + private static object @__o; + private void @__RazorDesignTimeHelpers__() + { + #pragma warning disable 219 + string __tagHelperDirectiveSyntaxHelper = null; + __tagHelperDirectiveSyntaxHelper = +#line 1 "TransitionsInTagHelperAttributes.cshtml" + "something, nice" + +#line default +#line hidden + ; + #pragma warning restore 219 + } + #line hidden + private PTagHelper __PTagHelper = null; + #line hidden + public TransitionsInTagHelperAttributes() + { + } + + #pragma warning disable 1998 + public override async Task ExecuteAsync() + { +#line 2 "TransitionsInTagHelperAttributes.cshtml" + + var @class = "container-fluid"; + var @int = 1; + +#line default +#line hidden + + __PTagHelper = CreateTagHelper(); +#line 7 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = 1337; + +#line default +#line hidden + __PTagHelper = CreateTagHelper(); +#line 8 "TransitionsInTagHelperAttributes.cshtml" +__o = @class; + +#line default +#line hidden +#line 8 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = 42; + +#line default +#line hidden + __PTagHelper = CreateTagHelper(); +#line 9 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = 42 + @int; + +#line default +#line hidden + __PTagHelper = CreateTagHelper(); +#line 10 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = int; + +#line default +#line hidden + __PTagHelper = CreateTagHelper(); +#line 11 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = (@int); + +#line default +#line hidden + __PTagHelper = CreateTagHelper(); +#line 12 "TransitionsInTagHelperAttributes.cshtml" +__o = @class; + +#line default +#line hidden +#line 12 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = 4 * @(@int + 2); + +#line default +#line hidden + } + #pragma warning restore 1998 + } +} diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.cs new file mode 100644 index 0000000000..251e3d06de --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.cs @@ -0,0 +1,169 @@ +#pragma checksum "TransitionsInTagHelperAttributes.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "050ce5cabf326eaa117aa12f5a1a10dbf82a8917" +namespace TestOutput +{ + using Microsoft.AspNet.Razor.Runtime.TagHelpers; + using System; + using System.Threading.Tasks; + + public class TransitionsInTagHelperAttributes + { + #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 TransitionsInTagHelperAttributes() + { + } + + #pragma warning disable 1998 + public override async Task ExecuteAsync() + { + __tagHelperRunner = __tagHelperRunner ?? new TagHelperRunner(); +#line 2 "TransitionsInTagHelperAttributes.cshtml" + + var @class = "container-fluid"; + var @int = 1; + +#line default +#line hidden + + Instrumentation.BeginContext(95, 4, true); + WriteLiteral("\r\n\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", TagMode.StartTagAndEndTag, "test", async() => { + Instrumentation.BeginContext(128, 11, true); + WriteLiteral("Body of Tag"); + Instrumentation.EndContext(); + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __PTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__PTagHelper); + AddHtmlAttributeValues("class", __tagHelperExecutionContext, + Tuple.Create(Tuple.Create("", 109), Tuple.Create(new Template((__razor_attribute_value_writer) => { + } + ), 109), false)); +#line 7 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = 1337; + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(99, 44, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(143, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", TagMode.StartTagAndEndTag, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __PTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__PTagHelper); + AddHtmlAttributeValues("class", __tagHelperExecutionContext, + Tuple.Create(Tuple.Create("", 155), Tuple.Create(@class, 155), false)); +#line 8 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = 42; + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(145, 34, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(179, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", TagMode.StartTagAndEndTag, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __PTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__PTagHelper); + __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw("test")); +#line 9 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = 42 + @int; + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(181, 36, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(217, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", TagMode.StartTagAndEndTag, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __PTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__PTagHelper); + __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw("test")); +#line 10 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = int; + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(219, 31, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(250, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", TagMode.StartTagAndEndTag, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __PTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__PTagHelper); + __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw("test")); +#line 11 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = (@int); + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(252, 34, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(286, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", TagMode.StartTagAndEndTag, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __PTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__PTagHelper); + AddHtmlAttributeValues("class", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 298), Tuple.Create("custom-", 298), true), + Tuple.Create(Tuple.Create("", 305), Tuple.Create(@class, 305), false)); +#line 12 "TransitionsInTagHelperAttributes.cshtml" + __PTagHelper.Age = 4 * @(@int + 2); + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(288, 54, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(342, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + } + #pragma warning restore 1998 + } +} diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/TransitionsInTagHelperAttributes.cshtml b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/TransitionsInTagHelperAttributes.cshtml new file mode 100644 index 0000000000..255dec901b --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/TransitionsInTagHelperAttributes.cshtml @@ -0,0 +1,12 @@ +@addTagHelper "something, nice" +@{ + var @class = "container-fluid"; + var @int = 1; +} + +

Body of Tag

+

+

+

+

+