Rewrite of code rendering context
This commit is contained in:
parent
8dfba25d59
commit
7408bcd025
|
|
@ -2,6 +2,7 @@
|
||||||
// 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;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
|
namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
|
||||||
|
|
@ -18,11 +19,15 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
|
||||||
public abstract string DocumentKind { get; }
|
public abstract string DocumentKind { get; }
|
||||||
|
|
||||||
public abstract ItemCollection Items { get; }
|
public abstract ItemCollection Items { get; }
|
||||||
|
|
||||||
|
public abstract IEnumerable<IntermediateNode> Ancestors { get; }
|
||||||
|
|
||||||
public abstract IntermediateNodeWriter NodeWriter { get; }
|
public abstract IntermediateNodeWriter NodeWriter { get; }
|
||||||
|
|
||||||
public abstract RazorCodeGenerationOptions Options { get; }
|
public abstract RazorCodeGenerationOptions Options { get; }
|
||||||
|
|
||||||
|
public abstract IntermediateNode Parent { get; }
|
||||||
|
|
||||||
public abstract RazorSourceDocument SourceDocument { get; }
|
public abstract RazorSourceDocument SourceDocument { get; }
|
||||||
|
|
||||||
public abstract Scope CreateScope();
|
public abstract Scope CreateScope();
|
||||||
|
|
@ -56,48 +61,5 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
|
||||||
_context.EndScope();
|
_context.EndScope();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// All bits below here are temporary
|
|
||||||
|
|
||||||
#region Temporary TagHelper bits
|
|
||||||
|
|
||||||
internal TagHelperRenderingContext TagHelperRenderingContext { get; set; }
|
|
||||||
|
|
||||||
internal TagHelperRenderingContextScope Push(TagHelperRenderingContext context)
|
|
||||||
{
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
var scope = new TagHelperRenderingContextScope(this, TagHelperRenderingContext);
|
|
||||||
TagHelperRenderingContext = context;
|
|
||||||
return scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal struct TagHelperRenderingContextScope : IDisposable
|
|
||||||
{
|
|
||||||
private readonly CodeRenderingContext _context;
|
|
||||||
private readonly TagHelperRenderingContext _renderingContext;
|
|
||||||
|
|
||||||
public TagHelperRenderingContextScope(CodeRenderingContext context, TagHelperRenderingContext renderingContext)
|
|
||||||
{
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
_context = context;
|
|
||||||
_renderingContext = renderingContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_context.TagHelperRenderingContext = _renderingContext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
|
||||||
{
|
{
|
||||||
internal class DefaultCodeRenderingContext : CodeRenderingContext
|
internal class DefaultCodeRenderingContext : CodeRenderingContext
|
||||||
{
|
{
|
||||||
|
private readonly Stack<IntermediateNode> _ancestors;
|
||||||
private readonly RazorCodeDocument _codeDocument;
|
private readonly RazorCodeDocument _codeDocument;
|
||||||
private readonly DocumentIntermediateNode _documentNode;
|
private readonly DocumentIntermediateNode _documentNode;
|
||||||
|
|
||||||
private readonly List<ScopeInternal> _scopes;
|
private readonly List<ScopeInternal> _scopes;
|
||||||
|
|
||||||
public DefaultCodeRenderingContext(
|
public DefaultCodeRenderingContext(
|
||||||
|
|
@ -52,12 +52,11 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
|
||||||
_documentNode = documentNode;
|
_documentNode = documentNode;
|
||||||
Options = options;
|
Options = options;
|
||||||
|
|
||||||
|
_ancestors = new Stack<IntermediateNode>();
|
||||||
Diagnostics = new RazorDiagnosticCollection();
|
Diagnostics = new RazorDiagnosticCollection();
|
||||||
Items = new ItemCollection();
|
Items = new ItemCollection();
|
||||||
LineMappings = new List<LineMapping>();
|
LineMappings = new List<LineMapping>();
|
||||||
|
|
||||||
TagHelperRenderingContext = new TagHelperRenderingContext();
|
|
||||||
|
|
||||||
var diagnostics = _documentNode.GetAllDiagnostics();
|
var diagnostics = _documentNode.GetAllDiagnostics();
|
||||||
for (var i = 0; i < diagnostics.Count; i++)
|
for (var i = 0; i < diagnostics.Count; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -81,6 +80,10 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
|
||||||
// This will be initialized by the document writer when the context is 'live'.
|
// This will be initialized by the document writer when the context is 'live'.
|
||||||
public IntermediateNodeVisitor Visitor { get; set; }
|
public IntermediateNodeVisitor Visitor { get; set; }
|
||||||
|
|
||||||
|
public override IEnumerable<IntermediateNode> Ancestors => _ancestors;
|
||||||
|
|
||||||
|
internal Stack<IntermediateNode> AncestorsInternal => _ancestors;
|
||||||
|
|
||||||
public override CodeWriter CodeWriter { get; }
|
public override CodeWriter CodeWriter { get; }
|
||||||
|
|
||||||
public override RazorDiagnosticCollection Diagnostics { get; }
|
public override RazorDiagnosticCollection Diagnostics { get; }
|
||||||
|
|
@ -95,6 +98,8 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
|
||||||
|
|
||||||
public override RazorCodeGenerationOptions Options { get; }
|
public override RazorCodeGenerationOptions Options { get; }
|
||||||
|
|
||||||
|
public override IntermediateNode Parent => _ancestors.Count == 0 ? null : _ancestors.Peek();
|
||||||
|
|
||||||
public override RazorSourceDocument SourceDocument => _codeDocument.Source;
|
public override RazorSourceDocument SourceDocument => _codeDocument.Source;
|
||||||
|
|
||||||
private ScopeInternal Current => _scopes[_scopes.Count - 1];
|
private ScopeInternal Current => _scopes[_scopes.Count - 1];
|
||||||
|
|
@ -154,10 +159,14 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
|
||||||
throw new ArgumentNullException(nameof(node));
|
throw new ArgumentNullException(nameof(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ancestors.Push(node);
|
||||||
|
|
||||||
for (var i = 0; i < node.Children.Count; i++)
|
for (var i = 0; i < node.Children.Count; i++)
|
||||||
{
|
{
|
||||||
Visitor.Visit(node.Children[i]);
|
Visitor.Visit(node.Children[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ancestors.Pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RenderNode(IntermediateNode node)
|
public override void RenderNode(IntermediateNode node)
|
||||||
|
|
|
||||||
|
|
@ -200,12 +200,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
|
||||||
|
|
||||||
public override void VisitTagHelper(TagHelperIntermediateNode node)
|
public override void VisitTagHelper(TagHelperIntermediateNode node)
|
||||||
{
|
{
|
||||||
var tagHelperRenderingContext = new TagHelperRenderingContext();
|
VisitDefault(node);
|
||||||
|
|
||||||
using (Context.Push(tagHelperRenderingContext))
|
|
||||||
{
|
|
||||||
VisitDefault(node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void VisitDefault(IntermediateNode node)
|
public override void VisitDefault(IntermediateNode node)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// 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;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
@ -75,6 +76,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
|
|
||||||
public void WriteTagHelperBody(CodeRenderingContext context, DefaultTagHelperBodyIntermediateNode node)
|
public void WriteTagHelperBody(CodeRenderingContext context, DefaultTagHelperBodyIntermediateNode node)
|
||||||
{
|
{
|
||||||
|
if (context.Parent as TagHelperIntermediateNode == null)
|
||||||
|
{
|
||||||
|
var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode));
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
if (DesignTime)
|
if (DesignTime)
|
||||||
{
|
{
|
||||||
context.RenderChildren(node);
|
context.RenderChildren(node);
|
||||||
|
|
@ -121,6 +128,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
|
|
||||||
public void WriteTagHelperCreate(CodeRenderingContext context, DefaultTagHelperCreateIntermediateNode node)
|
public void WriteTagHelperCreate(CodeRenderingContext context, DefaultTagHelperCreateIntermediateNode node)
|
||||||
{
|
{
|
||||||
|
if (context.Parent as TagHelperIntermediateNode == null)
|
||||||
|
{
|
||||||
|
var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode));
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
context.CodeWriter
|
context.CodeWriter
|
||||||
.WriteStartAssignment(node.Field)
|
.WriteStartAssignment(node.Field)
|
||||||
.Write(CreateTagHelperMethodName)
|
.Write(CreateTagHelperMethodName)
|
||||||
|
|
@ -137,6 +150,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
|
|
||||||
public void WriteTagHelperExecute(CodeRenderingContext context, DefaultTagHelperExecuteIntermediateNode node)
|
public void WriteTagHelperExecute(CodeRenderingContext context, DefaultTagHelperExecuteIntermediateNode node)
|
||||||
{
|
{
|
||||||
|
if (context.Parent as TagHelperIntermediateNode == null)
|
||||||
|
{
|
||||||
|
var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode));
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
if (!DesignTime)
|
if (!DesignTime)
|
||||||
{
|
{
|
||||||
context.CodeWriter
|
context.CodeWriter
|
||||||
|
|
@ -178,6 +197,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
|
|
||||||
public void WriteTagHelperHtmlAttribute(CodeRenderingContext context, DefaultTagHelperHtmlAttributeIntermediateNode node)
|
public void WriteTagHelperHtmlAttribute(CodeRenderingContext context, DefaultTagHelperHtmlAttributeIntermediateNode node)
|
||||||
{
|
{
|
||||||
|
if (context.Parent as TagHelperIntermediateNode == null)
|
||||||
|
{
|
||||||
|
var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode));
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
if (DesignTime)
|
if (DesignTime)
|
||||||
{
|
{
|
||||||
context.RenderChildren(node);
|
context.RenderChildren(node);
|
||||||
|
|
@ -261,22 +286,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
|
|
||||||
public void WriteTagHelperProperty(CodeRenderingContext context, DefaultTagHelperPropertyIntermediateNode node)
|
public void WriteTagHelperProperty(CodeRenderingContext context, DefaultTagHelperPropertyIntermediateNode node)
|
||||||
{
|
{
|
||||||
var tagHelperRenderingContext = context.TagHelperRenderingContext;
|
var tagHelperNode = context.Parent as TagHelperIntermediateNode;
|
||||||
var propertyName = node.BoundAttribute.GetPropertyName();
|
if (context.Parent == null)
|
||||||
var propertyValueAccessor = GetTagHelperPropertyAccessor(node.IsIndexerNameMatch, node.Field, node.AttributeName, node.BoundAttribute);
|
{
|
||||||
|
var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode));
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
if (!DesignTime)
|
if (!DesignTime)
|
||||||
{
|
{
|
||||||
// Ensure that the property we're trying to set has initialized its dictionary bound properties.
|
// Ensure that the property we're trying to set has initialized its dictionary bound properties.
|
||||||
if (node.IsIndexerNameMatch &&
|
if (node.IsIndexerNameMatch &&
|
||||||
tagHelperRenderingContext.VerifiedPropertyDictionaries.Add($"{node.TagHelper.GetTypeName()}.{propertyName}"))
|
object.ReferenceEquals(FindFirstUseOfIndexer(tagHelperNode, node), node))
|
||||||
{
|
{
|
||||||
// Throw a reasonable Exception at runtime if the dictionary property is null.
|
// Throw a reasonable Exception at runtime if the dictionary property is null.
|
||||||
context.CodeWriter
|
context.CodeWriter
|
||||||
.Write("if (")
|
.Write("if (")
|
||||||
.Write(node.Field)
|
.Write(node.Field)
|
||||||
.Write(".")
|
.Write(".")
|
||||||
.Write(propertyName)
|
.Write(node.Property)
|
||||||
.WriteLine(" == null)");
|
.WriteLine(" == null)");
|
||||||
using (context.CodeWriter.BuildScope())
|
using (context.CodeWriter.BuildScope())
|
||||||
{
|
{
|
||||||
|
|
@ -290,34 +318,40 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
.WriteParameterSeparator()
|
.WriteParameterSeparator()
|
||||||
.WriteStringLiteral(node.TagHelper.GetTypeName())
|
.WriteStringLiteral(node.TagHelper.GetTypeName())
|
||||||
.WriteParameterSeparator()
|
.WriteParameterSeparator()
|
||||||
.WriteStringLiteral(propertyName)
|
.WriteStringLiteral(node.Property)
|
||||||
.WriteEndMethodInvocation(endLine: false) // End of method call
|
.WriteEndMethodInvocation(endLine: false) // End of method call
|
||||||
.WriteEndMethodInvocation(); // End of new expression / throw statement
|
.WriteEndMethodInvocation(); // End of new expression / throw statement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagHelperRenderingContext.RenderedBoundAttributes.TryGetValue(node.AttributeName, out var previousValueAccessor))
|
// If this is not the first use of the attribute value, we need to evaluate the expression and assign it to
|
||||||
|
// the tag helper property.
|
||||||
|
//
|
||||||
|
// Otherwise, the value has already been computed and assigned to another tag helper. We just need to
|
||||||
|
// copy from that tag helper to this one.
|
||||||
|
//
|
||||||
|
// This is important because we can't evaluate the expression twice due to side-effects.
|
||||||
|
var firstUseOfAttribute = FindFirstUseOfAttribute(tagHelperNode, node);
|
||||||
|
if (!object.ReferenceEquals(firstUseOfAttribute, node))
|
||||||
{
|
{
|
||||||
|
// If we get here, this value has already been used. We just need to copy the value.
|
||||||
context.CodeWriter
|
context.CodeWriter
|
||||||
.WriteStartAssignment(propertyValueAccessor)
|
.WriteStartAssignment(GetPropertyAccessor(node))
|
||||||
.Write(previousValueAccessor)
|
.Write(GetPropertyAccessor(firstUseOfAttribute))
|
||||||
.WriteLine(";");
|
.WriteLine(";");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
tagHelperRenderingContext.RenderedBoundAttributes[node.AttributeName] = propertyValueAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// If we get there, this is the first time seeing this property so we need to evaluate the expression.
|
||||||
if (node.BoundAttribute.IsStringProperty || (node.IsIndexerNameMatch && node.BoundAttribute.IsIndexerStringProperty))
|
if (node.BoundAttribute.IsStringProperty || (node.IsIndexerNameMatch && node.BoundAttribute.IsIndexerStringProperty))
|
||||||
{
|
{
|
||||||
if (DesignTime)
|
if (DesignTime)
|
||||||
{
|
{
|
||||||
context.RenderChildren(node);
|
context.RenderChildren(node);
|
||||||
|
|
||||||
context.CodeWriter.WriteStartAssignment(propertyValueAccessor);
|
context.CodeWriter.WriteStartAssignment(GetPropertyAccessor(node));
|
||||||
if (node.Children.Count == 1 && node.Children.First() is HtmlContentIntermediateNode htmlNode)
|
if (node.Children.Count == 1 && node.Children.First() is HtmlContentIntermediateNode htmlNode)
|
||||||
{
|
{
|
||||||
var content = GetContent(htmlNode);
|
var content = GetContent(htmlNode);
|
||||||
|
|
@ -341,7 +375,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
context.CodeWriter
|
context.CodeWriter
|
||||||
.WriteStartAssignment(StringValueBufferVariableName)
|
.WriteStartAssignment(StringValueBufferVariableName)
|
||||||
.WriteMethodInvocation(EndWriteTagHelperAttributeMethodName)
|
.WriteMethodInvocation(EndWriteTagHelperAttributeMethodName)
|
||||||
.WriteStartAssignment(propertyValueAccessor)
|
.WriteStartAssignment(GetPropertyAccessor(node))
|
||||||
.Write(StringValueBufferVariableName)
|
.Write(StringValueBufferVariableName)
|
||||||
.WriteLine(";");
|
.WriteLine(";");
|
||||||
}
|
}
|
||||||
|
|
@ -355,7 +389,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
|
|
||||||
using (context.CodeWriter.BuildLinePragma(node.Source))
|
using (context.CodeWriter.BuildLinePragma(node.Source))
|
||||||
{
|
{
|
||||||
var assignmentPrefixLength = propertyValueAccessor.Length + " = ".Length;
|
var accessor = GetPropertyAccessor(node);
|
||||||
|
var assignmentPrefixLength = accessor.Length + " = ".Length;
|
||||||
if (node.BoundAttribute.IsEnum &&
|
if (node.BoundAttribute.IsEnum &&
|
||||||
node.Children.Count == 1 &&
|
node.Children.Count == 1 &&
|
||||||
node.Children.First() is IntermediateToken token &&
|
node.Children.First() is IntermediateToken token &&
|
||||||
|
|
@ -369,7 +404,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
context.CodeWriter
|
context.CodeWriter
|
||||||
.WriteStartAssignment(propertyValueAccessor)
|
.WriteStartAssignment(accessor)
|
||||||
.Write("global::")
|
.Write("global::")
|
||||||
.Write(node.BoundAttribute.TypeName)
|
.Write(node.BoundAttribute.TypeName)
|
||||||
.Write(".");
|
.Write(".");
|
||||||
|
|
@ -381,7 +416,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
context.CodeWriter.WritePadding(assignmentPrefixLength, node.Source, context);
|
context.CodeWriter.WritePadding(assignmentPrefixLength, node.Source, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.CodeWriter.WriteStartAssignment(propertyValueAccessor);
|
context.CodeWriter.WriteStartAssignment(GetPropertyAccessor(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderTagHelperAttributeInline(context, node, node.Source);
|
RenderTagHelperAttributeInline(context, node, node.Source);
|
||||||
|
|
@ -393,7 +428,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
{
|
{
|
||||||
using (context.CodeWriter.BuildLinePragma(node.Source))
|
using (context.CodeWriter.BuildLinePragma(node.Source))
|
||||||
{
|
{
|
||||||
context.CodeWriter.WriteStartAssignment(propertyValueAccessor);
|
context.CodeWriter.WriteStartAssignment(GetPropertyAccessor(node));
|
||||||
|
|
||||||
if (node.BoundAttribute.IsEnum &&
|
if (node.BoundAttribute.IsEnum &&
|
||||||
node.Children.Count == 1 &&
|
node.Children.Count == 1 &&
|
||||||
|
|
@ -422,7 +457,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
ExecutionContextAddTagHelperAttributeMethodName)
|
ExecutionContextAddTagHelperAttributeMethodName)
|
||||||
.WriteStringLiteral(node.AttributeName)
|
.WriteStringLiteral(node.AttributeName)
|
||||||
.WriteParameterSeparator()
|
.WriteParameterSeparator()
|
||||||
.Write(propertyValueAccessor)
|
.Write(GetPropertyAccessor(node))
|
||||||
.WriteParameterSeparator()
|
.WriteParameterSeparator()
|
||||||
.Write($"global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.{node.AttributeStructure}")
|
.Write($"global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.{node.AttributeStructure}")
|
||||||
.WriteEndMethodInvocation();
|
.WriteEndMethodInvocation();
|
||||||
|
|
@ -548,6 +583,45 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static DefaultTagHelperPropertyIntermediateNode FindFirstUseOfIndexer(
|
||||||
|
TagHelperIntermediateNode tagHelperNode,
|
||||||
|
DefaultTagHelperPropertyIntermediateNode propertyNode)
|
||||||
|
{
|
||||||
|
Debug.Assert(tagHelperNode.Children.Contains(propertyNode));
|
||||||
|
Debug.Assert(propertyNode.IsIndexerNameMatch);
|
||||||
|
|
||||||
|
for (var i = 0; i < tagHelperNode.Children.Count; i++)
|
||||||
|
{
|
||||||
|
if (tagHelperNode.Children[i] is DefaultTagHelperPropertyIntermediateNode otherPropertyNode &&
|
||||||
|
otherPropertyNode.TagHelper.Equals(propertyNode.TagHelper) &&
|
||||||
|
otherPropertyNode.BoundAttribute.Equals(propertyNode.BoundAttribute) &&
|
||||||
|
otherPropertyNode.IsIndexerNameMatch)
|
||||||
|
{
|
||||||
|
return otherPropertyNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is unreachable, we should find 'propertyNode' in the list of children.
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DefaultTagHelperPropertyIntermediateNode FindFirstUseOfAttribute(
|
||||||
|
TagHelperIntermediateNode tagHelperNode,
|
||||||
|
DefaultTagHelperPropertyIntermediateNode propertyNode)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < tagHelperNode.Children.Count; i++)
|
||||||
|
{
|
||||||
|
if (tagHelperNode.Children[i] is DefaultTagHelperPropertyIntermediateNode otherPropertyNode &&
|
||||||
|
string.Equals(otherPropertyNode.AttributeName, propertyNode.AttributeName, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return otherPropertyNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is unreachable, we should find 'propertyNode' in the list of children.
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
private string GetContent(HtmlContentIntermediateNode node)
|
private string GetContent(HtmlContentIntermediateNode node)
|
||||||
{
|
{
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
@ -562,17 +636,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetTagHelperPropertyAccessor(
|
private static string GetPropertyAccessor(DefaultTagHelperPropertyIntermediateNode node)
|
||||||
bool isIndexerNameMatch,
|
|
||||||
string tagHelperVariableName,
|
|
||||||
string attributeName,
|
|
||||||
BoundAttributeDescriptor descriptor)
|
|
||||||
{
|
{
|
||||||
var propertyAccessor = $"{tagHelperVariableName}.{descriptor.GetPropertyName()}";
|
var propertyAccessor = $"{node.Field}.{node.Property}";
|
||||||
|
|
||||||
if (isIndexerNameMatch)
|
if (node.IsIndexerNameMatch)
|
||||||
{
|
{
|
||||||
var dictionaryKey = attributeName.Substring(descriptor.IndexerNamePrefix.Length);
|
var dictionaryKey = node.AttributeName.Substring(node.BoundAttribute.IndexerNamePrefix.Length);
|
||||||
propertyAccessor += $"[\"{dictionaryKey}\"]";
|
propertyAccessor += $"[\"{dictionaryKey}\"]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
// 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;
|
||||||
|
using System.Diagnostics;
|
||||||
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
|
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
{
|
{
|
||||||
|
|
@ -50,6 +52,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
|
|
||||||
public void WriteTagHelperHtmlAttribute(CodeRenderingContext context, PreallocatedTagHelperHtmlAttributeIntermediateNode node)
|
public void WriteTagHelperHtmlAttribute(CodeRenderingContext context, PreallocatedTagHelperHtmlAttributeIntermediateNode node)
|
||||||
{
|
{
|
||||||
|
if (context.Parent as TagHelperIntermediateNode == null)
|
||||||
|
{
|
||||||
|
var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode));
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
context.CodeWriter
|
context.CodeWriter
|
||||||
.WriteStartInstanceMethodInvocation(ExecutionContextVariableName, ExecutionContextAddHtmlAttributeMethodName)
|
.WriteStartInstanceMethodInvocation(ExecutionContextVariableName, ExecutionContextAddHtmlAttributeMethodName)
|
||||||
.Write(node.VariableName)
|
.Write(node.VariableName)
|
||||||
|
|
@ -75,20 +83,23 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
|
|
||||||
public void WriteTagHelperProperty(CodeRenderingContext context, PreallocatedTagHelperPropertyIntermediateNode node)
|
public void WriteTagHelperProperty(CodeRenderingContext context, PreallocatedTagHelperPropertyIntermediateNode node)
|
||||||
{
|
{
|
||||||
var propertyName = node.BoundAttribute.GetPropertyName();
|
var tagHelperNode = context.Parent as TagHelperIntermediateNode;
|
||||||
var propertyValueAccessor = GetTagHelperPropertyAccessor(node.IsIndexerNameMatch, node.Field, node.AttributeName, node.BoundAttribute);
|
if (tagHelperNode == null)
|
||||||
var attributeValueAccessor = $"{node.VariableName}.Value" /* ORIGINAL: TagHelperAttributeValuePropertyName */;
|
{
|
||||||
|
var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode));
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that the property we're trying to set has initialized its dictionary bound properties.
|
// Ensure that the property we're trying to set has initialized its dictionary bound properties.
|
||||||
if (node.IsIndexerNameMatch &&
|
if (node.IsIndexerNameMatch &&
|
||||||
context.TagHelperRenderingContext.VerifiedPropertyDictionaries.Add($"{node.TagHelper.GetTypeName()}.{propertyName}"))
|
object.ReferenceEquals(FindFirstUseOfIndexer(tagHelperNode, node), node))
|
||||||
{
|
{
|
||||||
// Throw a reasonable Exception at runtime if the dictionary property is null.
|
// Throw a reasonable Exception at runtime if the dictionary property is null.
|
||||||
context.CodeWriter
|
context.CodeWriter
|
||||||
.Write("if (")
|
.Write("if (")
|
||||||
.Write(node.Field)
|
.Write(node.Field)
|
||||||
.Write(".")
|
.Write(".")
|
||||||
.Write(propertyName)
|
.Write(node.Property)
|
||||||
.WriteLine(" == null)");
|
.WriteLine(" == null)");
|
||||||
using (context.CodeWriter.BuildScope())
|
using (context.CodeWriter.BuildScope())
|
||||||
{
|
{
|
||||||
|
|
@ -102,33 +113,51 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
.WriteParameterSeparator()
|
.WriteParameterSeparator()
|
||||||
.WriteStringLiteral(node.TagHelper.GetTypeName())
|
.WriteStringLiteral(node.TagHelper.GetTypeName())
|
||||||
.WriteParameterSeparator()
|
.WriteParameterSeparator()
|
||||||
.WriteStringLiteral(propertyName)
|
.WriteStringLiteral(node.Property)
|
||||||
.WriteEndMethodInvocation(endLine: false) // End of method call
|
.WriteEndMethodInvocation(endLine: false) // End of method call
|
||||||
.WriteEndMethodInvocation(); // End of new expression / throw statement
|
.WriteEndMethodInvocation(); // End of new expression / throw statement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.CodeWriter
|
context.CodeWriter
|
||||||
.WriteStartAssignment(propertyValueAccessor)
|
.WriteStartAssignment(GetPropertyAccessor(node))
|
||||||
.Write("(string)")
|
.Write("(string)")
|
||||||
.Write(attributeValueAccessor)
|
.Write($"{node.VariableName}.Value")
|
||||||
.WriteLine(";")
|
.WriteLine(";")
|
||||||
.WriteStartInstanceMethodInvocation(ExecutionContextVariableName, ExecutionContextAddTagHelperAttributeMethodName)
|
.WriteStartInstanceMethodInvocation(ExecutionContextVariableName, ExecutionContextAddTagHelperAttributeMethodName)
|
||||||
.Write(node.VariableName)
|
.Write(node.VariableName)
|
||||||
.WriteEndMethodInvocation();
|
.WriteEndMethodInvocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetTagHelperPropertyAccessor(
|
private static PreallocatedTagHelperPropertyIntermediateNode FindFirstUseOfIndexer(
|
||||||
bool isIndexerNameMatch,
|
TagHelperIntermediateNode tagHelperNode,
|
||||||
string tagHelperVariableName,
|
PreallocatedTagHelperPropertyIntermediateNode propertyNode)
|
||||||
string attributeName,
|
|
||||||
BoundAttributeDescriptor descriptor)
|
|
||||||
{
|
{
|
||||||
var propertyAccessor = $"{tagHelperVariableName}.{descriptor.GetPropertyName()}";
|
Debug.Assert(tagHelperNode.Children.Contains(propertyNode));
|
||||||
|
Debug.Assert(propertyNode.IsIndexerNameMatch);
|
||||||
|
|
||||||
if (isIndexerNameMatch)
|
for (var i = 0; i < tagHelperNode.Children.Count; i++)
|
||||||
{
|
{
|
||||||
var dictionaryKey = attributeName.Substring(descriptor.IndexerNamePrefix.Length);
|
if (tagHelperNode.Children[i] is PreallocatedTagHelperPropertyIntermediateNode otherPropertyNode &&
|
||||||
|
otherPropertyNode.TagHelper.Equals(propertyNode.TagHelper) &&
|
||||||
|
otherPropertyNode.BoundAttribute.Equals(propertyNode.BoundAttribute) &&
|
||||||
|
otherPropertyNode.IsIndexerNameMatch)
|
||||||
|
{
|
||||||
|
return otherPropertyNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is unreachable, we should find 'propertyNode' in the list of children.
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetPropertyAccessor(PreallocatedTagHelperPropertyIntermediateNode node)
|
||||||
|
{
|
||||||
|
var propertyAccessor = $"{node.Field}.{node.Property}";
|
||||||
|
|
||||||
|
if (node.IsIndexerNameMatch)
|
||||||
|
{
|
||||||
|
var dictionaryKey = node.AttributeName.Substring(node.BoundAttribute.IndexerNamePrefix.Length);
|
||||||
propertyAccessor += $"[\"{dictionaryKey}\"]";
|
propertyAccessor += $"[\"{dictionaryKey}\"]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -584,6 +584,20 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
internal static string FormatRenderingContextRequiresDelegate(object p0, object p1)
|
internal static string FormatRenderingContextRequiresDelegate(object p0, object p1)
|
||||||
=> string.Format(CultureInfo.CurrentCulture, GetString("RenderingContextRequiresDelegate"), p0, p1);
|
=> string.Format(CultureInfo.CurrentCulture, GetString("RenderingContextRequiresDelegate"), p0, p1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The '{0}' node type can only be used as a direct child of a '{1}' node.
|
||||||
|
/// </summary>
|
||||||
|
internal static string IntermediateNodes_InvalidParentNode
|
||||||
|
{
|
||||||
|
get => GetString("IntermediateNodes_InvalidParentNode");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The '{0}' node type can only be used as a direct child of a '{1}' node.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatIntermediateNodes_InvalidParentNode(object p0, object p1)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("IntermediateNodes_InvalidParentNode"), p0, p1);
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -240,4 +240,7 @@
|
||||||
<data name="RenderingContextRequiresDelegate" xml:space="preserve">
|
<data name="RenderingContextRequiresDelegate" xml:space="preserve">
|
||||||
<value>The '{0}' requires a '{1}' delegate to be set.</value>
|
<value>The '{0}' requires a '{1}' delegate to be set.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="IntermediateNodes_InvalidParentNode" xml:space="preserve">
|
||||||
|
<value>The '{0}' node type can only be used as a direct child of a '{1}' node.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -71,6 +71,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperBodyIntermediateNode()
|
var node = new DefaultTagHelperBodyIntermediateNode()
|
||||||
{
|
{
|
||||||
Children =
|
Children =
|
||||||
|
|
@ -78,6 +79,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
new CSharpExpressionIntermediateNode(),
|
new CSharpExpressionIntermediateNode(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperBody(context, node);
|
extension.WriteTagHelperBody(context, node);
|
||||||
|
|
@ -98,6 +101,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperBodyIntermediateNode()
|
var node = new DefaultTagHelperBodyIntermediateNode()
|
||||||
{
|
{
|
||||||
Children =
|
Children =
|
||||||
|
|
@ -107,6 +111,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
TagMode = TagMode.SelfClosing,
|
TagMode = TagMode.SelfClosing,
|
||||||
TagName = "p",
|
TagName = "p",
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperBody(context, node);
|
extension.WriteTagHelperBody(context, node);
|
||||||
|
|
@ -130,11 +136,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperCreateIntermediateNode()
|
var node = new DefaultTagHelperCreateIntermediateNode()
|
||||||
{
|
{
|
||||||
Field = "__TestNamespace_MyTagHelper",
|
Field = "__TestNamespace_MyTagHelper",
|
||||||
Type = "TestNamespace.MyTagHelper",
|
Type = "TestNamespace.MyTagHelper",
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperCreate(context, node);
|
extension.WriteTagHelperCreate(context, node);
|
||||||
|
|
@ -155,11 +164,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperCreateIntermediateNode()
|
var node = new DefaultTagHelperCreateIntermediateNode()
|
||||||
{
|
{
|
||||||
Field = "__TestNamespace_MyTagHelper",
|
Field = "__TestNamespace_MyTagHelper",
|
||||||
Type = "TestNamespace.MyTagHelper",
|
Type = "TestNamespace.MyTagHelper",
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperCreate(context, node);
|
extension.WriteTagHelperCreate(context, node);
|
||||||
|
|
@ -181,7 +193,10 @@ __tagHelperExecutionContext.Add(__TestNamespace_MyTagHelper);
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperExecuteIntermediateNode();
|
var node = new DefaultTagHelperExecuteIntermediateNode();
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperExecute(context, node);
|
extension.WriteTagHelperExecute(context, node);
|
||||||
|
|
@ -201,7 +216,10 @@ __tagHelperExecutionContext.Add(__TestNamespace_MyTagHelper);
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperExecuteIntermediateNode();
|
var node = new DefaultTagHelperExecuteIntermediateNode();
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperExecute(context, node);
|
extension.WriteTagHelperExecute(context, node);
|
||||||
|
|
@ -228,6 +246,7 @@ __tagHelperExecutionContext = __tagHelperScopeManager.End();
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperHtmlAttributeIntermediateNode()
|
var node = new DefaultTagHelperHtmlAttributeIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "name",
|
AttributeName = "name",
|
||||||
|
|
@ -244,6 +263,8 @@ __tagHelperExecutionContext = __tagHelperScopeManager.End();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperHtmlAttribute(context, node);
|
extension.WriteTagHelperHtmlAttribute(context, node);
|
||||||
|
|
@ -265,6 +286,7 @@ Render Children
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperHtmlAttributeIntermediateNode()
|
var node = new DefaultTagHelperHtmlAttributeIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "name",
|
AttributeName = "name",
|
||||||
|
|
@ -277,6 +299,8 @@ Render Children
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperHtmlAttribute(context, node);
|
extension.WriteTagHelperHtmlAttribute(context, node);
|
||||||
|
|
@ -300,6 +324,7 @@ __tagHelperExecutionContext.AddHtmlAttribute(""name"", Html.Raw(__tagHelperStrin
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperHtmlAttributeIntermediateNode()
|
var node = new DefaultTagHelperHtmlAttributeIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "name",
|
AttributeName = "name",
|
||||||
|
|
@ -316,6 +341,8 @@ __tagHelperExecutionContext.AddHtmlAttribute(""name"", Html.Raw(__tagHelperStrin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperHtmlAttribute(context, node);
|
extension.WriteTagHelperHtmlAttribute(context, node);
|
||||||
|
|
@ -339,6 +366,7 @@ EndAddHtmlAttributeValues(__tagHelperExecutionContext);
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "bound",
|
AttributeName = "bound",
|
||||||
|
|
@ -356,6 +384,8 @@ EndAddHtmlAttributeValues(__tagHelperExecutionContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -377,6 +407,7 @@ __InputTagHelper.StringProp = ""value"";
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "bound",
|
AttributeName = "bound",
|
||||||
|
|
@ -394,6 +425,8 @@ __InputTagHelper.StringProp = ""value"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -415,6 +448,7 @@ __InputTagHelper.StringProp = string.Empty;
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "bound",
|
AttributeName = "bound",
|
||||||
|
|
@ -433,6 +467,8 @@ __InputTagHelper.StringProp = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -450,6 +486,50 @@ __InputTagHelper.IntProp = 32;
|
||||||
ignoreLineEndingDifferences: true);
|
ignoreLineEndingDifferences: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a value is bound to multiple tag helpers, we want to make sure to only render the first
|
||||||
|
// occurrence of the expression due to side-effects.
|
||||||
|
[Fact]
|
||||||
|
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",
|
||||||
|
Field = "__OtherTagHelper",
|
||||||
|
Property = "IntProp",
|
||||||
|
};
|
||||||
|
var node2 = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
|
{
|
||||||
|
AttributeName = "bound",
|
||||||
|
AttributeStructure = AttributeStructure.DoubleQuotes,
|
||||||
|
BoundAttribute = IntPropertyTagHelper.BoundAttributes.Single(),
|
||||||
|
Field = "__InputTagHelper",
|
||||||
|
IsIndexerNameMatch = false,
|
||||||
|
Property = "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.Builder.ToString();
|
||||||
|
Assert.Equal(
|
||||||
|
@"__InputTagHelper.IntProp = __OtherTagHelper.IntProp;
|
||||||
|
",
|
||||||
|
csharp,
|
||||||
|
ignoreLineEndingDifferences: true);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WriteTagHelperProperty_DesignTime_NonStringProperty_RendersCorrectly_WithoutLocation()
|
public void WriteTagHelperProperty_DesignTime_NonStringProperty_RendersCorrectly_WithoutLocation()
|
||||||
{
|
{
|
||||||
|
|
@ -457,6 +537,7 @@ __InputTagHelper.IntProp = 32;
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "bound",
|
AttributeName = "bound",
|
||||||
|
|
@ -474,6 +555,8 @@ __InputTagHelper.IntProp = 32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -494,6 +577,7 @@ __InputTagHelper.IntProp = 32;
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "foo-bound",
|
AttributeName = "foo-bound",
|
||||||
|
|
@ -512,6 +596,8 @@ __InputTagHelper.IntProp = 32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -536,6 +622,7 @@ __InputTagHelper.IntIndexer[""bound""] = 32;
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "foo-bound",
|
AttributeName = "foo-bound",
|
||||||
|
|
@ -553,6 +640,8 @@ __InputTagHelper.IntIndexer[""bound""] = 32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -573,6 +662,7 @@ __InputTagHelper.IntIndexer[""bound""] = 32;
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "bound",
|
AttributeName = "bound",
|
||||||
|
|
@ -590,6 +680,8 @@ __InputTagHelper.IntIndexer[""bound""] = 32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -616,6 +708,7 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""bound"", __InputTagHelper.St
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "bound",
|
AttributeName = "bound",
|
||||||
|
|
@ -634,6 +727,8 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""bound"", __InputTagHelper.St
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -652,6 +747,50 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""bound"", __InputTagHelper.In
|
||||||
ignoreLineEndingDifferences: true);
|
ignoreLineEndingDifferences: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a value is bound to multiple tag helpers, we want to make sure to only render the first
|
||||||
|
// occurrence of the expression due to side-effects.
|
||||||
|
[Fact]
|
||||||
|
public void WriteTagHelperProperty_Runtime_NonStringProperty_SecondUseOfAttribute()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
|
var node1 = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
|
{
|
||||||
|
// We only look at the attribute name here.
|
||||||
|
AttributeName = "bound",
|
||||||
|
Field = "__OtherTagHelper",
|
||||||
|
Property = "IntProp",
|
||||||
|
};
|
||||||
|
var node2 = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
|
{
|
||||||
|
AttributeName = "bound",
|
||||||
|
AttributeStructure = AttributeStructure.DoubleQuotes,
|
||||||
|
BoundAttribute = IntPropertyTagHelper.BoundAttributes.Single(),
|
||||||
|
Field = "__InputTagHelper",
|
||||||
|
IsIndexerNameMatch = false,
|
||||||
|
Property = "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.Builder.ToString();
|
||||||
|
Assert.Equal(
|
||||||
|
@"__InputTagHelper.IntProp = __OtherTagHelper.IntProp;
|
||||||
|
",
|
||||||
|
csharp,
|
||||||
|
ignoreLineEndingDifferences: true);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WriteTagHelperProperty_Runtime_NonStringProperty_RendersCorrectly_WithoutLocation()
|
public void WriteTagHelperProperty_Runtime_NonStringProperty_RendersCorrectly_WithoutLocation()
|
||||||
{
|
{
|
||||||
|
|
@ -659,6 +798,7 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""bound"", __InputTagHelper.In
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "bound",
|
AttributeName = "bound",
|
||||||
|
|
@ -676,6 +816,8 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""bound"", __InputTagHelper.In
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -697,6 +839,7 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""bound"", __InputTagHelper.In
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "foo-bound",
|
AttributeName = "foo-bound",
|
||||||
|
|
@ -715,6 +858,8 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""bound"", __InputTagHelper.In
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -729,6 +874,71 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""bound"", __InputTagHelper.In
|
||||||
#line 3 ""test.cshtml""
|
#line 3 ""test.cshtml""
|
||||||
__InputTagHelper.IntIndexer[""bound""] = 32;
|
__InputTagHelper.IntIndexer[""bound""] = 32;
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
__tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelper.IntIndexer[""bound""], global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes);
|
||||||
|
",
|
||||||
|
csharp,
|
||||||
|
ignoreLineEndingDifferences: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact] // We should only emit the validation code for the first use of an indexer property.
|
||||||
|
public void WriteTagHelperProperty_Runtime_NonStringIndexer_MultipleValues()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
|
var node1 = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
|
{
|
||||||
|
AttributeName = "foo-first",
|
||||||
|
AttributeStructure = AttributeStructure.DoubleQuotes,
|
||||||
|
BoundAttribute = IntIndexerTagHelper.BoundAttributes.Single(),
|
||||||
|
Field = "__InputTagHelper",
|
||||||
|
IsIndexerNameMatch = true,
|
||||||
|
Property = "IntIndexer",
|
||||||
|
TagHelper = IntIndexerTagHelper,
|
||||||
|
Source = Span,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new CSharpExpressionIntermediateNode()
|
||||||
|
{
|
||||||
|
Children = { new IntermediateToken { Kind = IntermediateToken.TokenKind.CSharp, Content = "17", } },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var node2 = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
|
{
|
||||||
|
AttributeName = "foo-bound",
|
||||||
|
AttributeStructure = AttributeStructure.DoubleQuotes,
|
||||||
|
BoundAttribute = IntIndexerTagHelper.BoundAttributes.Single(),
|
||||||
|
Field = "__InputTagHelper",
|
||||||
|
IsIndexerNameMatch = true,
|
||||||
|
Property = "IntIndexer",
|
||||||
|
TagHelper = IntIndexerTagHelper,
|
||||||
|
Source = Span,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new CSharpExpressionIntermediateNode()
|
||||||
|
{
|
||||||
|
Children = { new IntermediateToken { Kind = IntermediateToken.TokenKind.CSharp, Content = "32", } },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tagHelperNode.Children.Add(node1);
|
||||||
|
tagHelperNode.Children.Add(node2);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
extension.WriteTagHelperProperty(context, node2);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var csharp = context.CodeWriter.Builder.ToString();
|
||||||
|
Assert.Equal(
|
||||||
|
@"#line 3 ""test.cshtml""
|
||||||
|
__InputTagHelper.IntIndexer[""bound""] = 32;
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
__tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelper.IntIndexer[""bound""], global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes);
|
__tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelper.IntIndexer[""bound""], global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes);
|
||||||
|
|
@ -744,6 +954,7 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelpe
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new DefaultTagHelperPropertyIntermediateNode()
|
var node = new DefaultTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "foo-bound",
|
AttributeName = "foo-bound",
|
||||||
|
|
@ -761,6 +972,8 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelpe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -785,7 +998,7 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelpe
|
||||||
// Arrange
|
// Arrange
|
||||||
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
|
||||||
var context = TestCodeRenderingContext.CreateDesignTime();
|
var context = TestCodeRenderingContext.CreateDesignTime();
|
||||||
|
|
||||||
var node = new DefaultTagHelperRuntimeIntermediateNode();
|
var node = new DefaultTagHelperRuntimeIntermediateNode();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -805,7 +1018,7 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelpe
|
||||||
// Arrange
|
// Arrange
|
||||||
var extension = new DefaultTagHelperTargetExtension();
|
var extension = new DefaultTagHelperTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
var node = new DefaultTagHelperRuntimeIntermediateNode();
|
var node = new DefaultTagHelperRuntimeIntermediateNode();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -837,6 +1050,11 @@ private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeMana
|
||||||
ignoreLineEndingDifferences: true);
|
ignoreLineEndingDifferences: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void Push(CodeRenderingContext context, TagHelperIntermediateNode node)
|
||||||
|
{
|
||||||
|
((DefaultCodeRenderingContext)context).AncestorsInternal.Push(node);
|
||||||
|
}
|
||||||
|
|
||||||
private static DocumentIntermediateNode Lower(RazorCodeDocument codeDocument)
|
private static DocumentIntermediateNode Lower(RazorCodeDocument codeDocument)
|
||||||
{
|
{
|
||||||
var engine = RazorEngine.Create();
|
var engine = RazorEngine.Create();
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// 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 Microsoft.AspNetCore.Razor.Language.CodeGeneration;
|
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
|
|
@ -9,7 +10,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
public class PreallocatedAttributeTargetExtensionTest
|
public class PreallocatedAttributeTargetExtensionTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WriteDeclarePreallocatedTagHelperHtmlAttribute_RendersCorrectly()
|
public void WriteTagHelperHtmlAttributeValue_RendersCorrectly()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var extension = new PreallocatedAttributeTargetExtension();
|
var extension = new PreallocatedAttributeTargetExtension();
|
||||||
|
|
@ -36,7 +37,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WriteDeclarePreallocatedTagHelperHtmlAttribute_Minimized_RendersCorrectly()
|
public void WriteTagHelperHtmlAttributeValue_Minimized_RendersCorrectly()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var extension = new PreallocatedAttributeTargetExtension();
|
var extension = new PreallocatedAttributeTargetExtension();
|
||||||
|
|
@ -63,16 +64,19 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WriteAddPreallocatedTagHelperHtmlAttribute_RendersCorrectly()
|
public void WriteTagHelperHtmlAttribute_RendersCorrectly()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var extension = new PreallocatedAttributeTargetExtension();
|
var extension = new PreallocatedAttributeTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new PreallocatedTagHelperHtmlAttributeIntermediateNode()
|
var node = new PreallocatedTagHelperHtmlAttributeIntermediateNode()
|
||||||
{
|
{
|
||||||
VariableName = "_tagHelper1"
|
VariableName = "_tagHelper1"
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperHtmlAttribute(context, node);
|
extension.WriteTagHelperHtmlAttribute(context, node);
|
||||||
|
|
@ -87,12 +91,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WriteDeclarePreallocatedTagHelperAttribute_RendersCorrectly()
|
public void WriteTagHelperPropertyValue_RendersCorrectly()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var extension = new PreallocatedAttributeTargetExtension();
|
var extension = new PreallocatedAttributeTargetExtension();
|
||||||
var context = TestCodeRenderingContext.CreateRuntime();
|
var context = TestCodeRenderingContext.CreateRuntime();
|
||||||
|
|
||||||
var node = new PreallocatedTagHelperPropertyValueIntermediateNode()
|
var node = new PreallocatedTagHelperPropertyValueIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "Foo",
|
AttributeName = "Foo",
|
||||||
|
|
@ -114,7 +118,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WriteSetPreallocatedTagHelperProperty_RendersCorrectly()
|
public void WriteTagHelperProperty_RendersCorrectly()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var extension = new PreallocatedAttributeTargetExtension();
|
var extension = new PreallocatedAttributeTargetExtension();
|
||||||
|
|
@ -124,7 +128,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
tagHelperBuilder.TypeName("FooTagHelper");
|
tagHelperBuilder.TypeName("FooTagHelper");
|
||||||
|
|
||||||
var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind);
|
var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind);
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.Name("Foo")
|
.Name("Foo")
|
||||||
.TypeName("System.String")
|
.TypeName("System.String")
|
||||||
|
|
@ -132,13 +135,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
|
|
||||||
var descriptor = builder.Build();
|
var descriptor = builder.Build();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new PreallocatedTagHelperPropertyIntermediateNode()
|
var node = new PreallocatedTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = descriptor.Name,
|
AttributeName = descriptor.Name,
|
||||||
Field = "__FooTagHelper",
|
|
||||||
VariableName = "_tagHelper1",
|
|
||||||
BoundAttribute = descriptor,
|
BoundAttribute = descriptor,
|
||||||
|
Field = "__FooTagHelper",
|
||||||
|
Property = "FooProp",
|
||||||
|
VariableName = "_tagHelper1",
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -164,7 +171,6 @@ __tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1);
|
||||||
tagHelperBuilder.TypeName("FooTagHelper");
|
tagHelperBuilder.TypeName("FooTagHelper");
|
||||||
|
|
||||||
var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind);
|
var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind);
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.Name("Foo")
|
.Name("Foo")
|
||||||
.TypeName("System.Collections.Generic.Dictionary<System.String, System.String>")
|
.TypeName("System.Collections.Generic.Dictionary<System.String, System.String>")
|
||||||
|
|
@ -173,6 +179,7 @@ __tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1);
|
||||||
|
|
||||||
var descriptor = builder.Build();
|
var descriptor = builder.Build();
|
||||||
|
|
||||||
|
var tagHelperNode = new TagHelperIntermediateNode();
|
||||||
var node = new PreallocatedTagHelperPropertyIntermediateNode()
|
var node = new PreallocatedTagHelperPropertyIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = "pre-Foo",
|
AttributeName = "pre-Foo",
|
||||||
|
|
@ -180,8 +187,11 @@ __tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1);
|
||||||
VariableName = "_tagHelper1",
|
VariableName = "_tagHelper1",
|
||||||
BoundAttribute = descriptor,
|
BoundAttribute = descriptor,
|
||||||
IsIndexerNameMatch = true,
|
IsIndexerNameMatch = true,
|
||||||
|
Property = "FooProp",
|
||||||
TagHelper = tagHelperBuilder.Build(),
|
TagHelper = tagHelperBuilder.Build(),
|
||||||
};
|
};
|
||||||
|
tagHelperNode.Children.Add(node);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
extension.WriteTagHelperProperty(context, node);
|
extension.WriteTagHelperProperty(context, node);
|
||||||
|
|
@ -199,5 +209,68 @@ __tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1);
|
||||||
csharp,
|
csharp,
|
||||||
ignoreLineEndingDifferences: true);
|
ignoreLineEndingDifferences: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
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",
|
||||||
|
Field = "__FooTagHelper",
|
||||||
|
VariableName = "_tagHelper0s",
|
||||||
|
BoundAttribute = boundAttribute,
|
||||||
|
IsIndexerNameMatch = true,
|
||||||
|
Property = "FooProp",
|
||||||
|
TagHelper = tagHelper,
|
||||||
|
};
|
||||||
|
var node2 = new PreallocatedTagHelperPropertyIntermediateNode()
|
||||||
|
{
|
||||||
|
AttributeName = "pre-Foo",
|
||||||
|
Field = "__FooTagHelper",
|
||||||
|
VariableName = "_tagHelper1",
|
||||||
|
BoundAttribute = boundAttribute,
|
||||||
|
IsIndexerNameMatch = true,
|
||||||
|
Property = "FooProp",
|
||||||
|
TagHelper = tagHelper,
|
||||||
|
};
|
||||||
|
tagHelperNode.Children.Add(node1);
|
||||||
|
tagHelperNode.Children.Add(node2);
|
||||||
|
Push(context, tagHelperNode);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
extension.WriteTagHelperProperty(context, node2);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var csharp = context.CodeWriter.Builder.ToString();
|
||||||
|
Assert.Equal(
|
||||||
|
@"__FooTagHelper.FooProp[""Foo""] = (string)_tagHelper1.Value;
|
||||||
|
__tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1);
|
||||||
|
",
|
||||||
|
csharp,
|
||||||
|
ignoreLineEndingDifferences: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Push(CodeRenderingContext context, TagHelperIntermediateNode node)
|
||||||
|
{
|
||||||
|
((DefaultCodeRenderingContext)context).AncestorsInternal.Push(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,10 @@ __TestNamespace_InputTagHelper1.IntDictionaryProperty["pepper"] = 98;
|
||||||
__tagHelperExecutionContext.AddTagHelperAttribute(__tagHelperAttribute_5);
|
__tagHelperExecutionContext.AddTagHelperAttribute(__tagHelperAttribute_5);
|
||||||
__TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"] = (string)__tagHelperAttribute_5.Value;
|
__TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"] = (string)__tagHelperAttribute_5.Value;
|
||||||
__tagHelperExecutionContext.AddTagHelperAttribute(__tagHelperAttribute_5);
|
__tagHelperExecutionContext.AddTagHelperAttribute(__tagHelperAttribute_5);
|
||||||
|
if (__TestNamespace_InputTagHelper1.StringDictionaryProperty == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("string-prefix-cumin", "TestNamespace.InputTagHelper1", "StringDictionaryProperty"));
|
||||||
|
}
|
||||||
BeginWriteTagHelperAttribute();
|
BeginWriteTagHelperAttribute();
|
||||||
WriteLiteral("literate ");
|
WriteLiteral("literate ");
|
||||||
#line 21 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PrefixedAttributeTagHelpers.cshtml"
|
#line 21 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PrefixedAttributeTagHelpers.cshtml"
|
||||||
|
|
@ -192,6 +196,10 @@ __TestNamespace_InputTagHelper1.IntDictionaryProperty["pepper"] = 98;
|
||||||
__tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
|
__tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
|
||||||
__TestNamespace_InputTagHelper1.StringDictionaryProperty["cumin"] = __tagHelperStringValueBuffer;
|
__TestNamespace_InputTagHelper1.StringDictionaryProperty["cumin"] = __tagHelperStringValueBuffer;
|
||||||
__tagHelperExecutionContext.AddTagHelperAttribute("string-prefix-cumin", __TestNamespace_InputTagHelper1.StringDictionaryProperty["cumin"], global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes);
|
__tagHelperExecutionContext.AddTagHelperAttribute("string-prefix-cumin", __TestNamespace_InputTagHelper1.StringDictionaryProperty["cumin"], global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes);
|
||||||
|
if (__TestNamespace_InputTagHelper2.StringDictionaryProperty == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("string-prefix-cumin", "TestNamespace.InputTagHelper2", "StringDictionaryProperty"));
|
||||||
|
}
|
||||||
__TestNamespace_InputTagHelper2.StringDictionaryProperty["cumin"] = __TestNamespace_InputTagHelper1.StringDictionaryProperty["cumin"];
|
__TestNamespace_InputTagHelper2.StringDictionaryProperty["cumin"] = __TestNamespace_InputTagHelper1.StringDictionaryProperty["cumin"];
|
||||||
await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
|
await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
|
||||||
if (!__tagHelperExecutionContext.Output.IsContentModified)
|
if (!__tagHelperExecutionContext.Output.IsContentModified)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue