Remove ability to specify ignored '@' in the middle of non-string

TagHelper bound attributes.

Fixes #436
This commit is contained in:
Pranav K 2015-08-14 10:03:58 -07:00
parent 156f859edc
commit 3361507c29
9 changed files with 663 additions and 75 deletions

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -271,10 +272,13 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
var result = CreateTryParseResult(name, descriptors); 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. // 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; Span attributeValue = null;
result.AttributeValueNode = if (afterEquals)
CreateMarkupAttribute(attributeValueBuilder, result.IsBoundNonStringAttribute); {
attributeValue = CreateMarkupAttribute(builder, result.IsBoundNonStringAttribute);
}
result.AttributeValueNode = attributeValue;
return result; 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; return result;
} }
private static Block ConvertToMarkupAttributeBlock(Block block, bool isBoundNonStringAttribute) private static Block ConvertToMarkupAttributeBlock(
Block block,
Func<Block, Span, Span> createMarkupAttribute)
{ {
var blockBuilder = new BlockBuilder var blockBuilder = new BlockBuilder
{ {
@ -381,12 +431,11 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
if (child.IsBlock) if (child.IsBlock)
{ {
markupAttributeChild = ConvertToMarkupAttributeBlock((Block)child, isBoundNonStringAttribute); markupAttributeChild = ConvertToMarkupAttributeBlock((Block)child, createMarkupAttribute);
} }
else else
{ {
var spanBuilder = new SpanBuilder((Span)child); markupAttributeChild = createMarkupAttribute(block, (Span)child);
markupAttributeChild = CreateMarkupAttribute(spanBuilder, isBoundNonStringAttribute);
} }
blockBuilder.Children.Add(markupAttributeChild); blockBuilder.Children.Add(markupAttributeChild);
@ -504,25 +553,19 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
return nodeStart + firstNonWhitespaceSymbol.Start; 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 the attribute was requested by a tag helper but the corresponding property was not a string,
if (builder != null) // 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, builder.Kind = SpanKind.Code;
// 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();
} }
return value; return builder.Build();
} }
private static bool IsNullOrWhitespaceAttributeValue(SyntaxTreeNode attributeValue) private static bool IsNullOrWhitespaceAttributeValue(SyntaxTreeNode attributeValue)

View File

@ -405,7 +405,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
get get
{ {
// Test resource name, baseline resource name, expected TagHelperDescriptors, expected LineMappings // Test resource name, baseline resource name, expected TagHelperDescriptors, expected LineMappings
return new TheoryData<string, string, IEnumerable<TagHelperDescriptor>, List<LineMapping>> return new TheoryData<string, string, IEnumerable<TagHelperDescriptor>, IList<LineMapping>>
{ {
{ {
"SingleTagHelper", "SingleTagHelper",
@ -622,18 +622,34 @@ namespace Microsoft.AspNet.Razor.Test.Generator
characterOffsetIndex: 14, characterOffsetIndex: 14,
contentLength: 21), contentLength: 21),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 837, documentAbsoluteIndex: 836,
documentLineIndex: 22, documentLineIndex: 22,
documentCharacterOffsetIndex: 30, documentCharacterOffsetIndex: 29,
generatedAbsoluteIndex: 3832, generatedAbsoluteIndex: 3832,
generatedLineIndex: 154, generatedLineIndex: 154,
generatedCharacterOffsetIndex: 28, generatedCharacterOffsetIndex: 28,
contentLength: 1),
BuildLineMapping(
documentAbsoluteIndex: 837,
documentLineIndex: 22,
documentCharacterOffsetIndex: 30,
generatedAbsoluteIndex: 3833,
generatedLineIndex: 154,
generatedCharacterOffsetIndex: 29,
contentLength: 7), contentLength: 7),
BuildLineMapping(
documentAbsoluteIndex: 844,
documentLineIndex: 22,
documentCharacterOffsetIndex: 37,
generatedAbsoluteIndex: 3840,
generatedLineIndex: 154,
generatedCharacterOffsetIndex: 36,
contentLength: 1),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 711, documentAbsoluteIndex: 711,
documentLineIndex: 20, documentLineIndex: 20,
documentCharacterOffsetIndex: 39, documentCharacterOffsetIndex: 39,
generatedAbsoluteIndex: 4007, generatedAbsoluteIndex: 4009,
generatedLineIndex: 160, generatedLineIndex: 160,
generatedCharacterOffsetIndex: 38, generatedCharacterOffsetIndex: 38,
contentLength: 23), contentLength: 23),
@ -641,38 +657,62 @@ namespace Microsoft.AspNet.Razor.Test.Generator
documentAbsoluteIndex: 734, documentAbsoluteIndex: 734,
documentLineIndex: 20, documentLineIndex: 20,
documentCharacterOffsetIndex: 62, documentCharacterOffsetIndex: 62,
generatedAbsoluteIndex: 4030, generatedAbsoluteIndex: 4032,
generatedLineIndex: 160, generatedLineIndex: 160,
generatedCharacterOffsetIndex: 61, generatedCharacterOffsetIndex: 61,
contentLength: 7), contentLength: 7),
BuildLineMapping(
documentAbsoluteIndex: 976,
documentLineIndex: 25,
documentCharacterOffsetIndex: 61,
generatedAbsoluteIndex: 4306,
generatedLineIndex: 167,
generatedCharacterOffsetIndex: 60,
contentLength: 1),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 977, documentAbsoluteIndex: 977,
documentLineIndex: 25, documentLineIndex: 25,
documentCharacterOffsetIndex: 62, documentCharacterOffsetIndex: 62,
generatedAbsoluteIndex: 4304, generatedAbsoluteIndex: 4307,
generatedLineIndex: 167, generatedLineIndex: 167,
generatedCharacterOffsetIndex: 60, generatedCharacterOffsetIndex: 61,
contentLength: 30), contentLength: 30),
BuildLineMapping(
documentAbsoluteIndex: 1007,
documentLineIndex: 25,
documentCharacterOffsetIndex: 92,
generatedAbsoluteIndex: 4337,
generatedLineIndex: 167,
generatedCharacterOffsetIndex: 91,
contentLength: 1),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 879, documentAbsoluteIndex: 879,
documentLineIndex: 24, documentLineIndex: 24,
documentCharacterOffsetIndex: 16, documentCharacterOffsetIndex: 16,
generatedAbsoluteIndex: 4483, generatedAbsoluteIndex: 4487,
generatedLineIndex: 173, generatedLineIndex: 173,
generatedCharacterOffsetIndex: 19, generatedCharacterOffsetIndex: 19,
contentLength: 8), contentLength: 8),
BuildLineMapping(
documentAbsoluteIndex: 887,
documentLineIndex: 24,
documentCharacterOffsetIndex: 24,
generatedAbsoluteIndex: 4495,
generatedLineIndex: 173,
generatedCharacterOffsetIndex: 27,
contentLength: 1),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 888, documentAbsoluteIndex: 888,
documentLineIndex: 24, documentLineIndex: 24,
documentCharacterOffsetIndex: 25, documentCharacterOffsetIndex: 25,
generatedAbsoluteIndex: 4491, generatedAbsoluteIndex: 4496,
generatedLineIndex: 173, generatedLineIndex: 173,
generatedCharacterOffsetIndex: 27, generatedCharacterOffsetIndex: 28,
contentLength: 23), contentLength: 23),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 1106, documentAbsoluteIndex: 1106,
documentLineIndex: 28, documentLineIndex: 28,
generatedAbsoluteIndex: 4749, generatedAbsoluteIndex: 4754,
generatedLineIndex: 180, generatedLineIndex: 180,
characterOffsetIndex: 28, characterOffsetIndex: 28,
contentLength: 30), contentLength: 30),
@ -680,45 +720,73 @@ namespace Microsoft.AspNet.Razor.Test.Generator
documentAbsoluteIndex: 1044, documentAbsoluteIndex: 1044,
documentLineIndex: 27, documentLineIndex: 27,
documentCharacterOffsetIndex: 16, documentCharacterOffsetIndex: 16,
generatedAbsoluteIndex: 4928, generatedAbsoluteIndex: 4933,
generatedLineIndex: 186, generatedLineIndex: 186,
generatedCharacterOffsetIndex: 19, generatedCharacterOffsetIndex: 19,
contentLength: 30), contentLength: 30),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 1234, documentAbsoluteIndex: 1234,
documentLineIndex: 31, documentLineIndex: 31,
generatedAbsoluteIndex: 5193, generatedAbsoluteIndex: 5198,
generatedLineIndex: 193, generatedLineIndex: 193,
characterOffsetIndex: 28, characterOffsetIndex: 28,
contentLength: 3), contentLength: 3),
BuildLineMapping(
documentAbsoluteIndex: 1237,
documentLineIndex: 31,
generatedAbsoluteIndex: 5201,
generatedLineIndex: 193,
characterOffsetIndex: 31,
contentLength: 2),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 1239, documentAbsoluteIndex: 1239,
documentLineIndex: 31, documentLineIndex: 31,
documentCharacterOffsetIndex: 33, generatedAbsoluteIndex: 5203,
generatedAbsoluteIndex: 5196,
generatedLineIndex: 193, generatedLineIndex: 193,
generatedCharacterOffsetIndex: 31, characterOffsetIndex: 33,
contentLength: 27), contentLength: 27),
BuildLineMapping(
documentAbsoluteIndex: 1266,
documentLineIndex: 31,
generatedAbsoluteIndex: 5230,
generatedLineIndex: 193,
characterOffsetIndex: 60,
contentLength: 1),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 1267, documentAbsoluteIndex: 1267,
documentLineIndex: 31, documentLineIndex: 31,
documentCharacterOffsetIndex: 61, generatedAbsoluteIndex: 5231,
generatedAbsoluteIndex: 5223,
generatedLineIndex: 193, generatedLineIndex: 193,
generatedCharacterOffsetIndex: 58, characterOffsetIndex: 61,
contentLength: 10), contentLength: 10),
BuildLineMapping(
documentAbsoluteIndex: 1171,
documentLineIndex: 30,
documentCharacterOffsetIndex: 17,
generatedAbsoluteIndex: 5390,
generatedLineIndex: 199,
generatedCharacterOffsetIndex: 19,
contentLength: 1),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 1172, documentAbsoluteIndex: 1172,
documentLineIndex: 30, documentLineIndex: 30,
documentCharacterOffsetIndex: 18, documentCharacterOffsetIndex: 18,
generatedAbsoluteIndex: 5382, generatedAbsoluteIndex: 5391,
generatedLineIndex: 199, generatedLineIndex: 199,
generatedCharacterOffsetIndex: 19, generatedCharacterOffsetIndex: 20,
contentLength: 29), contentLength: 29),
BuildLineMapping(
documentAbsoluteIndex: 1201,
documentLineIndex: 30,
documentCharacterOffsetIndex: 47,
generatedAbsoluteIndex: 5420,
generatedLineIndex: 199,
generatedCharacterOffsetIndex: 49,
contentLength: 1),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 1309, documentAbsoluteIndex: 1309,
documentLineIndex: 34, documentLineIndex: 34,
generatedAbsoluteIndex: 5482, generatedAbsoluteIndex: 5492,
generatedLineIndex: 204, generatedLineIndex: 204,
characterOffsetIndex: 0, characterOffsetIndex: 0,
contentLength: 1), contentLength: 1),
@ -1204,6 +1272,139 @@ namespace Microsoft.AspNet.Razor.Test.Generator
contentLength: 2), 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, public void TagHelpers_GenerateExpectedDesignTimeOutput(string testName,
string baseLineName, string baseLineName,
IEnumerable<TagHelperDescriptor> tagHelperDescriptors, IEnumerable<TagHelperDescriptor> tagHelperDescriptors,
List<LineMapping> expectedDesignTimePragmas) IList<LineMapping> expectedDesignTimePragmas)
{ {
// Act & Assert // Act & Assert
RunTagHelperTest(testName, RunTagHelperTest(testName,
@ -1248,6 +1449,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
}, },
{ "DuplicateAttributeTagHelpers", null, DefaultPAndInputTagHelperDescriptors }, { "DuplicateAttributeTagHelpers", null, DefaultPAndInputTagHelperDescriptors },
{ "DynamicAttributeTagHelpers", null, DynamicAttributeTagHelpers_Descriptors }, { "DynamicAttributeTagHelpers", null, DynamicAttributeTagHelpers_Descriptors },
{ "TransitionsInTagHelperAttributes", null, DefaultPAndInputTagHelperDescriptors }
}; };
} }
} }

View File

@ -782,6 +782,48 @@ namespace Microsoft.AspNet.Razor.TagHelpers
factory.CodeMarkup("DateTime.Now")) factory.CodeMarkup("DateTime.Now"))
})) }))
}, },
{
"<person age=\"@DateTime.Now.Year\" />",
new MarkupBlock(
new MarkupTagHelperBlock("person",
TagMode.SelfClosing,
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>(
"age",
new MarkupBlock(
new MarkupBlock(
new ExpressionBlock(
factory.CodeTransition(),
factory
.Code("DateTime.Now.Year")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)))))
}))
},
{
"<person age=\" @DateTime.Now.Year\" />",
new MarkupBlock(
new MarkupTagHelperBlock("person",
TagMode.SelfClosing,
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>(
"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)))))
}))
},
{ {
"<person name=\"John\" />", "<person name=\"John\" />",
new MarkupBlock( new MarkupBlock(
@ -819,7 +861,10 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupBlock( new MarkupBlock(
factory.CodeMarkup(" "), factory.CodeMarkup(" "),
new ExpressionBlock( new ExpressionBlock(
factory.CodeTransition().As(SpanKind.Code), factory
.CodeTransition()
.As(SpanKind.Code)
.With(new MarkupChunkGenerator()),
factory factory
.Code("value") .Code("value")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
@ -832,7 +877,10 @@ namespace Microsoft.AspNet.Razor.TagHelpers
factory.CodeMarkup("(bool)"), factory.CodeMarkup("(bool)"),
new MarkupBlock( new MarkupBlock(
new ExpressionBlock( new ExpressionBlock(
factory.CodeTransition().As(SpanKind.Code), factory
.CodeTransition()
.As(SpanKind.Code)
.With(new MarkupChunkGenerator()),
factory factory
.Code("Bag[\"val\"]") .Code("Bag[\"val\"]")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
@ -848,11 +896,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupBlock( new MarkupBlock(
factory.CodeMarkup(" "), factory.CodeMarkup(" "),
new ExpressionBlock( new ExpressionBlock(
factory.CodeTransition().As(SpanKind.Code), factory
factory .CodeTransition()
.Code("DateTime.Now") .As(SpanKind.Code)
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .With(new MarkupChunkGenerator()),
.Accepts(AcceptedCharacters.NonWhiteSpace))) factory
.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)))
)) ))
})) }))
}, },
@ -928,21 +979,27 @@ namespace Microsoft.AspNet.Razor.TagHelpers
"age", "age",
new MarkupBlock( new MarkupBlock(
new MarkupBlock( new MarkupBlock(
factory.CodeMarkup("@").Accepts(AcceptedCharacters.None), factory.CodeMarkup("@")
.Accepts(AcceptedCharacters.None)
.With(new MarkupChunkGenerator()),
factory.CodeMarkup("@") factory.CodeMarkup("@")
.With(SpanChunkGenerator.Null) .With(SpanChunkGenerator.Null)
.Accepts(AcceptedCharacters.None)), .Accepts(AcceptedCharacters.None)),
new MarkupBlock( new MarkupBlock(
factory.EmptyHtml().As(SpanKind.Code), factory.EmptyHtml().As(SpanKind.Code),
new ExpressionBlock( new ExpressionBlock(
factory.CodeTransition().As(SpanKind.Code), factory.CodeTransition()
.As(SpanKind.Code)
.With(new MarkupChunkGenerator()),
factory.MetaCode("(") factory.MetaCode("(")
.Accepts(AcceptedCharacters.None) .Accepts(AcceptedCharacters.None)
.As(SpanKind.Code), .As(SpanKind.Code)
.With(new MarkupChunkGenerator()),
factory.Code("11+1").AsExpression(), factory.Code("11+1").AsExpression(),
factory.MetaCode(")") factory.MetaCode(")")
.Accepts(AcceptedCharacters.None) .Accepts(AcceptedCharacters.None)
.As(SpanKind.Code))))), .As(SpanKind.Code)
.With(new MarkupChunkGenerator()))))),
new KeyValuePair<string, SyntaxTreeNode>( new KeyValuePair<string, SyntaxTreeNode>(
"birthday", "birthday",
factory.CodeMarkup("DateTime.Now")), factory.CodeMarkup("DateTime.Now")),
@ -1950,7 +2007,9 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupBlock( new MarkupBlock(
factory.CodeMarkup(" "), factory.CodeMarkup(" "),
new ExpressionBlock( new ExpressionBlock(
factory.CodeTransition().As(SpanKind.Code), factory.CodeTransition()
.As(SpanKind.Code)
.With(new MarkupChunkGenerator()),
factory.Code("true") factory.Code("true")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))), .Accepts(AcceptedCharacters.NonWhiteSpace))),
@ -1974,14 +2033,18 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupBlock( new MarkupBlock(
factory.CodeMarkup(" "), factory.CodeMarkup(" "),
new ExpressionBlock( new ExpressionBlock(
factory.CodeTransition().As(SpanKind.Code), factory.CodeTransition()
.As(SpanKind.Code)
.With(new MarkupChunkGenerator()),
factory.MetaCode("(") factory.MetaCode("(")
.Accepts(AcceptedCharacters.None) .Accepts(AcceptedCharacters.None)
.As(SpanKind.Code), .As(SpanKind.Code)
.With(new MarkupChunkGenerator()),
factory.Code("true").AsExpression(), factory.Code("true").AsExpression(),
factory.MetaCode(")") factory.MetaCode(")")
.Accepts(AcceptedCharacters.None) .Accepts(AcceptedCharacters.None)
.As(SpanKind.Code))), .As(SpanKind.Code)
.With(new MarkupChunkGenerator()))),
factory.CodeMarkup(" "))) factory.CodeMarkup(" ")))
} }
})), })),

View File

@ -1254,7 +1254,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
new MarkupBlock( new MarkupBlock(
new MarkupBlock( new MarkupBlock(
new ExpressionBlock( new ExpressionBlock(
factory.CodeTransition().As(SpanKind.Code), factory.CodeTransition(),
factory.Code("DateTime.Now") factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))))) .Accepts(AcceptedCharacters.NonWhiteSpace)))))
@ -1276,7 +1276,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
new MarkupBlock( new MarkupBlock(
new MarkupBlock( new MarkupBlock(
new ExpressionBlock( new ExpressionBlock(
factory.CodeTransition().As(SpanKind.Code), factory.CodeTransition(),
factory.Code("DateTime.Now") factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))))) .Accepts(AcceptedCharacters.NonWhiteSpace)))))
@ -1297,12 +1297,21 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
"bound", "bound",
new MarkupBlock( new MarkupBlock(
new MarkupBlock( new MarkupBlock(
factory.CodeMarkup("@").Accepts(AcceptedCharacters.None), factory
factory.CodeMarkup("@").With(SpanChunkGenerator.Null).Accepts(AcceptedCharacters.None)), .CodeMarkup("@")
.With(new MarkupChunkGenerator())
.Accepts(AcceptedCharacters.None),
factory
.CodeMarkup("@")
.With(SpanChunkGenerator.Null)
.Accepts(AcceptedCharacters.None)),
new MarkupBlock( new MarkupBlock(
factory.EmptyHtml().As(SpanKind.Code), factory.EmptyHtml().As(SpanKind.Code),
new ExpressionBlock( new ExpressionBlock(
factory.CodeTransition().As(SpanKind.Code), factory
.CodeTransition()
.As(SpanKind.Code)
.With(new MarkupChunkGenerator()),
factory.Code("DateTime.Now") factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))))) .Accepts(AcceptedCharacters.NonWhiteSpace)))))

View File

@ -152,7 +152,7 @@ __o = DateTime.Now;
__InputTagHelper = CreateTagHelper<InputTagHelper>(); __InputTagHelper = CreateTagHelper<InputTagHelper>();
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>(); __InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
#line 23 "ComplexTagHelpers.cshtml" #line 23 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = @object; __InputTagHelper2.Checked = (@object);
#line default #line default
#line hidden #line hidden
@ -165,13 +165,13 @@ __InputTagHelper2.Checked = @object;
__InputTagHelper = CreateTagHelper<InputTagHelper>(); __InputTagHelper = CreateTagHelper<InputTagHelper>();
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>(); __InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
#line 26 "ComplexTagHelpers.cshtml" #line 26 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014; __InputTagHelper2.Checked = (DateTimeOffset.Now.Year > 2014);
#line default #line default
#line hidden #line hidden
__PTagHelper = CreateTagHelper<PTagHelper>(); __PTagHelper = CreateTagHelper<PTagHelper>();
#line 25 "ComplexTagHelpers.cshtml" #line 25 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = -1970 + DateTimeOffset.Now.Year; __PTagHelper.Age = -1970 + @DateTimeOffset.Now.Year;
#line default #line default
#line hidden #line hidden
@ -191,13 +191,13 @@ __PTagHelper.Age = DateTimeOffset.Now.Year - 1970;
__InputTagHelper = CreateTagHelper<InputTagHelper>(); __InputTagHelper = CreateTagHelper<InputTagHelper>();
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>(); __InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
#line 32 "ComplexTagHelpers.cshtml" #line 32 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014 ; __InputTagHelper2.Checked = @( DateTimeOffset.Now.Year ) > 2014 ;
#line default #line default
#line hidden #line hidden
__PTagHelper = CreateTagHelper<PTagHelper>(); __PTagHelper = CreateTagHelper<PTagHelper>();
#line 31 "ComplexTagHelpers.cshtml" #line 31 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = "My age is this long.".Length; __PTagHelper.Age = ("My age is this long.".Length);
#line default #line default
#line hidden #line hidden

View File

@ -276,7 +276,7 @@ if(true) {
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>(); __InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2); __tagHelperExecutionContext.Add(__InputTagHelper2);
#line 23 "ComplexTagHelpers.cshtml" #line 23 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = @object; __InputTagHelper2.Checked = (@object);
#line default #line default
#line hidden #line hidden
@ -323,7 +323,7 @@ __InputTagHelper2.Checked = @object;
__tagHelperExecutionContext.AddHtmlAttribute("unbound", Html.Raw("hello")); __tagHelperExecutionContext.AddHtmlAttribute("unbound", Html.Raw("hello"));
__tagHelperExecutionContext.AddHtmlAttribute("unbound", Html.Raw("world")); __tagHelperExecutionContext.AddHtmlAttribute("unbound", Html.Raw("world"));
#line 26 "ComplexTagHelpers.cshtml" #line 26 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014; __InputTagHelper2.Checked = (DateTimeOffset.Now.Year > 2014);
#line default #line default
#line hidden #line hidden
@ -341,7 +341,7 @@ __InputTagHelper2.Checked = @object;
__PTagHelper = CreateTagHelper<PTagHelper>(); __PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper); __tagHelperExecutionContext.Add(__PTagHelper);
#line 25 "ComplexTagHelpers.cshtml" #line 25 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = -1970 + DateTimeOffset.Now.Year; __PTagHelper.Age = -1970 + @DateTimeOffset.Now.Year;
#line default #line default
#line hidden #line hidden
@ -409,7 +409,7 @@ __PTagHelper.Age = DateTimeOffset.Now.Year - 1970;
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>(); __InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2); __tagHelperExecutionContext.Add(__InputTagHelper2);
#line 32 "ComplexTagHelpers.cshtml" #line 32 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014 ; __InputTagHelper2.Checked = @( DateTimeOffset.Now.Year ) > 2014 ;
#line default #line default
#line hidden #line hidden
@ -427,7 +427,7 @@ __InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014 ;
__PTagHelper = CreateTagHelper<PTagHelper>(); __PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper); __tagHelperExecutionContext.Add(__PTagHelper);
#line 31 "ComplexTagHelpers.cshtml" #line 31 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = "My age is this long.".Length; __PTagHelper.Age = ("My age is this long.".Length);
#line default #line default
#line hidden #line hidden

View File

@ -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<PTagHelper>();
#line 7 "TransitionsInTagHelperAttributes.cshtml"
__PTagHelper.Age = 1337;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 8 "TransitionsInTagHelperAttributes.cshtml"
__o = @class;
#line default
#line hidden
#line 8 "TransitionsInTagHelperAttributes.cshtml"
__PTagHelper.Age = 42;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 9 "TransitionsInTagHelperAttributes.cshtml"
__PTagHelper.Age = 42 + @int;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 10 "TransitionsInTagHelperAttributes.cshtml"
__PTagHelper.Age = int;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 11 "TransitionsInTagHelperAttributes.cshtml"
__PTagHelper.Age = (@int);
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#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
}
}

View File

@ -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<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
AddHtmlAttributeValues("class", __tagHelperExecutionContext,
Tuple.Create(Tuple.Create("", 109), Tuple.Create<System.Object, System.Int32>(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<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
AddHtmlAttributeValues("class", __tagHelperExecutionContext,
Tuple.Create(Tuple.Create("", 155), Tuple.Create<System.Object, System.Int32>(@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<PTagHelper>();
__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<PTagHelper>();
__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<PTagHelper>();
__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<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
AddHtmlAttributeValues("class", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 298), Tuple.Create("custom-", 298), true),
Tuple.Create(Tuple.Create("", 305), Tuple.Create<System.Object, System.Int32>(@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
}
}

View File

@ -0,0 +1,12 @@
@addTagHelper "something, nice"
@{
var @class = "container-fluid";
var @int = 1;
}
<p class="@class" age="1337">Body of Tag</p>
<p class="@(@class)" age="42"></p>
<p class="test" age="42 + @int"></p>
<p class="test" age="@int"></p>
<p class="test" age="@(@int)"></p>
<p class="custom-@(@class)" age="4 * @(@int + 2)"></p>