public void WriteTagHelperBody_DesignTime_WritesChildren() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateDesignTime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperBodyIntermediateNode() { Children = { new CSharpExpressionIntermediateNode(), } }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperBody(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"Render Children ", csharp, ignoreLineEndingDifferences: true); }
private void ProcessAttributes(TagHelperIntermediateNode node) { for (var i = node.Children.Count - 1; i >= 0; i--) { if (node.Children[i] is TagHelperPropertyIntermediateNode propertyNode) { if (TrySimplifyContent(propertyNode) && node.TagHelpers.Any(t => t.IsComponentTagHelper())) { node.Diagnostics.Add(ComponentDiagnosticFactory.Create_UnsupportedComplexContent( propertyNode, propertyNode.AttributeName)); node.Children.RemoveAt(i); continue; } } else if (node.Children[i] is TagHelperHtmlAttributeIntermediateNode htmlNode) { if (TrySimplifyContent(htmlNode) && node.TagHelpers.Any(t => t.IsComponentTagHelper())) { node.Diagnostics.Add(ComponentDiagnosticFactory.Create_UnsupportedComplexContent( htmlNode, htmlNode.AttributeName)); node.Children.RemoveAt(i); continue; } } } }
public void WriteTagHelperExecute_DesignTime_WritesNothing() { // Arrange var extension = new DefaultTagHelperTargetExtension() { DesignTime = true }; var context = TestCodeRenderingContext.CreateDesignTime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperExecuteIntermediateNode(); tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperExecute(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"", csharp, ignoreLineEndingDifferences: true); }
public void WriteTagHelperCreate_Runtime_RendersCorrectly_UsesSpecifiedTagHelperType() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperCreateIntermediateNode() { FieldName = "__TestNamespace_MyTagHelper", TypeName = "TestNamespace.MyTagHelper", }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperCreate(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"__TestNamespace_MyTagHelper = CreateTagHelper<global::TestNamespace.MyTagHelper>(); __tagHelperExecutionContext.Add(__TestNamespace_MyTagHelper); ", csharp, ignoreLineEndingDifferences: true); }
private ComponentIntermediateNode RewriteAsComponent(TagHelperIntermediateNode node, TagHelperDescriptor tagHelper) { var component = new ComponentIntermediateNode() { Component = tagHelper, Source = node.Source, TagName = node.TagName, TypeName = tagHelper.GetTypeName(), }; for (var i = 0; i < node.Diagnostics.Count; i++) { component.Diagnostics.Add(node.Diagnostics[i]); } var visitor = new ComponentRewriteVisitor(component); visitor.Visit(node); // Fixup the parameter names of child content elements. We can't do this during the rewrite // because we see the nodes in the wrong order. foreach (var childContent in component.ChildContents) { childContent.ParameterName = childContent.ParameterName ?? component.ChildContentParameterName ?? ComponentMetadata.ChildContent.DefaultParameterName; } return(component); }
private void ProcessAttributes(TagHelperIntermediateNode node) { for (var i = node.Children.Count - 1; i >= 0; i--) { if (node.Children[i] is TagHelperPropertyIntermediateNode propertyNode) { if (HasComplexChildContent(propertyNode)) { node.Diagnostics.Add(BlazorDiagnosticFactory.Create_UnsupportedComplexContent( propertyNode, propertyNode.AttributeName)); node.Children.RemoveAt(i); continue; } node.Children[i] = new ComponentAttributeExtensionNode(propertyNode); } else if (node.Children[i] is TagHelperHtmlAttributeIntermediateNode htmlNode) { if (HasComplexChildContent(htmlNode)) { node.Diagnostics.Add(BlazorDiagnosticFactory.Create_UnsupportedComplexContent( htmlNode, htmlNode.AttributeName)); node.Children.RemoveAt(i); continue; } } } }
public void WriteTagHelperHtmlAttribute_RendersCorrectly() { // Arrange var extension = new PreallocatedAttributeTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new PreallocatedTagHelperHtmlAttributeIntermediateNode() { VariableName = "_tagHelper1" }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperHtmlAttribute(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"__tagHelperExecutionContext.AddHtmlAttribute(_tagHelper1); ", csharp, ignoreLineEndingDifferences: true); }
public void WriteSetPreallocatedTagHelperProperty_IndexerAttribute_MultipleValues() { // Arrange var extension = new PreallocatedAttributeTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, "FooTagHelper", "Test"); tagHelperBuilder.TypeName("FooTagHelper"); var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind); builder .Name("Foo") .TypeName("System.Collections.Generic.Dictionary<System.String, System.String>") .AsDictionaryAttribute("pre-", "System.String") .PropertyName("FooProp"); var boundAttribute = builder.Build(); var tagHelper = tagHelperBuilder.Build(); var tagHelperNode = new TagHelperIntermediateNode(); var node1 = new PreallocatedTagHelperPropertyIntermediateNode() { AttributeName = "pre-Bar", FieldName = "__FooTagHelper", VariableName = "_tagHelper0s", BoundAttribute = boundAttribute, IsIndexerNameMatch = true, PropertyName = "FooProp", TagHelper = tagHelper, }; var node2 = new PreallocatedTagHelperPropertyIntermediateNode() { AttributeName = "pre-Foo", FieldName = "__FooTagHelper", VariableName = "_tagHelper1", BoundAttribute = boundAttribute, IsIndexerNameMatch = true, PropertyName = "FooProp", TagHelper = tagHelper, }; tagHelperNode.Children.Add(node1); tagHelperNode.Children.Add(node2); Push(context, tagHelperNode); // Act extension.WriteTagHelperProperty(context, node2); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"__FooTagHelper.FooProp[""Foo""] = (string)_tagHelper1.Value; __tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1); ", csharp, ignoreLineEndingDifferences: true); }
public void WriteTagHelperExecute_Runtime_RendersCorrectly() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperExecuteIntermediateNode(); tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperExecute(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); if (!__tagHelperExecutionContext.Output.IsContentModified) { await __tagHelperExecutionContext.SetOutputContentAsync(); } Write(__tagHelperExecutionContext.Output); __tagHelperExecutionContext = __tagHelperScopeManager.End(); ", csharp, ignoreLineEndingDifferences: true); }
public void WriteTagHelperBody_Runtime_RendersCorrectly_UsesTagNameAndModeFromContext() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperBodyIntermediateNode() { Children = { new CSharpExpressionIntermediateNode(), }, TagMode = TagMode.SelfClosing, TagName = "p", }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperBody(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"__tagHelperExecutionContext = __tagHelperScopeManager.Begin(""p"", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.SelfClosing, ""test"", async() => { Render Children } ); ", csharp, ignoreLineEndingDifferences: true); }
public override void VisitTagHelper(TagHelperIntermediateNode node) { // Visit children, we're replacing this node. for (var i = 0; i < node.Children.Count; i++) { Visit(node.Children[i]); } }
private void RewriteUsage(Context context, TagHelperIntermediateNode node, TagHelperDescriptor tagHelper) { if (!tagHelper.IsDefaultKind()) { return; } context.Add(tagHelper); // First we need to insert a node for the creation of the tag helper, and the hook up to the execution // context. This should come after the body node and any existing create nodes. // // If we're dealing with something totally malformed, then we'll end up just inserting at the end, and that's not // so bad. var i = 0; // Find the body node. while (i < node.Children.Count && node.Children[i] is TagHelperBodyIntermediateNode) { i++; } while (i < node.Children.Count && node.Children[i] is DefaultTagHelperBodyIntermediateNode) { i++; } // Now find the last create node. while (i < node.Children.Count && node.Children[i] is DefaultTagHelperCreateIntermediateNode) { i++; } // Now i has the right insertion point. node.Children.Insert(i, new DefaultTagHelperCreateIntermediateNode() { FieldName = context.GetFieldName(tagHelper), TagHelper = tagHelper, TypeName = tagHelper.GetTypeName(), }); // Next we need to rewrite any property nodes to use the field and property name for this // tag helper. for (i = 0; i < node.Children.Count; i++) { if (node.Children[i] is TagHelperPropertyIntermediateNode propertyNode && propertyNode.TagHelper == tagHelper) { // This belongs to the current tag helper, replace it. node.Children[i] = new DefaultTagHelperPropertyIntermediateNode(propertyNode) { FieldName = context.GetFieldName(tagHelper), PropertyName = propertyNode.BoundAttribute.GetPropertyName(), }; } } }
private void RewriteHtmlAttributes(TagHelperIntermediateNode node) { // We need to rewrite each html attribute, so that it will get added to the execution context. for (var i = 0; i < node.Children.Count; i++) { if (node.Children[i] is TagHelperHtmlAttributeIntermediateNode htmlAttributeNode) { node.Children[i] = new DefaultTagHelperHtmlAttributeIntermediateNode(htmlAttributeNode); } } }
public void WriteTagHelperProperty_Runtime_NonStringIndexer_RendersCorrectly() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperPropertyIntermediateNode() { AttributeName = "foo-bound", AttributeStructure = AttributeStructure.DoubleQuotes, BoundAttribute = IntIndexerTagHelper.BoundAttributes.Single(), FieldName = "__InputTagHelper", IsIndexerNameMatch = true, PropertyName = "IntIndexer", TagHelper = IntIndexerTagHelper, Source = Span, Children = { new CSharpExpressionIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.CSharp, Content = "32", } }, } } }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperProperty(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"if (__InputTagHelper.IntIndexer == null) { throw new InvalidOperationException(InvalidTagHelperIndexerAssignment(""foo-bound"", ""InputTagHelper"", ""IntIndexer"")); } #nullable restore #line 3 ""test.cshtml"" __InputTagHelper.IntIndexer[""bound""] = 32; #line default #line hidden #nullable disable __tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelper.IntIndexer[""bound""], global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes); ", csharp, ignoreLineEndingDifferences: true); }
private void RewriteUsage(Context context, TagHelperIntermediateNode node, TagHelperDescriptor tagHelper) { if (!tagHelper.IsViewComponentKind()) { return; } context.Add(tagHelper); // Now we need to insert a create node using the default tag helper runtime. This is similar to // code in DefaultTagHelperOptimizationPass. // // Find the body node. var i = 0; while (i < node.Children.Count && node.Children[i] is TagHelperBodyIntermediateNode) { i++; } while (i < node.Children.Count && node.Children[i] is DefaultTagHelperBodyIntermediateNode) { i++; } // Now find the last create node. while (i < node.Children.Count && node.Children[i] is DefaultTagHelperCreateIntermediateNode) { i++; } // Now i has the right insertion point. node.Children.Insert(i, new DefaultTagHelperCreateIntermediateNode() { FieldName = context.GetFieldName(tagHelper), TagHelper = tagHelper, TypeName = context.GetFullyQualifiedName(tagHelper), }); // Now we need to rewrite any set property nodes to use the default runtime. for (i = 0; i < node.Children.Count; i++) { if (node.Children[i] is TagHelperPropertyIntermediateNode propertyNode && propertyNode.TagHelper == tagHelper) { // This is a set property for this VCTH - we need to replace it with a node // that will use our field and property name. node.Children[i] = new DefaultTagHelperPropertyIntermediateNode(propertyNode) { FieldName = context.GetFieldName(tagHelper), PropertyName = propertyNode.BoundAttribute.GetPropertyName(), }; } } }
private bool IsTagHelperRuntimeNode(TagHelperIntermediateNode node) { foreach (var tagHelper in node.TagHelpers) { if (tagHelper.KindUsesDefaultTagHelperRuntime()) { return(true); } } return(false); }
private void RewriteUsage(TagHelperIntermediateNode node, TagHelperDescriptor tagHelper) { // Ignore Kind here. Some versions of Razor have a bug in the serializer that ignores it. // We need to surround the contents of the node with open and close nodes to ensure the component // is scoped correctly. node.Children.Insert(0, new ComponentOpenExtensionNode() { TypeName = tagHelper.GetTypeName(), }); for (var i = node.Children.Count - 1; i >= 0; i--) { if (node.Children[i] is TagHelperBodyIntermediateNode bodyNode) { // Replace with a node that we recognize so that it we can do proper scope tracking. // // Note that we force the body node to be last, this is done to push it after the // attribute nodes. This gives us the ordering we want for the render tree. node.Children.RemoveAt(i); node.Children.Add(new ComponentBodyExtensionNode(bodyNode) { TagMode = node.TagMode, TagName = node.TagName, }); } } node.Children.Add(new ComponentCloseExtensionNode()); // Now we need to rewrite any set property or HTML nodes to call the appropriate AddAttribute api. for (var i = node.Children.Count - 1; i >= 0; i--) { if (node.Children[i] is TagHelperPropertyIntermediateNode propertyNode && propertyNode.TagHelper == tagHelper) { // We don't support 'complex' content for components (mixed C# and markup) right now. // It's not clear yet if Blazor will have a good scenario to use these constructs. // // This is where a lot of the complexity in the Razor/TagHelpers model creeps in and we // might be able to avoid it if these features aren't needed. if (HasComplexChildContent(propertyNode)) { node.Diagnostics.Add(BlazorDiagnosticFactory.Create_UnsupportedComplexContent( propertyNode, propertyNode.AttributeName)); node.Children.RemoveAt(i); continue; } node.Children[i] = new ComponentAttributeExtensionNode(propertyNode); }
public override void VisitTagHelper(TagHelperIntermediateNode node) { base.VisitTagHelper(node); // Use a post-order traversal because we're going to rewite tag helper nodes, and thus // change the parent nodes. // // This ensures that we operate the leaf nodes first. if (!node.TagHelpers.Any(t => t.IsComponentTagHelper())) { References.Add(new IntermediateNodeReference(Parent, node)); } }
private void ProcessDuplicates(TagHelperIntermediateNode node) { // Reverse order because we will remove nodes. // // Each 'property' node could be duplicated if there are multiple tag helpers that match that // particular attribute. This is likely to happen when a component also defines something like // OnClick. We want to remove the 'onclick' and let it fall back to be handled by the component. for (var i = node.Children.Count - 1; i >= 0; i--) { var attributeNode = node.Children[i] as ComponentAttributeExtensionNode; if (attributeNode != null && attributeNode.TagHelper != null && attributeNode.TagHelper.IsEventHandlerTagHelper()) { for (var j = 0; j < node.Children.Count; j++) { var duplicate = node.Children[j] as ComponentAttributeExtensionNode; if (duplicate != null && duplicate.TagHelper != null && duplicate.TagHelper.IsComponentTagHelper() && duplicate.AttributeName == attributeNode.AttributeName) { // Found a duplicate - remove the 'fallback' in favor of the // more specific tag helper. node.Children.RemoveAt(i); node.TagHelpers.Remove(attributeNode.TagHelper); break; } } } } // If we still have duplicates at this point then they are genuine conflicts. var duplicates = node.Children .OfType <ComponentAttributeExtensionNode>() .Where(p => p.TagHelper?.IsEventHandlerTagHelper() ?? false) .GroupBy(p => p.AttributeName) .Where(g => g.Count() > 1); foreach (var duplicate in duplicates) { node.Diagnostics.Add(BlazorDiagnosticFactory.CreateEventHandler_Duplicates( node.Source, duplicate.Key, duplicate.ToArray())); foreach (var property in duplicate) { node.Children.Remove(property); } } }
public void WriteTagHelperProperty_DesignTime_NonStringIndexer_RendersCorrectly() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateDesignTime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperPropertyIntermediateNode() { AttributeName = "foo-bound", AttributeStructure = AttributeStructure.DoubleQuotes, BoundAttribute = IntIndexerTagHelper.BoundAttributes.Single(), FieldName = "__InputTagHelper", IsIndexerNameMatch = true, PropertyName = "IntIndexer", TagHelper = IntIndexerTagHelper, Source = Span, Children = { new CSharpExpressionIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.CSharp, Content = "32", } }, } } }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperProperty(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @" #nullable restore #line 3 ""test.cshtml"" __InputTagHelper.IntIndexer[""bound""] = 32; #line default #line hidden #nullable disable ", csharp, ignoreLineEndingDifferences: true); }
private void RewriteBody(TagHelperIntermediateNode node) { for (var i = 0; i < node.Children.Count; i++) { if (node.Children[i] is TagHelperBodyIntermediateNode bodyNode) { // We only expect one body node. node.Children[i] = new DefaultTagHelperBodyIntermediateNode(bodyNode) { TagMode = node.TagMode, TagName = node.TagName, }; break; } } }
public void WriteTagHelperHtmlAttribute_DesignTime_WritesNothing() { // Arrange var extension = new DefaultTagHelperTargetExtension() { DesignTime = true }; var context = TestCodeRenderingContext.CreateDesignTime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperHtmlAttributeIntermediateNode() { AttributeName = "name", AttributeStructure = AttributeStructure.DoubleQuotes, Children = { new HtmlAttributeValueIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.Html, Content = "Blah-" } } }, new CSharpCodeAttributeValueIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.CSharp, Content = "\"Foo\"", } }, } } }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperHtmlAttribute(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"Render Children Render Children ", csharp, ignoreLineEndingDifferences: true); }
public void WriteTagHelperProperty_Runtime_StringProperty_HtmlContent_RendersCorrectly() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperPropertyIntermediateNode() { AttributeName = "bound", AttributeStructure = AttributeStructure.DoubleQuotes, BoundAttribute = StringPropertyTagHelper.BoundAttributes.Single(), FieldName = "__InputTagHelper", IsIndexerNameMatch = false, PropertyName = "StringProp", TagHelper = StringPropertyTagHelper, Children = { new HtmlContentIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.Html, Content = "\"value\"", } }, } } }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperProperty(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); // The attribute value is not rendered inline because we are not using the preallocated writer. Assert.Equal( @"BeginWriteTagHelperAttribute(); Render Children __tagHelperStringValueBuffer = EndWriteTagHelperAttribute(); __InputTagHelper.StringProp = __tagHelperStringValueBuffer; __tagHelperExecutionContext.AddTagHelperAttribute(""bound"", __InputTagHelper.StringProp, global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes); ", csharp, ignoreLineEndingDifferences: true); }
[Fact] // We don't actually assign the expression result at design time, we just use string.Empty as a placeholder. public void WriteTagHelperProperty_DesignTime_StringProperty_NonHtmlContent_RendersCorrectly() { // Arrange var extension = new DefaultTagHelperTargetExtension() { DesignTime = true }; var context = TestCodeRenderingContext.CreateDesignTime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperPropertyIntermediateNode() { AttributeName = "bound", AttributeStructure = AttributeStructure.DoubleQuotes, BoundAttribute = StringPropertyTagHelper.BoundAttributes.Single(), FieldName = "__InputTagHelper", IsIndexerNameMatch = false, PropertyName = "StringProp", TagHelper = StringPropertyTagHelper, Children = { new CSharpExpressionIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.CSharp, Content = "\"3+5\"", } }, } } }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperProperty(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"Render Children __InputTagHelper.StringProp = string.Empty; ", csharp, ignoreLineEndingDifferences: true); }
public void WriteTagHelperHtmlAttribute_Runtime_DynamicAttribute_RendersCorrectly() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperHtmlAttributeIntermediateNode() { AttributeName = "name", AttributeStructure = AttributeStructure.DoubleQuotes, Children = { new HtmlAttributeValueIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.Html, Content = "Blah-" } } }, new CSharpCodeAttributeValueIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.CSharp, Content = "\"Foo\"", } }, } } }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperHtmlAttribute(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"BeginAddHtmlAttributeValues(__tagHelperExecutionContext, ""name"", 2, global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes); Render Children Render Children EndAddHtmlAttributeValues(__tagHelperExecutionContext); ", csharp, ignoreLineEndingDifferences: true); }
public void WriteTagHelperProperty_DesignTime_NonStringProperty_SecondUseOfAttribute() { // Arrange var extension = new DefaultTagHelperTargetExtension() { DesignTime = true }; var context = TestCodeRenderingContext.CreateDesignTime(); var tagHelperNode = new TagHelperIntermediateNode(); var node1 = new DefaultTagHelperPropertyIntermediateNode() { // We only look at the attribute name here. AttributeName = "bound", FieldName = "__OtherTagHelper", PropertyName = "IntProp", }; var node2 = new DefaultTagHelperPropertyIntermediateNode() { AttributeName = "bound", AttributeStructure = AttributeStructure.DoubleQuotes, BoundAttribute = IntPropertyTagHelper.BoundAttributes.Single(), FieldName = "__InputTagHelper", IsIndexerNameMatch = false, PropertyName = "IntProp", TagHelper = IntPropertyTagHelper, Source = Span, }; tagHelperNode.Children.Add(node1); tagHelperNode.Children.Add(node2); Push(context, tagHelperNode); // Act extension.WriteTagHelperProperty(context, node2); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"__InputTagHelper.IntProp = __OtherTagHelper.IntProp; ", csharp, ignoreLineEndingDifferences: true); }
public void WriteTagHelperProperty_RendersCorrectly() { // Arrange var extension = new PreallocatedAttributeTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, "FooTagHelper", "Test"); tagHelperBuilder.TypeName("FooTagHelper"); var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind); builder .Name("Foo") .TypeName("System.String") .PropertyName("FooProp"); var descriptor = builder.Build(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new PreallocatedTagHelperPropertyIntermediateNode() { AttributeName = descriptor.Name, BoundAttribute = descriptor, FieldName = "__FooTagHelper", PropertyName = "FooProp", VariableName = "_tagHelper1", }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperProperty(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"__FooTagHelper.FooProp = (string)_tagHelper1.Value; __tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1); ", csharp, ignoreLineEndingDifferences: true); }
public override void VisitTagHelper(TagHelperIntermediateNode node) { if (node.Source != null) { Items.Add(new InstrumentationItem(node, Parent, isLiteral: false, source: node.Source.Value)); } // Inside a tag helper we only want to visit inside of the body (skip all of the attributes and properties). for (var i = 0; i < node.Children.Count; i++) { var child = node.Children[i]; if (child is TagHelperBodyIntermediateNode || child is DefaultTagHelperBodyIntermediateNode) { VisitDefault(child); } } }
public void WriteTagHelperProperty_Runtime_NonStringProperty_RendersCorrectly_WithoutLocation() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperPropertyIntermediateNode() { AttributeName = "bound", AttributeStructure = AttributeStructure.DoubleQuotes, BoundAttribute = IntPropertyTagHelper.BoundAttributes.Single(), FieldName = "__InputTagHelper", IsIndexerNameMatch = false, PropertyName = "IntProp", TagHelper = IntPropertyTagHelper, Children = { new CSharpExpressionIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.CSharp, Content = "32", } }, } } }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperProperty(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"__InputTagHelper.IntProp = 32; __tagHelperExecutionContext.AddTagHelperAttribute(""bound"", __InputTagHelper.IntProp, global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes); ", csharp, ignoreLineEndingDifferences: true); }
private MarkupElementIntermediateNode RewriteAsElement(TagHelperIntermediateNode node) { var result = new MarkupElementIntermediateNode() { Source = node.Source, TagName = node.TagName, }; for (var i = 0; i < node.Diagnostics.Count; i++) { result.Diagnostics.Add(node.Diagnostics[i]); } var visitor = new ElementRewriteVisitor(result.Children); visitor.Visit(node); return(result); }