Use an explicit intermediate node for directive attributes (dotnet/aspnetcore-tooling#638)
* Use an explicit intermediate node for directive attributes
* More cleanup
\n\nCommit migrated from f8d7f4cc3b
This commit is contained in:
parent
6be2d3dfcd
commit
c588d53a42
|
|
@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
return isIndexerNameMatch && attribute.IsIndexerBooleanProperty;
|
return isIndexerNameMatch && attribute.IsIndexerBooleanProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool IsDirectiveAttribute(this BoundAttributeDescriptor attribute)
|
public static bool IsDirectiveAttribute(this BoundAttributeDescriptor attribute)
|
||||||
{
|
{
|
||||||
if (attribute == null)
|
if (attribute == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each @bind *usage* we need to rewrite the tag helper node to map to basic constructs.
|
// For each @bind *usage* we need to rewrite the tag helper node to map to basic constructs.
|
||||||
var references = documentNode.FindDescendantReferences<TagHelperPropertyIntermediateNode>();
|
var references = documentNode.FindDescendantReferences<TagHelperDirectiveAttributeIntermediateNode>();
|
||||||
var parameterReferences = documentNode.FindDescendantReferences<TagHelperAttributeParameterIntermediateNode>();
|
var parameterReferences = documentNode.FindDescendantReferences<TagHelperDirectiveAttributeParameterIntermediateNode>();
|
||||||
|
|
||||||
var parents = new HashSet<IntermediateNode>();
|
var parents = new HashSet<IntermediateNode>();
|
||||||
for (var i = 0; i < references.Count; i++)
|
for (var i = 0; i < references.Count; i++)
|
||||||
|
|
@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
var reference = references[i];
|
var reference = references[i];
|
||||||
var parent = reference.Parent;
|
var parent = reference.Parent;
|
||||||
var node = (TagHelperPropertyIntermediateNode)reference.Node;
|
var node = (TagHelperDirectiveAttributeIntermediateNode)reference.Node;
|
||||||
|
|
||||||
if (!parent.Children.Contains(node))
|
if (!parent.Children.Contains(node))
|
||||||
{
|
{
|
||||||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.TagHelper.IsBindTagHelper() && node.IsDirectiveAttribute)
|
if (node.TagHelper.IsBindTagHelper())
|
||||||
{
|
{
|
||||||
bindEntries[(parent, node.AttributeName)] = new BindEntry(reference);
|
bindEntries[(parent, node.AttributeName)] = new BindEntry(reference);
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
var parameterReference = parameterReferences[i];
|
var parameterReference = parameterReferences[i];
|
||||||
var parent = parameterReference.Parent;
|
var parent = parameterReference.Parent;
|
||||||
var node = (TagHelperAttributeParameterIntermediateNode)parameterReference.Node;
|
var node = (TagHelperDirectiveAttributeParameterIntermediateNode)parameterReference.Node;
|
||||||
|
|
||||||
if (!parent.Children.Contains(node))
|
if (!parent.Children.Contains(node))
|
||||||
{
|
{
|
||||||
|
|
@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.TagHelper.IsBindTagHelper() && node.IsDirectiveAttribute)
|
if (node.TagHelper.IsBindTagHelper())
|
||||||
{
|
{
|
||||||
// Check if this tag contains a corresponding non-parameterized bind node.
|
// Check if this tag contains a corresponding non-parameterized bind node.
|
||||||
if (!bindEntries.TryGetValue((parent, node.AttributeNameWithoutParameter), out var entry))
|
if (!bindEntries.TryGetValue((parent, node.AttributeNameWithoutParameter), out var entry))
|
||||||
|
|
@ -140,12 +140,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
TagHelperDescriptor tagHelper = null;
|
TagHelperDescriptor tagHelper = null;
|
||||||
string attributeName = null;
|
string attributeName = null;
|
||||||
var attribute = node.Children[i];
|
var attribute = node.Children[i];
|
||||||
if (attribute is TagHelperPropertyIntermediateNode propertyAttribute)
|
if (attribute is TagHelperDirectiveAttributeIntermediateNode directiveAttribute)
|
||||||
{
|
{
|
||||||
attributeName = propertyAttribute.AttributeName;
|
attributeName = directiveAttribute.AttributeName;
|
||||||
tagHelper = propertyAttribute.TagHelper;
|
tagHelper = directiveAttribute.TagHelper;
|
||||||
}
|
}
|
||||||
else if (attribute is TagHelperAttributeParameterIntermediateNode parameterAttribute)
|
else if (attribute is TagHelperDirectiveAttributeParameterIntermediateNode parameterAttribute)
|
||||||
{
|
{
|
||||||
attributeName = parameterAttribute.AttributeName;
|
attributeName = parameterAttribute.AttributeName;
|
||||||
tagHelper = parameterAttribute.TagHelper;
|
tagHelper = parameterAttribute.TagHelper;
|
||||||
|
|
@ -159,12 +159,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
TagHelperDescriptor duplicateTagHelper = null;
|
TagHelperDescriptor duplicateTagHelper = null;
|
||||||
string duplicateAttributeName = null;
|
string duplicateAttributeName = null;
|
||||||
var duplicate = node.Children[j];
|
var duplicate = node.Children[j];
|
||||||
if (duplicate is TagHelperPropertyIntermediateNode duplicatePropertyAttribute)
|
if (duplicate is TagHelperDirectiveAttributeIntermediateNode duplicateDirectiveAttribute)
|
||||||
{
|
{
|
||||||
duplicateAttributeName = duplicatePropertyAttribute.AttributeName;
|
duplicateAttributeName = duplicateDirectiveAttribute.AttributeName;
|
||||||
duplicateTagHelper = duplicatePropertyAttribute.TagHelper;
|
duplicateTagHelper = duplicateDirectiveAttribute.TagHelper;
|
||||||
}
|
}
|
||||||
else if (duplicate is TagHelperAttributeParameterIntermediateNode duplicateParameterAttribute)
|
else if (duplicate is TagHelperDirectiveAttributeParameterIntermediateNode duplicateParameterAttribute)
|
||||||
{
|
{
|
||||||
duplicateAttributeName = duplicateParameterAttribute.AttributeName;
|
duplicateAttributeName = duplicateParameterAttribute.AttributeName;
|
||||||
duplicateTagHelper = duplicateParameterAttribute.TagHelper;
|
duplicateTagHelper = duplicateParameterAttribute.TagHelper;
|
||||||
|
|
@ -195,12 +195,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
TagHelperDescriptor duplicateTagHelper = null;
|
TagHelperDescriptor duplicateTagHelper = null;
|
||||||
string duplicateAttributeName = null;
|
string duplicateAttributeName = null;
|
||||||
var duplicate = node.Children[j];
|
var duplicate = node.Children[j];
|
||||||
if (duplicate is TagHelperPropertyIntermediateNode duplicatePropertyAttribute)
|
if (duplicate is TagHelperDirectiveAttributeIntermediateNode duplicateDirectiveAttribute)
|
||||||
{
|
{
|
||||||
duplicateAttributeName = duplicatePropertyAttribute.AttributeName;
|
duplicateAttributeName = duplicateDirectiveAttribute.AttributeName;
|
||||||
duplicateTagHelper = duplicatePropertyAttribute.TagHelper;
|
duplicateTagHelper = duplicateDirectiveAttribute.TagHelper;
|
||||||
}
|
}
|
||||||
else if (duplicate is TagHelperAttributeParameterIntermediateNode duplicateParameterAttribute)
|
else if (duplicate is TagHelperDirectiveAttributeParameterIntermediateNode duplicateParameterAttribute)
|
||||||
{
|
{
|
||||||
duplicateAttributeName = duplicateParameterAttribute.AttributeName;
|
duplicateAttributeName = duplicateParameterAttribute.AttributeName;
|
||||||
duplicateTagHelper = duplicateParameterAttribute.TagHelper;
|
duplicateTagHelper = duplicateParameterAttribute.TagHelper;
|
||||||
|
|
@ -222,7 +222,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
|
|
||||||
// If we still have duplicates at this point then they are genuine conflicts.
|
// If we still have duplicates at this point then they are genuine conflicts.
|
||||||
var duplicates = node.Children
|
var duplicates = node.Children
|
||||||
.OfType<TagHelperPropertyIntermediateNode>()
|
.OfType<TagHelperDirectiveAttributeIntermediateNode>()
|
||||||
.GroupBy(p => p.AttributeName)
|
.GroupBy(p => p.AttributeName)
|
||||||
.Where(g => g.Count() > 1);
|
.Where(g => g.Count() > 1);
|
||||||
|
|
||||||
|
|
@ -230,7 +230,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
node.Diagnostics.Add(ComponentDiagnosticFactory.CreateBindAttribute_Duplicates(
|
node.Diagnostics.Add(ComponentDiagnosticFactory.CreateBindAttribute_Duplicates(
|
||||||
node.Source,
|
node.Source,
|
||||||
duplicate.Key,
|
duplicate.First().OriginalAttributeName,
|
||||||
duplicate.ToArray()));
|
duplicate.ToArray()));
|
||||||
foreach (var property in duplicate)
|
foreach (var property in duplicate)
|
||||||
{
|
{
|
||||||
|
|
@ -338,7 +338,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
Annotations =
|
Annotations =
|
||||||
{
|
{
|
||||||
[ComponentMetadata.Common.OriginalAttributeName] = node.AttributeName,
|
[ComponentMetadata.Common.OriginalAttributeName] = node.OriginalAttributeName,
|
||||||
},
|
},
|
||||||
AttributeName = valueAttributeName,
|
AttributeName = valueAttributeName,
|
||||||
Source = node.Source,
|
Source = node.Source,
|
||||||
|
|
@ -362,7 +362,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
Annotations =
|
Annotations =
|
||||||
{
|
{
|
||||||
[ComponentMetadata.Common.OriginalAttributeName] = node.AttributeName,
|
[ComponentMetadata.Common.OriginalAttributeName] = node.OriginalAttributeName,
|
||||||
},
|
},
|
||||||
AttributeName = changeAttributeName,
|
AttributeName = changeAttributeName,
|
||||||
Source = node.Source,
|
Source = node.Source,
|
||||||
|
|
@ -385,7 +385,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
Annotations =
|
Annotations =
|
||||||
{
|
{
|
||||||
[ComponentMetadata.Common.OriginalAttributeName] = node.AttributeName,
|
[ComponentMetadata.Common.OriginalAttributeName] = node.OriginalAttributeName,
|
||||||
},
|
},
|
||||||
AttributeName = valueAttributeName,
|
AttributeName = valueAttributeName,
|
||||||
BoundAttribute = valueAttribute, // Might be null if it doesn't match a component attribute
|
BoundAttribute = valueAttribute, // Might be null if it doesn't match a component attribute
|
||||||
|
|
@ -405,7 +405,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
Annotations =
|
Annotations =
|
||||||
{
|
{
|
||||||
[ComponentMetadata.Common.OriginalAttributeName] = node.AttributeName,
|
[ComponentMetadata.Common.OriginalAttributeName] = node.OriginalAttributeName,
|
||||||
},
|
},
|
||||||
AttributeName = changeAttributeName,
|
AttributeName = changeAttributeName,
|
||||||
BoundAttribute = changeAttribute, // Might be null if it doesn't match a component attribute
|
BoundAttribute = changeAttribute, // Might be null if it doesn't match a component attribute
|
||||||
|
|
@ -430,7 +430,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
Annotations =
|
Annotations =
|
||||||
{
|
{
|
||||||
[ComponentMetadata.Common.OriginalAttributeName] = node.AttributeName,
|
[ComponentMetadata.Common.OriginalAttributeName] = node.OriginalAttributeName,
|
||||||
},
|
},
|
||||||
AttributeName = expressionAttributeName,
|
AttributeName = expressionAttributeName,
|
||||||
BoundAttribute = expressionAttribute,
|
BoundAttribute = expressionAttribute,
|
||||||
|
|
@ -463,7 +463,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
valueAttributeName = null;
|
valueAttributeName = null;
|
||||||
changeAttributeName = null;
|
changeAttributeName = null;
|
||||||
|
|
||||||
if (!attributeName.StartsWith("@bind"))
|
if (!attributeName.StartsWith("bind"))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -473,7 +473,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
changeAttributeName = GetAttributeContent(bindEntry.BindEventNode)?.Content?.Trim('"');
|
changeAttributeName = GetAttributeContent(bindEntry.BindEventNode)?.Content?.Trim('"');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributeName == "@bind")
|
if (attributeName == "bind")
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -591,7 +591,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
|
|
||||||
private bool TryGetFormatNode(
|
private bool TryGetFormatNode(
|
||||||
IntermediateNode node,
|
IntermediateNode node,
|
||||||
TagHelperPropertyIntermediateNode attributeNode,
|
TagHelperDirectiveAttributeIntermediateNode attributeNode,
|
||||||
string valueAttributeName,
|
string valueAttributeName,
|
||||||
out TagHelperPropertyIntermediateNode formatNode)
|
out TagHelperPropertyIntermediateNode formatNode)
|
||||||
{
|
{
|
||||||
|
|
@ -807,16 +807,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
public BindEntry(IntermediateNodeReference bindNodeReference)
|
public BindEntry(IntermediateNodeReference bindNodeReference)
|
||||||
{
|
{
|
||||||
BindNodeReference = bindNodeReference;
|
BindNodeReference = bindNodeReference;
|
||||||
BindNode = (TagHelperPropertyIntermediateNode)bindNodeReference.Node;
|
BindNode = (TagHelperDirectiveAttributeIntermediateNode)bindNodeReference.Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntermediateNodeReference BindNodeReference { get; }
|
public IntermediateNodeReference BindNodeReference { get; }
|
||||||
|
|
||||||
public TagHelperPropertyIntermediateNode BindNode { get; }
|
public TagHelperDirectiveAttributeIntermediateNode BindNode { get; }
|
||||||
|
|
||||||
public TagHelperAttributeParameterIntermediateNode BindEventNode { get; set; }
|
public TagHelperDirectiveAttributeParameterIntermediateNode BindEventNode { get; set; }
|
||||||
|
|
||||||
public TagHelperAttributeParameterIntermediateNode BindFormatNode { get; set; }
|
public TagHelperDirectiveAttributeParameterIntermediateNode BindFormatNode { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
if (node.Children[i] is TagHelperPropertyIntermediateNode propertyNode)
|
if (node.Children[i] is TagHelperPropertyIntermediateNode propertyNode)
|
||||||
{
|
{
|
||||||
if (TrySimplifyContent(propertyNode) && node.TagHelpers.Any(t => t.IsComponentTagHelper()))
|
if (!TrySimplifyContent(propertyNode) && node.TagHelpers.Any(t => t.IsComponentTagHelper()))
|
||||||
{
|
{
|
||||||
node.Diagnostics.Add(ComponentDiagnosticFactory.Create_UnsupportedComplexContent(
|
node.Diagnostics.Add(ComponentDiagnosticFactory.Create_UnsupportedComplexContent(
|
||||||
propertyNode,
|
propertyNode,
|
||||||
|
|
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
}
|
}
|
||||||
else if (node.Children[i] is TagHelperHtmlAttributeIntermediateNode htmlNode)
|
else if (node.Children[i] is TagHelperHtmlAttributeIntermediateNode htmlNode)
|
||||||
{
|
{
|
||||||
if (TrySimplifyContent(htmlNode) && node.TagHelpers.Any(t => t.IsComponentTagHelper()))
|
if (!TrySimplifyContent(htmlNode) && node.TagHelpers.Any(t => t.IsComponentTagHelper()))
|
||||||
{
|
{
|
||||||
node.Diagnostics.Add(ComponentDiagnosticFactory.Create_UnsupportedComplexContent(
|
node.Diagnostics.Add(ComponentDiagnosticFactory.Create_UnsupportedComplexContent(
|
||||||
htmlNode,
|
htmlNode,
|
||||||
|
|
@ -56,6 +56,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (node.Children[i] is TagHelperDirectiveAttributeIntermediateNode directiveAttributeNode)
|
||||||
|
{
|
||||||
|
if (!TrySimplifyContent(directiveAttributeNode))
|
||||||
|
{
|
||||||
|
node.Diagnostics.Add(ComponentDiagnosticFactory.Create_UnsupportedComplexContent(
|
||||||
|
directiveAttributeNode,
|
||||||
|
directiveAttributeNode.OriginalAttributeName));
|
||||||
|
node.Children.RemoveAt(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,7 +77,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
htmlNode.Children.Count > 1)
|
htmlNode.Children.Count > 1)
|
||||||
{
|
{
|
||||||
// This case can be hit for a 'string' attribute
|
// This case can be hit for a 'string' attribute
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
else if (node.Children.Count == 1 &&
|
else if (node.Children.Count == 1 &&
|
||||||
node.Children[0] is CSharpExpressionIntermediateNode cSharpNode &&
|
node.Children[0] is CSharpExpressionIntermediateNode cSharpNode &&
|
||||||
|
|
@ -87,25 +98,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
cSharpNode.Children.RemoveAt(0);
|
cSharpNode.Children.RemoveAt(0);
|
||||||
|
|
||||||
// We were able to simplify it, all good.
|
// We were able to simplify it, all good.
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
else if (node.Children.Count == 1 &&
|
else if (node.Children.Count == 1 &&
|
||||||
node.Children[0] is CSharpCodeIntermediateNode cSharpCodeNode)
|
node.Children[0] is CSharpCodeIntermediateNode)
|
||||||
{
|
{
|
||||||
// This is the case when an attribute contains a code block @{ ... }
|
// This is the case when an attribute contains a code block @{ ... }
|
||||||
// We don't support this.
|
// We don't support this.
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
else if (node.Children.Count > 1)
|
else if (node.Children.Count > 1)
|
||||||
{
|
{
|
||||||
// This is the common case for 'mixed' content
|
// This is the common case for 'mixed' content
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
|
|
||||||
public static readonly RazorDiagnosticDescriptor UnsupportedComplexContent = new RazorDiagnosticDescriptor(
|
public static readonly RazorDiagnosticDescriptor UnsupportedComplexContent = new RazorDiagnosticDescriptor(
|
||||||
$"{DiagnosticPrefix}9986",
|
$"{DiagnosticPrefix}9986",
|
||||||
() => "Component attributes do not support complex content (mixed C# and markup). Attribute: '{0}', text '{1}'",
|
() => "Component attributes do not support complex content (mixed C# and markup). Attribute: '{0}', text: '{1}'",
|
||||||
RazorDiagnosticSeverity.Error);
|
RazorDiagnosticSeverity.Error);
|
||||||
|
|
||||||
public static RazorDiagnostic Create_UnsupportedComplexContent(IntermediateNode node, string attributeName)
|
public static RazorDiagnostic Create_UnsupportedComplexContent(IntermediateNode node, string attributeName)
|
||||||
|
|
@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
() => "The attribute '{0}' was matched by multiple bind attributes. Duplicates:{1}",
|
() => "The attribute '{0}' was matched by multiple bind attributes. Duplicates:{1}",
|
||||||
RazorDiagnosticSeverity.Error);
|
RazorDiagnosticSeverity.Error);
|
||||||
|
|
||||||
public static RazorDiagnostic CreateBindAttribute_Duplicates(SourceSpan? source, string attribute, TagHelperPropertyIntermediateNode[] attributes)
|
public static RazorDiagnostic CreateBindAttribute_Duplicates(SourceSpan? source, string attribute, TagHelperDirectiveAttributeIntermediateNode[] attributes)
|
||||||
{
|
{
|
||||||
var diagnostic = RazorDiagnostic.Create(
|
var diagnostic = RazorDiagnostic.Create(
|
||||||
BindAttribute_Duplicates,
|
BindAttribute_Duplicates,
|
||||||
|
|
@ -152,7 +152,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
() => "The attribute '{0}' was matched by multiple event handlers attributes. Duplicates:{1}",
|
() => "The attribute '{0}' was matched by multiple event handlers attributes. Duplicates:{1}",
|
||||||
RazorDiagnosticSeverity.Error);
|
RazorDiagnosticSeverity.Error);
|
||||||
|
|
||||||
public static RazorDiagnostic CreateEventHandler_Duplicates(SourceSpan? source, string attribute, TagHelperPropertyIntermediateNode[] attributes)
|
public static RazorDiagnostic CreateEventHandler_Duplicates(SourceSpan? source, string attribute, TagHelperDirectiveAttributeIntermediateNode[] attributes)
|
||||||
{
|
{
|
||||||
var diagnostic = RazorDiagnostic.Create(
|
var diagnostic = RazorDiagnostic.Create(
|
||||||
EventHandler_Duplicates,
|
EventHandler_Duplicates,
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
// For each event handler *usage* we need to rewrite the tag helper node to map to basic constructs.
|
// For each event handler *usage* we need to rewrite the tag helper node to map to basic constructs.
|
||||||
// Each usage will be represented by a tag helper property that is a descendant of either
|
// Each usage will be represented by a tag helper property that is a descendant of either
|
||||||
// a component or element.
|
// a component or element.
|
||||||
var references = documentNode.FindDescendantReferences<TagHelperPropertyIntermediateNode>();
|
var references = documentNode.FindDescendantReferences<TagHelperDirectiveAttributeIntermediateNode>();
|
||||||
|
|
||||||
var parents = new HashSet<IntermediateNode>();
|
var parents = new HashSet<IntermediateNode>();
|
||||||
for (var i = 0; i < references.Count; i++)
|
for (var i = 0; i < references.Count; i++)
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
for (var i = 0; i < references.Count; i++)
|
for (var i = 0; i < references.Count; i++)
|
||||||
{
|
{
|
||||||
var reference = references[i];
|
var reference = references[i];
|
||||||
var node = (TagHelperPropertyIntermediateNode)reference.Node;
|
var node = (TagHelperDirectiveAttributeIntermediateNode)reference.Node;
|
||||||
|
|
||||||
if (!reference.Parent.Children.Contains(node))
|
if (!reference.Parent.Children.Contains(node))
|
||||||
{
|
{
|
||||||
|
|
@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.TagHelper.IsEventHandlerTagHelper() && node.IsDirectiveAttribute)
|
if (node.TagHelper.IsEventHandlerTagHelper())
|
||||||
{
|
{
|
||||||
reference.Replace(RewriteUsage(reference.Parent, node));
|
reference.Replace(RewriteUsage(reference.Parent, node));
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +93,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
|
|
||||||
// If we still have duplicates at this point then they are genuine conflicts.
|
// If we still have duplicates at this point then they are genuine conflicts.
|
||||||
var duplicates = parent.Children
|
var duplicates = parent.Children
|
||||||
.OfType<TagHelperPropertyIntermediateNode>()
|
.OfType<TagHelperDirectiveAttributeIntermediateNode>()
|
||||||
.Where(p => p.TagHelper?.IsEventHandlerTagHelper() ?? false)
|
.Where(p => p.TagHelper?.IsEventHandlerTagHelper() ?? false)
|
||||||
.GroupBy(p => p.AttributeName)
|
.GroupBy(p => p.AttributeName)
|
||||||
.Where(g => g.Count() > 1);
|
.Where(g => g.Count() > 1);
|
||||||
|
|
@ -111,7 +111,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntermediateNode RewriteUsage(IntermediateNode parent, TagHelperPropertyIntermediateNode node)
|
private IntermediateNode RewriteUsage(IntermediateNode parent, TagHelperDirectiveAttributeIntermediateNode node)
|
||||||
{
|
{
|
||||||
var original = GetAttributeContent(node);
|
var original = GetAttributeContent(node);
|
||||||
if (original.Count == 0)
|
if (original.Count == 0)
|
||||||
|
|
@ -148,19 +148,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
}
|
}
|
||||||
|
|
||||||
var attributeName = node.AttributeName;
|
var attributeName = node.AttributeName;
|
||||||
if (node.IsDirectiveAttribute && attributeName.StartsWith("@"))
|
|
||||||
{
|
|
||||||
// Directive attributes start with a "@" but we don't want that to be included in the output attribute name.
|
|
||||||
// E.g, <input @onclick="..." /> should result in the creation of 'onclick' attribute.
|
|
||||||
attributeName = attributeName.Substring(1);
|
|
||||||
}
|
|
||||||
if (parent is MarkupElementIntermediateNode)
|
if (parent is MarkupElementIntermediateNode)
|
||||||
{
|
{
|
||||||
var result = new HtmlAttributeIntermediateNode()
|
var result = new HtmlAttributeIntermediateNode()
|
||||||
{
|
{
|
||||||
Annotations =
|
Annotations =
|
||||||
{
|
{
|
||||||
[ComponentMetadata.Common.OriginalAttributeName] = node.AttributeName,
|
[ComponentMetadata.Common.OriginalAttributeName] = node.OriginalAttributeName,
|
||||||
},
|
},
|
||||||
AttributeName = attributeName,
|
AttributeName = attributeName,
|
||||||
Source = node.Source,
|
Source = node.Source,
|
||||||
|
|
@ -188,7 +183,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
Annotations =
|
Annotations =
|
||||||
{
|
{
|
||||||
[ComponentMetadata.Common.OriginalAttributeName] = node.AttributeName,
|
[ComponentMetadata.Common.OriginalAttributeName] = node.OriginalAttributeName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -203,7 +198,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IReadOnlyList<IntermediateToken> GetAttributeContent(TagHelperPropertyIntermediateNode node)
|
private static IReadOnlyList<IntermediateToken> GetAttributeContent(TagHelperDirectiveAttributeIntermediateNode node)
|
||||||
{
|
{
|
||||||
var template = node.FindDescendantNodes<TemplateIntermediateNode>().FirstOrDefault();
|
var template = node.FindDescendantNodes<TemplateIntermediateNode>().FirstOrDefault();
|
||||||
if (template != null)
|
if (template != null)
|
||||||
|
|
|
||||||
|
|
@ -25,20 +25,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var references = documentNode.FindDescendantReferences<TagHelperPropertyIntermediateNode>();
|
var references = documentNode.FindDescendantReferences<TagHelperDirectiveAttributeIntermediateNode>();
|
||||||
for (var i = 0; i < references.Count; i++)
|
for (var i = 0; i < references.Count; i++)
|
||||||
{
|
{
|
||||||
var reference = references[i];
|
var reference = references[i];
|
||||||
var node = (TagHelperPropertyIntermediateNode)reference.Node;
|
var node = (TagHelperDirectiveAttributeIntermediateNode)reference.Node;
|
||||||
|
|
||||||
if (node.TagHelper.IsKeyTagHelper() && node.IsDirectiveAttribute)
|
if (node.TagHelper.IsKeyTagHelper())
|
||||||
{
|
{
|
||||||
reference.Replace(RewriteUsage(reference.Parent, node));
|
reference.Replace(RewriteUsage(reference.Parent, node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntermediateNode RewriteUsage(IntermediateNode parent, TagHelperPropertyIntermediateNode node)
|
private IntermediateNode RewriteUsage(IntermediateNode parent, TagHelperDirectiveAttributeIntermediateNode node)
|
||||||
{
|
{
|
||||||
// If we can't get a nonempty attribute value, do nothing because there will
|
// If we can't get a nonempty attribute value, do nothing because there will
|
||||||
// already be a diagnostic for empty values
|
// already be a diagnostic for empty values
|
||||||
|
|
@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
return new SetKeyIntermediateNode(keyValueToken);
|
return new SetKeyIntermediateNode(keyValueToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntermediateToken DetermineKeyValueToken(TagHelperPropertyIntermediateNode attributeNode)
|
private IntermediateToken DetermineKeyValueToken(TagHelperDirectiveAttributeIntermediateNode attributeNode)
|
||||||
{
|
{
|
||||||
IntermediateToken foundToken = null;
|
IntermediateToken foundToken = null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is an unrecognized attribute, this is possible if you try to do something like put 'ref' on a child content.
|
// This is an unrecognized tag helper bound attribute. This will practically never happen unless the child content descriptor was misconfigured.
|
||||||
childContent.Diagnostics.Add(ComponentDiagnosticFactory.Create_ChildContentHasInvalidAttribute(property.Source, property.AttributeName, attribute.Name));
|
childContent.Diagnostics.Add(ComponentDiagnosticFactory.Create_ChildContentHasInvalidAttribute(property.Source, property.AttributeName, attribute.Name));
|
||||||
}
|
}
|
||||||
else if (child is TagHelperHtmlAttributeIntermediateNode a)
|
else if (child is TagHelperHtmlAttributeIntermediateNode a)
|
||||||
|
|
@ -269,6 +269,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
// This is an HTML attribute on a child content.
|
// This is an HTML attribute on a child content.
|
||||||
childContent.Diagnostics.Add(ComponentDiagnosticFactory.Create_ChildContentHasInvalidAttribute(a.Source, a.AttributeName, attribute.Name));
|
childContent.Diagnostics.Add(ComponentDiagnosticFactory.Create_ChildContentHasInvalidAttribute(a.Source, a.AttributeName, attribute.Name));
|
||||||
}
|
}
|
||||||
|
else if (child is TagHelperDirectiveAttributeIntermediateNode directiveAttribute)
|
||||||
|
{
|
||||||
|
// We don't support directive attributes inside child content, this is possible if you try to do something like put '@ref' on a child content.
|
||||||
|
childContent.Diagnostics.Add(ComponentDiagnosticFactory.Create_ChildContentHasInvalidAttribute(directiveAttribute.Source, directiveAttribute.OriginalAttributeName, attribute.Name));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This is some other kind of node (likely an implicit child content)
|
// This is some other kind of node (likely an implicit child content)
|
||||||
|
|
@ -385,6 +390,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
_children.Add(new ComponentAttributeIntermediateNode(node));
|
_children.Add(new ComponentAttributeIntermediateNode(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void VisitTagHelperDirectiveAttribute(TagHelperDirectiveAttributeIntermediateNode node)
|
||||||
|
{
|
||||||
|
// We don't want to do anything special with directive attributes here.
|
||||||
|
// Let their corresponding lowering pass take care of processing them.
|
||||||
|
_children.Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
public override void VisitDefault(IntermediateNode node)
|
public override void VisitDefault(IntermediateNode node)
|
||||||
{
|
{
|
||||||
_children.Add(node);
|
_children.Add(node);
|
||||||
|
|
@ -490,6 +502,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
_children.Add(node.TagHelper.IsComponentTagHelper() ? (IntermediateNode)new ComponentAttributeIntermediateNode(node) : node);
|
_children.Add(node.TagHelper.IsComponentTagHelper() ? (IntermediateNode)new ComponentAttributeIntermediateNode(node) : node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void VisitTagHelperDirectiveAttribute(TagHelperDirectiveAttributeIntermediateNode node)
|
||||||
|
{
|
||||||
|
// We don't want to do anything special with directive attributes here.
|
||||||
|
// Let their corresponding lowering pass take care of processing them.
|
||||||
|
_children.Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
public override void VisitDefault(IntermediateNode node)
|
public override void VisitDefault(IntermediateNode node)
|
||||||
{
|
{
|
||||||
_children.Add(node);
|
_children.Add(node);
|
||||||
|
|
|
||||||
|
|
@ -25,20 +25,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var references = documentNode.FindDescendantReferences<TagHelperPropertyIntermediateNode>();
|
var references = documentNode.FindDescendantReferences<TagHelperDirectiveAttributeIntermediateNode>();
|
||||||
for (var i = 0; i < references.Count; i++)
|
for (var i = 0; i < references.Count; i++)
|
||||||
{
|
{
|
||||||
var reference = references[i];
|
var reference = references[i];
|
||||||
var node = (TagHelperPropertyIntermediateNode)reference.Node;
|
var node = (TagHelperDirectiveAttributeIntermediateNode)reference.Node;
|
||||||
|
|
||||||
if (node.TagHelper.IsRefTagHelper() && node.IsDirectiveAttribute)
|
if (node.TagHelper.IsRefTagHelper())
|
||||||
{
|
{
|
||||||
reference.Replace(RewriteUsage(@class, reference.Parent, node));
|
reference.Replace(RewriteUsage(@class, reference.Parent, node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntermediateNode RewriteUsage(ClassDeclarationIntermediateNode classNode, IntermediateNode parent, TagHelperPropertyIntermediateNode node)
|
private IntermediateNode RewriteUsage(ClassDeclarationIntermediateNode classNode, IntermediateNode parent, TagHelperDirectiveAttributeIntermediateNode node)
|
||||||
{
|
{
|
||||||
// If we can't get a nonempty attribute name, do nothing because there will
|
// If we can't get a nonempty attribute name, do nothing because there will
|
||||||
// already be a diagnostic for empty values
|
// already be a diagnostic for empty values
|
||||||
|
|
@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntermediateToken DetermineIdentifierToken(TagHelperPropertyIntermediateNode attributeNode)
|
private IntermediateToken DetermineIdentifierToken(TagHelperDirectiveAttributeIntermediateNode attributeNode)
|
||||||
{
|
{
|
||||||
IntermediateToken foundToken = null;
|
IntermediateToken foundToken = null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
ancestor is ComponentAttributeIntermediateNode ||
|
ancestor is ComponentAttributeIntermediateNode ||
|
||||||
|
|
||||||
// Inside malformed ref attribute
|
// Inside malformed ref attribute
|
||||||
ancestor is TagHelperPropertyIntermediateNode)
|
ancestor is TagHelperPropertyIntermediateNode ||
|
||||||
|
|
||||||
|
// Inside a directive attribute
|
||||||
|
ancestor is TagHelperDirectiveAttributeIntermediateNode)
|
||||||
{
|
{
|
||||||
Candidates.Add(new IntermediateNodeReference(Parent, node));
|
Candidates.Add(new IntermediateNodeReference(Parent, node));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1752,14 +1752,19 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Directive attributes should start with '@' unless the descriptors are misconfigured.
|
||||||
|
// In that case, we would have already logged an error.
|
||||||
|
var actualAttributeName = attributeName.StartsWith("@") ? attributeName.Substring(1) : attributeName;
|
||||||
|
|
||||||
IntermediateNode attributeNode;
|
IntermediateNode attributeNode;
|
||||||
if (parameterMatch &&
|
if (parameterMatch &&
|
||||||
TagHelperMatchingConventions.TryGetBoundAttributeParameter(attributeName, out var attributeNameWithoutParameter, out _))
|
TagHelperMatchingConventions.TryGetBoundAttributeParameter(actualAttributeName, out var attributeNameWithoutParameter, out _))
|
||||||
{
|
{
|
||||||
attributeNode = new TagHelperAttributeParameterIntermediateNode()
|
attributeNode = new TagHelperDirectiveAttributeParameterIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = attributeName,
|
AttributeName = actualAttributeName,
|
||||||
AttributeNameWithoutParameter = attributeNameWithoutParameter,
|
AttributeNameWithoutParameter = attributeNameWithoutParameter,
|
||||||
|
OriginalAttributeName = attributeName,
|
||||||
BoundAttributeParameter = associatedAttributeParameterDescriptor,
|
BoundAttributeParameter = associatedAttributeParameterDescriptor,
|
||||||
BoundAttribute = associatedAttributeDescriptor,
|
BoundAttribute = associatedAttributeDescriptor,
|
||||||
TagHelper = associatedDescriptor,
|
TagHelper = associatedDescriptor,
|
||||||
|
|
@ -1770,9 +1775,10 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
attributeNode = new TagHelperPropertyIntermediateNode()
|
attributeNode = new TagHelperDirectiveAttributeIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = attributeName,
|
AttributeName = actualAttributeName,
|
||||||
|
OriginalAttributeName = attributeName,
|
||||||
BoundAttribute = associatedAttributeDescriptor,
|
BoundAttribute = associatedAttributeDescriptor,
|
||||||
TagHelper = associatedDescriptor,
|
TagHelper = associatedDescriptor,
|
||||||
AttributeStructure = node.TagHelperAttributeInfo.AttributeStructure,
|
AttributeStructure = node.TagHelperAttributeInfo.AttributeStructure,
|
||||||
|
|
@ -1870,14 +1876,19 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
out var parameterMatch,
|
out var parameterMatch,
|
||||||
out var associatedAttributeParameterDescriptor))
|
out var associatedAttributeParameterDescriptor))
|
||||||
{
|
{
|
||||||
|
// Directive attributes should start with '@' unless the descriptors are misconfigured.
|
||||||
|
// In that case, we would have already logged an error.
|
||||||
|
var actualAttributeName = attributeName.StartsWith("@") ? attributeName.Substring(1) : attributeName;
|
||||||
|
|
||||||
IntermediateNode attributeNode;
|
IntermediateNode attributeNode;
|
||||||
if (parameterMatch &&
|
if (parameterMatch &&
|
||||||
TagHelperMatchingConventions.TryGetBoundAttributeParameter(attributeName, out var attributeNameWithoutParameter, out _))
|
TagHelperMatchingConventions.TryGetBoundAttributeParameter(actualAttributeName, out var attributeNameWithoutParameter, out _))
|
||||||
{
|
{
|
||||||
attributeNode = new TagHelperAttributeParameterIntermediateNode()
|
attributeNode = new TagHelperDirectiveAttributeParameterIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = attributeName,
|
AttributeName = actualAttributeName,
|
||||||
AttributeNameWithoutParameter = attributeNameWithoutParameter,
|
AttributeNameWithoutParameter = attributeNameWithoutParameter,
|
||||||
|
OriginalAttributeName = attributeName,
|
||||||
BoundAttributeParameter = associatedAttributeParameterDescriptor,
|
BoundAttributeParameter = associatedAttributeParameterDescriptor,
|
||||||
BoundAttribute = associatedAttributeDescriptor,
|
BoundAttribute = associatedAttributeDescriptor,
|
||||||
TagHelper = associatedDescriptor,
|
TagHelper = associatedDescriptor,
|
||||||
|
|
@ -1888,9 +1899,10 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
attributeNode = new TagHelperPropertyIntermediateNode()
|
attributeNode = new TagHelperDirectiveAttributeIntermediateNode()
|
||||||
{
|
{
|
||||||
AttributeName = attributeName,
|
AttributeName = actualAttributeName,
|
||||||
|
OriginalAttributeName = attributeName,
|
||||||
BoundAttribute = associatedAttributeDescriptor,
|
BoundAttribute = associatedAttributeDescriptor,
|
||||||
TagHelper = associatedDescriptor,
|
TagHelper = associatedDescriptor,
|
||||||
AttributeStructure = node.TagHelperAttributeInfo.AttributeStructure,
|
AttributeStructure = node.TagHelperAttributeInfo.AttributeStructure,
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
}
|
}
|
||||||
|
|
||||||
var attributeName = propertyNode.AttributeName;
|
var attributeName = propertyNode.AttributeName;
|
||||||
if (propertyNode.IsDirectiveAttribute && attributeName.StartsWith("@"))
|
|
||||||
{
|
|
||||||
// Directive attributes start with a "@" but we don't want that to be included in the output attribute name.
|
|
||||||
// E.g, <input @onclick="..." /> should result in the creation of 'onclick' attribute.
|
|
||||||
attributeName = attributeName.Substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
AttributeName = attributeName;
|
AttributeName = attributeName;
|
||||||
AttributeStructure = propertyNode.AttributeStructure;
|
AttributeStructure = propertyNode.AttributeStructure;
|
||||||
|
|
@ -68,6 +62,32 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ComponentAttributeIntermediateNode(TagHelperDirectiveAttributeIntermediateNode directiveAttributeNode)
|
||||||
|
{
|
||||||
|
if (directiveAttributeNode == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(directiveAttributeNode));
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeName = directiveAttributeNode.AttributeName;
|
||||||
|
AttributeStructure = directiveAttributeNode.AttributeStructure;
|
||||||
|
BoundAttribute = directiveAttributeNode.BoundAttribute;
|
||||||
|
PropertyName = directiveAttributeNode.BoundAttribute.GetPropertyName();
|
||||||
|
Source = directiveAttributeNode.Source;
|
||||||
|
TagHelper = directiveAttributeNode.TagHelper;
|
||||||
|
TypeName = directiveAttributeNode.BoundAttribute.IsWeaklyTyped() ? null : directiveAttributeNode.BoundAttribute.TypeName;
|
||||||
|
|
||||||
|
for (var i = 0; i < directiveAttributeNode.Children.Count; i++)
|
||||||
|
{
|
||||||
|
Children.Add(directiveAttributeNode.Children[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < directiveAttributeNode.Diagnostics.Count; i++)
|
||||||
|
{
|
||||||
|
Diagnostics.Add(directiveAttributeNode.Diagnostics[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override IntermediateNodeCollection Children { get; } = new IntermediateNodeCollection();
|
public override IntermediateNodeCollection Children { get; } = new IntermediateNodeCollection();
|
||||||
|
|
||||||
public string AttributeName { get; set; }
|
public string AttributeName { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -124,12 +124,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
VisitDefault(node);
|
VisitDefault(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void VisitTagHelperDirectiveAttribute(TagHelperDirectiveAttributeIntermediateNode node)
|
||||||
|
{
|
||||||
|
VisitDefault(node);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void VisitTagHelperHtmlAttribute(TagHelperHtmlAttributeIntermediateNode node)
|
public virtual void VisitTagHelperHtmlAttribute(TagHelperHtmlAttributeIntermediateNode node)
|
||||||
{
|
{
|
||||||
VisitDefault(node);
|
VisitDefault(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void VisitTagHelperAttributeParameter(TagHelperAttributeParameterIntermediateNode node)
|
public virtual void VisitTagHelperDirectiveAttributeParameter(TagHelperDirectiveAttributeParameterIntermediateNode node)
|
||||||
{
|
{
|
||||||
VisitDefault(node);
|
VisitDefault(node);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
|
{
|
||||||
|
public sealed class TagHelperDirectiveAttributeIntermediateNode : IntermediateNode
|
||||||
|
{
|
||||||
|
public override IntermediateNodeCollection Children { get; } = new IntermediateNodeCollection();
|
||||||
|
|
||||||
|
public string AttributeName { get; set; }
|
||||||
|
|
||||||
|
public string OriginalAttributeName { get; set; }
|
||||||
|
|
||||||
|
public AttributeStructure AttributeStructure { get; set; }
|
||||||
|
|
||||||
|
public BoundAttributeDescriptor BoundAttribute { get; set; }
|
||||||
|
|
||||||
|
public TagHelperDescriptor TagHelper { get; set; }
|
||||||
|
|
||||||
|
public bool IsIndexerNameMatch { get; set; }
|
||||||
|
|
||||||
|
public override void Accept(IntermediateNodeVisitor visitor)
|
||||||
|
{
|
||||||
|
if (visitor == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(visitor));
|
||||||
|
}
|
||||||
|
|
||||||
|
visitor.VisitTagHelperDirectiveAttribute(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FormatNode(IntermediateNodeFormatter formatter)
|
||||||
|
{
|
||||||
|
formatter.WriteContent(AttributeName);
|
||||||
|
|
||||||
|
formatter.WriteProperty(nameof(AttributeName), AttributeName);
|
||||||
|
formatter.WriteProperty(nameof(OriginalAttributeName), OriginalAttributeName);
|
||||||
|
formatter.WriteProperty(nameof(AttributeStructure), AttributeStructure.ToString());
|
||||||
|
formatter.WriteProperty(nameof(BoundAttribute), BoundAttribute?.DisplayName);
|
||||||
|
formatter.WriteProperty(nameof(IsIndexerNameMatch), IsIndexerNameMatch.ToString());
|
||||||
|
formatter.WriteProperty(nameof(TagHelper), TagHelper?.DisplayName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ using System;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
{
|
{
|
||||||
public sealed class TagHelperAttributeParameterIntermediateNode : IntermediateNode
|
public sealed class TagHelperDirectiveAttributeParameterIntermediateNode : IntermediateNode
|
||||||
{
|
{
|
||||||
public override IntermediateNodeCollection Children { get; } = new IntermediateNodeCollection();
|
public override IntermediateNodeCollection Children { get; } = new IntermediateNodeCollection();
|
||||||
|
|
||||||
|
|
@ -13,6 +13,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
|
|
||||||
public string AttributeNameWithoutParameter { get; set; }
|
public string AttributeNameWithoutParameter { get; set; }
|
||||||
|
|
||||||
|
public string OriginalAttributeName { get; set; }
|
||||||
|
|
||||||
public AttributeStructure AttributeStructure { get; set; }
|
public AttributeStructure AttributeStructure { get; set; }
|
||||||
|
|
||||||
public BoundAttributeParameterDescriptor BoundAttributeParameter { get; set; }
|
public BoundAttributeParameterDescriptor BoundAttributeParameter { get; set; }
|
||||||
|
|
@ -23,8 +25,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
|
|
||||||
public bool IsIndexerNameMatch { get; set; }
|
public bool IsIndexerNameMatch { get; set; }
|
||||||
|
|
||||||
public bool IsDirectiveAttribute => BoundAttribute?.IsDirectiveAttribute() ?? false;
|
|
||||||
|
|
||||||
public override void Accept(IntermediateNodeVisitor visitor)
|
public override void Accept(IntermediateNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
if (visitor == null)
|
if (visitor == null)
|
||||||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
throw new ArgumentNullException(nameof(visitor));
|
throw new ArgumentNullException(nameof(visitor));
|
||||||
}
|
}
|
||||||
|
|
||||||
visitor.VisitTagHelperAttributeParameter(this);
|
visitor.VisitTagHelperDirectiveAttributeParameter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void FormatNode(IntermediateNodeFormatter formatter)
|
public override void FormatNode(IntermediateNodeFormatter formatter)
|
||||||
|
|
@ -40,10 +40,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
formatter.WriteContent(AttributeName);
|
formatter.WriteContent(AttributeName);
|
||||||
|
|
||||||
formatter.WriteProperty(nameof(AttributeName), AttributeName);
|
formatter.WriteProperty(nameof(AttributeName), AttributeName);
|
||||||
|
formatter.WriteProperty(nameof(OriginalAttributeName), OriginalAttributeName);
|
||||||
formatter.WriteProperty(nameof(AttributeStructure), AttributeStructure.ToString());
|
formatter.WriteProperty(nameof(AttributeStructure), AttributeStructure.ToString());
|
||||||
formatter.WriteProperty(nameof(BoundAttribute), BoundAttribute?.DisplayName);
|
formatter.WriteProperty(nameof(BoundAttribute), BoundAttribute?.DisplayName);
|
||||||
formatter.WriteProperty(nameof(BoundAttributeParameter), BoundAttributeParameter?.DisplayName);
|
formatter.WriteProperty(nameof(BoundAttributeParameter), BoundAttributeParameter?.DisplayName);
|
||||||
formatter.WriteProperty(nameof(IsDirectiveAttribute), IsDirectiveAttribute.ToString());
|
|
||||||
formatter.WriteProperty(nameof(TagHelper), TagHelper?.DisplayName);
|
formatter.WriteProperty(nameof(TagHelper), TagHelper?.DisplayName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -19,8 +19,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
|
|
||||||
public bool IsIndexerNameMatch { get; set; }
|
public bool IsIndexerNameMatch { get; set; }
|
||||||
|
|
||||||
public bool IsDirectiveAttribute => BoundAttribute?.IsDirectiveAttribute() ?? false;
|
|
||||||
|
|
||||||
public override void Accept(IntermediateNodeVisitor visitor)
|
public override void Accept(IntermediateNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
if (visitor == null)
|
if (visitor == null)
|
||||||
|
|
@ -38,7 +36,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
formatter.WriteProperty(nameof(AttributeName), AttributeName);
|
formatter.WriteProperty(nameof(AttributeName), AttributeName);
|
||||||
formatter.WriteProperty(nameof(AttributeStructure), AttributeStructure.ToString());
|
formatter.WriteProperty(nameof(AttributeStructure), AttributeStructure.ToString());
|
||||||
formatter.WriteProperty(nameof(BoundAttribute), BoundAttribute?.DisplayName);
|
formatter.WriteProperty(nameof(BoundAttribute), BoundAttribute?.DisplayName);
|
||||||
formatter.WriteProperty(nameof(IsDirectiveAttribute), IsDirectiveAttribute.ToString());
|
|
||||||
formatter.WriteProperty(nameof(IsIndexerNameMatch), IsIndexerNameMatch.ToString());
|
formatter.WriteProperty(nameof(IsIndexerNameMatch), IsIndexerNameMatch.ToString());
|
||||||
formatter.WriteProperty(nameof(TagHelper), TagHelper?.DisplayName);
|
formatter.WriteProperty(nameof(TagHelper), TagHelper?.DisplayName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -245,5 +245,26 @@ Some Content
|
||||||
"Invalid parameter name. The parameter name attribute 'Context' on component 'RenderChildContentString' can only include literal text.",
|
"Invalid parameter name. The parameter name attribute 'Context' on component 'RenderChildContentString' can only include literal text.",
|
||||||
diagnostic.GetMessage());
|
diagnostic.GetMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ChildContent_ExplicitChildContent_ContainsDirectiveAttribute_ProducesDiagnostic()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
AdditionalSyntaxTrees.Add(RenderChildContentStringComponent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var generated = CompileToCSharp(@"
|
||||||
|
<RenderChildContentString>
|
||||||
|
<ChildContent Context=""items"" @key=""Hello"">
|
||||||
|
</ChildContent>
|
||||||
|
</RenderChildContentString>");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var diagnostic = Assert.Single(generated.Diagnostics);
|
||||||
|
Assert.Same(ComponentDiagnosticFactory.ChildContentHasInvalidAttribute.Id, diagnostic.Id);
|
||||||
|
Assert.Equal(
|
||||||
|
"Unrecognized attribute '@key' on child content element 'ChildContent'.",
|
||||||
|
diagnostic.GetMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,5 +107,23 @@ namespace Test
|
||||||
Assert.Equal(0, item.Span.CharacterIndex);
|
Assert.Equal(0, item.Span.CharacterIndex);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DirectiveAttribute_ComplexContent_ReportsError()
|
||||||
|
{
|
||||||
|
// Arrange & Act
|
||||||
|
var generated = CompileToCSharp(@"
|
||||||
|
<input type=""text"" @key=""Foo @Text"" />
|
||||||
|
@functions {
|
||||||
|
public string Text { get; set; } = ""text"";
|
||||||
|
}");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var diagnostic = Assert.Single(generated.Diagnostics);
|
||||||
|
Assert.Equal("RZ9986", diagnostic.Id);
|
||||||
|
Assert.Equal(
|
||||||
|
"Component attributes do not support complex content (mixed C# and markup). Attribute: '@key', text: 'Foo @Text'",
|
||||||
|
diagnostic.GetMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,12 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
|
||||||
WriteContentNode(node, node.AttributeName, string.Format("HtmlAttributeValueStyle.{0}", node.AttributeStructure));
|
WriteContentNode(node, node.AttributeName, string.Format("HtmlAttributeValueStyle.{0}", node.AttributeStructure));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void VisitTagHelperAttributeParameter(TagHelperAttributeParameterIntermediateNode node)
|
public override void VisitTagHelperDirectiveAttribute(TagHelperDirectiveAttributeIntermediateNode node)
|
||||||
|
{
|
||||||
|
WriteContentNode(node, node.AttributeName, node.BoundAttribute.DisplayName, string.Format("HtmlAttributeValueStyle.{0}", node.AttributeStructure));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void VisitTagHelperDirectiveAttributeParameter(TagHelperDirectiveAttributeParameterIntermediateNode node)
|
||||||
{
|
{
|
||||||
WriteContentNode(node, node.AttributeName, string.Format("HtmlAttributeValueStyle.{0}", node.AttributeStructure));
|
WriteContentNode(node, node.AttributeName, string.Format("HtmlAttributeValueStyle.{0}", node.AttributeStructure));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue