Add support for data bound symbols as attribute names.

- Took the HTML5 spec approach of disallowing specific characters and accepting all others.
- Added several parser and code generation tests to cover both `TagHelper` and non-`TagHelper` variations of symbol bound attribute names.

#137
This commit is contained in:
N. Taylor Mullen 2015-09-17 15:28:07 -07:00
parent fb0d235301
commit 7239eb015c
8 changed files with 722 additions and 6 deletions

View File

@ -464,7 +464,7 @@ namespace Microsoft.AspNet.Razor.Parser
// Read the 'name' (i.e. read until the '=' or whitespace/newline)
var name = Enumerable.Empty<HtmlSymbol>();
var whitespaceAfterAttributeName = Enumerable.Empty<HtmlSymbol>();
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;
}
}
}

View File

@ -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<HtmlSymbol>()
.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,

View File

@ -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<TagHelperDescriptor> PrefixedPAndInputTagHelperDescriptors { get; }
= BuildPAndInputTagHelperDescriptors(prefix: "THS");
private static IEnumerable<TagHelperDescriptor> SymbolBoundTagHelperDescriptors
{
get
{
return new[]
{
new TagHelperDescriptor
{
TagName = "*",
TypeName = "CatchAllTagHelper",
AssemblyName = "SomeAssembly",
Attributes = new[]
{
new TagHelperAttributeDescriptor
{
Name = "[item]",
PropertyName = "ListItems",
TypeName = typeof(List<string>).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<TagHelperDescriptor> 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 },
};
}
}

View File

@ -14,6 +14,174 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
{
public class HtmlAttributeTest : CsHtmlMarkupParserTestBase
{
public static TheoryData SymbolBoundAttributeNames
{
get
{
return new TheoryData<string>
{
"[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(
$"<a {attributeName}{Environment.NewLine}='Foo'\t{attributeName}={Environment.NewLine}'Bar' />",
new MarkupBlock(
new MarkupTagBlock(
Factory.Markup("<a"),
new MarkupBlock(
new AttributeBlockChunkGenerator(
attributeName,
prefix: new LocationTagged<string>(
$" {attributeName}{Environment.NewLine}='", prefixLocation1),
suffix: new LocationTagged<string>("'", suffixLocation1)),
Factory.Markup($" {attributeName}{Environment.NewLine}='").With(SpanChunkGenerator.Null),
Factory.Markup("Foo").With(
new LiteralAttributeChunkGenerator(
prefix: new LocationTagged<string>(string.Empty, valueLocation1),
value: new LocationTagged<string>("Foo", valueLocation1))),
Factory.Markup("'").With(SpanChunkGenerator.Null)),
new MarkupBlock(
new AttributeBlockChunkGenerator(
attributeName,
prefix: new LocationTagged<string>(
$"\t{attributeName}={Environment.NewLine}'", prefixLocation2),
suffix: new LocationTagged<string>("'", suffixLocation2)),
Factory.Markup($"\t{attributeName}={Environment.NewLine}'").With(SpanChunkGenerator.Null),
Factory.Markup("Bar").With(
new LiteralAttributeChunkGenerator(
prefix: new LocationTagged<string>(string.Empty, valueLocation2),
value: new LocationTagged<string>("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(
$"<a {Environment.NewLine} {attributeName}='Foo'\t{Environment.NewLine}{attributeName}='Bar' />",
new MarkupBlock(
new MarkupTagBlock(
Factory.Markup("<a"),
new MarkupBlock(
new AttributeBlockChunkGenerator(
attributeName,
prefix: new LocationTagged<string>(
$" {Environment.NewLine} {attributeName}='", prefixLocation1),
suffix: new LocationTagged<string>("'", suffixLocation1)),
Factory.Markup($" {Environment.NewLine} {attributeName}='").With(SpanChunkGenerator.Null),
Factory.Markup("Foo").With(
new LiteralAttributeChunkGenerator(
prefix: new LocationTagged<string>(string.Empty, valueLocation1),
value: new LocationTagged<string>("Foo", valueLocation1))),
Factory.Markup("'").With(SpanChunkGenerator.Null)),
new MarkupBlock(
new AttributeBlockChunkGenerator(
attributeName,
prefix: new LocationTagged<string>(
$"\t{Environment.NewLine}{attributeName}='", prefixLocation2),
suffix: new LocationTagged<string>("'", suffixLocation2)),
Factory.Markup($"\t{Environment.NewLine}{attributeName}='").With(SpanChunkGenerator.Null),
Factory.Markup("Bar").With(
new LiteralAttributeChunkGenerator(
prefix: new LocationTagged<string>(string.Empty, valueLocation2),
value: new LocationTagged<string>("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($"<a {attributeName}='Foo' />",
new MarkupBlock(
new MarkupTagBlock(
Factory.Markup("<a"),
new MarkupBlock(
new AttributeBlockChunkGenerator(
attributeName,
prefix: new LocationTagged<string>($" {attributeName}='", 2, 0, 2),
suffix: new LocationTagged<string>("'", suffixLocation, 0, suffixLocation)),
Factory.Markup($" {attributeName}='").With(SpanChunkGenerator.Null),
Factory.Markup("Foo").With(
new LiteralAttributeChunkGenerator(
prefix: new LocationTagged<string>(string.Empty, valueLocation, 0, valueLocation),
value: new LocationTagged<string>("Foo", valueLocation, 0, valueLocation))),
Factory.Markup("'").With(SpanChunkGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None))));
}
[Fact]
public void SimpleLiteralAttribute()
{

View File

@ -18,6 +18,154 @@ namespace Microsoft.AspNet.Razor.TagHelpers
{
public class TagHelperBlockRewriterTest : TagHelperRewritingTestBase
{
public static TheoryData SymbolBoundAttributeData
{
get
{
var factory = CreateDefaultSpanFactory();
return new TheoryData<string, MarkupBlock>
{
{
"<ul bound [item]='items'></ul>",
new MarkupBlock(
new MarkupTagHelperBlock("ul",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("bound", null),
new KeyValuePair<string, SyntaxTreeNode>("[item]", factory.CodeMarkup("items"))
}))
},
{
"<ul bound [(item)]='items'></ul>",
new MarkupBlock(
new MarkupTagHelperBlock("ul",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("bound", null),
new KeyValuePair<string, SyntaxTreeNode>("[(item)]", factory.CodeMarkup("items"))
}))
},
{
"<button bound (click)='doSomething()'>Click Me</button>",
new MarkupBlock(
new MarkupTagHelperBlock("button",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("bound", null),
new KeyValuePair<string, SyntaxTreeNode>(
"(click)",
factory.CodeMarkup("doSomething()"))
},
children: factory.Markup("Click Me")))
},
{
"<button bound (^click)='doSomething()'>Click Me</button>",
new MarkupBlock(
new MarkupTagHelperBlock("button",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("bound", null),
new KeyValuePair<string, SyntaxTreeNode>(
"(^click)",
factory.CodeMarkup("doSomething()"))
},
children: factory.Markup("Click Me")))
},
{
"<template bound *something='value'></template>",
new MarkupBlock(
new MarkupTagHelperBlock("template",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("bound", null),
new KeyValuePair<string, SyntaxTreeNode>("*something", factory.Markup("value"))
}))
},
{
"<div bound #localminimized></div>",
new MarkupBlock(
new MarkupTagHelperBlock("div",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("bound", null),
new KeyValuePair<string, SyntaxTreeNode>("#localminimized", null)
}))
},
{
"<div bound #local='value'></div>",
new MarkupBlock(
new MarkupTagHelperBlock("div",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("bound", null),
new KeyValuePair<string, SyntaxTreeNode>("#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<string>).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

View File

@ -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<CatchAllTagHelper>();
#line 12 "SymbolBoundAttributes.cshtml"
__CatchAllTagHelper.ListItems = items;
#line default
#line hidden
__CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>();
#line 13 "SymbolBoundAttributes.cshtml"
__CatchAllTagHelper.ArrayItems = items;
#line default
#line hidden
__CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>();
#line 14 "SymbolBoundAttributes.cshtml"
__CatchAllTagHelper.Event1 = doSomething();
#line default
#line hidden
__CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>();
#line 15 "SymbolBoundAttributes.cshtml"
__CatchAllTagHelper.Event2 = doSomething();
#line default
#line hidden
__CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>();
__CatchAllTagHelper.StringProperty1 = "value";
__CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>();
__CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>();
__CatchAllTagHelper.StringProperty2 = "value";
}
#pragma warning restore 1998
}
}

View File

@ -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<ul [item]=\"items\"></ul>\r\n<ul [(item)]=\"items\"></ul>\r\n<button (click)=\"doSometh" +
"ing()\">Click Me</button>\r\n<button (^click)=\"doSomething()\">Click Me</button>\r\n<t" +
"emplate *something=\"value\">\r\n</template>\r\n<div #local></div>\r\n<div #local=\"value" +
"\"></div>\r\n\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("ul", TagMode.StartTagAndEndTag, "test", async() => {
}
, StartTagHelperWritingScope, EndTagHelperWritingScope);
__CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>();
__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<CatchAllTagHelper>();
__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<CatchAllTagHelper>();
__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<CatchAllTagHelper>();
__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<CatchAllTagHelper>();
__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<CatchAllTagHelper>();
__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<CatchAllTagHelper>();
__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
}
}

View File

@ -0,0 +1,19 @@
@addTagHelper "*, nice"
<ul [item]="items"></ul>
<ul [(item)]="items"></ul>
<button (click)="doSomething()">Click Me</button>
<button (^click)="doSomething()">Click Me</button>
<template *something="value">
</template>
<div #local></div>
<div #local="value"></div>
<ul bound [item]="items" [item]="items"></ul>
<ul bound [(item)]="items" [(item)]="items"></ul>
<button bound (click)="doSomething()" (click)="doSomething()">Click Me</button>
<button bound (^click)="doSomething()" (^click)="doSomething()">Click Me</button>
<template bound *something="value" *something="value">
</template>
<div bound #localminimized></div>
<div bound #local="value" #local="value"></div>