diff --git a/src/Microsoft.AspNet.Razor/Parser/HtmlMarkupParser.Block.cs b/src/Microsoft.AspNet.Razor/Parser/HtmlMarkupParser.Block.cs index 31a778fd5e..0f6a6d52d3 100644 --- a/src/Microsoft.AspNet.Razor/Parser/HtmlMarkupParser.Block.cs +++ b/src/Microsoft.AspNet.Razor/Parser/HtmlMarkupParser.Block.cs @@ -464,7 +464,7 @@ namespace Microsoft.AspNet.Razor.Parser // Read the 'name' (i.e. read until the '=' or whitespace/newline) var name = Enumerable.Empty(); var whitespaceAfterAttributeName = Enumerable.Empty(); - if (At(HtmlSymbolType.Text)) + if (IsValidAttributeNameSymbol(CurrentSymbol)) { name = ReadWhile(sym => sym.Type != HtmlSymbolType.WhiteSpace && @@ -1136,5 +1136,28 @@ namespace Microsoft.AspNet.Razor.Parser } Output(SpanKind.Markup); } + + internal static bool IsValidAttributeNameSymbol(HtmlSymbol symbol) + { + if (symbol == null) + { + return false; + } + + // These restrictions cover most of the spec defined: http://www.w3.org/TR/html5/syntax.html#attributes-0 + // However, it's not all of it. For instance we don't special case control characters or allow OpenAngle. + // It also doesn't try to exclude Razor specific features such as the @ transition. This is based on the + // expectation that the parser handles such scenarios prior to falling through to name resolution. + var symbolType = symbol.Type; + return symbolType != HtmlSymbolType.WhiteSpace && + symbolType != HtmlSymbolType.NewLine && + symbolType != HtmlSymbolType.CloseAngle && + symbolType != HtmlSymbolType.OpenAngle && + symbolType != HtmlSymbolType.ForwardSlash && + symbolType != HtmlSymbolType.DoubleQuote && + symbolType != HtmlSymbolType.SingleQuote && + symbolType != HtmlSymbolType.Equals && + symbolType != HtmlSymbolType.Unknown; + } } } diff --git a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs index d2cbc48b7a..d4fa1053e4 100644 --- a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs +++ b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs @@ -186,13 +186,21 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal builder.Accept(symbol); } - else if (name == null && symbol.Type == HtmlSymbolType.Text) + else if (name == null && HtmlMarkupParser.IsValidAttributeNameSymbol(symbol)) { // We've captured all leading whitespace prior to the attribute name. // We're now at: " |asp-for='...'" or " |asp-for=..." // The goal here is to capture the attribute name. - name = symbol.Content; + var symbolContents = htmlSymbols + .Skip(i) // Skip prefix + .TakeWhile(nameSymbol => HtmlMarkupParser.IsValidAttributeNameSymbol(nameSymbol)) + .Select(nameSymbol => nameSymbol.Content); + + // Move the indexer past the attribute name symbols. + i += symbolContents.Count() - 1; + + name = string.Concat(symbolContents); attributeValueStartLocation = SourceLocation.Advance(attributeValueStartLocation, name); } else if (symbol.Type == HtmlSymbolType.Equals) @@ -322,10 +330,15 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal return TryParseSpan(childSpan, descriptors, errorSink); } - var textSymbol = childSpan.Symbols.FirstHtmlSymbolAs(HtmlSymbolType.Text); - var name = textSymbol != null ? textSymbol.Content : null; + var nameSymbols = childSpan + .Symbols + .OfType() + .SkipWhile(symbol => !HtmlMarkupParser.IsValidAttributeNameSymbol(symbol)) // Skip prefix + .TakeWhile(nameSymbol => HtmlMarkupParser.IsValidAttributeNameSymbol(nameSymbol)) + .Select(nameSymbol => nameSymbol.Content); - if (name == null) + var name = string.Concat(nameSymbols); + if (string.IsNullOrEmpty(name)) { errorSink.OnError( childSpan.Start, diff --git a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs index fc4d1062dc..f001633b00 100644 --- a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.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.Linq; #if DNXCORE50 @@ -20,6 +21,62 @@ namespace Microsoft.AspNet.Razor.Test.Generator private static IEnumerable PrefixedPAndInputTagHelperDescriptors { get; } = BuildPAndInputTagHelperDescriptors(prefix: "THS"); + private static IEnumerable SymbolBoundTagHelperDescriptors + { + get + { + return new[] + { + new TagHelperDescriptor + { + TagName = "*", + TypeName = "CatchAllTagHelper", + AssemblyName = "SomeAssembly", + Attributes = new[] + { + new TagHelperAttributeDescriptor + { + Name = "[item]", + PropertyName = "ListItems", + TypeName = typeof(List).FullName + }, + new TagHelperAttributeDescriptor + { + Name = "[(item)]", + PropertyName = "ArrayItems", + TypeName = typeof(string[]).FullName + }, + new TagHelperAttributeDescriptor + { + Name = "(click)", + PropertyName = "Event1", + TypeName = typeof(Action).FullName + }, + new TagHelperAttributeDescriptor + { + Name = "(^click)", + PropertyName = "Event2", + TypeName = typeof(Action).FullName + }, + new TagHelperAttributeDescriptor + { + Name = "*something", + PropertyName = "StringProperty1", + TypeName = typeof(string).FullName + }, + new TagHelperAttributeDescriptor + { + Name = "#local", + PropertyName = "StringProperty2", + TypeName = typeof(string).FullName + }, + }, + RequiredAttributes = new[] { "bound" }, + }, + }; + } + } + private static IEnumerable MinimizedTagHelpers_Descriptors { get @@ -1518,6 +1575,53 @@ namespace Microsoft.AspNet.Razor.Test.Generator contentLength: 15), } }, + { + "SymbolBoundAttributes", + "SymbolBoundAttributes.DesignTime", + SymbolBoundTagHelperDescriptors, + new[] + { + BuildLineMapping( + documentAbsoluteIndex: 14, + documentLineIndex: 0, + generatedAbsoluteIndex: 487, + generatedLineIndex: 15, + characterOffsetIndex: 14, + contentLength: 9), + BuildLineMapping( + documentAbsoluteIndex: 296, + documentLineIndex: 11, + documentCharacterOffsetIndex: 18, + generatedAbsoluteIndex: 1013, + generatedLineIndex: 34, + generatedCharacterOffsetIndex: 32, + contentLength: 5), + BuildLineMapping( + documentAbsoluteIndex: 345, + documentLineIndex: 12, + documentCharacterOffsetIndex: 20, + generatedAbsoluteIndex: 1199, + generatedLineIndex: 40, + generatedCharacterOffsetIndex: 33, + contentLength: 5), + BuildLineMapping( + documentAbsoluteIndex: 399, + documentLineIndex: 13, + documentCharacterOffsetIndex: 23, + generatedAbsoluteIndex: 1381, + generatedLineIndex: 46, + generatedCharacterOffsetIndex: 29, + contentLength: 13), + BuildLineMapping( + documentAbsoluteIndex: 481, + documentLineIndex: 14, + documentCharacterOffsetIndex: 24, + generatedAbsoluteIndex: 1571, + generatedLineIndex: 52, + generatedCharacterOffsetIndex: 29, + contentLength: 13), + } + } }; } } @@ -1567,6 +1671,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator { "DynamicAttributeTagHelpers", null, DynamicAttributeTagHelpers_Descriptors }, { "TransitionsInTagHelperAttributes", null, DefaultPAndInputTagHelperDescriptors }, { "NestedScriptTagTagHelpers", null, DefaultPAndInputTagHelperDescriptors }, + { "SymbolBoundAttributes", null, SymbolBoundTagHelperDescriptors }, }; } } diff --git a/test/Microsoft.AspNet.Razor.Test/Parser/Html/HtmlAttributeTest.cs b/test/Microsoft.AspNet.Razor.Test/Parser/Html/HtmlAttributeTest.cs index fadf3defa1..4a5462fd0e 100644 --- a/test/Microsoft.AspNet.Razor.Test/Parser/Html/HtmlAttributeTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/Parser/Html/HtmlAttributeTest.cs @@ -14,6 +14,174 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html { public class HtmlAttributeTest : CsHtmlMarkupParserTestBase { + public static TheoryData SymbolBoundAttributeNames + { + get + { + return new TheoryData + { + "[item]", + "[(item,", + "(click)", + "(^click)", + "*something", + "#local", + }; + } + } + + [Theory] + [MemberData(nameof(SymbolBoundAttributeNames))] + public void SymbolBoundAttributes_BeforeEqualWhitespace(string attributeName) + { + // Arrange + var attributeNameLength = attributeName.Length; + var newlineLength = Environment.NewLine.Length; + var prefixLocation1 = new SourceLocation( + absoluteIndex: 2, + lineIndex: 0, + characterIndex: 2); + var suffixLocation1 = new SourceLocation( + absoluteIndex: 8 + newlineLength + attributeNameLength, + lineIndex: 1, + characterIndex: 5 + attributeNameLength); + var valueLocation1 = new SourceLocation( + absoluteIndex: 5 + attributeNameLength + newlineLength, + lineIndex: 1, + characterIndex: 2 + attributeNameLength); + var prefixLocation2 = SourceLocation.Advance(suffixLocation1, "'"); + var suffixLocation2 = new SourceLocation( + absoluteIndex: 15 + attributeNameLength * 2 + newlineLength * 2, + lineIndex: 2, + characterIndex: 4); + var valueLocation2 = new SourceLocation( + absoluteIndex: 12 + attributeNameLength * 2 + newlineLength * 2, + lineIndex: 2, + characterIndex: 1); + + // Act & Assert + ParseBlockTest( + $"", + new MarkupBlock( + new MarkupTagBlock( + Factory.Markup("( + $" {attributeName}{Environment.NewLine}='", prefixLocation1), + suffix: new LocationTagged("'", suffixLocation1)), + Factory.Markup($" {attributeName}{Environment.NewLine}='").With(SpanChunkGenerator.Null), + Factory.Markup("Foo").With( + new LiteralAttributeChunkGenerator( + prefix: new LocationTagged(string.Empty, valueLocation1), + value: new LocationTagged("Foo", valueLocation1))), + Factory.Markup("'").With(SpanChunkGenerator.Null)), + new MarkupBlock( + new AttributeBlockChunkGenerator( + attributeName, + prefix: new LocationTagged( + $"\t{attributeName}={Environment.NewLine}'", prefixLocation2), + suffix: new LocationTagged("'", suffixLocation2)), + Factory.Markup($"\t{attributeName}={Environment.NewLine}'").With(SpanChunkGenerator.Null), + Factory.Markup("Bar").With( + new LiteralAttributeChunkGenerator( + prefix: new LocationTagged(string.Empty, valueLocation2), + value: new LocationTagged("Bar", valueLocation2))), + Factory.Markup("'").With(SpanChunkGenerator.Null)), + Factory.Markup(" />").Accepts(AcceptedCharacters.None)))); + } + + [Theory] + [MemberData(nameof(SymbolBoundAttributeNames))] + public void SymbolBoundAttributes_Whitespace(string attributeName) + { + // Arrange + var attributeNameLength = attributeName.Length; + var newlineLength = Environment.NewLine.Length; + var prefixLocation1 = new SourceLocation( + absoluteIndex: 2, + lineIndex: 0, + characterIndex: 2); + var suffixLocation1 = new SourceLocation( + absoluteIndex: 10 + newlineLength + attributeNameLength, + lineIndex: 1, + characterIndex: 5 + attributeNameLength + newlineLength); + var valueLocation1 = new SourceLocation( + absoluteIndex: 7 + attributeNameLength + newlineLength, + lineIndex: 1, + characterIndex: 4 + attributeNameLength); + var prefixLocation2 = SourceLocation.Advance(suffixLocation1, "'"); + var suffixLocation2 = new SourceLocation( + absoluteIndex: 17 + attributeNameLength * 2 + newlineLength * 2, + lineIndex: 2, + characterIndex: 5 + attributeNameLength); + var valueLocation2 = new SourceLocation( + absoluteIndex: 14 + attributeNameLength * 2 + newlineLength * 2, + lineIndex: 2, + characterIndex: 2 + attributeNameLength); + + // Act & Assert + ParseBlockTest( + $"", + new MarkupBlock( + new MarkupTagBlock( + Factory.Markup("( + $" {Environment.NewLine} {attributeName}='", prefixLocation1), + suffix: new LocationTagged("'", suffixLocation1)), + Factory.Markup($" {Environment.NewLine} {attributeName}='").With(SpanChunkGenerator.Null), + Factory.Markup("Foo").With( + new LiteralAttributeChunkGenerator( + prefix: new LocationTagged(string.Empty, valueLocation1), + value: new LocationTagged("Foo", valueLocation1))), + Factory.Markup("'").With(SpanChunkGenerator.Null)), + new MarkupBlock( + new AttributeBlockChunkGenerator( + attributeName, + prefix: new LocationTagged( + $"\t{Environment.NewLine}{attributeName}='", prefixLocation2), + suffix: new LocationTagged("'", suffixLocation2)), + Factory.Markup($"\t{Environment.NewLine}{attributeName}='").With(SpanChunkGenerator.Null), + Factory.Markup("Bar").With( + new LiteralAttributeChunkGenerator( + prefix: new LocationTagged(string.Empty, valueLocation2), + value: new LocationTagged("Bar", valueLocation2))), + Factory.Markup("'").With(SpanChunkGenerator.Null)), + Factory.Markup(" />").Accepts(AcceptedCharacters.None)))); + } + + [Theory] + [MemberData(nameof(SymbolBoundAttributeNames))] + public void SymbolBoundAttributes(string attributeName) + { + // Arrange + var attributeNameLength = attributeName.Length; + var suffixLocation = 8 + attributeNameLength; + var valueLocation = 5 + attributeNameLength; + + // Act & Assert + ParseBlockTest($"", + new MarkupBlock( + new MarkupTagBlock( + Factory.Markup("($" {attributeName}='", 2, 0, 2), + suffix: new LocationTagged("'", suffixLocation, 0, suffixLocation)), + Factory.Markup($" {attributeName}='").With(SpanChunkGenerator.Null), + Factory.Markup("Foo").With( + new LiteralAttributeChunkGenerator( + prefix: new LocationTagged(string.Empty, valueLocation, 0, valueLocation), + value: new LocationTagged("Foo", valueLocation, 0, valueLocation))), + Factory.Markup("'").With(SpanChunkGenerator.Null)), + Factory.Markup(" />").Accepts(AcceptedCharacters.None)))); + } + [Fact] public void SimpleLiteralAttribute() { diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs index 6ce6c69bfa..acddce1e83 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs @@ -18,6 +18,154 @@ namespace Microsoft.AspNet.Razor.TagHelpers { public class TagHelperBlockRewriterTest : TagHelperRewritingTestBase { + public static TheoryData SymbolBoundAttributeData + { + get + { + var factory = CreateDefaultSpanFactory(); + + return new TheoryData + { + { + "
    ", + new MarkupBlock( + new MarkupTagHelperBlock("ul", + attributes: new List> + { + new KeyValuePair("bound", null), + new KeyValuePair("[item]", factory.CodeMarkup("items")) + })) + }, + { + "
      ", + new MarkupBlock( + new MarkupTagHelperBlock("ul", + attributes: new List> + { + new KeyValuePair("bound", null), + new KeyValuePair("[(item)]", factory.CodeMarkup("items")) + })) + }, + { + "", + new MarkupBlock( + new MarkupTagHelperBlock("button", + attributes: new List> + { + new KeyValuePair("bound", null), + new KeyValuePair( + "(click)", + factory.CodeMarkup("doSomething()")) + }, + children: factory.Markup("Click Me"))) + }, + { + "", + new MarkupBlock( + new MarkupTagHelperBlock("button", + attributes: new List> + { + new KeyValuePair("bound", null), + new KeyValuePair( + "(^click)", + factory.CodeMarkup("doSomething()")) + }, + children: factory.Markup("Click Me"))) + }, + { + "", + new MarkupBlock( + new MarkupTagHelperBlock("template", + attributes: new List> + { + new KeyValuePair("bound", null), + new KeyValuePair("*something", factory.Markup("value")) + })) + }, + { + "
      ", + new MarkupBlock( + new MarkupTagHelperBlock("div", + attributes: new List> + { + new KeyValuePair("bound", null), + new KeyValuePair("#localminimized", null) + })) + }, + { + "
      ", + new MarkupBlock( + new MarkupTagHelperBlock("div", + attributes: new List> + { + new KeyValuePair("bound", null), + new KeyValuePair("#local", factory.Markup("value")) + })) + }, + }; + } + } + + [Theory] + [MemberData(nameof(SymbolBoundAttributeData))] + public void Rewrite_CanHandleSymbolBoundAttributes(string documentContent, MarkupBlock expectedOutput) + { + // Arrange + var descriptors = new[] + { + new TagHelperDescriptor + { + TagName = "*", + TypeName = "CatchAllTagHelper", + AssemblyName = "SomeAssembly", + Attributes = new[] + { + new TagHelperAttributeDescriptor + { + Name = "[item]", + PropertyName = "ListItems", + TypeName = typeof(List).FullName + }, + new TagHelperAttributeDescriptor + { + Name = "[(item)]", + PropertyName = "ArrayItems", + TypeName = typeof(string[]).FullName + }, + new TagHelperAttributeDescriptor + { + Name = "(click)", + PropertyName = "Event1", + TypeName = typeof(Action).FullName + }, + new TagHelperAttributeDescriptor + { + Name = "(^click)", + PropertyName = "Event2", + TypeName = typeof(Action).FullName + }, + new TagHelperAttributeDescriptor + { + Name = "*something", + PropertyName = "StringProperty1", + TypeName = typeof(string).FullName + }, + new TagHelperAttributeDescriptor + { + Name = "#local", + PropertyName = "StringProperty2", + TypeName = typeof(string).FullName + }, + }, + RequiredAttributes = new[] { "bound" }, + }, + }; + var descriptorProvider = new TagHelperDescriptorProvider(descriptors); + + // Act & Assert + EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors: new RazorError[0]); + } + public static TheoryData WithoutEndTagElementData { get diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/SymbolBoundAttributes.DesignTime.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/SymbolBoundAttributes.DesignTime.cs new file mode 100644 index 0000000000..6daaa40afe --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/SymbolBoundAttributes.DesignTime.cs @@ -0,0 +1,65 @@ +namespace TestOutput +{ + using Microsoft.AspNet.Razor.Runtime.TagHelpers; + using System; + using System.Threading.Tasks; + + public class SymbolBoundAttributes + { + private static object @__o; + private void @__RazorDesignTimeHelpers__() + { + #pragma warning disable 219 + string __tagHelperDirectiveSyntaxHelper = null; + __tagHelperDirectiveSyntaxHelper = +#line 1 "SymbolBoundAttributes.cshtml" + "*, nice" + +#line default +#line hidden + ; + #pragma warning restore 219 + } + #line hidden + private CatchAllTagHelper __CatchAllTagHelper = null; + #line hidden + public SymbolBoundAttributes() + { + } + + #pragma warning disable 1998 + public override async Task ExecuteAsync() + { + __CatchAllTagHelper = CreateTagHelper(); +#line 12 "SymbolBoundAttributes.cshtml" +__CatchAllTagHelper.ListItems = items; + +#line default +#line hidden + __CatchAllTagHelper = CreateTagHelper(); +#line 13 "SymbolBoundAttributes.cshtml" +__CatchAllTagHelper.ArrayItems = items; + +#line default +#line hidden + __CatchAllTagHelper = CreateTagHelper(); +#line 14 "SymbolBoundAttributes.cshtml" +__CatchAllTagHelper.Event1 = doSomething(); + +#line default +#line hidden + __CatchAllTagHelper = CreateTagHelper(); +#line 15 "SymbolBoundAttributes.cshtml" +__CatchAllTagHelper.Event2 = doSomething(); + +#line default +#line hidden + __CatchAllTagHelper = CreateTagHelper(); + __CatchAllTagHelper.StringProperty1 = "value"; + __CatchAllTagHelper = CreateTagHelper(); + __CatchAllTagHelper = CreateTagHelper(); + __CatchAllTagHelper.StringProperty2 = "value"; + } + #pragma warning restore 1998 + } +} diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/SymbolBoundAttributes.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/SymbolBoundAttributes.cs new file mode 100644 index 0000000000..4d1eb601ac --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/SymbolBoundAttributes.cs @@ -0,0 +1,175 @@ +#pragma checksum "SymbolBoundAttributes.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "65ef0c8f673481f5ab85bd4936f91f31e84c490c" +namespace TestOutput +{ + using Microsoft.AspNet.Razor.Runtime.TagHelpers; + using System; + using System.Threading.Tasks; + + public class SymbolBoundAttributes + { + #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 CatchAllTagHelper __CatchAllTagHelper = null; + #line hidden + public SymbolBoundAttributes() + { + } + + #pragma warning disable 1998 + public override async Task ExecuteAsync() + { + __tagHelperRunner = __tagHelperRunner ?? new TagHelperRunner(); + Instrumentation.BeginContext(25, 253, true); + WriteLiteral("\r\n
        \r\n
          \r\n\r\n\r\n\r\n\r\n
          \r\n
          \r\n\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("ul", TagMode.StartTagAndEndTag, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __CatchAllTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__CatchAllTagHelper); + __tagHelperExecutionContext.AddMinimizedHtmlAttribute("bound"); +#line 12 "SymbolBoundAttributes.cshtml" +__CatchAllTagHelper.ListItems = items; + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("[item]", __CatchAllTagHelper.ListItems); + __tagHelperExecutionContext.AddHtmlAttribute("[item]", Html.Raw("items")); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(278, 45, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(323, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("ul", TagMode.StartTagAndEndTag, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __CatchAllTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__CatchAllTagHelper); + __tagHelperExecutionContext.AddMinimizedHtmlAttribute("bound"); +#line 13 "SymbolBoundAttributes.cshtml" +__CatchAllTagHelper.ArrayItems = items; + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("[(item)]", __CatchAllTagHelper.ArrayItems); + __tagHelperExecutionContext.AddHtmlAttribute("[(item)]", Html.Raw("items")); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(325, 49, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(374, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("button", TagMode.StartTagAndEndTag, "test", async() => { + Instrumentation.BeginContext(438, 8, true); + WriteLiteral("Click Me"); + Instrumentation.EndContext(); + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __CatchAllTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__CatchAllTagHelper); + __tagHelperExecutionContext.AddMinimizedHtmlAttribute("bound"); +#line 14 "SymbolBoundAttributes.cshtml" +__CatchAllTagHelper.Event1 = doSomething(); + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("(click)", __CatchAllTagHelper.Event1); + __tagHelperExecutionContext.AddHtmlAttribute("(click)", Html.Raw("doSomething()")); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(376, 79, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(455, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("button", TagMode.StartTagAndEndTag, "test", async() => { + Instrumentation.BeginContext(521, 8, true); + WriteLiteral("Click Me"); + Instrumentation.EndContext(); + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __CatchAllTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__CatchAllTagHelper); + __tagHelperExecutionContext.AddMinimizedHtmlAttribute("bound"); +#line 15 "SymbolBoundAttributes.cshtml" +__CatchAllTagHelper.Event2 = doSomething(); + +#line default +#line hidden + __tagHelperExecutionContext.AddTagHelperAttribute("(^click)", __CatchAllTagHelper.Event2); + __tagHelperExecutionContext.AddHtmlAttribute("(^click)", Html.Raw("doSomething()")); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(457, 81, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(538, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("template", TagMode.StartTagAndEndTag, "test", async() => { + Instrumentation.BeginContext(594, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __CatchAllTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__CatchAllTagHelper); + __tagHelperExecutionContext.AddMinimizedHtmlAttribute("bound"); + __CatchAllTagHelper.StringProperty1 = "value"; + __tagHelperExecutionContext.AddTagHelperAttribute("*something", __CatchAllTagHelper.StringProperty1); + __tagHelperExecutionContext.AddHtmlAttribute("*something", Html.Raw("value")); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(540, 67, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(607, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("div", TagMode.StartTagAndEndTag, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __CatchAllTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__CatchAllTagHelper); + __tagHelperExecutionContext.AddMinimizedHtmlAttribute("bound"); + __tagHelperExecutionContext.AddMinimizedHtmlAttribute("#localminimized"); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(609, 33, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(642, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("div", TagMode.StartTagAndEndTag, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __CatchAllTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__CatchAllTagHelper); + __tagHelperExecutionContext.AddMinimizedHtmlAttribute("bound"); + __CatchAllTagHelper.StringProperty2 = "value"; + __tagHelperExecutionContext.AddTagHelperAttribute("#local", __CatchAllTagHelper.StringProperty2); + __tagHelperExecutionContext.AddHtmlAttribute("#local", Html.Raw("value")); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(644, 47, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + } + #pragma warning restore 1998 + } +} diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/SymbolBoundAttributes.cshtml b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/SymbolBoundAttributes.cshtml new file mode 100644 index 0000000000..112c496953 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/SymbolBoundAttributes.cshtml @@ -0,0 +1,19 @@ +@addTagHelper "*, nice" + +
            +
              + + + +
              +
              + +
                +
                  + + + +
                  +
                  \ No newline at end of file